diff semiconginev2/gltf.nim @ 1249:d83726af7abb

did: first triangles getting loaded from gltf
author sam <sam@basx.dev>
date Thu, 25 Jul 2024 22:41:24 +0700
parents 317bb5a73606
children 9ceb509af5ea
line wrap: on
line diff
--- a/semiconginev2/gltf.nim	Thu Jul 25 20:23:54 2024 +0700
+++ b/semiconginev2/gltf.nim	Thu Jul 25 22:41:24 2024 +0700
@@ -141,7 +141,34 @@
     raise newException(Exception, "Unsupported feature: byteStride in buffer view")
   copyMem(dstPointer, addr mainBuffer[bufferOffset], result.len)
 
+proc componentTypeId(t: typedesc): int =
+  if t is int8: return 5120
+  elif t is uint8: return 5121
+  elif t is int16: return 5122
+  elif t is uint16: return 5123
+  elif t is uint32: return 5125
+  elif t is float32: return 5126
+
 proc getAccessorData[T](root: JsonNode, accessor: JsonNode, mainBuffer: seq[uint8]): seq[T] =
+  let componentType = accessor["componentType"].getInt()
+  let itemType = accessor["type"].getStr()
+
+  when T is TVec or T is TMat:
+    assert componentTypeId(elementType(default(T))) == componentType, name(T) & " != " & $componentType
+  else:
+    assert componentTypeId(T) == componentType, name(T) & " != " & $componentType
+
+  when T is TVec:
+    when len(default(T)) == 2: assert itemType == "VEC2"
+    elif len(default(T)) == 3: assert itemType == "VEC3"
+    elif len(default(T)) == 4: assert itemType == "VEC4"
+  elif T is TMat:
+    when T is Mat2: assert itemType == "MAT2"
+    elif T is Mat3: assert itemType == "MAT3"
+    elif T is Mat4: assert itemType == "MAT4"
+  else:
+    assert itemType == "SCALAR"
+
   result.setLen(accessor["count"].getInt())
 
   let bufferView = root["bufferViews"][accessor["bufferView"].getInt()]
@@ -158,9 +185,9 @@
   if bufferView.hasKey("byteStride"):
     warn "Congratulations, you try to test a feature (loading buffer data with stride attributes) that we have no idea where it is used and how it can be tested (need a coresponding *.glb file)."
     # we don't support stride, have to convert stuff here... does this even work?
-    for i in 0 ..< int(result.len):
-      copyMem(dstPointer, addr mainBuffer[bufferOffset + i * bufferView["byteStride"].getInt()], result.len * sizeof(T))
-      dstPointer = cast[typeof(dstPointer)](cast[uint](dstPointer) + (result.len * sizeof(T)).uint)
+    for i in 0 ..< result.len:
+      copyMem(dstPointer, addr mainBuffer[bufferOffset + i * bufferView["byteStride"].getInt()], sizeof(T))
+      dstPointer = cast[typeof(dstPointer)](cast[uint](dstPointer) + sizeof(T).uint)
   else:
     copyMem(dstPointer, addr mainBuffer[bufferOffset], length)
 
@@ -193,8 +220,8 @@
 proc loadMaterial[TMaterial](
   root: JsonNode,
   materialNode: JsonNode,
+  mapping: static MaterialAttributeNames,
   mainBuffer: seq[uint8],
-  mapping: static MaterialAttributeNames
 ): TMaterial =
   result = TMaterial()
 
@@ -214,16 +241,43 @@
           else:
             {.error: "Unsupported gltf material attribute".}
 
-proc loadPrimitive[TMesh](root: JsonNode, primitive: JsonNode, mapping: static MeshAttributeNames, mainBuffer: seq[uint8]): (TMesh, VkPrimitiveTopology) =
+proc loadPrimitive[TMesh](
+  root: JsonNode,
+  primitive: JsonNode,
+  mapping: static MeshAttributeNames,
+  mainBuffer: seq[uint8]
+): (TMesh, VkPrimitiveTopology) =
   result[0] = TMesh()
   result[1] = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST
   if primitive.hasKey("mode"):
     result[1] = PRIMITIVE_MODE_MAP[primitive["mode"].getInt()]
 
-  for name, value in fieldPairs(result[0]):
+  for resultFieldName, resultValue in fieldPairs(result[0]):
     for gltfAttribute, mappedName in fieldPairs(mapping):
-      when gltfAttribute != "" and name == mappedName:
-        assert value is GPUData, "Attribute " & name & " must be of type GPUData"
+      when typeof(mappedName) is string:
+        when gltfAttribute != "" and resultFieldName == mappedName:
+          assert resultValue is GPUData, "Attribute " & resultFieldName & " must be of type GPUData"
+          when gltfAttribute == "indices":
+            if primitive.hasKey(gltfAttribute):
+              let accessor = primitive[gltfAttribute].getInt()
+              resultValue.data = getAccessorData[elementType(resultValue.data)](root, root["accessors"][accessor], mainBuffer)
+          elif gltfAttribute == "material":
+            if primitive.hasKey(gltfAttribute):
+              resultValue.data = typeof(resultValue.data)(primitive[gltfAttribute].getInt())
+          else:
+            if primitive["attributes"].hasKey(gltfAttribute):
+              let accessor = primitive["attributes"][gltfAttribute].getInt()
+              resultValue.data = getAccessorData[elementType(resultValue.data)](root, root["accessors"][accessor], mainBuffer)
+      else:
+        var i = 0
+        for mappedIndexName in mappedName:
+          if gltfAttribute != "" and resultFieldName == mappedIndexName:
+            assert resultValue is GPUData, "Attribute " & resultFieldName & " must be of type GPUData"
+            let gltfAttributeIndexed = gltfAttribute & "_" & $i
+            if primitive["attributes"].hasKey(gltfAttributeIndexed):
+              let accessor = primitive["attributes"][gltfAttributeIndexed].getInt()
+              resultValue.data = getAccessorData[elementType(resultValue.data)](root, root["accessors"][accessor], mainBuffer)
+          inc i
         #[
         when gltfAttribute == "indices":
           if primitive.hasKey(gltfAttribute):
@@ -436,7 +490,7 @@
 
   if "materials" in data.structuredContent:
     for materialnode in items(data.structuredContent["materials"]):
-      result.materials.add loadMaterial[TMaterial](data.structuredContent, materialnode, data.binaryBufferData, materialAttributesMapping)
+      result.materials.add loadMaterial[TMaterial](data.structuredContent, materialnode, materialAttributesMapping, data.binaryBufferData)
 
   if "textures" in data.structuredContent:
     for texturenode in items(data.structuredContent["textures"]):
@@ -461,7 +515,9 @@
   for m in result.meshes:
     echo "  Primitives:"
     for p in m:
-      echo "    ", p[1], ": ", p[0]
+      for field, value in fieldPairs(p[0]):
+        if typeof(value) is GPUData:
+          echo "    ", field, ": ", value.data.len
 
 proc LoadMeshes*[TMesh, TMaterial](
   path: string,