# HG changeset patch # User Sam # Date 1681761877 -25200 # Node ID 15d37022625c3c02bf1c6c5623dcf12145da85ed # Parent 9901ec3831d1ed87b5396c3a7b1953235529fb37 add: input handling, small refactoring for renderer diff -r 9901ec3831d1 -r 15d37022625c src/semicongine/engine.nim --- a/src/semicongine/engine.nim Mon Apr 17 18:02:19 2023 +0700 +++ b/src/semicongine/engine.nim Tue Apr 18 03:04:37 2023 +0700 @@ -4,21 +4,60 @@ import ./vulkan/instance import ./vulkan/device import ./vulkan/physicaldevice +import ./vulkan/renderpass +import ./gpu_data +import ./entity +import ./renderer +import ./events import ./config +import ./math type + Input = object + keyIsDown: set[Key] + keyWasPressed: set[Key] + keyWasReleased: set[Key] + mouseIsDown: set[MouseButton] + mouseWasPressed: set[MouseButton] + mouseWasReleased: set[MouseButton] + mousePosition: Vec2f + eventsProcessed: uint64 Engine* = object + running*: bool device: Device debugger: Debugger instance: Instance window: NativeWindow + renderer: Renderer + input: Input + exitHandler: proc(engine: var Engine) + resizeHandler: proc(engine: var Engine) + eventHandler: proc(engine: var Engine, event: Event) -func gpuDevice*(engine: Engine): Device = - engine.device + +proc destroy*(engine: var Engine) = + checkVkResult engine.device.vk.vkDeviceWaitIdle() + engine.renderer.destroy() + engine.device.destroy() + engine.debugger.destroy() + engine.instance.destroy() + engine.window.destroy() + -proc initEngine*(applicationName: string, debug=DEBUG): Engine = +proc initEngine*( + applicationName: string, + debug=DEBUG, + exitHandler: proc(engine: var Engine) = nil, + resizeHandler: proc(engine: var Engine) = nil, + eventHandler: proc(engine: var Engine, event: Event) = nil +): Engine = + result.running = true + result.exitHandler = exitHandler + result.resizeHandler = resizeHandler + result.eventHandler = eventHandler result.window = createWindow(applicationName) + var instanceExtensions: seq[string] enabledLayers: seq[string] @@ -42,8 +81,62 @@ selectedPhysicalDevice.filterForGraphicsPresentationQueues() ) -proc destroy*(engine: var Engine) = - engine.device.destroy() - engine.debugger.destroy() - engine.instance.destroy() - engine.window.destroy() +proc setRenderer*(engine: var Engine, renderPasses: openArray[RenderPass]) = + engine.renderer = engine.device.initRenderer(renderPasses) + +proc addScene*(engine: var Engine, entity: Entity, vertexInput: seq[ShaderAttribute]) = + engine.renderer.setupDrawableBuffers(entity, vertexInput) + +proc renderScene*(engine: var Engine, entity: Entity): auto = + assert engine.running + engine.renderer.render(entity) + +proc updateInputs*(engine: var Engine) = + assert engine.running + engine.input.keyWasPressed = {} + engine.input.keyWasReleased = {} + engine.input.mouseWasPressed = {} + engine.input.mouseWasReleased = {} + var + killed = false + resized = false + for event in engine.window.pendingEvents(): + inc engine.input.eventsProcessed + if engine.eventHandler != nil: + engine.eventHandler(engine, event) + case event.eventType: + of Quit: + killed = true + of ResizedWindow: + resized = true + of KeyPressed: + engine.input.keyWasPressed.incl event.key + engine.input.keyIsDown.incl event.key + of KeyReleased: + engine.input.keyWasReleased.incl event.key + engine.input.keyIsDown.excl event.key + of MousePressed: + engine.input.mouseWasPressed.incl event.button + engine.input.mouseIsDown.incl event.button + of MouseReleased: + engine.input.mouseWasReleased.incl event.button + engine.input.mouseIsDown.excl event.button + of MouseMoved: + engine.input.mousePosition = newVec2(float32(event.x), float32(event.y)) + if killed: + engine.running = false + if engine.exitHandler != nil: + engine.exitHandler(engine) + if resized and engine.resizeHandler != nil: + engine.resizeHandler(engine) + +func keyIsDown*(engine: Engine, key: Key): auto = key in engine.input.keyIsDown +func keyWasPressed*(engine: Engine, key: Key): auto = key in engine.input.keyWasPressed +func keyWasReleased*(engine: Engine, key: Key): auto = key in engine.input.keyWasReleased +func mouseIsDown*(engine: Engine, button: MouseButton): auto = button in engine.input.mouseIsDown +func mouseWasPressed*(engine: Engine, button: MouseButton): auto = button in engine.input.mouseWasPressed +func mouseWasReleased*(engine: Engine, button: MouseButton): auto = button in engine.input.mouseWasReleased +func mousePosition*(engine: Engine, key: Key): auto = engine.input.mousePosition +func eventsProcessed*(engine: Engine): auto = engine.input.eventsProcessed +func framesRendered*(engine: Engine): auto = engine.renderer.framesRendered +func gpuDevice*(engine: Engine): Device = engine.device diff -r 9901ec3831d1 -r 15d37022625c src/semicongine/renderer.nim --- a/src/semicongine/renderer.nim Mon Apr 17 18:02:19 2023 +0700 +++ b/src/semicongine/renderer.nim Tue Apr 18 03:04:37 2023 +0700 @@ -8,7 +8,6 @@ import ./vulkan/buffer import ./vulkan/device import ./vulkan/drawable -import ./vulkan/framebuffer import ./vulkan/pipeline import ./vulkan/physicaldevice import ./vulkan/renderpass @@ -130,6 +129,7 @@ renderer.scenedata[tree] = data proc render*(renderer: var Renderer, entity: Entity): bool = + # TODO: check if nextFrame had any problems var commandBuffer = renderer.swapchain.nextFrame() commandBuffer.beginRenderCommands(renderer.swapchain.renderPass, renderer.swapchain.currentFramebuffer()) diff -r 9901ec3831d1 -r 15d37022625c src/semicongine/vulkan/swapchain.nim --- a/src/semicongine/vulkan/swapchain.nim Mon Apr 17 18:02:19 2023 +0700 +++ b/src/semicongine/vulkan/swapchain.nim Tue Apr 18 03:04:37 2023 +0700 @@ -122,6 +122,8 @@ VkFence(0), addr(swapchain.currentFramebufferIndex) ) + # TODO: resize swapchain on VK_SUBOPTIMAL_KHR + echo "HIIIIIIIIIIII next image result", nextImageResult if not (nextImageResult in [VK_SUCCESS, VK_TIMEOUT, VK_NOT_READY, VK_SUBOPTIMAL_KHR]): return @@ -161,6 +163,8 @@ pResults: nil, ) let presentResult = vkQueuePresentKHR(swapchain.device.firstPresentationQueue().get().vk, addr(presentInfo)) + # TODO: resize swapchain on VK_SUBOPTIMAL_KHR + echo "HIIIIIIIIIIII Present Result:", presentResult if not (presentResult in [VK_SUCCESS, VK_SUBOPTIMAL_KHR]): return false diff -r 9901ec3831d1 -r 15d37022625c tests/test_vulkan_wrapper.nim --- a/tests/test_vulkan_wrapper.nim Mon Apr 17 18:02:19 2023 +0700 +++ b/tests/test_vulkan_wrapper.nim Tue Apr 18 03:04:37 2023 +0700 @@ -105,7 +105,7 @@ setInstanceData[Vec3f](c, "translate", @[newVec3f(-0.3, 0.1)]) result = newEntity("root", t, r, c) -when isMainModule: +proc main() = var engine = initEngine("Test") # INIT RENDERER: @@ -135,27 +135,32 @@ var surfaceFormat = engine.gpuDevice.physicalDevice.getSurfaceFormats().filterSurfaceFormat() renderPass = engine.gpuDevice.simpleForwardRenderPass(surfaceFormat.format, vertexCode, fragmentCode, 2) - renderer = engine.gpuDevice.initRenderer([renderPass]) + engine.setRenderer([renderPass]) - # INIT SCENE - + # INIT SCENES var scenes = [scene_simple(), scene_different_mesh_types(), scene_primitives()] var time = initShaderGlobal("time", 0.0'f32) for scene in scenes.mitems: scene.components.add time - renderer.setupDrawableBuffers(scene, vertexInput) + engine.addScene(scene, vertexInput) # MAINLOOP echo "Setup successfull, start rendering" for i in 0 ..< 3: for scene in scenes: for i in 0 ..< 1000: + engine.updateInputs() setValue[float32](time.value, get[float32](time.value) + 0.0005) - discard renderer.render(scene) - echo "Rendered ", renderer.framesRendered, " frames" + if not engine.running or engine.keyIsDown(Escape): + engine.destroy() + return + discard engine.renderScene(scene) + echo "Rendered ", engine.framesRendered, " frames" + echo "Processed ", engine.eventsProcessed, " events" # cleanup echo "Start cleanup" - checkVkResult engine.gpuDevice.vk.vkDeviceWaitIdle() - renderer.destroy() engine.destroy() + +when isMainModule: + main()