packages feed

gltf-loader 0.1.0.0 → 0.2.0.0

raw patch · 15 files changed

+812/−245 lines, 15 filesdep +microlens-platformPVP ok

version bump matches the API change (PVP)

Dependencies added: microlens-platform

API changes (from Hackage documentation)

- Text.GLTF.Loader.BufferAccessor: getByte :: Get Int8
- Text.GLTF.Loader.BufferAccessor: getFloat :: Get Float
- Text.GLTF.Loader.BufferAccessor: getIndices :: Get [Int]
- Text.GLTF.Loader.BufferAccessor: getMat2 :: Get a -> Get [M22 a]
- Text.GLTF.Loader.BufferAccessor: getMat3 :: Get a -> Get [M33 a]
- Text.GLTF.Loader.BufferAccessor: getMat4 :: Get a -> Get [M44 a]
- Text.GLTF.Loader.BufferAccessor: getPositions :: Get [V3 Float]
- Text.GLTF.Loader.BufferAccessor: getScalar :: Get a -> Get [a]
- Text.GLTF.Loader.BufferAccessor: getShort :: Get Int16
- Text.GLTF.Loader.BufferAccessor: getUnsignedByte :: Get Word8
- Text.GLTF.Loader.BufferAccessor: getUnsignedInt :: Get Word32
- Text.GLTF.Loader.BufferAccessor: getUnsignedShort :: Get Word16
- Text.GLTF.Loader.BufferAccessor: getVec2 :: Get a -> Get [V2 a]
- Text.GLTF.Loader.BufferAccessor: getVec3 :: Get a -> Get [V3 a]
- Text.GLTF.Loader.BufferAccessor: getVec4 :: Get a -> Get [V4 a]
+ Text.GLTF.Loader.Adapter: adaptAlphaMode :: MaterialAlphaMode -> MaterialAlphaMode
+ Text.GLTF.Loader.Adapter: adaptMaterial :: Material -> Material
+ Text.GLTF.Loader.Adapter: adaptMaterials :: Maybe (Vector Material) -> Vector Material
+ Text.GLTF.Loader.Adapter: adaptPbrMetallicRoughness :: PbrMetallicRoughness -> PbrMetallicRoughness
+ Text.GLTF.Loader.Adapter: attributeTexCoord :: Text
+ Text.GLTF.Loader.BufferAccessor: vertexTexCoords :: GlTF -> Vector GltfBuffer -> AccessorIx -> Vector (V2 Float)
+ Text.GLTF.Loader.Decoders: getByte :: Get Int8
+ Text.GLTF.Loader.Decoders: getFloat :: Get Float
+ Text.GLTF.Loader.Decoders: getIndices :: Get (Vector Int)
+ Text.GLTF.Loader.Decoders: getMat2 :: Get a -> Get (Vector (M22 a))
+ Text.GLTF.Loader.Decoders: getMat3 :: Get a -> Get (Vector (M33 a))
+ Text.GLTF.Loader.Decoders: getMat4 :: Get a -> Get (Vector (M44 a))
+ Text.GLTF.Loader.Decoders: getNormals :: Get (Vector (V3 Float))
+ Text.GLTF.Loader.Decoders: getPositions :: Get (Vector (V3 Float))
+ Text.GLTF.Loader.Decoders: getScalar :: Get a -> Get (Vector a)
+ Text.GLTF.Loader.Decoders: getShort :: Get Int16
+ Text.GLTF.Loader.Decoders: getTexCoords :: Get (Vector (V2 Float))
+ Text.GLTF.Loader.Decoders: getUnsignedByte :: Get Word8
+ Text.GLTF.Loader.Decoders: getUnsignedInt :: Get Word32
+ Text.GLTF.Loader.Decoders: getUnsignedShort :: Get Word16
+ Text.GLTF.Loader.Decoders: getVec2 :: Get a -> Get (Vector (V2 a))
+ Text.GLTF.Loader.Decoders: getVec3 :: Get a -> Get (Vector (V3 a))
+ Text.GLTF.Loader.Decoders: getVec4 :: Get a -> Get (Vector (V4 a))
+ Text.GLTF.Loader.Gltf: Blend :: MaterialAlphaMode
+ Text.GLTF.Loader.Gltf: Mask :: MaterialAlphaMode
+ Text.GLTF.Loader.Gltf: Material :: Float -> MaterialAlphaMode -> Bool -> V3 Float -> Maybe Text -> Maybe PbrMetallicRoughness -> Material
+ Text.GLTF.Loader.Gltf: Opaque :: MaterialAlphaMode
+ Text.GLTF.Loader.Gltf: PbrMetallicRoughness :: V4 Float -> Float -> Float -> PbrMetallicRoughness
+ Text.GLTF.Loader.Gltf: [gltfMaterials] :: Gltf -> Vector Material
+ Text.GLTF.Loader.Gltf: [materialAlphaCutoff] :: Material -> Float
+ Text.GLTF.Loader.Gltf: [materialAlphaMode] :: Material -> MaterialAlphaMode
+ Text.GLTF.Loader.Gltf: [materialDoubleSided] :: Material -> Bool
+ Text.GLTF.Loader.Gltf: [materialEmissiveFactor] :: Material -> V3 Float
+ Text.GLTF.Loader.Gltf: [materialName] :: Material -> Maybe Text
+ Text.GLTF.Loader.Gltf: [materialPbrMetallicRoughness] :: Material -> Maybe PbrMetallicRoughness
+ Text.GLTF.Loader.Gltf: [meshPrimitiveMaterial] :: MeshPrimitive -> Maybe Int
+ Text.GLTF.Loader.Gltf: [meshPrimitiveTexCoords] :: MeshPrimitive -> Vector (V2 Float)
+ Text.GLTF.Loader.Gltf: [pbrBaseColorFactor] :: PbrMetallicRoughness -> V4 Float
+ Text.GLTF.Loader.Gltf: [pbrMetallicFactor] :: PbrMetallicRoughness -> Float
+ Text.GLTF.Loader.Gltf: [pbrRoughnessFactor] :: PbrMetallicRoughness -> Float
+ Text.GLTF.Loader.Gltf: _materialAlphaCutoff :: Lens' Material Float
+ Text.GLTF.Loader.Gltf: _materialAlphaMode :: Lens' Material MaterialAlphaMode
+ Text.GLTF.Loader.Gltf: _materialDoubleSided :: Lens' Material Bool
+ Text.GLTF.Loader.Gltf: _materialEmissiveFactor :: Lens' Material (V3 Float)
+ Text.GLTF.Loader.Gltf: _materialName :: Lens' Material (Maybe Text)
+ Text.GLTF.Loader.Gltf: _materialPbrMetallicRoughness :: Lens' Material (Maybe PbrMetallicRoughness)
+ Text.GLTF.Loader.Gltf: _materials :: Lens' Gltf (Vector Material)
+ Text.GLTF.Loader.Gltf: _meshPrimitiveMaterial :: Lens' MeshPrimitive (Maybe Int)
+ Text.GLTF.Loader.Gltf: _pbrBaseColorFactor :: Lens' PbrMetallicRoughness (V4 Float)
+ Text.GLTF.Loader.Gltf: _pbrMetallicFactor :: Lens' PbrMetallicRoughness Float
+ Text.GLTF.Loader.Gltf: _pbrRoughnessFactor :: Lens' PbrMetallicRoughness Float
+ Text.GLTF.Loader.Gltf: data Material
+ Text.GLTF.Loader.Gltf: data MaterialAlphaMode
+ Text.GLTF.Loader.Gltf: data PbrMetallicRoughness
+ Text.GLTF.Loader.Gltf: instance GHC.Classes.Eq Text.GLTF.Loader.Gltf.Material
+ Text.GLTF.Loader.Gltf: instance GHC.Classes.Eq Text.GLTF.Loader.Gltf.MaterialAlphaMode
+ Text.GLTF.Loader.Gltf: instance GHC.Classes.Eq Text.GLTF.Loader.Gltf.PbrMetallicRoughness
+ Text.GLTF.Loader.Gltf: instance GHC.Enum.Enum Text.GLTF.Loader.Gltf.MaterialAlphaMode
+ Text.GLTF.Loader.Gltf: instance GHC.Show.Show Text.GLTF.Loader.Gltf.Material
+ Text.GLTF.Loader.Gltf: instance GHC.Show.Show Text.GLTF.Loader.Gltf.MaterialAlphaMode
+ Text.GLTF.Loader.Gltf: instance GHC.Show.Show Text.GLTF.Loader.Gltf.PbrMetallicRoughness
- Text.GLTF.Loader.Adapter: adaptMeshPrimitives :: GlTF -> Vector GltfBuffer -> Vector MeshPrimitive -> [MeshPrimitive]
+ Text.GLTF.Loader.Adapter: adaptMeshPrimitives :: GlTF -> Vector GltfBuffer -> Vector MeshPrimitive -> Vector MeshPrimitive
- Text.GLTF.Loader.Adapter: adaptMeshes :: GlTF -> Vector GltfBuffer -> Maybe (Vector Mesh) -> [Mesh]
+ Text.GLTF.Loader.Adapter: adaptMeshes :: GlTF -> Vector GltfBuffer -> Maybe (Vector Mesh) -> Vector Mesh
- Text.GLTF.Loader.Adapter: adaptNodes :: Maybe (Vector Node) -> [Node]
+ Text.GLTF.Loader.Adapter: adaptNodes :: Maybe (Vector Node) -> Vector Node
- Text.GLTF.Loader.BufferAccessor: vertexIndices :: GlTF -> Vector GltfBuffer -> AccessorIx -> [Int]
+ Text.GLTF.Loader.BufferAccessor: vertexIndices :: GlTF -> Vector GltfBuffer -> AccessorIx -> Vector Int
- Text.GLTF.Loader.BufferAccessor: vertexNormals :: GlTF -> Vector GltfBuffer -> AccessorIx -> [V3 Float]
+ Text.GLTF.Loader.BufferAccessor: vertexNormals :: GlTF -> Vector GltfBuffer -> AccessorIx -> Vector (V3 Float)
- Text.GLTF.Loader.BufferAccessor: vertexPositions :: GlTF -> Vector GltfBuffer -> AccessorIx -> [V3 Float]
+ Text.GLTF.Loader.BufferAccessor: vertexPositions :: GlTF -> Vector GltfBuffer -> AccessorIx -> Vector (V3 Float)
- Text.GLTF.Loader.Gltf: Gltf :: Asset -> [Mesh] -> [Node] -> Gltf
+ Text.GLTF.Loader.Gltf: Gltf :: Asset -> Vector Material -> Vector Mesh -> Vector Node -> Gltf
- Text.GLTF.Loader.Gltf: Mesh :: [MeshPrimitive] -> [Float] -> Maybe Text -> Mesh
+ Text.GLTF.Loader.Gltf: Mesh :: Vector MeshPrimitive -> Vector Float -> Maybe Text -> Mesh
- Text.GLTF.Loader.Gltf: MeshPrimitive :: MeshPrimitiveMode -> [Int] -> [V3 Float] -> [V3 Float] -> MeshPrimitive
+ Text.GLTF.Loader.Gltf: MeshPrimitive :: Vector Int -> Maybe Int -> MeshPrimitiveMode -> Vector (V3 Float) -> Vector (V3 Float) -> Vector (V2 Float) -> MeshPrimitive
- Text.GLTF.Loader.Gltf: [gltfMeshes] :: Gltf -> [Mesh]
+ Text.GLTF.Loader.Gltf: [gltfMeshes] :: Gltf -> Vector Mesh
- Text.GLTF.Loader.Gltf: [gltfNodes] :: Gltf -> [Node]
+ Text.GLTF.Loader.Gltf: [gltfNodes] :: Gltf -> Vector Node
- Text.GLTF.Loader.Gltf: [meshPrimitiveIndices] :: MeshPrimitive -> [Int]
+ Text.GLTF.Loader.Gltf: [meshPrimitiveIndices] :: MeshPrimitive -> Vector Int
- Text.GLTF.Loader.Gltf: [meshPrimitiveNormals] :: MeshPrimitive -> [V3 Float]
+ Text.GLTF.Loader.Gltf: [meshPrimitiveNormals] :: MeshPrimitive -> Vector (V3 Float)
- Text.GLTF.Loader.Gltf: [meshPrimitivePositions] :: MeshPrimitive -> [V3 Float]
+ Text.GLTF.Loader.Gltf: [meshPrimitivePositions] :: MeshPrimitive -> Vector (V3 Float)
- Text.GLTF.Loader.Gltf: [meshPrimitives] :: Mesh -> [MeshPrimitive]
+ Text.GLTF.Loader.Gltf: [meshPrimitives] :: Mesh -> Vector MeshPrimitive
- Text.GLTF.Loader.Gltf: [meshWeights] :: Mesh -> [Float]
+ Text.GLTF.Loader.Gltf: [meshWeights] :: Mesh -> Vector Float
- Text.GLTF.Loader.Gltf: _meshPrimitiveIndices :: Lens' MeshPrimitive [Int]
+ Text.GLTF.Loader.Gltf: _meshPrimitiveIndices :: Lens' MeshPrimitive (Vector Int)
- Text.GLTF.Loader.Gltf: _meshPrimitiveNormals :: Lens' MeshPrimitive [V3 Float]
+ Text.GLTF.Loader.Gltf: _meshPrimitiveNormals :: Lens' MeshPrimitive (Vector (V3 Float))
- Text.GLTF.Loader.Gltf: _meshPrimitivePositions :: Lens' MeshPrimitive [V3 Float]
+ Text.GLTF.Loader.Gltf: _meshPrimitivePositions :: Lens' MeshPrimitive (Vector (V3 Float))
- Text.GLTF.Loader.Gltf: _meshPrimitives :: Lens' Mesh [MeshPrimitive]
+ Text.GLTF.Loader.Gltf: _meshPrimitives :: Lens' Mesh (Vector MeshPrimitive)
- Text.GLTF.Loader.Gltf: _meshWeights :: Lens' Mesh [Float]
+ Text.GLTF.Loader.Gltf: _meshWeights :: Lens' Mesh (Vector Float)
- Text.GLTF.Loader.Gltf: _meshes :: Lens' Gltf [Mesh]
+ Text.GLTF.Loader.Gltf: _meshes :: Lens' Gltf (Vector Mesh)
- Text.GLTF.Loader.Gltf: _nodes :: Lens' Gltf [Node]
+ Text.GLTF.Loader.Gltf: _nodes :: Lens' Gltf (Vector Node)

Files

README.md view
@@ -57,19 +57,19 @@ Currently, only retreiving indices are supported, but we hope to support the majority of GlTF features: -[] Animitions-[] Asset-[] Cameras-[] Images-[] Materials-[x] Meshes-  [x] Positions-  [x] Indices-  [] Normals-  [] Texture Coordinates-[] Node-[] Samplers-[] Skins+ - [ ] Animitions+ - [ ] Asset+ - [ ] Cameras+ - [ ] Images+ - [ ] Materials+ - [x] Meshes+    - [x] Positions+    - [x] Indices+    - [ ] Normals+    - [ ] Texture Coordinates+ - [ ] Node+ - [ ] Samplers+ - [ ] Skins  ## Authors 
app/Command/GLTF/Loader/App.hs view
@@ -5,7 +5,8 @@  -- | Command line arguments data Options = Options-  { optionsVerbose :: !Bool,+  { optionsSummary :: !Bool,+    optionsVerbose :: !Bool,     optionsFile :: FilePath   } @@ -27,6 +28,11 @@  instance HasOptions App where   optionsL = lens appOptions (\app opts -> app { appOptions = opts })++_optionsSummary :: Lens' Options Bool+_optionsSummary = lens+  optionsSummary+  (\opts summary -> opts { optionsSummary = summary })  _optionsVerbose :: Lens' Options Bool _optionsVerbose = lens
app/Command/GLTF/Loader/Run.hs view
@@ -4,38 +4,64 @@ import Text.GLTF.Loader  import Lens.Micro-import Linear (V3(..))+import Lens.Micro.Platform ()+import Linear (V3(..), V4(..)) import RIO-import RIO.List (nub)+import qualified RIO.Vector.Boxed as Vector  run :: RIO App () run = do-  file <- asks $ view (optionsL . _optionsFile)-  logInfo $ "File: " <> fromString file+  options <- asks (^. optionsL)+  let file = options ^. _optionsFile+      summary = options ^. _optionsSummary+      verbose = options ^. _optionsVerbose +  logInfo $ "File: " <> fromString file   result <- liftIO $ fromFile file-  either reportError reportGltf result +  either reportError (reporter verbose summary) result++reporter :: Bool -> Bool -> (Gltf -> RIO App ())+reporter True _ = reportVerbose+reporter _ True = reportSummary+reporter _ _ = reportGltf+ reportError :: HasLogFunc logger => Errors -> RIO logger () reportError err   = logError (display err)   >> exitFailure +reportVerbose :: Gltf -> RIO App ()+reportVerbose gltf = do+  reportAsset $ gltf ^. _asset++  logInfo "" -- Blank line++  reportNodes gltf $ reportMeshVerbose gltf++reportSummary :: Gltf -> RIO App ()+reportSummary gltf = do+  reportAsset $ gltf ^. _asset+  +  logInfo "" -- Blank line++  reportNodes gltf reportMeshSummary+ reportGltf :: Gltf -> RIO App () reportGltf gltf = do   reportAsset $ gltf ^. _asset      logInfo "" -- Blank line -  reportNodes gltf+  reportNodes gltf $ reportMesh gltf  reportAsset :: Asset -> RIO App () reportAsset asset = do   logInfo $ "Generator: " <> asset ^. _assetGenerator . to (fromMaybe "Unknown") . to display   logInfo $ "Version: " <> asset ^. _assetVersion . to display -reportNodes :: Gltf -> RIO App ()-reportNodes gltf = do+reportNodes :: Gltf -> (Mesh -> RIO App ()) -> RIO App ()+reportNodes gltf meshReporter = do   let nodes = gltf ^. _nodes   logInfo $ "Nodes: " <> display (RIO.length nodes) @@ -44,20 +70,63 @@      forM_ (node ^. _nodeMeshId) $ \meshId -> do       logInfo "  Mesh: "-      forM_ (gltf ^. _meshes  ^? ix meshId) reportMesh-        +      forM_ (gltf ^. _meshes ^? ix meshId) meshReporter -reportMesh :: Mesh -> RIO App ()-reportMesh mesh = do+reportMeshVerbose :: Gltf -> Mesh -> RIO App ()+reportMeshVerbose gltf mesh = do   logInfo $ "    Name: " <> mesh ^. _meshName . to (display . fromMaybe "Unknown")   logInfo "    Mesh Primitives:"    forM_ (mesh ^. _meshPrimitives) $ \primitive' -> do+    -- Report Vertices+    logInfo "      Vertices:"++    let positions = primitive' ^. _meshPrimitivePositions+    forM_ (primitive' ^. _meshPrimitiveIndices) $ \index -> do+      forM_ (positions Vector.!? index) $ \position -> do+        logInfo $ "        [" <> display index <> "]: " <> displayV3 position++    -- Report material+    forM_ (primitive' ^. _meshPrimitiveMaterial) $ \materialId -> do+      forM_ (gltf ^. _materials . to (Vector.!? materialId)) reportMaterial+    +reportMesh :: Gltf -> Mesh -> RIO App ()+reportMesh gltf mesh = do+  logInfo $ "    Name: " <> mesh ^. _meshName . to (display . fromMaybe "Unknown")+  logInfo "    Mesh Primitives:"++  forM_ (mesh ^. _meshPrimitives) $ \primitive' -> do     logInfo "      Vertex Positions:" -    forM_ (nub $ primitive' ^. _meshPrimitivePositions) $ \position -> do+    forM_ (Vector.uniq $ primitive' ^. _meshPrimitivePositions) $ \position -> do       logInfo $ "        " <> displayV3 position++    -- Report material+    forM_ (primitive' ^. _meshPrimitiveMaterial) $ \materialId -> do+      forM_ (gltf ^. _materials . to (Vector.!? materialId)) reportMaterial++reportMeshSummary :: Mesh -> RIO App ()+reportMeshSummary mesh = do+  logInfo $ "    Name: " <> mesh ^. _meshName . to (display . fromMaybe "Unknown")++  let primitives' = mesh ^. _meshPrimitives+      vertices = Vector.concatMap (^. _meshPrimitivePositions) primitives'+      indices = Vector.concatMap (^. _meshPrimitiveIndices) primitives'++  logInfo $ "    Unique Vertices: " <> display (length vertices)+  logInfo $ "    Total Vertices: " <> display (length indices)++reportMaterial :: Material -> RIO App ()+reportMaterial material = do+  logInfo $ "      Material:"+  logInfo $ "        Name: " <>+    material ^. _materialName . to (display . fromMaybe "Unknown")   +  forM_ (material ^. _materialPbrMetallicRoughness) $ \pbr -> do+    logInfo $ "        Base Color Factor: " <> pbr ^. _pbrBaseColorFactor . to displayV4+    logInfo $ "        Metallic Factor: " <> pbr ^. _pbrMetallicFactor . to display+    logInfo $ "        Roughness Factor: " <> pbr ^. _pbrRoughnessFactor . to display+   displayV3 :: Display a => V3 a -> Utf8Builder displayV3 (V3 x y z)   = "("@@ -65,3 +134,13 @@   <> display y <> ", "   <> display z <>   ")"++displayV4 :: Display a => V4 a -> Utf8Builder+displayV4 (V4 w x y z)+  = "("+  <> display w <> ", "+  <> display x <> ", "+  <> display y <> ", "+  <> display z <>+  ")"+
app/Main.hs view
@@ -12,7 +12,7 @@ main :: IO () main = do   (options', _) <- parseOptions-  logOptions <- logOptionsHandle stderr (optionsVerbose options')+  logOptions <- logOptionsHandle stderr False   processContext <- mkDefaultProcessContext    runApp processContext options' logOptions run@@ -39,7 +39,16 @@           }  options :: Parser Options-options = Options <$> switch verboseOption <*> strArgument fileArg+options = Options+  <$> switch summaryOption+  <*> switch verboseOption+  <*> strArgument fileArg++summaryOption :: Mod FlagFields Bool+summaryOption+  = long "summary"+    <> short 's'+    <> help "Compact output?"  verboseOption :: Mod FlagFields Bool verboseOption
+ data/big-cube.gltf view

file too large to diff

gltf-loader.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack  name:           gltf-loader-version:        0.1.0.0+version:        0.2.0.0 synopsis:       High level GlTF loader description:    Please see the README on Github at <https://github.com/sgillespie/haskell-gltf-loader#readme> category:       Graphics@@ -19,6 +19,7 @@ build-type:     Simple extra-source-files:     README.md+    data/big-cube.gltf     data/cube.gltf     data/invalid.gltf @@ -31,6 +32,7 @@       Text.GLTF.Loader       Text.GLTF.Loader.Adapter       Text.GLTF.Loader.BufferAccessor+      Text.GLTF.Loader.Decoders       Text.GLTF.Loader.Errors       Text.GLTF.Loader.Gltf   other-modules:@@ -142,6 +144,7 @@     , gltf-loader     , linear     , microlens+    , microlens-platform     , optparse-simple     , rio >=0.1.12.0   default-language: Haskell2010
src/Text/GLTF/Loader.hs view
@@ -1,9 +1,14 @@+ module Text.GLTF.Loader-  ( fromByteString,+  ( -- * Scene loading functions     fromFile,-    -    module Text.GLTF.Loader.Errors,-    module Text.GLTF.Loader.Gltf+    fromByteString,++    -- * GLTF Types+    module Text.GLTF.Loader.Gltf,++    -- * Loading Errors+    module Text.GLTF.Loader.Errors   ) where  import Text.GLTF.Loader.Adapter@@ -14,20 +19,13 @@ import Data.Either import Lens.Micro import RIO-    ( Monad((>>=)),-      IsString(fromString),-      String,-      (<$>),-      (.),-      MonadIO(liftIO),-      MonadUnliftIO,-      ByteString,-      FilePath ) import qualified Codec.GlTF as GlTF +-- | Load a glTF scene from a ByteString fromByteString :: MonadUnliftIO io => ByteString -> io (Either Errors Gltf) fromByteString =  toGltfResult . GlTF.fromByteString +-- | Load a glTF scene from a file fromFile :: MonadUnliftIO io => FilePath -> io (Either Errors Gltf) fromFile path = liftIO (GlTF.fromFile path) >>= toGltfResult   
src/Text/GLTF/Loader/Adapter.hs view
@@ -2,12 +2,17 @@ module Text.GLTF.Loader.Adapter   ( attributePosition,     attributeNormal,+    attributeTexCoord,     adaptGltf,     adaptAsset,+    adaptMaterials,     adaptMeshes,     adaptNodes,+    adaptMaterial,     adaptMesh,     adaptNode,+    adaptAlphaMode,+    adaptPbrMetallicRoughness,     adaptMeshPrimitives,     adaptMeshPrimitive,     adaptMeshPrimitiveMode@@ -21,6 +26,8 @@ import RIO.Partial (toEnum) import qualified Codec.GlTF as GlTF import qualified Codec.GlTF.Asset as GlTF.Asset+import qualified Codec.GlTF.Material as GlTF.Material+import qualified Codec.GlTF.PbrMetallicRoughness as GlTF.PbrMetallicRoughness import qualified Codec.GlTF.Mesh as GlTF.Mesh import qualified Codec.GlTF.Node as GlTF.Node import qualified Data.HashMap.Strict as HashMap@@ -31,10 +38,13 @@ attributeNormal :: Text attributeNormal = "NORMAL" +attributeTexCoord :: Text+attributeTexCoord = "TEXCOORD_0"  adaptGltf :: GlTF.GlTF -> Vector GltfBuffer -> Gltf adaptGltf gltf@GlTF.GlTF{..} buffers' = Gltf     { gltfAsset = adaptAsset asset,+      gltfMaterials = adaptMaterials materials,       gltfMeshes = adaptMeshes gltf buffers' meshes,       gltfNodes = adaptNodes nodes     }@@ -47,16 +57,29 @@     assetMinVersion = minVersion   } +adaptMaterials :: Maybe (Vector GlTF.Material.Material) -> Vector Material+adaptMaterials = maybe mempty (fmap adaptMaterial)+ adaptMeshes   :: GlTF.GlTF   -> Vector GltfBuffer   -> Maybe (Vector GlTF.Mesh.Mesh)-  -> [Mesh]-adaptMeshes gltf buffers' = maybe [] (map (adaptMesh gltf buffers') . toList)+  -> Vector Mesh+adaptMeshes gltf buffers' = maybe mempty (fmap $ adaptMesh gltf buffers') -adaptNodes :: Maybe (Vector GlTF.Node.Node) -> [Node]-adaptNodes = maybe [] (map adaptNode . toList)+adaptNodes :: Maybe (Vector GlTF.Node.Node) -> Vector Node+adaptNodes = maybe mempty (fmap adaptNode) +adaptMaterial :: GlTF.Material.Material -> Material+adaptMaterial GlTF.Material.Material{..} = Material+  { materialAlphaCutoff = alphaCutoff,+    materialAlphaMode = adaptAlphaMode alphaMode,+    materialDoubleSided = doubleSided,+    materialEmissiveFactor = toV3 emissiveFactor,+    materialName = name,+    materialPbrMetallicRoughness = adaptPbrMetallicRoughness <$> pbrMetallicRoughness+  }+ adaptMesh   :: GlTF.GlTF   -> Vector GltfBuffer@@ -64,7 +87,7 @@   -> Mesh adaptMesh gltf buffers' GlTF.Mesh.Mesh{..} = Mesh     { meshPrimitives = adaptMeshPrimitives gltf buffers' primitives,-      meshWeights = maybe [] toList weights,+      meshWeights = fromMaybe mempty weights,       meshName = name     } @@ -78,12 +101,29 @@     nodeWeights = maybe [] toList weights   } +adaptAlphaMode :: GlTF.Material.MaterialAlphaMode -> MaterialAlphaMode+adaptAlphaMode GlTF.Material.BLEND = Blend+adaptAlphaMode GlTF.Material.MASK = Mask+adaptAlphaMode GlTF.Material.OPAQUE = Opaque+adaptAlphaMode (GlTF.Material.MaterialAlphaMode alphaMode)+  = error $ "Invalid MaterialAlphaMode: " <> show alphaMode++adaptPbrMetallicRoughness+  :: GlTF.PbrMetallicRoughness.PbrMetallicRoughness+  -> PbrMetallicRoughness+adaptPbrMetallicRoughness GlTF.PbrMetallicRoughness.PbrMetallicRoughness{..}+  = PbrMetallicRoughness+    { pbrBaseColorFactor = toV4 baseColorFactor,+      pbrMetallicFactor = metallicFactor,+      pbrRoughnessFactor = roughnessFactor+    }+ adaptMeshPrimitives   :: GlTF.GlTF   -> Vector GltfBuffer   -> Vector GlTF.Mesh.MeshPrimitive-  -> [MeshPrimitive]-adaptMeshPrimitives gltf buffers' = map (adaptMeshPrimitive gltf buffers') . toList+  -> Vector MeshPrimitive+adaptMeshPrimitives gltf = fmap . adaptMeshPrimitive gltf  adaptMeshPrimitive   :: GlTF.GlTF@@ -91,12 +131,17 @@   -> GlTF.Mesh.MeshPrimitive   -> MeshPrimitive adaptMeshPrimitive gltf buffers' GlTF.Mesh.MeshPrimitive{..} = MeshPrimitive-    { meshPrimitiveMode = adaptMeshPrimitiveMode mode,-      meshPrimitiveIndices = maybe [] (vertexIndices gltf buffers') indices,-      meshPrimitivePositions = maybe [] (vertexPositions gltf buffers') positions,-      meshPrimitiveNormals = []+    { meshPrimitiveIndices = maybe mempty (vertexIndices gltf buffers') indices,+      meshPrimitiveMaterial = GlTF.Material.unMaterialIx <$> material,+      meshPrimitiveMode = adaptMeshPrimitiveMode mode,+      meshPrimitiveNormals = maybe mempty (vertexNormals gltf buffers') normals,+      meshPrimitivePositions = maybe mempty (vertexPositions gltf buffers') positions,+      meshPrimitiveTexCoords = maybe mempty (vertexTexCoords gltf buffers') texCoords     }     where positions = attributes HashMap.!? attributePosition+          normals = attributes HashMap.!? attributeNormal+          texCoords = attributes HashMap.!? attributeTexCoord+            adaptMeshPrimitiveMode :: GlTF.Mesh.MeshPrimitiveMode -> MeshPrimitiveMode adaptMeshPrimitiveMode = toEnum . GlTF.Mesh.unMeshPrimitiveMode
src/Text/GLTF/Loader/BufferAccessor.hs view
@@ -6,27 +6,11 @@     vertexIndices,     vertexPositions,     vertexNormals,-    -- * Binary Get decoders-    -- ** Specific Type decoders-    getIndices,-    getPositions,-    -- ** GLTF Accessor Type decoders-    getScalar,-    getVec2,-    getVec3,-    getVec4,-    getMat2,-    getMat3,-    getMat4,-    -- ** GLTF Component Type decoders-    getByte,-    getUnsignedByte,-    getShort,-    getUnsignedShort,-    getUnsignedInt,-    getFloat+    vertexTexCoords,   ) where +import Text.GLTF.Loader.Decoders+ import Codec.GlTF.Accessor import Codec.GlTF.Buffer import Codec.GlTF.BufferView@@ -40,15 +24,18 @@ import qualified RIO.Vector as Vector import qualified RIO.ByteString as ByteString +-- | Holds the entire payload of a glTF buffer newtype GltfBuffer = GltfBuffer { unBuffer :: ByteString }   deriving (Eq, Show) +-- | A buffer and some metadata data BufferAccessor = BufferAccessor   { offset :: Int,     count :: Int,     buffer :: GltfBuffer   } +-- | Read all the buffers into memory loadBuffers :: MonadUnliftIO io => GlTF -> io (Vector GltfBuffer) loadBuffers GlTF{buffers=buffers} = do   let buffers' = fromMaybe [] buffers@@ -66,27 +53,36 @@          return $ GltfBuffer payload -vertexIndices :: GlTF -> Vector GltfBuffer -> AccessorIx -> [Int]+-- | Decode vertex indices+vertexIndices :: GlTF -> Vector GltfBuffer -> AccessorIx -> Vector Int vertexIndices = readBufferWithGet getIndices -vertexPositions :: GlTF -> Vector GltfBuffer -> AccessorIx -> [V3 Float]+-- | Decode vertex positions+vertexPositions :: GlTF -> Vector GltfBuffer -> AccessorIx -> Vector (V3 Float) vertexPositions = readBufferWithGet getPositions -vertexNormals :: GlTF -> Vector GltfBuffer -> AccessorIx -> [V3 Float]-vertexNormals = undefined+-- | Decode vertex normals+vertexNormals :: GlTF -> Vector GltfBuffer -> AccessorIx -> Vector (V3 Float)+vertexNormals = readBufferWithGet getNormals +-- | Decode texture coordinates. Note that we only use the first one.+vertexTexCoords :: GlTF -> Vector GltfBuffer -> AccessorIx -> Vector (V2 Float)+vertexTexCoords = readBufferWithGet getTexCoords++-- | Decode a buffer using the given Binary decoder readBufferWithGet   :: Storable storable-  => Get [storable]+  => Get (Vector storable)   -> GlTF   -> Vector GltfBuffer   -> AccessorIx-  -> [storable]+  -> Vector storable readBufferWithGet getter gltf buffers' accessorId-  = maybe []+  = maybe mempty       (readFromBuffer undefined getter)       (bufferAccessor gltf buffers' accessorId) +-- | Look up a Buffer from a GlTF and AccessorIx bufferAccessor   :: GlTF   -> Vector GltfBuffer@@ -106,131 +102,35 @@       buffer = buffer     } +-- | Look up a BufferView by Accessor lookupBufferViewFromAccessor :: Accessor -> Vector BufferView -> Maybe BufferView lookupBufferViewFromAccessor Accessor{..} bufferViews   = bufferView >>= flip lookupBufferView bufferViews +-- | Look up a Buffer by BufferView lookupBufferFromBufferView :: BufferView -> Vector GltfBuffer -> Maybe GltfBuffer lookupBufferFromBufferView BufferView{..} = lookupBuffer buffer +-- | Look up an Accessor by Ix lookupAccessor :: AccessorIx -> Vector Accessor -> Maybe Accessor lookupAccessor (AccessorIx accessorId) = (Vector.!? accessorId) +-- | Look up a BufferView by Ix lookupBufferView :: BufferViewIx -> Vector BufferView -> Maybe BufferView lookupBufferView (BufferViewIx bufferViewId) = (Vector.!? bufferViewId) +-- | Look up a Buffer by Ix lookupBuffer :: BufferIx -> Vector GltfBuffer -> Maybe GltfBuffer lookupBuffer (BufferIx bufferId) = (Vector.!? bufferId) +-- | Decode a buffer using the given Binary decoder readFromBuffer   :: Storable storable   => storable-  -> Get [storable]+  -> Get (Vector storable)   -> BufferAccessor-  -> [storable]+  -> Vector storable readFromBuffer storable getter BufferAccessor{..}   = runGet getter (fromStrict payload')   where payload' = ByteString.take len' . ByteString.drop offset . unBuffer $ buffer         len' = count * sizeOf storable--getIndices :: Get [Int]-getIndices = getScalar (fromIntegral <$> getUnsignedShort)--getPositions :: Get [V3 Float]-getPositions = getVec3 getFloat--getScalar :: Get a -> Get [a]-getScalar = getList--getVec2 :: Get a -> Get [V2 a]-getVec2 getter = getList $ V2 <$> getter <*> getter--getVec3 :: Get a -> Get [V3 a]-getVec3 getter = getList $ V3 <$> getter <*> getter <*> getter--getVec4 :: Get a -> Get [V4 a]-getVec4 getter = getList $ V4 <$> getter <*> getter <*> getter <*> getter--getMat2 :: Get a -> Get [M22 a]-getMat2 getter = getList $ do-  m1_1 <- getter-  m1_2 <- getter--  m2_1 <- getter-  m2_2 <- getter--  return $ V2-    (V2 m1_1 m2_1)-    (V2 m1_2 m2_2)--getMat3 :: Get a -> Get [M33 a]-getMat3 getter = getList $ do-  m1_1 <- getter-  m1_2 <- getter-  m1_3 <- getter-  -  m2_1 <- getter-  m2_2 <- getter-  m2_3 <- getter--  m3_1 <- getter-  m3_2 <- getter-  m3_3 <- getter--  return $ V3-    (V3 m1_1 m2_1 m3_1)-    (V3 m1_2 m2_2 m3_2)-    (V3 m1_3 m2_3 m3_3)--getMat4 :: Get a -> Get [M44 a]-getMat4 getter = getList $ do-  m1_1 <- getter-  m1_2 <- getter-  m1_3 <- getter-  m1_4 <- getter-  -  m2_1 <- getter-  m2_2 <- getter-  m2_3 <- getter-  m2_4 <- getter--  m3_1 <- getter-  m3_2 <- getter-  m3_3 <- getter-  m3_4 <- getter--  m4_1 <- getter-  m4_2 <- getter-  m4_3 <- getter-  m4_4 <- getter--  return $ V4-    (V4 m1_1 m2_1 m3_1 m4_1)-    (V4 m1_2 m2_2 m3_2 m4_2)-    (V4 m1_3 m2_3 m3_3 m4_3)-    (V4 m1_4 m2_4 m3_4 m4_4)--getByte :: Get Int8-getByte = getInt8--getUnsignedByte :: Get Word8-getUnsignedByte = getWord8--getShort :: Get Int16-getShort = getInt16le--getUnsignedShort :: Get Word16-getUnsignedShort = getWord16le--getUnsignedInt :: Get Word32-getUnsignedInt = getWord32le--getFloat :: Get Float-getFloat = getFloatle--getList :: Get a -> Get [a]-getList getter = do-  empty <- isEmpty-  if empty-    then return []-    else (:) <$> getter <*> getList getter
+ src/Text/GLTF/Loader/Decoders.hs view
@@ -0,0 +1,157 @@+module Text.GLTF.Loader.Decoders+  ( -- * GLTF Property-specific Type decoders+    getIndices,+    getPositions,+    getNormals,+    getTexCoords,+    -- * GLTF Accessor Type decoders+    getScalar,+    getVec2,+    getVec3,+    getVec4,+    getMat2,+    getMat3,+    getMat4,+    -- * GLTF Component Type decoders+    getByte,+    getUnsignedByte,+    getShort,+    getUnsignedShort,+    getUnsignedInt,+    getFloat+  ) where++import Data.Binary.Get+import Linear+import RIO hiding (min, max)+import qualified RIO.Vector as Vector++-- | Vertex indices binary decoder+getIndices :: Get (Vector Int)+getIndices = getScalar (fromIntegral <$> getUnsignedShort)++-- | Vertex positions binary decoder+getPositions :: Get (Vector (V3 Float))+getPositions = getVec3 getFloat++-- | Vertex normals binary decoder+getNormals :: Get (Vector (V3 Float))+getNormals = getVec3 getFloat++-- | Texture coordinates binary decoder+getTexCoords :: Get (Vector (V2 Float))+getTexCoords = getVec2 getFloat++-- | Scalar (simple) type binary decoder+getScalar :: Get a -> Get (Vector a)+getScalar = getVector++-- | 2D Vector binary decoder+getVec2 :: Get a -> Get (Vector (V2 a))+getVec2 getter = getVector $ V2 <$> getter <*> getter++-- | 3D Vector binary decoder+getVec3 :: Get a -> Get (Vector (V3 a))+getVec3 getter = getVector $ V3 <$> getter <*> getter <*> getter++-- | 4D Vector binary decoder+getVec4 :: Get a -> Get (Vector (V4 a))+getVec4 getter = getVector $ V4 <$> getter <*> getter <*> getter <*> getter++-- | 2x2 Matrix binary decoder+getMat2 :: Get a -> Get (Vector (M22 a))+getMat2 getter = getVector $ do+  m1_1 <- getter+  m1_2 <- getter++  m2_1 <- getter+  m2_2 <- getter++  return $ V2+    (V2 m1_1 m2_1)+    (V2 m1_2 m2_2)++-- | 3x3 Matrix binary decoder+getMat3 :: Get a -> Get (Vector (M33 a))+getMat3 getter = getVector $ do+  m1_1 <- getter+  m1_2 <- getter+  m1_3 <- getter+  +  m2_1 <- getter+  m2_2 <- getter+  m2_3 <- getter++  m3_1 <- getter+  m3_2 <- getter+  m3_3 <- getter++  return $ V3+    (V3 m1_1 m2_1 m3_1)+    (V3 m1_2 m2_2 m3_2)+    (V3 m1_3 m2_3 m3_3)++-- | 4x4 Matrix binary decoder+getMat4 :: Get a -> Get (Vector (M44 a))+getMat4 getter = getVector $ do+  m1_1 <- getter+  m1_2 <- getter+  m1_3 <- getter+  m1_4 <- getter+  +  m2_1 <- getter+  m2_2 <- getter+  m2_3 <- getter+  m2_4 <- getter++  m3_1 <- getter+  m3_2 <- getter+  m3_3 <- getter+  m3_4 <- getter++  m4_1 <- getter+  m4_2 <- getter+  m4_3 <- getter+  m4_4 <- getter++  return $ V4+    (V4 m1_1 m2_1 m3_1 m4_1)+    (V4 m1_2 m2_2 m3_2 m4_2)+    (V4 m1_3 m2_3 m3_3 m4_3)+    (V4 m1_4 m2_4 m3_4 m4_4)++-- | Byte binary decoder+getByte :: Get Int8+getByte = getInt8++-- | Unsigned Byte binary decoder+getUnsignedByte :: Get Word8+getUnsignedByte = getWord8++-- | Short binary decoder+getShort :: Get Int16+getShort = getInt16le++-- | Unsigned Short binary decoder+getUnsignedShort :: Get Word16+getUnsignedShort = getWord16le++-- | Unsigned Int binary decoder+getUnsignedInt :: Get Word32+getUnsignedInt = getWord32le++-- | Float binary decoder+getFloat :: Get Float+getFloat = getFloatle++-- | Boxed Vector binary decoder+getVector :: Get a -> Get (Vector a)+getVector = fmap Vector.fromList . getList++-- | List binary decoder+getList :: Get a -> Get [a]+getList getter = do+  empty <- isEmpty+  if empty+    then return []+    else (:) <$> getter <*> getList getter
src/Text/GLTF/Loader/Gltf.hs view
@@ -2,43 +2,65 @@   ( -- * Data constructors     Gltf(..),     Asset(..),+    Material(..),+    MaterialAlphaMode(..),     Mesh(..),     Node(..),     MeshPrimitive(..),+    PbrMetallicRoughness(..),     MeshPrimitiveMode(..),     -- * Lenses     _asset,+    _materials,     _meshes,     _nodes,+    -- ** Asset Lenses     _assetVersion,     _assetCopyright,     _assetGenerator,     _assetMinVersion,+    -- ** Material Lenses+    _materialAlphaCutoff,+    _materialAlphaMode,+    _materialDoubleSided,+    _materialEmissiveFactor,+    _materialName,+    _materialPbrMetallicRoughness,+    -- ** Mesh Lenses     _meshPrimitives,-    _meshPrimitiveMode,-    _meshPrimitiveIndices,-    _meshPrimitivePositions,-    _meshPrimitiveNormals,     _meshWeights,     _meshName,+    -- ** Node Lenses     _nodeMeshId,     _nodeName,     _nodeRotation,     _nodeScale,     _nodeTranslation,-    _nodeWeights+    _nodeWeights,+    -- ** MeshPrimitive Lenses+    _meshPrimitiveMaterial,+    _meshPrimitiveIndices,+    _meshPrimitiveMode,+    _meshPrimitiveNormals,+    _meshPrimitivePositions,+    -- ** PbrMetallicRoughness Lenses+    _pbrBaseColorFactor,+    _pbrMetallicFactor,+    _pbrRoughnessFactor   ) where -import Linear.V3 (V3(..))-import Linear.V4 (V4(..))+import Linear import RIO +-- | The root data type for a glTF asset data Gltf = Gltf   { gltfAsset :: Asset,-    gltfMeshes :: [Mesh],-    gltfNodes :: [Node] }-  deriving (Eq, Show)+    gltfMaterials :: Vector Material,+    gltfMeshes :: Vector Mesh,+    gltfNodes :: Vector Node+  } deriving (Eq, Show) +-- | Metadata about the glTF asset data Asset = Asset   { assetVersion :: Text,     assetCopyright :: Maybe Text,@@ -46,12 +68,24 @@     assetMinVersion :: Maybe Text   } deriving (Eq, Show) +-- | The material appearance of a primitive+data Material = Material+  { materialAlphaCutoff :: Float,+    materialAlphaMode :: MaterialAlphaMode,+    materialDoubleSided :: Bool,+    materialEmissiveFactor :: V3 Float,+    materialName :: Maybe Text,+    materialPbrMetallicRoughness :: Maybe PbrMetallicRoughness+  } deriving (Eq, Show)++-- | A set of primitives to be rendered data Mesh = Mesh-  { meshPrimitives :: [MeshPrimitive],-    meshWeights :: [Float],+  { meshPrimitives :: Vector MeshPrimitive,+    meshWeights :: Vector Float,     meshName :: Maybe Text   } deriving (Eq, Show) +-- | A node in the node hierarchy data Node = Node   { nodeMeshId :: Maybe Int,     nodeName :: Maybe Text,@@ -61,13 +95,32 @@     nodeWeights :: [Float]   } deriving (Eq, Show) +-- | Geometry to be rendered with the given material data MeshPrimitive = MeshPrimitive-  { meshPrimitiveMode :: MeshPrimitiveMode,-    meshPrimitiveIndices :: [Int],-    meshPrimitivePositions :: [V3 Float],-    meshPrimitiveNormals :: [V3 Float]+  { meshPrimitiveIndices :: Vector Int,+    meshPrimitiveMaterial :: Maybe Int,+    meshPrimitiveMode :: MeshPrimitiveMode,+    meshPrimitiveNormals :: Vector (V3 Float),+    meshPrimitivePositions :: Vector (V3 Float),+    meshPrimitiveTexCoords :: Vector (V2 Float)   } deriving (Eq, Show) +-- | Alpha rendering mode of a material+data MaterialAlphaMode+  = Blend+  | Mask+  | Opaque+  deriving (Eq, Enum, Show)++-- | A set of parameter values that are used to define the metallic-roughness material+-- model from Physically-Based Rendering (PBR) methodology.+data PbrMetallicRoughness = PbrMetallicRoughness+  { pbrBaseColorFactor :: V4 Float,+    pbrMetallicFactor :: Float,+    pbrRoughnessFactor :: Float+  } deriving (Eq, Show)++-- | The topology type of primitives to render. data MeshPrimitiveMode   = Points   | Lines@@ -81,10 +134,13 @@ _asset :: Lens' Gltf Asset _asset = lens gltfAsset (\gltf asset -> gltf { gltfAsset = asset }) -_meshes :: Lens' Gltf [Mesh]+_materials :: Lens' Gltf (Vector Material)+_materials = lens gltfMaterials (\gltf mats -> gltf { gltfMaterials = mats })++_meshes :: Lens' Gltf (Vector Mesh) _meshes = lens gltfMeshes (\gltf meshes -> gltf { gltfMeshes = meshes }) -_nodes :: Lens' Gltf [Node]+_nodes :: Lens' Gltf (Vector Node) _nodes = lens gltfNodes (\gltf nodes -> gltf { gltfNodes = nodes })  _assetVersion :: Lens' Asset Text@@ -105,37 +161,47 @@   assetMinVersion   (\asset minVersion' -> asset { assetMinVersion = minVersion' }) -_meshPrimitives :: Lens' Mesh [MeshPrimitive]-_meshPrimitives = lens-  meshPrimitives-  (\mesh primitives -> mesh { meshPrimitives = primitives })+_materialAlphaCutoff :: Lens' Material Float+_materialAlphaCutoff = lens+  materialAlphaCutoff+  (\material alphaCutoff -> material { materialAlphaCutoff = alphaCutoff }) -_meshPrimitiveMode :: Lens' MeshPrimitive MeshPrimitiveMode-_meshPrimitiveMode = lens-  meshPrimitiveMode-  (\primitive' mode -> primitive' { meshPrimitiveMode = mode })+_materialAlphaMode :: Lens' Material MaterialAlphaMode+_materialAlphaMode = lens+  materialAlphaMode+  (\material mode -> material { materialAlphaMode = mode }) -_meshPrimitiveIndices :: Lens' MeshPrimitive [Int]-_meshPrimitiveIndices = lens-  meshPrimitiveIndices-  (\primitive' indices -> primitive' { meshPrimitiveIndices = indices })+_materialDoubleSided :: Lens' Material Bool+_materialDoubleSided = lens+  materialDoubleSided+  (\material doubleSided -> material { materialDoubleSided = doubleSided }) -_meshPrimitivePositions :: Lens' MeshPrimitive [V3 Float]-_meshPrimitivePositions = lens-  meshPrimitivePositions-  (\primitive' positions -> primitive' { meshPrimitivePositions = positions })+_materialEmissiveFactor :: Lens' Material (V3 Float)+_materialEmissiveFactor = lens+  materialEmissiveFactor+  (\material emissiveFactor -> material { materialEmissiveFactor = emissiveFactor }) -_meshPrimitiveNormals :: Lens' MeshPrimitive [V3 Float]-_meshPrimitiveNormals = lens-  meshPrimitiveNormals-  (\primitive' normals -> primitive' { meshPrimitiveNormals = normals })-  -_meshWeights :: Lens' Mesh [Float]+_materialName :: Lens' Material (Maybe Text)+_materialName = lens+  materialName+  (\material name -> material { materialName = name })++_materialPbrMetallicRoughness :: Lens' Material (Maybe PbrMetallicRoughness)+_materialPbrMetallicRoughness = lens+  materialPbrMetallicRoughness+  (\material roughness -> material { materialPbrMetallicRoughness = roughness })++_meshWeights :: Lens' Mesh (Vector Float) _meshWeights = lens meshWeights (\mesh weights -> mesh { meshWeights = weights })  _meshName :: Lens' Mesh (Maybe Text) _meshName = lens meshName (\mesh name -> mesh { meshName = name }) +_meshPrimitives :: Lens' Mesh (Vector MeshPrimitive)+_meshPrimitives = lens+  meshPrimitives+  (\mesh primitives -> mesh { meshPrimitives = primitives })+ _nodeMeshId :: Lens' Node (Maybe Int) _nodeMeshId = lens nodeMeshId (\node meshId -> node { nodeMeshId = meshId }) @@ -155,3 +221,48 @@  _nodeWeights :: Lens' Node [Float] _nodeWeights = lens nodeWeights (\node weights' -> node { nodeWeights = weights' })++_meshPrimitiveIndices :: Lens' MeshPrimitive (Vector Int)+_meshPrimitiveIndices = lens+  meshPrimitiveIndices+  (\primitive' indices -> primitive' { meshPrimitiveIndices = indices })++_meshPrimitiveMaterial :: Lens' MeshPrimitive (Maybe Int)+_meshPrimitiveMaterial = lens+  meshPrimitiveMaterial+  (\primitive' material -> primitive' { meshPrimitiveMaterial = material })++_meshPrimitiveMode :: Lens' MeshPrimitive MeshPrimitiveMode+_meshPrimitiveMode = lens+  meshPrimitiveMode+  (\primitive' mode -> primitive' { meshPrimitiveMode = mode })++_meshPrimitiveNormals :: Lens' MeshPrimitive (Vector (V3 Float))+_meshPrimitiveNormals = lens+  meshPrimitiveNormals+  (\primitive' normals -> primitive' { meshPrimitiveNormals = normals })++_meshPrimitivePositions :: Lens' MeshPrimitive (Vector (V3 Float))+_meshPrimitivePositions = lens+  meshPrimitivePositions+  (\primitive' positions -> primitive' { meshPrimitivePositions = positions })++_meshPrimitiveTexCoords :: Lens' MeshPrimitive (Vector (V2 Float))+_meshPrimitiveTexCoords = lens+  meshPrimitiveTexCoords+  (\primitive' coords -> primitive' { meshPrimitiveTexCoords = coords })+  +_pbrBaseColorFactor :: Lens' PbrMetallicRoughness (V4 Float)+_pbrBaseColorFactor = lens+  pbrBaseColorFactor+  (\pbr baseColor -> pbr { pbrBaseColorFactor = baseColor })+  +_pbrMetallicFactor :: Lens' PbrMetallicRoughness Float+_pbrMetallicFactor = lens+  pbrMetallicFactor+  (\pbr metallicFactor -> pbr { pbrMetallicFactor = metallicFactor })++_pbrRoughnessFactor :: Lens' PbrMetallicRoughness Float+_pbrRoughnessFactor = lens+  pbrRoughnessFactor+  (\pbr roughnessFactor -> pbr { pbrRoughnessFactor = roughnessFactor })
test/Text/GLTF/Loader/AdapterSpec.hs view
@@ -5,9 +5,10 @@ import Text.GLTF.Loader.Gltf import Text.GLTF.Loader.Test.MkGltf -import Linear (V3(..), V4(..))+import Linear import RIO import Test.Hspec+import qualified Codec.GlTF.Material as Material import qualified Codec.GlTF.Mesh as Mesh import qualified Codec.GlTF.Node as Node @@ -45,6 +46,20 @@       adaptMeshes codecGltf buffers' (Just []) `shouldBe` []       adaptMeshes codecGltf buffers' Nothing `shouldBe` [] +  describe "adaptMaterials" $ do+    let materials = Just [mkCodecMaterial]++    it "Adapts a list of materials" $ do+      adaptMaterials Nothing `shouldBe` []+      adaptMaterials materials `shouldBe` [loaderMaterial]++    it "Ignores PBR metallic roughness when not specified" $ do+      let materials' = Just+            [mkCodecMaterial { Material.pbrMetallicRoughness = Nothing }]+          adaptedMaterial = set _materialPbrMetallicRoughness Nothing loaderMaterial++      adaptMaterials materials' `shouldBe` [adaptedMaterial]+   describe "adaptNodes" $ do     let codecNode = mkCodecNode         codecNode' = codecNode { Node.rotation = Nothing }@@ -86,6 +101,14 @@       adaptNode codecNode' `shouldBe` nodeEmptyWeight       adaptNode codecNode'' `shouldBe` nodeEmptyWeight +  describe "adaptAlphaMode" $ do+    it "Adapts all expected modes" $ do+      adaptAlphaMode Material.BLEND `shouldBe` Blend+      adaptAlphaMode Material.MASK `shouldBe` Mask+      adaptAlphaMode Material.OPAQUE `shouldBe` Opaque+      evaluate (adaptAlphaMode $ Material.MaterialAlphaMode "???")+        `shouldThrow` anyErrorCall+   describe "adaptMeshPrimitives" $ do     let codecMeshPrimitive' = mkCodecMeshPrimitive           { Mesh.mode = Mesh.MeshPrimitiveMode 0 }@@ -103,13 +126,27 @@   describe "adaptMeshPrimitive" $ do     it "adapts a basic primitive" $ do       buffers' <- buffers+      adaptMeshPrimitive codecGltf buffers' codecMeshPrimitive `shouldBe` loaderMeshPrimitive +    it "ignores indices when unspecified" $ do+      buffers' <- buffers+             let codecMeshPrimitive' = mkCodecMeshPrimitive             { Mesh.indices = Nothing }-          loaderMeshPrimitive' = set _meshPrimitiveIndices [] loaderMeshPrimitive-      -      adaptMeshPrimitive codecGltf buffers' codecMeshPrimitive `shouldBe` loaderMeshPrimitive+          loaderMeshPrimitive' = loaderMeshPrimitive & _meshPrimitiveIndices .~ []+       adaptMeshPrimitive codecGltf buffers' codecMeshPrimitive' `shouldBe` loaderMeshPrimitive'++    it "ignores material when unspecified" $ do+      buffers' <- buffers++      let codecMeshPrimitive' = mkCodecMeshPrimitive+            { Mesh.material = Nothing }+          loaderMeshPrimitive' = loaderMeshPrimitive & _meshPrimitiveMaterial .~ Nothing++      adaptMeshPrimitive codecGltf buffers' codecMeshPrimitive'+        `shouldBe` loaderMeshPrimitive'+              describe "adaptMeshPrimitiveMode" $     it "Adapts all expected modes" $ do@@ -129,6 +166,7 @@ loaderGltf :: Gltf loaderGltf = Gltf   { gltfAsset = loaderAsset,+    gltfMaterials = [loaderMaterial],     gltfMeshes = [loaderMesh],     gltfNodes = [loaderNode]   }@@ -141,6 +179,16 @@     assetMinVersion = Just "minVersion"   } +loaderMaterial :: Material+loaderMaterial = Material+  { materialAlphaCutoff = 1.0,+    materialAlphaMode = Opaque,+    materialDoubleSided = True,+    materialEmissiveFactor = V3 1.0 2.0 3.0,+    materialName = Just "Material",+    materialPbrMetallicRoughness = Just loaderPbrMetallicRoughness+  }+ loaderMesh :: Mesh loaderMesh = Mesh   { meshPrimitives = [loaderMeshPrimitive],@@ -158,10 +206,19 @@     nodeWeights = [11, 12, 13]   } +loaderPbrMetallicRoughness :: PbrMetallicRoughness+loaderPbrMetallicRoughness = PbrMetallicRoughness+  { pbrBaseColorFactor = V4 1.0 2.0 3.0 4.0,+    pbrMetallicFactor = 1.0,+    pbrRoughnessFactor = 2.0+  }+ loaderMeshPrimitive :: MeshPrimitive loaderMeshPrimitive = MeshPrimitive-  { meshPrimitiveMode = Triangles,-    meshPrimitiveIndices = [1..4],-    meshPrimitivePositions = map (\x -> V3 x x x) [1..4],-    meshPrimitiveNormals = []+  { meshPrimitiveIndices = [1..4],+    meshPrimitiveMaterial = Just 1,+    meshPrimitiveMode = Triangles,+    meshPrimitiveNormals = fmap (\x -> V3 x x x) [5..8],+    meshPrimitivePositions = fmap (\x -> V3 x x x) [1..4],+    meshPrimitiveTexCoords = fmap (\x -> V2 x x) [9..12]   }
test/Text/GLTF/Loader/BufferAccessorSpec.hs view
@@ -1,6 +1,7 @@ module Text.GLTF.Loader.BufferAccessorSpec (spec) where  import Text.GLTF.Loader.BufferAccessor+import Text.GLTF.Loader.Decoders import Text.GLTF.Loader.Test.MkGltf  import Linear (V3(..))@@ -28,7 +29,7 @@       let (GltfBuffer buffer') = buffers ! 0           values = runGet (getScalar (fromIntegral <$> getUnsignedShort)) . fromStrict $ buffer'       -      values `shouldBe` ([1..4] :: [Integer])+      values `shouldBe` ([1..4] :: Vector Integer)      it "Handles malformed URI" $ do       let gltf' = gltf@@ -43,7 +44,6 @@       buffers <- loadBuffers gltf'        buffers `shouldBe` []-          describe "vertexIndices" $ do     it "Reads basic values from buffer" $ do
test/Text/GLTF/Loader/Test/MkGltf.hs view
@@ -1,20 +1,23 @@ module Text.GLTF.Loader.Test.MkGltf where -import Text.GLTF.Loader.Adapter (attributePosition)+import Text.GLTF.Loader.Adapter  import Data.Binary.Builder import Data.Binary.Put (putFloatle, runPut)+ import Data.ByteString.Base64 (encodeBase64) import Data.ByteString.Lazy (toStrict) import Foreign (Storable(..))-import Linear (V3(..))+import Linear import RIO import qualified Codec.GlTF as GlTF import qualified Codec.GlTF.Accessor as Accessor import qualified Codec.GlTF.Asset as Asset import qualified Codec.GlTF.Buffer as Buffer import qualified Codec.GlTF.BufferView as BufferView+import qualified Codec.GlTF.Material as Material import qualified Codec.GlTF.Mesh as Mesh+import qualified Codec.GlTF.PbrMetallicRoughness as PbrMetallicRoughness import qualified Codec.GlTF.Node as Node import qualified Codec.GlTF.URI as URI import qualified Data.HashMap.Strict as HashMap@@ -24,13 +27,28 @@   { asset = mkCodecAsset,     extensionsUsed = Nothing,     extensionsRequired = Nothing,-    accessors = Just [mkCodecAccessorIndices, mkCodecAccessorPositions],+    accessors = Just+      [ mkCodecAccessorIndices,+        mkCodecAccessorPositions,+        mkCodecAccessorNormals,+        mkCodecAccessorTexCoords+      ],     animations = Nothing,-    buffers = Just [mkCodecBufferIndices, mkCodecBufferPositions],-    bufferViews = Just [mkCodecBufferViewIndices, mkCodecBufferViewPositions],+    buffers = Just+      [ mkCodecBufferIndices,+        mkCodecBufferPositions,+        mkCodecBufferNormals,+        mkCodecBufferTexCoords+      ],+    bufferViews = Just+      [ mkCodecBufferViewIndices,+        mkCodecBufferViewPositions,+        mkCodecBufferViewNormals,+        mkCodecBufferViewTexCoords+      ],     cameras = Nothing,     images = Nothing,-    materials = Nothing,+    materials = Just [mkCodecMaterial],     meshes = Just [mkCodecMesh],     nodes = Just [mkCodecNode],     samplers = Nothing,@@ -68,6 +86,23 @@     type' = Accessor.AttributeType "SCALAR"   } +mkCodecAccessorNormals :: Accessor.Accessor+mkCodecAccessorNormals = Accessor.Accessor+  {+    bufferView = Just $ BufferView.BufferViewIx 2,+    byteOffset = 0,+    componentType = Accessor.ComponentType 5126,+    count = 4,+    extensions = Nothing,+    extras = Nothing,+    max = Nothing,+    min = Nothing,+    name = Just "Accessor Normals",+    normalized = False,+    sparse = Nothing,+    type' = Accessor.AttributeType "VEC3"+  }+ mkCodecAccessorPositions :: Accessor.Accessor mkCodecAccessorPositions = Accessor.Accessor   {@@ -82,9 +117,26 @@     name = Just "Accessor Positions",     normalized = False,     sparse = Nothing,-    type' = Accessor.AttributeType "VEC3"+    type' = Accessor.AttributeType "VEC2"   } +mkCodecAccessorTexCoords :: Accessor.Accessor+mkCodecAccessorTexCoords = Accessor.Accessor+  {+    bufferView = Just $ BufferView.BufferViewIx 3,+    byteOffset = 0,+    componentType = Accessor.ComponentType 5126,+    count = 4,+    extensions = Nothing,+    extras = Nothing,+    max = Nothing,+    min = Nothing,+    name = Just "Accessor Texture Coordinates",+    normalized = False,+    sparse = Nothing,+    type' = Accessor.AttributeType "VEC2"+  }+ mkCodecBufferViewIndices :: BufferView.BufferView mkCodecBufferViewIndices = BufferView.BufferView   { buffer = Buffer.BufferIx 0,@@ -97,6 +149,18 @@     extras = Nothing   } +mkCodecBufferViewNormals :: BufferView.BufferView+mkCodecBufferViewNormals = BufferView.BufferView+  { buffer = Buffer.BufferIx 2,+    byteOffset = 0,+    byteLength = sizeOf (undefined :: V3 Float) * 4,+    byteStride = Nothing,+    target = Nothing,+    name = Just "BufferView Normals",+    extensions = Nothing,+    extras = Nothing+  }+ mkCodecBufferViewPositions :: BufferView.BufferView mkCodecBufferViewPositions = BufferView.BufferView   { buffer = Buffer.BufferIx 1,@@ -109,6 +173,18 @@     extras = Nothing   } +mkCodecBufferViewTexCoords :: BufferView.BufferView+mkCodecBufferViewTexCoords = BufferView.BufferView+  { buffer = Buffer.BufferIx 3,+    byteOffset = 0,+    byteLength = sizeOf (undefined :: V2 Float) * 4,+    byteStride = Nothing,+    target = Nothing,+    name = Just "BufferView Positions",+    extensions = Nothing,+    extras = Nothing+  }+ mkCodecBufferIndices :: Buffer.Buffer mkCodecBufferIndices = Buffer.Buffer   { byteLength = sizeOf (undefined :: Word16) * 4,@@ -118,6 +194,15 @@     name = Just "Buffer Indices"   } +mkCodecBufferNormals :: Buffer.Buffer+mkCodecBufferNormals = Buffer.Buffer+  { byteLength = sizeOf (undefined :: V3 Float) * 4,+    uri = Just mkCodecBufferUriNormals,+    extensions = Nothing,+    extras = Nothing,+    name = Just "Buffer Positions"+  }+ mkCodecBufferPositions :: Buffer.Buffer mkCodecBufferPositions = Buffer.Buffer   { byteLength = sizeOf (undefined :: V3 Float) * 4,@@ -127,6 +212,30 @@     name = Just "Buffer Positions"   } +mkCodecBufferTexCoords :: Buffer.Buffer+mkCodecBufferTexCoords = Buffer.Buffer+  { byteLength = sizeOf (undefined :: V2 Float) * 4,+    uri = Just mkCodecBufferUriTexCoords,+    extensions = Nothing,+    extras = Nothing,+    name = Just "Buffer Positions"+  }++mkCodecMaterial :: Material.Material+mkCodecMaterial = Material.Material+  { alphaCutoff = 1.0,+    emissiveFactor = (1.0, 2.0, 3.0),+    alphaMode = Material.OPAQUE,+    doubleSided = True,+    pbrMetallicRoughness = Just mkCodecPbrMetallicRoughness,+    normalTexture = Nothing,+    occlusionTexture = Nothing,+    emissiveTexture = Nothing,+    name = Just "Material",+    extensions = Nothing,+    extras = Nothing+  }+ mkCodecMesh :: Mesh.Mesh mkCodecMesh = Mesh.Mesh   { primitives = [mkCodecMeshPrimitive],@@ -136,25 +245,51 @@     extras = Nothing   } +mkCodecPbrMetallicRoughness :: PbrMetallicRoughness.PbrMetallicRoughness+mkCodecPbrMetallicRoughness = PbrMetallicRoughness.PbrMetallicRoughness+  { baseColorFactor = (1.0, 2.0, 3.0, 4.0),+    metallicFactor = 1.0,+    roughnessFactor = 2.0,+    metallicRoughnessTexture = Nothing,+    baseColorTexture = Nothing,+    extensions = Nothing,+    extras = Nothing+  }+ mkCodecBufferUriIndices :: URI.URI mkCodecBufferUriIndices = URI.URI uriText   where uriText = "data:application/octet-stream;base64," <> encodedText         encodedText = encodeBase64. toStrict . toLazyByteString $ putIndices         putIndices = foldr ((<>) . putWord16le) empty ([1..4] :: [Word16]) +mkCodecBufferUriNormals :: URI.URI+mkCodecBufferUriNormals = URI.URI uriText+  where uriText = "data:application/octet-stream;base64," <> encodedText+        encodedText = encodeBase64. toStrict . runPut $ putPositions+        putPositions = mapM_ (replicateM_ 3 . putFloatle) ([5..8] :: [Float])+ mkCodecBufferUriPositions :: URI.URI mkCodecBufferUriPositions = URI.URI uriText   where uriText = "data:application/octet-stream;base64," <> encodedText         encodedText = encodeBase64. toStrict . runPut $ putPositions         putPositions = mapM_ (replicateM_ 3 . putFloatle) ([1..4] :: [Float]) +mkCodecBufferUriTexCoords :: URI.URI+mkCodecBufferUriTexCoords = URI.URI uriText+  where uriText = "data:application/octet-stream;base64," <> encodedText+        encodedText = encodeBase64. toStrict . runPut $ putPositions+        putPositions = mapM_ (replicateM_ 2 . putFloatle) ([9..12] :: [Float])+ mkCodecMeshPrimitive :: Mesh.MeshPrimitive mkCodecMeshPrimitive = Mesh.MeshPrimitive   { attributes = HashMap.fromList-      [(attributePosition, Accessor.AccessorIx 1)],+      [ (attributePosition, Accessor.AccessorIx 1),+        (attributeNormal, Accessor.AccessorIx 2),+        (attributeTexCoord, Accessor.AccessorIx 3)+      ],     mode = Mesh.MeshPrimitiveMode 4,     indices = Just $ Accessor.AccessorIx 0,-    material = Nothing,+    material = Just $ Material.MaterialIx 1,     targets = Nothing,     extensions = Nothing,     extras = Nothing
test/Text/GLTF/LoaderSpec.hs view
@@ -3,7 +3,7 @@ import Text.GLTF.Loader  import Lens.Micro-import Linear (V3(..))+import Linear (V2(..), V3(..), V4(..)) import RIO import Test.Hspec @@ -34,6 +34,21 @@                   assetMinVersion = Nothing                 }, +              gltfMaterials+                = [ Material+                      { materialAlphaCutoff = 0.5,+                        materialAlphaMode = Opaque,+                        materialDoubleSided = True,+                        materialEmissiveFactor = V3 0.0 0.0 0.0,+                        materialName = Just "Material",+                        materialPbrMetallicRoughness = Just $ PbrMetallicRoughness+                          { pbrBaseColorFactor = V4 0.8 0.8 0.8 1.0,+                            pbrMetallicFactor = 0.0,+                            pbrRoughnessFactor = 0.4+                          }+                      }+                  ],+                             gltfMeshes                 = [ Mesh                      { meshPrimitives@@ -44,6 +59,7 @@                                        21, 18, 12, 21, 12, 15, 16, 3, 9, 16, 9,                                        22, 5, 2, 8, 5, 8, 11, 17, 13, 0, 17, 0, 4                                      ],+                                 meshPrimitiveMaterial = Just 0,                                  meshPrimitivePositions                                    =  [ V3 1.0 1.0 (-1.0),      -- 1                                         V3 1.0 1.0 (-1.0),      -- 2@@ -70,7 +86,58 @@                                         V3 (-1.0) (-1.0) 1.0,   -- 23                                         V3 (-1.0) (-1.0) 1.0    -- 24                                       ],-                                 meshPrimitiveNormals = []+                                 meshPrimitiveNormals+                                   = [ V3 0.0 0.0 (-1.0),+                                       V3 0.0 1.0 (-0.0),+                                       V3 1.0 0.0 (-0.0),+                                       V3 0.0 (-1.0) (-0.0),+                                       V3 0.0 0.0 (-1.0),+                                       V3 1.0 0.0 (-0.0),+                                       V3 0.0 0.0 1.0,+                                       V3 0.0 1.0 (-0.0),+                                       V3 1.0 0.0 (-0.0),+                                       V3 0.0 (-1.0) (-0.0),+                                       V3 0.0 0.0 1.0,+                                       V3 1.0 0.0 (-0.0),+                                       V3 (-1.0) 0.0 (-0.0),+                                       V3 0.0 0.0 (-1.0),+                                       V3 0.0 1.0 (-0.0),+                                       V3 (-1.0) 0.0 (-0.0),+                                       V3 0.0 (-1.0) (-0.0),+                                       V3 0.0 0.0 (-1.0),+                                       V3 (-1.0) 0.0 (-0.0),+                                       V3 0.0 0.0 1.0,+                                       V3 0.0 1.0 (-0.0),+                                       V3 (-1.0) 0.0 (-0.0),+                                       V3 0.0 (-1.0) (-0.0),+                                       V3 0.0 0.0 1.0+                                     ],+                                 meshPrimitiveTexCoords+                                   = [ V2 0.625 0.5,+                                       V2 0.625 0.5,+                                       V2 0.625 0.5,+                                       V2 0.375 0.5,+                                       V2 0.375 0.5,+                                       V2 0.375 0.5,+                                       V2 0.625 0.25,+                                       V2 0.625 0.25,+                                       V2 0.625 0.25,+                                       V2 0.375 0.25,+                                       V2 0.375 0.25,+                                       V2 0.375 0.25,+                                       V2 0.625 0.75,+                                       V2 0.625 0.75,+                                       V2 0.875 0.5,+                                       V2 0.375 0.75,+                                       V2 0.125 0.5,+                                       V2 0.375 0.75,+                                       V2 0.625 1.0,+                                       V2 0.625 0.0,+                                       V2 0.875 0.25,+                                       V2 0.375 1.0,+                                       V2 0.125 0.25,+                                       V2 0.375 0.0+                                     ]                                }                            ],                        meshWeights = [],