diff options
author | Joe Crayne <joe@jerkface.net> | 2019-06-12 16:48:33 -0400 |
---|---|---|
committer | Joe Crayne <joe@jerkface.net> | 2019-06-12 16:48:33 -0400 |
commit | 550c43c8491e2b6a2873caf8e9c032b69e56e03f (patch) | |
tree | 3cd4cc5b57e205d6d798194fd6991c5f5fee47c7 | |
parent | 74fdcbd78256f9f89f32a47dfd1e060fde5ea8ba (diff) |
Started bytestring-lexing based parser.
-rw-r--r-- | src/Wavefront.hs | 450 | ||||
-rw-r--r-- | wavefront-obj.cabal | 5 |
2 files changed, 455 insertions, 0 deletions
diff --git a/src/Wavefront.hs b/src/Wavefront.hs new file mode 100644 index 0000000..66d6cdb --- /dev/null +++ b/src/Wavefront.hs | |||
@@ -0,0 +1,450 @@ | |||
1 | {-# LANGUAGE NondecreasingIndentation #-} | ||
2 | {-# LANGUAGE OverloadedStrings #-} | ||
3 | module Wavefront where | ||
4 | |||
5 | import qualified Data.ByteString.Lazy.Char8 as L | ||
6 | import qualified Data.ByteString.Char8 as S | ||
7 | import Data.ByteString.Internal as BS | ||
8 | import Data.Char | ||
9 | import Data.IntMap (IntMap) | ||
10 | import qualified Data.IntMap as IntMap | ||
11 | import Data.ByteString.Lex.Fractional as F | ||
12 | import Data.ByteString.Lex.Integral as I | ||
13 | |||
14 | data ObjBuilder m = ObjBuilder | ||
15 | { vertex :: [Double] -> m () | ||
16 | , vertexT :: [Double] -> m () | ||
17 | , vertexN :: [Double] -> m () | ||
18 | , vertexP :: [Double] -> m () | ||
19 | , face :: [RefTriple] -> m () | ||
20 | , cstype :: Bool -> CSType -> m () | ||
21 | , curv2 :: [Int] -> m () | ||
22 | , curv :: Double -> Double -> [Int] -> m () | ||
23 | , parm :: ParamSpec -> [Double] -> m () | ||
24 | , specialPoints :: [Int] -> m () | ||
25 | , endFreeForm :: m () | ||
26 | , ctech :: CurveSamplingSpec -> m () | ||
27 | , stech :: SurfaceSamplingSpec -> m () | ||
28 | , deg :: [Int] -> m () | ||
29 | , surf :: Double -> Double -> Double -> Double -> [RefTriple] -> m () | ||
30 | , trim :: [CurveSpec] -> m () | ||
31 | , hole :: [CurveSpec] -> m () | ||
32 | , specialCurves :: [CurveSpec] -> m () | ||
33 | , equivalentCurves :: [EmbeddedCurve] -> m () | ||
34 | , groups :: [S.ByteString] -> m () | ||
35 | , smoothingGroup :: Int -> m () | ||
36 | , mergingGroup :: Int -> Double -> m () | ||
37 | , usemtl :: S.ByteString -> m () | ||
38 | , deprecated_cdc :: [Int] -> m () | ||
39 | , deprecated_bzp :: [Int] -> m () | ||
40 | , mtllib :: [S.ByteString] -> m () | ||
41 | , objectName :: S.ByteString -> m () | ||
42 | , badToken :: L.ByteString -> m () | ||
43 | } | ||
44 | |||
45 | data CurveSamplingSpec | ||
46 | -- ctech cparm | ||
47 | = UniformSubdivision | ||
48 | { divisionsPerCurveDegree :: Double -- ^ This really ought to be an integer but | ||
49 | -- but examples show floats. The only way | ||
50 | -- it makes sense as a float is if we are to | ||
51 | -- convert to an integer *after* multiplying | ||
52 | -- by the curve degree. | ||
53 | } | ||
54 | -- ctech cspace | ||
55 | | MaxLengthPolygonal { maxPolygonEdgeLength :: Double } | ||
56 | -- ctech curv | ||
57 | | CurvatureBasedPolygon { maxDistanceToCurve :: Double, maximumDegreesPerSample :: Double } | ||
58 | deriving (Eq,Show) | ||
59 | |||
60 | data SurfaceSamplingSpec | ||
61 | -- stech cparma ures vres | ||
62 | = UniformIsoparametric { uDivisionsPerDegree :: Double, vDivisionsPerDegree :: Double } | ||
63 | -- stech cparmb uvres | ||
64 | | UniformAfterTrimming { uvDivisionsPerDegree :: Double } | ||
65 | -- stech cspace maxlength | ||
66 | | MaxLengthPolytopal { maxPolytopEdgeLength :: Double } | ||
67 | -- stech curv maxdist maxangle | ||
68 | | CurvatureBasedPolytope { maxDistanceToSurface :: Double, maxDegreesPerCorner :: Double } | ||
69 | deriving (Eq,Show) | ||
70 | |||
71 | |||
72 | data ObjState = ObjState | ||
73 | { | ||
74 | } | ||
75 | |||
76 | newtype ObjConfig = ObjConfig | ||
77 | { cfgSubst :: IntMap L.ByteString | ||
78 | } | ||
79 | |||
80 | -- consChunk :: S.ByteString -> L.ByteString -> L.ByteString | ||
81 | -- consChunk c bs = L.fromChunks (c : L.toChunks bs) | ||
82 | |||
83 | reappend :: ByteString -> ByteString -> Maybe ByteString | ||
84 | reappend a b = | ||
85 | let (ap,ao,al) = BS.toForeignPtr a | ||
86 | (bp,bo,bl) = BS.toForeignPtr b | ||
87 | in if ap == bp && ao+al == bo | ||
88 | then Just $ BS.PS ap ao (al+bl) | ||
89 | else Nothing | ||
90 | |||
91 | reconsChunk :: S.ByteString -> L.ByteString -> L.ByteString | ||
92 | reconsChunk b bs = case L.toChunks bs of | ||
93 | (c:cs) -> case reappend b c of | ||
94 | Just x -> L.fromChunks (x:cs) | ||
95 | Nothing -> L.fromChunks (b:c:cs) | ||
96 | _ -> L.fromChunks [b] | ||
97 | |||
98 | findToken :: ObjConfig -> L.ByteString -> L.ByteString | ||
99 | findToken (ObjConfig args) bs = case L.dropWhile (\c -> isSpace c || c=='\\') bs of | ||
100 | cs -> case L.uncons cs of | ||
101 | Just ('#',comment) -> findToken (ObjConfig args) $ L.drop 1 $ L.dropWhile (/='\n') comment | ||
102 | Just ('$',ref) -> case L.splitAt 5 ref of | ||
103 | (refp,ds) -> case I.readDecimal (L.toStrict refp) of | ||
104 | Just (i,es) -> case IntMap.lookup i args of | ||
105 | Just val -> val <> reconsChunk es ds | ||
106 | _ -> reconsChunk es ds | ||
107 | _ -> cs | ||
108 | Just _ -> cs | ||
109 | Nothing -> L.empty | ||
110 | |||
111 | {- | ||
112 | |||
113 | 1 x bevel | ||
114 | 2 x bmat | ||
115 | 3 bzp | ||
116 | 4 x call | ||
117 | 5 cdc | ||
118 | 6 x c_interp | ||
119 | 7 con | ||
120 | 8 x csh -- for all except these, | ||
121 | 9 cstype -- Two chars suffice to distinguish | ||
122 | 10 ctech | ||
123 | 11 curv2 -- for all except these, | ||
124 | 12 curv -- Two chars suffice to distinguish | ||
125 | 13 deg | ||
126 | 14 x d_interp | ||
127 | 15 end | ||
128 | 16 f | ||
129 | 17 g | ||
130 | 18 hole | ||
131 | 19 x lod | ||
132 | 20 x maplib | ||
133 | 21 mg | ||
134 | 22 mtllib | ||
135 | 23 o | ||
136 | 24 parm | ||
137 | 25 s | ||
138 | 26 scrv | ||
139 | 27 x shadow_obj | ||
140 | 28 sp | ||
141 | 29 stech -- for all except these, | ||
142 | 30 x step -- Two chars suffice to distinguish | ||
143 | 31 surf | ||
144 | 32 x trace_obj -- for all except these, | ||
145 | 33 trim -- Two chars suffice to distinguish | ||
146 | 34 x usemap -- for all except these, | ||
147 | 35 usemtl -- Two chars suffice to distinguish | ||
148 | 36 v | ||
149 | 37 vn | ||
150 | 38 vp | ||
151 | 39 vt | ||
152 | |||
153 | -} | ||
154 | |||
155 | nextToken :: (L.ByteString -> L.ByteString) -> L.ByteString -> L.ByteString | ||
156 | nextToken tok bs = tok $ L.dropWhile (not . isSpace) bs | ||
157 | |||
158 | parseFloats tok bs cont = case L.splitAt 10 (tok bs) of | ||
159 | (ds,bs') -> case F.readSigned F.readExponential (L.toStrict ds) of | ||
160 | Just (x,b) -> parseFloats tok (reconsChunk b bs') (cont . (x :)) | ||
161 | Nothing -> cont [] (ds <> bs') | ||
162 | |||
163 | parseFloatsN 0 _ bs cont = cont [] bs | ||
164 | parseFloatsN n tok bs cont = case L.splitAt 10 (tok bs) of | ||
165 | (ds,bs') -> case F.readSigned F.readExponential (L.toStrict ds) of | ||
166 | Just (x,b) -> parseFloatsN (n-1) tok (reconsChunk b bs') (cont . (x :)) | ||
167 | Nothing -> cont [] (ds <> bs') | ||
168 | |||
169 | parseInts tok bs cont = case L.splitAt 5 (tok bs) of | ||
170 | (ds,bs') -> case I.readSigned I.readDecimal (L.toStrict ds) of | ||
171 | Just (x,b) -> parseInts tok (reconsChunk b bs') (cont . (x :)) | ||
172 | Nothing -> cont [] (ds <> bs') | ||
173 | |||
174 | parseIntsN 0 tok bs cont = cont [] bs | ||
175 | parseIntsN n tok bs cont = case L.splitAt 5 (tok bs) of | ||
176 | (ds,bs') -> case I.readSigned I.readDecimal (L.toStrict ds) of | ||
177 | Just (x,b) -> parseIntsN (n-1) tok (reconsChunk b bs') (cont . (x :)) | ||
178 | Nothing -> cont [] (ds <> bs') | ||
179 | |||
180 | parseTriples :: (L.ByteString -> L.ByteString) -> L.ByteString -> ([RefTriple] -> L.ByteString -> b) -> b | ||
181 | parseTriples tok bs cont = case L.splitAt 17 (tok bs) of | ||
182 | (ds,bs') -> case I.readSigned I.readDecimal (L.toStrict ds) of | ||
183 | |||
184 | Just (v,b) -> case S.splitAt 1 b of | ||
185 | |||
186 | ("/",ds') -> case I.readSigned I.readDecimal ds' of | ||
187 | |||
188 | Just (vt,c) -> case S.splitAt 1 c of | ||
189 | ("/",ds'') -> case I.readSigned I.readDecimal ds'' of | ||
190 | Just (vn,d) -> parseTriples tok (reconsChunk d bs') $ cont . (RefTriple v (Just vt) (Just vn) :) | ||
191 | Nothing -> parseTriples tok (reconsChunk ds'' bs') $ cont . (RefTriple v (Just vt) Nothing :) | ||
192 | |||
193 | _ -> parseTriples tok (reconsChunk c bs') $ cont . (RefTriple v (Just vt) Nothing :) | ||
194 | |||
195 | Nothing -> case S.splitAt 1 ds' of | ||
196 | ("/",ds'') -> case I.readSigned I.readDecimal ds'' of | ||
197 | Just (vn,d) -> parseTriples tok (reconsChunk d bs') $ cont . (RefTriple v Nothing (Just vn) :) | ||
198 | Nothing -> parseTriples tok (reconsChunk ds'' bs') $ cont . (RefTriple v Nothing Nothing :) | ||
199 | |||
200 | _ -> parseTriples tok (reconsChunk ds' bs') $ cont . (RefTriple v Nothing Nothing :) | ||
201 | |||
202 | |||
203 | _ -> parseTriples tok (reconsChunk b bs') $ cont . (RefTriple v Nothing Nothing :) | ||
204 | |||
205 | Nothing -> cont [] (ds <> bs') | ||
206 | |||
207 | parseCurveSpecs :: (L.ByteString -> L.ByteString) -> L.ByteString -> ([CurveSpec] -> L.ByteString -> b) -> b | ||
208 | parseCurveSpecs tok bs cont = parseFloatsN 2 tok bs $ \fs bs' -> case fs of | ||
209 | (u0:u1:_) -> do | ||
210 | parseIntsN 1 tok bs' $ \is bs'' -> case is of | ||
211 | (i:_) -> parseCurveSpecs tok bs'' $ cont . (CurveSpec u0 u1 i :) | ||
212 | _ -> cont [] bs'' | ||
213 | |||
214 | _ -> cont [] bs' | ||
215 | |||
216 | |||
217 | parseCurveSpecsN :: Int -> (L.ByteString -> L.ByteString) -> L.ByteString -> ([CurveSpec] -> L.ByteString -> b) -> b | ||
218 | parseCurveSpecsN 0 tok bs cont = cont [] bs | ||
219 | parseCurveSpecsN n tok bs cont = parseFloatsN 2 tok bs $ \fs bs' -> case fs of | ||
220 | (u0:u1:_) -> do | ||
221 | parseIntsN 1 tok bs' $ \is bs'' -> case is of | ||
222 | (i:_) -> parseCurveSpecsN (n-1) tok bs'' $ cont . (CurveSpec u0 u1 i :) | ||
223 | _ -> cont [] bs'' | ||
224 | |||
225 | _ -> cont [] bs' | ||
226 | |||
227 | parseEmbeddedCurves :: (L.ByteString -> L.ByteString) -> L.ByteString -> ([EmbeddedCurve] -> L.ByteString -> b) -> b | ||
228 | parseEmbeddedCurves tok bs cont = parseIntsN 1 tok bs $ \is bs' -> case is of | ||
229 | (sref:_) -> do | ||
230 | parseCurveSpecsN 1 tok bs' $ \cs bs'' -> case cs of | ||
231 | (c:_) -> parseEmbeddedCurves tok bs'' $ cont . (EmbeddedCurve sref c :) | ||
232 | _ -> cont [] bs'' | ||
233 | |||
234 | _ -> cont [] bs' | ||
235 | |||
236 | data CSType = Bmatrix | Bezier | Bspline | Cardinal | Taylor | ||
237 | deriving (Eq,Ord,Show,Enum) | ||
238 | |||
239 | data ParamSpec = ParamU | ParamV | ||
240 | deriving (Eq,Ord,Show,Enum) | ||
241 | |||
242 | data RefTriple = RefTriple | ||
243 | { refV :: Int | ||
244 | , refT :: Maybe Int | ||
245 | , refN :: Maybe Int | ||
246 | } | ||
247 | -- data RefTriple = RefTriple Int (Maybe Int) (Maybe Int) | ||
248 | deriving (Eq,Ord,Show) | ||
249 | |||
250 | data CurveSpec = CurveSpec | ||
251 | { curveStart :: Double | ||
252 | , curveEnd :: Double | ||
253 | , curveRef :: Int | ||
254 | } | ||
255 | deriving (Eq,Ord,Show) | ||
256 | |||
257 | data EmbeddedCurve = EmbeddedCurve | ||
258 | { curveSurfaceRef :: Int | ||
259 | , embeddedCurve :: CurveSpec | ||
260 | } | ||
261 | deriving (Eq,Ord,Show) | ||
262 | |||
263 | lengthLessThan :: Int -> L.ByteString -> Bool | ||
264 | lengthLessThan n bs = | ||
265 | foldr (\c ret ac -> let m = S.length c in if ac <= m then False else ret $! ac - m) | ||
266 | (const True) | ||
267 | (L.toChunks bs) | ||
268 | n | ||
269 | |||
270 | parseOBJ :: Monad m => ObjBuilder m -> ObjConfig -> L.ByteString -> m () | ||
271 | parseOBJ builder args bs0 | ||
272 | | lengthLessThan 2 bs = return () | ||
273 | | isSpace (L.index bs 1) = case L.head bs of | ||
274 | 'f' -> parseT face 2 | ||
275 | 'g' -> case L.break (=='\n') $ L.drop 1 bs of -- Newline required to terminate group name list. | ||
276 | (gn,bs') -> do | ||
277 | groups builder (map L.toStrict $ L.words gn) | ||
278 | parseOBJ builder args bs' | ||
279 | 's' -> case next 1 bs of | ||
280 | tok -> parseOffOrNumber tok $ \sg bs' -> do | ||
281 | smoothingGroup builder sg | ||
282 | parseOBJ builder args bs' | ||
283 | 'v' -> parseV vertex 2 | ||
284 | 'o' -> -- o object-name | ||
285 | case L.break (=='\n') $ findToken args $ L.drop 1 bs of | ||
286 | (objn,bs') -> do | ||
287 | objectName builder (L.toStrict objn) | ||
288 | parseOBJ builder args bs' | ||
289 | _ -> badToken builder bs | ||
290 | | otherwise = case L.take 2 bs of | ||
291 | "vt" -> parseV vertexT 3 | ||
292 | "vn" -> parseV vertexN 3 | ||
293 | "vp" -> parseV vertexP 3 | ||
294 | "bz" -> parseI deprecated_bzp 4 -- bzp | ||
295 | "cd" -> parseI deprecated_cdc 4 -- cdc | ||
296 | "co" -> -- con | ||
297 | parseEmbeddedCurves (findToken args) (next 2 bs) $ \ss bs' -> do | ||
298 | equivalentCurves builder ss | ||
299 | parseOBJ builder args bs' | ||
300 | "cs" -> -- cstype | ||
301 | let parseRat = parseChar 'r' | ||
302 | parseTyp tok cont | lengthLessThan 3 tok = badToken builder tok | ||
303 | | otherwise = case L.index tok 2 of | ||
304 | 'a' -> cont Bmatrix $ next 3 tok | ||
305 | 'z' -> cont Bezier $ next 3 tok | ||
306 | 'p' -> cont Bspline $ next 3 tok | ||
307 | 'r' -> cont Cardinal $ next 3 tok | ||
308 | 'y' -> cont Taylor $ next 3 tok | ||
309 | _ -> badToken builder tok | ||
310 | in parseRat (next 2 bs) $ \isRat bs' -> do | ||
311 | parseTyp bs' $ \typ bs'' -> do | ||
312 | cstype builder isRat typ | ||
313 | parseOBJ builder args bs'' | ||
314 | "ct" -> -- ctech | ||
315 | let tok = next 2 bs | ||
316 | in if lengthLessThan 2 tok | ||
317 | then badToken builder tok | ||
318 | else case L.index tok 1 of | ||
319 | 'p' -> -- cparm | ||
320 | parseFloats (findToken args) (next 2 tok) $ \is bs' -> do | ||
321 | let x:_ = is ++ [0] | ||
322 | ctech builder (UniformSubdivision x) | ||
323 | parseOBJ builder args bs' | ||
324 | 's' -> -- cspace | ||
325 | parseFloats (findToken args) (next 2 tok) $ \fs bs' -> do | ||
326 | let x:_ = fs ++ [1.0] | ||
327 | ctech builder (MaxLengthPolygonal x) | ||
328 | parseOBJ builder args bs' | ||
329 | 'u' -> -- curv | ||
330 | parseFloats (findToken args) (next 2 tok) $ \fs bs' -> do | ||
331 | let δ:θ:_ = fs ++ repeat 1.0 | ||
332 | ctech builder (CurvatureBasedPolygon δ θ) | ||
333 | parseOBJ builder args bs' | ||
334 | _ -> badToken builder tok | ||
335 | "cu" -> if lengthLessThan 5 bs | ||
336 | then badToken builder bs | ||
337 | else if L.index bs 4 == '2' | ||
338 | then parseI curv2 5 -- curv2 | ||
339 | else do -- curv | ||
340 | parseFloatsN 2 (findToken args) (L.drop 4 bs) $ \vs bs' -> | ||
341 | parseInts (findToken args) bs' $ \is bs'' -> do | ||
342 | let u0:v0:_ = vs ++ repeat 0.0 | ||
343 | curv builder u0 v0 is | ||
344 | parseOBJ builder args bs'' | ||
345 | "de" -> parseI deg 3 | ||
346 | "en" -> do endFreeForm builder | ||
347 | parseOBJ builder args (next 2 bs) | ||
348 | "ho" -> -- hole | ||
349 | parseCurveSpecs (findToken args) (next 2 bs) $ \ss bs' -> do | ||
350 | hole builder ss | ||
351 | parseOBJ builder args bs' | ||
352 | "mg" -> case next 2 bs of | ||
353 | tok -> parseOffOrNumber tok $ \mg bs' -> do | ||
354 | parseFloatsN 1 (findToken args) bs' $ \fs bs'' -> do | ||
355 | mergingGroup builder mg (head $ fs ++ [0]) | ||
356 | parseOBJ builder args bs'' | ||
357 | "pa" -> parseChar 'u' (next 2 bs) $ \isU bs' -> do | ||
358 | parseFloats (findToken args) (if isU then bs' else L.drop 1 bs') $ \vs bs'' -> do | ||
359 | parm builder (if isU then ParamU else ParamV) vs | ||
360 | parseOBJ builder args bs'' | ||
361 | "sc" -> -- scrv | ||
362 | parseCurveSpecs (findToken args) (next 2 bs) $ \ss bs' -> do | ||
363 | specialCurves builder ss | ||
364 | parseOBJ builder args bs' | ||
365 | "sp" -> parseI specialPoints 3 | ||
366 | "st" -> -- stech | ||
367 | let tok = next 2 bs | ||
368 | in if lengthLessThan 2 tok | ||
369 | then badToken builder tok | ||
370 | else case L.index tok 1 of | ||
371 | 'p' -> -- cparma/cparmb | ||
372 | if lengthLessThan 6 tok | ||
373 | then badToken builder tok | ||
374 | else if L.index tok 5 == 'b' | ||
375 | then -- cparmb | ||
376 | parseFloats (findToken args) (next 5 tok) $ \is bs' -> do | ||
377 | let x:_ = is ++ [0] | ||
378 | stech builder (UniformAfterTrimming x) | ||
379 | parseOBJ builder args bs' | ||
380 | else -- cparma | ||
381 | parseFloats (findToken args) (next 5 tok) $ \is bs' -> do | ||
382 | let x:y:_ = is ++ [0] | ||
383 | stech builder (UniformIsoparametric x y) | ||
384 | parseOBJ builder args bs' | ||
385 | 's' -> -- cspace | ||
386 | parseFloats (findToken args) (next 2 tok) $ \fs bs' -> do | ||
387 | let x:_ = fs ++ [1.0] | ||
388 | stech builder (MaxLengthPolytopal x) | ||
389 | parseOBJ builder args bs' | ||
390 | 'u' -> -- curv | ||
391 | parseFloats (findToken args) (next 2 tok) $ \fs bs' -> do | ||
392 | let δ:θ:_ = fs ++ repeat 1.0 | ||
393 | stech builder (CurvatureBasedPolytope δ θ) | ||
394 | parseOBJ builder args bs' | ||
395 | _ -> badToken builder tok | ||
396 | "su" -> -- surf | ||
397 | parseFloatsN 4 (findToken args) (next 2 bs) $ \fs bs' -> do | ||
398 | parseTriples (findToken args) bs' $ \ts bs'' -> do | ||
399 | let u0:u1:v0:v1:_ = fs ++ repeat 0 | ||
400 | surf builder u0 u1 v0 v1 ts | ||
401 | parseOBJ builder args bs'' | ||
402 | "tr" -> -- trim | ||
403 | parseCurveSpecs (findToken args) (next 2 bs) $ \ss bs' -> do | ||
404 | trim builder ss | ||
405 | parseOBJ builder args bs' | ||
406 | "us" -> -- usemtl | ||
407 | case L.break isSpace $ next 2 bs of | ||
408 | (mtl,bs') -> do | ||
409 | usemtl builder (L.toStrict mtl) | ||
410 | parseOBJ builder args bs' | ||
411 | "mt" -> -- mtllib | ||
412 | case L.break (=='\n') $ next 2 bs of | ||
413 | (fnn,bs') -> do | ||
414 | let slurp fnn = case L.break (=='.') fnn of | ||
415 | (fn,ext) | L.null (L.drop 1 ext) -> if L.null fn then [] | ||
416 | else [fn] | ||
417 | | ".mtl" <- L.take 4 ext -> | ||
418 | if L.all isSpace (L.take 1 $ L.drop 4 ext) | ||
419 | then (fn <> ".mtl") : slurp (findToken args $ L.drop 4 ext) | ||
420 | else let f:fs = slurp (L.drop 3 ext) in (fn <> L.take 3 ext <> f) : fs | ||
421 | | otherwise -> let (f:fs) = slurp (L.drop 1 ext) | ||
422 | in (fn <> L.take 1 ext <> f) : fs | ||
423 | mtllib builder (map L.toStrict $ slurp fnn) | ||
424 | parseOBJ builder args bs' | ||
425 | -- TODO: call,csh,step,bmat,c_interp,d_interp,lod,shadow_obj,trace_obj,bevel | ||
426 | _ -> badToken builder bs | ||
427 | where | ||
428 | bs = findToken args bs0 | ||
429 | next n xs = nextToken (findToken args) $ L.drop n xs | ||
430 | parseChar c tok cont = case L.uncons tok of | ||
431 | Just (x,cs) | x==c -> cont True $ next 0 cs | ||
432 | _ -> cont False tok | ||
433 | parseV build n = do | ||
434 | parseFloats (findToken args) (L.drop n bs) $ \vs bs' -> do | ||
435 | build builder vs | ||
436 | parseOBJ builder args bs' | ||
437 | parseI build n = do | ||
438 | parseInts (findToken args) (L.drop n bs) $ \vs bs' -> do | ||
439 | build builder vs | ||
440 | parseOBJ builder args bs' | ||
441 | parseT build n = do | ||
442 | parseTriples (findToken args) (L.drop n bs) $ \vs bs' -> do | ||
443 | build builder vs | ||
444 | parseOBJ builder args bs' | ||
445 | parseOffOrNumber tok cont = parseIntsN 1 (findToken args) tok $ \is bs' -> do | ||
446 | let (sg,bs'') = case is of | ||
447 | (i:_) -> (i,bs') | ||
448 | _ | lengthLessThan 2 tok -> (0,tok) | ||
449 | _ -> (if L.index tok 1 == 'f' then 0 else 1, next 1 tok) | ||
450 | cont sg bs'' | ||
diff --git a/wavefront-obj.cabal b/wavefront-obj.cabal index 717ab5f..612d6f5 100644 --- a/wavefront-obj.cabal +++ b/wavefront-obj.cabal | |||
@@ -48,6 +48,7 @@ library | |||
48 | , Codec.Wavefront.Face | 48 | , Codec.Wavefront.Face |
49 | , Codec.Wavefront.FreeForm | 49 | , Codec.Wavefront.FreeForm |
50 | , Codec.Wavefront.Token | 50 | , Codec.Wavefront.Token |
51 | , Wavefront | ||
51 | -- other-modules: | 52 | -- other-modules: |
52 | other-extensions: ForeignFunctionInterface | 53 | other-extensions: ForeignFunctionInterface |
53 | , UnicodeSyntax | 54 | , UnicodeSyntax |
@@ -85,5 +86,9 @@ library | |||
85 | , lens >=4.16 && <4.17 | 86 | , lens >=4.16 && <4.17 |
86 | , transformers >=0.5 && <0.6 | 87 | , transformers >=0.5 && <0.6 |
87 | , mtl >=2.2 && <2.3 | 88 | , mtl >=2.2 && <2.3 |
89 | , bytestring | ||
90 | , bytestring-lexing | ||
91 | , pretty-show | ||
92 | |||
88 | hs-source-dirs: src | 93 | hs-source-dirs: src |
89 | default-language: Haskell2010 | 94 | default-language: Haskell2010 |