# HG changeset patch # User Sam # Date 1707652033 -25200 # Node ID fa54a8a1e3e4309fb84ff2614f070308a3aacebd # Parent cf59fa28ae1633eb360631db43accbef80d8ff78 fix: text-alignment, a few smaller fixes diff -r cf59fa28ae16 -r fa54a8a1e3e4 semicongine/core/fonttypes.nim --- a/semicongine/core/fonttypes.nim Sat Feb 10 21:19:43 2024 +0700 +++ b/semicongine/core/fonttypes.nim Sun Feb 11 18:47:13 2024 +0700 @@ -33,4 +33,7 @@ maxHeight*: int kerning*: Table[(Rune, Rune), float32] fontscale*: float32 + lineHeight*: float32 lineAdvance*: float32 + capHeight*: float32 + xHeight*: float32 diff -r cf59fa28ae16 -r fa54a8a1e3e4 semicongine/engine.nim --- a/semicongine/engine.nim Sat Feb 10 21:19:43 2024 +0700 +++ b/semicongine/engine.nim Sun Feb 11 18:47:13 2024 +0700 @@ -109,8 +109,9 @@ assert not engine.renderer.isSome var allShaders = @shaders + allShaders.add (EMPTY_MATERIAL, EMPTY_SHADER) + allShaders.add (PANEL_MATERIAL_TYPE, PANEL_SHADER) allShaders.add (TEXT_MATERIAL_TYPE, TEXT_SHADER) - 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])) = diff -r cf59fa28ae16 -r fa54a8a1e3e4 semicongine/material.nim --- a/semicongine/material.nim Sat Feb 10 21:19:43 2024 +0700 +++ b/semicongine/material.nim Sun Feb 11 18:47:13 2024 +0700 @@ -2,8 +2,8 @@ import std/strformat import std/strutils - import ./core +import ./vulkan/shader type MaterialType* = object @@ -49,46 +49,6 @@ proc clearDirtyAttributes*(material: var MaterialData) = material.dirtyAttributes.reset -let EMPTY_MATERIAL* = MaterialType( - name: "empty material", - vertexAttributes: {"position": Vec3F32}.toTable, -) -let COLORED_MATERIAL* = MaterialType( - name: "single color material", - vertexAttributes: {"position": Vec3F32}.toTable, - attributes: {"color": Vec4F32}.toTable, -) -let VERTEX_COLORED_MATERIAL* = MaterialType( - name: "vertex color material", - vertexAttributes: { - "position": Vec3F32, - "color": Vec4F32, - }.toTable, -) -let SINGLE_COLOR_MATERIAL* = MaterialType( - name: "single color material", - vertexAttributes: { - "position": Vec3F32, - }.toTable, - attributes: {"color": Vec4F32}.toTable -) -let SINGLE_TEXTURE_MATERIAL* = MaterialType( - name: "single texture material", - vertexAttributes: { - "position": Vec3F32, - "uv": Vec2F32, - }.toTable, - attributes: {"baseTexture": TextureType}.toTable -) -let COLORED_SINGLE_TEXTURE_MATERIAL* = MaterialType( - name: "colored single texture material", - vertexAttributes: { - "position": Vec3F32, - "uv": Vec2F32, - }.toTable, - attributes: {"baseTexture": TextureType, "color": Vec4F32}.toTable -) - proc `$`*(materialType: MaterialType): string = var attributes: seq[string] for key, value in materialType.attributes.pairs: @@ -128,3 +88,52 @@ theName = &"material instance of '{theType}'" initMaterialData(theType = theType, name = theName, attributes = attributes.toTable) +const + EMPTY_MATERIAL* = MaterialType( + name: "empty material", + vertexAttributes: {"position": Vec3F32}.toTable, + ) + COLORED_MATERIAL* = MaterialType( + name: "single color material", + vertexAttributes: {"position": Vec3F32}.toTable, + attributes: {"color": Vec4F32}.toTable, + ) + VERTEX_COLORED_MATERIAL* = MaterialType( + name: "vertex color material", + vertexAttributes: { + "position": Vec3F32, + "color": Vec4F32, + }.toTable, + ) + SINGLE_COLOR_MATERIAL* = MaterialType( + name: "single color material", + vertexAttributes: { + "position": Vec3F32, + }.toTable, + attributes: {"color": Vec4F32}.toTable + ) + SINGLE_TEXTURE_MATERIAL* = MaterialType( + name: "single texture material", + vertexAttributes: { + "position": Vec3F32, + "uv": Vec2F32, + }.toTable, + attributes: {"baseTexture": TextureType}.toTable + ) + COLORED_SINGLE_TEXTURE_MATERIAL* = MaterialType( + name: "colored single texture material", + vertexAttributes: { + "position": Vec3F32, + "uv": Vec2F32, + }.toTable, + attributes: {"baseTexture": TextureType, "color": Vec4F32}.toTable + ) + EMPTY_SHADER* = createShaderConfiguration( + inputs = [ + attr[Mat4](TRANSFORM_ATTRIB, memoryPerformanceHint = PreferFastWrite, perInstance = true), + attr[Vec3f]("position", memoryPerformanceHint = PreferFastWrite), + ], + outputs = [attr[Vec4f]("color")], + vertexCode = &"gl_Position = vec4(position, 1.0) * {TRANSFORM_ATTRIB};", + fragmentCode = &"color = vec4(1, 0, 1, 1);" + ) diff -r cf59fa28ae16 -r fa54a8a1e3e4 semicongine/panel.nim --- a/semicongine/panel.nim Sat Feb 10 21:19:43 2024 +0700 +++ b/semicongine/panel.nim Sun Feb 11 18:47:13 2024 +0700 @@ -155,6 +155,12 @@ if value != panel.color: panel.mesh.material["color", 0] = value +proc transform*(panel: Panel): Mat4 = + panel.mesh.transform +proc `transform=`*(panel: var Panel, value: Mat4) = + if value != panel.transform: + panel.mesh.transform = value + proc size*(panel: Panel): Vec2f = panel.size proc `size=`*(panel: var Panel, value: Vec2f) = diff -r cf59fa28ae16 -r fa54a8a1e3e4 semicongine/renderer.nim --- a/semicongine/renderer.nim Sat Feb 10 21:19:43 2024 +0700 +++ b/semicongine/renderer.nim Sun Feb 11 18:47:13 2024 +0700 @@ -383,10 +383,10 @@ assert foundValue, &"Uniform '{uniform.name}' not found in scene shaderGlobals or materials" assert (uniform.arrayCount == 0 and value.len == 1) or value.len <= uniform.arrayCount, &"Uniform '{uniform.name}' found has wrong length (shader declares {uniform.arrayCount} but shaderGlobals and materials provide {value.len})" if value.len <= uniform.arrayCount: - warn &"Uniform '{uniform.name}' found has short length (shader declares {uniform.arrayCount} but shaderGlobals and materials provide {value.len})" + debug &"Uniform '{uniform.name}' found has short length (shader declares {uniform.arrayCount} but shaderGlobals and materials provide {value.len})" assert value.size <= uniform.size, &"During uniform update: gathered value has size {value.size} but uniform expects size {uniform.size}" if value.size <= uniform.size: - warn &"During uniform update: gathered value has size {value.size} but uniform expects size {uniform.size}" + debug &"During uniform update: gathered value has size {value.size} but uniform expects size {uniform.size}" debug &" update uniform {uniform.name} with value: {value}" # TODO: technically we would only need to update the uniform buffer of the current # frameInFlight (I think), but we don't track for which frame the shaderglobals are no longer dirty diff -r cf59fa28ae16 -r fa54a8a1e3e4 semicongine/resources/font.nim --- a/semicongine/resources/font.nim Sat Feb 10 21:19:43 2024 +0700 +++ b/semicongine/resources/font.nim Sun Feb 11 18:47:13 2024 +0700 @@ -1,4 +1,5 @@ import std/tables +import std/strutils import std/strformat import std/streams import std/os @@ -10,11 +11,11 @@ import ../core/fonttypes import ../algorithms -{.emit: "#define STBTT_STATIC" .} -{.emit: "#define STB_TRUETYPE_IMPLEMENTATION" .} -{.emit: "#include \"" & currentSourcePath.parentDir() & "/stb_truetype.h\"" .} +{.emit: "#define STBTT_STATIC".} +{.emit: "#define STB_TRUETYPE_IMPLEMENTATION".} +{.emit: "#include \"" & currentSourcePath.parentDir() & "/stb_truetype.h\"".} -type stbtt_fontinfo {.importc, incompleteStruct .} = object +type stbtt_fontinfo {.importc, incompleteStruct.} = object proc stbtt_InitFont(info: ptr stbtt_fontinfo, data: ptr char, offset: cint): cint {.importc, nodecl.} proc stbtt_ScaleForPixelHeight(info: ptr stbtt_fontinfo, pixels: cfloat): cfloat {.importc, nodecl.} @@ -42,6 +43,8 @@ var ascent, descent, lineGap: cint stbtt_GetFontVMetrics(addr fontinfo, addr ascent, addr descent, addr lineGap) + + result.lineHeight = float32(ascent - descent) * result.fontscale result.lineAdvance = float32(ascent - descent + lineGap) * result.fontscale # ensure all codepoints are available in the font @@ -69,6 +72,11 @@ ) topOffsets[codePoint] = offY + if char(codePoint) in UppercaseLetters: + result.capHeight = float32(height) + if codePoint == Rune('x'): + result.xHeight = float32(height) + if width > 0 and height > 0: var bitmap = newSeq[GrayPixel](width * height) for i in 0 ..< width * height: @@ -104,9 +112,9 @@ result.glyphs[codePoint] = GlyphInfo( dimension: newVec2f(float32(image.width), float32(image.height)), uvs: [ - newVec2f((coord.x + 0.5 ) / w, (coord.y + ih - 0.5) / h), - newVec2f((coord.x + 0.5 ) / w, (coord.y + 0.5) / h), - newVec2f((coord.x + iw - 0.5) / w, (coord.y + 0.5) / h), + newVec2f((coord.x + 0.5) / w, (coord.y + ih - 0.5) / h), + newVec2f((coord.x + 0.5) / w, (coord.y + 0.5) / h), + newVec2f((coord.x + iw - 0.5) / w, (coord.y + 0.5) / h), newVec2f((coord.x + iw - 0.5) / w, (coord.y + ih - 0.5) / h), ], topOffset: float32(topOffsets[codePoint]), diff -r cf59fa28ae16 -r fa54a8a1e3e4 semicongine/text.nim --- a/semicongine/text.nim Sat Feb 10 21:19:43 2024 +0700 +++ b/semicongine/text.nim Sun Feb 11 18:47:13 2024 +0700 @@ -84,14 +84,14 @@ if i < text.processedText.len - 1: width += text.font.kerning[(text.processedText[i], text.processedText[i + 1])] lineWidths.add width - var height = float32(lineWidths.len) * text.font.lineAdvance + var height = float32(lineWidths.len - 1) * text.font.lineAdvance + text.font.capHeight if lineWidths[^1] == 0 and lineWidths.len > 1: height -= 1 let anchorY = (case text.verticalAlignment of Top: 0'f32 of Center: height / 2 - of Bottom: height) - text.font.lineAdvance + of Bottom: height) - text.font.capHeight var offsetX = 0'f32 diff -r cf59fa28ae16 -r fa54a8a1e3e4 tests/test_font.nim --- a/tests/test_font.nim Sat Feb 10 21:19:43 2024 +0700 +++ b/tests/test_font.nim Sun Feb 11 18:47:13 2024 +0700 @@ -12,6 +12,7 @@ # build scene var scene = Scene(name: "main") var font = loadFont("DejaVuSans.ttf", lineHeightPixels = 210'f32) + var origin = initPanel(size = newVec2f(0.01, 0.01)) var main_text = font.initText("", maxLen = 255, color = newVec4f(1, 0.15, 0.15, 1), scale = 0.0005, maxWidth = 1.0) var help_text = font.initText("""Controls @@ -23,6 +24,7 @@ F4: Top F5: Center F6: Bottom""", scale = 0.0002, position = newVec2f(-0.9, -0.9), horizontalAlignment = Left, verticalAlignment = Top) + scene.add origin scene.add main_text scene.add help_text engine.loadScene(scene) @@ -35,6 +37,7 @@ if engine.windowWasResized(): var winSize = engine.getWindow().size main_text.aspect_ratio = winSize[0] / winSize[1] + origin.aspect_ratio = winSize[0] / winSize[1] help_text.aspect_ratio = winSize[0] / winSize[1] # add character @@ -68,6 +71,7 @@ elif engine.keyWasPressed(F5): main_text.verticalAlignment = Center elif engine.keyWasPressed(F6): main_text.verticalAlignment = Bottom + origin.refresh() main_text.text = main_text.text & Rune('_') main_text.refresh() main_text.text = main_text.text[0 ..< ^1] diff -r cf59fa28ae16 -r fa54a8a1e3e4 tests/test_panel.nim --- a/tests/test_panel.nim Sat Feb 10 21:19:43 2024 +0700 +++ b/tests/test_panel.nim Sun Feb 11 18:47:13 2024 +0700 @@ -29,7 +29,7 @@ font = loadFont("DejaVuSans.ttf", lineHeightPixels = 210'f32) scene = Scene(name: "main") origin = initPanel( - size = newVec2f(0.02, 0.02), + size = newVec2f(0.005, 0.005), color = newVec4f(1, 1, 1, 1), texture = Texture(isGrayscale: false, colorImage: newImage[RGBAPixel](3, 3, [T, B, T, B, B, B, T, B, T]), sampler: NEAREST_SAMPLER), ) @@ -49,7 +49,10 @@ Vertical alignment: F4: Top F5: Center - F6: Bottom""", scale = 0.0002, position = newVec2f(-0.9, -0.9), horizontalAlignment = Left, verticalAlignment = Top) + F6: Bottom +Mouse: + Left click: Increase counter + Right click: Decrease counter""", scale = 0.0002, position = newVec2f(-0.9, -0.9), horizontalAlignment = Left, verticalAlignment = Top) counterText = font.initText($counter, maxLen = 99, scale = 0.0004)