Mercurial > games > semicongine
view src/semicongine/engine.nim @ 321:30117d8f0052
did next step in renderpipeline-refactoring, using shaderconfiguration objects instead for less ambigious shader-pipeline configuration
author | Sam <sam@basx.dev> |
---|---|
date | Tue, 15 Aug 2023 23:51:37 +0700 |
parents | 9efc258df208 |
children | 6dab370d1758 |
line wrap: on
line source
import std/sequtils import std/options import std/logging import std/os import ./platform/window import ./core import ./vulkan/instance import ./vulkan/device import ./vulkan/physicaldevice import ./vulkan/renderpass import ./vulkan/shader import ./scene import ./renderer import ./events import ./audio type EngineState* = enum Starting Running Shutdown Input = object keyIsDown: set[Key] keyWasPressed: set[Key] keyWasReleased: set[Key] mouseIsDown: set[MouseButton] mouseWasPressed: set[MouseButton] mouseWasReleased: set[MouseButton] mousePosition: Vec2f mouseMove: Vec2f eventsProcessed: uint64 windowWasResized: bool mouseWheel: float32 Engine* = object state*: EngineState device: Device debugger: Debugger instance: Instance window: NativeWindow renderer: Option[Renderer] input: Input exitHandler: proc(engine: var Engine) resizeHandler: proc(engine: var Engine) eventHandler: proc(engine: var Engine, event: Event) proc destroy*(engine: var Engine) = checkVkResult engine.device.vk.vkDeviceWaitIdle() if engine.renderer.isSome: engine.renderer.get.destroy() engine.device.destroy() if engine.debugger.messenger.valid: engine.debugger.destroy() engine.window.destroy() engine.instance.destroy() 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 = echo "Set log level to ", ENGINE_LOGLEVEL setLogFilter(ENGINE_LOGLEVEL) result.state = Starting result.exitHandler = exitHandler result.resizeHandler = resizeHandler result.eventHandler = eventHandler result.window = createWindow(applicationName) var instanceExtensions: seq[string] enabledLayers: seq[string] if debug: instanceExtensions.add "VK_EXT_debug_utils" enabledLayers.add "VK_LAYER_KHRONOS_validation" putEnv("VK_LAYER_ENABLES", "VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT") if defined(linux) and DEBUG: enabledLayers.add "VK_LAYER_MESA_overlay" result.instance = result.window.createInstance( vulkanVersion=VK_MAKE_API_VERSION(0, 1, 3, 0), instanceExtensions=instanceExtensions, layers=enabledLayers, ) if debug: result.debugger = result.instance.createDebugMessenger() # create devices let selectedPhysicalDevice = result.instance.getPhysicalDevices().filterBestGraphics() result.device = result.instance.createDevice( selectedPhysicalDevice, enabledLayers = @[], enabledExtensions = @[], selectedPhysicalDevice.filterForGraphicsPresentationQueues() ) startMixerThread() proc setRenderer*(engine: var Engine, renderPass: RenderPass) = if engine.renderer.isSome: engine.renderer.get.destroy() engine.renderer = some(engine.device.initRenderer(renderPass)) proc addScene*(engine: var Engine, scene: Scene, vertexInput: seq[ShaderAttribute], samplers: seq[ShaderAttribute], transformAttribute="transform", materialIndexAttribute="materialIndex") = assert transformAttribute == "" or transformAttribute in map(vertexInput, proc(a: ShaderAttribute): string = a.name) assert materialIndexAttribute == "" or materialIndexAttribute in map(vertexInput, proc(a: ShaderAttribute): string = a.name) assert engine.renderer.isSome # TODO: # rethink when and how we set up those buffers # scene should have no idea about shader inputs and samplers, but we need to use those in the setup # idea: gather material-names -> get materials -> get shaders -> determine vertexInputs and samplers? # also, be aware: need to support multiple pipelines/shaders engine.renderer.get.setupDrawableBuffers(scene, vertexInput, samplers) proc renderScene*(engine: var Engine, scene: var Scene) = assert engine.state == Running assert engine.renderer.isSome engine.renderer.get.updateMeshData(scene) engine.renderer.get.updateUniformData(scene) engine.renderer.get.render(scene) proc updateAnimations*(engine: var Engine, scene: var Scene, dt: float32) = assert engine.state == Running assert engine.renderer.isSome engine.renderer.get.updateAnimations(scene, dt) proc updateInputs*(engine: var Engine): EngineState = assert engine.state in [Starting, Running] engine.input.keyWasPressed = {} engine.input.keyWasReleased = {} engine.input.mouseWasPressed = {} engine.input.mouseWasReleased = {} engine.input.mouseWheel = 0 engine.input.mouseMove = newVec2f() if engine.state == Starting: engine.input.windowWasResized = true var mpos = engine.window.getMousePosition() if mpos.isSome: engine.input.mousePosition = mpos.get var killed = 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: engine.input.windowWasResized = 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: let newPos = newVec2(float32(event.x), float32(event.y)) engine.input.mouseMove = newPos - engine.input.mousePosition engine.input.mousePosition = newPos of MouseWheel: engine.input.mouseWheel = event.amount if engine.state == Starting: engine.state = Running if killed: engine.state = Shutdown if engine.exitHandler != nil: engine.exitHandler(engine) if engine.input.windowWasResized and engine.resizeHandler != nil: engine.resizeHandler(engine) return engine.state # wrappers for internal things 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): auto = engine.input.mousePosition func mouseMove*(engine: Engine): auto = engine.input.mouseMove func mouseWheel*(engine: Engine): auto = engine.input.mouseWheel func eventsProcessed*(engine: Engine): auto = engine.input.eventsProcessed func framesRendered*(engine: Engine): uint64 = (if engine.renderer.isSome: engine.renderer.get.framesRendered else: 0) func gpuDevice*(engine: Engine): Device = engine.device func getWindow*(engine: Engine): auto = engine.window func windowWasResized*(engine: Engine): auto = engine.input.windowWasResized func showSystemCursor*(engine: Engine) = engine.window.showSystemCursor() func hideSystemCursor*(engine: Engine) = engine.window.hideSystemCursor() proc fullscreen*(engine: var Engine, enable: bool) = engine.window.fullscreen(enable)