diff options
author | Joe Crayne <joe@jerkface.net> | 2019-07-18 17:19:18 -0400 |
---|---|---|
committer | Joe Crayne <joe@jerkface.net> | 2019-07-18 17:19:26 -0400 |
commit | 8d6b40691b6b40687c2a461baa0c22d14e125224 (patch) | |
tree | 9e1e33531b1910fe263231d425ea6b43473825b0 | |
parent | bf3001c4c4577cf5c65e05a21a3e9502dbe0b834 (diff) |
LoadMesh: support multiple mtllib files.
-rw-r--r-- | LoadMesh.hs | 36 |
1 files changed, 26 insertions, 10 deletions
diff --git a/LoadMesh.hs b/LoadMesh.hs index b970f3e..cda6349 100644 --- a/LoadMesh.hs +++ b/LoadMesh.hs | |||
@@ -20,7 +20,7 @@ import qualified Data.Map as Map | |||
20 | import qualified Data.Vector as V | 20 | import qualified Data.Vector as V |
21 | import qualified Data.ByteString as SB | 21 | import qualified Data.ByteString as SB |
22 | import qualified Data.ByteString.Lazy.Char8 as L | 22 | import qualified Data.ByteString.Lazy.Char8 as L |
23 | import Data.Text (unpack,Text) | 23 | import Data.Text (unpack,Text,pack) |
24 | import Data.List (groupBy,nub) | 24 | import Data.List (groupBy,nub) |
25 | import Numeric.LinearAlgebra hiding ((<>),Element) | 25 | import Numeric.LinearAlgebra hiding ((<>),Element) |
26 | import System.FilePath | 26 | import System.FilePath |
@@ -33,12 +33,12 @@ import Mask | |||
33 | 33 | ||
34 | data MaterialMesh m = MaterialMesh | 34 | data MaterialMesh m = MaterialMesh |
35 | { materialMesh :: m | 35 | { materialMesh :: m |
36 | , materialName :: Maybe Text | 36 | , materialName :: Maybe (Int,Text) |
37 | , materialMasks :: Map Text Mask | 37 | , materialMasks :: Map Text Mask |
38 | } | 38 | } |
39 | 39 | ||
40 | type MeshData = ( [MaterialMesh Mesh] -- List of uniform-material meshes (and the name of the material). | 40 | type MeshData = ( [MaterialMesh Mesh] -- List of uniform-material meshes (and the name of the material). |
41 | , ( MtlLib -- Material definitions. | 41 | , ( V.Vector MtlLib -- Material definitions. |
42 | , FilePath ) -- Path to wavefront obj file. | 42 | , FilePath ) -- Path to wavefront obj file. |
43 | ) | 43 | ) |
44 | 44 | ||
@@ -50,7 +50,7 @@ loadOBJ :: String -> IO (Either String MeshData) | |||
50 | loadOBJ fname = L.readFile fname >>= \bs -> do | 50 | loadOBJ fname = L.readFile fname >>= \bs -> do |
51 | let obj@OBJ{..} = parse bs | 51 | let obj@OBJ{..} = parse bs |
52 | -- load materials | 52 | -- load materials |
53 | mtlLib <- mconcat . V.toList <$> mapM (readMtlWithFallback . relativeFrom fname . unpack) objMtlLibs | 53 | mtlLib <- mapM (readMtlWithFallback . relativeFrom fname . unpack) objMtlLibs |
54 | return $ Right (objToMesh obj,(mtlLib,fname)) | 54 | return $ Right (objToMesh obj,(mtlLib,fname)) |
55 | 55 | ||
56 | 56 | ||
@@ -107,9 +107,13 @@ scaleWithin meshbb scalebb = | |||
107 | in tr1 <> sc <> tr0 | 107 | in tr1 <> sc <> tr0 |
108 | else ident 4 | 108 | else ident 4 |
109 | 109 | ||
110 | transV3 :: Matrix Float -> V3 Float -> V3 Float | ||
110 | transV3 t (V3 x y z) = let v = t #> fromList [x,y,z,1] in V3 (v!0/v!3) (v!1/v!3) (v!2/v!3) | 111 | transV3 t (V3 x y z) = let v = t #> fromList [x,y,z,1] in V3 (v!0/v!3) (v!1/v!3) (v!2/v!3) |
112 | |||
113 | transV4 :: Matrix Float -> V4 Float -> V4 Float | ||
111 | transV4 t (V4 x y z w) = let v = t #> fromList [x,y,z,w] in V4 (v!0) (v!1) (v!2) (v!3) | 114 | transV4 t (V4 x y z w) = let v = t #> fromList [x,y,z,w] in V4 (v!0) (v!1) (v!2) (v!3) |
112 | 115 | ||
116 | tranformAttribute :: Matrix Float -> MeshAttribute -> MeshAttribute | ||
113 | tranformAttribute t (A_V3F v) = A_V3F $ transV3 t <$> v | 117 | tranformAttribute t (A_V3F v) = A_V3F $ transV3 t <$> v |
114 | tranformAttribute t (A_V4F v) = A_V4F $ transV4 t <$> v | 118 | tranformAttribute t (A_V4F v) = A_V4F $ transV4 t <$> v |
115 | 119 | ||
@@ -122,15 +126,18 @@ uploadOBJToGPU :: Maybe BoundingBox -> MeshData -> IO ([MaterialMesh GPUMesh],Ma | |||
122 | uploadOBJToGPU scalebb (subModels,(mtlLib,objpath)) = do | 126 | uploadOBJToGPU scalebb (subModels,(mtlLib,objpath)) = do |
123 | let meshbb = foldMap (attribBoundingBox . mAttributes . materialMesh) subModels :: BoundingBox | 127 | let meshbb = foldMap (attribBoundingBox . mAttributes . materialMesh) subModels :: BoundingBox |
124 | m = maybe (ident 4) (scaleWithin meshbb) scalebb | 128 | m = maybe (ident 4) (scaleWithin meshbb) scalebb |
129 | -- BoundingBox {minX = -6.44698, maxX = 6.44698, minY = 0.0, maxY = 1.0e9, minZ = -0.768655, maxZ = 1.0e8} | ||
130 | -- BoundingBox {minX = -6.44698, maxX = 6.44698, minY = 0.0, maxY = 18.2027, minZ = -0.768655, maxZ = 2.238049} | ||
131 | putStrLn $ show meshbb | ||
125 | gpuSubModels <- forM subModels $ \matmesh -> do | 132 | gpuSubModels <- forM subModels $ \matmesh -> do |
126 | a <- LambdaCubeGL.uploadMeshToGPU (transformMesh m (materialMesh matmesh)) | 133 | a <- LambdaCubeGL.uploadMeshToGPU (transformMesh m (materialMesh matmesh)) |
127 | return matmesh { materialMesh = a } | 134 | return matmesh { materialMesh = a } |
128 | return (gpuSubModels,m) | 135 | return (gpuSubModels,m) |
129 | 136 | ||
130 | uploadMtlLib :: (MtlLib,FilePath) -> IO (Map Text (ObjMaterial,TextureData)) | 137 | uploadMtlLib :: (V.Vector MtlLib,FilePath) -> IO (V.Vector (Map Text (ObjMaterial,TextureData))) |
131 | uploadMtlLib (mtlLib,objpath) = do | 138 | uploadMtlLib (mtlLib,objpath) = do |
132 | -- collect used textures | 139 | -- collect used textures |
133 | let usedTextures = nub . concatMap (maybeToList . mtl_map_Kd) $ Map.elems mtlLib | 140 | let usedTextures = nub . concatMap (maybeToList . mtl_map_Kd) $ concatMap Map.elems $ V.toList mtlLib |
134 | whiteImage = Juicy.ImageRGB8 $ Juicy.generateImage (\_ _ -> Juicy.PixelRGB8 255 255 255) 1 1 | 141 | whiteImage = Juicy.ImageRGB8 $ Juicy.generateImage (\_ _ -> Juicy.PixelRGB8 255 255 255) 1 1 |
135 | checkerImage = Juicy.ImageRGB8 $ Juicy.generateImage (\x y -> if mod (x + y) 2 == 0 then Juicy.PixelRGB8 0 0 0 else Juicy.PixelRGB8 255 255 0) 2 2 | 142 | checkerImage = Juicy.ImageRGB8 $ Juicy.generateImage (\x y -> if mod (x + y) 2 == 0 then Juicy.PixelRGB8 0 0 0 else Juicy.PixelRGB8 255 255 0) 2 2 |
136 | checkerTex <- LC.uploadTexture2DToGPU checkerImage | 143 | checkerTex <- LC.uploadTexture2DToGPU checkerImage |
@@ -140,7 +147,7 @@ uploadMtlLib (mtlLib,objpath) = do | |||
140 | Right img -> LC.uploadTexture2DToGPU img | 147 | Right img -> LC.uploadTexture2DToGPU img |
141 | whiteTex <- LC.uploadTexture2DToGPU whiteImage | 148 | whiteTex <- LC.uploadTexture2DToGPU whiteImage |
142 | -- pair textures and materials | 149 | -- pair textures and materials |
143 | return $ (\a -> (a, maybe whiteTex (fromMaybe checkerTex . flip Map.lookup textureLib) . mtl_map_Kd $ a)) <$> mtlLib | 150 | return $ fmap (\a -> (a, maybe whiteTex (fromMaybe checkerTex . flip Map.lookup textureLib) . mtl_map_Kd $ a)) <$> mtlLib |
144 | 151 | ||
145 | objToMesh :: WavefrontOBJ -> [MaterialMesh Mesh] | 152 | objToMesh :: WavefrontOBJ -> [MaterialMesh Mesh] |
146 | objToMesh OBJ{..} = [ toMesh faceGroup | faceGroup <- faces ] | 153 | objToMesh OBJ{..} = [ toMesh faceGroup | faceGroup <- faces ] |
@@ -197,16 +204,25 @@ objSpan obj = case Map.elems (objAttributes obj) of | |||
197 | _ -> Mask [(0,1)] | 204 | _ -> Mask [(0,1)] |
198 | 205 | ||
199 | 206 | ||
207 | searchMaterial :: V.Vector (Map Text (ObjMaterial, TextureData)) | ||
208 | -> (Int, Text) | ||
209 | -> Maybe (ObjMaterial, TextureData) | ||
210 | searchMaterial mtlLib (count,name) = foldr go id (V.drop (V.length mtlLib - count) mtlLib) Nothing | ||
211 | where | ||
212 | go m f r = case Map.lookup name m of | ||
213 | Nothing -> f r | ||
214 | x -> x :: Maybe (ObjMaterial,TextureData) | ||
200 | 215 | ||
201 | addOBJToObjectArray :: GLStorage -> String -> [MaterialMesh GPUMesh] -> Map Text (ObjMaterial,TextureData) | 216 | addOBJToObjectArray :: GLStorage -> String -> [MaterialMesh GPUMesh] -> V.Vector (Map Text (ObjMaterial,TextureData)) |
202 | -> IO [MaskableObject] | 217 | -> IO [MaskableObject] |
203 | addOBJToObjectArray storage slotName objMesh mtlLib = forM objMesh $ \matmesh -> do | 218 | addOBJToObjectArray storage slotName objMesh mtlLib = forM objMesh $ \matmesh -> do |
204 | obj <- LambdaCubeGL.addMeshToObjectArray storage slotName ["diffuseTexture","diffuseColor"] (materialMesh matmesh) | 219 | obj <- LambdaCubeGL.addMeshToObjectArray storage slotName ["diffuseTexture","diffuseColor"] (materialMesh matmesh) |
205 | -- diffuseTexture and diffuseColor values can change on each model | 220 | -- diffuseTexture and diffuseColor values can change on each model |
206 | case (materialName matmesh) >>= flip Map.lookup mtlLib of | 221 | case materialName matmesh >>= searchMaterial mtlLib of |
207 | Nothing -> return () | 222 | Nothing -> return () |
208 | Just (ObjMaterial{..},t) -> LC.updateObjectUniforms obj $ do | 223 | Just (ObjMaterial{..},t) -> LC.updateObjectUniforms obj $ do |
209 | "diffuseTexture" @= return t -- set model's diffuse texture | 224 | "diffuseTexture" @= return t -- set model's diffuse texture |
210 | "diffuseColor" @= let (r,g,b) = mtl_Kd in return (V4 r g b mtl_Tr) | 225 | "diffuseColor" @= let (r,g,b) = mtl_Kd in return (V4 r g b mtl_Tr) |
211 | let matmask = maybe Map.empty (`Map.singleton` objSpan obj) (fmap ("m:" <>) $ materialName matmesh) | 226 | let matmask = maybe Map.empty (`Map.singleton` objSpan obj) |
227 | (fmap (\(c,n) -> "m:" <> pack (show c) <> ":" <> n) $ materialName matmesh) | ||
212 | return $ MaskableObject obj (matmask `Map.union` materialMasks matmesh) | 228 | return $ MaskableObject obj (matmask `Map.union` materialMasks matmesh) |