From d9c74a71d7f4b53278350311b20123ba38302b96 Mon Sep 17 00:00:00 2001 From: Bixilon Date: Mon, 5 Jun 2023 18:39:57 +0200 Subject: [PATCH] refactor font rendering more --- .../minosoft/data/text/BaseComponent.kt | 2 + .../data/text/LegacyComponentReader.kt | 6 +- .../minosoft/data/text/TextComponent.kt | 4 +- .../minosoft/gui/rendering/font/CharData.kt | 110 +-------------- .../gui/rendering/font/WorldGUIConsumer.kt | 2 + .../gui/rendering/font/manager/FontManager.kt | 23 +++- .../code/AscentedCodePointRenderer.kt | 23 ++++ .../font/renderer/code/CodePointRenderer.kt | 10 +- .../code/RasterizedCodePointRenderer.kt | 127 ++++++++++++++++++ .../component/BaseComponentRenderer.kt | 3 +- .../component/ChatComponentRenderer.kt | 5 +- .../component/TextComponentRenderer.kt | 37 +++-- .../font/renderer/element/TextLineInfo.kt | 2 +- .../font/renderer/element/TextRenderInfo.kt | 2 +- .../renderer/properties/FontProperties.kt | 23 ++++ .../FormattingProperties.kt} | 13 +- .../font/types/bitmap/BitmapCodeRenderer.kt | 18 ++- .../font/types/empty/EmptyCodeRenderer.kt | 4 +- .../font/types/empty/EmptyFontType.kt | 2 +- .../legacy/LegacyUnicodeCodeRenderer.kt | 12 +- .../unicode/legacy/LegacyUnicodeFontType.kt | 8 +- .../gui/rendering/gui/elements/Element.kt | 2 +- .../gui/elements/HorizontalAlignments.kt | 13 ++ .../gui/elements/text/TextElement.kt | 18 +-- .../gui/elements/text/mark/MarkTextElement.kt | 2 +- .../gui/elements/input/TextInputElement.kt | 4 +- .../gui/rendering/gui/mesh/GUIMeshCache.kt | 2 + .../rendering/gui/mesh/GUIVertexConsumer.kt | 2 + 28 files changed, 298 insertions(+), 181 deletions(-) create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/code/AscentedCodePointRenderer.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/code/RasterizedCodePointRenderer.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/properties/FontProperties.kt rename src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/{FontProperties.kt => properties/FormattingProperties.kt} (73%) diff --git a/src/main/java/de/bixilon/minosoft/data/text/BaseComponent.kt b/src/main/java/de/bixilon/minosoft/data/text/BaseComponent.kt index 33b46523b..1c4521d7a 100644 --- a/src/main/java/de/bixilon/minosoft/data/text/BaseComponent.kt +++ b/src/main/java/de/bixilon/minosoft/data/text/BaseComponent.kt @@ -57,6 +57,7 @@ class BaseComponent : ChatComponent { json["strikethrough"]?.toBoolean()?.let { formatting[FormattingCodes.STRIKETHROUGH] = it } json["obfuscated"]?.toBoolean()?.let { formatting[FormattingCodes.OBFUSCATED] = it } + val font = json["font"]?.toResourceLocation() ?: parent?.font val clickEvent = json["clickEvent", "click_event"]?.toJsonObject()?.let { click -> ClickEvents.build(click, restricted) } ?: parent?.clickEvent val hoverEvent = json["hoverEvent", "hover_event"]?.toJsonObject()?.let { hover -> HoverEvents.build(hover, restricted) } ?: parent?.hoverEvent @@ -66,6 +67,7 @@ class BaseComponent : ChatComponent { message = text, color = color, formatting = formatting, + font = font, clickEvent = clickEvent, hoverEvent = hoverEvent, ) diff --git a/src/main/java/de/bixilon/minosoft/data/text/LegacyComponentReader.kt b/src/main/java/de/bixilon/minosoft/data/text/LegacyComponentReader.kt index d5eb5dea1..496be3b4a 100644 --- a/src/main/java/de/bixilon/minosoft/data/text/LegacyComponentReader.kt +++ b/src/main/java/de/bixilon/minosoft/data/text/LegacyComponentReader.kt @@ -50,15 +50,15 @@ object LegacyComponentReader { } if (text.isNotEmpty()) { // an url follows, push the previous part - this += TextComponent(text, sequence.color, sequence.formatting.copy(), parent?.clickEvent, parent?.hoverEvent) + this += TextComponent(text, sequence.color, sequence.formatting.copy(), null, parent?.clickEvent, parent?.hoverEvent) text.clear() } - this += TextComponent(part, sequence.color, sequence.formatting.copy(), parent?.clickEvent ?: event, parent?.hoverEvent) + this += TextComponent(part, sequence.color, sequence.formatting.copy(), null, parent?.clickEvent ?: event, parent?.hoverEvent) } if (text.isNotEmpty()) { // data that was not pushed yet - this += TextComponent(text, sequence.color, sequence.formatting.copy(), parent?.clickEvent, parent?.hoverEvent) + this += TextComponent(text, sequence.color, sequence.formatting.copy(), null, parent?.clickEvent, parent?.hoverEvent) } sequence.reset() // clear it up again for next usage diff --git a/src/main/java/de/bixilon/minosoft/data/text/TextComponent.kt b/src/main/java/de/bixilon/minosoft/data/text/TextComponent.kt index 2f056fc30..b049e9a1e 100644 --- a/src/main/java/de/bixilon/minosoft/data/text/TextComponent.kt +++ b/src/main/java/de/bixilon/minosoft/data/text/TextComponent.kt @@ -14,6 +14,7 @@ package de.bixilon.minosoft.data.text import de.bixilon.kutil.json.MutableJsonObject import de.bixilon.minosoft.config.profile.profiles.eros.ErosProfileManager +import de.bixilon.minosoft.data.registries.identified.ResourceLocation import de.bixilon.minosoft.data.text.events.click.ClickEvent import de.bixilon.minosoft.data.text.events.hover.HoverEvent import de.bixilon.minosoft.data.text.formatting.FormattingCodes @@ -37,6 +38,7 @@ open class TextComponent( message: Any? = "", override var color: RGBColor? = null, override val formatting: TextFormatting = TextFormatting(), + var font: ResourceLocation? = null, var clickEvent: ClickEvent? = null, var hoverEvent: HoverEvent? = null, ) : ChatComponent, TextStyle { @@ -224,7 +226,7 @@ open class TextComponent( } override fun copy(): ChatComponent { - return TextComponent(message, color, formatting.copy(), clickEvent, hoverEvent) + return TextComponent(message, color, formatting.copy(), font, clickEvent, hoverEvent) } override fun hashCode(): Int { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/font/CharData.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/CharData.kt index 2ee979e97..fc40cf621 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/font/CharData.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/CharData.kt @@ -14,13 +14,7 @@ package de.bixilon.minosoft.gui.rendering.font import de.bixilon.kotlinglm.vec2.Vec2 -import de.bixilon.kotlinglm.vec2.Vec2i -import de.bixilon.kutil.math.simple.FloatMath.ceil -import de.bixilon.minosoft.data.text.formatting.color.RGBColor import de.bixilon.minosoft.gui.rendering.RenderContext -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 @Deprecated("renderer") @@ -31,106 +25,4 @@ class CharData( val scaledWidth: Int, var uvStart: Vec2, var uvEnd: Vec2, -) { - - fun postInit() { - if (texture == null) { - return - } - uvStart = uvStart * texture.textureArrayUV - uvEnd = uvEnd * texture.textureArrayUV - } - - fun render(position: Vec2i, color: RGBColor, shadow: Boolean, italic: Boolean, bold: Boolean, strikethrough: Boolean, underlined: Boolean, consumer: GUIVertexConsumer, options: GUIVertexOptions?, scale: Float) { - if (shadow) { - _render(position, color, true, italic, bold, strikethrough, underlined, consumer, options, scale) - } - _render(position, color, false, italic, bold, strikethrough, underlined, consumer, options, scale) - } - - private fun GUIVertexConsumer.addQuad(start: Vec2, end: Vec2, texture: AbstractTexture, uvStart: Vec2, uvEnd: Vec2, italic: Boolean, tint: RGBColor, options: GUIVertexOptions?) { - val italicOffset = if (italic) (end.y - start.y) / Font.CHAR_HEIGHT.toFloat() * ITALIC_OFFSET else 0.0f - - val positions = arrayOf( - Vec2(start.x + italicOffset, start.y), - Vec2(end.x + italicOffset, 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) - } - } - - private fun _render(position: Vec2i, color: RGBColor, shadow: Boolean, italic: Boolean, bold: Boolean, strikethrough: Boolean, underlined: Boolean, vertexConsumer: GUIVertexConsumer, options: GUIVertexOptions?, scale: Float) { - if (texture == null) { - return - } - var color = color - - var shadowOffset = 0.0f - if (shadow) { - shadowOffset = SHADOW_OFFSET - color *= 0.25f - } - - var boldOffset = 0.0f - - if (bold) { - boldOffset = BOLD_OFFSET * scale - } - val charHeight = Font.CHAR_HEIGHT * scale - val horizontalSpacing = Font.HORIZONTAL_SPACING * scale - val verticalSpacing = Font.VERTICAL_SPACING * scale - - - val startPosition = Vec2(position) + (shadowOffset * scale) - val endPosition = startPosition + (Vec2(scaledWidth * scale, charHeight)) - - - - vertexConsumer.addQuad(startPosition, endPosition, texture, uvStart, uvEnd, italic, color, options) - - if (bold) { - vertexConsumer.addQuad(startPosition + Vec2(boldOffset, 0.0f), endPosition + Vec2(boldOffset, 0.0f), texture, uvStart, uvEnd, italic, color, options) - } - val whiteTexture = context.textureManager.whiteTexture - - if (strikethrough) { - vertexConsumer.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 (underlined) { - vertexConsumer.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) - } - - // ToDo: Obfuscated - } - - fun calculateWidth(scale: Float, shadow: Boolean): Int { - var width = scaledWidth.toFloat() - if (shadow) { - width += SHADOW_OFFSET - } - - return (width * scale).ceil - } - - fun render3d(consumer: WorldGUIConsumer, color: RGBColor, shadow: Boolean, italic: Boolean, bold: Boolean, strikethrough: Boolean, underlined: Boolean, scale: Float): Float { - render(Vec2i(0, 0), color, shadow, italic, bold, strikethrough, underlined, consumer, null, scale) - return scaledWidth.toFloat() - } - - companion object { - const val ITALIC_OFFSET = 2.5f - const val SHADOW_OFFSET = 1.0f - const val BOLD_OFFSET = 0.5f - } -} +) 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 2b9e60cbc..f79b4e720 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,6 +16,7 @@ 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 @@ -26,6 +27,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 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/manager/FontManager.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/manager/FontManager.kt index 23fcf9334..d7e2caa92 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/font/manager/FontManager.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/manager/FontManager.kt @@ -16,18 +16,31 @@ package de.bixilon.minosoft.gui.rendering.font.manager import de.bixilon.kutil.latch.AbstractLatch import de.bixilon.minosoft.data.registries.identified.ResourceLocation import de.bixilon.minosoft.gui.rendering.RenderContext +import de.bixilon.minosoft.gui.rendering.font.loader.DefaultFontIndices +import de.bixilon.minosoft.gui.rendering.font.loader.FontLoader import de.bixilon.minosoft.gui.rendering.font.types.FontType +import de.bixilon.minosoft.gui.rendering.font.types.PostInitFontType +import de.bixilon.minosoft.gui.rendering.font.types.font.EmptyFont import de.bixilon.minosoft.gui.rendering.font.types.font.Font -class FontManager { - val default: FontType +class FontManager( + val default: FontType, +) { - fun postInit(latch: AbstractLatch) + fun postInit(latch: AbstractLatch) { + if (default is PostInitFontType) { + default.postInit(latch) + } + } - operator fun get(font: ResourceLocation): Font? + operator fun get(font: ResourceLocation?): Font? = null companion object { - fun create(context: RenderContext, latch: AbstractLatch): FontManager {} + fun create(context: RenderContext, latch: AbstractLatch): FontManager { + val font = FontLoader.load(context, DefaultFontIndices.DEFAULT, latch) + + return FontManager(font ?: EmptyFont) + } } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/code/AscentedCodePointRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/code/AscentedCodePointRenderer.kt new file mode 100644 index 000000000..1394af52b --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/code/AscentedCodePointRenderer.kt @@ -0,0 +1,23 @@ +/* + * 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 + +/** + * Font that is shifted vertically + * See the great explanation of @Suragch at https://stackoverflow.com/questions/27631736/meaning-of-top-ascent-baseline-descent-bottom-and-leading-in-androids-font + */ +interface AscentedCodePointRenderer : CodePointRenderer { + val descent: Float + val ascent: Float +} 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 6eb9a122e..631b53c48 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 @@ -16,12 +16,20 @@ 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 import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions +import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2Util.EMPTY interface CodePointRenderer { fun calculateWidth(scale: Float, shadow: Boolean): Float - fun render(position: Vec2, color: RGBColor, formatting: TextFormatting, consumer: GUIVertexConsumer, options: GUIVertexOptions?, scale: Float) + fun render(position: Vec2, color: RGBColor, shadow: Boolean, formatting: TextFormatting, consumer: GUIVertexConsumer, options: GUIVertexOptions?, scale: Float) + + fun render3d(consumer: WorldGUIConsumer, color: RGBColor, shadow: Boolean, formatting: TextFormatting, scale: Float): Float { + render(Vec2.EMPTY, color, shadow, formatting, consumer, null, scale) + + 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 new file mode 100644 index 000000000..059fe4888 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/code/RasterizedCodePointRenderer.kt @@ -0,0 +1,127 @@ +/* + * 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.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 + +interface RasterizedCodePointRenderer : CodePointRenderer { + val texture: AbstractTexture + + val uvStart: Vec2 + val uvEnd: Vec2 + + val width: Float + + + override fun calculateWidth(scale: Float, shadow: Boolean): Float { + var width = width + if (shadow) { + width += SHADOW_OFFSET + } + + return width * scale + } + + override fun render(position: Vec2, color: RGBColor, shadow: Boolean, formatting: TextFormatting, consumer: GUIVertexConsumer, options: GUIVertexOptions?, scale: Float) { + if (shadow) { + render(position + (SHADOW_OFFSET * scale), color * SHADOW_COLOR, formatting, consumer, options, scale) + } + render(position, color, formatting, consumer, options, scale) + } + + fun calculateStart(base: Vec2, scale: Float): Vec2 { + val position = Vec2(base) + position.y += (FontProperties.CHAR_SPACING_TOP * scale) + + return position + } + + fun calculateEnd(start: Vec2, scale: Float): Vec2 { + val position = Vec2(start) + position.y += (FontProperties.CHAR_BASE_HEIGHT * scale) + position.x += width * scale + + 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 + + + val startPosition = calculateStart(position, scale) + val endPosition = calculateEnd(startPosition, scale) + + + + 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) + } + } + + + 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/BaseComponentRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/component/BaseComponentRenderer.kt index 5f95d1b0f..28a69717b 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/component/BaseComponentRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/component/BaseComponentRenderer.kt @@ -13,6 +13,7 @@ package de.bixilon.minosoft.gui.rendering.font.renderer.component +import de.bixilon.kotlinglm.vec2.Vec2 import de.bixilon.kotlinglm.vec2.Vec2i import de.bixilon.minosoft.data.text.BaseComponent import de.bixilon.minosoft.gui.rendering.RenderContext @@ -24,7 +25,7 @@ import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions object BaseComponentRenderer : ChatComponentRenderer { - override fun render(initialOffset: Vec2i, offset: Vec2i, size: Vec2i, element: Element, context: RenderContext, consumer: GUIVertexConsumer?, options: GUIVertexOptions?, renderInfo: TextRenderInfo, text: BaseComponent): Boolean { + override fun render(initialOffset: Vec2, offset: Vec2, size: Vec2, element: Element, context: RenderContext, consumer: GUIVertexConsumer?, options: GUIVertexOptions?, renderInfo: TextRenderInfo, text: BaseComponent): Boolean { for (part in text.parts) { if (ChatComponentRenderer.render(initialOffset, offset, size, element, context, consumer, options, renderInfo, part)) { return true diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/component/ChatComponentRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/component/ChatComponentRenderer.kt index 51072e4d2..ae1e470fa 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/component/ChatComponentRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/component/ChatComponentRenderer.kt @@ -14,6 +14,7 @@ package de.bixilon.minosoft.gui.rendering.font.renderer.component import de.bixilon.kotlinglm.mat4x4.Mat4 +import de.bixilon.kotlinglm.vec2.Vec2 import de.bixilon.kotlinglm.vec2.Vec2i import de.bixilon.kotlinglm.vec3.Vec3 import de.bixilon.minosoft.data.text.BaseComponent @@ -35,7 +36,7 @@ interface ChatComponentRenderer { /** * Returns true if the text exceeded the maximum size */ - fun render(initialOffset: Vec2i, offset: Vec2i, size: Vec2i, element: Element, context: RenderContext, consumer: GUIVertexConsumer?, options: GUIVertexOptions?, renderInfo: TextRenderInfo, text: T): Boolean + fun render(initialOffset: Vec2, offset: Vec2, size: Vec2, element: Element, context: RenderContext, consumer: GUIVertexConsumer?, options: GUIVertexOptions?, renderInfo: TextRenderInfo, text: T): Boolean fun render3dFlat(context: RenderContext, offset: Vec2i, scale: Float, maxSize: Vec2i, consumer: WorldGUIConsumer, text: T, light: Int) @@ -44,7 +45,7 @@ interface ChatComponentRenderer { companion object : ChatComponentRenderer { const val TEXT_BLOCK_RESOLUTION = 128 - override fun render(initialOffset: Vec2i, offset: Vec2i, size: Vec2i, element: Element, context: RenderContext, consumer: GUIVertexConsumer?, options: GUIVertexOptions?, renderInfo: TextRenderInfo, text: ChatComponent): Boolean { + override fun render(initialOffset: Vec2, offset: Vec2, size: Vec2, element: Element, context: RenderContext, consumer: GUIVertexConsumer?, options: GUIVertexOptions?, renderInfo: TextRenderInfo, text: ChatComponent): Boolean { return when (text) { is BaseComponent -> BaseComponentRenderer.render(initialOffset, offset, size, element, context, consumer, options, renderInfo, text) is TextComponent -> TextComponentRenderer.render(initialOffset, offset, size, element, context, consumer, options, renderInfo, text) 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 6157c81ea..54ebbbf36 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 @@ -13,6 +13,7 @@ package de.bixilon.minosoft.gui.rendering.font.renderer.component +import de.bixilon.kotlinglm.vec2.Vec2 import de.bixilon.kotlinglm.vec2.Vec2i import de.bixilon.minosoft.data.text.TextComponent import de.bixilon.minosoft.data.text.formatting.FormattingCodes @@ -29,22 +30,20 @@ import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions object TextComponentRenderer : ChatComponentRenderer { - override fun render(initialOffset: Vec2i, offset: Vec2i, size: Vec2i, element: Element, context: RenderContext, consumer: GUIVertexConsumer?, options: GUIVertexOptions?, renderInfo: TextRenderInfo, text: TextComponent): Boolean { + override fun render(initialOffset: Vec2, offset: Vec2, size: Vec2, element: Element, context: RenderContext, consumer: GUIVertexConsumer?, options: GUIVertexOptions?, renderInfo: TextRenderInfo, text: TextComponent): Boolean { if (text.message.isEmpty()) { return false } + val font = context.font[text.font] val elementMaxSize = element.maxSize val elementSize = element.size val color = text.color ?: ChatColors.WHITE val shadow = renderInfo.shadow - val italic: Boolean = text.formatting.contains(FormattingCodes.ITALIC) val bold: Boolean = text.formatting.contains(FormattingCodes.BOLD) - val strikethrough: Boolean = text.formatting.contains(FormattingCodes.STRIKETHROUGH) - val underlined: Boolean = text.formatting.contains(FormattingCodes.UNDERLINED) // ToDo: Only 1 quad for the underline and the strikethrough - var alignmentXOffset = 0 + var alignmentXOffset = 0.0f var currentLineText = "" if (size.x > elementMaxSize.x || size.y > elementMaxSize.y) { // The size is already bigger/equals the maximum size @@ -65,15 +64,15 @@ object TextComponentRenderer : ChatComponentRenderer { fun applyOffset() { val lastLine = renderInfo.lines.getOrNull(renderInfo.lineIndex) - if (consumer == null && offset.x == initialOffset.x + renderInfo.charMargin && (lastLine == null || lastLine.width != 0)) { + if (consumer == null && offset.x == initialOffset.x + renderInfo.charMargin && (lastLine == null || lastLine.width != 0.0f)) { // preparing phase renderInfo.lines += TextLineInfo() } else { - alignmentXOffset = renderInfo.fontAlignment.getOffset(elementSize.x, renderInfo.currentLine.width) + alignmentXOffset = renderInfo.fontAlignment.getOffset(elementSize.x.toFloat(), renderInfo.currentLine.width) } } - fun addY(height: Int): Boolean { + fun addY(height: Float): Boolean { val nextY = offset.y + height val nextSizeY = nextY - initialOffset.y + renderInfo.charHeight // add initial height for chars + end margin if (nextSizeY > elementMaxSize.y) { @@ -97,7 +96,7 @@ object TextComponentRenderer : ChatComponentRenderer { return false } - fun addX(width: Int, wrap: Boolean = true): Boolean { + fun addX(width: Float, wrap: Boolean = true): Boolean { val nextX = offset.x + width val nextSizeX = nextX - initialOffset.x - renderInfo.charMargin // end margin if (nextSizeX > elementMaxSize.x) { @@ -121,7 +120,7 @@ object TextComponentRenderer : ChatComponentRenderer { } - if (size.y == 0) { + if (size.y == 0.0f) { // Add initial height of the letter for the first line val nextSizeY = renderInfo.charHeight if (nextSizeY > elementMaxSize.y) { @@ -147,7 +146,7 @@ object TextComponentRenderer : ChatComponentRenderer { continue } - val charData = context.font[char] ?: continue + val charData = font?.get(char) ?: context.font.default[char] ?: continue val charWidth = charData.calculateWidth(renderInfo.scale, renderInfo.shadow) var width = charWidth @@ -168,7 +167,7 @@ object TextComponentRenderer : ChatComponentRenderer { return true } - val letterOffset = Vec2i(offset.x + alignmentXOffset, offset.y) + val letterOffset = Vec2(offset.x + alignmentXOffset, offset.y) // remove width from the offset again letterOffset.x -= charWidth @@ -178,7 +177,7 @@ object TextComponentRenderer : ChatComponentRenderer { // ToDo: Remove Font.HORIZONTAL_SPACING } - consumer?.let { charData.render(letterOffset, color, shadow, italic, bold, strikethrough, underlined, it, options, renderInfo.scale) } + consumer?.let { charData.render(letterOffset, color, shadow, text.formatting, it, options, renderInfo.scale) } if (consumer == null) { currentLineText += char.toChar() @@ -207,18 +206,16 @@ object TextComponentRenderer : ChatComponentRenderer { override fun render3dFlat(context: RenderContext, offset: Vec2i, scale: Float, maxSize: Vec2i, consumer: WorldGUIConsumer, text: TextComponent, light: Int) { val color = text.color ?: ChatColors.BLACK - val italic = text.formatting.contains(FormattingCodes.ITALIC) - val bold = text.formatting.contains(FormattingCodes.BOLD) - val strikethrough = text.formatting.contains(FormattingCodes.STRIKETHROUGH) - val underlined = text.formatting.contains(FormattingCodes.UNDERLINED) + + val font = context.font[text.font] for (char in text.message.codePoints()) { - val data = context.font[char] ?: continue - val expectedWidth = ((data.width + Font.HORIZONTAL_SPACING) * scale).toInt() + 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, italic = italic, bold = bold, strikethrough = strikethrough, underlined = underlined, scale = scale) + Font.HORIZONTAL_SPACING) * scale).toInt() + val width = ((data.render3d(consumer, color, shadow = false, text.formatting, scale = scale) + 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/renderer/element/TextLineInfo.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/element/TextLineInfo.kt index 05eedecdc..2d7a0acca 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/element/TextLineInfo.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/element/TextLineInfo.kt @@ -17,5 +17,5 @@ import de.bixilon.minosoft.data.text.BaseComponent data class TextLineInfo( val text: BaseComponent = BaseComponent(), - var width: Int = 0, + var width: Float = 0.0f, ) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/element/TextRenderInfo.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/element/TextRenderInfo.kt index cd55a56d1..c9c151816 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/element/TextRenderInfo.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/element/TextRenderInfo.kt @@ -21,7 +21,7 @@ import de.bixilon.minosoft.util.logging.LogMessageType class TextRenderInfo( val fontAlignment: HorizontalAlignments, - val charHeight: Int, + val charHeight: Float, val charMargin: Int, val scale: Float, val shadow: Boolean, diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/properties/FontProperties.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/properties/FontProperties.kt new file mode 100644 index 000000000..381e752a6 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/properties/FontProperties.kt @@ -0,0 +1,23 @@ +/* + * 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.properties + +object FontProperties { + const val MAX_CHAR_WIDTH = 16 // maximum width that a char can have + const val CHAR_BASE_HEIGHT = 8 // base height of every char, it is allowed to take up the spacing if needed + const val CHAR_SPACING_TOP = 1 + const val CHAR_SPACING_BOTTOM = 2 // larger to not break underlined text + + const val LINE_HEIGHT = CHAR_SPACING_TOP + CHAR_BASE_HEIGHT + CHAR_SPACING_BOTTOM +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/FontProperties.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/properties/FormattingProperties.kt similarity index 73% rename from src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/FontProperties.kt rename to src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/properties/FormattingProperties.kt index 2916b3f4b..2e0252041 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/FontProperties.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/properties/FormattingProperties.kt @@ -11,10 +11,13 @@ * This software is not affiliated with Mojang AB, the original developer of Minecraft. */ -package de.bixilon.minosoft.gui.rendering.font.renderer +package de.bixilon.minosoft.gui.rendering.font.renderer.properties -object FontProperties { - const val MAX_CHAR_WIDTH = 16 // maximum width that a char can have - const val CHAR_HEIGHT = 12 // height every char has - const val CHAR_SPACING = 1 // spacing every char has around itself +object FormattingProperties { + const val ITALIC_OFFSET = 2.5f + const val SHADOW_OFFSET = 1.0f + const val BOLD_OFFSET = 0.5f + + + const val SHADOW_COLOR = 0.25f } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/bitmap/BitmapCodeRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/bitmap/BitmapCodeRenderer.kt index 37e7d7eed..f1438e322 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/bitmap/BitmapCodeRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/bitmap/BitmapCodeRenderer.kt @@ -14,16 +14,20 @@ package de.bixilon.minosoft.gui.rendering.font.types.bitmap import de.bixilon.kotlinglm.vec2.Vec2 -import de.bixilon.minosoft.gui.rendering.font.renderer.code.CodePointRenderer +import de.bixilon.minosoft.gui.rendering.font.renderer.code.AscentedCodePointRenderer +import de.bixilon.minosoft.gui.rendering.font.renderer.code.RasterizedCodePointRenderer import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture class BitmapCodeRenderer( - val texture: AbstractTexture, - var uvStart: Vec2, - var uvEnd: Vec2, - val width: Float, -) : CodePointRenderer { - + override val texture: AbstractTexture, + override var uvStart: Vec2, + override var uvEnd: Vec2, + override val width: Float, +) : RasterizedCodePointRenderer, AscentedCodePointRenderer { + override val ascent: Float + get() = 1.0f + override val descent: Float + get() = 1.0f fun updateArray() { uvStart = uvStart * texture.textureArrayUV 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 191e0c30c..7300997d0 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 @@ -16,8 +16,8 @@ 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.FontProperties.MAX_CHAR_WIDTH import de.bixilon.minosoft.gui.rendering.font.renderer.code.CodePointRenderer +import de.bixilon.minosoft.gui.rendering.font.renderer.properties.FontProperties.MAX_CHAR_WIDTH import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions @@ -31,5 +31,5 @@ class EmptyCodeRenderer( } override fun calculateWidth(scale: Float, shadow: Boolean): Float = width * scale - override fun render(position: Vec2, color: RGBColor, formatting: TextFormatting, consumer: GUIVertexConsumer, options: GUIVertexOptions?, scale: Float) = Unit + override fun render(position: Vec2, color: RGBColor, shadow: Boolean, formatting: TextFormatting, consumer: GUIVertexConsumer, options: GUIVertexOptions?, scale: Float) = Unit } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/empty/EmptyFontType.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/empty/EmptyFontType.kt index a215b96c1..28422f862 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/empty/EmptyFontType.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/empty/EmptyFontType.kt @@ -57,7 +57,7 @@ class EmptyFontType( fun load(data: JsonObject): Int2ObjectOpenHashMap? { val advances = data["advances"]?.toJsonObject() ?: return null - val spaces = Int2ObjectOpenHashMap(advances.size, 0.0f) + val spaces = Int2ObjectOpenHashMap(advances.size, 0.01f) for ((char, spacing) in advances) { val codePoint = char.codePointAt(0) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/unicode/legacy/LegacyUnicodeCodeRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/unicode/legacy/LegacyUnicodeCodeRenderer.kt index 18083f8bf..6f5774b21 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/unicode/legacy/LegacyUnicodeCodeRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/unicode/legacy/LegacyUnicodeCodeRenderer.kt @@ -14,15 +14,15 @@ package de.bixilon.minosoft.gui.rendering.font.types.unicode.legacy import de.bixilon.kotlinglm.vec2.Vec2 -import de.bixilon.minosoft.gui.rendering.font.renderer.code.CodePointRenderer +import de.bixilon.minosoft.gui.rendering.font.renderer.code.RasterizedCodePointRenderer import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture class LegacyUnicodeCodeRenderer( - val texture: AbstractTexture, - var uvStart: Vec2, - var uvEnd: Vec2, - val width: Float, -) : CodePointRenderer { + override val texture: AbstractTexture, + override var uvStart: Vec2, + override var uvEnd: Vec2, + override val width: Float, +) : RasterizedCodePointRenderer { fun updateArray() { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/unicode/legacy/LegacyUnicodeFontType.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/unicode/legacy/LegacyUnicodeFontType.kt index ed741fc9d..54444f34c 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/unicode/legacy/LegacyUnicodeFontType.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/types/unicode/legacy/LegacyUnicodeFontType.kt @@ -21,8 +21,8 @@ import de.bixilon.minosoft.assets.AssetsManager import de.bixilon.minosoft.data.registries.identified.Namespaces.minecraft import de.bixilon.minosoft.data.registries.identified.ResourceLocation import de.bixilon.minosoft.gui.rendering.RenderContext -import de.bixilon.minosoft.gui.rendering.font.renderer.FontProperties -import de.bixilon.minosoft.gui.rendering.font.types.FontType +import de.bixilon.minosoft.gui.rendering.font.renderer.properties.FontProperties +import de.bixilon.minosoft.gui.rendering.font.types.PostInitFontType import de.bixilon.minosoft.gui.rendering.font.types.factory.FontTypeFactory import de.bixilon.minosoft.gui.rendering.system.base.texture.StaticTextureArray import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture @@ -32,7 +32,7 @@ import java.io.InputStream class LegacyUnicodeFontType( val chars: Array, -) : FontType { +) : PostInitFontType { override fun postInit(latch: AbstractLatch) { for (char in chars) { @@ -51,7 +51,7 @@ class LegacyUnicodeFontType( private const val CHAR_ROW = 0x0F private const val CHAR_SIZE = 0x0F private const val PIXEL = 1.0f / (CHAR_SIZE * CHAR_ROW) - private const val WIDTH_SCALE = FontProperties.CHAR_HEIGHT / CHAR_SIZE.toFloat() + private const val WIDTH_SCALE = FontProperties.CHAR_BASE_HEIGHT / CHAR_SIZE.toFloat() override fun build(context: RenderContext, data: Map): LegacyUnicodeFontType? { val assets = context.connection.assetsManager diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/Element.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/Element.kt index 35bb7daf5..50dec9dee 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/Element.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/Element.kt @@ -67,7 +67,7 @@ abstract class Element(val guiRenderer: GUIRenderer, initialCacheSize: Int = 100 } @Deprecated("Warning: Should not be directly accessed!") - open val cache = GUIMeshCache(guiRenderer.halfSize, context.renderSystem.primitiveMeshOrder, initialCacheSize) + open val cache = GUIMeshCache(guiRenderer.halfSize, context.renderSystem.primitiveMeshOrder, context, initialCacheSize) private var previousMaxSize = Vec2i.EMPTY diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/HorizontalAlignments.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/HorizontalAlignments.kt index f6797319e..c019bbbcd 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/HorizontalAlignments.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/HorizontalAlignments.kt @@ -13,6 +13,7 @@ package de.bixilon.minosoft.gui.rendering.gui.elements +import de.bixilon.kotlinglm.vec2.Vec2 import de.bixilon.kotlinglm.vec2.Vec2i enum class HorizontalAlignments { @@ -22,6 +23,14 @@ enum class HorizontalAlignments { ; companion object { + fun HorizontalAlignments.getOffset(width: Float, childWidth: Float): Float { + return when (this) { + LEFT -> 0.0f + RIGHT -> width - childWidth + CENTER -> (width - childWidth) / 2 + } + } + fun HorizontalAlignments.getOffset(width: Int, childWidth: Int): Int { return when (this) { LEFT -> 0 @@ -33,5 +42,9 @@ enum class HorizontalAlignments { fun HorizontalAlignments.getOffset(size: Vec2i, childSize: Vec2i): Vec2i { return Vec2i(getOffset(size.x, childSize.x), 0) } + + fun HorizontalAlignments.getOffset(size: Vec2, childSize: Vec2): Vec2 { + return Vec2(getOffset(size.x, childSize.x), 0) + } } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/text/TextElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/text/TextElement.kt index 076804386..5b6fbe473 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/text/TextElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/text/TextElement.kt @@ -13,6 +13,7 @@ package de.bixilon.minosoft.gui.rendering.gui.elements.text +import de.bixilon.kotlinglm.vec2.Vec2 import de.bixilon.kotlinglm.vec2.Vec2i import de.bixilon.kutil.cast.CastUtil.unsafeNull import de.bixilon.kutil.primitive.BooleanUtil.decide @@ -36,6 +37,7 @@ import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIMesh 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.window.CursorShapes +import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2Util.EMPTY import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.EMPTY import de.bixilon.minosoft.gui.rendering.util.vec.vec4.Vec4iUtil.offset import de.bixilon.minosoft.util.KUtil.charCount @@ -118,12 +120,12 @@ open class TextElement( if (!emptyMessage) { val renderInfo = TextRenderInfo( fontAlignment = fontAlignment, - charHeight = charHeight, + charHeight = charHeight.toFloat(), charMargin = charMargin, scale = scale, shadow = shadow, ) - ChatComponentRenderer.render(Vec2i.EMPTY, Vec2i.EMPTY, prefSize, InfiniteSizeElement(guiRenderer), context, null, null, renderInfo, value) + ChatComponentRenderer.render(Vec2.EMPTY, Vec2.EMPTY, Vec2(prefSize), InfiniteSizeElement(guiRenderer), context, null, null, renderInfo, value) } _prefSize = prefSize } @@ -151,13 +153,13 @@ open class TextElement( val size = Vec2i.EMPTY val renderInfo = TextRenderInfo( fontAlignment = fontAlignment, - charHeight = charHeight, + charHeight = charHeight.toFloat(), charMargin = charMargin, scale = scale, shadow = shadow, ) if (!emptyMessage) { - ChatComponentRenderer.render(Vec2i.EMPTY, Vec2i.EMPTY, size, this, context, null, null, renderInfo, chatComponent) + ChatComponentRenderer.render(Vec2.EMPTY, Vec2.EMPTY, Vec2(size), this, context, null, null, renderInfo, chatComponent) renderInfo.lineIndex = 0 } if (renderInfo.lines.size > 1 && size.y > Font.CHAR_HEIGHT) { @@ -180,7 +182,7 @@ open class TextElement( if (background) { for ((line, info) in renderInfo.lines.withIndex()) { - val start = initialOffset + Vec2i(fontAlignment.getOffset(size.x, info.width), line * charHeight) + val start = initialOffset + Vec2i(fontAlignment.getOffset(size.x.toFloat(), info.width), line * charHeight) consumer.addQuad(start, start + Vec2i(info.width + charMargin, charHeight), context.textureManager.whiteTexture, backgroundColor, options) } } @@ -190,7 +192,7 @@ open class TextElement( vertices *= 2 } consumer.ensureSize(vertices) - ChatComponentRenderer.render(initialOffset, Vec2i(initialOffset), Vec2i.EMPTY, this, context, consumer, options, renderInfo, chatComponent) + ChatComponentRenderer.render(Vec2(initialOffset), Vec2(initialOffset), Vec2.EMPTY, this, context, consumer, options, renderInfo, chatComponent) renderInfo.lineIndex = 0 } @@ -262,10 +264,10 @@ open class TextElement( charToCheck++ } val text = line.text.getTextAt(charToCheck) - offset.x -= line0.width // ToDo: Not 100% correct + offset.x -= line0.width.toInt() // ToDo: Not 100% correct - offset.x += fontAlignment.getOffset(size.x, line.width) + offset.x += fontAlignment.getOffset(size.x, line.width.toInt()) return Pair(text, offset) } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/text/mark/MarkTextElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/text/mark/MarkTextElement.kt index c910c90f5..7719e3ccf 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/text/mark/MarkTextElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/text/mark/MarkTextElement.kt @@ -83,7 +83,7 @@ class MarkTextElement( val preMark = TextElement(guiRenderer, message.substring(0, markStartPosition), scale = scale, parent = _parent) val mark = TextElement(guiRenderer, message.substring(markStartPosition, markEndPosition), scale = scale, parent = _parent) val markOffset = Vec2i(preMark.renderInfo.lines.lastOrNull()?.width ?: 0, preMark.size.y) - if (markOffset.y > 0 && (preMark.renderInfo.lines.lastOrNull()?.width ?: 0) <= (renderInfo.lines.lastOrNull()?.width ?: 0)) { + if (markOffset.y > 0 && (preMark.renderInfo.lines.lastOrNull()?.width ?: 0.0f) <= (renderInfo.lines.lastOrNull()?.width ?: 0.0f)) { markOffset.y -= (Font.TOTAL_CHAR_HEIGHT * scale).toInt() } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/elements/input/TextInputElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/elements/input/TextInputElement.kt index 1afe3d4da..f11801ad4 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/elements/input/TextInputElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/elements/input/TextInputElement.kt @@ -344,8 +344,8 @@ open class TextInputElement( continue } val charDelta = position.x - line.width - val width = guiRenderer.context.font[value.codePointAtOrNull(pointer) ?: break]?.width ?: break - if (charDelta != 0 && charDelta >= width / 2) { + val width = guiRenderer.context.font.default[value.codePointAtOrNull(pointer) ?: break]?.calculateWidth(1.0f, true) ?: break + if (charDelta != 0.0f && charDelta >= width / 2) { pointer++ } break 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 f69e68446..3f89f5a1c 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 @@ -18,12 +18,14 @@ import de.bixilon.kotlinglm.vec2.Vec2i import de.bixilon.kutil.collections.primitive.floats.AbstractFloatList import de.bixilon.kutil.collections.primitive.floats.HeapArrayFloatList import de.bixilon.minosoft.data.text.formatting.color.RGBColor +import de.bixilon.minosoft.gui.rendering.RenderContext import de.bixilon.minosoft.gui.rendering.system.base.texture.ShaderIdentifiable import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.EMPTY class GUIMeshCache( var halfSize: Vec2, override val order: Array>, + override val context: RenderContext, initialCacheSize: Int = 1000, var data: AbstractFloatList = HeapArrayFloatList(initialCacheSize), ) : GUIVertexConsumer { 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 b8894d510..159893589 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,10 +16,12 @@ 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.system.base.texture.ShaderIdentifiable interface GUIVertexConsumer { + val context: RenderContext val order: Array> fun addVertex(position: Vec2, texture: ShaderIdentifiable, uv: Vec2, tint: RGBColor, options: GUIVertexOptions?)