Added extra Shape features
Getty Ritter
8 years ago
1 | 1 | {-# LANGUAGE RecordWildCards #-} |
2 | 2 | {-# LANGUAGE BinaryLiterals #-} |
3 | {-# LANGUAGE MultiWayIf #-} | |
3 | 4 | |
4 | 5 | module Graphics.HVIF |
5 | 6 | ( |
23 | 24 | , PathRef(..) |
24 | 25 | , StyleRef(..) |
25 | 26 | , ShapeFlags(..) |
27 | , Translation(..) | |
28 | , LodScale(..) | |
26 | 29 | ) where |
27 | 30 | |
28 | 31 | import Control.Monad (replicateM, when) |
118 | 121 | , shapePaths :: Seq PathRef |
119 | 122 | , shapeFlags :: ShapeFlags |
120 | 123 | , shapeTransform :: Maybe Matrix |
124 | , shapeTranslate :: Maybe Translation | |
125 | , shapeLodScale :: Maybe LodScale | |
126 | , shapeTransList :: Seq Transformer | |
121 | 127 | } deriving (Eq, Show) |
122 | 128 | |
123 | 129 | type Matrix = Seq Float |
133 | 139 | , sfTranslation :: Bool |
134 | 140 | } deriving (Eq, Show) |
135 | 141 | |
142 | data Translation = Translation | |
143 | { transX :: Float | |
144 | , transY :: Float | |
145 | } deriving (Eq, Show) | |
146 | ||
147 | data LodScale = LodScale | |
148 | { lsMin :: Float | |
149 | , lsMax :: Float | |
150 | } deriving (Eq, Show) | |
151 | ||
152 | data Transformer | |
153 | = TransformerAffine Matrix | |
154 | | TransformerContour Float Word8 Word8 | |
155 | | TransformerPerspective -- Not fully supported, I think? | |
156 | | TransformerStroke Float Word8 Word8 Word8 | |
157 | deriving (Eq, Show) | |
158 | ||
136 | 159 | -- Decoding code |
137 | 160 | |
138 | 161 | getSeveral :: Get a -> Get (Seq a) |
144 | 167 | pFile = do |
145 | 168 | header <- getByteString 4 |
146 | 169 | when (header /= "ncif") $ |
147 |
fail "Missing ` |
|
170 | fail "Missing `ncif' header" | |
148 | 171 | hvifColors <- getSeveral pStyle |
149 | 172 | hvifPaths <- getSeveral pPath |
150 | 173 | hvifShapes <- getSeveral pShape |
161 | 184 | 0x03 -> ColorSolidNoAlpha <$> get <*> get <*> get |
162 | 185 | 0x04 -> ColorSolidGray <$> get <*> get |
163 | 186 | 0x05 -> ColorSolidGrayNoAlpha <$> get |
164 |
_ -> |
|
187 | _ -> getWord16be >> fail "invalid" | |
165 | 188 | |
166 | 189 | pGradient :: Get Gradient |
167 | 190 | pGradient = do |
278 | 301 | else |
279 | 302 | return (fromIntegral b1 - 32.0) |
280 | 303 | |
304 | ifFlag :: Bool -> Get a -> Get (Maybe a) | |
305 | ifFlag True m = Just <$> m | |
306 | ifFlag False _ = pure Nothing | |
307 | ||
281 | 308 | pShape :: Get Shape |
282 | 309 | pShape = do |
283 | 310 | sType <- getWord8 |
286 | 313 | shapeStyle <- StyleRef <$> get |
287 | 314 | shapePaths <- getSeveral (PathRef <$> get) |
288 | 315 | shapeFlags <- pShapeFlags |
289 | shapeTransform <- | |
290 | if sfTransform shapeFlags | |
291 | then Just <$> pMatrix | |
292 | else return Nothing | |
316 | shapeTransform <- ifFlag (sfTransform shapeFlags) $ | |
317 | pMatrix | |
318 | shapeTranslate <- ifFlag (sfTranslation shapeFlags) $ | |
319 | Translation <$> pCoord <*> pCoord | |
320 | shapeLodScale <- ifFlag (sfLodScale shapeFlags) $ | |
321 | pLodScale | |
322 | shapeTransList <- getSeveral pTransformer | |
293 | 323 | return Shape { .. } |
294 | 324 | |
295 | 325 | pShapeFlags :: Get ShapeFlags |
323 | 353 | then return 0.0 |
324 | 354 | else castToFloat val |
325 | 355 | |
326 | ||
327 | 356 | castToFloat :: Word32 -> Get Float |
328 | 357 | castToFloat w32 = |
329 | 358 | let bs = encode w32 |
330 | 359 | in case runGet getFloat32be bs of |
331 | 360 | Left err -> fail err |
332 | 361 | Right x -> return x |
362 | ||
363 | pLodScale :: Get LodScale | |
364 | pLodScale = do | |
365 | minS <- fromIntegral <$> getWord8 | |
366 | maxS <- fromIntegral <$> getWord8 | |
367 | return LodScale | |
368 | { lsMin = minS / 63.75 | |
369 | , lsMax = maxS / 63.75 | |
370 | } | |
371 | ||
372 | pTransformer :: Get Transformer | |
373 | pTransformer = do | |
374 | tType <- getWord8 | |
375 | case tType of | |
376 | 20 -> TransformerAffine <$> pMatrix | |
377 | 21 -> do | |
378 | width <- fromIntegral <$> getWord8 | |
379 | lineJoin <- getWord8 | |
380 | miterLimit <- getWord8 | |
381 | return (TransformerContour (width - 128.0) lineJoin miterLimit) | |
382 | 22 -> pure TransformerPerspective | |
383 | 23 -> do | |
384 | width <- fromIntegral <$> getWord8 | |
385 | lineOptions <- getWord8 | |
386 | miterLimit <- getWord8 | |
387 | let lineJoin = lineOptions .&. 15 | |
388 | lineCap = lineOptions `shift` 4 | |
389 | return (TransformerStroke (width - 128.0) lineJoin lineCap miterLimit) | |
390 | _ -> fail ("Unknown transformer type: " ++ show tType) |