Mercurial > games > semicongine
changeset 1381:c8d1b87cf6c8
did: make progress on new glyph-rendering system
author | sam <sam@basx.dev> |
---|---|
date | Thu, 12 Dec 2024 23:54:49 +0700 |
parents | 4aa9e703af48 |
children | ec9f19151d44 7e998fce9260 |
files | semicongine/rendering.nim semicongine/text.nim semicongine/text/font.nim tests/test_text.nim |
diffstat | 4 files changed, 73 insertions(+), 30 deletions(-) [+] |
line wrap: on
line diff
--- a/semicongine/rendering.nim Thu Dec 12 21:35:34 2024 +0700 +++ b/semicongine/rendering.nim Thu Dec 12 23:54:49 2024 +0700 @@ -206,7 +206,7 @@ elif getBufferType(default(T)) in [StorageBuffer, StorageBufferMapped]: VK_DESCRIPTOR_TYPE_STORAGE_BUFFER else: - {.error: "Unsupported descriptor type: " & typetraits.name(T).} + {.error: "Unsupported descriptor type: " & $T.} elif T is array: when elementType(default(T)) is ImageObject: VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER @@ -218,11 +218,11 @@ [StorageBuffer, StorageBufferMapped]: VK_DESCRIPTOR_TYPE_STORAGE_BUFFER else: - {.error: "Unsupported descriptor type: " & typetraits.name(T).} + {.error: "Unsupported descriptor type: " & $T.} else: - {.error: "Unsupported descriptor type: " & typetraits.name(T).} + {.error: "Unsupported descriptor type: " & $T.} else: - {.error: "Unsupported descriptor type: " & typetraits.name(T).} + {.error: "Unsupported descriptor type: " & $T.} func getDescriptorCount[T](): uint32 {.compileTIme.} = when T is array: @@ -239,8 +239,7 @@ found = true else: inc c - assert found, - "Field '" & field & "' of descriptor '" & typetraits.name(T) & "' not found" + assert found, "Field '" & field & "' of descriptor '" & $T & "' not found" proc currentFiF*(): int = assert vulkan.swapchain != nil, "Swapchain has not been initialized yet"
--- a/semicongine/text.nim Thu Dec 12 21:35:34 2024 +0700 +++ b/semicongine/text.nim Thu Dec 12 23:54:49 2024 +0700 @@ -76,7 +76,7 @@ glyphIndex*: GPUArray[uint16, VertexBufferMapped] GlyphData[N: static int] = object - pos: array[N, Vec2f] # [left, bottom, right, top] + pos: array[N, Vec4f] # [left, bottom, right, top] uv: array[N, Vec4f] # [left, bottom, right, top] GlyphDescriptorSet*[N: static int] = object @@ -101,26 +101,64 @@ const vec2[4] pp = vec2[](vec2(-0.1, -0.1), vec2(-0.1, 0.1), vec2(0.1, 0.1), vec2(0.1, -0.1)); void main() { - // int vertexI = indices[gl_VertexIndex]; - // vec3 pos = vec3(glyphData.pos[glyphIndex][i_x[vertexI]], glyphData.pos[glyphIndex][i_y[vertexI]], 0); - // vec2 uv = vec2(glyphData.uv[glyphIndex][i_x[vertexI]], glyphData.uv[glyphIndex][i_y[vertexI]]); - // gl_Position = vec4(pos * scale + position, 1.0); - // fragmentUv = uv; - // fragmentColor = color; - gl_Position = vec4(pp[indices[gl_VertexIndex]] + glyphIndex * 0.1, 0, 1); + int vertexI = indices[gl_VertexIndex]; + vec3 pos = vec3(glyphData.pos[glyphIndex][i_x[vertexI]], glyphData.pos[glyphIndex][i_y[vertexI]], 0); + vec2 uv = vec2(glyphData.uv[glyphIndex][i_x[vertexI]], glyphData.uv[glyphIndex][i_y[vertexI]]); + gl_Position = vec4(pos * scale + position, 1.0); + fragmentUv = uv; + fragmentColor = color; } """ fragmentCode* = """void main() { - // float v = texture(fontAtlas, fragmentUv).r; + float v = texture(fontAtlas, fragmentUv).r; // CARFULL: This can lead to rough edges at times - // if(v == 0) { - // discard; - // } - // outColor = vec4(fragmentColor.rgb, fragmentColor.a * v); - outColor = vec4(1, 0, 1, 1); + if(v == 0) { + discard; + } + outColor = vec4(fragmentColor.rgb, fragmentColor.a * v); }""" proc `=copy`(dest: var FontObj, source: FontObj) {.error.} include ./text/font include ./text/textbox + +proc glyphDescriptorSet*( + font: Font, maxGlyphs: static int +): (DescriptorSetData[GlyphDescriptorSet[maxGlyphs]], Table[Rune, uint16]) = + assert font.glyphs.len <= maxGlyphs, + "font has " & $font.glyphs.len & " glyphs but shader is only configured for " & + $maxGlyphs + + var glyphData = GlyphData[maxGlyphs]() + var glyphTable: Table[Rune, uint16] + + var i = 0'u16 + for rune, info in font.glyphs.pairs(): + let + left = -info.leftOffset + right = -info.leftOffset + info.dimension.x + top = font.lineHeight + info.topOffset + bottom = font.lineHeight + info.topOffset - info.dimension.y + glyphData.pos[i] = vec4(left, bottom, right, top) * 0.005'f32 + assert info.uvs[0].x == info.uvs[1].x, + "Currently only axis aligned rectangles are allowed for info boxes in font texture maps" + assert info.uvs[0].y == info.uvs[3].y, + "Currently only axis aligned rectangles are allowed for info boxes in font texture maps" + assert info.uvs[2].x == info.uvs[3].x, + "Currently only axis aligned rectangles are allowed for info boxes in font texture maps" + assert info.uvs[1].y == info.uvs[2].y, + "Currently only axis aligned rectangles are allowed for info boxes in font texture maps" + glyphData.uv[i] = vec4(info.uvs[0].x, info.uvs[0].y, info.uvs[2].x, info.uvs[2].y) + glyphTable[rune] = i + inc i + + ( + asDescriptorSetData( + GlyphDescriptorSet[maxGlyphs]( + fontAtlas: font.fontAtlas.copy(), + glyphData: asGPUValue(glyphData, StorageBuffer), + ) + ), + glyphTable, + )
--- a/semicongine/text/font.nim Thu Dec 12 21:35:34 2024 +0700 +++ b/semicongine/text/font.nim Thu Dec 12 23:54:49 2024 +0700 @@ -71,6 +71,7 @@ var topOffsets: Table[Rune, int] + leftOffsets: Table[Rune, int] images: seq[Image[Gray]] for codePoint in codePoints: @@ -88,6 +89,7 @@ addr offY, ) topOffsets[codePoint] = offY + leftOffsets[codePoint] = offX if char(codePoint) in UppercaseLetters: result.capHeight = float32(height) @@ -130,8 +132,9 @@ vec2((coord.x + iw - 0.5) / w, (coord.y + 0.5) / h), vec2((coord.x + iw - 0.5) / w, (coord.y + ih - 0.5) / h), ], - topOffset: float32(topOffsets[codePoint]), - leftOffset: float32(leftBearing) * result.fontscale, + topOffset: float32(topOffsets[codePoint]) * result.fontscale, + # leftOffset: float32(leftBearing) * result.fontscale, + leftOffset: float32(leftOffsets[codePoint] + leftBearing) * result.fontscale, advance: float32(advance) * result.fontscale, )
--- a/tests/test_text.nim Thu Dec 12 21:35:34 2024 +0700 +++ b/tests/test_text.nim Thu Dec 12 23:54:49 2024 +0700 @@ -4,8 +4,10 @@ import std/sequtils import std/monotimes import std/times +import std/tables import std/options import std/random +import std/unicode import ../semicongine @@ -14,20 +16,21 @@ type EMPTY = object +const N_GLYPHS = 200 proc test_01_static_label_new(time: float32) = var font = loadFont("Overhaul.ttf", lineHeightPixels = 160) var renderdata = initRenderData() var pipeline = - createPipeline[GlyphShader[200]](renderPass = vulkan.swapchain.renderPass) + createPipeline[GlyphShader[N_GLYPHS]](renderPass = vulkan.swapchain.renderPass) + var (ds, glyphtable) = glyphDescriptorSet(font, N_GLYPHS) var glyphs = Glyphs( - position: asGPUArray([vec3()], VertexBufferMapped), - scale: asGPUArray([1'f32], VertexBufferMapped), - color: asGPUArray([vec4(1, 1, 1, 1)], VertexBufferMapped), - glyphIndex: asGPUArray([0'u16], VertexBufferMapped), + position: asGPUArray([vec3(), vec3()], VertexBufferMapped), + scale: asGPUArray([1'f32, 1'f32], VertexBufferMapped), + color: asGPUArray([vec4(1, 1, 1, 1), vec4(1, 1, 1, 1)], VertexBufferMapped), + glyphIndex: + asGPUArray([glyphtable[Rune('Q')], glyphtable[Rune('H')]], VertexBufferMapped), ) - var ds = - asDescriptorSetData(GlyphDescriptorSet[200](fontAtlas: font.fontAtlas.copy())) assignBuffers(renderdata, glyphs) assignBuffers(renderdata, ds) uploadImages(renderdata, ds) @@ -282,7 +285,7 @@ destroyRenderData(renderdata) when isMainModule: - var time = 1'f32 + var time = 1000'f32 initVulkan() for depthBuffer in [true, false]: