changeset 778:dfc5978a3168

fix: most errors and Nim 2 transition problems
author Sam <sam@basx.dev>
date Sat, 12 Aug 2023 23:54:28 +0700
parents 754835bf175e
children a2c14402acd2
files src/semicongine/engine.nim src/semicongine/material.nim src/semicongine/mesh.nim src/semicongine/renderer.nim src/semicongine/resources/mesh.nim src/semicongine/vulkan/buffer.nim src/semicongine/vulkan/image.nim src/semicongine/vulkan/memory.nim
diffstat 8 files changed, 100 insertions(+), 50 deletions(-) [+]
line wrap: on
line diff
--- a/src/semicongine/engine.nim	Mon Aug 07 00:23:00 2023 +0700
+++ b/src/semicongine/engine.nim	Sat Aug 12 23:54:28 2023 +0700
@@ -114,6 +114,7 @@
   assert engine.renderer.isSome
   engine.renderer.get.setupDrawableBuffers(scene, vertexInput, samplers, transformAttribute=transformAttribute, materialIndexAttribute=materialIndexAttribute)
 
+#[
 proc addScene*(engine: var Engine, scene: Scene, materialShaders: Table[string, ShaderConfiguration], transformAttribute="transform", materialIndexAttribute="materialIndex") =
   if transformAttribute != "":
     for shader in materialShaders.values:
@@ -123,6 +124,7 @@
       assert materialIndexAttribute in map(shader.inputs, proc(a: ShaderAttribute): string = a.name)
   assert engine.renderer.isSome
   engine.renderer.get.setupDrawableBuffers(scene, vertexInput, samplers, transformAttribute=transformAttribute, materialIndexAttribute=materialIndexAttribute)
+  ]#
 
 proc renderScene*(engine: var Engine, scene: var Scene) =
   assert engine.state == Running
--- a/src/semicongine/material.nim	Mon Aug 07 00:23:00 2023 +0700
+++ b/src/semicongine/material.nim	Sat Aug 12 23:54:28 2023 +0700
@@ -1,4 +1,6 @@
 import std/tables
+import std/strformat
+import std/strutils
 
 import ./core
 
@@ -9,4 +11,11 @@
     constants*: Table[string, DataValue]
     textures*: Table[string, Texture]
 
-func `$`*(mat: Material): string = mat.name
+proc `$`*(material: Material): string =
+  var constants: seq[string]
+  for key, value in material.constants.pairs:
+    constants.add &"{key}: {value}"
+  var textures: seq[string]
+  for key in material.textures.keys:
+    textures.add &"{key}"
+  return &"""{material.name} ({material.index}) | Values: {constants.join(", ")} | Textures: {textures.join(", ")}"""
--- a/src/semicongine/mesh.nim	Mon Aug 07 00:23:00 2023 +0700
+++ b/src/semicongine/mesh.nim	Sat Aug 12 23:54:28 2023 +0700
@@ -85,31 +85,36 @@
   assert colors.len == 0 or colors.len == positions.len
   assert uvs.len == 0 or uvs.len == positions.len
 
-  result = Mesh(instanceCount: instanceCount, instanceTransforms: newSeqWith(int(instanceCount), Unit4F32))
+  # determine index type (uint8, uint16, uint32)
+  var indexType = None
+  if indices.len > 0:
+    indexType = Big
+    if autoResize and uint32(positions.len) < uint32(high(uint8)) and false: # TODO: check feature support
+      indexType = Tiny
+    elif autoResize and uint32(positions.len) < uint32(high(uint16)):
+      indexType = Small
+
+  result = Mesh(instanceCount: instanceCount, instanceTransforms: newSeqWith(int(instanceCount), Unit4F32), indexType: indexType)
   setMeshData(result, "position", positions.toSeq)
   if colors.len > 0: setMeshData(result, "color", colors.toSeq)
   if uvs.len > 0: setMeshData(result, "uv", uvs.toSeq)
 
+  # assert all indices are valid
   for i in indices:
     assert uint32(i[0]) < result.vertexCount
     assert uint32(i[1]) < result.vertexCount
     assert uint32(i[2]) < result.vertexCount
 
-  if indices.len == 0:
-      result.indexType = None
-  else:
-    if autoResize and uint32(positions.len) < uint32(high(uint8)) and false: # TODO: check feature support
-      result.indexType = Tiny
-      for i, tri in enumerate(indices):
-        result.tinyIndices.add [uint8(tri[0]), uint8(tri[1]), uint8(tri[2])]
-    elif autoResize and uint32(positions.len) < uint32(high(uint16)):
-      result.indexType = Small
-      for i, tri in enumerate(indices):
-        result.smallIndices.add [uint16(tri[0]), uint16(tri[1]), uint16(tri[2])]
-    else:
-      result.indexType = Big
-      for i, tri in enumerate(indices):
-        result.bigIndices.add [uint32(tri[0]), uint32(tri[1]), uint32(tri[2])]
+  # cast index values to appropiate type
+  if result.indexType == Tiny and uint32(positions.len) < uint32(high(uint8)) and false: # TODO: check feature support
+    for i, tri in enumerate(indices):
+      result.tinyIndices.add [uint8(tri[0]), uint8(tri[1]), uint8(tri[2])]
+  elif result.indexType == Small and uint32(positions.len) < uint32(high(uint16)):
+    for i, tri in enumerate(indices):
+      result.smallIndices.add [uint16(tri[0]), uint16(tri[1]), uint16(tri[2])]
+  elif result.indexType == Big:
+    for i, tri in enumerate(indices):
+      result.bigIndices.add [uint32(tri[0]), uint32(tri[1]), uint32(tri[2])]
   setInstanceData(result, "transform", newSeqWith(int(instanceCount), Unit4F32))
 
 func newMesh*(
--- a/src/semicongine/renderer.nim	Mon Aug 07 00:23:00 2023 +0700
+++ b/src/semicongine/renderer.nim	Sat Aug 12 23:54:28 2023 +0700
@@ -95,7 +95,7 @@
         assert mesh.materials.len > 0, "Missing material specification for mesh. Either set the 'materials' attribute or pass the argument 'materialIndexAttribute=\"\"' when calling 'addScene'"
         assert mesh.materials.len == getMeshData[uint16](mesh, scenedata.materialIndexAttribute)[].len
         for i, material in enumerate(mesh.materials):
-          let matIndex = materialIndex(scene, material)
+          let matIndex = scene.materialIndex(material)
           if matIndex < 0:
             raise newException(Exception, &"Required material '{material}' not available in scene (available are: {scene.materials.toSeq})")
           updateMeshData[uint16](mesh, scenedata.materialIndexAttribute, uint32(i), uint16(matIndex))
--- a/src/semicongine/resources/mesh.nim	Mon Aug 07 00:23:00 2023 +0700
+++ b/src/semicongine/resources/mesh.nim	Sat Aug 12 23:54:28 2023 +0700
@@ -137,10 +137,11 @@
     mesh.appendMeshData(attribute.toLowerAscii, data)
     vertexCount = data.len
 
-  var materialId = 0'u8
+  var materialId = 0'u16
   if primitiveNode.hasKey("material"):
-    materialId = uint8(primitiveNode["material"].getInt())
-  mesh.appendMeshData("material", newSeqWith[uint8](int(vertexCount), materialId))
+    materialId = uint16(primitiveNode["material"].getInt())
+  mesh.appendMeshData("materialIndex", newSeqWith[uint8](int(vertexCount), materialId))
+  mesh.materials.add newSeqWith[string](int(vertexCount), root["materials"][int(materialId)]["name"].getStr())
 
   if primitiveNode.hasKey("indices"):
     assert mesh.indexType != None
@@ -164,21 +165,21 @@
         raise newException(Exception, &"Unsupported index data type: {data.thetype}")
 
 # TODO: use one mesh per primitive?? right now we are merging primitives... check addPrimitive below
-proc loadMesh(root: JsonNode, meshNode: JsonNode, mainBuffer: seq[uint8], materials: seq[string]): Mesh =
-  result = Mesh(instanceCount: 1, instanceTransforms: newSeqWith(1, Unit4F32))
+proc loadMesh(root: JsonNode, meshNode: JsonNode, mainBuffer: seq[uint8]): Mesh =
 
   # check if and how we use indexes
   var indexCount = 0
+  var indexType = None
   let indexed = meshNode["primitives"][0].hasKey("indices")
   if indexed:
     for primitive in meshNode["primitives"]:
       indexCount += root["accessors"][primitive["indices"].getInt()]["count"].getInt()
     if indexCount < int(high(uint16)):
-      result.indexType = Small
+      indexType = Small
     else:
-      result.indexType = Big
-  else:
-    result.indexType = None
+      indexType = Big
+
+  result = Mesh(instanceCount: 1, instanceTransforms: newSeqWith(1, Unit4F32), indexType: indexType)
 
   # check we have the same attributes for all primitives
   let attributes = meshNode["primitives"][0]["attributes"].keys.toSeq
@@ -188,6 +189,7 @@
   # prepare mesh attributes
   for attribute, accessor in meshNode["primitives"][0]["attributes"].pairs:
     result.setMeshData(attribute.toLowerAscii, newDataList(thetype=root["accessors"][accessor.getInt()].getGPUType()))
+  result.setMeshData("materialIndex", newDataList(theType=UInt16))
 
   # add all mesh data
   for primitive in meshNode["primitives"]:
@@ -195,7 +197,7 @@
 
   setInstanceData(result, "transform", newSeqWith(int(result.instanceCount), Unit4F32))
 
-proc loadNode(root: JsonNode, node: JsonNode, mainBuffer: var seq[uint8], materials: seq[string]): Entity =
+proc loadNode(root: JsonNode, node: JsonNode, mainBuffer: var seq[uint8]): Entity =
   var name = "<Unknown>"
   if node.hasKey("name"):
     name = node["name"].getStr()
@@ -235,16 +237,16 @@
   # children
   if node.hasKey("children"):
     for childNode in node["children"]:
-      result.add loadNode(root, root["nodes"][childNode.getInt()], mainBuffer, materials)
+      result.add loadNode(root, root["nodes"][childNode.getInt()], mainBuffer)
 
   # mesh
   if node.hasKey("mesh"):
-    result["mesh"] = loadMesh(root, root["meshes"][node["mesh"].getInt()], mainBuffer, materials)
+    result["mesh"] = loadMesh(root, root["meshes"][node["mesh"].getInt()], mainBuffer)
 
-proc loadScene(root: JsonNode, scenenode: JsonNode, mainBuffer: var seq[uint8], materials: seq[string]): Scene =
+proc loadScene(root: JsonNode, scenenode: JsonNode, mainBuffer: var seq[uint8]): Scene =
   var rootEntity = newEntity("<root>")
   for nodeId in scenenode["nodes"]:
-    var node = loadNode(root, root["nodes"][nodeId.getInt()], mainBuffer, materials)
+    var node = loadNode(root, root["nodes"][nodeId.getInt()], mainBuffer)
     node.transform = node.transform * scale3d(1'f32, -1'f32, 1'f32)
     rootEntity.add node
 
@@ -283,7 +285,7 @@
       result.sampler.wrapModeT = SAMPLER_WRAP_MODE_MAP[sampler["wrapS"].getInt()]
 
 proc loadMaterial(root: JsonNode, materialNode: JsonNode, mainBuffer: var seq[uint8], materialIndex: int): Material =
-  result = Material(name: materialNode.getStr("name"), index: materialIndex)
+  result = Material(name: materialNode["name"].getStr(), index: materialIndex)
 
   let pbr = materialNode["pbrMetallicRoughness"]
 
@@ -367,14 +369,12 @@
   let bufferLenDiff = int(chunkLength) - data.structuredContent["buffers"][0]["byteLength"].getInt()
   assert 0 <= bufferLenDiff <= 3 # binary buffer may be aligned to 4 bytes
 
-  debug data.structuredContent.pretty
+  debug "Loading mesh: ", data.structuredContent.pretty
 
   for scenedata in data.structuredContent["scenes"]:
-    var materials: seq[string]
-    var scene = data.structuredContent.loadScene(scenedata, data.binaryBufferData, materials)
+    var scene = data.structuredContent.loadScene(scenedata, data.binaryBufferData)
     for i, materialNode in enumerate(data.structuredContent["materials"]):
       let material = loadMaterial(data.structuredContent, materialNode, data.binaryBufferData, i)
-      materials.add material.name
       scene.addMaterial material
 
     result.add scene
--- a/src/semicongine/vulkan/buffer.nim	Mon Aug 07 00:23:00 2023 +0700
+++ b/src/semicongine/vulkan/buffer.nim	Sat Aug 12 23:54:28 2023 +0700
@@ -50,9 +50,17 @@
     preferVRAM=preferVRAM,
     preferAutoFlush=preferAutoFlush
   )
-  buffer.memoryAllocated = true
+
   debug "Allocating memory for buffer: ", buffer.size, " bytes of type ", memoryType
-  buffer.memory = buffer.device.allocate(requirements.size, memoryType)
+  # need to replace the whole buffer object, due to case statement
+  buffer = Buffer(
+    device: buffer.device,
+    vk: buffer.vk,
+    size: buffer.size,
+    usage: buffer.usage,
+    memoryAllocated: true,
+    memory: buffer.device.allocate(requirements.size, memoryType)
+  )
   checkVkResult buffer.device.vk.vkBindBufferMemory(buffer.vk, buffer.memory.vk, VkDeviceSize(0))
 
 # currently no support for extended structure and concurrent/shared use
@@ -109,7 +117,13 @@
   if buffer.memoryAllocated:
     assert buffer.memory.vk.valid
     buffer.memory.free
-    buffer.memoryAllocated = false
+    buffer = Buffer(
+      device: buffer.device,
+      vk: buffer.vk,
+      size: buffer.size,
+      usage: buffer.usage,
+      memoryAllocated: false,
+    )
   buffer.vk.reset
 
 proc setData*(dst: Buffer, src: pointer, size: uint64, bufferOffset=0'u64) =
@@ -120,7 +134,7 @@
       dst.memory.flush()
   else: # use staging buffer, slower but required if memory is not host visible
     var stagingBuffer = dst.device.createBuffer(size, [VK_BUFFER_USAGE_TRANSFER_SRC_BIT], requireMappable=true, preferVRAM=false, preferAutoFlush=true)
-    stagingBuffer.setData(src, size, 0)
+    setData(stagingBuffer, src, size, 0)
     stagingBuffer.copy(dst, bufferOffset)
     stagingBuffer.destroy()
 
--- a/src/semicongine/vulkan/image.nim	Mon Aug 07 00:23:00 2023 +0700
+++ b/src/semicongine/vulkan/image.nim	Sat Aug 12 23:54:28 2023 +0700
@@ -63,9 +63,19 @@
     preferVRAM=preferVRAM,
     preferAutoFlush=preferAutoFlush
   )
-  image.memoryAllocated = true
+
   debug "Allocating memory for image: ", image.width, "x", image.height, "x", image.depth, ", ", requirements.size, " bytes of type ", memoryType
-  image.memory = image.device.allocate(requirements.size, memoryType)
+  image = VulkanImage(
+    device: image.device,
+    vk: image.vk,
+    width: image.width,
+    height: image.height,
+    depth: image.depth,
+    format: image.format,
+    usage: image.usage,
+    memoryAllocated: true,
+    memory: image.device.allocate(requirements.size, memoryType),
+  )
   checkVkResult image.device.vk.vkBindImageMemory(image.vk, image.memory.vk, VkDeviceSize(0))
 
 proc transitionImageLayout*(image: VulkanImage, oldLayout, newLayout: VkImageLayout) =
@@ -184,7 +194,16 @@
   if image.memoryAllocated:
     assert image.memory.vk.valid
     image.memory.free
-    image.memoryAllocated = false
+    image = VulkanImage(
+      device: image.device,
+      vk: image.vk,
+      width: image.width,
+      height: image.height,
+      depth: image.depth,
+      format: image.format,
+      usage: image.usage,
+      memoryAllocated: false,
+    )
   image.vk.reset
 
 proc createSampler*(device: Device, sampler: Sampler): VulkanSampler =
--- a/src/semicongine/vulkan/memory.nim	Mon Aug 07 00:23:00 2023 +0700
+++ b/src/semicongine/vulkan/memory.nim	Sat Aug 12 23:54:28 2023 +0700
@@ -68,12 +68,13 @@
 proc allocate*(device: Device, size: uint64, memoryType: MemoryType): DeviceMemory =
   assert device.vk.valid
   assert size > 0
-
-  result.device = device
-  result.size = size
-  result.memoryType = memoryType
-  result.canMap = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT in result.memoryType.flags
-  result.needsFlushing = not (VK_MEMORY_PROPERTY_HOST_COHERENT_BIT in result.memoryType.flags)
+  result = DeviceMemory(
+    device: device,
+    size: size,
+    memoryType: memoryType,
+    canMap: VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT in memoryType.flags,
+    needsFlushing: not (VK_MEMORY_PROPERTY_HOST_COHERENT_BIT in result.memoryType.flags),
+  )
 
   var allocationInfo = VkMemoryAllocateInfo(
     sType: VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,