diff options
author | Joe Crayne <joe@jerkface.net> | 2019-06-10 23:03:04 -0400 |
---|---|---|
committer | Joe Crayne <joe@jerkface.net> | 2019-06-10 23:03:04 -0400 |
commit | 38b7bcf654e5e804a13518b060ebdba59bf232bb (patch) | |
tree | 2fa3c4ccf3496750f0ce388a9ea0998fdd93bf69 /src/Graphics/WaveFront/Parse |
Initial commit.
Diffstat (limited to 'src/Graphics/WaveFront/Parse')
-rw-r--r-- | src/Graphics/WaveFront/Parse/Common.hs | 166 | ||||
-rw-r--r-- | src/Graphics/WaveFront/Parse/MTL.hs | 142 | ||||
-rw-r--r-- | src/Graphics/WaveFront/Parse/OBJ.hs | 173 |
3 files changed, 481 insertions, 0 deletions
diff --git a/src/Graphics/WaveFront/Parse/Common.hs b/src/Graphics/WaveFront/Parse/Common.hs new file mode 100644 index 0000000..bfeb2d8 --- /dev/null +++ b/src/Graphics/WaveFront/Parse/Common.hs | |||
@@ -0,0 +1,166 @@ | |||
1 | -- | | ||
2 | -- Module : Graphics.WaveFront.Parse.Common | ||
3 | -- Description : | ||
4 | -- Copyright : (c) Jonatan H Sundqvist, October 2 2016 | ||
5 | -- License : MIT | ||
6 | -- Maintainer : Jonatan H Sundqvist | ||
7 | -- Stability : experimental|stable | ||
8 | -- Portability : POSIX (not sure) | ||
9 | |||
10 | -- TODO | - Fully polymorphic (even in the string and list types) (?) | ||
11 | -- - | ||
12 | |||
13 | -- SPEC | - | ||
14 | -- - | ||
15 | |||
16 | |||
17 | |||
18 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
19 | -- GHC Extensions | ||
20 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
21 | {-# LANGUAGE OverloadedStrings #-} | ||
22 | |||
23 | |||
24 | |||
25 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
26 | -- Section | ||
27 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
28 | module Graphics.WaveFront.Parse.Common where | ||
29 | |||
30 | |||
31 | |||
32 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
33 | -- We'll need these | ||
34 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
35 | import Data.Text (Text, pack) | ||
36 | import qualified Data.Attoparsec.Text as Atto | ||
37 | |||
38 | import Control.Applicative (pure, liftA2, (<$>), (<*>), (<*), (*>), (<|>)) | ||
39 | import Linear (V2(..), V3(..)) | ||
40 | |||
41 | import Graphics.WaveFront.Types | ||
42 | |||
43 | |||
44 | |||
45 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
46 | -- Functions (pure) | ||
47 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
48 | |||
49 | -- Jon's little helpers -------------------------------------------------------------------------------------------------------------------- | ||
50 | |||
51 | -- | Consumes all input, including any leading or trailing comments and whitespace | ||
52 | -- TODO | - Rename (?) | ||
53 | wholeFile :: Atto.Parser a -> Atto.Parser a | ||
54 | wholeFile p = cutToTheChase *> p <* cutToTheChase <* Atto.endOfInput | ||
55 | |||
56 | |||
57 | -- | Skips any leading comments, line breaks and empty lines | ||
58 | -- TODO | - Rename (?) | ||
59 | -- - Skip whitespace | ||
60 | cutToTheChase :: Atto.Parser () | ||
61 | cutToTheChase = Atto.skipMany ((comment *> pure ()) <|> (Atto.satisfy isLinearSpace *> pure ()) <|> Atto.endOfLine) | ||
62 | |||
63 | |||
64 | -- | OBJ rows may be separated by one or more lines of comments and whitespace, or empty lines. | ||
65 | -- TODO | - Make sure this is right | ||
66 | lineSeparator :: Atto.Parser () | ||
67 | lineSeparator = Atto.skipMany1 $ ignore space *> ignore comment *> Atto.endOfLine | ||
68 | |||
69 | |||
70 | -- | Parses a comment (from the '#' to end of the line), possibly preceded by whitespace | ||
71 | -- TODO | - Break out the whitespace part (?) | ||
72 | comment :: Atto.Parser Text | ||
73 | comment = Atto.skipSpace *> Atto.char '#' *> Atto.takeTill (\c -> (c == '\r') || (c == '\n')) -- TODO: Is the newline consumed (?) | ||
74 | |||
75 | |||
76 | -- | Tries the given parser, falls back to 'Nothing' if it fails | ||
77 | -- TODO | - Use 'try' to enforce backtracking (?) | ||
78 | optional :: Atto.Parser a -> Atto.Parser (Maybe a) | ||
79 | optional p = Atto.option Nothing (Just <$> p) | ||
80 | |||
81 | |||
82 | -- | Like Atto.skipMany, except it skips one match at the most | ||
83 | ignore :: Atto.Parser a -> Atto.Parser () | ||
84 | ignore p = optional p *> pure () | ||
85 | |||
86 | |||
87 | -- | | ||
88 | atleast :: Int -> Atto.Parser a -> Atto.Parser [a] | ||
89 | atleast n p = liftA2 (++) (Atto.count n p) (Atto.many' p) | ||
90 | |||
91 | |||
92 | -- | Skips atleast one white space character (not including newlines and carriage returns) | ||
93 | space :: Atto.Parser () | ||
94 | space = Atto.skipMany1 (Atto.satisfy isLinearSpace) | ||
95 | |||
96 | |||
97 | -- | Predicate for linear space (eg. whitespace besides newlines) | ||
98 | -- TODO | - Unicode awareness (cf. Data.Char.isSpace) | ||
99 | -- - Come up with a better name (?) | ||
100 | isLinearSpace :: Char -> Bool | ||
101 | isLinearSpace c = (c == ' ') || (c == '\t') | ||
102 | |||
103 | |||
104 | -- | One or more letters (cf. 'Atto.letter' for details) | ||
105 | word :: Atto.Parser Text | ||
106 | word = pack <$> Atto.many1 Atto.letter | ||
107 | |||
108 | |||
109 | -- | Used for texture, material, object and group names (and maybe others that I have yet to think of) | ||
110 | -- TODO | - Use Unicode groups, make more robust (?) | ||
111 | name :: Atto.Parser Text | ||
112 | name = pack <$> Atto.many1 (Atto.satisfy $ \c -> (c /= ' ') && (c /= '\t') && (c /= '\r') && (c /= '\n')) | ||
113 | |||
114 | |||
115 | -- | Parses the strings "off" (False) and "on" (True) | ||
116 | toggle :: Atto.Parser Bool | ||
117 | toggle = (Atto.string "off" *> pure False) <|> (Atto.string "on" *> pure True) | ||
118 | |||
119 | |||
120 | -- | Wraps a parser in a '(' and a ')', with no whitespace in between | ||
121 | parenthesised :: Atto.Parser a -> Atto.Parser a | ||
122 | parenthesised p = Atto.char '(' *> p <* Atto.char ')' | ||
123 | |||
124 | |||
125 | -- TODO | - Allow scientific notation (?) | ||
126 | |||
127 | -- | | ||
128 | coord :: Fractional f => Atto.Parser f | ||
129 | coord = space *> (parenthesised Atto.rational <|> Atto.rational) | ||
130 | |||
131 | |||
132 | -- | A single colour channel | ||
133 | -- TODO | - Clamp to [0,1] (cf. partial from monadplus) (?) | ||
134 | -- - Can channels be parenthesised (?) | ||
135 | channel :: Fractional f => Atto.Parser f | ||
136 | channel = space *> (parenthesised Atto.rational <|> Atto.rational) | ||
137 | |||
138 | |||
139 | -- | A colour with three or four channels (RGB[A]) | ||
140 | colour :: Fractional f => Atto.Parser (Colour f) | ||
141 | colour = Colour <$> channel <*> channel <*> channel <*> Atto.option 1 channel | ||
142 | |||
143 | |||
144 | -- | A point in 3D space | ||
145 | point3D :: Fractional f => Atto.Parser (V3 f) | ||
146 | point3D = V3 <$> coord <*> coord <*> coord | ||
147 | |||
148 | |||
149 | -- | A point in 2D space | ||
150 | point2D :: Fractional f => Atto.Parser (V2 f) | ||
151 | point2D = V2 <$> coord <*> coord | ||
152 | |||
153 | |||
154 | -- | | ||
155 | clamp :: Ord n => n -> n -> n -> Atto.Parser n | ||
156 | clamp lower upper n | ||
157 | | between lower upper n = pure n | ||
158 | | otherwise = fail "Number not in range" | ||
159 | where | ||
160 | between lw up n = (lower <= n) && (n <= upper) | ||
161 | -- between 0 <. n <. 5 | ||
162 | |||
163 | -- | | ||
164 | -- TODO | - Clean up and generalise | ||
165 | clamped :: Integral i => i -> i -> Atto.Parser i | ||
166 | clamped lower upper = Atto.decimal >>= clamp lower upper \ No newline at end of file | ||
diff --git a/src/Graphics/WaveFront/Parse/MTL.hs b/src/Graphics/WaveFront/Parse/MTL.hs new file mode 100644 index 0000000..060952f --- /dev/null +++ b/src/Graphics/WaveFront/Parse/MTL.hs | |||
@@ -0,0 +1,142 @@ | |||
1 | -- | | ||
2 | -- Module : Graphics.WaveFront.Parse.MTL | ||
3 | -- Description : | ||
4 | -- Copyright : (c) Jonatan H Sundqvist, October 2 2016 | ||
5 | -- License : MIT | ||
6 | -- Maintainer : Jonatan H Sundqvist | ||
7 | -- Stability : experimental|stable | ||
8 | -- Portability : POSIX (not sure) | ||
9 | |||
10 | -- TODO | - | ||
11 | -- - | ||
12 | |||
13 | -- SPEC | - | ||
14 | -- - | ||
15 | |||
16 | |||
17 | |||
18 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
19 | -- GHC Extensions | ||
20 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
21 | {-# LANGUAGE UnicodeSyntax #-} | ||
22 | {-# LANGUAGE TupleSections #-} | ||
23 | {-# LANGUAGE OverloadedStrings #-} | ||
24 | {-# LANGUAGE NamedFieldPuns #-} | ||
25 | |||
26 | |||
27 | |||
28 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
29 | -- API | ||
30 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
31 | module Graphics.WaveFront.Parse.MTL ( | ||
32 | mtl, row, token, | ||
33 | ambient, diffuse, specular, | ||
34 | mapDiffuse, newMaterial | ||
35 | ) where | ||
36 | |||
37 | |||
38 | |||
39 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
40 | -- We'll need these | ||
41 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
42 | -- import qualified Data.Map as M | ||
43 | -- import qualified Data.Set as S | ||
44 | -- import qualified Data.Vector as V | ||
45 | import Data.Text (Text) | ||
46 | |||
47 | import qualified Data.Attoparsec.Text as Atto | ||
48 | |||
49 | import Control.Applicative ((<$>), (<*), (*>), (<|>)) | ||
50 | |||
51 | import Graphics.WaveFront.Parse.Common | ||
52 | |||
53 | import Graphics.WaveFront.Types hiding (ambient, diffuse, specular) | ||
54 | |||
55 | |||
56 | |||
57 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
58 | -- Functions | ||
59 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
60 | |||
61 | -- MTL parsing ----------------------------------------------------------------------------------------------------------------------------- | ||
62 | |||
63 | -- | Produces a list of MTL tokens | ||
64 | mtl :: (Fractional f) => Atto.Parser (MTL f Text []) | ||
65 | mtl = Atto.sepBy row lineSeparator | ||
66 | |||
67 | |||
68 | -- | Parses a single MTL row. | ||
69 | row :: (Fractional f) => Atto.Parser (MTLToken f Text) | ||
70 | row = token <* ignore comment | ||
71 | |||
72 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
73 | |||
74 | -- | Parse an MTL token | ||
75 | -- TODO: How to deal with common prefix (Ka, Kd, Ks) (backtrack?) | ||
76 | token :: (Fractional f) => Atto.Parser (MTLToken f Text) | ||
77 | token = (Atto.string "Ka" *> ambient) <|> | ||
78 | (Atto.string "Kd" *> diffuse) <|> | ||
79 | (Atto.string "Ks" *> specular) <|> | ||
80 | (Atto.string "Ns" *> specExp) <|> | ||
81 | (Atto.string "illum" *> illum) <|> | ||
82 | (Atto.string "Ni" *> refraction) <|> | ||
83 | (Atto.string "d" *> dissolve) <|> -- TODO: Handle inverse as well (cf. 'Tr' attribute) | ||
84 | (Atto.string "map_Kd" *> mapDiffuse) <|> | ||
85 | (Atto.string "map_Ka" *> mapAmbient) <|> | ||
86 | (Atto.string "newmtl" *> newMaterial) | ||
87 | |||
88 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
89 | |||
90 | -- TODO: Expose these parsers for testing purposes (?) | ||
91 | |||
92 | -- TODO | - Change definition of 'colour' and 'Colour' to only allow three channels (alpha is handled by the 'dissolve' attribute) | ||
93 | -- - Change the definition of 'Colour' or use the one defined in the colour package | ||
94 | |||
95 | -- | Three or four channel values (RGB[A]) | ||
96 | ambient :: (Fractional f) => Atto.Parser (MTLToken f s) | ||
97 | ambient = Ambient <$> colour | ||
98 | |||
99 | |||
100 | -- | Three or four channel values (RGB[A]) | ||
101 | diffuse :: (Fractional f) => Atto.Parser (MTLToken f s) | ||
102 | diffuse = Diffuse <$> colour | ||
103 | |||
104 | |||
105 | -- | Three or four channel values (RGB[A]) | ||
106 | specular :: (Fractional f) => Atto.Parser (MTLToken f s) | ||
107 | specular = Specular <$> colour | ||
108 | |||
109 | |||
110 | -- | A rational number, preceded by whitespace (specular exponent) | ||
111 | specExp :: (Fractional f) => Atto.Parser (MTLToken f s) | ||
112 | specExp = space *> (SpecularExponent <$> Atto.rational) | ||
113 | |||
114 | |||
115 | -- | A number between 0 and 10 (inclusive) (illumination model) | ||
116 | illum :: Atto.Parser (MTLToken f s) | ||
117 | illum = space *> (Illum <$> clamped 0 10) | ||
118 | |||
119 | |||
120 | -- | A rational number, preceded by whitespace (refraction index) | ||
121 | refraction :: (Fractional f) => Atto.Parser (MTLToken f s) | ||
122 | refraction = space *> (Refraction <$> Atto.rational) | ||
123 | |||
124 | |||
125 | -- | A rational number, preceded by whitespace (doss) | ||
126 | dissolve :: (Fractional f) => Atto.Parser (MTLToken f s) | ||
127 | dissolve = space *> (Dissolve <$> Atto.rational) | ||
128 | |||
129 | |||
130 | -- | A texture name, preceded by whitespace | ||
131 | mapDiffuse :: Atto.Parser (MTLToken f Text) | ||
132 | mapDiffuse = space *> (MapDiffuse <$> name) | ||
133 | |||
134 | |||
135 | -- | A texture name, preceded by whitespace | ||
136 | mapAmbient :: Atto.Parser (MTLToken f Text) | ||
137 | mapAmbient = space *> (MapAmbient <$> name) | ||
138 | |||
139 | |||
140 | -- | A material name, preceded by whitespace | ||
141 | newMaterial :: Atto.Parser (MTLToken f Text) | ||
142 | newMaterial = space *> (NewMaterial <$> name) \ No newline at end of file | ||
diff --git a/src/Graphics/WaveFront/Parse/OBJ.hs b/src/Graphics/WaveFront/Parse/OBJ.hs new file mode 100644 index 0000000..37aa5a0 --- /dev/null +++ b/src/Graphics/WaveFront/Parse/OBJ.hs | |||
@@ -0,0 +1,173 @@ | |||
1 | -- | | ||
2 | -- Module : Graphics.WaveFront.Parse.OBJ | ||
3 | -- Description : | ||
4 | -- Copyright : (c) Jonatan H Sundqvist, October 2 2016 | ||
5 | -- License : MIT | ||
6 | -- Maintainer : Jonatan H Sundqvist | ||
7 | -- Stability : experimental|stable | ||
8 | -- Portability : POSIX (not sure) | ||
9 | |||
10 | -- TODO | - Fully polymorphic (even in the string and list types) (?) | ||
11 | -- - | ||
12 | |||
13 | -- SPEC | - | ||
14 | -- - | ||
15 | |||
16 | |||
17 | |||
18 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
19 | -- GHC Extensions | ||
20 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
21 | {-# LANGUAGE UnicodeSyntax #-} | ||
22 | {-# LANGUAGE TupleSections #-} | ||
23 | {-# LANGUAGE OverloadedStrings #-} | ||
24 | {-# LANGUAGE NamedFieldPuns #-} | ||
25 | |||
26 | |||
27 | |||
28 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
29 | -- API | ||
30 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
31 | module Graphics.WaveFront.Parse.OBJ ( | ||
32 | obj, row, face, | ||
33 | normal, texcoord, vertex, object, group, | ||
34 | lib, use, | ||
35 | vertexIndices, | ||
36 | ) where | ||
37 | |||
38 | |||
39 | |||
40 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
41 | -- We'll need these | ||
42 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
43 | import Data.Text (Text) | ||
44 | -- import qualified Data.Vector as V | ||
45 | import qualified Data.Set as S | ||
46 | |||
47 | import qualified Data.Attoparsec.Text as Atto | ||
48 | |||
49 | import Control.Applicative ((<$>), (<*>), (<*), (*>), (<|>)) | ||
50 | |||
51 | -- import Linear (V2(..), V3(..)) | ||
52 | |||
53 | import Graphics.WaveFront.Parse.Common | ||
54 | import Graphics.WaveFront.Types hiding (texture) | ||
55 | |||
56 | |||
57 | |||
58 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
59 | -- Functions | ||
60 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
61 | |||
62 | -- OBJ parsing ----------------------------------------------------------------------------------------------------------------------------- | ||
63 | |||
64 | -- | This function creates an OBJToken or error for each line in the input data | ||
65 | obj :: (Fractional f, Integral i) => Atto.Parser (OBJ f Text i []) | ||
66 | obj = Atto.sepBy row lineSeparator -- <* Atto.endOfInput | ||
67 | |||
68 | |||
69 | -- | Parses a token given a single valid OBJ row | ||
70 | -- | ||
71 | -- TODO | - Correctness (total function, no runtime exceptions) | ||
72 | -- - Handle invalid rows (how to deal with mangled definitions w.r.t indices?) | ||
73 | -- - Use ListLike or Monoid (or maybe Indexable, since that's the real requirement) (?) | ||
74 | row :: (Fractional f, Integral i) => Atto.Parser (OBJToken f Text i []) | ||
75 | row = token <* ignore comment -- TODO: Let the separator handle comments (?) | ||
76 | |||
77 | |||
78 | -- | | ||
79 | -- Parses an OBJ token | ||
80 | token :: (Fractional f, Integral i) => Atto.Parser (OBJToken f Text i []) | ||
81 | token = (Atto.string "f" *> face) <|> | ||
82 | (Atto.string "l" *> line) <|> | ||
83 | -- TODO: How to deal with common prefix (v, vn, vt) (backtrack?) (doesn't seem to be a problem) | ||
84 | (Atto.string "vn" *> normal) <|> | ||
85 | (Atto.string "vt" *> texcoord) <|> | ||
86 | (Atto.string "v" *> vertex) <|> | ||
87 | (Atto.string "o" *> object) <|> | ||
88 | (Atto.string "g" *> group) <|> | ||
89 | (Atto.string "s" *> smooth) <|> | ||
90 | (Atto.string "mtllib" *> lib) <|> | ||
91 | (Atto.string "usemtl" *> use) | ||
92 | |||
93 | |||
94 | -- TODO: Expose these parsers for testing purposes (?) | ||
95 | |||
96 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
97 | |||
98 | -- | Three or more vertex definitions (cf. 'vertexIndices' for details) | ||
99 | face :: Integral i => Atto.Parser (OBJToken f Text i []) | ||
100 | face = OBJFace <$> vertexIndices | ||
101 | |||
102 | |||
103 | -- | A single vertex definition with indices for vertex position, normal, and texture coordinates | ||
104 | -- | ||
105 | -- TODO: | - Should the slashes be optional? | ||
106 | -- - Allowed trailing slashes (I'll have to check the spec again) (?) | ||
107 | -- | ||
108 | -- f Int[/((Int[/Int])|(/Int))] | ||
109 | vertexIndices :: Integral i => Atto.Parser [VertexIndices i] | ||
110 | vertexIndices = atleast 3 (space *> (ivertex <*> index <*> index)) <|> -- vi/ti/ni | ||
111 | atleast 3 (space *> (ivertex <*> nothing <*> skipIndex)) <|> -- vi//ni | ||
112 | atleast 3 (space *> (ivertex <*> index <*> nothing)) <|> -- vi/ti | ||
113 | atleast 3 (space *> (ivertex <*> nothing <*> nothing)) -- vi | ||
114 | where | ||
115 | ivertex :: Integral i => Atto.Parser (Maybe i -> Maybe i -> VertexIndices i) | ||
116 | ivertex = VertexIndices <$> Atto.decimal | ||
117 | |||
118 | index :: Integral i => Atto.Parser (Maybe i) | ||
119 | index = Just <$> (Atto.char '/' *> Atto.decimal) | ||
120 | |||
121 | skipIndex :: Integral i => Atto.Parser (Maybe i) | ||
122 | skipIndex = Atto.char '/' *> index | ||
123 | |||
124 | nothing :: Atto.Parser (Maybe i) | ||
125 | nothing = pure Nothing | ||
126 | |||
127 | -- Geometry primitives --------------------------------------------------------------------------------------------------------------------- | ||
128 | |||
129 | -- | Two integers, separated by whitespace | ||
130 | line :: Integral i => Atto.Parser (OBJToken f Text i m) | ||
131 | line = Line <$> (space *> Atto.decimal) <*> (space *> Atto.decimal) | ||
132 | |||
133 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
134 | |||
135 | -- | Three cordinates, separated by whitespace | ||
136 | normal :: (Fractional f) => Atto.Parser (OBJToken f Text i m) | ||
137 | normal = OBJNormal <$> point3D | ||
138 | |||
139 | |||
140 | -- | Two coordinates, separated by whitespace | ||
141 | texcoord :: (Fractional f) => Atto.Parser (OBJToken f Text i m) | ||
142 | texcoord = OBJTexCoord <$> point2D | ||
143 | |||
144 | |||
145 | -- | Three coordinates, separated by whitespace | ||
146 | vertex :: (Fractional f) => Atto.Parser (OBJToken f s i m) | ||
147 | vertex = OBJVertex <$> point3D | ||
148 | |||
149 | |||
150 | -- | Object names, separated by whitespace | ||
151 | object :: Atto.Parser (OBJToken f Text i m) | ||
152 | object = Object . S.fromList <$> atleast 1 (space *> name) | ||
153 | |||
154 | |||
155 | -- | Group names, separated by whitespace | ||
156 | group :: Atto.Parser (OBJToken f Text i m) | ||
157 | group = Group . S.fromList <$> atleast 1 (space *> name) | ||
158 | |||
159 | |||
160 | -- | Smoothing group | ||
161 | -- TODO: Refactor | ||
162 | smooth :: Atto.Parser (OBJToken f Text i m) | ||
163 | smooth = SmoothGroup <$> (((Atto.string "off" <|> Atto.string "0") *> pure Nothing) <|> (space *> (Just <$> name))) | ||
164 | |||
165 | |||
166 | -- | An MTL library name | ||
167 | lib :: Atto.Parser (OBJToken f Text i m) | ||
168 | lib = LibMTL <$> (space *> name) | ||
169 | |||
170 | |||
171 | -- | An MTL material name | ||
172 | use :: Atto.Parser (OBJToken f Text i m) | ||
173 | use = UseMTL <$> (space *> name) \ No newline at end of file | ||