wip: TextComponent rendering

This commit is contained in:
Bixilon 2021-08-04 16:36:43 +02:00
parent 1f86d73846
commit 2ee3868a4b
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
16 changed files with 299 additions and 32 deletions

View File

@ -125,7 +125,6 @@ class BaseComponent : ChatComponent {
val color = json["color"]?.nullCast<String>()?.toColor() ?: parent?.color
val outlineColor = json["outlineColor", "outline_color"]?.nullCast<String>()?.toColor() ?: parent?.outlineColor
val formatting = parent?.formatting?.toMutableSet() ?: mutableSetOf()
@ -142,7 +141,6 @@ class BaseComponent : ChatComponent {
val textComponent = TextComponent(
message = currentText,
color = color,
outlineColor = outlineColor,
formatting = formatting,
clickEvent = clickEvent,
hoverEvent = hoverEvent,

View File

@ -32,7 +32,6 @@ import javafx.util.Duration
open class TextComponent(
message: Any? = "",
override var color: RGBColor? = null,
override var outlineColor: RGBColor? = null,
override val formatting: MutableSet<ChatFormattingCode> = mutableSetOf(),
var clickEvent: ClickEvent? = null,
var hoverEvent: HoverEvent? = null,
@ -74,11 +73,6 @@ open class TextComponent(
return this
}
fun outline(color: RGBColor): TextComponent {
this.outlineColor = color
return this
}
override fun toString(): String {
return legacyText
}
@ -156,16 +150,16 @@ open class TextComponent(
text.styleClass.add("obfuscated")
}
PreChatFormattingCodes.BOLD -> {
text.style = "-fx-font-weight: bold;"
text.style += "-fx-font-weight: bold;"
}
PreChatFormattingCodes.STRIKETHROUGH -> {
text.style = "-fx-strikethrough: true;"
text.style += "-fx-strikethrough: true;"
}
PreChatFormattingCodes.UNDERLINED -> {
text.style = "-fx-underline: true;"
text.style += "-fx-underline: true;"
}
PreChatFormattingCodes.ITALIC -> {
text.style = "-fx-font-weight: italic;"
text.style += "-fx-font-weight: italic;"
}
}
}

View File

@ -14,7 +14,6 @@
package de.bixilon.minosoft.data.text
interface TextStyle {
var outlineColor: RGBColor?
var color: RGBColor?
val formatting: MutableCollection<ChatFormattingCode>
}

View File

@ -18,10 +18,11 @@ import de.bixilon.minosoft.data.text.PreChatFormattingCodes
import de.bixilon.minosoft.data.text.RGBColor
import de.bixilon.minosoft.data.text.TextStyle
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.gui.mesh.FontVertexConsumer
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture
import de.bixilon.minosoft.gui.rendering.util.mesh.Mesh
import de.bixilon.minosoft.util.KUtil.decide
import de.bixilon.minosoft.util.MMath.ceil
import glm_.vec2.Vec2
import glm_.vec2.Vec2i
import glm_.vec2.Vec2t
@ -40,15 +41,15 @@ class CharData(
uvEnd = uvEnd * texture.textureArrayUV
}
fun render(position: Vec2i, style: TextStyle, vertexConsumer: FontVertexConsumer) {
fun render(position: Vec2i, style: TextStyle, vertexConsumer: GUIVertexConsumer) {
render(position, false, style, vertexConsumer)
if (style.formatting.contains(PreChatFormattingCodes.SHADOWED)) {
render(position, true, style, vertexConsumer)
}
}
private fun FontVertexConsumer.addQuad(start: Vec2t<*>, end: Vec2t<*>, texture: AbstractTexture, uvStart: Vec2, uvEnd: Vec2, italic: Boolean, tint: RGBColor) {
val italicOffset = italic.decide(2.5f, 0.0f)
private fun GUIVertexConsumer.addQuad(start: Vec2t<*>, end: Vec2t<*>, texture: AbstractTexture, uvStart: Vec2, uvEnd: Vec2, italic: Boolean, tint: RGBColor) {
val italicOffset = italic.decide(ITALIC_OFFSET, 0.0f)
val positions = arrayOf(
Vec2(start.x.toFloat() + italicOffset, start.y),
Vec2(end.x.toFloat() + italicOffset, start.y),
@ -67,20 +68,20 @@ class CharData(
}
}
private fun render(position: Vec2i, shadow: Boolean, style: TextStyle, vertexConsumer: FontVertexConsumer) {
private fun render(position: Vec2i, shadow: Boolean, style: TextStyle, vertexConsumer: GUIVertexConsumer) {
var color = style.color ?: ChatColors.WHITE
var shadowOffset = 0.0f
if (shadow) {
shadowOffset = 1.0f
shadowOffset = SHADOW_OFFSET
color *= 0.25f
}
var boldOffset = 0.0f
if (style.formatting.contains(PreChatFormattingCodes.BOLD)) {
boldOffset = 0.5f
boldOffset = BOLD_OFFSET
}
@ -98,12 +99,30 @@ class CharData(
}
if (style.formatting.contains(PreChatFormattingCodes.STRIKETHROUGH)) {
vertexConsumer.addQuad(startPosition + Vec2(-1.0f, Font.CHAR_HEIGHT / 2.0f + 0.5f), Vec2(endPosition.x + boldOffset, startPosition.y + Font.CHAR_HEIGHT / 2.0f + 1.5f), renderWindow.WHITE_TEXTURE.texture, renderWindow.WHITE_TEXTURE.uvStart, renderWindow.WHITE_TEXTURE.uvEnd, italic, color)
vertexConsumer.addQuad(startPosition + Vec2(-Font.HORIZONTAL_SPACING / 2.0f, Font.CHAR_HEIGHT / 2.0f + 0.5f), Vec2(endPosition.x + Font.HORIZONTAL_SPACING / 2.0f, startPosition.y + Font.CHAR_HEIGHT / 2.0f + 1.5f), renderWindow.WHITE_TEXTURE.texture, renderWindow.WHITE_TEXTURE.uvStart, renderWindow.WHITE_TEXTURE.uvEnd, italic, color)
}
if (style.formatting.contains(PreChatFormattingCodes.UNDERLINED)) {
vertexConsumer.addQuad(startPosition + Vec2i(-1.0f, Font.CHAR_HEIGHT), Vec2i(endPosition.x + boldOffset, startPosition.y + Font.CHAR_HEIGHT + 1.0f), renderWindow.WHITE_TEXTURE.texture, renderWindow.WHITE_TEXTURE.uvStart, renderWindow.WHITE_TEXTURE.uvEnd, italic, color)
vertexConsumer.addQuad(startPosition + Vec2i(-Font.HORIZONTAL_SPACING / 2.0f, Font.CHAR_HEIGHT), Vec2i(endPosition.x + boldOffset, startPosition.y + Font.CHAR_HEIGHT + Font.HORIZONTAL_SPACING / 2.0f), renderWindow.WHITE_TEXTURE.texture, renderWindow.WHITE_TEXTURE.uvStart, renderWindow.WHITE_TEXTURE.uvEnd, italic, color)
}
// ToDo: Obfuscated
}
fun calculateWidth(style: TextStyle): Int {
var width = width.toFloat()
if (style.formatting.contains(PreChatFormattingCodes.SHADOWED)) {
width += SHADOW_OFFSET
}
return width.ceil
}
companion object {
const val ITALIC_OFFSET = 2.5f
const val SHADOW_OFFSET = 1.0f
const val BOLD_OFFSET = 0.5f
}
}

View File

@ -35,5 +35,7 @@ class Font(
companion object {
const val CHAR_HEIGHT = 8
const val HORIZONTAL_SPACING = 2
const val VERTICAL_SPACING = 2
}
}

View File

@ -0,0 +1,28 @@
/*
* Minosoft
* Copyright (C) 2021 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.font.renderer
import de.bixilon.minosoft.data.text.BaseComponent
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.gui.elements.text.LabeledElement
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import glm_.vec2.Vec2i
object BaseComponentRenderer : ChatComponentRenderer<BaseComponent> {
override fun render(offset: Vec2i, element: LabeledElement, renderWindow: RenderWindow, consumer: GUIVertexConsumer, text: BaseComponent) {
for (part in text.parts) {
ChatComponentRenderer.render(offset, element, renderWindow, consumer, part)
}
}
}

View File

@ -0,0 +1,39 @@
/*
* Minosoft
* Copyright (C) 2021 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.font.renderer
import de.bixilon.minosoft.data.text.BaseComponent
import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.data.text.TextComponent
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.gui.elements.text.LabeledElement
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import glm_.vec2.Vec2i
interface ChatComponentRenderer<T : ChatComponent> {
fun render(offset: Vec2i, element: LabeledElement, renderWindow: RenderWindow, consumer: GUIVertexConsumer, text: T)
companion object {
fun render(offset: Vec2i, element: LabeledElement, renderWindow: RenderWindow, consumer: GUIVertexConsumer, text: ChatComponent) {
when (text) {
is BaseComponent -> BaseComponentRenderer.render(offset, element, renderWindow, consumer, text)
is TextComponent -> TextComponentRenderer.render(offset, element, renderWindow, consumer, text)
else -> TODO("Don't know how to render ${text::class.java}")
}
}
}
}

View File

@ -0,0 +1,53 @@
/*
* Minosoft
* Copyright (C) 2021 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.font.renderer
import de.bixilon.minosoft.data.text.PreChatFormattingCodes
import de.bixilon.minosoft.data.text.TextComponent
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.font.CharData
import de.bixilon.minosoft.gui.rendering.font.Font
import de.bixilon.minosoft.gui.rendering.gui.elements.text.LabeledElement
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import de.bixilon.minosoft.util.MMath.ceil
import glm_.vec2.Vec2i
object TextComponentRenderer : ChatComponentRenderer<TextComponent> {
override fun render(offset: Vec2i, element: LabeledElement, renderWindow: RenderWindow, consumer: GUIVertexConsumer, text: TextComponent) {
var first = true
for (char in text.message.toCharArray()) {
if (char == '\n') {
offset.y += Font.CHAR_HEIGHT + Font.VERTICAL_SPACING
continue
}
if (!first) {
offset.x += Font.HORIZONTAL_SPACING
first = false
}
val charData = renderWindow.font[char] ?: continue
charData.render(offset, text, consumer)
offset.x += charData.calculateWidth(text)
}
if (text.formatting.contains(PreChatFormattingCodes.ITALIC)) {
offset.x += CharData.ITALIC_OFFSET.ceil
}
if (text.formatting.contains(PreChatFormattingCodes.BOLD)) {
offset.x += CharData.BOLD_OFFSET.ceil
}
}
}

View File

@ -0,0 +1,28 @@
/*
* Minosoft
* Copyright (C) 2021 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.gui.elements
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import glm_.vec2.Vec2i
abstract class Element {
open var prepared: Boolean = false
open var minSize: Vec2i = Vec2i()
open var maxSize: Vec2i = Vec2i()
open var size: Vec2i = Vec2i()
abstract fun render(offset: Vec2i, consumer: GUIVertexConsumer)
}

View File

@ -0,0 +1,21 @@
/*
* Minosoft
* Copyright (C) 2021 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.gui.elements.text
import de.bixilon.minosoft.data.text.ChatComponent
interface Labeled {
var text: Any
val textComponent: ChatComponent
}

View File

@ -0,0 +1,18 @@
/*
* Minosoft
* Copyright (C) 2021 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.gui.elements.text
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
abstract class LabeledElement : Element(), Labeled

View File

@ -0,0 +1,43 @@
/*
* Minosoft
* Copyright (C) 2021 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.gui.elements.text
import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.font.renderer.ChatComponentRenderer
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import glm_.vec2.Vec2i
class TextElement(
private val renderWindow: RenderWindow,
text: Any,
) : LabeledElement() {
override var text: Any = text
set(value) {
textComponent = ChatComponent.of(value)
field = value
prepared = false
}
override var textComponent: ChatComponent = ChatComponent.of(text)
private set(value) {
size = minSize
field = value
}
override fun render(offset: Vec2i, consumer: GUIVertexConsumer) {
ChatComponentRenderer.render(offset, this, renderWindow, consumer, textComponent)
}
}

View File

@ -21,6 +21,7 @@ import de.bixilon.minosoft.data.text.TextComponent
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.Renderer
import de.bixilon.minosoft.gui.rendering.RendererBuilder
import de.bixilon.minosoft.gui.rendering.gui.elements.text.TextElement
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIMesh
import de.bixilon.minosoft.gui.rendering.modding.events.ResizeWindowEvent
import de.bixilon.minosoft.modding.event.invoker.CallbackEventInvoker
@ -53,19 +54,31 @@ class HUDRenderer(
}
override fun draw() {
renderWindow.renderSystem.reset(faceCulling = false)
renderWindow.renderSystem.reset()
if (this::mesh.isInitialized) {
mesh.unload()
}
mesh = GUIMesh(renderWindow, matrix)
val style = TextComponent("", ChatColors.GOLD, ChatColors.RED, formatting = mutableSetOf(PreChatFormattingCodes.BOLD, PreChatFormattingCodes.SHADOWED, PreChatFormattingCodes.UNDERLINED, PreChatFormattingCodes.ITALIC, PreChatFormattingCodes.STRIKETHROUGH, PreChatFormattingCodes.OBFUSCATED))
renderWindow.font['M']?.render(Vec2i(10, 10), style, mesh)
renderWindow.font['o']?.render(Vec2i(19, 10), style, mesh)
renderWindow.font['r']?.render(Vec2i(28, 10), style, mesh)
renderWindow.font['i']?.render(Vec2i(37, 10), style, mesh)
renderWindow.font['t']?.render(Vec2i(46, 10), style, mesh)
renderWindow.font['z']?.render(Vec2i(55, 10), style, mesh)
val text = TextElement(
renderWindow = renderWindow,
text = TextComponent(
message = "Moritz ist toll!!!",
color = ChatColors.RED,
formatting = mutableSetOf(
PreChatFormattingCodes.BOLD,
PreChatFormattingCodes.SHADOWED,
PreChatFormattingCodes.UNDERLINED,
PreChatFormattingCodes.ITALIC,
PreChatFormattingCodes.STRIKETHROUGH,
PreChatFormattingCodes.OBFUSCATED
),
),
)
if (!text.prepared) {
text.render(Vec2i(10, 10), mesh)
}
mesh.load()

View File

@ -28,7 +28,7 @@ import glm_.vec4.Vec4
class GUIMesh(
renderWindow: RenderWindow,
val matrix: Mat4,
) : Mesh(renderWindow, HUDMeshStruct), FontVertexConsumer {
) : Mesh(renderWindow, HUDMeshStruct), GUIVertexConsumer {
override fun addVertex(position: Vec2t<*>, texture: AbstractTexture, uv: Vec2, tint: RGBColor) {
val outPosition = matrix * Vec4(position.x.toFloat(), position.y.toFloat(), 1.0f, 1.0f)

View File

@ -18,7 +18,7 @@ import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTex
import glm_.vec2.Vec2
import glm_.vec2.Vec2t
interface FontVertexConsumer {
interface GUIVertexConsumer {
fun addVertex(position: Vec2t<*>, texture: AbstractTexture, uv: Vec2, tint: RGBColor)
}

View File

@ -106,9 +106,21 @@ object MMath {
return (this < int).decide(int - 1, int)
}
val Float.floor: Int
get() {
val int = this.toInt()
return (this < int).decide(int - 1, int)
}
val Double.ceil: Int
get() {
val int = this.toInt()
return (this > int).decide(int + 1, int)
}
val Float.ceil: Int
get() {
val int = this.toInt()
return (this > int).decide(int + 1, int)
}
}