# HG changeset patch # User sam # Date 1733500105 -25200 # Node ID 92c089136a054fb36394821408f31a040e2cee70 # Parent 19469f21f34e4599a769ea8fb22caf7d862bf23b did: start with new glyph-renderer diff -r 19469f21f34e -r 92c089136a05 semicongine/text.nim --- a/semicongine/text.nim Fri Dec 06 22:20:39 2024 +0700 +++ b/semicongine/text.nim Fri Dec 06 22:48:25 2024 +0700 @@ -69,6 +69,45 @@ color = vec4(textbox.color.rgb, textbox.color.a * v); }""" + GlyphDescriptors[N: static int] = object + fontAtlas: Image[Gray] + uvs1: array[N, Vec2f] + uvs2: array[N, Vec2f] + vertexPos1: array[N, Vec2f] + vertexPos2: array[N, Vec2f] + + GlyphShader*[N: static int] = object + position {.InstanceAttribute.}: Vec3f + color {.InstanceAttribute.}: Vec4f + scale {.InstanceAttribute.}: float32 + glyphIndex {.InstanceAttribute.}: uint16 + + fragmentUv {.Pass.}: Vec2f + fragmentColor {.PassFlat.}: Vec4f + color {.ShaderOutput.}: Vec4f + glyphData {.DescriptorSet: 0.}: GlyphDescriptors[N] + vertexCode* = + """void main() { + vec2 uv1 = uvs1[glyphIndex]; + vec2 uv2 = uvs2[glyphIndex]; + vec2 p1 = vertexPos1[glyphIndex]; + vec2 p2 = vertexPos2[glyphIndex]; + uv1[gl_VertexIndex % ] + + gl_Position = vec4(position * vec3(textbox.scale, 1) + textbox.position, 1.0); + fragmentUv = uv; + fragmentColor = color; +} """ + fragmentCode* = + """void main() { + float v = texture(fontAtlas, fragmentUv).r; + // CARFULL: This can lead to rough edges at times + if(v == 0) { + discard; + } + color = vec4(fragmentColor.rgb, fragmentColor.a * v); +}""" + proc `=copy`(dest: var FontObj, source: FontObj) {.error.} include ./text/font diff -r 19469f21f34e -r 92c089136a05 tests/test_text.nim --- a/tests/test_text.nim Fri Dec 06 22:20:39 2024 +0700 +++ b/tests/test_text.nim Fri Dec 06 22:48:25 2024 +0700 @@ -12,6 +12,36 @@ type FontDS = object fontAtlas: Image[Gray] +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) + + var ds = asDescriptorSetData(GlyphDescriptors[200](fontAtlas: font.fontAtlas.copy())) + uploadImages(renderdata, ds) + initDescriptorSet(renderdata, pipeline.layout(0), ds) + + var start = getMonoTime() + while ((getMonoTime() - start).inMilliseconds().int / 1000) < time: + withNextFrame(framebuffer, commandbuffer): + bindDescriptorSet(commandbuffer, ds, 0, pipeline) + withRenderPass( + vulkan.swapchain.renderPass, + framebuffer, + commandbuffer, + vulkan.swapchain.width, + vulkan.swapchain.height, + vec4(0, 0, 0, 0), + ): + withPipeline(commandbuffer, pipeline): + render(commandbuffer, pipeline, label1, vec3(), vec4(1, 1, 1, 1)) + + # cleanup + checkVkResult vkDeviceWaitIdle(vulkan.device) + destroyPipeline(pipeline) + destroyRenderData(renderdata) + proc test_01_static_label(time: float32) = var font = loadFont("Overhaul.ttf", lineHeightPixels = 160) var renderdata = initRenderData() @@ -39,7 +69,14 @@ vec4(0, 0, 0, 0), ): withPipeline(commandbuffer, pipeline): - render(commandbuffer, pipeline, label1, vec3(), vec4(1, 1, 1, 1)) + proc render( + commandBuffer = commandbuffer, + pipeline = pipeline, + mesh: TMesh, + instances: TInstance, + fixedVertexCount = -1, + fixedInstanceCount = -1, + ) # cleanup checkVkResult vkDeviceWaitIdle(vulkan.device) @@ -250,6 +287,7 @@ setupSwapchain(renderpass = renderpass) # tests a simple triangle with minimalistic shader and vertex format + test_01_static_label_new(time) test_01_static_label(time) test_02_multiple_animated(time) test_03_layouting(time)