diff options
author | Joe Crayne <joe@jerkface.net> | 2019-04-17 18:39:12 -0400 |
---|---|---|
committer | Joe Crayne <joe@jerkface.net> | 2019-04-17 18:41:18 -0400 |
commit | 395f3b525090097c88434b03c88fe2fb8b8d7aba (patch) | |
tree | 0f60388ddd09bc69e7257be32959e95574a73a73 /LoadMesh.hs | |
parent | 64f1a100fc887fb2a8bc87e2ac6975e872010ef5 (diff) |
Refactored object-loading demo.
Diffstat (limited to 'LoadMesh.hs')
-rw-r--r-- | LoadMesh.hs | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/LoadMesh.hs b/LoadMesh.hs new file mode 100644 index 0000000..69e66d6 --- /dev/null +++ b/LoadMesh.hs | |||
@@ -0,0 +1,75 @@ | |||
1 | {-# LANGUAGE LambdaCase #-} | ||
2 | {-# LANGUAGE RecordWildCards #-} | ||
3 | module LoadMesh where | ||
4 | |||
5 | import LambdaCube.GL as LambdaCubeGL -- renderer | ||
6 | import LambdaCube.GL.Mesh as LambdaCubeGL | ||
7 | import MtlParser | ||
8 | |||
9 | import Control.Monad | ||
10 | import Data.Maybe | ||
11 | import Data.Map (Map) | ||
12 | import qualified Data.Map as Map | ||
13 | import qualified Data.Vector as V | ||
14 | import qualified Data.ByteString as SB | ||
15 | import Data.Text (unpack,Text) | ||
16 | import Data.List (groupBy,nub) | ||
17 | |||
18 | import Codec.Picture as Juicy | ||
19 | import Codec.Wavefront | ||
20 | import Data.Aeson | ||
21 | |||
22 | type MeshData = ([(Mesh,Maybe Text)],MtlLib) | ||
23 | |||
24 | loadOBJ :: String -> IO (Either String MeshData) | ||
25 | loadOBJ fname = fromFile fname >>= \case -- load geometry | ||
26 | Left err -> putStrLn err >> return (Left err) | ||
27 | Right obj@WavefrontOBJ{..} -> do | ||
28 | -- load materials | ||
29 | mtlLib <- mconcat . V.toList <$> mapM (readMtl . unpack) objMtlLibs | ||
30 | return $ Right (objToMesh obj,mtlLib) | ||
31 | |||
32 | uploadOBJToGPU :: MeshData -> IO ([(GPUMesh, Maybe Text)], MtlLib) | ||
33 | uploadOBJToGPU (subModels,mtlLib) = do | ||
34 | gpuSubModels <- forM subModels $ \(mesh,mat) -> LambdaCubeGL.uploadMeshToGPU mesh >>= \a -> return (a,mat) | ||
35 | return (gpuSubModels,mtlLib) | ||
36 | |||
37 | uploadMtlLib :: MtlLib -> IO (Map Text (ObjMaterial,TextureData)) | ||
38 | uploadMtlLib mtlLib = do | ||
39 | -- collect used textures | ||
40 | let usedTextures = nub . concatMap (maybeToList . mtl_map_Kd) $ Map.elems mtlLib | ||
41 | whiteImage = Juicy.ImageRGB8 $ Juicy.generateImage (\_ _ -> Juicy.PixelRGB8 255 255 255) 1 1 | ||
42 | 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 | ||
43 | checkerTex <- LambdaCubeGL.uploadTexture2DToGPU checkerImage | ||
44 | -- load images and upload to gpu | ||
45 | textureLib <- forM (Map.fromList $ zip usedTextures usedTextures) $ \fname -> Juicy.readImage fname >>= \case | ||
46 | Left err -> putStrLn err >> return checkerTex | ||
47 | Right img -> LambdaCubeGL.uploadTexture2DToGPU img | ||
48 | whiteTex <- LambdaCubeGL.uploadTexture2DToGPU whiteImage | ||
49 | -- pair textures and materials | ||
50 | return $ (\a -> (a, maybe whiteTex (fromMaybe checkerTex . flip Map.lookup textureLib) . mtl_map_Kd $ a)) <$> mtlLib | ||
51 | |||
52 | objToMesh :: WavefrontOBJ -> [(Mesh,Maybe Text)] | ||
53 | objToMesh WavefrontOBJ{..} = [(toMesh faceGroup, elMtl . head $ faceGroup) | faceGroup <- faces] where | ||
54 | faces = groupBy (\a b -> elMtl a == elMtl b) (V.toList objFaces) | ||
55 | toMesh l = Mesh | ||
56 | { mAttributes = Map.fromList | ||
57 | [ ("position", A_V4F position) | ||
58 | , ("normal", A_V3F normal) | ||
59 | , ("uvw", A_V3F texcoord) | ||
60 | ] | ||
61 | , mPrimitive = P_Triangles | ||
62 | } where | ||
63 | triangulate (Triangle a b c) = [a,b,c] | ||
64 | triangulate (Quad a b c d) = [a,b,c, c,d,a] | ||
65 | triangulate (Face a b c l) = a : b : c : concatMap (\(x,y) -> [a,x,y]) (zip (c:l) l) -- should work for convex polygons without holes | ||
66 | defaultPosition = Location 0 0 0 0 | ||
67 | defaultNormal = Normal 0 0 0 | ||
68 | defaultTexCoord = TexCoord 0 0 0 | ||
69 | v !- i = v V.!? (i-1) | ||
70 | toVertex FaceIndex{..} = ( let Location x y z w = fromMaybe defaultPosition (objLocations !- faceLocIndex) in V4 x y z w | ||
71 | , let Normal x y z = fromMaybe defaultNormal ((objNormals !-) =<< faceNorIndex) in V3 x y z | ||
72 | , let TexCoord x y z = fromMaybe defaultTexCoord ((objTexCoords !-) =<< faceTexCoordIndex) in V3 x y z | ||
73 | ) | ||
74 | (position,normal,texcoord) = V.unzip3 . V.concat . map (V.fromList . map toVertex . triangulate . elValue) $ l | ||
75 | |||