Mercurial > games > semicongine
changeset 433:08b8facaf3b7
add: initial implementation of "panels"
author | Sam <sam@basx.dev> |
---|---|
date | Sat, 10 Feb 2024 15:55:05 +0700 |
parents | 2b373a03cf64 |
children | 30cc1deda4c1 |
files | semicongine/engine.nim semicongine/panel.nim tests/test_panel.nim |
diffstat | 3 files changed, 130 insertions(+), 19 deletions(-) [+] |
line wrap: on
line diff
--- a/semicongine/engine.nim Sat Feb 10 15:54:25 2024 +0700 +++ b/semicongine/engine.nim Sat Feb 10 15:55:05 2024 +0700 @@ -16,6 +16,7 @@ import ./events import ./audio import ./text +import ./panel type EngineState* = enum @@ -61,7 +62,7 @@ proc initEngine*( applicationName: string, - debug=DEBUG, + debug = DEBUG, exitHandler: proc(engine: var Engine) = nil, resizeHandler: proc(engine: var Engine) = nil, eventHandler: proc(engine: var Engine, event: Event) = nil @@ -88,9 +89,9 @@ 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, + vulkanVersion = VK_MAKE_API_VERSION(0, 1, 3, 0), + instanceExtensions = instanceExtensions, + layers = enabledLayers, ) if debug: result.debugger = result.instance.createDebugMessenger() @@ -104,22 +105,23 @@ ) startMixerThread() -proc initRenderer*(engine: var Engine, shaders: openArray[(MaterialType, ShaderConfiguration)], clearColor=Vec4f([0.8'f32, 0.8'f32, 0.8'f32, 1'f32]), backFaceCulling=true) = +proc initRenderer*(engine: var Engine, shaders: openArray[(MaterialType, ShaderConfiguration)], clearColor = Vec4f([0.8'f32, 0.8'f32, 0.8'f32, 1'f32]), backFaceCulling = true) = assert not engine.renderer.isSome var allShaders = @shaders allShaders.add (TEXT_MATERIAL_TYPE, TEXT_SHADER) - engine.renderer = some(engine.device.initRenderer(shaders=allShaders, clearColor=clearColor, backFaceCulling=backFaceCulling)) + allShaders.add (PANEL_MATERIAL_TYPE, PANEL_SHADER) + engine.renderer = some(engine.device.initRenderer(shaders = allShaders, clearColor = clearColor, backFaceCulling = backFaceCulling)) -proc initRenderer*(engine: var Engine, clearColor=Vec4f([0.8'f32, 0.8'f32, 0.8'f32, 1'f32])) = +proc initRenderer*(engine: var Engine, clearColor = Vec4f([0.8'f32, 0.8'f32, 0.8'f32, 1'f32])) = engine.initRenderer(@[], clearColor) proc loadScene*(engine: var Engine, scene: var Scene) = assert engine.renderer.isSome assert not scene.loaded engine.renderer.get.setupDrawableBuffers(scene) - engine.renderer.get.updateMeshData(scene, forceAll=true) - engine.renderer.get.updateUniformData(scene, forceAll=true) + engine.renderer.get.updateMeshData(scene, forceAll = true) + engine.renderer.get.updateUniformData(scene, forceAll = true) proc unloadScene*(engine: var Engine, scene: Scene) = engine.renderer.get.destroy(scene)
--- a/semicongine/panel.nim Sat Feb 10 15:54:25 2024 +0700 +++ b/semicongine/panel.nim Sat Feb 10 15:55:05 2024 +0700 @@ -1,11 +1,43 @@ import std/strformat +import std/tables import ./core import ./mesh +import ./material +import ./vulkan/shader const + # font shader SHADER_ATTRIB_PREFIX = "semicon_panel_" MAX_PANEL_MATERIALS = 10 + POSITION_ATTRIB = SHADER_ATTRIB_PREFIX & "position" + UV_ATTRIB = SHADER_ATTRIB_PREFIX & "uv" + PANEL_MATERIAL_TYPE* = MaterialType( + name: "default-panel-material-type", + vertexAttributes: {TRANSFORM_ATTRIB: Mat4F32, POSITION_ATTRIB: Vec3F32, UV_ATTRIB: Vec2F32}.toTable, + attributes: {"panelTexture": TextureType, "color": Vec4F32}.toTable, + ) + PANEL_SHADER* = createShaderConfiguration( + inputs = [ + attr[Mat4](TRANSFORM_ATTRIB, memoryPerformanceHint = PreferFastWrite, perInstance = true), + attr[Vec3f](POSITION_ATTRIB, memoryPerformanceHint = PreferFastWrite), + attr[Vec2f](UV_ATTRIB, memoryPerformanceHint = PreferFastWrite), + attr[uint16](MATERIALINDEX_ATTRIBUTE, memoryPerformanceHint = PreferFastRead, perInstance = true), + ], + intermediates = [ + attr[Vec2f]("uvFrag"), + attr[uint16]("materialIndexOut", noInterpolation = true) + ], + outputs = [attr[Vec4f]("color")], + uniforms = [attr[Vec4f]("color", arrayCount = MAX_PANEL_MATERIALS)], + samplers = [attr[Texture]("panelTexture", arrayCount = MAX_PANEL_MATERIALS)], + vertexCode = &""" + gl_Position = vec4({POSITION_ATTRIB}, 1.0) * {TRANSFORM_ATTRIB}; + uvFrag = {UV_ATTRIB}; + materialIndexOut = {MATERIALINDEX_ATTRIBUTE}; + """, + fragmentCode = &"""color = Uniforms.color[materialIndexOut] * texture(panelTexture[materialIndexOut], uvFrag);""" + ) var instanceCounter = 0 @@ -13,7 +45,6 @@ Panel* = object position: Vec2f size: Vec2f - color*: Vec4f texture: Texture horizontalAlignment: HorizontalAlignment = Center @@ -22,19 +53,63 @@ dirty: bool mesh: Mesh +proc `$`*(panel: Panel): string = + &"Panel {panel.position} (size {panel.size})" + +proc refresh*(panel: var Panel) = + if not panel.dirty: + return + + var + offsetX = case panel.horizontalAlignment + of Left: panel.size.x / 2 + of Center: 0 + of Right: -panel.size.x / 2 + offsetY = case panel.verticalAlignment + of Top: panel.size.y / 2 + of Center: 0 + of Bottom: -panel.size.y / 2 + + panel.mesh[POSITION_ATTRIB, 0] = newVec3f( + panel.position.x - panel.size.x / 2 + offsetX, + (panel.position.y - panel.size.y / 2 + offsetY) * panel.aspect_ratio + ) + panel.mesh[POSITION_ATTRIB, 1] = newVec3f( + panel.position.x + panel.size.x / 2 + offsetX, + (panel.position.y - panel.size.y / 2 + offsetY) * panel.aspect_ratio + ) + panel.mesh[POSITION_ATTRIB, 2] = newVec3f( + panel.position.x + panel.size.x / 2 + offsetX, + (panel.position.y + panel.size.y / 2 + offsetY) * panel.aspect_ratio + ) + panel.mesh[POSITION_ATTRIB, 3] = newVec3f( + panel.position.x - panel.size.x / 2 + offsetX, + (panel.position.y + panel.size.y / 2 + offsetY) * panel.aspect_ratio + ) + + panel.dirty = false + proc initPanel*(position = newVec2f(), size = newVec2f(), color = newVec4f(1, 1, 1, 1), texture = EMPTY_TEXTURE, horizontalAlignment = HorizontalAlignment.Center, verticalAlignment = VerticalAlignment.Center): Panel = - result = Panel(position: position, size: size, color: color, texture: texture, horizontalAlignment: horizontalAlignment, verticalAlignment: verticalAlignment, aspect_ratio: 1) + result = Panel(position: position, size: size, texture: texture, horizontalAlignment: horizontalAlignment, verticalAlignment: verticalAlignment, aspect_ratio: 1) - inc instanceCounter - var - positions = newSeq[Vec3f](4) + result.mesh = newMesh( + positions = newSeq[Vec3f](4), indices = @[ [uint16(0), uint16(1), uint16(2)], [uint16(2), uint16(3), uint16(0)], - ] - uvs = newSeq[Vec2f](4) - result.mesh = newMesh(positions = positions, indices = indices, uvs = uvs, name = &"panel-{instanceCounter}") + ], + uvs = @[newVec2f(0, 1), newVec2f(1, 1), newVec2f(1, 0), newVec2f(0, 0)], name = &"panel-{instanceCounter}" + ) + result.mesh[].renameAttribute("position", POSITION_ATTRIB) + result.mesh[].renameAttribute("uv", UV_ATTRIB) + result.mesh.material = initMaterialData( + theType = PANEL_MATERIAL_TYPE, + name = "Panel material", + attributes = {"panelTexture": initDataList(@[texture]), "color": initDataList(@[color])}, + ) + inc instanceCounter + result.refresh() proc position*(panel: Panel): Vec2f = panel.position @@ -43,6 +118,12 @@ panel.position = value panel.dirty = true +proc color*(panel: Panel): Vec4f = + panel.mesh.material["color", 0, Vec4f] +proc `color=`*(panel: var Panel, value: Vec4f) = + if value != panel.color: + panel.mesh.material["color", 0] = value + proc size*(panel: Panel): Vec2f = panel.size proc `size=`*(panel: var Panel, value: Vec2f) =
--- a/tests/test_panel.nim Sat Feb 10 15:54:25 2024 +0700 +++ b/tests/test_panel.nim Sat Feb 10 15:55:05 2024 +0700 @@ -9,16 +9,44 @@ engine.initRenderer([]) # build scene - var scene = Scene(name: "main") - var panel = Panel(position: newVec2f(0, 0), size: newVec2f(0.1, 0.1)) + var + font = loadFont("DejaVuSans.ttf", lineHeightPixels = 210'f32) + scene = Scene(name: "main") + origin = initPanel(size = newVec2f(0.01, 0.01), color = newVec4f(0, 0, 0, 1)) + panel = initPanel(size = newVec2f(0.2, 0.2), color = newVec4f(1, 0, 0, 1)) + help_text = font.initText("""Controls + +Horizontal alignment: + F1: Left + F2: Center + F3: Right +Vertical alignment: + F4: Top + F5: Center + F6: Bottom""", scale = 0.0002, position = newVec2f(-0.9, -0.9), horizontalAlignment = Left, verticalAlignment = Top) scene.add panel + scene.add help_text + scene.add origin engine.loadScene(scene) while engine.updateInputs() == Running and not engine.keyIsDown(Escape): if engine.windowWasResized(): var winSize = engine.getWindow().size panel.aspect_ratio = winSize[0] / winSize[1] + origin.aspect_ratio = winSize[0] / winSize[1] + help_text.aspect_ratio = winSize[0] / winSize[1] + + if engine.keyWasPressed(F1): panel.horizontalAlignment = Left + elif engine.keyWasPressed(F2): panel.horizontalAlignment = Center + elif engine.keyWasPressed(F3): panel.horizontalAlignment = Right + elif engine.keyWasPressed(F4): panel.verticalAlignment = Top + elif engine.keyWasPressed(F5): panel.verticalAlignment = Center + elif engine.keyWasPressed(F6): panel.verticalAlignment = Bottom + + panel.refresh() + origin.refresh() + help_text.refresh() engine.renderScene(scene) engine.destroy()