@@ -12,9 +12,9 @@ import java.awt.Color
1212
1313class FontRenderer (
1414 private val font : LambdaFont ,
15- private val emojis : LambdaMoji ,
15+ private val emojis : LambdaMoji
1616) : Renderer(VertexMode .TRIANGLES , VertexAttrib .Group .FONT ) {
17- var scaleMultiplier = 1.0
17+ private val scaleMultiplier = 1.0
1818 private val emojiRegex = Regex (" :[a-zA-Z0-9_]+:" )
1919
2020 /* *
@@ -23,30 +23,72 @@ class FontRenderer(
2323 * @param text The text to parse.
2424 * @return A list of triples containing the emoji text, start index, and end index.
2525 */
26- fun parseEmojis (text : String ): List <
27- Triple <CharInfo , Int , Int >> {
26+ fun parseEmojis (text : String ): List <Triple <CharInfo , Int , Int >> {
2827 val result = mutableListOf<Triple <CharInfo , Int , Int >>()
2928 val matches = emojiRegex.findAll(text)
3029
31- matches.forEach {
32- val index = it.value.substring(1 , it.value.length - 1 )
33- result.add(Triple (emojis[index] ? : return @forEach, it.range.first, it.range.last))
30+ for (match in matches) {
31+ val emojiKey = match.value.substring(1 , match.value.length - 1 )
32+ val charInfo = emojis[emojiKey] ? : continue
33+ result.add(Triple (charInfo, match.range.first, match.range.last))
3434 }
3535
3636 return result
3737 }
3838
39+ /* *
40+ * Builds the vertex array for rendering the text.
41+ */
3942 fun build (
4043 text : String ,
4144 position : Vec2d ,
4245 color : Color = Color .WHITE ,
4346 scale : Double = 1.0,
4447 shadow : Boolean = true
4548 ) = vao.use {
49+ iterateText(text, scale, shadow, color) { char, pos1, pos2, color ->
50+ putChar(position, pos1, pos2, color, char)
51+ }
52+ }
53+
54+ /* *
55+ * Calculates the width of the given text.
56+ */
57+ fun getWidth (text : String , scale : Double = 1.0): Double {
58+ var width = 0.0
59+ iterateText(text, scale, false ) { char, _, _, _ -> width + = char.width + gap }
60+ return width * getScaleFactor(scale)
61+ }
62+
63+ /* *
64+ * Calculates the height of the text.
65+ *
66+ * The values are hardcoded
67+ * We do not need to ask the emoji font since the height is smaller
68+ */
69+ private fun getHeight (scale : Double = 1.0) = font.glyphs.fontHeight * getScaleFactor(scale) * 0.7
70+
71+ /* *
72+ * Iterates over each character and emoji in the text.
73+ *
74+ * @param text The text to iterate over.
75+ * @param scale The scale of the text.
76+ * @param shadow Whether to render a shadow.
77+ * @param color The color of the text.
78+ * @param block The block to execute for each character.
79+ *
80+ * @see CharInfo
81+ */
82+ private fun iterateText (
83+ text : String ,
84+ scale : Double ,
85+ shadow : Boolean ,
86+ color : Color = Color .WHITE ,
87+ block : (CharInfo , Vec2d , Vec2d , Color ) -> Unit
88+ ) {
4689 val actualScale = getScaleFactor(scale)
4790 val scaledShadowShift = shadowShift * actualScale
4891 val scaledGap = gap * actualScale
49- val shadowColor = getShadowColor(color)
5092
5193 var posX = 0.0
5294 val posY = getHeight(scale) * - 0.5 + baselineOffset * actualScale
@@ -55,85 +97,43 @@ class FontRenderer(
5597
5698 var index = 0
5799 while (index < text.length) {
58- emojis
59- .firstOrNull { index in it.second.. it.third }
60- ?.let { emoji ->
61- val scaledSize = emoji.first.size * actualScale
62- val pos1 = Vec2d (posX, posY)
63- val pos2 = pos1 + scaledSize
64-
65- putChar(position, pos1, pos2, color, emoji.first)
66-
67- posX + = scaledSize.x + scaledGap
68- index + = emoji.third - emoji.second + 1
69-
70- if (index >= text.length) {
71- // This means we've reached the end of the text
72- return @use
100+ run { // Because continue is not allowed in lambda
101+ emojis
102+ .firstOrNull { index in it.second.. it.third }
103+ ?.let { emoji ->
104+ val scaledSize = emoji.first.size * actualScale
105+ val pos1 = Vec2d (posX, posY)
106+ val pos2 = pos1 + scaledSize
107+
108+ block(emoji.first, pos1, pos2, color)
109+
110+ posX + = scaledSize.x + scaledGap
111+ index + = emoji.third - emoji.second + 1
112+ return @run
73113 }
74- }
75114
76- val char = text[index]
77- val glyph = font[char] ? : run {
78- index++
79- return @use
80- }
115+ val char = text[index]
116+ val glyph = font[char] ? : return @run
81117
82- val scaledSize = glyph.size * actualScale
118+ val scaledSize = glyph.size * actualScale
119+ val pos1 = Vec2d (posX, posY)
120+ val pos2 = pos1 + scaledSize
83121
84- val pos1 = Vec2d (posX, posY)
85- val pos2 = pos1 + scaledSize
86-
87- if (shadow && FontSettings .shadow) {
88- val shadowPos1 = pos1 + scaledShadowShift
89- val shadowPos2 = shadowPos1 + scaledSize
90- putChar(position, shadowPos1, shadowPos2, shadowColor, glyph)
91- }
92-
93- putChar(position, pos1, pos2, color, glyph)
94-
95- posX + = scaledSize.x + scaledGap
96- index++
97- }
98- }
99-
100- fun getWidth (text : String , scale : Double = 1.0): Double {
101- var width = 0.0
102-
103- val emojis = parseEmojis(text)
104-
105- var index = 0
106- while (index < text.length) {
107- emojis
108- .firstOrNull { index in it.second.. it.third }
109- ?.let { emoji ->
110- val scaledSize = emoji.first.size * getScaleFactor(scale)
111- width + = scaledSize.x + gap
112-
113- index + = emoji.third - emoji.second + 1
114-
115- if (index >= text.length) {
116- // This means we've reached the end of the text
117- return width * getScaleFactor(scale)
118- }
122+ if (shadow && FontSettings .shadow) {
123+ val shadowPos1 = pos1 + scaledShadowShift
124+ val shadowPos2 = shadowPos1 + scaledSize
125+ block(glyph, shadowPos1, shadowPos2, getShadowColor(color))
119126 }
120127
121- val char = text[index]
122- val glyph = font[char] ? : run {
123- index++
124- return width * getScaleFactor(scale)
128+ block(glyph, pos1, pos2, color)
129+
130+ posX + = scaledSize.x + scaledGap
125131 }
126132
127- width + = glyph.width + gap
128133 index++
129134 }
130-
131- return width * getScaleFactor(scale)
132135 }
133136
134- fun getHeight (scale : Double = 1.0) =
135- font.glyphs.fontHeight * getScaleFactor(scale) * 0.7
136-
137137 private fun IRenderContext.putChar (pos : Vec2d , lt : Vec2d , rb : Vec2d , color : Color , ci : CharInfo ) {
138138 val x = pos.x
139139 val y = pos.y
@@ -148,20 +148,22 @@ class FontRenderer(
148148 )
149149 }
150150
151- private fun getScaleFactor (scale : Double ) =
152- scaleMultiplier * scale * 0.12
151+ private fun getScaleFactor (scale : Double ) = scaleMultiplier * scale * 0.12
153152
154- private fun getShadowColor (color : Color ) = Color (
155- (color.red * FontSettings .shadowBrightness).toInt(),
156- (color.green * FontSettings .shadowBrightness).toInt(),
157- (color.blue * FontSettings .shadowBrightness).toInt(),
158- color.alpha
159- )
153+ private fun getShadowColor (color : Color ): Color {
154+ return Color (
155+ (color.red * FontSettings .shadowBrightness).toInt(),
156+ (color.green * FontSettings .shadowBrightness).toInt(),
157+ (color.blue * FontSettings .shadowBrightness).toInt(),
158+ color.alpha
159+ )
160+ }
160161
161162 override fun render () {
162163 shader.use()
163164
164165 font.glyphs.bind()
166+
165167 emojis.glyphs.bind()
166168 shader[" u_EmojiTexture" ] = 1
167169
@@ -170,7 +172,6 @@ class FontRenderer(
170172
171173 companion object {
172174 private val shader = Shader (" renderer/font" )
173-
174175 private val shadowShift get() = FontSettings .shadowShift * 4.0
175176 private val baselineOffset get() = FontSettings .baselineOffset * 2.0f - 10f
176177 private val gap get() = FontSettings .gapSetting * 0.5f - 0.8f
0 commit comments