diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/font/renderer/component/ChatComponentRendererTest.kt b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/font/renderer/component/ChatComponentRendererTest.kt index 0f99748e3..2210eeb7a 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/font/renderer/component/ChatComponentRendererTest.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/font/renderer/component/ChatComponentRendererTest.kt @@ -13,7 +13,6 @@ import de.bixilon.minosoft.gui.rendering.font.types.dummy.DummyFontType import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2Util.MAX import org.testng.Assert.assertEquals -import org.testng.Assert.assertFalse import org.testng.annotations.Test @Test(groups = ["font"]) @@ -27,49 +26,164 @@ class ChatComponentRendererTest { return info } + private fun TextRenderInfo.assert( + lineIndex: Int? = null, + lines: List? = null, + size: Vec2? = null, + cutOff: Boolean = false, + ) { + if (lineIndex != null) assertEquals(this.lineIndex, lineIndex, "Line index mismatch") + if (lines != null) assertEquals(this.lines, lines, "Lines mismatch") + if (size != null) assertEquals(this.size, size, "Size mismatch") + assertEquals(this.cutOff, cutOff, "Cutoff mismatch!") + } + fun noText() { val info = render(ChatComponent.EMPTY) - assertEquals(info.lineIndex, 0) - assertEquals(info.lines.size, 0) - assertEquals(info.size, Vec2()) + info.assert(lineIndex = 0, lines = emptyList(), size = Vec2()) } fun emptyChar() { val info = render(TextComponent("a")) // a has a length of 0px - assertEquals(info.lineIndex, 0) - assertEquals(info.lines.size, 0) - assertEquals(info.size, Vec2()) + info.assert(lineIndex = 0, lines = emptyList(), size = Vec2()) } fun singleChar() { val info = render(TextComponent("b")) - assertEquals(info.lineIndex, 0) - assertEquals(info.lines, listOf(TextLineInfo(BaseComponent(TextComponent("b")), 0.5f))) - assertEquals(info.size, Vec2(0.5f, 11.0f)) - assertFalse(info.cutOff) + info.assert( + lineIndex = 0, + lines = listOf(TextLineInfo(BaseComponent(TextComponent("b")), 0.5f)), + size = Vec2(0.5f, 11.0f), + ) } fun `2 chars`() { val info = render(TextComponent("bc")) - assertEquals(info.lineIndex, 0) - assertEquals(info.lines, listOf(TextLineInfo(BaseComponent(TextComponent("bc")), 2.5f))) - assertEquals(info.size, Vec2(2.5f, 11.0f)) // b + spacing + c - assertFalse(info.cutOff) + info.assert( + lineIndex = 0, + lines = listOf(TextLineInfo(BaseComponent(TextComponent("bc")), 2.5f)), + size = Vec2(2.5f, 11.0f), // b + spacing + c + ) } fun `3 chars`() { val info = render(TextComponent("bcd")) - assertEquals(info.lineIndex, 0) - assertEquals(info.lines, listOf(TextLineInfo(BaseComponent(TextComponent("bcd")), 5.0f))) - assertEquals(info.size, Vec2(5.0f, 11.0f)) // b + spacing + c + spacing + d - assertFalse(info.cutOff) + info.assert( + lineIndex = 0, + lines = listOf(TextLineInfo(BaseComponent(TextComponent("bcd")), 5.0f)), + size = Vec2(5.0f, 11.0f), + ) } - fun `max line size`() { + fun `max line size 1`() { val info = render(TextComponent("bcdef"), maxSize = Vec2(5.5f, Float.MAX_VALUE)) - assertEquals(info.lineIndex, 1) - assertEquals(info.lines, listOf(TextLineInfo(BaseComponent(TextComponent("bcd")), 5.0f), TextLineInfo(BaseComponent(TextComponent("ef")), 5.5f))) - assertEquals(info.size, Vec2(5.5f, 22.0f)) // b + spacing + c + spacing + d \n e + spacing + f - assertFalse(info.cutOff) + info.assert( + lineIndex = 1, + lines = listOf( + TextLineInfo(BaseComponent(TextComponent("bcd")), 5.0f), + TextLineInfo(BaseComponent(TextComponent("ef")), 5.5f), + ), + size = Vec2(5.5f, 22.0f), + ) } + + fun `max line size 2`() { + val info = render(TextComponent("bcdefg"), maxSize = Vec2(5.5f, Float.MAX_VALUE)) + info.assert( + lineIndex = 2, + lines = listOf( + TextLineInfo(BaseComponent(TextComponent("bcd")), 5.0f), + TextLineInfo(BaseComponent(TextComponent("ef")), 5.5f), + TextLineInfo(BaseComponent(TextComponent("g")), 3.0f), + ), + size = Vec2(5.5f, 33.0f), + ) + } + + fun `single line with spacing`() { + val info = render(TextComponent("bcd"), maxSize = Vec2(5.5f, Float.MAX_VALUE), properties = TextRenderProperties(lineSpacing = 100.0f, shadow = false)) + info.assert( + lineIndex = 0, + lines = listOf( + TextLineInfo(BaseComponent(TextComponent("bcd")), 5.0f), + ), + size = Vec2(5.0f, 11.0f), + ) + } + + fun `line spacing 1`() { + val info = render(TextComponent("bcdef"), maxSize = Vec2(5.5f, Float.MAX_VALUE), properties = TextRenderProperties(lineSpacing = 1.0f, shadow = false)) + info.assert( + lineIndex = 1, + lines = listOf( + TextLineInfo(BaseComponent(TextComponent("bcd")), 5.0f), + TextLineInfo(BaseComponent(TextComponent("ef")), 5.5f), + ), + size = Vec2(5.5f, 23.0f), + ) + } + + fun `line spacing 2`() { + val info = render(TextComponent("bcdefg"), maxSize = Vec2(5.5f, Float.MAX_VALUE), properties = TextRenderProperties(lineSpacing = 1.0f, shadow = false)) + info.assert( + lineIndex = 2, + lines = listOf( + TextLineInfo(BaseComponent(TextComponent("bcd")), 5.0f), + TextLineInfo(BaseComponent(TextComponent("ef")), 5.5f), + TextLineInfo(BaseComponent(TextComponent("g")), 3.0f), + ), + size = Vec2(5.5f, 35.0f), + ) + } + + fun `line spacing 3`() { + val info = render(TextComponent("bcdefg"), maxSize = Vec2(5.5f, Float.MAX_VALUE), properties = TextRenderProperties(lineSpacing = 20.0f, shadow = false)) + info.assert( + lineIndex = 2, + lines = listOf( + TextLineInfo(BaseComponent(TextComponent("bcd")), 5.0f), + TextLineInfo(BaseComponent(TextComponent("ef")), 5.5f), + TextLineInfo(BaseComponent(TextComponent("g")), 3.0f), + ), + size = Vec2(5.5f, 73.0f), + ) + } + + fun `empty new line`() { + val info = render(TextComponent("\n")) + info.assert( + lineIndex = 1, + lines = listOf( + TextLineInfo(BaseComponent(TextComponent("")), 0.0f), + ), + size = Vec2(0.0f, 11.0f), + ) + } + + fun `basic new line 1`() { + val info = render(TextComponent("b\nb")) + info.assert( + lineIndex = 1, + lines = listOf( + TextLineInfo(BaseComponent(TextComponent("b")), 0.5f), + TextLineInfo(BaseComponent(TextComponent("b")), 0.5f), + ), + size = Vec2(0.5f, 22.0f), + ) + } + + fun `basic new line 2`() { + val info = render(TextComponent("bcd\n\nefgh")) + info.assert( + lineIndex = 1, + lines = listOf( + TextLineInfo(BaseComponent(TextComponent("bcd")), 5.0f), + TextLineInfo(BaseComponent(TextComponent("")), 0.0f), + TextLineInfo(BaseComponent(TextComponent("efgh")), 14.0f), + ), + size = Vec2(14f, 33.0f), + ) + } + + // TODO: shadow, cutoff, underline, strikethrough, using with consumer, formatting (just basic, that is code point renderer's job) } diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/font/types/dummy/DummyFontType.kt b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/font/types/dummy/DummyFontType.kt index 00b7077c8..af9e47381 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/font/types/dummy/DummyFontType.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/font/types/dummy/DummyFontType.kt @@ -19,6 +19,8 @@ import de.bixilon.minosoft.gui.rendering.font.types.FontType object DummyFontType : FontType { private val chars: Array = arrayOfNulls(26) // a-z + // a:0 b:0.5 c:1.0 d:1.5 e:2.0 f:2.5 g:3.0 h:3.5 + init { build() } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/element/TextOffset.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/element/TextOffset.kt index 008bbb0f0..b713a0e60 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/element/TextOffset.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/element/TextOffset.kt @@ -44,15 +44,12 @@ class TextOffset( fun getNextLineHeight(properties: TextRenderProperties): Float { var height = properties.lineHeight - if (offset.y != initial.y) { - // previous line present - height += properties.lineSpacing * properties.scale - } + height += properties.lineSpacing * properties.scale return height } - fun addLine(properties: TextRenderProperties, info: TextRenderInfo, height: Float): Boolean { + fun addLine(info: TextRenderInfo, height: Float): Boolean { if (!fitsY(info, height)) return false offset.y += height @@ -66,7 +63,7 @@ class TextOffset( fun canAdd(properties: TextRenderProperties, info: TextRenderInfo, width: Float, height: Float): CodePointAddResult { if (fitsInLine(properties, info, width)) return CodePointAddResult.FINE - if (addLine(properties, info, height) && fitsInLine(properties, info, width)) return CodePointAddResult.NEW_LINE + if (addLine(info, height) && fitsInLine(properties, info, width)) return CodePointAddResult.NEW_LINE info.cutOff = true return CodePointAddResult.BREAK