diff options
Diffstat (limited to 'src/Wavefront.hs')
-rw-r--r-- | src/Wavefront.hs | 84 |
1 files changed, 71 insertions, 13 deletions
diff --git a/src/Wavefront.hs b/src/Wavefront.hs index cae6508..3c4eff0 100644 --- a/src/Wavefront.hs +++ b/src/Wavefront.hs | |||
@@ -1,4 +1,5 @@ | |||
1 | {-# LANGUAGE FlexibleContexts #-} | 1 | {-# LANGUAGE FlexibleContexts #-} |
2 | {-# LANGUAGE RankNTypes #-} | ||
2 | module Wavefront where | 3 | module Wavefront where |
3 | 4 | ||
4 | import Wavefront.Types | 5 | import Wavefront.Types |
@@ -60,7 +61,9 @@ objBookKeeping builder = (lift Rank2.<$> builder) | |||
60 | incrementCount objFaces $ \x o -> o { objFaces = x } | 61 | incrementCount objFaces $ \x o -> o { objFaces = x } |
61 | } | 62 | } |
62 | 63 | ||
64 | -- TODO: meshlab vertex colors extension | ||
63 | mkv :: [Double] -> Location | 65 | mkv :: [Double] -> Location |
66 | mkv [x,y,z,r,g,b] = Location x' y' z' 1 where (x':y':z':_) = map realToFrac [x,y,z] | ||
64 | mkv cs = Location x y z w where (x:y:z:w:_) = map realToFrac cs ++ repeat 1 | 67 | mkv cs = Location x y z w where (x:y:z:w:_) = map realToFrac cs ++ repeat 1 |
65 | 68 | ||
66 | mkt :: [Double] -> TexCoord | 69 | mkt :: [Double] -> TexCoord |
@@ -79,45 +82,94 @@ mkF (RefTriple a at an) = FaceIndex a at an | |||
79 | elemental :: Element () -> x -> Element x | 82 | elemental :: Element () -> x -> Element x |
80 | elemental element x = fmap (const x) element | 83 | elemental element x = fmap (const x) element |
81 | 84 | ||
82 | modifyFirst :: MonadState (c, d) m => (c -> c) -> m () | 85 | modifyFirst :: MonadState ParserState m => (OBJ DList -> OBJ DList) -> m () |
83 | modifyFirst = modify' . first | 86 | modifyFirst = modify' . (\f s -> s { pstObj = f (pstObj s) }) |
84 | 87 | ||
85 | buildOBJ :: ObjBuilder (State (OBJ DList,Element ())) | 88 | modifySecond :: MonadState ParserState m => (Element () -> Element ()) -> m () |
89 | modifySecond = modify' . (\f s -> s { pstElm = f (pstElm s) }) | ||
90 | |||
91 | (*.*) :: (OBJ DList -> a) -> (Element () -> b) -> ParserState -> (a, b) | ||
92 | fld *.* elm = \s -> (fld (pstObj s), elm (pstElm s)) | ||
93 | |||
94 | data FFPts = Curv Float Float [Int] | ||
95 | | Curv2 [Int] | ||
96 | | Surf Float Float Float Float [RefTriple] | ||
97 | |||
98 | data FreeForm = FreeForm | ||
99 | { ffRat :: Bool | ||
100 | , ffTyp :: CSType | ||
101 | , ffDeg :: (Int,Int) | ||
102 | , ffPts :: FFPts | ||
103 | } | ||
104 | |||
105 | initFF :: FreeForm | ||
106 | initFF = FreeForm | ||
107 | { ffRat = False | ||
108 | , ffTyp = Bspline | ||
109 | , ffDeg = (1,1) | ||
110 | , ffPts = Curv2 [] | ||
111 | } | ||
112 | |||
113 | mkcurv2 :: FreeForm -> EmbeddedCurve | ||
114 | mkcurv2 ff = EmbeddedCurve | ||
115 | |||
116 | mkcurv :: FreeForm -> Curve | ||
117 | mkcurv ff = Curve | ||
118 | |||
119 | mksurf :: FreeForm -> Surface | ||
120 | mksurf ff = Surface | ||
121 | |||
122 | addFreeForm :: (forall x. x -> Element x) -> FreeForm -> OBJ DList -> OBJ DList | ||
123 | addFreeForm elm ff o = case ffPts ff of | ||
124 | Curv2 {} -> o { objEmbeddedCurves = objEmbeddedCurves o `DList.snoc` mkcurv2 ff } | ||
125 | Curv {} -> o { objCurves = objCurves o `DList.snoc` elm (mkcurv ff) } | ||
126 | Surf {} -> o { objSurfaces = objSurfaces o `DList.snoc` elm (mksurf ff) } | ||
127 | |||
128 | data ParserState = ParserState | ||
129 | { pstObj :: OBJ DList | ||
130 | , pstElm :: Element () | ||
131 | , pstFF :: FreeForm | ||
132 | } | ||
133 | |||
134 | buildOBJ :: ObjBuilder (State ParserState) | ||
86 | buildOBJ = nullBuilder | 135 | buildOBJ = nullBuilder |
87 | { vertex = \xs -> modifyFirst $ \o -> o { objLocations = objLocations o `DList.snoc` mkv xs } | 136 | { vertex = \xs -> modifyFirst $ \o -> o { objLocations = objLocations o `DList.snoc` mkv xs } |
88 | , vertexT = \xs -> modifyFirst $ \o -> o { objTexCoords = objTexCoords o `DList.snoc` mkt xs } | 137 | , vertexT = \xs -> modifyFirst $ \o -> o { objTexCoords = objTexCoords o `DList.snoc` mkt xs } |
89 | , vertexN = \xs -> modifyFirst $ \o -> o { objNormals = objNormals o `DList.snoc` mkn xs } | 138 | , vertexN = \xs -> modifyFirst $ \o -> o { objNormals = objNormals o `DList.snoc` mkn xs } |
90 | , points = \xs -> do | 139 | , points = \xs -> do |
91 | let p = map Point xs :: [Point] | 140 | let p = map Point xs :: [Point] |
92 | (pts,element) <- gets (objPoints *** elemental) | 141 | (pts,element) <- gets (objPoints *.* elemental) |
93 | modifyFirst $ \o -> o { objPoints = pts `DList.append` fmap element (DList.fromList p) } | 142 | modifyFirst $ \o -> o { objPoints = pts `DList.append` fmap element (DList.fromList p) } |
94 | , line = \xs -> do | 143 | , line = \xs -> do |
95 | (lns,element) <- gets (objLines *** elemental) | 144 | (lns,element) <- gets (objLines *.* elemental) |
96 | let l = zipWith mkl xs (tail xs) | 145 | let l = zipWith mkl xs (tail xs) |
97 | -- Line requires at least two points. We'll ignore it otherwise. | 146 | -- Line requires at least two points. We'll ignore it otherwise. |
98 | when (not $ null l) $ | 147 | when (not $ null l) $ |
99 | modifyFirst $ \o -> o { objLines = lns `DList.append` fmap element (DList.fromList l) } | 148 | modifyFirst $ \o -> o { objLines = lns `DList.append` fmap element (DList.fromList l) } |
100 | , face = \xs -> do | 149 | , face = \xs -> do |
101 | (fcs,element) <- gets (objFaces *** elemental) | 150 | (fcs,element) <- gets (objFaces *.* elemental) |
102 | case map mkF xs of | 151 | case map mkF xs of |
103 | a:b:c:ds -> modifyFirst $ \o -> o { objFaces = fcs `DList.snoc` element (Face a b c ds) } | 152 | a:b:c:ds -> modifyFirst $ \o -> o { objFaces = fcs `DList.snoc` element (Face a b c ds) } |
104 | _ -> return () -- Ignore faces with less than 3 indices. | 153 | _ -> return () -- Ignore faces with less than 3 indices. |
105 | , mtllib = \xs -> do | 154 | , mtllib = \xs -> do |
106 | let l = map decodeUtf8 xs | 155 | let l = map decodeUtf8 xs |
107 | libs <- gets (objMtlLibs . fst) | 156 | libs <- gets (objMtlLibs . pstObj) |
108 | modifyFirst $ \o -> o { objMtlLibs = DList.fromList l `DList.append` libs } | 157 | modifyFirst $ \o -> o { objMtlLibs = DList.fromList l `DList.append` libs } |
109 | , groups = \xs -> do | 158 | , groups = \xs -> do |
110 | let g = map decodeUtf8 xs | 159 | let g = map decodeUtf8 xs |
111 | modify' $ second $ \e -> e { elGroups = g } | 160 | modifySecond $ \e -> e { elGroups = g } |
112 | , objectName = \x -> do | 161 | , objectName = \x -> do |
113 | let o = decodeUtf8 x | 162 | let o = decodeUtf8 x |
114 | modify' $ second $ \e -> e { elObject = Just o } | 163 | modifySecond $ \e -> e { elObject = Just o } |
115 | , usemtl = \x -> do | 164 | , usemtl = \x -> do |
116 | let mtl = decodeUtf8 x | 165 | let mtl = decodeUtf8 x |
117 | libs <- DList.toList <$> gets (objMtlLibs . fst) | 166 | libs <- DList.toList <$> gets (objMtlLibs . pstObj) |
118 | modify' $ second $ \e -> e { elMtl = Just (length libs,mtl) } | 167 | modifySecond $ \e -> e { elMtl = Just (length libs,mtl) } |
119 | , smoothingGroup = \x -> when (x > 0) $ do | 168 | , smoothingGroup = \x -> when (x > 0) $ do |
120 | modify $ second $ \e -> e { elSmoothingGroup = fromIntegral x } | 169 | modifySecond $ \e -> e { elSmoothingGroup = fromIntegral x } |
170 | , endFreeForm = | ||
171 | modify' $ \s -> s { pstObj = addFreeForm (elemental $ pstElm s) (pstFF s) (pstObj s) | ||
172 | , pstFF = initFF } | ||
121 | } | 173 | } |
122 | 174 | ||
123 | blankElement :: Element () | 175 | blankElement :: Element () |
@@ -134,9 +186,12 @@ emptyCounts = OBJ | |||
134 | { objLocations = Count 0 | 186 | { objLocations = Count 0 |
135 | , objTexCoords = Count 0 | 187 | , objTexCoords = Count 0 |
136 | , objNormals = Count 0 | 188 | , objNormals = Count 0 |
189 | , objEmbeddedCurves = Count 0 | ||
137 | , objPoints = Count 0 | 190 | , objPoints = Count 0 |
138 | , objLines = Count 0 | 191 | , objLines = Count 0 |
139 | , objFaces = Count 0 | 192 | , objFaces = Count 0 |
193 | , objCurves = Count 0 | ||
194 | , objSurfaces = Count 0 | ||
140 | , objMtlLibs = Count 0 | 195 | , objMtlLibs = Count 0 |
141 | } | 196 | } |
142 | 197 | ||
@@ -145,9 +200,12 @@ mzeroOBJ = OBJ | |||
145 | { objLocations = mzero | 200 | { objLocations = mzero |
146 | , objTexCoords = mzero | 201 | , objTexCoords = mzero |
147 | , objNormals = mzero | 202 | , objNormals = mzero |
203 | , objEmbeddedCurves = mzero | ||
148 | , objPoints = mzero | 204 | , objPoints = mzero |
149 | , objLines = mzero | 205 | , objLines = mzero |
150 | , objFaces = mzero | 206 | , objFaces = mzero |
207 | , objCurves = mzero | ||
208 | , objSurfaces = mzero | ||
151 | , objMtlLibs = mzero | 209 | , objMtlLibs = mzero |
152 | } | 210 | } |
153 | 211 | ||
@@ -155,7 +213,7 @@ parse :: L.ByteString -> OBJ Vector | |||
155 | parse bs = Rank2.fmap (Vector.fromList . DList.toList) obj | 213 | parse bs = Rank2.fmap (Vector.fromList . DList.toList) obj |
156 | where | 214 | where |
157 | go = parseCustom buildOBJ (const $ return ()) bs | 215 | go = parseCustom buildOBJ (const $ return ()) bs |
158 | (obj,_) = execState go (mzeroOBJ,blankElement) | 216 | ParserState { pstObj = obj } = execState go (ParserState mzeroOBJ blankElement initFF) |
159 | 217 | ||
160 | parseCustom :: Monad m => ObjBuilder m -> (OBJ Count -> m b) -> L.ByteString -> m b | 218 | parseCustom :: Monad m => ObjBuilder m -> (OBJ Count -> m b) -> L.ByteString -> m b |
161 | parseCustom builder finish bs = do | 219 | parseCustom builder finish bs = do |