diff options
Diffstat (limited to 'examples/MtlParser.hs')
-rw-r--r-- | examples/MtlParser.hs | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/examples/MtlParser.hs b/examples/MtlParser.hs new file mode 100644 index 0000000..b57a7f0 --- /dev/null +++ b/examples/MtlParser.hs | |||
@@ -0,0 +1,74 @@ | |||
1 | module MtlParser | ||
2 | ( ObjMaterial (..) | ||
3 | , MtlLib | ||
4 | , parseMtl | ||
5 | , readMtl | ||
6 | ) where | ||
7 | |||
8 | import Data.Map (Map) | ||
9 | import qualified Data.Map as Map | ||
10 | import Data.Maybe | ||
11 | import Control.Monad.State.Strict | ||
12 | import Control.Monad.Writer | ||
13 | import Data.Text (pack,Text) | ||
14 | |||
15 | type Vec3 = (Float,Float,Float) | ||
16 | |||
17 | type MtlLib = Map Text ObjMaterial | ||
18 | |||
19 | data ObjMaterial | ||
20 | = ObjMaterial | ||
21 | { mtl_Name :: Text | ||
22 | , mtl_Ka :: Vec3 -- ambient color | ||
23 | , mtl_Kd :: Vec3 -- diffuse color | ||
24 | , mtl_Ks :: Vec3 -- specular color | ||
25 | , mtl_illum :: Int | ||
26 | , mtl_Tr :: Float -- transparency | ||
27 | , mtl_Ns :: Float -- specular exponent | ||
28 | , mtl_map_Kd :: Maybe String -- diffuse texture file name | ||
29 | } | ||
30 | deriving (Eq,Show) | ||
31 | |||
32 | newMaterial name = ObjMaterial | ||
33 | { mtl_Name = name | ||
34 | , mtl_Ka = (1, 1, 1) | ||
35 | , mtl_Kd = (1, 1, 1) | ||
36 | , mtl_Ks = (0, 0, 0) | ||
37 | , mtl_illum = 1 | ||
38 | , mtl_Tr = 1 | ||
39 | , mtl_Ns = 0 | ||
40 | , mtl_map_Kd = Nothing | ||
41 | } | ||
42 | |||
43 | type Mtl = WriterT [ObjMaterial] (State (Maybe ObjMaterial)) | ||
44 | |||
45 | readMaybe :: Read a => String -> Maybe a | ||
46 | readMaybe s = case reads s of | ||
47 | [(val, "")] -> Just val | ||
48 | _ -> Nothing | ||
49 | |||
50 | readVec3 :: String -> String -> String -> Maybe Vec3 | ||
51 | readVec3 r g b = (,,) <$> readMaybe r <*> readMaybe g <*> readMaybe b | ||
52 | |||
53 | setAttr = modify' . fmap | ||
54 | addMaterial = gets maybeToList >>= tell | ||
55 | |||
56 | parseLine :: String -> Mtl () | ||
57 | parseLine s = case words $ takeWhile (/='#') s of | ||
58 | ["newmtl",name] -> do | ||
59 | addMaterial | ||
60 | put $ Just $ newMaterial $ pack name | ||
61 | ["map_Kd",textureName] -> setAttr (\s -> s {mtl_map_Kd = Just textureName}) | ||
62 | ["Ka",r,g,b] | Just rgb <- readVec3 r g b -> setAttr (\s -> s {mtl_Ka = rgb}) | ||
63 | ["Kd",r,g,b] | Just rgb <- readVec3 r g b -> setAttr (\s -> s {mtl_Kd = rgb}) | ||
64 | ["Ks",r,g,b] | Just rgb <- readVec3 r g b -> setAttr (\s -> s {mtl_Ks = rgb}) | ||
65 | ["illum",a] | Just v <- readMaybe a -> setAttr (\s -> s {mtl_illum = v}) | ||
66 | ["Tr",a] | Just v <- readMaybe a -> setAttr (\s -> s {mtl_Tr = v}) | ||
67 | ["Ns",a] | Just v <- readMaybe a -> setAttr (\s -> s {mtl_Ns = v}) | ||
68 | _ -> return () | ||
69 | |||
70 | parseMtl :: String -> MtlLib | ||
71 | parseMtl src = Map.fromList [(mtl_Name m,m) | m <- evalState (execWriterT (mapM_ parseLine (lines src) >> addMaterial)) Nothing] | ||
72 | |||
73 | readMtl :: String -> IO MtlLib | ||
74 | readMtl fname = parseMtl <$> readFile fname | ||