# HG changeset patch # User Sam # Date 1704255595 -25200 # Node ID 252cbc10b25f14d87c24e76c11af6bcb726e84bc # Parent 8fd450acc6f84652cf5a6d48abf50bcbd786c6a2 did: improve/refactor some of the material API diff -r 8fd450acc6f8 -r 252cbc10b25f semicongine/core/dynamic_arrays.nim --- a/semicongine/core/dynamic_arrays.nim Mon Jan 01 21:41:40 2024 +0700 +++ b/semicongine/core/dynamic_arrays.nim Wed Jan 03 11:19:55 2024 +0700 @@ -1,4 +1,5 @@ import std/hashes +import std/strformat import ./gpu_types import ./vector @@ -252,7 +253,7 @@ elif T is Texture: value.texture[] = data else: {. error: "Virtual datatype has no values" .} -proc initDataList*(theType: DataType, len=1): DataList = +proc initDataList*(theType: DataType, len=0): DataList = result = DataList(theType: theType) case result.theType of Float32: result.float32 = new seq[float32] @@ -515,7 +516,7 @@ else: {. error: "Virtual datatype has no values" .} proc appendValues*(value: var DataList, data: DataList) = - assert value.theType == data.theType + assert value.theType == data.theType, &"Expected datalist of type {value.theType} but got {data.theType}" value.len += data.len case value.theType: of Float32: value.float32[].add data.float32[] @@ -563,6 +564,7 @@ of TextureType: value.texture[].add data.texture[] proc setValue*[T: GPUType|int|uint|float](value: var DataList, data: seq[T]) = + value.len = data.len when T is float32: value.float32[] = data elif T is float64: value.float64[] = data elif T is int8: value.int8[] = data diff -r 8fd450acc6f8 -r 252cbc10b25f semicongine/material.nim --- a/semicongine/material.nim Mon Jan 01 21:41:40 2024 +0700 +++ b/semicongine/material.nim Wed Jan 03 11:19:55 2024 +0700 @@ -35,9 +35,15 @@ proc `==`*(a, b: MaterialData): bool = return a.name == b.name -proc get*(material: MaterialData, attributeName: string): DataList = +proc get*[T](material: MaterialData, attributeName: string): seq[T] = + getValues[T](material.attributes[attributeName])[] + +proc getDataList*(material: MaterialData, attributeName: string): DataList = material.attributes[attributeName] +proc getSingle*[T](material: MaterialData, attributeName: string): T = + getValues[T](material.attributes[attributeName])[][0] + let EMPTY_MATERIAL* = MaterialType( name: "empty material", vertexAttributes: {"position": Vec3F32}.toTable, @@ -91,29 +97,29 @@ return &"""Material '{material.name}' | Attributes: {attributes.join(", ")}""" proc initMaterialData*( - materialType: MaterialType, + theType: MaterialType, name: string, attributes: Table[string, DataList], ): MaterialData = var theName = name if theName == "": - theName = &"material instance of '{materialType}'" - for matName, theType in materialType.attributes.pairs: - assert attributes.contains(matName), &"missing material attribute '{matName}' for {materialType}" + theName = &"material instance of '{theType}'" + for matName, theType in theType.attributes.pairs: + assert attributes.contains(matName), &"missing material attribute '{matName}' for {theType}" assert attributes[matName].theType == theType MaterialData( - theType: materialType, + theType: theType, name: theName, attributes: attributes, ) proc initMaterialData*( - materialType: MaterialType, + theType: MaterialType, name: string = "", attributes: openArray[(string, DataList)] = @[], ): MaterialData = var theName = name if theName == "": - theName = &"material instance of '{materialType}'" - initMaterialData(materialType=materialType, name=theName, attributes=attributes.toTable) + theName = &"material instance of '{theType}'" + initMaterialData(theType=theType, name=theName, attributes=attributes.toTable) diff -r 8fd450acc6f8 -r 252cbc10b25f semicongine/renderer.nim --- a/semicongine/renderer.nim Mon Jan 01 21:41:40 2024 +0700 +++ b/semicongine/renderer.nim Wed Jan 03 11:19:55 2024 +0700 @@ -271,13 +271,11 @@ for material in scene.getMaterials(materialType): if material.hasMatchingAttribute(texture): foundTexture = true - assert value.len == 1, &"Mesh material attribute '{materialAttribName}' has texture-array, but only single textures are allowed" - let textureValue = getValues[Texture](value)[][0] - if not uploadedTextures.contains(textureValue): - uploadedTextures[textureValue] = renderer.device.uploadTexture(textureValue) - scenedata.textures[shaderPipeline.vk][texture.name].add uploadedTextures[textureValue] - - break + let value = get[Texture](material, texture.name) + assert value.len == 1, &"Mesh material attribute '{texture.name}' has texture-array, but only single textures are allowed" + if not uploadedTextures.contains(value[0]): + uploadedTextures[value[0]] = renderer.device.uploadTexture(value[0]) + scenedata.textures[shaderPipeline.vk][texture.name].add uploadedTextures[value[0]] assert foundTexture, &"No texture found in shaderGlobals or materials for '{texture.name}'" let nTextures = scenedata.textures[shaderPipeline.vk][texture.name].len assert (texture.arrayCount == 0 and nTextures == 1) or texture.arrayCount == nTextures, &"Shader assigned to render '{materialType}' expected {texture.arrayCount} textures for '{texture.name}' but got {nTextures}" @@ -348,7 +346,6 @@ let dirty = scene.dirtyShaderGlobals if not forceAll and dirty.len == 0: - echo "Nothing dirty" return if forceAll: @@ -372,31 +369,24 @@ var offset = 0 # loop over all uniforms of the shader-shaderPipeline for uniform in shaderPipeline.uniforms: - echo "UNIFORM: ", uniform - if dirty.contains(uniform.name) or forceAll: # only update if necessary - var value: DataList + if dirty.contains(uniform.name) or forceAll: # only update uniforms if necessary + var value = initDataList(uniform.theType) if scene.shaderGlobals.hasKey(uniform.name): assert scene.shaderGlobals[uniform.name].thetype == uniform.thetype value = scene.shaderGlobals[uniform.name] else: var foundValue = false for material in renderer.scenedata[scene].materials[materialType]: - for name, materialValue in material.attributes.pairs: - if uniform.name == name: - if not foundValue: - foundValue = true - value = initDataList(materialValue.theType, 0) - else: - assert value.theType == materialValue.theType, &"Material for uniform '{uniform.name}' was found multiple times with different types: {value.theType} and {materialValue.theType}" - value.appendValues(materialValue) - break + if material.hasMatchingAttribute(uniform): + value.appendValues(material.getDataList(uniform.name)) + foundValue = true assert foundValue, &"Uniform '{uniform.name}' not found in scene shaderGlobals or materials" - assert (uniform.arrayCount == 0 and value.len == 1) or value.len == uniform.arrayCount, &"Uniform '{uniform.name}' found has wrong length (shader declares {uniform.arrayCount} but shaderGlobals and materials only provide {value.len})" + assert (uniform.arrayCount == 0 and value.len == 1) or value.len == uniform.arrayCount, &"Uniform '{uniform.name}' found has wrong length (shader declares {uniform.arrayCount} but shaderGlobals and materials provide {value.len})" let (pdata, size) = value.getRawData() assert size == uniform.size, "During uniform update: gathered value has size {size} but uniform expects size {uniform.size}" debug &" update uniform {uniform.name} with value: {value}" # TODO: technically we would only need to update the uniform buffer of the current - # frameInFlight, but we don't track for which frame the shaderglobals are no longer dirty + # frameInFlight (I think), but we don't track for which frame the shaderglobals are no longer dirty # therefore we have to update the uniform values in all buffers, of all inFlightframes (usually 2) for buffer in renderer.scenedata[scene].uniformBuffers[shaderPipeline.vk]: buffer.setData(pdata, size, offset) diff -r 8fd450acc6f8 -r 252cbc10b25f semicongine/resources/mesh.nim --- a/semicongine/resources/mesh.nim Mon Jan 01 21:41:40 2024 +0700 +++ b/semicongine/resources/mesh.nim Wed Jan 03 11:19:55 2024 +0700 @@ -224,7 +224,7 @@ else: setValue(attributes["emissiveColor"], @[newVec3f(1'f32, 1'f32, 1'f32)]) - result = initMaterialData(materialType=defaultMaterial, name=materialNode["name"].getStr(), attributes=attributes) + result = initMaterialData(theType=defaultMaterial, name=materialNode["name"].getStr(), attributes=attributes) proc loadMesh(meshname: string, root: JsonNode, primitiveNode: JsonNode, defaultMaterial: MaterialType, mainBuffer: seq[uint8]): Mesh = if primitiveNode.hasKey("mode") and primitiveNode["mode"].getInt() != 4: diff -r 8fd450acc6f8 -r 252cbc10b25f semicongine/text.nim --- a/semicongine/text.nim Mon Jan 01 21:41:40 2024 +0700 +++ b/semicongine/text.nim Wed Jan 03 11:19:55 2024 +0700 @@ -114,10 +114,10 @@ inc instanceCounter result.mesh[].renameAttribute("position", POSITION_ATTRIB) result.mesh[].renameAttribute("uv", UV_ATTRIB) - result.mesh.material = MaterialData( - theType: TEXT_MATERIAL_TYPE, - name: font.name & " text", - attributes: {"fontAtlas": initDataList(@[font.fontAtlas])}.toTable, + result.mesh.material = initMaterialData( + theType=TEXT_MATERIAL_TYPE, + name=font.name & " text", + attributes={"fontAtlas": initDataList(@[font.fontAtlas])}, ) result.updateMesh() diff -r 8fd450acc6f8 -r 252cbc10b25f tests/test_audio.nim --- a/tests/test_audio.nim Mon Jan 01 21:41:40 2024 +0700 +++ b/tests/test_audio.nim Wed Jan 03 11:19:55 2024 +0700 @@ -73,9 +73,9 @@ when isMainModule: startMixerThread() - # test1() + test1() + mixer[].stop() + test2() + mixer[].stop() + # test3() # mixer[].stop() - # test2() - # mixer[].stop() - test3() - mixer[].stop() diff -r 8fd450acc6f8 -r 252cbc10b25f tests/test_materials.nim --- a/tests/test_materials.nim Mon Jan 01 21:41:40 2024 +0700 +++ b/tests/test_materials.nim Wed Jan 03 11:19:55 2024 +0700 @@ -22,13 +22,13 @@ }.toTable, attributes: {"tex1": TextureType, "tex2": TextureType}.toTable ) - material = MaterialData( - theType: doubleTextureMaterial, - name: "swiss-thai", - attributes: { + material = initMaterialData( + theType=doubleTextureMaterial, + name="swiss-thai", + attributes={ "tex1": initDataList(@[Texture(image: thai, sampler: sampler)]), "tex2": initDataList(@[Texture(image: swiss, sampler: sampler)]), - }.toTable + } ) proc main() =