# HG changeset patch # User Sam # Date 1674530558 -25200 # Node ID f2c97bdbb0b3587e78d8a95f7226a1db43744096 # Parent a25325bec7f2256b991d7fa5935da1898046cc4d did: rename and update older demos to work with new APIs diff -r a25325bec7f2 -r f2c97bdbb0b3 examples/E01_hello_triangle.nim --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/E01_hello_triangle.nim Tue Jan 24 10:22:38 2023 +0700 @@ -0,0 +1,55 @@ +import std/times +import std/strutils +import std/enumerate + +import semicongine + +type + # define type of vertex + VertexDataA = object + position: PositionAttribute[Vec2] + color: ColorAttribute[Vec3] + +var pipeline: RenderPipeline[VertexDataA, void] + +proc globalUpdate(engine: var Engine, dt: float32) = + discard + +# vertex data (types must match the above VertexAttributes) +const + triangle_pos = @[ + Vec2([0.0'f32, -0.5'f32]), + Vec2([0.5'f32, 0.5'f32]), + Vec2([-0.5'f32, 0.5'f32]), + ] + triangle_color = @[ + Vec3([1.0'f32, 0.0'f32, 0.0'f32]), + Vec3([0.0'f32, 1.0'f32, 0.0'f32]), + Vec3([0.0'f32, 0.0'f32, 1.0'f32]), + ] + +when isMainModule: + var myengine = igniteEngine("Hello triangle") + + # build a mesh + var trianglemesh = new Mesh[VertexDataA] + trianglemesh.vertexData = VertexDataA( + position: PositionAttribute[Vec2](data: triangle_pos), + color: ColorAttribute[Vec3](data: triangle_color), + ) + # build a single-object scene graph + var triangle = newThing("triangle", trianglemesh) + + # upload data, prepare shaders, etc + const vertexShader = generateVertexShaderCode[VertexDataA, void]() + const fragmentShader = generateFragmentShaderCode[VertexDataA]() + pipeline = setupPipeline[VertexDataA, void, void]( + myengine, + triangle, + vertexShader, + fragmentShader + ) + # show something + myengine.run(pipeline, globalUpdate) + pipeline.trash() + myengine.trash() diff -r a25325bec7f2 -r f2c97bdbb0b3 examples/E02_squares.nim --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/E02_squares.nim Tue Jan 24 10:22:38 2023 +0700 @@ -0,0 +1,94 @@ +import std/times +import std/strutils +import std/math +import std/random + +import semicongine + +type + VertexDataA = object + position11: PositionAttribute[Vec2] + color22: ColorAttribute[Vec3] + index: GenericAttribute[uint32] + Uniforms = object + t: Descriptor[float32] + +var + pipeline: RenderPipeline[VertexDataA, Uniforms] + uniformdata = Uniforms(t: Descriptor[float32](value: 0'f32)) + +proc globalUpdate(engine: var Engine, dt: float32) = + uniformdata.t.value += dt + engine.vulkan.device.updateUniformData(pipeline, uniformdata) + +when isMainModule: + randomize() + var myengine = igniteEngine("Squares") + const + COLUMNS = 10 + ROWS = 10 + WIDTH = 2'f32 / COLUMNS + HEIGHT = 2'f32 / ROWS + var + vertices: array[COLUMNS * ROWS * 4, Vec2] + colors: array[COLUMNS * ROWS * 4, Vec3] + iValues: array[COLUMNS * ROWS * 4, uint32] + indices: array[COLUMNS * ROWS * 2, array[3, uint16]] + + for row in 0 ..< ROWS: + for col in 0 ..< COLUMNS: + let + y: float32 = (row * 2 / COLUMNS) - 1 + x: float32 = (col * 2 / ROWS) - 1 + color = Vec3([(x + 1) / 2, (y + 1) / 2, 0'f32]) + squareIndex = row * COLUMNS + col + vertIndex = squareIndex * 4 + vertices[vertIndex + 0] = Vec2([x, y]) + vertices[vertIndex + 1] = Vec2([x + WIDTH, y]) + vertices[vertIndex + 2] = Vec2([x + WIDTH, y + HEIGHT]) + vertices[vertIndex + 3] = Vec2([x, y + HEIGHT]) + colors[vertIndex + 0] = color + colors[vertIndex + 1] = color + colors[vertIndex + 2] = color + colors[vertIndex + 3] = color + iValues[vertIndex + 0] = uint32(squareIndex) + iValues[vertIndex + 1] = uint32(squareIndex) + iValues[vertIndex + 2] = uint32(squareIndex) + iValues[vertIndex + 3] = uint32(squareIndex) + indices[squareIndex * 2 + 0] = [uint16(vertIndex + 0), uint16(vertIndex + + 1), uint16(vertIndex + 2)] + indices[squareIndex * 2 + 1] = [uint16(vertIndex + 2), uint16(vertIndex + + 3), uint16(vertIndex + 0)] + + + type PIndexedMesh = IndexedMesh[VertexDataA, + uint16] # required so we can use ctor with ref/on heap + var squaremesh = PIndexedMesh( + vertexData: VertexDataA( + position11: PositionAttribute[Vec2](data: @vertices), + color22: ColorAttribute[Vec3](data: @colors), + index: GenericAttribute[uint32](data: @iValues), + ), + indices: @indices + ) + var scene = newThing("scene", newThing("squares", squaremesh)) + + const vertexShader = generateVertexShaderCode[VertexDataA, Uniforms]( + """ + float pos_weight = index / 100.0; // add some gamma correction? + float t = sin(uniforms.t * 0.5) * 0.5 + 0.5; + float v = min(1, max(0, pow(pos_weight - t, 2))); + v = pow(1 - v, 3000); + out_color = vec3(in_color.r, in_color.g, v * 0.5); + """ + ) + const fragmentShader = generateFragmentShaderCode[VertexDataA]() + pipeline = setupPipeline[VertexDataA, Uniforms, uint16]( + myengine, + scene, + vertexShader, + fragmentShader + ) + myengine.run(pipeline, globalUpdate) + pipeline.trash() + myengine.trash() diff -r a25325bec7f2 -r f2c97bdbb0b3 examples/E03_hello_cube.nim --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/E03_hello_cube.nim Tue Jan 24 10:22:38 2023 +0700 @@ -0,0 +1,110 @@ +# +# TODO: Needs Depth-Buffer first! +# +# +# +# +# +# + + +import std/times +import std/strutils + +import semicongine + +type + # define type of vertex + VertexDataA = object + position: PositionAttribute[Vec3] + color: ColorAttribute[Vec3] + Uniforms = object + model: Descriptor[Mat44] + view: Descriptor[Mat44] + projection: Descriptor[Mat44] + +var + pipeline: RenderPipeline[VertexDataA, Uniforms] + uniforms: Uniforms + t: float32 + + +proc globalUpdate(engine: var Engine, dt: float32) = + let ratio = float32(engine.vulkan.frameSize.y) / float32( + engine.vulkan.frameSize.x) + t += dt + uniforms.model.value = translate3d(0'f32, 0'f32, 10'f32) * rotate3d(t, + Yf32) # * rotate3d(float32(PI), Yf32) + + uniforms.view.value = Unit44f32 + uniforms.projection.value = Mat44(data: [ + ratio, 0'f32, 0'f32, 0'f32, + 0'f32, 1'f32, 0'f32, 0'f32, + 0'f32, 0'f32, 1'f32, 0'f32, + 0'f32, 0'f32, 0'f32, 1'f32, + ]) + uniforms.projection.value = perspective(float32(PI / 4), float32( + engine.vulkan.frameSize.x) / float32( + engine.vulkan.frameSize.y), 0.1'f32, 100'f32) + engine.vulkan.device.updateUniformData(pipeline, uniforms) + +const + TopLeftFront = Vec3([-0.5'f32, -0.5'f32, -0.5'f32]) + TopRightFront = Vec3([0.5'f32, -0.5'f32, -0.5'f32]) + BottomRightFront = Vec3([0.5'f32, 0.5'f32, -0.5'f32]) + BottomLeftFront = Vec3([-0.5'f32, 0.5'f32, -0.5'f32]) + TopLeftBack = Vec3([0.5'f32, -0.5'f32, 0.5'f32]) + TopRightBack = Vec3([-0.5'f32, -0.5'f32, 0.5'f32]) + BottomRightBack = Vec3([-0.5'f32, 0.5'f32, 0.5'f32]) + BottomLeftBack = Vec3([0.5'f32, 0.5'f32, 0.5'f32]) +const + cube_pos = @[ + TopLeftFront, TopRightFront, BottomRightFront, BottomLeftFront, # front + TopLeftBack, TopRightBack, BottomRightBack, BottomLeftBack, # back + TopLeftBack, TopLeftFront, BottomLeftFront, BottomLeftBack, # left + TopRightBack, TopRightFront, BottomRightFront, BottomRightBack, # right + TopLeftBack, TopRightBack, TopRightFront, TopLeftFront, # top + BottomLeftFront, BottomRightFront, BottomRightBack, BottomLeftBack, # bottom + ] + cube_color = @[ + Rf32, Rf32, Rf32, Rf32, + Rf32 * 0.5'f32, Rf32 * 0.5'f32, Rf32 * 0.5'f32, Rf32 * 0.5'f32, + Gf32, Gf32, Gf32, Gf32, + Gf32 * 0.5'f32, Gf32 * 0.5'f32, Gf32 * 0.5'f32, Gf32 * 0.5'f32, + Bf32, Bf32, Bf32, Bf32, + Bf32 * 0.5'f32, Bf32 * 0.5'f32, Bf32 * 0.5'f32, Bf32 * 0.5'f32, + ] +var + tris: seq[array[3, uint16]] +for i in 0'u16 ..< 6'u16: + let off = i * 4 + tris.add [off + 0'u16, off + 1'u16, off + 2'u16] + tris.add [off + 2'u16, off + 3'u16, off + 0'u16] + +when isMainModule: + var myengine = igniteEngine("Hello cube") + + # build a mesh + var trianglemesh = new IndexedMesh[VertexDataA, uint16] + trianglemesh.vertexData = VertexDataA( + position: PositionAttribute[Vec3](data: cube_pos), + color: ColorAttribute[Vec3](data: cube_color), + ) + trianglemesh.indices = tris + var cube = newThing("cube", trianglemesh) + + # upload data, prepare shaders, etc + const vertexShader = generateVertexShaderCode[VertexDataA, Uniforms](""" + out_position = (uniforms.projection * uniforms.view * uniforms.model) * vec4(in_position, 1); + """) + const fragmentShader = generateFragmentShaderCode[VertexDataA]() + pipeline = setupPipeline[VertexDataA, Uniforms, uint16]( + myengine, + cube, + vertexShader, + fragmentShader + ) + # show something + myengine.run(pipeline, globalUpdate) + pipeline.trash() + myengine.trash() diff -r a25325bec7f2 -r f2c97bdbb0b3 examples/E04_input.nim --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/E04_input.nim Tue Jan 24 10:22:38 2023 +0700 @@ -0,0 +1,117 @@ +import std/strutils +import std/times + +import semicongine + +type + # define type of vertex + VertexDataA = object + position: PositionAttribute[Vec2] + color: ColorAttribute[Vec3] + transform: ModelTransformAttribute + Uniforms = object + projection: Descriptor[Mat44] + cursor: Descriptor[Vec2] + +var + pipeline: RenderPipeline[VertexDataA, Uniforms] + uniforms: Uniforms + scene: Thing + time: float + + +proc globalUpdate(engine: var Engine, dt: float32) = + time += dt + uniforms.cursor.value = engine.input.mousePos + uniforms.projection.value = ortho[float32]( + 0'f32, float32(engine.vulkan.frameSize.x), + 0'f32, float32(engine.vulkan.frameSize.y), + 0'f32, 1'f32, + ) + engine.vulkan.device.updateUniformData(pipeline, uniforms) + + let cursor = firstPartWithName[Mesh[VertexDataA]](scene, "cursor") + if cursor != nil: + for c in cursor.vertexData.color.data.mitems: + c[1] = (sin(time * 8) * 0.5 + 0.5) * 0.2 + c[2] = (sin(time * 8) * 0.5 + 0.5) * 0.2 + engine.vulkan.device.updateVertexData(cursor.vertexData.color) + + var trans = translate3d(engine.input.mousePos.x, engine.input.mousePos.y, 0'f32) + # cursor.vertexData.transform.data = @[trans.transposed()] + engine.vulkan.device.updateVertexData(cursor.vertexData.transform) + + +const + shape = @[ + Vec2([ - 1'f32, - 1'f32]), + Vec2([1'f32, - 1'f32]), + Vec2([-0.3'f32, -0.3'f32]), + Vec2([-0.3'f32, -0.3'f32]), + Vec2([ - 1'f32, 1'f32]), + Vec2([ - 1'f32, - 1'f32]), + ] + colors = @[ + Vec3([1'f32, 0'f32, 0'f32]), + Vec3([1'f32, 0'f32, 0'f32]), + Vec3([1'f32, 0'f32, 0'f32]), + Vec3([0.8'f32, 0'f32, 0'f32]), + Vec3([0.8'f32, 0'f32, 0'f32]), + Vec3([0.8'f32, 0'f32, 0'f32]), + ] + +when isMainModule: + var myengine = igniteEngine("Input") + + var cursormesh = new Mesh[VertexDataA] + cursormesh.vertexData = VertexDataA( + position: PositionAttribute[Vec2](data: shape, useOnDeviceMemory: true), + color: ColorAttribute[Vec3](data: colors), + transform: ModelTransformAttribute(data: @[Unit44]), + ) + # transform the cursor a bit to make it look nice + for i in 0 ..< cursormesh.vertexData.position.data.len: + let cursorscale = ( + scale2d(20'f32, 20'f32) * + translate2d(1'f32, 1'f32) * + rotate2d(-float32(PI) / 4'f32) * + scale2d(0.5'f32, 1'f32) * + rotate2d(float32(PI) / 4'f32) + ) + let pos = Vec3([cursormesh.vertexData.position.data[i][0], + cursormesh.vertexData.position.data[i][1], 1'f32]) + cursormesh.vertexData.position.data[i] = (cursorscale * pos).xy + + var boxmesh = new Mesh[VertexDataA] + boxmesh.vertexData = VertexDataA( + position: PositionAttribute[Vec2](data: shape), + color: ColorAttribute[Vec3](data: colors), + transform: ModelTransformAttribute(data: @[Unit44]), + ) + for i in 0 ..< boxmesh.vertexData.position.data.len: + let boxscale = translate2d(100'f32, 100'f32) * scale2d(100'f32, 100'f32) + let pos = Vec3([boxmesh.vertexData.position.data[i][0], + boxmesh.vertexData.position.data[i][1], 1'f32]) + boxmesh.vertexData.position.data[i] = (boxscale * pos).xy + + scene = newThing("scene") + scene.add newThing("cursor", cursormesh) + scene.add newThing("a box", boxmesh, newTransform(Unit44), newTransform( + translate3d(1'f32, 0'f32, 0'f32))) + scene.add newTransform(scale3d(1.5'f32, 1.5'f32, 1.5'f32)) + + # upload data, prepare shaders, etc + const vertexShader = generateVertexShaderCode[VertexDataA, Uniforms](""" + out_position = uniforms.projection * transform * vec4(position, 0, 1); + """) + const fragmentShader = generateFragmentShaderCode[VertexDataA]() + pipeline = setupPipeline[VertexDataA, Uniforms, uint16]( + myengine, + scene, + vertexShader, + fragmentShader + ) + # show something + myengine.run(pipeline, globalUpdate) + pipeline.trash() + myengine.trash() diff -r a25325bec7f2 -r f2c97bdbb0b3 examples/alotof_triangles.nim --- a/examples/alotof_triangles.nim Sun Jan 22 22:46:53 2023 +0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -import std/times -import std/strutils -import std/math -import std/random - -import semicongine - -type - VertexDataA = object - position11: PositionAttribute[Vec2] - color22: ColorAttribute[Vec3] - Uniforms = object - dt: Descriptor[float32] - -proc globalUpdate(engine: var Engine, dt: float32) = - discard - -proc randomtransform(): Mat33 = - let randomscale = scale2d(float32(rand(1.0) + 0.5), float32(rand(1.0) + 0.5)) - let randomrotate = rotate2d(float32(rand(2 * PI))) - let randomtranslate = translate2d(float32(rand(1.6) - 0.8), float32(rand( - 1.6) - 0.8)) - result = randomtranslate * randomrotate * randomscale - -when isMainModule: - randomize() - var myengine = igniteEngine("A lot of triangles") - const baseTriangle = [ - Vec3([-0.1'f32, -0.1'f32, 1'f32]), - Vec3([0.1'f32, 0.1'f32, 1'f32]), - Vec3([-0.1'f32, 0.1'f32, 1'f32]), - ] - - var scene = newThing("scene") - - for i in 1 .. 300: - var randommesh = new Mesh[VertexDataA] - let randomcolor1 = Vec3([float32(rand(1)), float32(rand(1)), float32(rand(1))]) - let transform1 = randomtransform() - randommesh.vertexData = VertexDataA( - position11: PositionAttribute[Vec2]( - data: @[ - Vec2(transform1 * baseTriangle[0]), - Vec2(transform1 * baseTriangle[1]), - Vec2(transform1 * baseTriangle[2]), - ] - ), - color22: ColorAttribute[Vec3]( - data: @[randomcolor1, randomcolor1, randomcolor1] - ) - ) - - let randomcolor2 = Vec3([float32(rand(1)), float32(rand(1)), float32(rand(1))]) - let transform2 = randomtransform() - var randomindexedmesh = new IndexedMesh[VertexDataA, uint16] - randomindexedmesh.vertexData = VertexDataA( - position11: PositionAttribute[Vec2]( - data: @[ - Vec2(transform2 * baseTriangle[0]), - Vec2(transform2 * baseTriangle[1]), - Vec2(transform2 * baseTriangle[2]), - ] - ), - color22: ColorAttribute[Vec3]( - data: @[randomcolor2, randomcolor2, randomcolor2] - ) - ) - randomindexedmesh.indices = @[[0'u16, 1'u16, 2'u16]] - scene.add newThing("randommesh", randommesh, randomindexedmesh) - - const vertexShader = generateVertexShaderCode[VertexDataA, Uniforms]() - const fragmentShader = generateFragmentShaderCode[VertexDataA]() - var pipeline = setupPipeline[VertexDataA, float32, uint16]( - myengine, - scene, - vertexShader, - fragmentShader - ) - myengine.run(pipeline, globalUpdate) - pipeline.trash() - myengine.trash() diff -r a25325bec7f2 -r f2c97bdbb0b3 examples/hello_cube.nim --- a/examples/hello_cube.nim Sun Jan 22 22:46:53 2023 +0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,110 +0,0 @@ -# -# TODO: Needs Depth-Buffer first! -# -# -# -# -# -# - - -import std/times -import std/strutils - -import semicongine - -type - # define type of vertex - VertexDataA = object - position: PositionAttribute[Vec3] - color: ColorAttribute[Vec3] - Uniforms = object - model: Descriptor[Mat44] - view: Descriptor[Mat44] - projection: Descriptor[Mat44] - -var - pipeline: RenderPipeline[VertexDataA, Uniforms] - uniforms: Uniforms - t: float32 - - -proc globalUpdate(engine: var Engine, dt: float32) = - let ratio = float32(engine.vulkan.frameDimension.height) / float32( - engine.vulkan.frameDimension.width) - t += dt - uniforms.model.value = translate3d(0'f32, 0'f32, 10'f32) * rotate3d(t, - Yf32) # * rotate3d(float32(PI), Yf32) - - uniforms.view.value = Unit44f32 - uniforms.projection.value = Mat44(data: [ - ratio, 0'f32, 0'f32, 0'f32, - 0'f32, 1'f32, 0'f32, 0'f32, - 0'f32, 0'f32, 1'f32, 0'f32, - 0'f32, 0'f32, 0'f32, 1'f32, - ]) - uniforms.projection.value = perspective(float32(PI / 4), float32( - engine.vulkan.frameDimension.width) / float32( - engine.vulkan.frameDimension.height), 0.1'f32, 100'f32) - pipeline.updateUniformValues(uniforms) - -const - TopLeftFront = Vec3([-0.5'f32, -0.5'f32, -0.5'f32]) - TopRightFront = Vec3([0.5'f32, -0.5'f32, -0.5'f32]) - BottomRightFront = Vec3([0.5'f32, 0.5'f32, -0.5'f32]) - BottomLeftFront = Vec3([-0.5'f32, 0.5'f32, -0.5'f32]) - TopLeftBack = Vec3([0.5'f32, -0.5'f32, 0.5'f32]) - TopRightBack = Vec3([-0.5'f32, -0.5'f32, 0.5'f32]) - BottomRightBack = Vec3([-0.5'f32, 0.5'f32, 0.5'f32]) - BottomLeftBack = Vec3([0.5'f32, 0.5'f32, 0.5'f32]) -const - cube_pos = @[ - TopLeftFront, TopRightFront, BottomRightFront, BottomLeftFront, # front - TopLeftBack, TopRightBack, BottomRightBack, BottomLeftBack, # back - TopLeftBack, TopLeftFront, BottomLeftFront, BottomLeftBack, # left - TopRightBack, TopRightFront, BottomRightFront, BottomRightBack, # right - TopLeftBack, TopRightBack, TopRightFront, TopLeftFront, # top - BottomLeftFront, BottomRightFront, BottomRightBack, BottomLeftBack, # bottom - ] - cube_color = @[ - Rf32, Rf32, Rf32, Rf32, - Rf32 * 0.5'f32, Rf32 * 0.5'f32, Rf32 * 0.5'f32, Rf32 * 0.5'f32, - Gf32, Gf32, Gf32, Gf32, - Gf32 * 0.5'f32, Gf32 * 0.5'f32, Gf32 * 0.5'f32, Gf32 * 0.5'f32, - Bf32, Bf32, Bf32, Bf32, - Bf32 * 0.5'f32, Bf32 * 0.5'f32, Bf32 * 0.5'f32, Bf32 * 0.5'f32, - ] -var - tris: seq[array[3, uint16]] -for i in 0'u16 ..< 6'u16: - let off = i * 4 - tris.add [off + 0'u16, off + 1'u16, off + 2'u16] - tris.add [off + 2'u16, off + 3'u16, off + 0'u16] - -when isMainModule: - var myengine = igniteEngine("Hello cube") - - # build a mesh - var trianglemesh = new IndexedMesh[VertexDataA, uint16] - trianglemesh.vertexData = VertexDataA( - position: PositionAttribute[Vec3](data: cube_pos), - color: ColorAttribute[Vec3](data: cube_color), - ) - trianglemesh.indices = tris - var cube = newThing("cube", trianglemesh) - - # upload data, prepare shaders, etc - const vertexShader = generateVertexShaderCode[VertexDataA, Uniforms](""" - out_position = (uniforms.projection * uniforms.view * uniforms.model) * vec4(in_position, 1); - """) - const fragmentShader = generateFragmentShaderCode[VertexDataA]() - pipeline = setupPipeline[VertexDataA, Uniforms, uint16]( - myengine, - cube, - vertexShader, - fragmentShader - ) - # show something - myengine.run(pipeline, globalUpdate) - pipeline.trash() - myengine.trash() diff -r a25325bec7f2 -r f2c97bdbb0b3 examples/hello_triangle.nim --- a/examples/hello_triangle.nim Sun Jan 22 22:46:53 2023 +0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -import std/times -import std/strutils -import std/enumerate - -import semicongine - -type - # define type of vertex - VertexDataA = object - position: PositionAttribute[Vec2] - color: ColorAttribute[Vec3] - -var pipeline: RenderPipeline[VertexDataA, void] - -proc globalUpdate(engine: var Engine, dt: float32) = - discard - -# vertex data (types must match the above VertexAttributes) -const - triangle_pos = @[ - Vec2([0.0'f32, -0.5'f32]), - Vec2([0.5'f32, 0.5'f32]), - Vec2([-0.5'f32, 0.5'f32]), - ] - triangle_color = @[ - Vec3([1.0'f32, 0.0'f32, 0.0'f32]), - Vec3([0.0'f32, 1.0'f32, 0.0'f32]), - Vec3([0.0'f32, 0.0'f32, 1.0'f32]), - ] - -when isMainModule: - var myengine = igniteEngine("Hello triangle") - - # build a mesh - var trianglemesh = new Mesh[VertexDataA] - trianglemesh.vertexData = VertexDataA( - position: PositionAttribute[Vec2](data: triangle_pos), - color: ColorAttribute[Vec3](data: triangle_color), - ) - # build a single-object scene graph - var triangle = newThing("triangle", trianglemesh) - - # upload data, prepare shaders, etc - const vertexShader = generateVertexShaderCode[VertexDataA, void]() - const fragmentShader = generateFragmentShaderCode[VertexDataA]() - pipeline = setupPipeline[VertexDataA, void, void]( - myengine, - triangle, - vertexShader, - fragmentShader - ) - # show something - myengine.run(pipeline, globalUpdate) - pipeline.trash() - myengine.trash() diff -r a25325bec7f2 -r f2c97bdbb0b3 examples/input.nim --- a/examples/input.nim Sun Jan 22 22:46:53 2023 +0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,139 +0,0 @@ -import std/strutils -import std/times - -import semicongine - -type - # define type of vertex - VertexDataA = object - position: PositionAttribute[Vec2] - color: ColorAttribute[Vec3] - # transform: ModelTransformAttribute - # TODO: make this somehow a single vertex attribute - m1: GenericInstanceAttribute[Vec4] - m2: GenericInstanceAttribute[Vec4] - m3: GenericInstanceAttribute[Vec4] - m4: GenericInstanceAttribute[Vec4] - Uniforms = object - projection: Descriptor[Mat44] - cursor: Descriptor[Vec2] - -var - pipeline: RenderPipeline[VertexDataA, Uniforms] - uniforms: Uniforms - scene: Thing - time: float - - -proc globalUpdate(engine: var Engine, dt: float32) = - time += dt - uniforms.cursor.value = engine.input.mousePos - uniforms.projection.value = ortho[float32]( - 0'f32, float32(engine.vulkan.frameSize.x), - 0'f32, float32(engine.vulkan.frameSize.y), - 0'f32, 1'f32, - ) - engine.vulkan.device.updateUniformData(pipeline, uniforms) - - let cursor = firstPartWithName[Mesh[VertexDataA]](scene, "cursor") - if cursor != nil: - for c in cursor.vertexData.color.data.mitems: - c[1] = (sin(time * 8) * 0.5 + 0.5) * 0.2 - c[2] = (sin(time * 8) * 0.5 + 0.5) * 0.2 - engine.vulkan.device.updateVertexData(cursor.vertexData.color) - var trans = Unit44 * translate3d(engine.input.mousePos.x, - engine.input.mousePos.y, 0'f32) - cursor.vertexData.m1.data = @[trans.col(0)] - cursor.vertexData.m2.data = @[trans.col(1)] - cursor.vertexData.m3.data = @[trans.col(2)] - cursor.vertexData.m4.data = @[trans.col(3)] - engine.vulkan.device.updateVertexData(cursor.vertexData.m1) - engine.vulkan.device.updateVertexData(cursor.vertexData.m2) - engine.vulkan.device.updateVertexData(cursor.vertexData.m3) - engine.vulkan.device.updateVertexData(cursor.vertexData.m4) - - -const - shape = @[ - Vec2([ - 1'f32, - 1'f32]), - Vec2([1'f32, - 1'f32]), - Vec2([-0.3'f32, -0.3'f32]), - Vec2([-0.3'f32, -0.3'f32]), - Vec2([ - 1'f32, 1'f32]), - Vec2([ - 1'f32, - 1'f32]), - ] - colors = @[ - Vec3([1'f32, 0'f32, 0'f32]), - Vec3([1'f32, 0'f32, 0'f32]), - Vec3([1'f32, 0'f32, 0'f32]), - Vec3([0.8'f32, 0'f32, 0'f32]), - Vec3([0.8'f32, 0'f32, 0'f32]), - Vec3([0.8'f32, 0'f32, 0'f32]), - ] - -when isMainModule: - var myengine = igniteEngine("Input") - - var cursormesh = new Mesh[VertexDataA] - cursormesh.vertexData = VertexDataA( - position: PositionAttribute[Vec2](data: shape, useOnDeviceMemory: true), - color: ColorAttribute[Vec3](data: colors), - # transform: ModelTransformAttribute(data: @[Unit44]), - m1: GenericInstanceAttribute[Vec4](data: @[Unit44.row(0)]), - m2: GenericInstanceAttribute[Vec4](data: @[Unit44.row(1)]), - m3: GenericInstanceAttribute[Vec4](data: @[Unit44.row(2)]), - m4: GenericInstanceAttribute[Vec4](data: @[Unit44.row(3)]), - ) - # transform the cursor a bit to make it look nice - for i in 0 ..< cursormesh.vertexData.position.data.len: - let cursorscale = ( - scale2d(20'f32, 20'f32) * - translate2d(1'f32, 1'f32) * - rotate2d(-float32(PI) / 4'f32) * - scale2d(0.5'f32, 1'f32) * - rotate2d(float32(PI) / 4'f32) - ) - let pos = Vec3([cursormesh.vertexData.position.data[i][0], - cursormesh.vertexData.position.data[i][1], 1'f32]) - cursormesh.vertexData.position.data[i] = (cursorscale * pos).xy - - var boxmesh = new Mesh[VertexDataA] - boxmesh.vertexData = VertexDataA( - position: PositionAttribute[Vec2](data: shape), - color: ColorAttribute[Vec3](data: colors), - # transform: ModelTransformAttribute(data: @[Unit44]), - m1: GenericInstanceAttribute[Vec4](data: @[Unit44.row(0)]), - m2: GenericInstanceAttribute[Vec4](data: @[Unit44.row(1)]), - m3: GenericInstanceAttribute[Vec4](data: @[Unit44.row(2)]), - m4: GenericInstanceAttribute[Vec4](data: @[Unit44.row(3)]), - ) - for i in 0 ..< boxmesh.vertexData.position.data.len: - let boxscale = translate2d(100'f32, 100'f32) * scale2d(100'f32, 100'f32) - let pos = Vec3([boxmesh.vertexData.position.data[i][0], - boxmesh.vertexData.position.data[i][1], 1'f32]) - boxmesh.vertexData.position.data[i] = (boxscale * pos).xy - echo boxmesh.vertexData.position.data - - scene = newThing("scene") - scene.add newThing("cursor", cursormesh) - scene.add newThing("a box", boxmesh, newTransform(Unit44), newTransform( - translate3d(1'f32, 0'f32, 0'f32))) - scene.add newTransform(scale3d(1.5'f32, 1.5'f32, 1.5'f32)) - - # upload data, prepare shaders, etc - const vertexShader = generateVertexShaderCode[VertexDataA, Uniforms](""" - mat4 mat = mat4(m1, m2, m3, m4); - out_position = uniforms.projection * mat * vec4(position, 0, 1); - """) - echo vertexShader - const fragmentShader = generateFragmentShaderCode[VertexDataA]() - pipeline = setupPipeline[VertexDataA, Uniforms, uint16]( - myengine, - scene, - vertexShader, - fragmentShader - ) - # show something - myengine.run(pipeline, globalUpdate) - pipeline.trash() - myengine.trash() diff -r a25325bec7f2 -r f2c97bdbb0b3 examples/squares.nim --- a/examples/squares.nim Sun Jan 22 22:46:53 2023 +0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +0,0 @@ -import std/times -import std/strutils -import std/math -import std/random - -import semicongine - -type - VertexDataA = object - position11: PositionAttribute[Vec2] - color22: ColorAttribute[Vec3] - index: GenericAttribute[uint32] - Uniforms = object - t: Descriptor[float32] - -var - pipeline: RenderPipeline[VertexDataA, Uniforms] - uniformdata = Uniforms(t: Descriptor[float32](value: 0'f32)) - -proc globalUpdate(engine: var Engine, dt: float32) = - uniformdata.t.value += dt - pipeline.updateUniformValues(uniformdata) - -when isMainModule: - randomize() - var myengine = igniteEngine("Squares") - const - COLUMNS = 10 - ROWS = 10 - WIDTH = 2'f32 / COLUMNS - HEIGHT = 2'f32 / ROWS - var - vertices: array[COLUMNS * ROWS * 4, Vec2] - colors: array[COLUMNS * ROWS * 4, Vec3] - iValues: array[COLUMNS * ROWS * 4, uint32] - indices: array[COLUMNS * ROWS * 2, array[3, uint16]] - - for row in 0 ..< ROWS: - for col in 0 ..< COLUMNS: - let - y: float32 = (row * 2 / COLUMNS) - 1 - x: float32 = (col * 2 / ROWS) - 1 - color = Vec3([(x + 1) / 2, (y + 1) / 2, 0'f32]) - squareIndex = row * COLUMNS + col - vertIndex = squareIndex * 4 - vertices[vertIndex + 0] = Vec2([x, y]) - vertices[vertIndex + 1] = Vec2([x + WIDTH, y]) - vertices[vertIndex + 2] = Vec2([x + WIDTH, y + HEIGHT]) - vertices[vertIndex + 3] = Vec2([x, y + HEIGHT]) - colors[vertIndex + 0] = color - colors[vertIndex + 1] = color - colors[vertIndex + 2] = color - colors[vertIndex + 3] = color - iValues[vertIndex + 0] = uint32(squareIndex) - iValues[vertIndex + 1] = uint32(squareIndex) - iValues[vertIndex + 2] = uint32(squareIndex) - iValues[vertIndex + 3] = uint32(squareIndex) - indices[squareIndex * 2 + 0] = [uint16(vertIndex + 0), uint16(vertIndex + - 1), uint16(vertIndex + 2)] - indices[squareIndex * 2 + 1] = [uint16(vertIndex + 2), uint16(vertIndex + - 3), uint16(vertIndex + 0)] - - - type PIndexedMesh = ref IndexedMesh[VertexDataA, - uint16] # required so we can use ctor with ref/on heap - var squaremesh = PIndexedMesh( - vertexData: VertexDataA( - position11: PositionAttribute[Vec2](data: @vertices), - color22: ColorAttribute[Vec3](data: @colors), - index: GenericAttribute[uint32](data: @iValues), - ), - indices: @indices - ) - var scene = newThing("scene", newThing("squares", squaremesh)) - - const vertexShader = generateVertexShaderCode[VertexDataA, Uniforms]( - """ - float pos_weight = index / 100.0; // add some gamma correction? - float t = sin(uniforms.t * 0.5) * 0.5 + 0.5; - float v = min(1, max(0, pow(pos_weight - t, 2))); - v = pow(1 - v, 3000); - out_color = vec3(in_color.r, in_color.g, v * 0.5); - """ - ) - const fragmentShader = generateFragmentShaderCode[VertexDataA]() - pipeline = setupPipeline[VertexDataA, Uniforms, uint16]( - myengine, - scene, - vertexShader, - fragmentShader - ) - myengine.run(pipeline, globalUpdate) - pipeline.trash() - myengine.trash() diff -r a25325bec7f2 -r f2c97bdbb0b3 src/semicongine/engine.nim --- a/src/semicongine/engine.nim Sun Jan 22 22:46:53 2023 +0700 +++ b/src/semicongine/engine.nim Tue Jan 24 10:22:38 2023 +0700 @@ -95,33 +95,40 @@ currentscenedata*: Thing input*: Input -proc getAllPhysicalDevices(instance: VkInstance, surface: VkSurfaceKHR): seq[PhysicalDevice] = +proc getAllPhysicalDevices(instance: VkInstance, surface: VkSurfaceKHR): seq[ + PhysicalDevice] = for vulkanPhysicalDevice in getVulkanPhysicalDevices(instance): - var device = PhysicalDevice(device: vulkanPhysicalDevice, extensions: getDeviceExtensions(vulkanPhysicalDevice)) + var device = PhysicalDevice(device: vulkanPhysicalDevice, + extensions: getDeviceExtensions(vulkanPhysicalDevice)) vkGetPhysicalDeviceProperties(vulkanPhysicalDevice, addr(device.properties)) vkGetPhysicalDeviceFeatures(vulkanPhysicalDevice, addr(device.features)) device.formats = vulkanPhysicalDevice.getDeviceSurfaceFormats(surface) device.presentModes = vulkanPhysicalDevice.getDeviceSurfacePresentModes(surface) debug(&"Physical device nr {int(vulkanPhysicalDevice)} {cleanString(device.properties.deviceName)}") - for i, queueFamilyProperty in enumerate(getQueueFamilies(vulkanPhysicalDevice)): + for i, queueFamilyProperty in enumerate(getQueueFamilies( + vulkanPhysicalDevice)): var hasSurfaceSupport: VkBool32 = VK_FALSE - checkVkResult vkGetPhysicalDeviceSurfaceSupportKHR(vulkanPhysicalDevice, uint32(i), surface, addr(hasSurfaceSupport)) - device.queueFamilies.add(QueueFamily(properties: queueFamilyProperty, hasSurfaceSupport: bool(hasSurfaceSupport))) + checkVkResult vkGetPhysicalDeviceSurfaceSupportKHR(vulkanPhysicalDevice, + uint32(i), surface, addr(hasSurfaceSupport)) + device.queueFamilies.add(QueueFamily(properties: queueFamilyProperty, + hasSurfaceSupport: bool(hasSurfaceSupport))) debug(&" Queue family {i} {queueFamilyProperty}") result.add(device) proc filterForDevice(devices: seq[PhysicalDevice]): seq[(PhysicalDevice, uint32, uint32)] = for device in devices: - if not (device.formats.len > 0 and device.presentModes.len > 0 and "VK_KHR_swapchain" in device.extensions): + if not (device.formats.len > 0 and device.presentModes.len > 0 and + "VK_KHR_swapchain" in device.extensions): continue var graphicsQueueFamily = high(uint32) var presentationQueueFamily = high(uint32) for i, queueFamily in enumerate(device.queueFamilies): if queueFamily.hasSurfaceSupport: presentationQueueFamily = uint32(i) - if bool(uint32(queueFamily.properties.queueFlags) and ord(VK_QUEUE_GRAPHICS_BIT)): + if bool(uint32(queueFamily.properties.queueFlags) and ord( + VK_QUEUE_GRAPHICS_BIT)): graphicsQueueFamily = uint32(i) if graphicsQueueFamily != high(uint32) and presentationQueueFamily != high(uint32): result.add((device, graphicsQueueFamily, presentationQueueFamily)) @@ -130,15 +137,19 @@ debug(&"Viable device: {cleanString(device.properties.deviceName)} (graphics queue family {graphicsQueueFamily}, presentation queue family {presentationQueueFamily})") -proc getFrameDimension(window: NativeWindow, device: VkPhysicalDevice, surface: VkSurfaceKHR): TVec2[uint32] = +proc getFrameDimension(window: NativeWindow, device: VkPhysicalDevice, + surface: VkSurfaceKHR): TVec2[uint32] = let capabilities = device.getSurfaceCapabilities(surface) if capabilities.currentExtent.width != high(uint32): - return TVec2[uint32]([capabilities.currentExtent.width, capabilities.currentExtent.height]) + return TVec2[uint32]([capabilities.currentExtent.width, + capabilities.currentExtent.height]) else: let (width, height) = window.size() return TVec2[uint32]([ - min(max(uint32(width), capabilities.minImageExtent.width), capabilities.maxImageExtent.width), - min(max(uint32(height), capabilities.minImageExtent.height), capabilities.maxImageExtent.height), + min(max(uint32(width), capabilities.minImageExtent.width), + capabilities.maxImageExtent.width), + min(max(uint32(height), capabilities.minImageExtent.height), + capabilities.maxImageExtent.height), ]) when DEBUG_LOG: @@ -158,9 +169,11 @@ pfnUserCallback: debugCallback, pUserData: nil, ) - checkVkResult instance.vkCreateDebugUtilsMessengerEXT(addr(createInfo), nil, addr(result)) + checkVkResult instance.vkCreateDebugUtilsMessengerEXT(addr(createInfo), nil, + addr(result)) -proc setupVulkanDeviceAndQueues(instance: VkInstance, surface: VkSurfaceKHR): Device = +proc setupVulkanDeviceAndQueues(instance: VkInstance, + surface: VkSurfaceKHR): Device = let usableDevices = instance.getAllPhysicalDevices(surface).filterForDevice() if len(usableDevices) == 0: raise newException(Exception, "No suitable graphics device found") @@ -169,7 +182,7 @@ result.presentationQueueFamily = usableDevices[0][2] debug(&"Chose device {cleanString(result.physicalDevice.properties.deviceName)}") - + (result.device, result.graphicsQueue, result.presentationQueue) = getVulcanDevice( result.physicalDevice.device, result.physicalDevice.features, @@ -177,7 +190,9 @@ result.presentationQueueFamily, ) -proc setupSwapChain(device: VkDevice, physicalDevice: PhysicalDevice, surface: VkSurfaceKHR, dimension: TVec2[uint32], surfaceFormat: VkSurfaceFormatKHR): Swapchain = +proc setupSwapChain(device: VkDevice, physicalDevice: PhysicalDevice, + surface: VkSurfaceKHR, dimension: TVec2[uint32], + surfaceFormat: VkSurfaceFormatKHR): Swapchain = let capabilities = physicalDevice.device.getSurfaceCapabilities(surface) var selectedPresentationMode = getPresentMode(physicalDevice.presentModes) @@ -202,7 +217,8 @@ clipped: VK_TRUE, oldSwapchain: VkSwapchainKHR(0), ) - checkVkResult device.vkCreateSwapchainKHR(addr(swapchainCreateInfo), nil, addr(result.swapchain)) + checkVkResult device.vkCreateSwapchainKHR(addr(swapchainCreateInfo), nil, + addr(result.swapchain)) result.images = device.getSwapChainImages(result.swapchain) # setup swapchian image views @@ -228,7 +244,8 @@ layerCount: 1, ), ) - checkVkResult device.vkCreateImageView(addr(imageViewCreateInfo), nil, addr(result.imageviews[i])) + checkVkResult device.vkCreateImageView(addr(imageViewCreateInfo), nil, addr( + result.imageviews[i])) proc setupRenderPass(device: VkDevice, format: VkFormat): VkRenderPass = var @@ -254,9 +271,11 @@ dependency = VkSubpassDependency( srcSubpass: VK_SUBPASS_EXTERNAL, dstSubpass: 0, - srcStageMask: VkPipelineStageFlags(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT), + srcStageMask: VkPipelineStageFlags( + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT), srcAccessMask: VkAccessFlags(0), - dstStageMask: VkPipelineStageFlags(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT), + dstStageMask: VkPipelineStageFlags( + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT), dstAccessMask: VkAccessFlags(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT), ) renderPassCreateInfo = VkRenderPassCreateInfo( @@ -270,11 +289,15 @@ ) checkVkResult device.vkCreateRenderPass(addr(renderPassCreateInfo), nil, addr(result)) -proc initRenderPipeline[VertexType, Uniforms](device: VkDevice, frameSize: TVec2[uint32], renderPass: VkRenderPass, vertexShader, fragmentShader: static string): RenderPipeline[VertexType, Uniforms] = +proc initRenderPipeline[VertexType, Uniforms](device: VkDevice, + frameSize: TVec2[uint32], renderPass: VkRenderPass, vertexShader, + fragmentShader: static string): RenderPipeline[VertexType, Uniforms] = # load shaders result.device = device - result.shaders.add(initShaderProgram[VertexType, Uniforms](device, VK_SHADER_STAGE_VERTEX_BIT, vertexShader)) - result.shaders.add(initShaderProgram[VertexType, Uniforms](device, VK_SHADER_STAGE_FRAGMENT_BIT, fragmentShader)) + result.shaders.add(initShaderProgram[VertexType, Uniforms](device, + VK_SHADER_STAGE_VERTEX_BIT, vertexShader)) + result.shaders.add(initShaderProgram[VertexType, Uniforms](device, + VK_SHADER_STAGE_FRAGMENT_BIT, fragmentShader)) var # define which parts can be dynamic (pipeline is fixed after setup) @@ -356,8 +379,9 @@ blendConstants: [0.0'f, 0.0'f, 0.0'f, 0.0'f], ) - result.descriptorSetLayout = device.createUniformDescriptorLayout(VkShaderStageFlags(VK_SHADER_STAGE_VERTEX_BIT), 0) - var + result.descriptorSetLayout = device.createUniformDescriptorLayout( + VkShaderStageFlags(VK_SHADER_STAGE_VERTEX_BIT), 0) + var # "globals" that go into the shader, uniforms etc. pipelineLayoutInfo = VkPipelineLayoutCreateInfo( sType: VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, @@ -366,7 +390,8 @@ pushConstantRangeCount: 0, pPushConstantRanges: nil, ) - checkVkResult vkCreatePipelineLayout(device, addr(pipelineLayoutInfo), nil, addr(result.layout)) + checkVkResult vkCreatePipelineLayout(device, addr(pipelineLayoutInfo), nil, + addr(result.layout)) var stages: seq[VkPipelineShaderStageCreateInfo] for shader in result.shaders: @@ -398,7 +423,8 @@ addr(result.pipeline) ) -proc setupFramebuffers(device: VkDevice, swapchain: var Swapchain, renderPass: VkRenderPass, dimension: TVec2[uint32]): seq[VkFramebuffer] = +proc setupFramebuffers(device: VkDevice, swapchain: var Swapchain, + renderPass: VkRenderPass, dimension: TVec2[uint32]): seq[VkFramebuffer] = result = newSeq[VkFramebuffer](swapchain.images.len) for i, imageview in enumerate(swapchain.imageviews): var framebufferInfo = VkFramebufferCreateInfo( @@ -410,9 +436,11 @@ height: dimension[1], layers: 1, ) - checkVkResult device.vkCreateFramebuffer(addr(framebufferInfo), nil, addr(result[i])) - -proc trash(device: VkDevice, swapchain: Swapchain, framebuffers: seq[VkFramebuffer]) = + checkVkResult device.vkCreateFramebuffer(addr(framebufferInfo), nil, addr( + result[i])) + +proc trash(device: VkDevice, swapchain: Swapchain, framebuffers: seq[ + VkFramebuffer]) = for framebuffer in framebuffers: device.vkDestroyFramebuffer(framebuffer, nil) for imageview in swapchain.imageviews: @@ -440,7 +468,8 @@ ) -proc setupCommandBuffers(device: VkDevice, graphicsQueueFamily: uint32): (VkCommandPool, array[MAX_FRAMES_IN_FLIGHT, VkCommandBuffer]) = +proc setupCommandBuffers(device: VkDevice, graphicsQueueFamily: uint32): ( + VkCommandPool, array[MAX_FRAMES_IN_FLIGHT, VkCommandBuffer]) = # set up command buffer var poolInfo = VkCommandPoolCreateInfo( sType: VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, @@ -462,14 +491,17 @@ array[MAX_FRAMES_IN_FLIGHT, VkSemaphore], array[MAX_FRAMES_IN_FLIGHT, VkFence], ) = - var semaphoreInfo = VkSemaphoreCreateInfo(sType: VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO) + var semaphoreInfo = VkSemaphoreCreateInfo( + sType: VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO) var fenceInfo = VkFenceCreateInfo( sType: VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, flags: VkFenceCreateFlags(VK_FENCE_CREATE_SIGNALED_BIT) ) for i in 0 ..< MAX_FRAMES_IN_FLIGHT: - checkVkResult device.vkCreateSemaphore(addr(semaphoreInfo), nil, addr(result[0][i])) - checkVkResult device.vkCreateSemaphore(addr(semaphoreInfo), nil, addr(result[1][i])) + checkVkResult device.vkCreateSemaphore(addr(semaphoreInfo), nil, addr( + result[0][i])) + checkVkResult device.vkCreateSemaphore(addr(semaphoreInfo), nil, addr( + result[1][i])) checkVkResult device.vkCreateFence(addr(fenceInfo), nil, addr(result[2][i])) proc igniteEngine*(windowTitle: string): Engine = @@ -489,11 +521,13 @@ when DEBUG_LOG: result.vulkan.debugMessenger = result.vulkan.instance.setupDebugLog() result.vulkan.surface = result.vulkan.instance.createVulkanSurface(result.window) - result.vulkan.device = result.vulkan.instance.setupVulkanDeviceAndQueues(result.vulkan.surface) + result.vulkan.device = result.vulkan.instance.setupVulkanDeviceAndQueues( + result.vulkan.surface) # get basic frame information result.vulkan.surfaceFormat = result.vulkan.device.physicalDevice.formats.getSuitableSurfaceFormat() - result.vulkan.frameSize = result.window.getFrameDimension(result.vulkan.device.physicalDevice.device, result.vulkan.surface) + result.vulkan.frameSize = result.window.getFrameDimension( + result.vulkan.device.physicalDevice.device, result.vulkan.surface) # setup swapchain and render pipeline result.vulkan.swapchain = result.vulkan.device.device.setupSwapChain( @@ -502,7 +536,8 @@ result.vulkan.frameSize, result.vulkan.surfaceFormat ) - result.vulkan.renderPass = result.vulkan.device.device.setupRenderPass(result.vulkan.surfaceFormat.format) + result.vulkan.renderPass = result.vulkan.device.device.setupRenderPass( + result.vulkan.surfaceFormat.format) result.vulkan.framebuffers = result.vulkan.device.device.setupFramebuffers( result.vulkan.swapchain, result.vulkan.renderPass, @@ -511,7 +546,8 @@ ( result.vulkan.device.commandPool, result.vulkan.device.commandBuffers, - ) = result.vulkan.device.device.setupCommandBuffers(result.vulkan.device.graphicsQueueFamily) + ) = result.vulkan.device.device.setupCommandBuffers( + result.vulkan.device.graphicsQueueFamily) ( result.vulkan.imageAvailableSemaphores, @@ -520,7 +556,9 @@ ) = result.vulkan.device.device.setupSyncPrimitives() -proc setupPipeline*[VertexType; UniformType; IndexType: uint16|uint32](engine: var Engine, scenedata: Thing, vertexShader, fragmentShader: static string): RenderPipeline[VertexType, UniformType] = +proc setupPipeline*[VertexType; UniformType; IndexType: uint16|uint32]( + engine: var Engine, scenedata: Thing, vertexShader, + fragmentShader: static string): RenderPipeline[VertexType, UniformType] = engine.currentscenedata = scenedata result = initRenderPipeline[VertexType, UniformType]( engine.vulkan.device.device, @@ -532,16 +570,22 @@ # vertex buffers for mesh in allPartsOfType[Mesh[VertexType]](engine.currentscenedata): - result.vertexBuffers.add createVertexBuffers(mesh, result.device, engine.vulkan.device.physicalDevice.device, engine.vulkan.device.commandPool, engine.vulkan.device.graphicsQueue) + result.vertexBuffers.add createVertexBuffers(mesh, result.device, + engine.vulkan.device.physicalDevice.device, + engine.vulkan.device.commandPool, engine.vulkan.device.graphicsQueue) # vertex buffers with indexes when not (IndexType is void): - for mesh in allPartsOfType[IndexedMesh[VertexType, IndexType]](engine.currentscenedata): - result.indexedVertexBuffers.add createIndexedVertexBuffers(mesh, result.device, engine.vulkan.device.physicalDevice.device, engine.vulkan.device.commandPool, engine.vulkan.device.graphicsQueue) + for mesh in allPartsOfType[IndexedMesh[VertexType, IndexType]]( + engine.currentscenedata): + result.indexedVertexBuffers.add createIndexedVertexBuffers(mesh, + result.device, engine.vulkan.device.physicalDevice.device, + engine.vulkan.device.commandPool, engine.vulkan.device.graphicsQueue) # uniform buffers when not (UniformType is void): - result.uniformBuffers = createUniformBuffers[MAX_FRAMES_IN_FLIGHT, UniformType]( + result.uniformBuffers = createUniformBuffers[MAX_FRAMES_IN_FLIGHT, + UniformType]( result.device, engine.vulkan.device.physicalDevice.device ) @@ -557,7 +601,8 @@ pPoolSizes: addr(poolSize), maxSets: uint32(MAX_FRAMES_IN_FLIGHT), ) - checkVkResult vkCreateDescriptorPool(result.device, addr(poolInfo), nil, addr(result.descriptorPool)) + checkVkResult vkCreateDescriptorPool(result.device, addr(poolInfo), nil, addr( + result.descriptorPool)) var layouts: array[MAX_FRAMES_IN_FLIGHT, VkDescriptorSetLayout] for i in 0 ..< MAX_FRAMES_IN_FLIGHT: @@ -569,10 +614,12 @@ pSetLayouts: addr(layouts[0]), ) - checkVkResult vkAllocateDescriptorSets(result.device, addr(allocInfo), addr(result.descriptors[0])) + checkVkResult vkAllocateDescriptorSets(result.device, addr(allocInfo), addr( + result.descriptors[0])) when not (UniformType is void): - var bufferInfos: array[MAX_FRAMES_IN_FLIGHT, array[1, VkDescriptorBufferInfo]] # because we use only one Uniform atm + var bufferInfos: array[MAX_FRAMES_IN_FLIGHT, array[1, + VkDescriptorBufferInfo]] # because we use only one Uniform atm for i in 0 ..< MAX_FRAMES_IN_FLIGHT: bufferInfos[i][0] = VkDescriptorBufferInfo( buffer: result.uniformBuffers[i].vkBuffer, @@ -586,7 +633,8 @@ dstArrayElement: 0, descriptorType: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount: 1, - pBufferInfo: cast[ptr ptr VkDescriptorBufferInfo](addr(bufferInfos[i][0])), + pBufferInfo: cast[ptr ptr VkDescriptorBufferInfo](addr(bufferInfos[i][ + 0])), ) vkUpdateDescriptorSets(result.device, 1, addr(descriptorWrite), 0, nil) @@ -601,25 +649,32 @@ if not (HostVisible in buffer.memoryProperties): if not (TransferDst in buffer.bufferTypes): raise newException(Exception, "Buffer cannot be updated") - var stagingBuffer = device.device.InitBuffer(device.physicalDevice.device, uint64(size), {TransferSrc}, {HostVisible, HostCoherent}) + var stagingBuffer = device.device.InitBuffer(device.physicalDevice.device, + uint64(size), {TransferSrc}, {HostVisible, HostCoherent}) copyMem(stagingBuffer.data, dataptr, size) - transferBuffer(device.commandPool, device.graphicsQueue, stagingBuffer, buffer, uint64(size)) + transferBuffer(device.commandPool, device.graphicsQueue, stagingBuffer, + buffer, uint64(size)) stagingBuffer.trash() else: copyMem(buffer.data, dataptr, size) -proc updateVertexData*[T: VertexAttribute](device: Device, vertexAttribute: var T) = +proc updateVertexData*[T: VertexAttribute](device: Device, + vertexAttribute: var T) = device.updateBufferData(vertexAttribute.buffer, vertexAttribute.data) -proc updateUniformData*[VertexType, Uniforms](device: Device, pipeline: RenderPipeline[VertexType, Uniforms], data: var Uniforms) = +proc updateUniformData*[VertexType, Uniforms](device: Device, + pipeline: RenderPipeline[VertexType, Uniforms], data: var Uniforms) = for buffer in pipeline.uniformBuffers: device.updateBufferData(buffer, data) -proc runPipeline[VertexType; Uniforms](commandBuffer: VkCommandBuffer, pipeline: var RenderPipeline[VertexType, Uniforms], currentFrame: int) = - vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipeline) +proc runPipeline[VertexType; Uniforms](commandBuffer: VkCommandBuffer, + pipeline: var RenderPipeline[VertexType, Uniforms], currentFrame: int) = + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + pipeline.pipeline) - vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.layout, 0, 1, addr(pipeline.descriptors[currentFrame]), 0, nil) + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + pipeline.layout, 0, 1, addr(pipeline.descriptors[currentFrame]), 0, nil) for (vertexBufferSet, vertexCount) in pipeline.vertexBuffers: var vertexBuffers: seq[VkBuffer] @@ -628,10 +683,14 @@ vertexBuffers.add buffer.vkBuffer offsets.add VkDeviceSize(0) - vkCmdBindVertexBuffers(commandBuffer, firstBinding=0'u32, bindingCount=uint32(vertexBuffers.len), pBuffers=addr(vertexBuffers[0]), pOffsets=addr(offsets[0])) - vkCmdDraw(commandBuffer, vertexCount=vertexCount, instanceCount=1'u32, firstVertex=0'u32, firstInstance=0'u32) + vkCmdBindVertexBuffers(commandBuffer, firstBinding = 0'u32, + bindingCount = uint32(vertexBuffers.len), pBuffers = addr(vertexBuffers[ + 0]), pOffsets = addr(offsets[0])) + vkCmdDraw(commandBuffer, vertexCount = vertexCount, instanceCount = 1'u32, + firstVertex = 0'u32, firstInstance = 0'u32) - for (vertexBufferSet, indexBuffer, indicesCount, indexType) in pipeline.indexedVertexBuffers: + for (vertexBufferSet, indexBuffer, indicesCount, indexType) in + pipeline.indexedVertexBuffers: var vertexBuffers: seq[VkBuffer] offsets: seq[VkDeviceSize] @@ -639,17 +698,22 @@ vertexBuffers.add buffer.vkBuffer offsets.add VkDeviceSize(0) - vkCmdBindVertexBuffers(commandBuffer, firstBinding=0'u32, bindingCount=uint32(vertexBuffers.len), pBuffers=addr(vertexBuffers[0]), pOffsets=addr(offsets[0])) + vkCmdBindVertexBuffers(commandBuffer, firstBinding = 0'u32, + bindingCount = uint32(vertexBuffers.len), pBuffers = addr(vertexBuffers[ + 0]), pOffsets = addr(offsets[0])) vkCmdBindIndexBuffer(commandBuffer, indexBuffer.vkBuffer, VkDeviceSize(0), indexType) vkCmdDrawIndexed(commandBuffer, indicesCount, 1, 0, 0, 0) -proc recordCommandBuffer(renderPass: VkRenderPass, pipeline: var RenderPipeline, commandBuffer: VkCommandBuffer, framebuffer: VkFramebuffer, frameSize: TVec2[uint32], currentFrame: int) = +proc recordCommandBuffer(renderPass: VkRenderPass, pipeline: var RenderPipeline, + commandBuffer: VkCommandBuffer, framebuffer: VkFramebuffer, + frameSize: TVec2[uint32], currentFrame: int) = var beginInfo = VkCommandBufferBeginInfo( sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, pInheritanceInfo: nil, ) - clearColor = VkClearValue(color: VkClearColorValue(float32: [0.2'f, 0.2'f, 0.2'f, 1.0'f])) + clearColor = VkClearValue(color: VkClearColorValue(float32: [0.2'f, 0.2'f, + 0.2'f, 1.0'f])) renderPassInfo = VkRenderPassBeginInfo( sType: VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, renderPass: renderPass, @@ -664,8 +728,8 @@ viewport = VkViewport( x: 0.0, y: 0.0, - width: (float) frameSize.x, - height: (float) frameSize.y, + width: (float)frameSize.x, + height: (float)frameSize.y, minDepth: 0.0, maxDepth: 1.0, ) @@ -676,14 +740,16 @@ checkVkResult vkBeginCommandBuffer(commandBuffer, addr(beginInfo)) block: vkCmdBeginRenderPass(commandBuffer, addr(renderPassInfo), VK_SUBPASS_CONTENTS_INLINE) - vkCmdSetViewport(commandBuffer, firstViewport=0, viewportCount=1, addr(viewport)) - vkCmdSetScissor(commandBuffer, firstScissor=0, scissorCount=1, addr(scissor)) + vkCmdSetViewport(commandBuffer, firstViewport = 0, viewportCount = 1, addr(viewport)) + vkCmdSetScissor(commandBuffer, firstScissor = 0, scissorCount = 1, addr(scissor)) runPipeline(commandBuffer, pipeline, currentFrame) vkCmdEndRenderPass(commandBuffer) checkVkResult vkEndCommandBuffer(commandBuffer) -proc drawFrame(window: NativeWindow, vulkan: var Vulkan, currentFrame: int, resized: bool, pipeline: var RenderPipeline) = - checkVkResult vkWaitForFences(vulkan.device.device, 1, addr(vulkan.inFlightFences[currentFrame]), VK_TRUE, high(uint64)) +proc drawFrame(window: NativeWindow, vulkan: var Vulkan, currentFrame: int, + resized: bool, pipeline: var RenderPipeline) = + checkVkResult vkWaitForFences(vulkan.device.device, 1, addr( + vulkan.inFlightFences[currentFrame]), VK_TRUE, high(uint64)) var bufferImageIndex: uint32 let nextImageResult = vkAcquireNextImageKHR( vulkan.device.device, @@ -694,14 +760,19 @@ addr(bufferImageIndex) ) if nextImageResult == VK_ERROR_OUT_OF_DATE_KHR: - vulkan.frameSize = window.getFrameDimension(vulkan.device.physicalDevice.device, vulkan.surface) + vulkan.frameSize = window.getFrameDimension( + vulkan.device.physicalDevice.device, vulkan.surface) (vulkan.swapchain, vulkan.framebuffers) = vulkan.recreateSwapchain() elif not (nextImageResult in [VK_SUCCESS, VK_SUBOPTIMAL_KHR]): - raise newException(Exception, "Vulkan error: vkAcquireNextImageKHR returned " & $nextImageResult) - checkVkResult vkResetFences(vulkan.device.device, 1, addr(vulkan.inFlightFences[currentFrame])) + raise newException(Exception, "Vulkan error: vkAcquireNextImageKHR returned " & + $nextImageResult) + checkVkResult vkResetFences(vulkan.device.device, 1, addr( + vulkan.inFlightFences[currentFrame])) - checkVkResult vkResetCommandBuffer(vulkan.device.commandBuffers[currentFrame], VkCommandBufferResetFlags(0)) - vulkan.renderPass.recordCommandBuffer(pipeline, vulkan.device.commandBuffers[currentFrame], vulkan.framebuffers[bufferImageIndex], vulkan.frameSize, currentFrame) + checkVkResult vkResetCommandBuffer(vulkan.device.commandBuffers[currentFrame], + VkCommandBufferResetFlags(0)) + vulkan.renderPass.recordCommandBuffer(pipeline, vulkan.device.commandBuffers[ + currentFrame], vulkan.framebuffers[bufferImageIndex], vulkan.frameSize, currentFrame) var waitSemaphores = [vulkan.imageAvailableSemaphores[currentFrame]] waitStages = [VkPipelineStageFlags(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)] @@ -716,7 +787,8 @@ signalSemaphoreCount: 1, pSignalSemaphores: addr(signalSemaphores[0]), ) - checkVkResult vkQueueSubmit(vulkan.device.graphicsQueue, 1, addr(submitInfo), vulkan.inFlightFences[currentFrame]) + checkVkResult vkQueueSubmit(vulkan.device.graphicsQueue, 1, addr(submitInfo), + vulkan.inFlightFences[currentFrame]) var presentInfo = VkPresentInfoKHR( sType: VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, @@ -729,12 +801,15 @@ ) let presentResult = vkQueuePresentKHR(vulkan.device.presentationQueue, addr(presentInfo)) - if presentResult == VK_ERROR_OUT_OF_DATE_KHR or presentResult == VK_SUBOPTIMAL_KHR or resized: - vulkan.frameSize = window.getFrameDimension(vulkan.device.physicalDevice.device, vulkan.surface) + if presentResult == VK_ERROR_OUT_OF_DATE_KHR or presentResult == + VK_SUBOPTIMAL_KHR or resized: + vulkan.frameSize = window.getFrameDimension( + vulkan.device.physicalDevice.device, vulkan.surface) (vulkan.swapchain, vulkan.framebuffers) = vulkan.recreateSwapchain() -proc run*(engine: var Engine, pipeline: var RenderPipeline, globalUpdate: proc(engine: var Engine, dt: float32)) = +proc run*(engine: var Engine, pipeline: var RenderPipeline, globalUpdate: proc( + engine: var Engine, dt: float32)) = var currentFrame = 0 resized = false @@ -807,19 +882,25 @@ proc trash*(engine: var Engine) = checkVkResult vkDeviceWaitIdle(engine.vulkan.device.device) - engine.vulkan.device.device.trash(engine.vulkan.swapchain, engine.vulkan.framebuffers) + engine.vulkan.device.device.trash(engine.vulkan.swapchain, + engine.vulkan.framebuffers) for i in 0 ..< MAX_FRAMES_IN_FLIGHT: - engine.vulkan.device.device.vkDestroySemaphore(engine.vulkan.imageAvailableSemaphores[i], nil) - engine.vulkan.device.device.vkDestroySemaphore(engine.vulkan.renderFinishedSemaphores[i], nil) + engine.vulkan.device.device.vkDestroySemaphore( + engine.vulkan.imageAvailableSemaphores[i], nil) + engine.vulkan.device.device.vkDestroySemaphore( + engine.vulkan.renderFinishedSemaphores[i], nil) engine.vulkan.device.device.vkDestroyFence(engine.vulkan.inFlightFences[i], nil) engine.vulkan.device.device.vkDestroyRenderPass(engine.vulkan.renderPass, nil) - engine.vulkan.device.device.vkDestroyCommandPool(engine.vulkan.device.commandPool, nil) + engine.vulkan.device.device.vkDestroyCommandPool( + engine.vulkan.device.commandPool, nil) engine.vulkan.instance.vkDestroySurfaceKHR(engine.vulkan.surface, nil) engine.vulkan.device.device.vkDestroyDevice(nil) when DEBUG_LOG: - engine.vulkan.instance.vkDestroyDebugUtilsMessengerEXT(engine.vulkan.debugMessenger, nil) + engine.vulkan.instance.vkDestroyDebugUtilsMessengerEXT( + engine.vulkan.debugMessenger, nil) engine.window.trash() - engine.vulkan.instance.vkDestroyInstance(nil) # needs to happen after window is trashed as the driver might have a hook registered for the window destruction + engine.vulkan.instance.vkDestroyInstance( + nil) # needs to happen after window is trashed as the driver might have a hook registered for the window destruction diff -r a25325bec7f2 -r f2c97bdbb0b3 src/semicongine/thing.nim --- a/src/semicongine/thing.nim Sun Jan 22 22:46:53 2023 +0700 +++ b/src/semicongine/thing.nim Tue Jan 24 10:22:38 2023 +0700 @@ -25,9 +25,6 @@ result = new Transform result.mat = mat -method update*(thing: Thing, dt: float32) {.base.} = discard -method update*(part: Part, dt: float32) {.base.} = discard - proc add*(thing: Thing, child: Thing) = child.parent = thing thing.children.add child @@ -43,12 +40,13 @@ part.thing = thing thing.parts.add part -func newThing*(name: string=""): Thing = +func newThing*(name: string = ""): Thing = result = new Thing result.name = name if result.name == "": result.name = &"Thing[{$(cast[ByteAddress](result))}]" -func newThing*(name: string, firstChild: Thing, children: varargs[Thing]): Thing = +func newThing*(name: string, firstChild: Thing, children: varargs[ + Thing]): Thing = result = new Thing result.add firstChild for child in children: @@ -73,7 +71,7 @@ if part of Transform: result = Transform(part).mat * result currentThing = currentThing.parent - + iterator allPartsOfType*[T: Part](root: Thing): T = var queue = @[root] while queue.len > 0: @@ -131,3 +129,17 @@ for child in next.children: queue.add child yield next + +method update*(thing: Thing, dt: float32) {.base.} = + echo "The update" + let transform = thing.getModelTransform() + for part in thing.parts: + echo " The part ", part + for name, value in part[].fieldPairs: + echo " attribute ", name + when typeof(value) is ModelTransformAttribute: + value.data = @[transform.transposed()] + echo "updated stuff" + +method update*(part: Part, dt: float32) {.base.} = discard + diff -r a25325bec7f2 -r f2c97bdbb0b3 src/semicongine/vertex.nim --- a/src/semicongine/vertex.nim Sun Jan 22 22:46:53 2023 +0700 +++ b/src/semicongine/vertex.nim Tue Jan 24 10:22:38 2023 +0700 @@ -14,19 +14,19 @@ VertexAttributeType = SomeNumber|TVec|TMat # useOnDeviceMemory can be used to make sure the attribute buffer memory will # be on the device. Data will be faster to access but much slower to update - GenericAttribute*[T:VertexAttributeType] = object + GenericAttribute*[T: VertexAttributeType] = object data*: seq[T] buffer*: Buffer useOnDeviceMemory*: bool - PositionAttribute*[T:TVec] = object + PositionAttribute*[T: TVec] = object data*: seq[T] buffer*: Buffer useOnDeviceMemory*: bool - ColorAttribute*[T:TVec] = object + ColorAttribute*[T: TVec] = object data*: seq[T] buffer*: Buffer useOnDeviceMemory*: bool - GenericInstanceAttribute*[T:VertexAttributeType] = object + GenericInstanceAttribute*[T: VertexAttributeType] = object data*: seq[T] buffer*: Buffer useOnDeviceMemory*: bool @@ -41,7 +41,8 @@ # from https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap15.html func nLocationSlots[T: VertexAttributeType](): int = - when (T is TVec3[float64] or T is TVec3[uint64] or T is TVec4[float64] or T is TVec4[float64]): + when (T is TVec3[float64] or T is TVec3[uint64] or T is TVec4[float64] or + T is TVec4[float64]): 2 elif T is SomeNumber or T is TVec: 1 @@ -50,64 +51,83 @@ # numbers func getVkFormat[T: VertexAttributeType](): VkFormat = - when T is uint8: VK_FORMAT_R8_UINT - elif T is int8: VK_FORMAT_R8_SINT - elif T is uint16: VK_FORMAT_R16_UINT - elif T is int16: VK_FORMAT_R16_SINT - elif T is uint32: VK_FORMAT_R32_UINT - elif T is int32: VK_FORMAT_R32_SINT - elif T is uint64: VK_FORMAT_R64_UINT - elif T is int64: VK_FORMAT_R64_SINT - elif T is float32: VK_FORMAT_R32_SFLOAT - elif T is float64: VK_FORMAT_R64_SFLOAT - elif T is TVec2[uint8]: VK_FORMAT_R8G8_UINT - elif T is TVec2[int8]: VK_FORMAT_R8G8_SINT - elif T is TVec2[uint16]: VK_FORMAT_R16G16_UINT - elif T is TVec2[int16]: VK_FORMAT_R16G16_SINT - elif T is TVec2[uint32]: VK_FORMAT_R32G32_UINT - elif T is TVec2[int32]: VK_FORMAT_R32G32_SINT - elif T is TVec2[uint64]: VK_FORMAT_R64G64_UINT - elif T is TVec2[int64]: VK_FORMAT_R64G64_SINT + when T is uint8: VK_FORMAT_R8_UINT + elif T is int8: VK_FORMAT_R8_SINT + elif T is uint16: VK_FORMAT_R16_UINT + elif T is int16: VK_FORMAT_R16_SINT + elif T is uint32: VK_FORMAT_R32_UINT + elif T is int32: VK_FORMAT_R32_SINT + elif T is uint64: VK_FORMAT_R64_UINT + elif T is int64: VK_FORMAT_R64_SINT + elif T is float32: VK_FORMAT_R32_SFLOAT + elif T is float64: VK_FORMAT_R64_SFLOAT + elif T is TVec2[uint8]: VK_FORMAT_R8G8_UINT + elif T is TVec2[int8]: VK_FORMAT_R8G8_SINT + elif T is TVec2[uint16]: VK_FORMAT_R16G16_UINT + elif T is TVec2[int16]: VK_FORMAT_R16G16_SINT + elif T is TVec2[uint32]: VK_FORMAT_R32G32_UINT + elif T is TVec2[int32]: VK_FORMAT_R32G32_SINT + elif T is TVec2[uint64]: VK_FORMAT_R64G64_UINT + elif T is TVec2[int64]: VK_FORMAT_R64G64_SINT elif T is TVec2[float32]: VK_FORMAT_R32G32_SFLOAT elif T is TVec2[float64]: VK_FORMAT_R64G64_SFLOAT - elif T is TVec3[uint8]: VK_FORMAT_R8G8B8_UINT - elif T is TVec3[int8]: VK_FORMAT_R8G8B8_SINT - elif T is TVec3[uint16]: VK_FORMAT_R16G16B16_UINT - elif T is TVec3[int16]: VK_FORMAT_R16G16B16_SINT - elif T is TVec3[uint32]: VK_FORMAT_R32G32B32_UINT - elif T is TVec3[int32]: VK_FORMAT_R32G32B32_SINT - elif T is TVec3[uint64]: VK_FORMAT_R64G64B64_UINT - elif T is TVec3[int64]: VK_FORMAT_R64G64B64_SINT + elif T is TVec3[uint8]: VK_FORMAT_R8G8B8_UINT + elif T is TVec3[int8]: VK_FORMAT_R8G8B8_SINT + elif T is TVec3[uint16]: VK_FORMAT_R16G16B16_UINT + elif T is TVec3[int16]: VK_FORMAT_R16G16B16_SINT + elif T is TVec3[uint32]: VK_FORMAT_R32G32B32_UINT + elif T is TVec3[int32]: VK_FORMAT_R32G32B32_SINT + elif T is TVec3[uint64]: VK_FORMAT_R64G64B64_UINT + elif T is TVec3[int64]: VK_FORMAT_R64G64B64_SINT elif T is TVec3[float32]: VK_FORMAT_R32G32B32_SFLOAT elif T is TVec3[float64]: VK_FORMAT_R64G64B64_SFLOAT - elif T is TVec4[uint8]: VK_FORMAT_R8G8B8A8_UINT - elif T is TVec4[int8]: VK_FORMAT_R8G8B8A8_SINT - elif T is TVec4[uint16]: VK_FORMAT_R16G16B16A16_UINT - elif T is TVec4[int16]: VK_FORMAT_R16G16B16A16_SINT - elif T is TVec4[uint32]: VK_FORMAT_R32G32B32A32_UINT - elif T is TVec4[int32]: VK_FORMAT_R32G32B32A32_SINT - elif T is TVec4[uint64]: VK_FORMAT_R64G64B64A64_UINT - elif T is TVec4[int64]: VK_FORMAT_R64G64B64A64_SINT + elif T is TVec4[uint8]: VK_FORMAT_R8G8B8A8_UINT + elif T is TVec4[int8]: VK_FORMAT_R8G8B8A8_SINT + elif T is TVec4[uint16]: VK_FORMAT_R16G16B16A16_UINT + elif T is TVec4[int16]: VK_FORMAT_R16G16B16A16_SINT + elif T is TVec4[uint32]: VK_FORMAT_R32G32B32A32_UINT + elif T is TVec4[int32]: VK_FORMAT_R32G32B32A32_SINT + elif T is TVec4[uint64]: VK_FORMAT_R64G64B64A64_UINT + elif T is TVec4[int64]: VK_FORMAT_R64G64B64A64_SINT elif T is TVec4[float32]: VK_FORMAT_R32G32B32A32_SFLOAT elif T is TVec4[float64]: VK_FORMAT_R64G64B64A64_SFLOAT else: {.error: "Unsupported vertex attribute type".} - func VertexCount*[T](t: T): uint32 = for name, value in t.fieldPairs: - when typeof(value) is VertexAttribute and not (typeof(value) is InstanceAttribute): + when typeof(value) is VertexAttribute and not (typeof( + value) is InstanceAttribute): if result == 0: result = uint32(value.data.len) else: assert result == uint32(value.data.len) + func hasAttributeType*[T, AT](t: T): uint32 = for name, value in t.fieldPairs: when typeof(value) is AT: return true return false +# helper function to make sure matrices are correctly +# divided into multiple vector attributes +template compositeAttributeType[T]() = + when T is TMat33[float32]: + Vec3 + elif T is TMat44[float32]: + Vec4 + else: + T +func compositeAttributesNumber[T](): int = + when T is TMat33[float32]: + 3 + elif T is TMat44[float32]: + 4 + else: + 1 + + func generateGLSLVertexDeclarations*[T](): string = var stmtList: seq[string] var i = 0 @@ -116,46 +136,51 @@ let glsltype = getGLSLType[getAttributeType(value)]() let n = name stmtList.add(&"layout(location = {i}) in {glsltype} {n};") - i += nLocationSlots[getAttributeType(value)]() + for j in 0 ..< compositeAttributesNumber[getAttributeType(value)](): + i += nLocationSlots[compositeAttributeType(getAttributeType(value))]() return stmtList.join("\n") -func generateInputVertexBinding*[T](bindingoffset: int = 0, locationoffset: int = 0): seq[VkVertexInputBindingDescription] = + +func generateInputVertexBinding*[T](bindingoffset: int = 0, + locationoffset: int = 0): seq[VkVertexInputBindingDescription] = # packed attribute data, not interleaved (aks "struct of arrays") var binding = bindingoffset for name, value in T().fieldPairs: when typeof(value) is InstanceAttribute: - result.add( - VkVertexInputBindingDescription( - binding: uint32(binding), - stride: uint32(sizeof(getAttributeType(value))), - inputRate: VK_VERTEX_INPUT_RATE_INSTANCE, - ) - ) - binding += 1 + let inputRate = VK_VERTEX_INPUT_RATE_INSTANCE elif typeof(value) is VertexAttribute: - result.add( - VkVertexInputBindingDescription( - binding: uint32(binding), - stride: uint32(sizeof(getAttributeType(value))), - inputRate: VK_VERTEX_INPUT_RATE_VERTEX, - ) + let inputRate = VK_VERTEX_INPUT_RATE_VERTEX + else: + {.error: "Unsupported vertex attribute type".} + result.add( + VkVertexInputBindingDescription( + binding: uint32(binding), + stride: uint32(sizeof(getAttributeType(value))), + inputRate: inputRate, ) - binding += 1 + ) + binding += 1 + -func generateInputAttributeBinding*[T](bindingoffset: int = 0, locationoffset: int = 0): seq[VkVertexInputAttributeDescription] = - # packed attribute data, not interleaved (aks "struct of arrays") +func generateInputAttributeBinding*[T](bindingoffset: int = 0, + locationoffset: int = 0): seq[VkVertexInputAttributeDescription] = + # TODO: var location = 0 var binding = bindingoffset for name, value in T().fieldPairs: when typeof(value) is VertexAttribute: - result.add( - VkVertexInputAttributeDescription( - binding: uint32(binding), - location: uint32(location), - format: getVkFormat[getAttributeType(value)](), - offset: 0, + for i in 0 ..< compositeAttributesNumber[getAttributeType(value)](): + result.add( + VkVertexInputAttributeDescription( + binding: uint32(binding), + location: uint32(location), + format: getVkFormat[compositeAttributeType(getAttributeType( + value))](), + offset: uint32(i * sizeof(compositeAttributeType(getAttributeType( + value)))), + ) ) - ) - location += nLocationSlots[getAttributeType(value)]() + location += nLocationSlots[compositeAttributeType(getAttributeType( + value))]() binding += 1