Skip to content

Commit 8921bf7

Browse files
committed
Emoji artifact & space fixes
1 parent 944a9bc commit 8921bf7

File tree

6 files changed

+40
-31
lines changed

6 files changed

+40
-31
lines changed

common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/FontRenderer.kt

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ import com.lambda.graphics.buffer.vao.IRenderContext
44
import com.lambda.graphics.buffer.vao.vertex.VertexAttrib
55
import com.lambda.graphics.buffer.vao.vertex.VertexMode
66
import com.lambda.graphics.renderer.Renderer
7-
import com.lambda.graphics.renderer.gui.font.glyph.CharInfo
7+
import com.lambda.graphics.renderer.gui.font.glyph.GlyphInfo
88
import com.lambda.graphics.shader.Shader
99
import com.lambda.module.modules.client.FontSettings
10+
import com.lambda.util.math.ColorUtils.a
11+
import com.lambda.util.math.ColorUtils.setAlpha
1012
import com.lambda.util.math.Vec2d
1113
import java.awt.Color
1214

@@ -23,14 +25,14 @@ class FontRenderer(
2325
* @param text The text to parse.
2426
* @return A list of triples containing the emoji text, start index, and end index.
2527
*/
26-
fun parseEmojis(text: String): List<Triple<CharInfo, Int, Int>> {
27-
val result = mutableListOf<Triple<CharInfo, Int, Int>>()
28+
fun parseEmojis(text: String): List<Pair<GlyphInfo, IntRange>> {
29+
val result = mutableListOf<Pair<GlyphInfo, IntRange>>()
2830
val matches = emojiRegex.findAll(text)
2931

3032
for (match in matches) {
3133
val emojiKey = match.value.substring(1, match.value.length - 1)
3234
val charInfo = emojis[emojiKey] ?: continue
33-
result.add(Triple(charInfo, match.range.first, match.range.last))
35+
result.add(charInfo to match.range)
3436
}
3537

3638
return result
@@ -77,18 +79,20 @@ class FontRenderer(
7779
* @param color The color of the text.
7880
* @param block The block to execute for each character.
7981
*
80-
* @see CharInfo
82+
* @see GlyphInfo
8183
*/
8284
private fun iterateText(
8385
text: String,
8486
scale: Double,
8587
shadow: Boolean,
8688
color: Color = Color.WHITE,
87-
block: (CharInfo, Vec2d, Vec2d, Color) -> Unit
89+
block: (GlyphInfo, Vec2d, Vec2d, Color) -> Unit
8890
) {
8991
val actualScale = getScaleFactor(scale)
9092
val scaledShadowShift = shadowShift * actualScale
9193
val scaledGap = gap * actualScale
94+
val shadowColor = getShadowColor(color)
95+
val emojiColor = Color.WHITE.setAlpha(color.a)
9296

9397
var posX = 0.0
9498
val posY = getHeight(scale) * -0.5 + baselineOffset * actualScale
@@ -99,16 +103,16 @@ class FontRenderer(
99103
while (index < text.length) {
100104
run { // Because continue is not allowed in lambda
101105
emojis
102-
.firstOrNull { index in it.second..it.third }
106+
.firstOrNull { index in it.second }
103107
?.let { emoji ->
104108
val scaledSize = emoji.first.size * actualScale
105109
val pos1 = Vec2d(posX, posY)
106110
val pos2 = pos1 + scaledSize
107111

108-
block(emoji.first, pos1, pos2, color)
112+
block(emoji.first, pos1, pos2, emojiColor)
109113

110114
posX += scaledSize.x + scaledGap
111-
index += emoji.third - emoji.second + 1
115+
index = emoji.second.last
112116
return@run
113117
}
114118

@@ -122,7 +126,7 @@ class FontRenderer(
122126
if (shadow && FontSettings.shadow) {
123127
val shadowPos1 = pos1 + scaledShadowShift
124128
val shadowPos2 = shadowPos1 + scaledSize
125-
block(glyph, shadowPos1, shadowPos2, getShadowColor(color))
129+
block(glyph, shadowPos1, shadowPos2, shadowColor)
126130
}
127131

128132
block(glyph, pos1, pos2, color)
@@ -134,7 +138,7 @@ class FontRenderer(
134138
}
135139
}
136140

137-
private fun IRenderContext.putChar(pos: Vec2d, lt: Vec2d, rb: Vec2d, color: Color, ci: CharInfo) {
141+
private fun IRenderContext.putChar(pos: Vec2d, lt: Vec2d, rb: Vec2d, color: Color, ci: GlyphInfo) {
138142
val x = pos.x
139143
val y = pos.y
140144

@@ -161,17 +165,17 @@ class FontRenderer(
161165

162166
override fun render() {
163167
shader.use()
168+
shader["u_EmojiTexture"] = 1
164169

165170
font.glyphs.bind()
166-
167171
emojis.glyphs.bind()
168-
shader["u_EmojiTexture"] = 1
169172

170173
super.render()
171174
}
172175

173176
companion object {
174177
private val shader = Shader("renderer/font")
178+
175179
private val shadowShift get() = FontSettings.shadowShift * 4.0
176180
private val baselineOffset get() = FontSettings.baselineOffset * 2.0f - 10f
177181
private val gap get() = FontSettings.gapSetting * 0.5f - 0.8f

common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/LambdaMoji.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ enum class LambdaMoji(private val zipUrl: String) {
1616

1717
object Loader : Loadable {
1818
override fun load(): String {
19-
LambdaMoji.entries.forEach(LambdaMoji::loadGlyphs)
20-
return "Loaded ${LambdaMoji.entries.size} emoji pools"
19+
entries.forEach(LambdaMoji::loadGlyphs)
20+
return "Loaded ${entries.size} emoji pools"
2121
}
2222
}
2323
}

common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/glyph/EmojiGlyphs.kt

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ import kotlin.math.log2
1717
import kotlin.math.sqrt
1818
import kotlin.system.measureTimeMillis
1919

20+
// TODO: AbstractGlyphs to use for both Font & Emoji glyphs?
2021
class EmojiGlyphs(zipUrl: String) {
21-
private val emojiMap = mutableMapOf<String, CharInfo>()
22+
private val emojiMap = mutableMapOf<String, GlyphInfo>()
2223
private val fontTexture: MipmapTexture
2324

2425
private val image: BufferedImage
@@ -43,10 +44,12 @@ class EmojiGlyphs(zipUrl: String) {
4344

4445
val length = zip.size().toDouble()
4546

46-
// TODO: This is a hack but it works
47-
val width = pow(2, ceil(log2(firstImage.width * sqrt(length))).toInt())
48-
val height = pow(2, ceil(log2(firstImage.height * sqrt(length))).toInt())
49-
val texelSize = 1.0 / width // This assumes that the texture is a power of 2
47+
fun getTextureDimensionLength(dimLength: Int) =
48+
pow(2, ceil(log2((dimLength + STEP) * sqrt(length))).toInt())
49+
50+
val width = getTextureDimensionLength(firstImage.width)
51+
val height = getTextureDimensionLength(firstImage.height)
52+
val texelSize = Vec2d.ONE / Vec2d(width, height)
5053

5154
image = BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB)
5255
graphics = image.graphics as Graphics2D
@@ -57,7 +60,7 @@ class EmojiGlyphs(zipUrl: String) {
5760
val emoji = ImageIO.read(zip.getInputStream(entry))
5861

5962
if (x + emoji.width >= image.width) {
60-
y += emoji.height
63+
y += emoji.height + STEP
6164
x = 0
6265
}
6366

@@ -69,13 +72,13 @@ class EmojiGlyphs(zipUrl: String) {
6972
val uv1 = Vec2d(x, y) * texelSize
7073
val uv2 = Vec2d(x, y).plus(size) * texelSize
7174

72-
emojiMap[name] = CharInfo(size, -uv1, -uv2)
75+
emojiMap[name] = GlyphInfo(size, -uv1, -uv2)
7376

74-
x += emoji.width
77+
x += emoji.width + STEP
7578
}
7679
}
7780

78-
ImageIO.write(image, "png", File("emoji.png"))
81+
//ImageIO.write(image, "png", File("emoji.png"))
7982

8083
fontTexture = MipmapTexture(image)
8184
}
@@ -90,10 +93,12 @@ class EmojiGlyphs(zipUrl: String) {
9093
}
9194
}
9295

93-
fun getEmoji(emoji: String): CharInfo? =
96+
fun getEmoji(emoji: String): GlyphInfo? =
9497
emojiMap[emoji]
9598

9699
companion object {
100+
private const val STEP = 2
101+
97102
private const val GL_TEXTURE_SLOT = 1 // TODO: Texture slot borrowing
98103
}
99104
}

common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/glyph/FontGlyphs.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import kotlin.math.max
1414
import kotlin.system.measureTimeMillis
1515

1616
class FontGlyphs(font: Font) {
17-
private val charMap = Int2ObjectOpenHashMap<CharInfo>()
17+
private val charMap = Int2ObjectOpenHashMap<GlyphInfo>()
1818
private val fontTexture: MipmapTexture
1919

2020
var fontHeight = 0.0; private set
@@ -35,7 +35,7 @@ class FontGlyphs(font: Font) {
3535

3636
rowHeight = max(rowHeight, charImage.height + STEP)
3737

38-
if (x + charImage.width + STEP >= TEXTURE_SIZE) {
38+
if (x + charImage.width >= TEXTURE_SIZE) {
3939
y += rowHeight
4040
x = 0
4141
rowHeight = 0
@@ -49,7 +49,7 @@ class FontGlyphs(font: Font) {
4949
val uv1 = Vec2d(x, y) * ONE_TEXEL_SIZE
5050
val uv2 = Vec2d(x, y).plus(size) * ONE_TEXEL_SIZE
5151

52-
charMap[char.code] = CharInfo(size, uv1, uv2)
52+
charMap[char.code] = GlyphInfo(size, uv1, uv2)
5353
fontHeight = max(fontHeight, size.y)
5454

5555
x += charImage.width + STEP
@@ -68,7 +68,7 @@ class FontGlyphs(font: Font) {
6868
}
6969
}
7070

71-
fun getChar(char: Char): CharInfo? =
71+
fun getChar(char: Char): GlyphInfo? =
7272
charMap[char.code]
7373

7474
companion object {

common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/glyph/CharInfo.kt renamed to common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/glyph/GlyphInfo.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import com.lambda.util.math.Vec2d
99
* @property uv1 The top-left UV coordinates of the character texture.
1010
* @property uv2 The bottom-right UV coordinates of the character texture.
1111
*/
12-
data class CharInfo(
12+
data class GlyphInfo(
1313
val size: Vec2d,
1414
val uv1: Vec2d,
1515
val uv2: Vec2d

common/src/main/kotlin/com/lambda/module/modules/debug/RenderTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import com.lambda.module.Module
44
import com.lambda.module.tag.ModuleTag
55

66
object RenderTest : Module(
7-
name = "RenderTest",
7+
name = "Render:shrimp:Test:canned_food:",
88
description = "RenderTest",
99
defaultTags = setOf(ModuleTag.DEBUG)
1010
) {

0 commit comments

Comments
 (0)