changeset 877:773af36148bd

did: changes
author Sam <sam@basx.dev>
date Sat, 27 Jan 2024 21:08:31 +0700
parents 164b41a2d5a6
children 8ab77af322cc
files semicongine/text.nim tests/test_font.nim
diffstat 2 files changed, 42 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/semicongine/text.nim	Sat Jan 27 00:31:11 2024 +0700
+++ b/semicongine/text.nim	Sat Jan 27 21:08:31 2024 +0700
@@ -33,17 +33,17 @@
     attributes: {"fontAtlas": TextureType, "color": Vec4F32}.toTable,
   )
   TEXT_SHADER* = createShaderConfiguration(
-    inputs=[
-      attr[Mat4](TRANSFORM_ATTRIB, memoryPerformanceHint=PreferFastWrite, perInstance=true),
-      attr[Vec3f](POSITION_ATTRIB, memoryPerformanceHint=PreferFastWrite),
-      attr[Vec2f](UV_ATTRIB, memoryPerformanceHint=PreferFastWrite),
+    inputs = [
+      attr[Mat4](TRANSFORM_ATTRIB, memoryPerformanceHint = PreferFastWrite, perInstance = true),
+      attr[Vec3f](POSITION_ATTRIB, memoryPerformanceHint = PreferFastWrite),
+      attr[Vec2f](UV_ATTRIB, memoryPerformanceHint = PreferFastWrite),
     ],
-    intermediates=[attr[Vec2f]("uvFrag")],
-    outputs=[attr[Vec4f]("color")],
-    uniforms=[attr[Vec4f]("color")],
-    samplers=[attr[Texture]("fontAtlas")],
-    vertexCode= &"""gl_Position = vec4({POSITION_ATTRIB}, 1.0) * {TRANSFORM_ATTRIB}; uvFrag = {UV_ATTRIB};""",
-    fragmentCode= &"""color = vec4(Uniforms.color.rgb, Uniforms.color.a * texture(fontAtlas, uvFrag).r);"""
+    intermediates = [attr[Vec2f]("uvFrag")],
+    outputs = [attr[Vec4f]("color")],
+    uniforms = [attr[Vec4f]("color")],
+    samplers = [attr[Texture]("fontAtlas")],
+    vertexCode = &"""gl_Position = vec4({POSITION_ATTRIB}, 1.0) * {TRANSFORM_ATTRIB}; uvFrag = {UV_ATTRIB};""",
+    fragmentCode = &"""color = vec4(Uniforms.color.rgb, Uniforms.color.a * texture(fontAtlas, uvFrag).r);"""
   )
 
 proc updateMesh(textbox: var Text) =
@@ -64,8 +64,9 @@
         width += textbox.font.kerning[(textbox.text[i], textbox.text[i + 1])]
   maxWidth = max(width, maxWidth)
 
-  let centerX = maxWidth / 2
-  let centerY = height / 2
+  let anchorX = maxWidth / 2
+  # let anchorY = height / 2 # use this for vertical centering
+  let anchorY = 0'f32
 
   var offsetX = 0'f32
   var offsetY = 0'f32
@@ -84,10 +85,10 @@
           top = offsetY + glyph.topOffset
           bottom = offsetY + glyph.topOffset + glyph.dimension.y
 
-        textbox.mesh[POSITION_ATTRIB, vertexOffset + 0] = newVec3f(left - centerX, bottom - centerY)
-        textbox.mesh[POSITION_ATTRIB, vertexOffset + 1] = newVec3f(left - centerX, top - centerY)
-        textbox.mesh[POSITION_ATTRIB, vertexOffset + 2] = newVec3f(right - centerX, top - centerY)
-        textbox.mesh[POSITION_ATTRIB, vertexOffset + 3] = newVec3f(right - centerX, bottom - centerY)
+        textbox.mesh[POSITION_ATTRIB, vertexOffset + 0] = newVec3f(left - anchorX, bottom - anchorY)
+        textbox.mesh[POSITION_ATTRIB, vertexOffset + 1] = newVec3f(left - anchorX, top - anchorY)
+        textbox.mesh[POSITION_ATTRIB, vertexOffset + 2] = newVec3f(right - anchorX, top - anchorY)
+        textbox.mesh[POSITION_ATTRIB, vertexOffset + 3] = newVec3f(right - anchorX, bottom - anchorY)
 
         textbox.mesh[UV_ATTRIB, vertexOffset + 0] = glyph.uvs[0]
         textbox.mesh[UV_ATTRIB, vertexOffset + 1] = glyph.uvs[1]
@@ -108,12 +109,15 @@
   textbox.text
 
 proc `text=`*(textbox: var Text, text: seq[Rune]) =
-  textbox.text = text
-  textbox.updateMesh()
+  let newText = text[0 ..< min(text.len, textbox.maxLen)]
+  if textbox.text != newText:
+    textbox.text = newText
+    textbox.updateMesh()
+
 proc `text=`*(textbox: var Text, text: string) =
   `text=`(textbox, text.toRunes)
 
-proc initText*(maxLen: int, font: Font, text="".toRunes, color=newVec4f(0, 0, 0, 1)): Text =
+proc initText*(maxLen: int, font: Font, text = "".toRunes, color = newVec4f(0, 0, 0, 1)): Text =
   var
     positions = newSeq[Vec3f](int(maxLen * 4))
     indices: seq[array[3, uint16]]
@@ -131,12 +135,13 @@
   result.mesh[].renameAttribute("position", POSITION_ATTRIB)
   result.mesh[].renameAttribute("uv", UV_ATTRIB)
   result.mesh.material = initMaterialData(
-    theType=TEXT_MATERIAL_TYPE,
-    name=font.name & " text",
-    attributes={"fontAtlas": initDataList(@[font.fontAtlas]), "color": initDataList(@[color])},
+    theType = TEXT_MATERIAL_TYPE,
+    name = font.name & " text",
+    attributes = {"fontAtlas": initDataList(@[font.fontAtlas]),
+        "color": initDataList(@[color])},
   )
 
   result.updateMesh()
 
-proc initText*(maxLen: int, font: Font, text="", color=newVec4f(0, 0, 0, 1)): Text =
-  initText(maxLen=maxLen, font=font, text=text.toRunes, color=color)
+proc initText*(maxLen: int, font: Font, text = "", color = newVec4f(0, 0, 0, 1)): Text =
+  initText(maxLen = maxLen, font = font, text = text.toRunes, color = color)
--- a/tests/test_font.nim	Sat Jan 27 00:31:11 2024 +0700
+++ b/tests/test_font.nim	Sat Jan 27 21:08:31 2024 +0700
@@ -10,29 +10,32 @@
   # build scene
   var scene = Scene(name: "main")
   # var font = loadFont("DejaVuSans.ttf", lineHeightPixels=90'f32, charset="abcdefghijklmnopqrstuvwxyz ".toRunes)
-  var font = loadFont("DejaVuSans.ttf", lineHeightPixels=180'f32)
-  var textbox = initText(32, font, "", color=newVec4f(1, 0, 0, 1))
-  let fontscale = 0.002
+  var font = loadFont("DejaVuSans.ttf", lineHeightPixels = 250'f32)
+  var textbox = initText(32, font, "_", color = newVec4f(1, 0, 0, 1))
+  let fontscale = 0.001
   scene.add textbox
   textbox.mesh.transform = scale(fontscale, fontscale)
   engine.loadScene(scene)
 
+  let cursor = Rune('_')
   while engine.updateInputs() == Running and not engine.keyIsDown(Escape):
     if engine.windowWasResized():
       var winSize = engine.getWindow().size
       textbox.mesh.transform = scale(fontscale * (winSize[1] / winSize[0]), fontscale)
-    for c in [Key.A, Key.B, Key.C, Key.D, Key.E, Key.F, Key.G, Key.H, Key.I, Key.J, Key.K, Key.L, Key.M, Key.N, Key.O, Key.P, Key.Q, Key.R, Key.S, Key.T, Key.U, Key.V, Key.W, Key.X, Key.Y, Key.Z]:
+    for c in [Key.A, Key.B, Key.C, Key.D, Key.E, Key.F, Key.G, Key.H, Key.I,
+        Key.J, Key.K, Key.L, Key.M, Key.N, Key.O, Key.P, Key.Q, Key.R, Key.S,
+        Key.T, Key.U, Key.V, Key.W, Key.X, Key.Y, Key.Z]:
       if engine.keyWasPressed(c):
         if engine.keyIsDown(ShiftL) or engine.keyIsDown(ShiftR):
-          textbox.text = textbox.text & ($c).toRunes
+          textbox.text = textbox.text[0 ..< ^1] & ($c).toRunes & cursor
         else:
-          textbox.text = textbox.text & ($c).toRunes[0].toLower()
+          textbox.text = textbox.text[0 ..< ^1] & ($c).toRunes[0].toLower() & cursor
     if engine.keyWasPressed(Enter):
-        textbox.text = textbox.text & Rune('\n')
+      textbox.text = textbox.text[0 ..< ^1] & Rune('\n') & cursor
     if engine.keyWasPressed(Space):
-        textbox.text = textbox.text & Rune(' ')
-    if engine.keyWasPressed(Backspace) and textbox.text.len > 0:
-          textbox.text = textbox.text[0 ..< ^1]
+      textbox.text = textbox.text[0 ..< ^1] & Rune(' ') & cursor
+    if engine.keyWasPressed(Backspace) and textbox.text.len > 1:
+      textbox.text = textbox.text[0 ..< ^2] & cursor
     engine.renderScene(scene)
   engine.destroy()