Mercurial > games > semicongine
changeset 63:1862fada1726
fix: scene graph, input
author | Sam <sam@basx.dev> |
---|---|
date | Sat, 04 Feb 2023 02:24:15 +0700 |
parents | 7153eadb07eb |
children | e766d138cc5d |
files | src/semicongine/buffer.nim src/semicongine/engine.nim src/semicongine/mesh.nim src/semicongine/platform/linux/xlib.nim src/semicongine/shader.nim src/semicongine/thing.nim |
diffstat | 6 files changed, 136 insertions(+), 125 deletions(-) [+] |
line wrap: on
line diff
--- a/src/semicongine/buffer.nim Wed Jan 25 23:56:59 2023 +0700 +++ b/src/semicongine/buffer.nim Sat Feb 04 02:24:15 2023 +0700 @@ -36,13 +36,15 @@ vkFreeMemory(buffer.device, buffer.memory, nil) buffer.memory = VkDeviceMemory(0) -proc findMemoryType(buffer: Buffer, physicalDevice: VkPhysicalDevice, properties: MemoryProperties): uint32 = +proc findMemoryType(buffer: Buffer, physicalDevice: VkPhysicalDevice, + properties: MemoryProperties): uint32 = var physicalProperties: VkPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties(physicalDevice, addr(physicalProperties)) for i in 0'u32 ..< physicalProperties.memoryTypeCount: if bool(buffer.memoryRequirements.memoryTypeBits and (1'u32 shl i)): - if (uint32(physicalProperties.memoryTypes[i].propertyFlags) and cast[uint32](properties)) == cast[uint32](properties): + if (uint32(physicalProperties.memoryTypes[i].propertyFlags) and cast[ + uint32](properties)) == cast[uint32](properties): return i proc InitBuffer*( @@ -52,7 +54,8 @@ bufferTypes: set[BufferType], properties: MemoryProperties, ): Buffer = - result = Buffer(device: device, size: size, bufferTypes: bufferTypes, memoryProperties: properties) + result = Buffer(device: device, size: size, bufferTypes: bufferTypes, + memoryProperties: properties) var usageFlags = 0 for usage in bufferTypes: usageFlags = ord(usageFlags) or ord(usage) @@ -62,8 +65,10 @@ usage: VkBufferUsageFlags(usageFlags), sharingMode: VK_SHARING_MODE_EXCLUSIVE, ) - checkVkResult vkCreateBuffer(result.device, addr(bufferInfo), nil, addr(result.vkBuffer)) - vkGetBufferMemoryRequirements(result.device, result.vkBuffer, addr(result.memoryRequirements)) + checkVkResult vkCreateBuffer(result.device, addr(bufferInfo), nil, addr( + result.vkBuffer)) + vkGetBufferMemoryRequirements(result.device, result.vkBuffer, addr( + result.memoryRequirements)) var allocInfo = VkMemoryAllocateInfo( sType: VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, @@ -72,18 +77,20 @@ ) if result.size > 0: checkVkResult result.device.vkAllocateMemory(addr(allocInfo), nil, addr(result.memory)) - checkVkResult result.device.vkBindBufferMemory(result.vkBuffer, result.memory, VkDeviceSize(0)) + checkVkResult result.device.vkBindBufferMemory(result.vkBuffer, result.memory, + VkDeviceSize(0)) checkVkResult vkMapMemory( result.device, result.memory, - offset=VkDeviceSize(0), + offset = VkDeviceSize(0), VkDeviceSize(result.size), VkMemoryMapFlags(0), addr(result.data) ) -proc transferBuffer*(commandPool: VkCommandPool, queue: VkQueue, src, dst: Buffer, size: uint64) = +proc transferBuffer*(commandPool: VkCommandPool, queue: VkQueue, src, + dst: Buffer, size: uint64) = assert uint64(src.device) == uint64(dst.device) assert TransferSrc in src.bufferTypes assert TransferDst in dst.bufferTypes
--- a/src/semicongine/engine.nim Wed Jan 25 23:56:59 2023 +0700 +++ b/src/semicongine/engine.nim Sat Feb 04 02:24:15 2023 +0700 @@ -15,8 +15,8 @@ import ./vertex import ./buffer import ./thing +import ./descriptor import ./mesh -import ./descriptor const MAX_FRAMES_IN_FLIGHT = 2 const DEBUG_LOG = not defined(release) @@ -50,8 +50,7 @@ shaders*: seq[ShaderProgram[VertexType, Uniforms]] layout*: VkPipelineLayout pipeline*: VkPipeline - vertexBuffers*: seq[(seq[Buffer], uint32)] - indexedVertexBuffers*: seq[(seq[Buffer], Buffer, uint32, VkIndexType)] + vertexBuffers*: seq[(seq[Buffer], bool, Buffer, uint32, VkIndexType)] descriptorSetLayout*: VkDescriptorSetLayout uniformBuffers*: array[MAX_FRAMES_IN_FLIGHT, Buffer] descriptorPool*: VkDescriptorPool @@ -95,6 +94,17 @@ currentscenedata*: Thing input*: Input + +method update*(thing: Thing, engine: Engine, dt: float32) {.base.} = discard +method update*(part: Part, engine: Engine, dt: float32) {.base.} = discard + +method update*[T, U](mesh: Mesh[T, U], engine: Engine, dt: float32) = + let transform = @[mesh.thing.getModelTransform().transposed()] + for name, value in mesh.vertexData.fieldPairs: + when value is ModelTransformAttribute: + value.data = transform + engine.vulkan.device.updateVertexData(value) + proc getAllPhysicalDevices(instance: VkInstance, surface: VkSurfaceKHR): seq[ PhysicalDevice] = for vulkanPhysicalDevice in getVulkanPhysicalDevices(instance): @@ -199,7 +209,7 @@ var imageCount = capabilities.minImageCount + 1 if capabilities.maxImageCount > 0: imageCount = min(capabilities.maxImageCount, imageCount) - # TODO: fix when dimension is zero + # TODO: something not working on window..., likely the extent var extent = VkExtent2D( width: if dimension[0] > 0: dimension[0] else: 1, height: if dimension[1] > 0: dimension[1] else: 1, @@ -573,20 +583,12 @@ fragmentShader, ) - # vertex buffers - for mesh in allPartsOfType[Mesh[VertexType]](engine.currentscenedata): - result.vertexBuffers.add createVertexBuffers(mesh, result.device, - engine.vulkan.device.physicalDevice.device, + for mesh in allPartsOfType[Mesh[VertexType, IndexType]]( + engine.currentscenedata): + result.vertexBuffers.add createIndexedVertexBuffers(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) - # uniform buffers when not (UniformType is void): result.uniformBuffers = createUniformBuffers[MAX_FRAMES_IN_FLIGHT, @@ -680,7 +682,9 @@ vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.layout, 0, 1, addr(pipeline.descriptors[currentFrame]), 0, nil) - for (vertexBufferSet, vertexCount) in pipeline.vertexBuffers: + + for (vertexBufferSet, indexed, indexBuffer, count, indexType) in + pipeline.vertexBuffers: var vertexBuffers: seq[VkBuffer] offsets: seq[VkDeviceSize] @@ -690,24 +694,13 @@ 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: - var - vertexBuffers: seq[VkBuffer] - offsets: seq[VkDeviceSize] - for buffer in vertexBufferSet: - 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])) - vkCmdBindIndexBuffer(commandBuffer, indexBuffer.vkBuffer, VkDeviceSize(0), indexType) - vkCmdDrawIndexed(commandBuffer, indicesCount, 1, 0, 0, 0) + 0]), pOffsets = addr(offsets[0])) + if indexed: + vkCmdBindIndexBuffer(commandBuffer, indexBuffer.vkBuffer, VkDeviceSize(0), indexType) + vkCmdDrawIndexed(commandBuffer, count, 1, 0, 0, 0) + else: + vkCmdDraw(commandBuffer, vertexCount = count, instanceCount = 1, + firstVertex = 0, firstInstance = 0) proc recordCommandBuffer(renderPass: VkRenderPass, pipeline: var RenderPipeline, commandBuffer: VkCommandBuffer, framebuffer: VkFramebuffer, @@ -858,8 +851,8 @@ engine.globalUpdate(dt) for thing in allThings(engine.currentscenedata): for part in thing.parts: - part.update(dt) - thing.update(dt) + update(part, engine, dt) + update(thing, engine, dt) # submit frame for drawing engine.window.drawFrame(engine.vulkan, currentFrame, resized, pipeline) @@ -875,11 +868,10 @@ for shader in pipeline.shaders: vkDestroyShaderModule(pipeline.device, shader.shader.module, nil) - for (bufferset, cnt) in pipeline.vertexBuffers.mitems: - for buffer in bufferset.mitems: - buffer.trash() - for (bufferset, indexbuffer, cnt, t) in pipeline.indexedVertexBuffers.mitems: - indexbuffer.trash() + for (bufferset, indexed, indexbuffer, cnt, t) in + pipeline.vertexBuffers.mitems: + if indexed: + indexbuffer.trash() for buffer in bufferset.mitems: buffer.trash() for buffer in pipeline.uniformBuffers.mitems:
--- a/src/semicongine/mesh.nim Wed Jan 25 23:56:59 2023 +0700 +++ b/src/semicongine/mesh.nim Sat Feb 04 02:24:15 2023 +0700 @@ -8,22 +8,17 @@ import ./math/vector type - Mesh*[T] = ref object of Part + # TODO: make single mesh type, with case-of attribute for indices + Mesh*[T: object, U: uint16|uint32] = ref object of Part vertexData*: T - IndexedMesh*[T: object, U: uint16|uint32] = ref object of Part - vertexData*: T - indices*: seq[array[3, U]] + case indexed*: bool + of true: + indices*: seq[array[3, U]] + of false: + discard -func createUberMesh*[T](meshes: openArray[Mesh[T]]): Mesh[T] = - for mesh in meshes: - for srcname, srcvalue in mesh.vertexData.fieldPairs: - when typeof(srcvalue) is VertexAttribute: - for dstname, dstvalue in result.vertexData.fieldPairs: - when srcname == dstname: - dstvalue.data.add srcvalue.data - -func createUberMesh*[T: object, U: uint16|uint32](meshes: openArray[IndexedMesh[ - T, U]]): IndexedMesh[T, U] = +func createUberMesh*[T: object, U: uint16|uint32](meshes: openArray[Mesh[ + T, U]]): Mesh[T, U] = var indexoffset = U(0) for mesh in meshes: for srcname, srcvalue in mesh.vertexData.fieldPairs: @@ -37,12 +32,12 @@ result.indices.add indexdata indexoffset += U(mesh.vertexData.VertexCount) -func getVkIndexType[T: object, U: uint16|uint32](m: IndexedMesh[T, +func getVkIndexType[T: object, U: uint16|uint32](m: Mesh[T, U]): VkIndexType = when U is uint16: VK_INDEX_TYPE_UINT16 elif U is uint32: VK_INDEX_TYPE_UINT32 -proc createVertexBuffers*[M: Mesh|IndexedMesh]( +proc createVertexBuffers*[M: Mesh]( mesh: M, device: VkDevice, physicalDevice: VkPhysicalDevice, @@ -71,7 +66,7 @@ value.buffer = stagingBuffer proc createIndexBuffer*( - mesh: IndexedMesh, + mesh: Mesh, device: VkDevice, physicalDevice: VkPhysicalDevice, commandPool: VkCommandPool, @@ -96,20 +91,23 @@ return stagingBuffer proc createIndexedVertexBuffers*( - mesh: IndexedMesh, + mesh: Mesh, device: VkDevice, physicalDevice: VkPhysicalDevice, commandPool: VkCommandPool, queue: VkQueue, useDeviceLocalBufferForIndices: bool = true # decides if data is transfered to the fast device-local memory or not -): (seq[Buffer], Buffer, uint32, VkIndexType) = +): (seq[Buffer], bool, Buffer, uint32, VkIndexType) = result[0] = createVertexBuffers(mesh, device, physicalDevice, commandPool, queue)[0] - result[1] = createIndexBuffer(mesh, device, physicalDevice, commandPool, - queue, useDeviceLocalBufferForIndices) - result[2] = uint32(mesh.indices.len * mesh.indices[0].len) - - result[3] = getVkIndexType(mesh) + result[1] = mesh.indexed + if mesh.indexed: + result[2] = createIndexBuffer(mesh, device, physicalDevice, commandPool, + queue, useDeviceLocalBufferForIndices) + result[3] = uint32(mesh.indices.len * mesh.indices[0].len) + result[4] = getVkIndexType(mesh) + else: + result[3] = uint32(mesh.vertexData.VertexCount) func squareData*[T: SomeFloat](): auto = PositionAttribute[TVec2[T]]( data: @[TVec2[T]([T(0), T(0)]), TVec2[T]([T(0), T(1)]), TVec2[T]([T(1), T( @@ -118,12 +116,3 @@ func squareIndices*[T: uint16|uint32](): auto = seq[array[3, T]]( @[[T(0), T(1), T(3)], [T(2), T(1), T(3)]] ) - -method update*(mesh: Mesh, dt: float32) = - echo "The update" - echo mesh.thing.getModelTransform() - echo mesh.vertexData -method update*(mesh: IndexedMesh, dt: float32) = - echo "The update" - echo mesh.thing.getModelTransform() - echo mesh.vertexData
--- a/src/semicongine/platform/linux/xlib.nim Wed Jan 25 23:56:59 2023 +0700 +++ b/src/semicongine/platform/linux/xlib.nim Sat Feb 04 02:24:15 2023 +0700 @@ -1,4 +1,5 @@ import std/options +import std/tables import x11/xlib, x11/xutil, @@ -25,7 +26,8 @@ template checkXlibResult*(call: untyped) = let value = call if value == 0: - raise newException(Exception, "Xlib error: " & astToStr(call) & " returned " & $value) + raise newException(Exception, "Xlib error: " & astToStr(call) & + " returned " & $value) proc createWindow*(title: string): NativeWindow = checkXlibResult XInitThreads() @@ -39,9 +41,12 @@ foregroundColor = XBlackPixel(display, screen) backgroundColor = XWhitePixel(display, screen) - let window = XCreateSimpleWindow(display, rootWindow, -1, -1, 800, 600, 0, foregroundColor, backgroundColor) - checkXlibResult XSetStandardProperties(display, window, title, "window", 0, nil, 0, nil) - checkXlibResult XSelectInput(display, window, PointerMotionMask or ButtonPressMask or ButtonReleaseMask or KeyPressMask or KeyReleaseMask or ExposureMask) + let window = XCreateSimpleWindow(display, rootWindow, -1, -1, 800, 600, 0, + foregroundColor, backgroundColor) + checkXlibResult XSetStandardProperties(display, window, title, "window", 0, + nil, 0, nil) + checkXlibResult XSelectInput(display, window, PointerMotionMask or + ButtonPressMask or ButtonReleaseMask or KeyPressMask or KeyReleaseMask or ExposureMask) checkXlibResult XMapWindow(display, window) deleteMessage = XInternAtom(display, "WM_DELETE_WINDOW", XBool(false)) @@ -51,11 +56,13 @@ var data = "\0".cstring var pixmap = XCreateBitmapFromData(display, window, data, 1, 1) var color: XColor - var empty_cursor = XCreatePixmapCursor(display, pixmap, pixmap, addr(color), addr(color), 0, 0) + var empty_cursor = XCreatePixmapCursor(display, pixmap, pixmap, addr(color), + addr(color), 0, 0) checkXlibResult XFreePixmap(display, pixmap) checkXlibResult XDefineCursor(display, window, empty_cursor) - return NativeWindow(display: display, window: window, emptyCursor: empty_cursor) + return NativeWindow(display: display, window: window, + emptyCursor: empty_cursor) proc trash*(window: NativeWindow) = checkXlibResult window.display.XFreeCursor(window.emptyCursor) @@ -68,7 +75,9 @@ return (int(attribs.width), int(attribs.height)) proc pendingEvents*(window: NativeWindow): seq[Event] = - var event: XEvent + var + event: XEvent + serials: Table[culong, seq[Event]] while window.display.XPending() > 0: discard window.display.XNextEvent(addr(event)) case event.theType @@ -76,17 +85,27 @@ if cast[Atom](event.xclient.data.l[0]) == deleteMessage: result.add(Event(eventType: Quit)) of KeyPress: - let xkey = int(cast[PXKeyEvent](addr(event)).keycode) - result.add Event(eventType: KeyPressed, key: KeyTypeMap.getOrDefault(xkey, Key.UNKNOWN)) + let keyevent = cast[PXKeyEvent](addr(event)) + let xkey = int(keyevent.keycode) + if not (keyevent.serial in serials): + serials[keyevent.serial] = newSeq[Event]() + serials[keyevent.serial].add(Event(eventType: KeyPressed, + key: KeyTypeMap.getOrDefault(xkey, Key.UNKNOWN))) of KeyRelease: - let xkey = int(cast[PXKeyEvent](addr(event)).keycode) - result.add Event(eventType: KeyReleased, key: KeyTypeMap.getOrDefault(xkey, Key.UNKNOWN)) + let keyevent = cast[PXKeyEvent](addr(event)) + let xkey = int(keyevent.keycode) + if not (keyevent.serial in serials): + serials[keyevent.serial] = newSeq[Event]() + serials[keyevent.serial].add Event(eventType: KeyReleased, + key: KeyTypeMap.getOrDefault(xkey, Key.UNKNOWN)) of ButtonPress: let button = int(cast[PXButtonEvent](addr(event)).button) - result.add Event(eventType: MousePressed, button: MouseButtonTypeMap.getOrDefault(button, MouseButton.UNKNOWN)) + result.add Event(eventType: MousePressed, + button: MouseButtonTypeMap.getOrDefault(button, MouseButton.UNKNOWN)) of ButtonRelease: let button = int(cast[PXButtonEvent](addr(event)).button) - result.add Event(eventType: MouseReleased, button: MouseButtonTypeMap.getOrDefault(button, MouseButton.UNKNOWN)) + result.add Event(eventType: MouseReleased, + button: MouseButtonTypeMap.getOrDefault(button, MouseButton.UNKNOWN)) of MotionNotify: let motion = cast[PXMotionEvent](addr(event)) result.add Event(eventType: MouseMoved, x: motion.x, y: motion.y) @@ -94,6 +113,10 @@ result.add Event(eventType: ResizedWindow) else: discard + for (serial, events) in serials.pairs: + if events.len == 1: + result.add events[0] + proc getMousePosition*(window: NativeWindow): Option[Vec2] = var
--- a/src/semicongine/shader.nim Wed Jan 25 23:56:59 2023 +0700 +++ b/src/semicongine/shader.nim Sat Feb 04 02:24:15 2023 +0700 @@ -14,7 +14,7 @@ type AllowedUniformType = SomeNumber|TVec - UniformSlot *[T:AllowedUniformType] = object + UniformSlot *[T: AllowedUniformType] = object ShaderProgram*[VertexType, Uniforms] = object entryPoint*: string programType*: VkShaderStageFlagBits @@ -32,7 +32,9 @@ of VK_SHADER_STAGE_COMPUTE_BIT: "comp" of VK_SHADER_STAGE_ALL: "" -proc compileGLSLToSPIRV(stage: static VkShaderStageFlagBits, shaderSource: static string, entrypoint: string): seq[uint32] {.compileTime.} = +proc compileGLSLToSPIRV(stage: static VkShaderStageFlagBits, + shaderSource: static string, entrypoint: string): seq[ + uint32] {.compileTime.} = when defined(nimcheck): # will not run if nimcheck is running return result const @@ -42,7 +44,9 @@ shaderfile = getTempDir() / fmt"shader_{shaderHash}.{stagename}" projectPath = querySetting(projectPath) - let (output, exitCode_glsl) = gorgeEx(command=fmt"{projectPath}/glslangValidator --entry-point {entrypoint} -V --stdin -S {stagename} -o {shaderfile}", input=shaderSource) + let (output, exitCode_glsl) = gorgeEx( + command = fmt"{projectPath}/glslangValidator --entry-point {entrypoint} -V --stdin -S {stagename} -o {shaderfile}", + input = shaderSource) if exitCode_glsl != 0: raise newException(Exception, output) @@ -55,14 +59,16 @@ var i = 0 while i < shaderbinary.len: result.add( - (uint32(shaderbinary[i + 0]) shl 0) or - (uint32(shaderbinary[i + 1]) shl 8) or + (uint32(shaderbinary[i + 0]) shl 0) or + (uint32(shaderbinary[i + 1]) shl 8) or (uint32(shaderbinary[i + 2]) shl 16) or (uint32(shaderbinary[i + 3]) shl 24) ) i += 4 -proc initShaderProgram*[VertexType, Uniforms](device: VkDevice, programType: static VkShaderStageFlagBits, shader: static string, entryPoint: static string="main"): ShaderProgram[VertexType, Uniforms] = +proc initShaderProgram*[VertexType, Uniforms](device: VkDevice, + programType: static VkShaderStageFlagBits, shader: static string, + entryPoint: static string = "main"): ShaderProgram[VertexType, Uniforms] = result.entryPoint = entryPoint result.programType = programType @@ -93,7 +99,7 @@ lines.add "layout(row_major) uniform;" lines.add generateGLSLUniformDeclarations[Uniforms]() lines.add generateGLSLVertexDeclarations[VertexType]() - lines.add "layout(location = 0) out vec3 fragColor;" + lines.add "layout(location = 0) out vec4 fragColor;" lines.add "void " & entryPoint & "() {" var hasPosition = 0 @@ -112,7 +118,10 @@ when typeof(value) is ColorAttribute: let glsltype = getGLSLType[getAttributeType(value)]() lines.add &" {glsltype} in_color = " & name & ";" - lines.add &" {glsltype} out_color = in_color;"; + if getAttributeType(value) is TVec3: + lines.add &" vec4 out_color = vec4(in_color, 1);"; + elif getAttributeType(value) is TVec4: + lines.add &" vec4 out_color = in_color;"; hasColor += 1 lines.add shaderBody @@ -133,13 +142,13 @@ var lines: seq[string] lines.add "#version " & glslVersion lines.add "layout(row_major) uniform;" - lines.add "layout(location = 0) in vec3 fragColor;" + lines.add "layout(location = 0) in vec4 fragColor;" lines.add "layout(location = 0) out vec4 outColor;" lines.add "void " & entryPoint & "() {" - lines.add " vec3 in_color = fragColor;" - lines.add " vec3 out_color = in_color;" + lines.add " vec4 in_color = fragColor;" + lines.add " vec4 out_color = in_color;" lines.add shaderBody - lines.add " outColor = vec4(out_color, 1.0);" + lines.add " outColor = out_color;" lines.add "}" return lines.join("\n")
--- a/src/semicongine/thing.nim Wed Jan 25 23:56:59 2023 +0700 +++ b/src/semicongine/thing.nim Sat Feb 04 02:24:15 2023 +0700 @@ -1,17 +1,15 @@ import std/strformat import std/typetraits -import ./vertex import ./math/matrix type Part* = ref object of RootObj - thing: Thing - Transform* = ref object of Part - mat: Mat44 + thing*: Thing Thing* = ref object of RootObj name*: string + transform*: Mat44 # todo: cache transform + only update VBO when transform changed parent*: Thing children*: seq[Thing] parts*: seq[Part] @@ -19,11 +17,6 @@ func `$`*(thing: Thing): string = thing.name method `$`*(part: Part): string {.base.} = &"{part.thing} -> Part" -method `$`*(part: Transform): string = &"{part.thing} -> Transform" - -func newTransform*(mat: Mat44): Transform = - result = new Transform - result.mat = mat proc add*(thing: Thing, child: Thing) = child.parent = thing @@ -43,6 +36,7 @@ func newThing*(name: string = ""): Thing = result = new Thing result.name = name + result.transform = Unit44 if result.name == "": result.name = &"Thing[{$(cast[ByteAddress](result))}]" func newThing*(name: string, firstChild: Thing, children: varargs[ @@ -52,6 +46,7 @@ for child in children: result.add child result.name = name + result.transform = Unit44 if result.name == "": result.name = &"Thing[{$(cast[ByteAddress](result))}]" proc newThing*(name: string, firstPart: Part, parts: varargs[Part]): Thing = @@ -62,14 +57,13 @@ result.add part if result.name == "": result.name = &"Thing[{$(cast[ByteAddress](result))}]" + result.transform = Unit44 func getModelTransform*(thing: Thing): Mat44 = result = Unit44 var currentThing = thing while currentThing != nil: - for part in currentThing.parts: - if part of Transform: - result = Transform(part).mat * result + result = currentThing.transform * result currentThing = currentThing.parent iterator allPartsOfType*[T: Part](root: Thing): T = @@ -79,8 +73,8 @@ for part in thing.parts: if part of T: yield T(part) - for child in thing.children: - queue.insert(child, 0) + for i in countdown(thing.children.len - 1, 0): + queue.add thing.children[i] func firstWithName*(root: Thing, name: string): Thing = var queue = @[root] @@ -129,6 +123,3 @@ for child in next.children: queue.add child yield next - -method update*(thing: Thing, dt: float32) {.base.} = discard -method update*(part: Part, dt: float32) {.base.} = discard