From 8d6b40691b6b40687c2a461baa0c22d14e125224 Mon Sep 17 00:00:00 2001 From: Joe Crayne Date: Thu, 18 Jul 2019 17:19:18 -0400 Subject: LoadMesh: support multiple mtllib files. --- LoadMesh.hs | 36 ++++++++++++++++++++++++++---------- 1 file 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 import qualified Data.Vector as V import qualified Data.ByteString as SB import qualified Data.ByteString.Lazy.Char8 as L -import Data.Text (unpack,Text) +import Data.Text (unpack,Text,pack) import Data.List (groupBy,nub) import Numeric.LinearAlgebra hiding ((<>),Element) import System.FilePath @@ -33,12 +33,12 @@ import Mask data MaterialMesh m = MaterialMesh { materialMesh :: m - , materialName :: Maybe Text + , materialName :: Maybe (Int,Text) , materialMasks :: Map Text Mask } type MeshData = ( [MaterialMesh Mesh] -- List of uniform-material meshes (and the name of the material). - , ( MtlLib -- Material definitions. + , ( V.Vector MtlLib -- Material definitions. , FilePath ) -- Path to wavefront obj file. ) @@ -50,7 +50,7 @@ loadOBJ :: String -> IO (Either String MeshData) loadOBJ fname = L.readFile fname >>= \bs -> do let obj@OBJ{..} = parse bs -- load materials - mtlLib <- mconcat . V.toList <$> mapM (readMtlWithFallback . relativeFrom fname . unpack) objMtlLibs + mtlLib <- mapM (readMtlWithFallback . relativeFrom fname . unpack) objMtlLibs return $ Right (objToMesh obj,(mtlLib,fname)) @@ -107,9 +107,13 @@ scaleWithin meshbb scalebb = in tr1 <> sc <> tr0 else ident 4 +transV3 :: Matrix Float -> V3 Float -> V3 Float 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) + +transV4 :: Matrix Float -> V4 Float -> V4 Float 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) +tranformAttribute :: Matrix Float -> MeshAttribute -> MeshAttribute tranformAttribute t (A_V3F v) = A_V3F $ transV3 t <$> v tranformAttribute t (A_V4F v) = A_V4F $ transV4 t <$> v @@ -122,15 +126,18 @@ uploadOBJToGPU :: Maybe BoundingBox -> MeshData -> IO ([MaterialMesh GPUMesh],Ma uploadOBJToGPU scalebb (subModels,(mtlLib,objpath)) = do let meshbb = foldMap (attribBoundingBox . mAttributes . materialMesh) subModels :: BoundingBox m = maybe (ident 4) (scaleWithin meshbb) scalebb + -- BoundingBox {minX = -6.44698, maxX = 6.44698, minY = 0.0, maxY = 1.0e9, minZ = -0.768655, maxZ = 1.0e8} + -- BoundingBox {minX = -6.44698, maxX = 6.44698, minY = 0.0, maxY = 18.2027, minZ = -0.768655, maxZ = 2.238049} + putStrLn $ show meshbb gpuSubModels <- forM subModels $ \matmesh -> do a <- LambdaCubeGL.uploadMeshToGPU (transformMesh m (materialMesh matmesh)) return matmesh { materialMesh = a } return (gpuSubModels,m) -uploadMtlLib :: (MtlLib,FilePath) -> IO (Map Text (ObjMaterial,TextureData)) +uploadMtlLib :: (V.Vector MtlLib,FilePath) -> IO (V.Vector (Map Text (ObjMaterial,TextureData))) uploadMtlLib (mtlLib,objpath) = do -- collect used textures - let usedTextures = nub . concatMap (maybeToList . mtl_map_Kd) $ Map.elems mtlLib + let usedTextures = nub . concatMap (maybeToList . mtl_map_Kd) $ concatMap Map.elems $ V.toList mtlLib whiteImage = Juicy.ImageRGB8 $ Juicy.generateImage (\_ _ -> Juicy.PixelRGB8 255 255 255) 1 1 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 checkerTex <- LC.uploadTexture2DToGPU checkerImage @@ -140,7 +147,7 @@ uploadMtlLib (mtlLib,objpath) = do Right img -> LC.uploadTexture2DToGPU img whiteTex <- LC.uploadTexture2DToGPU whiteImage -- pair textures and materials - return $ (\a -> (a, maybe whiteTex (fromMaybe checkerTex . flip Map.lookup textureLib) . mtl_map_Kd $ a)) <$> mtlLib + return $ fmap (\a -> (a, maybe whiteTex (fromMaybe checkerTex . flip Map.lookup textureLib) . mtl_map_Kd $ a)) <$> mtlLib objToMesh :: WavefrontOBJ -> [MaterialMesh Mesh] objToMesh OBJ{..} = [ toMesh faceGroup | faceGroup <- faces ] @@ -197,16 +204,25 @@ objSpan obj = case Map.elems (objAttributes obj) of _ -> Mask [(0,1)] +searchMaterial :: V.Vector (Map Text (ObjMaterial, TextureData)) + -> (Int, Text) + -> Maybe (ObjMaterial, TextureData) +searchMaterial mtlLib (count,name) = foldr go id (V.drop (V.length mtlLib - count) mtlLib) Nothing + where + go m f r = case Map.lookup name m of + Nothing -> f r + x -> x :: Maybe (ObjMaterial,TextureData) -addOBJToObjectArray :: GLStorage -> String -> [MaterialMesh GPUMesh] -> Map Text (ObjMaterial,TextureData) +addOBJToObjectArray :: GLStorage -> String -> [MaterialMesh GPUMesh] -> V.Vector (Map Text (ObjMaterial,TextureData)) -> IO [MaskableObject] addOBJToObjectArray storage slotName objMesh mtlLib = forM objMesh $ \matmesh -> do obj <- LambdaCubeGL.addMeshToObjectArray storage slotName ["diffuseTexture","diffuseColor"] (materialMesh matmesh) -- diffuseTexture and diffuseColor values can change on each model - case (materialName matmesh) >>= flip Map.lookup mtlLib of + case materialName matmesh >>= searchMaterial mtlLib of Nothing -> return () Just (ObjMaterial{..},t) -> LC.updateObjectUniforms obj $ do "diffuseTexture" @= return t -- set model's diffuse texture "diffuseColor" @= let (r,g,b) = mtl_Kd in return (V4 r g b mtl_Tr) - let matmask = maybe Map.empty (`Map.singleton` objSpan obj) (fmap ("m:" <>) $ materialName matmesh) + let matmask = maybe Map.empty (`Map.singleton` objSpan obj) + (fmap (\(c,n) -> "m:" <> pack (show c) <> ":" <> n) $ materialName matmesh) return $ MaskableObject obj (matmask `Map.union` materialMasks matmesh) -- cgit v1.2.3