changeset 1448:96753bec055c default tip

add: support for "name" and "extras" on gltf nodes
author sam <sam@basx.dev>
date Sun, 09 Mar 2025 22:59:34 +0700
parents b17098eb052f
children
files semicongine/core/types.nim semicongine/gltf.nim tests/test_gltf.nim
diffstat 3 files changed, 83 insertions(+), 67 deletions(-) [+]
line wrap: on
line diff
--- a/semicongine/core/types.nim	Sat Mar 01 17:27:47 2025 +0700
+++ b/semicongine/core/types.nim	Sun Mar 09 22:59:34 2025 +0700
@@ -479,48 +479,6 @@
   # === steam ===
   SteamUserStatsRef* = ptr object
 
-  # === glTF ===
-  GltfNode* = object
-    children*: seq[int]
-    mesh*: int = -1
-    transform*: Mat4 = Unit4
-
-  GltfData*[TMesh, TMaterial] = object
-    scenes*: seq[seq[int]] # each scene has a seq of node indices
-    nodes*: seq[GltfNode] # each node has a seq of mesh indices
-    meshes*: seq[seq[(TMesh, VkPrimitiveTopology)]]
-    materials*: seq[TMaterial]
-    textures*: seq[Image[BGRA]]
-
-  MaterialAttributeNames* = object # pbr
-    baseColorTexture*: string
-    baseColorTextureUv*: string
-    baseColorFactor*: string
-    metallicRoughnessTexture*: string
-    metallicRoughnessTextureUv*: string
-    metallicFactor*: string
-    roughnessFactor*: string
-
-    # other
-    normalTexture*: string
-    normalTextureUv*: string
-    occlusionTexture*: string
-    occlusionTextureUv*: string
-    emissiveTexture*: string
-    emissiveTextureUv*: string
-    emissiveFactor*: string
-
-  MeshAttributeNames* = object
-    POSITION*: string
-    NORMAL*: string
-    TANGENT*: string
-    TEXCOORD*: seq[string]
-    COLOR*: seq[string]
-    JOINTS*: seq[string]
-    WEIGHTS*: seq[string]
-    indices*: string
-    material*: string
-
   # === global engine object ===
   EngineObj = object
     initialized*: bool
@@ -568,6 +526,3 @@
 proc `=copy`[MaxGlyphs: static int](
   dest: var TextBuffer[MaxGlyphs], source: TextBuffer[MaxGlyphs]
 ) {.error.}
-
-proc `=copy`(dest: var GltfNode, source: GltfNode) {.error.}
-proc `=copy`[S, T](dest: var GltfData[S, T], source: GltfData[S, T]) {.error.}
--- a/semicongine/gltf.nim	Sat Mar 01 17:27:47 2025 +0700
+++ b/semicongine/gltf.nim	Sun Mar 09 22:59:34 2025 +0700
@@ -10,6 +10,59 @@
 import ./resources
 
 type
+  # === public ===
+  GltfData*[TMesh, TMaterial] = object
+    scenes*: seq[seq[int]] # each scene has a seq of node indices
+    nodes*: seq[GltfNode] # each node has a seq of mesh indices
+    meshes*: seq[GltfMesh[TMesh]]
+    materials*: seq[TMaterial]
+    textures*: seq[Image[BGRA]]
+
+  GltfNode* = object
+    name*: string
+    properties*: JsonNode
+    children*: seq[int]
+    mesh*: int = -1
+    transform*: Mat4 = Unit4
+
+  GltfMesh*[TMesh] = object
+    primitives*: seq[GltfPrimitive[TMesh]]
+
+  GltfPrimitive*[TMesh] = object
+    data*: TMesh
+    topology*: VkPrimitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST
+    material*: int
+
+  MaterialAttributeNames* = object # pbr
+    baseColorTexture*: string
+    baseColorTextureUv*: string
+    baseColorFactor*: string
+    metallicRoughnessTexture*: string
+    metallicRoughnessTextureUv*: string
+    metallicFactor*: string
+    roughnessFactor*: string
+
+    # other
+    normalTexture*: string
+    normalTextureUv*: string
+    occlusionTexture*: string
+    occlusionTextureUv*: string
+    emissiveTexture*: string
+    emissiveTextureUv*: string
+    emissiveFactor*: string
+
+  MeshAttributeNames* = object
+    POSITION*: string
+    NORMAL*: string
+    TANGENT*: string
+    TEXCOORD*: seq[string]
+    COLOR*: seq[string]
+    JOINTS*: seq[string]
+    WEIGHTS*: seq[string]
+    indices*: string
+    material*: string
+
+  # === internal ===
   glTFHeader = object
     magic: uint32
     version: uint32
@@ -19,6 +72,11 @@
     structuredContent: JsonNode
     binaryBufferData: seq[uint8]
 
+proc `=copy`[M](dest: var GltfPrimitive[M], source: GltfPrimitive[M]) {.error.}
+proc `=copy`[M](dest: var GltfMesh[M], source: GltfMesh[M]) {.error.}
+proc `=copy`(dest: var GltfNode, source: GltfNode) {.error.}
+proc `=copy`[S, T](dest: var GltfData[S, T], source: GltfData[S, T]) {.error.}
+
 proc `=copy`(dest: var glTFHeader, source: glTFHeader) {.error.}
 proc `=copy`(dest: var glTFData, source: glTFData) {.error.}
 
@@ -212,16 +270,19 @@
     primitive: JsonNode,
     mapping: static MeshAttributeNames,
     mainBuffer: seq[uint8],
-): (TMesh, VkPrimitiveTopology) =
-  result[0] = TMesh()
-  result[1] = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST
+): GltfPrimitive[TMesh] =
+  result.data = TMesh()
+
   if primitive.hasKey("mode"):
-    result[1] = PRIMITIVE_MODE_MAP[primitive["mode"].getInt()]
+    result.topology = PRIMITIVE_MODE_MAP[primitive["mode"].getInt()]
+
+  if primitive.hasKey("material"):
+    result.material = primitive["material"].getInt()
 
   if primitive.hasKey("indices"):
-    assert mapping.indices != "", "Mesh requires indices"
+    doAssert mapping.indices != "", "Mesh requires indices"
 
-  for resultFieldName, resultValue in fieldPairs(result[0]):
+  for resultFieldName, resultValue in fieldPairs(result.data):
     for gltfAttribute, mappedName in fieldPairs(mapping):
       when typeof(mappedName) is seq:
         when resultFieldName in mappedName:
@@ -260,6 +321,10 @@
 
 proc loadNode(node: JsonNode): GltfNode =
   result = GltfNode()
+  if "name" in node:
+    result.name = node["name"].getStr()
+  if "properties" in node:
+    result.properties = node["properties"]
   if "mesh" in node:
     result.mesh = node["mesh"].getInt()
   if "children" in node:
@@ -346,13 +411,13 @@
 
   if "meshes" in data.structuredContent:
     for mesh in items(data.structuredContent["meshes"]):
-      var primitives: seq[(TMesh, VkPrimitiveTopology)]
+      var meshObj: GltfMesh[TMesh]
       for primitive in items(mesh["primitives"]):
-        primitives.add loadPrimitive[TMesh](
+        meshObj.primitives.add loadPrimitive[TMesh](
           data.structuredContent, primitive, meshAttributesMapping,
           data.binaryBufferData,
         )
-      result.meshes.add primitives
+      result.meshes.add meshObj
 
   if "nodes" in data.structuredContent:
     for node in items(data.structuredContent["nodes"]):
--- a/tests/test_gltf.nim	Sat Mar 01 17:27:47 2025 +0700
+++ b/tests/test_gltf.nim	Sun Mar 09 22:59:34 2025 +0700
@@ -8,6 +8,7 @@
 import ../semicongine/rendering
 import ../semicongine/loaders
 import ../semicongine/input
+import ../semicongine/gltf
 
 proc test_gltf(time: float32, renderPass: RenderPass) =
   var renderdata = initRenderData()
@@ -96,17 +97,12 @@
       color: GPUArray[Vec4f, VertexBuffer]
       normal: GPUArray[Vec3f, VertexBuffer]
       indices: GPUArray[uint32, IndexBuffer]
-      material: int32
 
   var gltfData = loadMeshes[Mesh, Material](
     "town.glb",
     # "forest.glb",
     MeshAttributeNames(
-      POSITION: "position",
-      COLOR: @["color"],
-      NORMAL: "normal",
-      indices: "indices",
-      material: "material",
+      POSITION: "position", COLOR: @["color"], NORMAL: "normal", indices: "indices"
     ),
     MaterialAttributeNames(
       baseColorFactor: "color",
@@ -130,11 +126,11 @@
   for i in 0 ..< gltfData.materials.len:
     descriptors.data.materials[i] = asGPUValue(gltfData.materials[i], UniformBuffer)
   for mesh in mitems(gltfData.meshes):
-    for primitive in mitems(mesh):
-      primitive[0].color = asGPUArray(
-        newSeqWith(primitive[0].position.data.len, vec4(1, 1, 1, 1)), VertexBuffer
+    for primitive in mitems(mesh.primitives):
+      primitive.data.color = asGPUArray(
+        newSeqWith(primitive.data.position.data.len, vec4(1, 1, 1, 1)), VertexBuffer
       )
-      renderdata.assignBuffers(primitive[0])
+      renderdata.assignBuffers(primitive.data)
   renderdata.assignBuffers(descriptors)
 
   var pipeline = createPipeline(Shader(), renderPass = renderPass, cullMode = [])
@@ -147,13 +143,13 @@
   ) =
     let nodeTransform = gltfData.nodes[nodeId].transform * transform
     if gltfData.nodes[nodeId].mesh >= 0:
-      for primitive in gltfData.meshes[gltfData.nodes[nodeId].mesh].mitems:
+      for primitive in gltfData.meshes[gltfData.nodes[nodeId].mesh].primitives:
         renderWithPushConstant(
           commandbuffer = commandbuffer,
           pipeline = pipeline,
-          mesh = primitive[0],
+          mesh = primitive.data,
           pushConstant =
-            ObjectData(transform: nodeTransform, materialId: primitive[0].material),
+            ObjectData(transform: nodeTransform, materialId: primitive.material.int32),
         )
     for childNode in gltfData.nodes[nodeId].children:
       drawNode(