Mercurial > games > semicongine
diff semiconginev2/gltf.nim @ 1248:317bb5a73606
did: continue on gltf importer
author | sam <sam@basx.dev> |
---|---|
date | Thu, 25 Jul 2024 20:23:54 +0700 |
parents | c15770761865 |
children | d83726af7abb |
line wrap: on
line diff
--- a/semiconginev2/gltf.nim Wed Jul 24 23:26:34 2024 +0700 +++ b/semiconginev2/gltf.nim Thu Jul 25 20:23:54 2024 +0700 @@ -2,7 +2,7 @@ GLTFMesh*[TMesh, TMaterial] = object scenes*: seq[seq[int]] # each scene has a seq of node indices nodes*: seq[seq[int]] # each node has a seq of mesh indices - meshes*: seq[TMesh] + meshes*: seq[seq[(TMesh, VkPrimitiveTopology)]] materials*: seq[TMaterial] textures*: seq[Image[BGRA]] glTFHeader = object @@ -13,24 +13,35 @@ structuredContent: JsonNode binaryBufferData: seq[uint8] - MaterialAttributeNames = object + MaterialAttributeNames* = object # pbr - baseColorTexture: string - baseColorTextureUv: string - baseColorFactor: string - metallicRoughnessTexture: string - metallicRoughnessTextureUv: string - metallicFactor: string - roughnessFactor: string + 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 + 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 #[ static: @@ -71,6 +82,15 @@ 33648: VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT, 10497: VK_SAMPLER_ADDRESS_MODE_REPEAT }.toTable + PRIMITIVE_MODE_MAP = [ + 0: VK_PRIMITIVE_TOPOLOGY_POINT_LIST, + 1: VK_PRIMITIVE_TOPOLOGY_LINE_LIST, + 2: VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, # not correct, as mode 2 would be a loo, but vulkan has no concept of this + 3: VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, + 4: VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + 5: VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, + 6: VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, + ] #[ proc getGPUType(accessor: JsonNode, attribute: string): DataType = @@ -121,31 +141,28 @@ raise newException(Exception, "Unsupported feature: byteStride in buffer view") copyMem(dstPointer, addr mainBuffer[bufferOffset], result.len) -#[ -proc getAccessorData(root: JsonNode, accessor: JsonNode, mainBuffer: seq[uint8]): DataList = - result = InitDataList(thetype = accessor.getGPUType("??")) - result.SetLen(accessor["count"].getInt()) +proc getAccessorData[T](root: JsonNode, accessor: JsonNode, mainBuffer: seq[uint8]): seq[T] = + result.setLen(accessor["count"].getInt()) let bufferView = root["bufferViews"][accessor["bufferView"].getInt()] assert bufferView["buffer"].getInt() == 0, "Currently no external buffers supported" if accessor.hasKey("sparse"): - raise newException(Exception, "Sparce accessors are currently not implemented") + raise newException(Exception, "Sparce accessors are currently not supported") let accessorOffset = if accessor.hasKey("byteOffset"): accessor["byteOffset"].getInt() else: 0 let length = bufferView["byteLength"].getInt() let bufferOffset = bufferView["byteOffset"].getInt() + accessorOffset - var dstPointer = result.GetPointer() + var dstPointer = result.ToCPointer() 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()], int(result.thetype.Size)) - dstPointer = cast[pointer](cast[uint](dstPointer) + result.thetype.Size) + 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) else: copyMem(dstPointer, addr mainBuffer[bufferOffset], length) -]# proc loadTexture(root: JsonNode, textureNode: JsonNode, mainBuffer: seq[uint8]): Image[BGRA] = @@ -197,10 +214,80 @@ else: {.error: "Unsupported gltf material attribute".} +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 gltfAttribute, mappedName in fieldPairs(mapping): + when gltfAttribute != "" and name == mappedName: + assert value is GPUData, "Attribute " & name & " must be of type GPUData" + #[ + when gltfAttribute == "indices": + if primitive.hasKey(gltfAttribute): + let accessor = primitive[gltfAttribute].getInt() + value.data = getAccessorData[elementType(value.data)](root, root["accessors"][accessor], mainBuffer) + elif gltfAttribute == "material": + if primitive.hasKey(gltfAttribute): + value.data = typeof(value.data)(primitive[gltfAttribute].getInt()) + else: + if primitive["attributes"].hasKey(gltfAttribute): + let accessor = primitive["attributes"][gltfAttribute].getInt() + value.data = getAccessorData[elementType(value.data)](root, root["accessors"][accessor], mainBuffer) + ]# + + #[ + var indexType = None + let indexed = primitive.hasKey("indices") + if indexed: + var indexCount = root["accessors"][primitive["indices"].getInt()]["count"].getInt() + if indexCount < int(high(uint16)): + indexType = Small + else: + indexType = Big + + for attribute, accessor in primitive["attributes"].pairs: + let data = root.getAccessorData(root["accessors"][accessor.getInt()], mainBuffer) + if result.vertexCount == 0: + result.vertexCount = data.len + assert data.len == result.vertexCount + result[].InitVertexAttribute(attribute.toLowerAscii, data) + + if primitive.hasKey("material"): + let materialId = primitive["material"].getInt() + result[].material = materials[materialId] + else: + result[].material = EMPTY_MATERIAL.InitMaterialData() + + if primitive.hasKey("indices"): + assert result[].indexType != None + let data = root.getAccessorData(root["accessors"][primitive["indices"].getInt()], mainBuffer) + var tri: seq[int] + case data.thetype + of UInt16: + for entry in data[uint16][]: + tri.add int(entry) + if tri.len == 3: + # FYI gltf uses counter-clockwise indexing + result[].AppendIndicesData(tri[0], tri[1], tri[2]) + tri.setLen(0) + of UInt32: + for entry in data[uint32][]: + tri.add int(entry) + if tri.len == 3: + # FYI gltf uses counter-clockwise indexing + result[].AppendIndicesData(tri[0], tri[1], tri[2]) + tri.setLen(0) + else: + raise newException(Exception, &"Unsupported index data type: {data.thetype}") + ]# + #[ -proc loadMesh(meshname: string, root: JsonNode, primitiveNode: JsonNode, materials: seq[MaterialData], mainBuffer: seq[uint8]): Mesh = +proc loadPrimitive(meshname: string, root: JsonNode, primitiveNode: JsonNode, materials: seq[MaterialData], mainBuffer: seq[uint8]): Mesh = if primitiveNode.hasKey("mode") and primitiveNode["mode"].getInt() != 4: raise newException(Exception, "Currently only TRIANGLE mode is supported for geometry mode") @@ -265,7 +352,7 @@ if node.hasKey("mesh"): let mesh = root["meshes"][node["mesh"].getInt()] for primitive in mesh["primitives"]: - result.children.add MeshTree(mesh: loadMesh(mesh["name"].getStr(), root, primitive, materials, mainBuffer)) + result.children.add MeshTree(mesh: loadPrimitive(mesh["name"].getStr(), root, primitive, materials, mainBuffer)) # transformation if node.hasKey("matrix"): @@ -316,27 +403,9 @@ proc ReadglTF*[TMesh, TMaterial]( stream: Stream, - baseColorFactor: static string = "", - emissiveFactor: static string = "", - metallicFactor: static string = "", - roughnessFactor: static string = "", - baseColorTexture: static string = "", - metallicRoughnessTexture: static string = "", - normalTexture: static string = "", - occlusionTexture: static string = "", - emissiveTexture: static string = "", + meshAttributesMapping: static MeshAttributeNames, + materialAttributesMapping: static MaterialAttributeNames, ): GLTFMesh[TMesh, TMaterial] = - const mapping = MaterialAttributeNames( - baseColorFactor: baseColorFactor, - emissiveFactor: emissiveFactor, - metallicFactor: metallicFactor, - roughnessFactor: roughnessFactor, - baseColorTexture: baseColorTexture, - metallicRoughnessTexture: metallicRoughnessTexture, - normalTexture: normalTexture, - occlusionTexture: occlusionTexture, - emissiveTexture: emissiveTexture, - ) var header: glTFHeader data: glTFData @@ -367,38 +436,41 @@ if "materials" in data.structuredContent: for materialnode in items(data.structuredContent["materials"]): - result.materials.add loadMaterial[TMaterial](data.structuredContent, materialnode, data.binaryBufferData, mapping) + result.materials.add loadMaterial[TMaterial](data.structuredContent, materialnode, data.binaryBufferData, materialAttributesMapping) if "textures" in data.structuredContent: for texturenode in items(data.structuredContent["textures"]): result.textures.add loadTexture(data.structuredContent, texturenode, data.binaryBufferData) - echo result - # for scenedata in data.structuredContent["scenes"]: - # result.add data.structuredContent.loadScene(scenedata, materials, data.binaryBufferData) - # + if "meshes" in data.structuredContent: + for mesh in items(data.structuredContent["meshes"]): + var primitives: seq[(TMesh, VkPrimitiveTopology)] + for primitive in items(mesh["primitives"]): + primitives.add loadPrimitive[TMesh](data.structuredContent, primitive, meshAttributesMapping, data.binaryBufferData) + result.meshes.add primitives + + echo "Textures:" + for t in result.textures: + echo " ", t + + echo "Materials:" + for m in result.materials: + echo " ", m + + echo "Meshes:" + for m in result.meshes: + echo " Primitives:" + for p in m: + echo " ", p[1], ": ", p[0] + proc LoadMeshes*[TMesh, TMaterial]( path: string, - baseColorFactor: static string = "", - emissiveFactor: static string = "", - metallicFactor: static string = "", - roughnessFactor: static string = "", - baseColorTexture: static string = "", - metallicRoughnessTexture: static string = "", - normalTexture: static string = "", - occlusionTexture: static string = "", - emissiveTexture: static string = "", + meshAttributesMapping: static MeshAttributeNames, + materialAttributesMapping: static MaterialAttributeNames, package = DEFAULT_PACKAGE ): GLTFMesh[TMesh, TMaterial] = ReadglTF[TMesh, TMaterial]( stream = loadResource_intern(path, package = package), - baseColorFactor = baseColorFactor, - emissiveFactor = emissiveFactor, - metallicFactor = metallicFactor, - roughnessFactor = roughnessFactor, - baseColorTexture = baseColorTexture, - metallicRoughnessTexture = metallicRoughnessTexture, - normalTexture = normalTexture, - occlusionTexture = occlusionTexture, - emissiveTexture = emissiveTexture, + meshAttributesMapping = meshAttributesMapping, + materialAttributesMapping = materialAttributesMapping, )