From a870d64d6fb44f5c092c63ea4c95ac51d09be3df Mon Sep 17 00:00:00 2001 From: Bixilon Date: Fri, 9 Jun 2023 19:24:51 +0200 Subject: [PATCH] font rendering improvements, rasterized font renderer test --- build.gradle.kts | 2 +- .../renderer/code/DummyCodePointRenderer.kt | 26 ++++ .../code/RasterizedCodePointRendererTest.kt | 121 ++++++++++++++++++ .../gui/mesh/DummyGUIVertexConsumer.kt | 50 ++++++++ .../gui/rendering/font/WorldGUIConsumer.kt | 3 +- .../font/renderer/code/CodePointRenderer.kt | 7 +- .../code/RasterizedCodePointRenderer.kt | 70 ++-------- .../component/TextComponentRenderer.kt | 9 +- .../font/types/empty/EmptyCodeRenderer.kt | 3 +- .../gui/rendering/gui/atlas/AtlasElement.kt | 2 +- ...xtureLikeTexture.kt => CodeTexturePart.kt} | 4 +- .../atlas/{TextureLike.kt => TexturePart.kt} | 2 +- .../elements/primitive/AtlasImageElement.kt | 12 +- .../gui/rendering/gui/mesh/GUIMesh.kt | 1 + .../gui/rendering/gui/mesh/GUIMeshCache.kt | 4 +- .../rendering/gui/mesh/GUIVertexConsumer.kt | 35 ++++- .../system/base/texture/TextureManager.kt | 6 +- 17 files changed, 269 insertions(+), 88 deletions(-) create mode 100644 src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/font/renderer/code/DummyCodePointRenderer.kt create mode 100644 src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/font/renderer/code/RasterizedCodePointRendererTest.kt create mode 100644 src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/gui/mesh/DummyGUIVertexConsumer.kt rename src/main/java/de/bixilon/minosoft/gui/rendering/gui/atlas/{TextureLikeTexture.kt => CodeTexturePart.kt} (96%) rename src/main/java/de/bixilon/minosoft/gui/rendering/gui/atlas/{TextureLike.kt => TexturePart.kt} (97%) diff --git a/build.gradle.kts b/build.gradle.kts index 824b0a635..a76a52d43 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -222,7 +222,7 @@ testing { options { val options = this as TestNGOptions options.preserveOrder = true - // options.excludeGroups("pixlyzer", "light", "packet", "version", "container", "item_stack", "signature", "private_key", "interaction", "item_digging", "world_renderer", "rendering") + options.excludeGroups("command", "registry", "biome", "input", "version", "fluid", "world", "raycasting", "pixlyzer", "item", "block", "physics", "light", "packet", "container", "item_stack", "signature", "private_key", "interaction", "item_digging", "world_renderer", "rendering") } } } diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/font/renderer/code/DummyCodePointRenderer.kt b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/font/renderer/code/DummyCodePointRenderer.kt new file mode 100644 index 000000000..09f2e8358 --- /dev/null +++ b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/font/renderer/code/DummyCodePointRenderer.kt @@ -0,0 +1,26 @@ +/* + * Minosoft + * Copyright (C) 2020-2023 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.font.renderer.code + +import de.bixilon.kotlinglm.vec2.Vec2 +import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft +import de.bixilon.minosoft.gui.rendering.system.dummy.texture.DummyTexture + +class DummyCodePointRenderer( + override val uvStart: Vec2 = Vec2(0.1f, 0.2f), + override val uvEnd: Vec2 = Vec2(0.6f, 0.7f), + override val width: Float = 5.0f, +) : RasterizedCodePointRenderer { + override val texture = DummyTexture(minosoft("test")) +} diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/font/renderer/code/RasterizedCodePointRendererTest.kt b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/font/renderer/code/RasterizedCodePointRendererTest.kt new file mode 100644 index 000000000..854cf3f35 --- /dev/null +++ b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/font/renderer/code/RasterizedCodePointRendererTest.kt @@ -0,0 +1,121 @@ +/* + * Minosoft + * Copyright (C) 2020-2023 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.font.renderer.code + +import de.bixilon.kotlinglm.vec2.Vec2 +import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft +import de.bixilon.minosoft.data.text.formatting.color.ChatColors +import de.bixilon.minosoft.data.text.formatting.color.RGBColor +import de.bixilon.minosoft.gui.rendering.gui.mesh.DummyGUIVertexConsumer +import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions +import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture +import org.testng.Assert.assertEquals +import org.testng.Assert.assertNull +import org.testng.annotations.Test + +@Test(groups = ["font"], priority = -1) +class RasterizedCodePointRendererTest { + + fun verifySimpleSetup() { + val consumer = object : DummyGUIVertexConsumer() { + override fun addChar(start: Vec2, end: Vec2, texture: AbstractTexture, uvStart: Vec2, uvEnd: Vec2, italic: Boolean, tint: RGBColor, options: GUIVertexOptions?) { + this.char++ + assertEquals(tint, ChatColors.BLUE) + assertEquals(uvStart, Vec2(0.1, 0.2)) + assertEquals(uvEnd, Vec2(0.6, 0.7)) + assertEquals(texture.resourceLocation, minosoft("test")) + assertNull(options) + } + } + val char = DummyCodePointRenderer() + + char.render(Vec2(10.0f, 12.0f), ChatColors.BLUE, false, false, false, 1.0f, consumer, null) + + assertEquals(1, consumer.char) + } + + fun verifyComplexSetup() { + var chars = 0 + val consumer = object : DummyGUIVertexConsumer() { + override fun addChar(start: Vec2, end: Vec2, texture: AbstractTexture, uvStart: Vec2, uvEnd: Vec2, italic: Boolean, tint: RGBColor, options: GUIVertexOptions?) { + chars++ + } + } + val char = DummyCodePointRenderer() + + char.render(Vec2(10.0f, 12.0f), ChatColors.BLUE, true, true, false, 1.0f, consumer, null) + + assertEquals(4, chars) + } + + fun unformatted() { + val consumer = object : DummyGUIVertexConsumer() { + override fun addChar(start: Vec2, end: Vec2, index: Int) { + assertEquals(start, Vec2(10.0f, 13.0f)) // top spacing + assertEquals(end, Vec2(15.0f, 21.0f)) // start + width | start + height + } + } + val char = DummyCodePointRenderer() + + char.render(Vec2(10.0f, 12.0f), ChatColors.BLUE, false, false, false, 1.0f, consumer, null) + } + + fun scaled() { + val consumer = object : DummyGUIVertexConsumer() { + override fun addChar(start: Vec2, end: Vec2, texture: AbstractTexture, uvStart: Vec2, uvEnd: Vec2, italic: Boolean, tint: RGBColor, options: GUIVertexOptions?) { + assertEquals(start, Vec2(10.0f, 13.5f)) // top spacing + assertEquals(end, Vec2(17.5f, 25.5f)) // start + width | start + height + + // uv stays the same + assertEquals(uvStart, Vec2(0.1, 0.2)) + assertEquals(uvEnd, Vec2(0.6, 0.7)) + } + } + val char = DummyCodePointRenderer() + + char.render(Vec2(10.0f, 12.0f), ChatColors.BLUE, false, false, false, 1.5f, consumer, null) + } + + fun shadow() { + val consumer = object : DummyGUIVertexConsumer() { + override fun addChar(start: Vec2, end: Vec2, index: Int) { + if (index == 1) return + assertEquals(start, Vec2(11.0f, 14.0f)) + assertEquals(end, Vec2(16.0f, 22.0f)) + } + } + val char = DummyCodePointRenderer() + + char.render(Vec2(10.0f, 12.0f), ChatColors.BLUE, true, false, false, 1.0f, consumer, null) + + assertEquals(consumer.char, 2) + } + + fun bold() { + val consumer = object : DummyGUIVertexConsumer() { + override fun addChar(start: Vec2, end: Vec2, index: Int) { + if (index == 0) return + assertEquals(start, Vec2(10.5f, 13.0f)) + assertEquals(end, Vec2(15.5f, 21.0f)) + } + } + val char = DummyCodePointRenderer() + + char.render(Vec2(10.0f, 12.0f), ChatColors.BLUE, false, true, false, 1.0f, consumer, null) + + assertEquals(consumer.char, 2) + } + + // TODO: ascent +} diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/gui/mesh/DummyGUIVertexConsumer.kt b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/gui/mesh/DummyGUIVertexConsumer.kt new file mode 100644 index 000000000..7d293f24b --- /dev/null +++ b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/gui/mesh/DummyGUIVertexConsumer.kt @@ -0,0 +1,50 @@ +/* + * Minosoft + * Copyright (C) 2020-2023 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.gui.mesh + +import de.bixilon.kotlinglm.vec2.Vec2 +import de.bixilon.kotlinglm.vec2.Vec2i +import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft +import de.bixilon.minosoft.data.text.formatting.color.RGBColor +import de.bixilon.minosoft.gui.rendering.gui.atlas.CodeTexturePart +import de.bixilon.minosoft.gui.rendering.system.base.texture.ShaderIdentifiable +import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture +import de.bixilon.minosoft.gui.rendering.system.dummy.texture.DummyTexture +import de.bixilon.minosoft.gui.rendering.util.mesh.Mesh + +open class DummyGUIVertexConsumer : GUIVertexConsumer { + override val whiteTexture = CodeTexturePart(texture = DummyTexture(minosoft("white")), uvStart = Vec2(0.0f, 0.0f), uvEnd = Vec2(0.001f, 0.001f), size = Vec2i(16, 16)) + override val order: Array> get() = Mesh.QUAD_TO_QUAD_ORDER + var char = 0 + + override fun addCache(cache: GUIMeshCache) { + TODO("Not yet implemented") + } + + override fun ensureSize(size: Int) { + TODO("Not yet implemented") + } + + override fun addVertex(position: Vec2, texture: ShaderIdentifiable, uv: Vec2, tint: RGBColor, options: GUIVertexOptions?) { + TODO("Not yet implemented") + } + + override fun addChar(start: Vec2, end: Vec2, texture: AbstractTexture, uvStart: Vec2, uvEnd: Vec2, italic: Boolean, tint: RGBColor, options: GUIVertexOptions?) { + addChar(start, end, this.char++) + } + + open fun addChar(start: Vec2, end: Vec2, index: Int) { + TODO("Abstract") + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/font/WorldGUIConsumer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/WorldGUIConsumer.kt index f79b4e720..17104be2b 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/font/WorldGUIConsumer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/WorldGUIConsumer.kt @@ -16,7 +16,6 @@ package de.bixilon.minosoft.gui.rendering.font import de.bixilon.kotlinglm.mat4x4.Mat4 import de.bixilon.kotlinglm.vec2.Vec2 import de.bixilon.minosoft.data.text.formatting.color.RGBColor -import de.bixilon.minosoft.gui.rendering.RenderContext import de.bixilon.minosoft.gui.rendering.font.renderer.component.ChatComponentRenderer import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIMeshCache import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer @@ -27,7 +26,7 @@ import de.bixilon.minosoft.gui.rendering.world.mesh.SingleWorldMesh class WorldGUIConsumer(val mesh: SingleWorldMesh, val transform: Mat4, val light: Int) : GUIVertexConsumer { - override val context: RenderContext get() = mesh.context + override val whiteTexture = mesh.context.textureManager.whiteTexture override val order: Array> get() = mesh.order override fun addVertex(position: Vec2, texture: ShaderIdentifiable, uv: Vec2, tint: RGBColor, options: GUIVertexOptions?) { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/code/CodePointRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/code/CodePointRenderer.kt index 631b53c48..992f93165 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/code/CodePointRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/code/CodePointRenderer.kt @@ -14,7 +14,6 @@ package de.bixilon.minosoft.gui.rendering.font.renderer.code import de.bixilon.kotlinglm.vec2.Vec2 -import de.bixilon.minosoft.data.text.formatting.TextFormatting import de.bixilon.minosoft.data.text.formatting.color.RGBColor import de.bixilon.minosoft.gui.rendering.font.WorldGUIConsumer import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer @@ -25,10 +24,10 @@ interface CodePointRenderer { fun calculateWidth(scale: Float, shadow: Boolean): Float - fun render(position: Vec2, color: RGBColor, shadow: Boolean, formatting: TextFormatting, consumer: GUIVertexConsumer, options: GUIVertexOptions?, scale: Float) + fun render(position: Vec2, color: RGBColor, shadow: Boolean, bold: Boolean, italic: Boolean, scale: Float, consumer: GUIVertexConsumer, options: GUIVertexOptions?) - fun render3d(consumer: WorldGUIConsumer, color: RGBColor, shadow: Boolean, formatting: TextFormatting, scale: Float): Float { - render(Vec2.EMPTY, color, shadow, formatting, consumer, null, scale) + fun render3d(color: RGBColor, shadow: Boolean, bold: Boolean, italic: Boolean, scale: Float, consumer: WorldGUIConsumer): Float { + render(Vec2.EMPTY, color, shadow, bold, italic, scale, consumer, null) return calculateWidth(scale, shadow) } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/code/RasterizedCodePointRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/code/RasterizedCodePointRenderer.kt index 059fe4888..5966a07d0 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/code/RasterizedCodePointRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/code/RasterizedCodePointRenderer.kt @@ -14,15 +14,11 @@ package de.bixilon.minosoft.gui.rendering.font.renderer.code import de.bixilon.kotlinglm.vec2.Vec2 -import de.bixilon.minosoft.data.text.formatting.FormattingCodes -import de.bixilon.minosoft.data.text.formatting.TextFormatting import de.bixilon.minosoft.data.text.formatting.color.RGBColor import de.bixilon.minosoft.gui.rendering.font.renderer.properties.FontProperties import de.bixilon.minosoft.gui.rendering.font.renderer.properties.FormattingProperties.BOLD_OFFSET -import de.bixilon.minosoft.gui.rendering.font.renderer.properties.FormattingProperties.ITALIC_OFFSET import de.bixilon.minosoft.gui.rendering.font.renderer.properties.FormattingProperties.SHADOW_COLOR import de.bixilon.minosoft.gui.rendering.font.renderer.properties.FormattingProperties.SHADOW_OFFSET -import de.bixilon.minosoft.gui.rendering.font.types.font.Font import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture @@ -45,11 +41,11 @@ interface RasterizedCodePointRenderer : CodePointRenderer { return width * scale } - override fun render(position: Vec2, color: RGBColor, shadow: Boolean, formatting: TextFormatting, consumer: GUIVertexConsumer, options: GUIVertexOptions?, scale: Float) { + override fun render(position: Vec2, color: RGBColor, shadow: Boolean, bold: Boolean, italic: Boolean, scale: Float, consumer: GUIVertexConsumer, options: GUIVertexOptions?) { if (shadow) { - render(position + (SHADOW_OFFSET * scale), color * SHADOW_COLOR, formatting, consumer, options, scale) + render(position + (SHADOW_OFFSET * scale), color * SHADOW_COLOR, bold, italic, scale, consumer, options) } - render(position, color, formatting, consumer, options, scale) + render(position, color, bold, italic, scale, consumer, options) } fun calculateStart(base: Vec2, scale: Float): Vec2 { @@ -67,61 +63,19 @@ interface RasterizedCodePointRenderer : CodePointRenderer { return position } - private fun render(position: Vec2, color: RGBColor, formatting: TextFormatting, consumer: GUIVertexConsumer, options: GUIVertexOptions?, scale: Float) { - var boldOffset = 0.0f - - val bold = FormattingCodes.BOLD in formatting - val italic = FormattingCodes.ITALIC in formatting - - if (bold) { - boldOffset = BOLD_OFFSET * scale - } - val charHeight = FontProperties.CHAR_BASE_HEIGHT * scale - val horizontalSpacing = Font.HORIZONTAL_SPACING * scale - val verticalSpacing = Font.VERTICAL_SPACING * scale - - + private fun render(position: Vec2, color: RGBColor, bold: Boolean, italic: Boolean, scale: Float, consumer: GUIVertexConsumer, options: GUIVertexOptions?) { val startPosition = calculateStart(position, scale) val endPosition = calculateEnd(startPosition, scale) + consumer.addChar(startPosition, endPosition, texture, uvStart, uvEnd, italic, color, options) - - consumer.addQuad(startPosition, endPosition, texture, uvStart, uvEnd, italic, color, options) - - if (FormattingCodes.BOLD in formatting) { - consumer.addQuad(startPosition + Vec2(boldOffset, 0.0f), endPosition + Vec2(boldOffset, 0.0f), texture, uvStart, uvEnd, italic, color, options) - } - val whiteTexture = consumer.context.textureManager.whiteTexture - - if (FormattingCodes.STRIKETHROUGH in formatting) { - consumer.addQuad(startPosition + Vec2(-horizontalSpacing, charHeight / 2.0f - scale / 2), Vec2(endPosition.x + horizontalSpacing, startPosition.y + charHeight / 2.0f + scale / 2), whiteTexture.texture, whiteTexture.uvStart, whiteTexture.uvEnd, italic, color, options) - } - - if (FormattingCodes.UNDERLINED in formatting) { - consumer.addQuad(startPosition + Vec2(-horizontalSpacing, charHeight), Vec2(endPosition.x + boldOffset + horizontalSpacing, startPosition.y + charHeight + verticalSpacing / 2.0f), whiteTexture.texture, whiteTexture.uvStart, whiteTexture.uvEnd, italic, color, options) + if (bold) { + // render char another time but offset in x direction + val boldOffset = BOLD_OFFSET * scale + consumer.addChar( + start = startPosition + Vec2(boldOffset, 0.0f), + end = endPosition + Vec2(boldOffset, 0.0f), + texture, uvStart, uvEnd, italic, color, options) } } - - - private fun GUIVertexConsumer.addQuad(start: Vec2, end: Vec2, texture: AbstractTexture, uvStart: Vec2, uvEnd: Vec2, italic: Boolean, tint: RGBColor, options: GUIVertexOptions?) { - val topOffset = if (italic) (end.y - start.y) / FontProperties.CHAR_BASE_HEIGHT * ITALIC_OFFSET else 0.0f - - val positions = arrayOf( - Vec2(start.x + topOffset, start.y), - Vec2(end.x + topOffset, start.y), - end, - Vec2(start.x, end.y), - ) - val texturePositions = arrayOf( - Vec2(uvEnd.x, uvStart.y), - uvStart, - Vec2(uvStart.x, uvEnd.y), - uvEnd, - ) - - for ((vertexIndex, textureIndex) in this.order) { - addVertex(positions[vertexIndex], texture, texturePositions[textureIndex], tint, options) - } - } - } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/component/TextComponentRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/component/TextComponentRenderer.kt index 54ebbbf36..8ea9b9c66 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/component/TextComponentRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/component/TextComponentRenderer.kt @@ -40,8 +40,10 @@ object TextComponentRenderer : ChatComponentRenderer { val color = text.color ?: ChatColors.WHITE val shadow = renderInfo.shadow val bold: Boolean = text.formatting.contains(FormattingCodes.BOLD) + val italic: Boolean = text.formatting.contains(FormattingCodes.ITALIC) // ToDo: Only 1 quad for the underline and the strikethrough + // TODO: strike, underlined var alignmentXOffset = 0.0f var currentLineText = "" @@ -177,7 +179,7 @@ object TextComponentRenderer : ChatComponentRenderer { // ToDo: Remove Font.HORIZONTAL_SPACING } - consumer?.let { charData.render(letterOffset, color, shadow, text.formatting, it, options, renderInfo.scale) } + consumer?.let { charData.render(letterOffset, color, shadow, bold, italic, renderInfo.scale, it, options) } if (consumer == null) { currentLineText += char.toChar() @@ -209,13 +211,16 @@ object TextComponentRenderer : ChatComponentRenderer { val font = context.font[text.font] + + // TODO: strike, underlined + for (char in text.message.codePoints()) { val data = font?.get(char) ?: context.font.default[char] ?: continue val expectedWidth = ((data.calculateWidth(scale, false) + Font.HORIZONTAL_SPACING) * scale).toInt() if (maxSize.x - offset.x < expectedWidth) { // ToDo return } - val width = ((data.render3d(consumer, color, shadow = false, text.formatting, scale = scale) + Font.HORIZONTAL_SPACING) * scale).toInt() + val width = ((data.render3d(color, shadow = false, FormattingCodes.BOLD in text.formatting, FormattingCodes.ITALIC in text.formatting, scale = scale, consumer) + Font.HORIZONTAL_SPACING) * scale).toInt() offset.x += width consumer.offset((width / ChatComponentRenderer.TEXT_BLOCK_RESOLUTION.toFloat())) } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/empty/EmptyCodeRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/empty/EmptyCodeRenderer.kt index e34ae1bc4..2962af7bc 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/empty/EmptyCodeRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/empty/EmptyCodeRenderer.kt @@ -14,7 +14,6 @@ package de.bixilon.minosoft.gui.rendering.font.types.empty import de.bixilon.kotlinglm.vec2.Vec2 -import de.bixilon.minosoft.data.text.formatting.TextFormatting import de.bixilon.minosoft.data.text.formatting.color.RGBColor import de.bixilon.minosoft.gui.rendering.font.renderer.code.CodePointRenderer import de.bixilon.minosoft.gui.rendering.font.renderer.properties.FontProperties.MAX_CHAR_WIDTH @@ -31,5 +30,5 @@ data class EmptyCodeRenderer( } override fun calculateWidth(scale: Float, shadow: Boolean): Float = width * scale - override fun render(position: Vec2, color: RGBColor, shadow: Boolean, formatting: TextFormatting, consumer: GUIVertexConsumer, options: GUIVertexOptions?, scale: Float) = Unit + override fun render(position: Vec2, color: RGBColor, shadow: Boolean, bold: Boolean, italic: Boolean, scale: Float, consumer: GUIVertexConsumer, options: GUIVertexOptions?) = Unit } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/atlas/AtlasElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/atlas/AtlasElement.kt index 08e9337ef..3ce510d0d 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/atlas/AtlasElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/atlas/AtlasElement.kt @@ -25,7 +25,7 @@ class AtlasElement( val end: Vec2i, val slots: Int2ObjectOpenHashMap, val areas: Map, -) : TextureLike { +) : TexturePart { override val size: Vec2i = end - start override lateinit var uvStart: Vec2 override lateinit var uvEnd: Vec2 diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/atlas/TextureLikeTexture.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/atlas/CodeTexturePart.kt similarity index 96% rename from src/main/java/de/bixilon/minosoft/gui/rendering/gui/atlas/TextureLikeTexture.kt rename to src/main/java/de/bixilon/minosoft/gui/rendering/gui/atlas/CodeTexturePart.kt index a29650a28..838e2836a 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/atlas/TextureLikeTexture.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/atlas/CodeTexturePart.kt @@ -17,9 +17,9 @@ import de.bixilon.kotlinglm.vec2.Vec2 import de.bixilon.kotlinglm.vec2.Vec2i import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture -class TextureLikeTexture( +class CodeTexturePart( override val texture: AbstractTexture, override val uvStart: Vec2, override val uvEnd: Vec2, override val size: Vec2i, -) : TextureLike +) : TexturePart diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/atlas/TextureLike.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/atlas/TexturePart.kt similarity index 97% rename from src/main/java/de/bixilon/minosoft/gui/rendering/gui/atlas/TextureLike.kt rename to src/main/java/de/bixilon/minosoft/gui/rendering/gui/atlas/TexturePart.kt index 47c1a0061..b34d23628 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/atlas/TextureLike.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/atlas/TexturePart.kt @@ -17,7 +17,7 @@ import de.bixilon.kotlinglm.vec2.Vec2 import de.bixilon.kotlinglm.vec2.Vec2i import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture -interface TextureLike { +interface TexturePart { val texture: AbstractTexture val uvStart: Vec2 val uvEnd: Vec2 diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/primitive/AtlasImageElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/primitive/AtlasImageElement.kt index c30c965e1..8b9a13c7a 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/primitive/AtlasImageElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/primitive/AtlasImageElement.kt @@ -18,7 +18,7 @@ import de.bixilon.kotlinglm.vec2.Vec2i import de.bixilon.minosoft.data.text.formatting.color.ChatColors import de.bixilon.minosoft.data.text.formatting.color.RGBColor import de.bixilon.minosoft.gui.rendering.gui.GUIRenderer -import de.bixilon.minosoft.gui.rendering.gui.atlas.TextureLike +import de.bixilon.minosoft.gui.rendering.gui.atlas.TexturePart import de.bixilon.minosoft.gui.rendering.gui.elements.Element import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIMesh import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer @@ -28,11 +28,11 @@ import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.EMPTY open class AtlasImageElement( guiRenderer: GUIRenderer, - textureLike: TextureLike?, - size: Vec2i = textureLike?.size ?: Vec2i.EMPTY, + texturePart: TexturePart?, + size: Vec2i = texturePart?.size ?: Vec2i.EMPTY, tint: RGBColor = ChatColors.WHITE, ) : Element(guiRenderer, GUIMesh.GUIMeshStruct.FLOATS_PER_VERTEX * 6) { - var texture: AbstractTexture? = textureLike?.texture + var texture: AbstractTexture? = texturePart?.texture set(value) { field = value cacheUpToDate = false @@ -67,7 +67,7 @@ open class AtlasImageElement( cacheUpToDate = false } - var textureLike: TextureLike? = textureLike + var texturePart: TexturePart? = texturePart set(value) { if (field === value) { return @@ -87,7 +87,7 @@ open class AtlasImageElement( override fun forceRender(offset: Vec2i, consumer: GUIVertexConsumer, options: GUIVertexOptions?) { val texture = texture ?: return - val textureLike = textureLike ?: return + val textureLike = texturePart ?: return consumer.addQuad(offset, offset + size, texture, uvStart ?: textureLike.uvStart, uvEnd ?: textureLike.uvEnd, tint, options) } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/mesh/GUIMesh.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/mesh/GUIMesh.kt index 158b7af2b..c283fc18a 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/mesh/GUIMesh.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/mesh/GUIMesh.kt @@ -27,6 +27,7 @@ class GUIMesh( val halfSize: Vec2, data: AbstractFloatList, ) : Mesh(context, GUIMeshStruct, initialCacheSize = 40000, clearOnLoad = false, data = data), GUIVertexConsumer { + override val whiteTexture = context.textureManager.whiteTexture override fun addVertex(position: Vec2, texture: ShaderIdentifiable, uv: Vec2, tint: RGBColor, options: GUIVertexOptions?) { addVertex(data, halfSize, position, texture, uv, tint, options) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/mesh/GUIMeshCache.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/mesh/GUIMeshCache.kt index 3f89f5a1c..d06468ca2 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/mesh/GUIMeshCache.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/mesh/GUIMeshCache.kt @@ -25,10 +25,12 @@ import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.EMPTY class GUIMeshCache( var halfSize: Vec2, override val order: Array>, - override val context: RenderContext, + val context: RenderContext, initialCacheSize: Int = 1000, var data: AbstractFloatList = HeapArrayFloatList(initialCacheSize), ) : GUIVertexConsumer { + override val whiteTexture = context.textureManager.whiteTexture + var revision: Long = 0 var offset: Vec2i = Vec2i.EMPTY var options: GUIVertexOptions? = null diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/mesh/GUIVertexConsumer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/mesh/GUIVertexConsumer.kt index 159893589..886bd86bc 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/mesh/GUIVertexConsumer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/mesh/GUIVertexConsumer.kt @@ -16,12 +16,15 @@ package de.bixilon.minosoft.gui.rendering.gui.mesh import de.bixilon.kotlinglm.vec2.Vec2 import de.bixilon.kotlinglm.vec2.Vec2i import de.bixilon.minosoft.data.text.formatting.color.RGBColor -import de.bixilon.minosoft.gui.rendering.RenderContext -import de.bixilon.minosoft.gui.rendering.gui.atlas.TextureLike +import de.bixilon.minosoft.gui.rendering.font.renderer.properties.FontProperties +import de.bixilon.minosoft.gui.rendering.font.renderer.properties.FormattingProperties +import de.bixilon.minosoft.gui.rendering.gui.atlas.CodeTexturePart +import de.bixilon.minosoft.gui.rendering.gui.atlas.TexturePart import de.bixilon.minosoft.gui.rendering.system.base.texture.ShaderIdentifiable +import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture interface GUIVertexConsumer { - val context: RenderContext + val whiteTexture: CodeTexturePart val order: Array> fun addVertex(position: Vec2, texture: ShaderIdentifiable, uv: Vec2, tint: RGBColor, options: GUIVertexOptions?) @@ -67,14 +70,36 @@ interface GUIVertexConsumer { } } - fun addQuad(start: Vec2, end: Vec2, texture: TextureLike, tint: RGBColor, options: GUIVertexOptions?) { + fun addQuad(start: Vec2, end: Vec2, texture: TexturePart, tint: RGBColor, options: GUIVertexOptions?) { addQuad(start, end, texture.texture, texture.uvStart, texture.uvEnd, tint, options) } - fun addQuad(start: Vec2i, end: Vec2i, texture: TextureLike, tint: RGBColor, options: GUIVertexOptions?) { + fun addQuad(start: Vec2i, end: Vec2i, texture: TexturePart, tint: RGBColor, options: GUIVertexOptions?) { addQuad(start, end, texture.texture, texture.uvStart, texture.uvEnd, tint, options) } + + fun addChar(start: Vec2, end: Vec2, texture: AbstractTexture, uvStart: Vec2, uvEnd: Vec2, italic: Boolean, tint: RGBColor, options: GUIVertexOptions?) { + val topOffset = if (italic) (end.y - start.y) / FontProperties.CHAR_BASE_HEIGHT * FormattingProperties.ITALIC_OFFSET else 0.0f + + val positions = arrayOf( + Vec2(start.x + topOffset, start.y), + Vec2(end.x + topOffset, start.y), + end, + Vec2(start.x, end.y), + ) + val texturePositions = arrayOf( + Vec2(uvEnd.x, uvStart.y), + uvStart, + Vec2(uvStart.x, uvEnd.y), + uvEnd, + ) + + for ((vertexIndex, textureIndex) in this.order) { + addVertex(positions[vertexIndex], texture, texturePositions[textureIndex], tint, options) + } + } + fun addCache(cache: GUIMeshCache) fun ensureSize(size: Int) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/TextureManager.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/TextureManager.kt index 0499083ea..182a0a226 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/TextureManager.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/base/texture/TextureManager.kt @@ -17,7 +17,7 @@ import de.bixilon.kotlinglm.vec2.Vec2 import de.bixilon.kotlinglm.vec2.Vec2i import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft import de.bixilon.minosoft.gui.rendering.RenderConstants -import de.bixilon.minosoft.gui.rendering.gui.atlas.TextureLikeTexture +import de.bixilon.minosoft.gui.rendering.gui.atlas.CodeTexturePart import de.bixilon.minosoft.gui.rendering.system.base.shader.NativeShader import de.bixilon.minosoft.gui.rendering.system.base.shader.ShaderUniforms import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTextureArray @@ -32,7 +32,7 @@ abstract class TextureManager { lateinit var debugTexture: AbstractTexture private set - lateinit var whiteTexture: TextureLikeTexture + lateinit var whiteTexture: CodeTexturePart private set lateinit var skins: SkinManager private set @@ -42,7 +42,7 @@ abstract class TextureManager { throw IllegalStateException("Already initialized!") } debugTexture = staticTextures.createTexture(RenderConstants.DEBUG_TEXTURE_RESOURCE_LOCATION) - whiteTexture = TextureLikeTexture(texture = staticTextures.createTexture(minosoft("white").texture()), uvStart = Vec2(0.0f, 0.0f), uvEnd = Vec2(0.001f, 0.001f), size = Vec2i(16, 16)) + whiteTexture = CodeTexturePart(texture = staticTextures.createTexture(minosoft("white").texture()), uvStart = Vec2(0.0f, 0.0f), uvEnd = Vec2(0.001f, 0.001f), size = Vec2i(16, 16)) } fun initializeSkins(connection: PlayConnection) {