# HG changeset patch # User Sam # Date 1708759875 -25200 # Node ID 7629f85823a48e63e3a8489d5b92750513cb43f9 # Parent 63797470148460161fea14a015c536ccbba2f4fc fix: font-api, allow consistent use of mesh-transform diff -r 637974701484 -r 7629f85823a4 semicongine/core/constants.nim --- a/semicongine/core/constants.nim Sat Feb 17 17:18:35 2024 +0700 +++ b/semicongine/core/constants.nim Sat Feb 24 14:31:15 2024 +0700 @@ -4,3 +4,4 @@ ENGINEVERSION* = "0.0.1" TRANSFORM_ATTRIB* = "transform" MATERIALINDEX_ATTRIBUTE* = "materialIndex" + ASPECT_RATIO_ATTRIBUTE* = "aspect_ratio" diff -r 637974701484 -r 7629f85823a4 semicongine/core/dynamic_arrays.nim --- a/semicongine/core/dynamic_arrays.nim Sat Feb 17 17:18:35 2024 +0700 +++ b/semicongine/core/dynamic_arrays.nim Sat Feb 24 14:31:15 2024 +0700 @@ -201,57 +201,57 @@ of TextureType: discard -proc setValues[T: GPUType|int|uint|float](value: var DataList, data: seq[T]) = +proc setValues[T: GPUType|int|uint|float](value: var DataList, data: openArray[T]) = value.setLen(data.len) - when T is float32: value.float32[] = data - elif T is float64: value.float64[] = data - elif T is int8: value.int8[] = data - elif T is int16: value.int16[] = data - elif T is int32: value.int32[] = data - elif T is int64: value.int64[] = data - elif T is uint8: value.uint8[] = data - elif T is uint16: value.uint16[] = data - elif T is uint32: value.uint32[] = data - elif T is uint64: value.uint64[] = data - elif T is int and sizeof(int) == sizeof(int32): value.int32[] = data - elif T is int and sizeof(int) == sizeof(int64): value.int64[] = data - elif T is uint and sizeof(uint) == sizeof(uint32): value.uint32[] = data - elif T is uint and sizeof(uint) == sizeof(uint64): value.uint64[] = data - elif T is float and sizeof(float) == sizeof(float32): value.float32[] = data - elif T is float and sizeof(float) == sizeof(float64): value.float64[] = data - elif T is TVec2[int32]: value.vec2i32[] = data - elif T is TVec2[int64]: value.vec2i64[] = data - elif T is TVec3[int32]: value.vec3i32[] = data - elif T is TVec3[int64]: value.vec3i64[] = data - elif T is TVec4[int32]: value.vec4i32[] = data - elif T is TVec4[int64]: value.vec4i64[] = data - elif T is TVec2[uint32]: value.vec2u32[] = data - elif T is TVec2[uint64]: value.vec2u64[] = data - elif T is TVec3[uint32]: value.vec3u32[] = data - elif T is TVec3[uint64]: value.vec3u64[] = data - elif T is TVec4[uint32]: value.vec4u32[] = data - elif T is TVec4[uint64]: value.vec4u64[] = data - elif T is TVec2[float32]: value.vec2f32[] = data - elif T is TVec2[float64]: value.vec2f64[] = data - elif T is TVec3[float32]: value.vec3f32[] = data - elif T is TVec3[float64]: value.vec3f64[] = data - elif T is TVec4[float32]: value.vec4f32[] = data - elif T is TVec4[float64]: value.vec4f64[] = data - elif T is TMat2[float32]: value.mat2f32[] = data - elif T is TMat2[float64]: value.mat2f64[] = data - elif T is TMat23[float32]: value.mat23f32[] = data - elif T is TMat23[float64]: value.mat23f64[] = data - elif T is TMat32[float32]: value.mat32f32[] = data - elif T is TMat32[float64]: value.mat32f64[] = data - elif T is TMat3[float32]: value.mat3f32[] = data - elif T is TMat3[float64]: value.mat3f64[] = data - elif T is TMat34[float32]: value.mat34f32[] = data - elif T is TMat34[float64]: value.mat34f64[] = data - elif T is TMat43[float32]: value.mat43f32[] = data - elif T is TMat43[float64]: value.mat43f64[] = data - elif T is TMat4[float32]: value.mat4f32[] = data - elif T is TMat4[float64]: value.mat4f64[] = data - elif T is Texture: value.texture[] = data + when T is float32: value.float32[] = @data + elif T is float64: value.float64[] = @data + elif T is int8: value.int8[] = @data + elif T is int16: value.int16[] = @data + elif T is int32: value.int32[] = @data + elif T is int64: value.int64[] = @data + elif T is uint8: value.uint8[] = @data + elif T is uint16: value.uint16[] = @data + elif T is uint32: value.uint32[] = @data + elif T is uint64: value.uint64[] = @data + elif T is int and sizeof(int) == sizeof(int32): value.int32[] = @data + elif T is int and sizeof(int) == sizeof(int64): value.int64[] = @data + elif T is uint and sizeof(uint) == sizeof(uint32): value.uint32[] = @data + elif T is uint and sizeof(uint) == sizeof(uint64): value.uint64[] = @data + elif T is float and sizeof(float) == sizeof(float32): value.float32[] = @data + elif T is float and sizeof(float) == sizeof(float64): value.float64[] = @data + elif T is TVec2[int32]: value.vec2i32[] = @data + elif T is TVec2[int64]: value.vec2i64[] = @data + elif T is TVec3[int32]: value.vec3i32[] = @data + elif T is TVec3[int64]: value.vec3i64[] = @data + elif T is TVec4[int32]: value.vec4i32[] = @data + elif T is TVec4[int64]: value.vec4i64[] = @data + elif T is TVec2[uint32]: value.vec2u32[] = @data + elif T is TVec2[uint64]: value.vec2u64[] = @data + elif T is TVec3[uint32]: value.vec3u32[] = @data + elif T is TVec3[uint64]: value.vec3u64[] = @data + elif T is TVec4[uint32]: value.vec4u32[] = @data + elif T is TVec4[uint64]: value.vec4u64[] = @data + elif T is TVec2[float32]: value.vec2f32[] = @data + elif T is TVec2[float64]: value.vec2f64[] = @data + elif T is TVec3[float32]: value.vec3f32[] = @data + elif T is TVec3[float64]: value.vec3f64[] = @data + elif T is TVec4[float32]: value.vec4f32[] = @data + elif T is TVec4[float64]: value.vec4f64[] = @data + elif T is TMat2[float32]: value.mat2f32[] = @data + elif T is TMat2[float64]: value.mat2f64[] = @data + elif T is TMat23[float32]: value.mat23f32[] = @data + elif T is TMat23[float64]: value.mat23f64[] = @data + elif T is TMat32[float32]: value.mat32f32[] = @data + elif T is TMat32[float64]: value.mat32f64[] = @data + elif T is TMat3[float32]: value.mat3f32[] = @data + elif T is TMat3[float64]: value.mat3f64[] = @data + elif T is TMat34[float32]: value.mat34f32[] = @data + elif T is TMat34[float64]: value.mat34f64[] = @data + elif T is TMat43[float32]: value.mat43f32[] = @data + elif T is TMat43[float64]: value.mat43f64[] = @data + elif T is TMat4[float32]: value.mat4f32[] = @data + elif T is TMat4[float64]: value.mat4f64[] = @data + elif T is Texture: value.texture[] = @data else: {.error: "Virtual datatype has no values".} proc setValue[T: GPUType|int|uint|float](value: var DataList, i: int, data: T) = @@ -473,13 +473,13 @@ getValue[t](list, i) # since we use this often with tables, add this for an easy assignment -template `[]=`*[T](table: var Table[string, DataList], key: string, values: seq[T]) = - if key in table: +template `[]=`*[T](table: var Table[string, DataList], key: string, values: openArray[T]) = + if table.contains(key): table[key].setValues(values) else: table[key] = initDataList(values) -template `[]=`*[T](list: var DataList, values: seq[T]) = +template `[]=`*[T](list: var DataList, values: openArray[T]) = list.setValues(values) template `[]=`*[T](list: var DataList, i: int, value: T) = list.setValue(i, value) @@ -532,57 +532,57 @@ of Mat4F64: result = value.mat4f64[].toCPointer of TextureType: nil -proc appendValues*[T: GPUType|int|uint|float](value: var DataList, data: seq[T]) = +proc appendValues*[T: GPUType|int|uint|float](value: var DataList, data: openArray[T]) = value.len += data.len - when T is float32: value.float32[].add data - elif T is float64: value.float64[].add data - elif T is int8: value.int8[].add data - elif T is int16: value.int16[].add data - elif T is int32: value.int32[].add data - elif T is int64: value.int64[].add data - elif T is uint8: value.uint8[].add data - elif T is uint16: value.uint16[].add data - elif T is uint32: value.uint32[].add data - elif T is uint64: value.uint64[].add data - elif T is int and sizeof(int) == sizeof(int32): value.int32[].add data - elif T is int and sizeof(int) == sizeof(int64): value.int64[].add data - elif T is uint and sizeof(uint) == sizeof(uint32): value.uint32[].add data - elif T is uint and sizeof(uint) == sizeof(uint64): value.uint64[].add data - elif T is float and sizeof(float) == sizeof(float32): value.float32[].add data - elif T is float and sizeof(float) == sizeof(float64): value.float64[].add data - elif T is TVec2[int32]: value.vec2i32[].add data - elif T is TVec2[int64]: value.vec2i64[].add data - elif T is TVec3[int32]: value.vec3i32[].add data - elif T is TVec3[int64]: value.vec3i64[].add data - elif T is TVec4[int32]: value.vec4i32[].add data - elif T is TVec4[int64]: value.vec4i64[].add data - elif T is TVec2[uint32]: value.vec2u32[].add data - elif T is TVec2[uint64]: value.vec2u64[].add data - elif T is TVec3[uint32]: value.vec3u32[].add data - elif T is TVec3[uint64]: value.vec3u64[].add data - elif T is TVec4[uint32]: value.vec4u32[].add data - elif T is TVec4[uint64]: value.vec4u64[].add data - elif T is TVec2[float32]: value.vec2f32[].add data - elif T is TVec2[float64]: value.vec2f64[].add data - elif T is TVec3[float32]: value.vec3f32[].add data - elif T is TVec3[float64]: value.vec3f64[].add data - elif T is TVec4[float32]: value.vec4f32[].add data - elif T is TVec4[float64]: value.vec4f64[].add data - elif T is TMat2[float32]: value.mat2f32[].add data - elif T is TMat2[float64]: value.mat2f64[].add data - elif T is TMat23[float32]: value.mat23f32[].add data - elif T is TMat23[float64]: value.mat23f64[].add data - elif T is TMat32[float32]: value.mat32f32[].add data - elif T is TMat32[float64]: value.mat32f64[].add data - elif T is TMat3[float32]: value.mat3f32[].add data - elif T is TMat3[float64]: value.mat3f64[].add data - elif T is TMat34[float32]: value.mat34f32[].add data - elif T is TMat34[float64]: value.mat34f64[].add data - elif T is TMat43[float32]: value.mat43f32[].add data - elif T is TMat43[float64]: value.mat43f64[].add data - elif T is TMat4[float32]: value.mat4f32[].add data - elif T is TMat4[float64]: value.mat4f64[].add data - elif T is Texture: value.texture[].add data + when T is float32: value.float32[].add @data + elif T is float64: value.float64[].add @data + elif T is int8: value.int8[].add @data + elif T is int16: value.int16[].add @data + elif T is int32: value.int32[].add @data + elif T is int64: value.int64[].add @data + elif T is uint8: value.uint8[].add @data + elif T is uint16: value.uint16[].add @data + elif T is uint32: value.uint32[].add @data + elif T is uint64: value.uint64[].add @data + elif T is int and sizeof(int) == sizeof(int32): value.int32[].add @data + elif T is int and sizeof(int) == sizeof(int64): value.int64[].add @data + elif T is uint and sizeof(uint) == sizeof(uint32): value.uint32[].add @data + elif T is uint and sizeof(uint) == sizeof(uint64): value.uint64[].add @data + elif T is float and sizeof(float) == sizeof(float32): value.float32[].add @data + elif T is float and sizeof(float) == sizeof(float64): value.float64[].add @data + elif T is TVec2[int32]: value.vec2i32[].add @data + elif T is TVec2[int64]: value.vec2i64[].add @data + elif T is TVec3[int32]: value.vec3i32[].add @data + elif T is TVec3[int64]: value.vec3i64[].add @data + elif T is TVec4[int32]: value.vec4i32[].add @data + elif T is TVec4[int64]: value.vec4i64[].add @data + elif T is TVec2[uint32]: value.vec2u32[].add @data + elif T is TVec2[uint64]: value.vec2u64[].add @data + elif T is TVec3[uint32]: value.vec3u32[].add @data + elif T is TVec3[uint64]: value.vec3u64[].add @data + elif T is TVec4[uint32]: value.vec4u32[].add @data + elif T is TVec4[uint64]: value.vec4u64[].add @data + elif T is TVec2[float32]: value.vec2f32[].add @data + elif T is TVec2[float64]: value.vec2f64[].add @data + elif T is TVec3[float32]: value.vec3f32[].add @data + elif T is TVec3[float64]: value.vec3f64[].add @data + elif T is TVec4[float32]: value.vec4f32[].add @data + elif T is TVec4[float64]: value.vec4f64[].add @data + elif T is TMat2[float32]: value.mat2f32[].add @data + elif T is TMat2[float64]: value.mat2f64[].add @data + elif T is TMat23[float32]: value.mat23f32[].add @data + elif T is TMat23[float64]: value.mat23f64[].add @data + elif T is TMat32[float32]: value.mat32f32[].add @data + elif T is TMat32[float64]: value.mat32f64[].add @data + elif T is TMat3[float32]: value.mat3f32[].add @data + elif T is TMat3[float64]: value.mat3f64[].add @data + elif T is TMat34[float32]: value.mat34f32[].add @data + elif T is TMat34[float64]: value.mat34f64[].add @data + elif T is TMat43[float32]: value.mat43f32[].add @data + elif T is TMat43[float64]: value.mat43f64[].add @data + elif T is TMat4[float32]: value.mat4f32[].add @data + elif T is TMat4[float64]: value.mat4f64[].add @data + elif T is Texture: value.texture[].add @data else: {.error: "Virtual datatype has no values".} proc appendValues*(value: var DataList, data: DataList) = diff -r 637974701484 -r 7629f85823a4 semicongine/engine.nim --- a/semicongine/engine.nim Sat Feb 17 17:18:35 2024 +0700 +++ b/semicongine/engine.nim Sat Feb 24 14:31:15 2024 +0700 @@ -1,3 +1,5 @@ +{.experimental: "codeReordering".} + import std/options import std/logging import std/os @@ -120,6 +122,7 @@ proc loadScene*(engine: var Engine, scene: var Scene) = assert engine.renderer.isSome assert not scene.loaded + scene.addShaderGlobal(ASPECT_RATIO_ATTRIBUTE, engine.getAspectRatio) engine.renderer.get.setupDrawableBuffers(scene) engine.renderer.get.updateMeshData(scene, forceAll = true) engine.renderer.get.updateUniformData(scene, forceAll = true) @@ -130,6 +133,7 @@ proc renderScene*(engine: var Engine, scene: var Scene) = assert engine.state == Running assert engine.renderer.isSome + scene.setShaderGlobal(ASPECT_RATIO_ATTRIBUTE, engine.getAspectRatio) engine.renderer.get.updateMeshData(scene) engine.renderer.get.updateUniformData(scene) engine.renderer.get.render(scene) @@ -208,7 +212,7 @@ func framesRendered*(engine: Engine): uint64 = (if engine.renderer.isSome: engine.renderer.get.framesRendered else: 0) func gpuDevice*(engine: Engine): Device = engine.device func getWindow*(engine: Engine): auto = engine.window -func getAspectRatio*(engine: Engine): auto = engine.getWindow().size[0] / engine.getWindow().size[1] +func getAspectRatio*(engine: Engine): float32 = engine.getWindow().size[0] / engine.getWindow().size[1] func windowWasResized*(engine: Engine): auto = engine.input.windowWasResized func showSystemCursor*(engine: Engine) = engine.window.showSystemCursor() func hideSystemCursor*(engine: Engine) = engine.window.hideSystemCursor() @@ -221,14 +225,7 @@ func limits*(engine: Engine): VkPhysicalDeviceLimits = engine.gpuDevice().physicalDevice.properties.limits -proc processEventsFor*(engine: Engine, text: var Text) = - if engine.input.windowWasResized: - text.aspect_ratio = engine.getAspectRatio() - text.refresh() - proc processEventsFor*(engine: Engine, panel: var Panel) = - if engine.input.windowWasResized: - panel.aspect_ratio = engine.getAspectRatio() panel.refresh() let hasMouseNow = panel.contains(engine.mousePositionNormalized()) diff -r 637974701484 -r 7629f85823a4 semicongine/renderer.nim --- a/semicongine/renderer.nim Sat Feb 17 17:18:35 2024 +0700 +++ b/semicongine/renderer.nim Sat Feb 24 14:31:15 2024 +0700 @@ -72,7 +72,7 @@ result.add input found[input.name] = input -func materialCompatibleWithPipeline(scene: Scene, materialType: MaterialType, shaderPipeline: ShaderPipeline): (bool, string) = +proc materialCompatibleWithPipeline(scene: Scene, materialType: MaterialType, shaderPipeline: ShaderPipeline): (bool, string) = for uniform in shaderPipeline.uniforms: if scene.shaderGlobals.contains(uniform.name): if scene.shaderGlobals[uniform.name].theType != uniform.theType: @@ -90,7 +90,7 @@ return (false, "") -func meshCompatibleWithPipeline(scene: Scene, mesh: Mesh, shaderPipeline: ShaderPipeline): (bool, string) = +proc meshCompatibleWithPipeline(scene: Scene, mesh: Mesh, shaderPipeline: ShaderPipeline): (bool, string) = for input in shaderPipeline.inputs: if input.name in [TRANSFORM_ATTRIB, MATERIALINDEX_ATTRIBUTE]: # will be populated automatically assert input.perInstance == true, &"Currently the {input.name} attribute must be a per instance attribute" @@ -109,7 +109,7 @@ return (true, pipelineCompatability[1]) return (false, "") -func checkSceneIntegrity(renderer: Renderer, scene: Scene) = +proc checkSceneIntegrity(renderer: Renderer, scene: Scene) = # TODO: this and the sub-functions can likely be simplified a ton if scene.meshes.len == 0: return diff -r 637974701484 -r 7629f85823a4 semicongine/scene.nim --- a/semicongine/scene.nim Sat Feb 17 17:18:35 2024 +0700 +++ b/semicongine/scene.nim Sat Feb 24 14:31:15 2024 +0700 @@ -8,7 +8,7 @@ import ./material type - Scene* = object + Scene* = ref object name*: string shaderGlobals*: Table[string, DataList] meshes*: seq[Mesh] @@ -43,37 +43,32 @@ assert not value.isNil, &"Cannot add a mesh that is 'nil': " & name scene.meshes.add value -proc addShaderGlobal*[T](scene: var Scene, name: string, data: T) = - assert not scene.loaded, &"Scene {scene.name} has already been loaded, cannot add shader values" - scene.shaderGlobals[name] = initDataList(thetype = getDataType[T]()) - scene.shaderGlobals[name] = @[data] - scene.dirtyShaderGlobals.add name - proc addShaderGlobalArray*[T](scene: var Scene, name: string, data: openArray[T]) = assert not scene.loaded, &"Scene {scene.name} has already been loaded, cannot add shader values" scene.shaderGlobals[name] = initDataList(data) scene.dirtyShaderGlobals.add name -func getShaderGlobal*[T](scene: Scene, name: string): T = - scene.shaderGlobals[name][T, 0] +proc addShaderGlobal*[T](scene: var Scene, name: string, data: T) = + scene.addShaderGlobalArray(name, [data]) func getShaderGlobalArray*[T](scene: Scene, name: string): ref seq[T] = scene.shaderGlobals[name][T] -proc setShaderGlobal*[T](scene: var Scene, name: string, value: T) = - scene.shaderGlobals[name] = @[value] - if not scene.dirtyShaderGlobals.contains(name): - scene.dirtyShaderGlobals.add name +func getShaderGlobal*[T](scene: Scene, name: string): T = + scene.getShaderGlobalArray(name)[][0] -proc setShaderGlobalArray*[T](scene: var Scene, name: string, value: seq[T]) = +proc setShaderGlobalArray*[T](scene: var Scene, name: string, value: openArray[T]) = scene.shaderGlobals[name] = value if not scene.dirtyShaderGlobals.contains(name): scene.dirtyShaderGlobals.add name +proc setShaderGlobal*[T](scene: var Scene, name: string, value: T) = + scene.setShaderGlobalArray(name, [value]) + func dirtyShaderGlobals*(scene: Scene): seq[string] = scene.dirtyShaderGlobals -func clearDirtyShaderGlobals*(scene: var Scene) = +proc clearDirtyShaderGlobals*(scene: var Scene) = scene.dirtyShaderGlobals.reset func hash*(scene: Scene): Hash = diff -r 637974701484 -r 7629f85823a4 semicongine/text.nim --- a/semicongine/text.nim Sat Feb 17 17:18:35 2024 +0700 +++ b/semicongine/text.nim Sat Feb 24 14:31:15 2024 +0700 @@ -34,10 +34,10 @@ attr[uint16]("materialIndexOut", noInterpolation = true) ], outputs = [attr[Vec4f]("color")], - uniforms = [attr[Vec4f]("color", arrayCount = MAX_TEXT_MATERIALS)], + uniforms = [attr[Vec4f]("color", arrayCount = MAX_TEXT_MATERIALS), attr[float32](ASPECT_RATIO_ATTRIBUTE)], samplers = [attr[Texture]("fontAtlas", arrayCount = MAX_TEXT_MATERIALS)], vertexCode = &""" - gl_Position = vec4({POSITION_ATTRIB}, 1.0) * {TRANSFORM_ATTRIB}; + gl_Position = vec4({POSITION_ATTRIB}.x, {POSITION_ATTRIB}.y * Uniforms.{ASPECT_RATIO_ATTRIBUTE}, {POSITION_ATTRIB}.z, 1.0) * {TRANSFORM_ATTRIB}; uvFrag = {UV_ATTRIB}; materialIndexOut = {MATERIALINDEX_ATTRIBUTE}; """, @@ -53,11 +53,8 @@ maxWidth: float32 = 0 # properties: text: seq[Rune] - position: Vec2f horizontalAlignment: HorizontalAlignment = Center verticalAlignment: VerticalAlignment = Center - scale: float32 - aspect_ratio: float32 # management/internal: dirty: bool # is true if any of the attributes changed processedText: seq[Rune] # used to store processed (word-wrapper) text to preserve original @@ -142,7 +139,6 @@ text.mesh[POSITION_ATTRIB, vertexOffset + 1] = newVec3f() text.mesh[POSITION_ATTRIB, vertexOffset + 2] = newVec3f() text.mesh[POSITION_ATTRIB, vertexOffset + 3] = newVec3f() - text.mesh.transform = translate(text.position.x, text.position.y * text.aspect_ratio, 0) * scale(text.scale, text.scale * text.aspect_ratio) text.lastRenderedText = text.processedText text.dirty = false @@ -215,7 +211,7 @@ text.processedText = text.text if text.maxWidth > 0: - text.processedText = text.processedText.wordWrapped(text.font, text.maxWidth / text.scale) + text.processedText = text.processedText.wordWrapped(text.font, text.maxWidth / text.mesh.transform.scaling.x) proc `text=`*(text: var Text, newText: string) = `text=`(text, newText.toRunes) @@ -247,21 +243,7 @@ text.verticalAlignment = value text.dirty = true -proc scale*(text: Text): float32 = - text.scale -proc `scale=`*(text: var Text, value: float32) = - if value != text.scale: - text.scale = value - text.dirty = true - -proc aspect_ratio*(text: Text): float32 = - text.aspect_ratio -proc `aspect_ratio=`*(text: var Text, value: float32) = - if value != text.aspect_ratio: - text.aspect_ratio = value - text.dirty = true - -proc initText*(font: Font, text = "".toRunes, maxLen: int = text.len, color = newVec4f(0.07, 0.07, 0.07, 1), scale = 1'f32, position = newVec2f(), verticalAlignment = VerticalAlignment.Center, horizontalAlignment = HorizontalAlignment.Center, maxWidth = 0'f32): Text = +proc initText*(font: Font, text = "".toRunes, maxLen: int = text.len, color = newVec4f(0.07, 0.07, 0.07, 1), position = newVec2f(), verticalAlignment = VerticalAlignment.Center, horizontalAlignment = HorizontalAlignment.Center, maxWidth = 0'f32, transform = Unit4): Text = var positions = newSeq[Vec3f](int(maxLen * 4)) indices: seq[array[3, uint16]] @@ -273,8 +255,7 @@ [uint16(offset + 2), uint16(offset + 3), uint16(offset + 0)], ] - result = Text(maxLen: maxLen, font: font, dirty: true, scale: scale, position: position, aspect_ratio: 1, horizontalAlignment: horizontalAlignment, verticalAlignment: verticalAlignment, maxWidth: maxWidth) - `text=`(result, text) + result = Text(maxLen: maxLen, font: font, dirty: true, horizontalAlignment: horizontalAlignment, verticalAlignment: verticalAlignment, maxWidth: maxWidth) result.mesh = newMesh(positions = positions, indices = indices, uvs = uvs, name = &"text-{instanceCounter}") result.mesh[].renameAttribute("position", POSITION_ATTRIB) result.mesh[].renameAttribute("uv", UV_ATTRIB) @@ -283,6 +264,8 @@ name = font.name & " text", attributes = {"fontAtlas": initDataList(@[font.fontAtlas]), "color": initDataList(@[color])}, ) + result.mesh.transform = transform + `text=`(result, text) inc instanceCounter result.refresh() diff -r 637974701484 -r 7629f85823a4 tests/test_font.nim --- a/tests/test_font.nim Sat Feb 17 17:18:35 2024 +0700 +++ b/tests/test_font.nim Sat Feb 24 14:31:15 2024 +0700 @@ -13,7 +13,7 @@ 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 main_text = font.initText("".toRunes, maxLen = 255, color = newVec4f(1, 0.15, 0.15, 1), maxWidth = 1.0, transform = scale(0.0005, 0.0005)) var help_text = font.initText("""Controls Horizontal alignment: @@ -23,7 +23,7 @@ Vertical alignment: F4: Top F5: Center - F6: Bottom""", scale = 0.0002, position = newVec2f(-0.9, -0.9), horizontalAlignment = Left, verticalAlignment = Top) + F6: Bottom""".toRunes, horizontalAlignment = Left, verticalAlignment = Top, transform = translate(-0.9, -0.9) * scale(0.0002, 0.0002)) scene.add origin scene.add main_text scene.add help_text @@ -36,9 +36,6 @@ main_text.color = newVec4f(sin(t) * 0.5 + 0.5, 0.15, 0.15, 1) 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 if main_text.text.len < main_text.maxLen - 1: