Mercurial > games > semicongine
view src/semicongine/text.nim @ 731:c12b11a5f112
did: overhaul some of the mesh-data uploading and transformation handling, added: text/font rendering
author | Sam <sam@basx.dev> |
---|---|
date | Tue, 30 May 2023 16:58:14 +0700 |
parents | 70d9147415b8 |
children | 5af702c95b16 |
line wrap: on
line source
import std/sequtils import std/tables import std/unicode import ./scene import ./mesh import ./core/vector import ./core/matrix import ./core/fonttypes type TextAlignment = enum Left Center Right Textbox* = ref object of Entity maxLen*: uint32 text: seq[Rune] dirty: bool alignment*: TextAlignment font*: Font mesh*: Mesh proc updateMesh(textbox: var Textbox) = # pre-calculate text-width var width = 0'f32 for i in 0 ..< min(uint32(textbox.text.len), textbox.maxLen): width += textbox.font.glyphs[textbox.text[i]].advance if i < uint32(textbox.text.len - 1): width += textbox.font.kerning[(textbox.text[i], textbox.text[i + 1])] let centerX = width / 2 let centerY = textbox.font.maxHeight / 2 var offsetX = 0'f32 for i in 0 ..< textbox.maxLen: let vertexOffset = i * 4 if i < uint32(textbox.text.len): let glyph = textbox.font.glyphs[textbox.text[i]] left = offsetX + glyph.leftOffset right = offsetX + glyph.leftOffset + glyph.dimension.x top = glyph.topOffset bottom = glyph.topOffset + glyph.dimension.y textbox.mesh.updateMeshData("position", vertexOffset + 0, newVec3f(left - centerX, bottom + centerY)) textbox.mesh.updateMeshData("position", vertexOffset + 1, newVec3f(left - centerX, top + centerY)) textbox.mesh.updateMeshData("position", vertexOffset + 2, newVec3f(right - centerX, top + centerY)) textbox.mesh.updateMeshData("position", vertexOffset + 3, newVec3f(right - centerX, bottom + centerY)) textbox.mesh.updateMeshData("uv", vertexOffset + 0, glyph.uvs[0]) textbox.mesh.updateMeshData("uv", vertexOffset + 1, glyph.uvs[1]) textbox.mesh.updateMeshData("uv", vertexOffset + 2, glyph.uvs[2]) textbox.mesh.updateMeshData("uv", vertexOffset + 3, glyph.uvs[3]) offsetX += glyph.advance if i < uint32(textbox.text.len - 1): offsetX += textbox.font.kerning[(textbox.text[i], textbox.text[i + 1])] else: textbox.mesh.updateMeshData("position", vertexOffset + 0, newVec3f()) textbox.mesh.updateMeshData("position", vertexOffset + 1, newVec3f()) textbox.mesh.updateMeshData("position", vertexOffset + 2, newVec3f()) textbox.mesh.updateMeshData("position", vertexOffset + 3, newVec3f()) func text*(textbox: Textbox): seq[Rune] = textbox.text proc `text=`*(textbox: var Textbox, text: seq[Rune]) = textbox.text = text textbox.name = $text textbox.updateMesh() proc newTextbox*(maxLen: uint32, font: Font, text=toRunes("")): Textbox = var positions = newSeq[Vec3f](int(maxLen * 4)) indices: seq[array[3, uint32]] uvs = newSeq[Vec2f](int(maxLen * 4)) for i in 0 ..< maxLen: let offset = i * 4 indices.add [[offset + 0, offset + 1, offset + 2], [offset + 2, offset + 3, offset + 0]] result = Textbox(maxLen: maxLen, text: text, font: font, dirty: true) result.mesh = newMesh(positions = positions, indices = indices, uvs = uvs) result.mesh.setInstanceTransforms(@[Unit4F32]) result.name = $text result.transform = Unit4F32 # wrap the text mesh in a new entity to preserve the font-scaling var box = newEntity("box", result.mesh) # box.transform = scale3d(font.fontscale * 0.002, font.fontscale * 0.002) box.transform = scale3d(1 / font.resolution, 1 / font.resolution) result.add box result.updateMesh()