diff options
Diffstat (limited to 'src/Graphics/WaveFront/Load.hs')
-rw-r--r-- | src/Graphics/WaveFront/Load.hs | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/src/Graphics/WaveFront/Load.hs b/src/Graphics/WaveFront/Load.hs new file mode 100644 index 0000000..6d65693 --- /dev/null +++ b/src/Graphics/WaveFront/Load.hs | |||
@@ -0,0 +1,108 @@ | |||
1 | -- | | ||
2 | -- Module : Graphics.WaveFront.Load | ||
3 | -- Description : Loading (and perhaps writing) OBJ and MTL files | ||
4 | -- Copyright : (c) Jonatan H Sundqvist, 2015 | ||
5 | -- License : MIT | ||
6 | -- Maintainer : Jonatan H Sundqvist | ||
7 | -- Stability : experimental|stable | ||
8 | -- Portability : POSIX (not sure) | ||
9 | -- | ||
10 | |||
11 | -- Created July 26 2015 | ||
12 | |||
13 | -- TODO | - Logging | ||
14 | -- - | ||
15 | |||
16 | -- SPEC | - | ||
17 | -- - | ||
18 | |||
19 | |||
20 | |||
21 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
22 | -- GHC Extensions | ||
23 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
24 | {-# LANGUAGE UnicodeSyntax #-} | ||
25 | -- {-# LANGUAGE TupleSections #-} | ||
26 | |||
27 | |||
28 | |||
29 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
30 | -- API | ||
31 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
32 | -- TODO | - Decide on an API | ||
33 | module Graphics.WaveFront.Load ( | ||
34 | obj, mtl, materials, model | ||
35 | ) where | ||
36 | |||
37 | |||
38 | |||
39 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
40 | -- We'll need these | ||
41 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
42 | import System.FilePath (splitFileName, takeDirectory, (</>)) | ||
43 | |||
44 | import Data.Text (Text) | ||
45 | import qualified Data.Text as T | ||
46 | import qualified Data.Text.IO as T | ||
47 | import Data.Vector (Vector) | ||
48 | |||
49 | import Control.Applicative ((<$>)) | ||
50 | import Control.Monad.Trans.Except | ||
51 | import Control.Monad.Trans.Class (lift) | ||
52 | |||
53 | import qualified Data.Attoparsec.Text as Atto | ||
54 | |||
55 | import Graphics.WaveFront.Types | ||
56 | import qualified Graphics.WaveFront.Parse as Parse | ||
57 | import qualified Graphics.WaveFront.Parse.Common as Parse | ||
58 | import Graphics.WaveFront.Model (createMTLTable, createModel) | ||
59 | |||
60 | |||
61 | |||
62 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
63 | -- Functions (IO) | ||
64 | -------------------------------------------------------------------------------------------------------------------------------------------- | ||
65 | |||
66 | -- Loading data ---------------------------------------------------------------------------------------------------------------------------- | ||
67 | |||
68 | -- | | ||
69 | -- TODO | - Use bytestrings (?) | ||
70 | -- - Deal with IO and parsing errors | ||
71 | obj :: (Fractional f, Integral i) => String -> IO (Either String (OBJ f Text i [])) | ||
72 | obj fn = runExceptT $ do | ||
73 | lift $ putStrLn $ "Loading obj file: " ++ fn | ||
74 | ExceptT $ Atto.parseOnly (Parse.wholeFile Parse.obj) <$> T.readFile fn | ||
75 | |||
76 | |||
77 | -- | | ||
78 | -- TODO | - Use bytestrings (?) | ||
79 | -- - Merge OBJ and MTL parsers (and plug in format-specific code as needed) (?) | ||
80 | -- - Deal with IO and parsing errors | ||
81 | mtl :: (Fractional f) => String -> IO (Either String (MTL f Text [])) | ||
82 | mtl fn = do | ||
83 | putStrLn $ "Loading mtl file: " ++ fn | ||
84 | Atto.parseOnly (Parse.wholeFile Parse.mtl) <$> T.readFile fn | ||
85 | |||
86 | |||
87 | -- | | ||
88 | -- TODO | - Better names (than 'mtls' and 'fns') (?) | ||
89 | -- - Refactor, simplify | ||
90 | -- - Improve path handling (cf. '</>') | ||
91 | -- - Graceful error handling | ||
92 | materials :: (Fractional f) => [FilePath] -> IO (Either String (MTLTable f Text)) | ||
93 | materials fns = runExceptT $ do | ||
94 | tokens <- mapM (ExceptT . mtl) fns | ||
95 | ExceptT . return $ createTableFromMTLs tokens | ||
96 | where | ||
97 | createTableFromMTLs :: [[MTLToken f Text]] -> Either String (MTLTable f Text) | ||
98 | createTableFromMTLs = createMTLTable . zip (map (T.pack . snd . splitFileName) fns) | ||
99 | |||
100 | |||
101 | -- | Loads an OBJ model from file, including associated materials | ||
102 | -- TODO | - Graceful error handling | ||
103 | model :: (Fractional f, Integral i) => FilePath -> IO (Either String (Model f Text i Vector)) | ||
104 | model fn = runExceptT $ do | ||
105 | obj <- ExceptT $ obj fn | ||
106 | materials <- ExceptT $ materials [ fst (splitFileName fn) </> T.unpack name | LibMTL name <- obj ] | ||
107 | ExceptT . return $ createModel obj materials (Just $ takeDirectory fn) | ||
108 | -- where loadWithName name = mtl name >>= return . (name,) | ||