11package com.lambda.graphics.renderer.gui.font
22
3- import com.lambda.graphics.buffer.vao.IRenderContext
43import com.lambda.graphics.buffer.vao.vertex.VertexAttrib
54import com.lambda.graphics.buffer.vao.vertex.VertexMode
65import com.lambda.graphics.renderer.Renderer
@@ -25,19 +24,15 @@ class FontRenderer(
2524 * @param text The text to parse.
2625 * @return A list of triples containing the emoji text, start index, and end index.
2726 */
28- fun parseEmojis (text : String ): List <Pair <GlyphInfo , IntRange >> {
29- val result = mutableListOf<Pair <GlyphInfo , IntRange >>()
30- val matches = emojiRegex.findAll(text)
31-
32- for (match in matches) {
33- val emojiKey = match.value.substring(1 , match.value.length - 1 )
34- val charInfo = emojis[emojiKey] ? : continue
35- result.add(charInfo to match.range)
27+ fun parseEmojis (text : String ) =
28+ mutableListOf<Pair <GlyphInfo , IntRange >>().apply {
29+ emojiRegex.findAll(text).forEach { match ->
30+ val emojiKey = match.value.substring(1 , match.value.length - 1 )
31+ val charInfo = emojis[emojiKey] ? : return @forEach
32+ add(charInfo to match.range)
33+ }
3634 }
3735
38- return result
39- }
40-
4136 /* *
4237 * Builds the vertex array for rendering the text.
4338 */
@@ -49,7 +44,13 @@ class FontRenderer(
4944 shadow : Boolean = true
5045 ) = vao.use {
5146 iterateText(text, scale, shadow, color) { char, pos1, pos2, color ->
52- putChar(position, pos1, pos2, color, char)
47+ grow(4 )
48+ putQuad(
49+ vec2(pos1.x + position.x, pos1.y + position.y).vec2(char.uv1.x, char.uv1.y).color(color).end(),
50+ vec2(pos1.x + position.x, pos2.y + position.y).vec2(char.uv1.x, char.uv2.y).color(color).end(),
51+ vec2(pos2.x + position.x, pos2.y + position.y).vec2(char.uv2.x, char.uv2.y).color(color).end(),
52+ vec2(pos2.x + position.x, pos1.y + position.y).vec2(char.uv2.x, char.uv1.y).color(color).end()
53+ )
5354 }
5455 }
5556
@@ -89,8 +90,8 @@ class FontRenderer(
8990 block : (GlyphInfo , Vec2d , Vec2d , Color ) -> Unit
9091 ) {
9192 val actualScale = getScaleFactor(scale)
92- val scaledShadowShift = shadowShift * actualScale
9393 val scaledGap = gap * actualScale
94+
9495 val shadowColor = getShadowColor(color)
9596 val emojiColor = Color .WHITE .setAlpha(color.a)
9697
@@ -99,59 +100,39 @@ class FontRenderer(
99100
100101 val emojis = parseEmojis(text)
101102
102- var index = 0
103- while (index < text.length) {
104- run { // Because continue is not allowed in lambda
105- emojis
106- .firstOrNull { index in it.second }
107- ?.let { emoji ->
108- val scaledSize = emoji.first.size * actualScale
109- val pos1 = Vec2d (posX, posY)
110- val pos2 = pos1 + scaledSize
111-
112- block(emoji.first, pos1, pos2, emojiColor)
103+ repeat(text.length) { index ->
104+ fun draw (info : GlyphInfo , color : Color , offset : Double = 0.0) {
105+ val scaledSize = info.size * actualScale
106+ val pos1 = Vec2d (posX, posY) + offset * actualScale
107+ val pos2 = pos1 + scaledSize
113108
114- posX + = scaledSize.x + scaledGap
115- index = emoji.second.last
116- return @run
117- }
109+ block(info, pos1, pos2, color)
110+ if (offset == 0.0 ) posX + = scaledSize.x + scaledGap
111+ }
118112
119- val char = text[index]
120- val glyph = font[char] ? : return @run
113+ // Check if there's an emoji
114+ emojis.firstOrNull { index in it.second }?.let { emoji ->
115+ // Replace first emoji char by an emoji glyph and skip the other ones
116+ if (index == emoji.second.first) {
117+ draw(emoji.first, emojiColor)
118+ }
121119
122- val scaledSize = glyph.size * actualScale
123- val pos1 = Vec2d (posX, posY)
124- val pos2 = pos1 + scaledSize
120+ return @repeat
121+ }
125122
126- if (shadow && FontSettings .shadow) {
127- val shadowPos1 = pos1 + scaledShadowShift
128- val shadowPos2 = shadowPos1 + scaledSize
129- block(glyph, shadowPos1, shadowPos2, shadowColor)
123+ // Render chars
124+ font[text[index]]?.let { info ->
125+ // Draw a shadow before
126+ if (shadow && FontSettings .shadow && shadowShift > 0.0 ) {
127+ draw(info, shadowColor, shadowShift)
130128 }
131129
132- block(glyph, pos1, pos2, color)
133-
134- posX + = scaledSize.x + scaledGap
130+ // Draw actual char over the shadow
131+ draw(info, color)
135132 }
136-
137- index++
138133 }
139134 }
140135
141- private fun IRenderContext.putChar (pos : Vec2d , lt : Vec2d , rb : Vec2d , color : Color , ci : GlyphInfo ) {
142- val x = pos.x
143- val y = pos.y
144-
145- grow(4 )
146-
147- putQuad(
148- vec2(lt.x + x, lt.y + y).vec2(ci.uv1.x, ci.uv1.y).color(color).end(),
149- vec2(lt.x + x, rb.y + y).vec2(ci.uv1.x, ci.uv2.y).color(color).end(),
150- vec2(rb.x + x, rb.y + y).vec2(ci.uv2.x, ci.uv2.y).color(color).end(),
151- vec2(rb.x + x, lt.y + y).vec2(ci.uv2.x, ci.uv1.y).color(color).end()
152- )
153- }
154-
155136 private fun getScaleFactor (scale : Double ) = scaleMultiplier * scale * 0.12
156137
157138 private fun getShadowColor (color : Color ): Color {
@@ -176,7 +157,7 @@ class FontRenderer(
176157 companion object {
177158 private val shader = Shader (" renderer/font" )
178159
179- private val shadowShift get() = FontSettings .shadowShift * 4 .0
160+ private val shadowShift get() = FontSettings .shadowShift * 5 .0
180161 private val baselineOffset get() = FontSettings .baselineOffset * 2.0f - 10f
181162 private val gap get() = FontSettings .gapSetting * 0.5f - 0.8f
182163 }
0 commit comments