wip text element tests

This commit is contained in:
Bixilon 2023-06-15 02:04:19 +02:00
parent 72ebb2303d
commit e27baeb8ea
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
8 changed files with 208 additions and 20 deletions

View File

@ -0,0 +1,59 @@
/*
* 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 <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
import de.bixilon.kotlinglm.vec2.Vec2
import de.bixilon.kotlinglm.vec2.Vec2i
import de.bixilon.kutil.observer.DataObserver
import de.bixilon.kutil.reflection.ReflectionUtil.forceSet
import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft
import de.bixilon.minosoft.gui.rendering.RenderContext
import de.bixilon.minosoft.gui.rendering.font.manager.FontManager
import de.bixilon.minosoft.gui.rendering.font.types.dummy.DummyFontType
import de.bixilon.minosoft.gui.rendering.gui.atlas.CodeTexturePart
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
import de.bixilon.minosoft.gui.rendering.system.dummy.DummyRenderSystem
import de.bixilon.minosoft.gui.rendering.system.dummy.texture.DummyTexture
import de.bixilon.minosoft.gui.rendering.system.dummy.texture.DummyTextureManager
import de.bixilon.minosoft.test.IT.OBJENESIS
import org.testng.Assert.assertEquals
object GuiRenderTestUtil {
private fun createContext(): RenderContext {
val context = OBJENESIS.newInstance(RenderContext::class.java)
context.font = FontManager(DummyFontType)
context::renderSystem.forceSet(DummyRenderSystem(context))
context::textureManager.forceSet(DummyTextureManager(context))
context.textureManager::whiteTexture.forceSet(CodeTexturePart(DummyTexture(minosoft("white")), size = Vec2i(16, 16)))
return context
}
fun create(size: Vec2 = Vec2(1920.0f, 1080.0f)): GUIRenderer {
val renderer = OBJENESIS.newInstance(GUIRenderer::class.java)
renderer::scaledSize.forceSet(DataObserver(size))
renderer::halfSize.forceSet(size / 2.0f)
renderer::context.forceSet(createContext())
return renderer
}
fun Element.assetSize(size: Vec2) {
assertEquals(size, this.size)
}
}

View File

@ -0,0 +1,63 @@
package de.bixilon.minosoft.gui.rendering.gui.elements.text
import de.bixilon.kotlinglm.vec2.Vec2
import de.bixilon.kotlinglm.vec4.Vec4
import de.bixilon.minosoft.gui.rendering.gui.GuiRenderTestUtil
import de.bixilon.minosoft.gui.rendering.gui.GuiRenderTestUtil.assetSize
import de.bixilon.minosoft.gui.rendering.gui.elements.text.background.TextBackground
import org.testng.annotations.Test
@Test(groups = ["font", "gui"])
class TextElementTest {
fun `size empty`() {
val element = TextElement(GuiRenderTestUtil.create(), "")
element.assetSize(Vec2(0, 0))
}
fun `size of single char`() {
val element = TextElement(GuiRenderTestUtil.create(), "b", background = null)
element.assetSize(Vec2(0.5f, 11.0f))
}
fun `size of multiple chars`() {
val element = TextElement(GuiRenderTestUtil.create(), "bc", background = null)
element.assetSize(Vec2(2.5f, 11.0f))
}
fun `size with new line`() {
val element = TextElement(GuiRenderTestUtil.create(), "bc\nbc", background = null)
element.assetSize(Vec2(2.5f, 22.0f))
}
fun `size with background`() {
val element = TextElement(GuiRenderTestUtil.create(), "bc")
element.assetSize(Vec2(4.5f, 13.0f))
}
fun `size with background and newlines`() {
val element = TextElement(GuiRenderTestUtil.create(), "bc\nbc")
element.assetSize(Vec2(4.5f, 24.0f))
}
fun `size if text changed`() {
val element = TextElement(GuiRenderTestUtil.create(), "bc\nbc")
element.text = "bcd\nbcd\nbcd"
element.assetSize(Vec2(6.0f, 35.0f))
}
fun `size if background cleared`() {
val element = TextElement(GuiRenderTestUtil.create(), "bcd\nbcd\nbcd")
element.background = null
element.assetSize(Vec2(4.0f, 33.0f))
}
fun `size if background set`() {
val element = TextElement(GuiRenderTestUtil.create(), "bcd\nbcd\nbcd")
element.background = TextBackground(size = Vec4(2.0f))
element.assetSize(Vec2(8.0f, 37.0f))
}
// TODO: test on mouse (click/hover events), rendering, size limiting
}

View File

@ -19,7 +19,7 @@ import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTex
class CodeTexturePart( class CodeTexturePart(
override val texture: AbstractTexture, override val texture: AbstractTexture,
override val uvStart: Vec2, override val uvStart: Vec2 = Vec2(0.0f),
override val uvEnd: Vec2, override val uvEnd: Vec2 = Vec2(1.0f),
override val size: Vec2i, override val size: Vec2i,
) : TexturePart ) : TexturePart

View File

@ -15,14 +15,12 @@ package de.bixilon.minosoft.gui.rendering.gui.elements.text
import de.bixilon.kotlinglm.vec2.Vec2i import de.bixilon.kotlinglm.vec2.Vec2i
import de.bixilon.kutil.primitive.BooleanUtil.decide import de.bixilon.kutil.primitive.BooleanUtil.decide
import de.bixilon.kutil.time.TimeUtil
import de.bixilon.kutil.time.TimeUtil.millis import de.bixilon.kutil.time.TimeUtil.millis
import de.bixilon.minosoft.data.text.formatting.color.RGBColor
import de.bixilon.minosoft.gui.rendering.RenderConstants
import de.bixilon.minosoft.gui.rendering.font.renderer.element.TextRenderProperties import de.bixilon.minosoft.gui.rendering.font.renderer.element.TextRenderProperties
import de.bixilon.minosoft.gui.rendering.gui.GUIRenderer import de.bixilon.minosoft.gui.rendering.gui.GUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.elements.Element import de.bixilon.minosoft.gui.rendering.gui.elements.Element
import de.bixilon.minosoft.gui.rendering.gui.elements.Pollable import de.bixilon.minosoft.gui.rendering.gui.elements.Pollable
import de.bixilon.minosoft.gui.rendering.gui.elements.text.background.TextBackground
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions.Companion.copy import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions.Companion.copy
@ -34,7 +32,7 @@ class FadingTextElement(
var fadeInTime: Long = 100, var fadeInTime: Long = 100,
var stayTime: Long = 1000, var stayTime: Long = 1000,
var fadeOutTime: Long = 100, var fadeOutTime: Long = 100,
background: RGBColor? = RenderConstants.TEXT_BACKGROUND_COLOR, background: TextBackground? = TextBackground.DEFAULT,
parent: Element? = null, parent: Element? = null,
properties: TextRenderProperties, properties: TextRenderProperties,
) : TextElement(guiRenderer = guiRenderer, text = text, background = background, parent, properties), Pollable { ) : TextElement(guiRenderer = guiRenderer, text = text, background = background, parent, properties), Pollable {

View File

@ -21,8 +21,6 @@ import de.bixilon.minosoft.Minosoft
import de.bixilon.minosoft.data.text.ChatComponent import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.data.text.EmptyComponent import de.bixilon.minosoft.data.text.EmptyComponent
import de.bixilon.minosoft.data.text.TextComponent import de.bixilon.minosoft.data.text.TextComponent
import de.bixilon.minosoft.data.text.formatting.color.RGBColor
import de.bixilon.minosoft.gui.rendering.RenderConstants
import de.bixilon.minosoft.gui.rendering.font.renderer.component.ChatComponentRenderer import de.bixilon.minosoft.gui.rendering.font.renderer.component.ChatComponentRenderer
import de.bixilon.minosoft.gui.rendering.font.renderer.element.LineRenderInfo import de.bixilon.minosoft.gui.rendering.font.renderer.element.LineRenderInfo
import de.bixilon.minosoft.gui.rendering.font.renderer.element.TextOffset import de.bixilon.minosoft.gui.rendering.font.renderer.element.TextOffset
@ -31,6 +29,7 @@ import de.bixilon.minosoft.gui.rendering.font.renderer.element.TextRenderPropert
import de.bixilon.minosoft.gui.rendering.gui.GUIRenderer import de.bixilon.minosoft.gui.rendering.gui.GUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.elements.Element import de.bixilon.minosoft.gui.rendering.gui.elements.Element
import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments.Companion.getOffset import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments.Companion.getOffset
import de.bixilon.minosoft.gui.rendering.gui.elements.text.background.TextBackground
import de.bixilon.minosoft.gui.rendering.gui.input.mouse.MouseActions import de.bixilon.minosoft.gui.rendering.gui.input.mouse.MouseActions
import de.bixilon.minosoft.gui.rendering.gui.input.mouse.MouseButtons import de.bixilon.minosoft.gui.rendering.gui.input.mouse.MouseButtons
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIMesh import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIMesh
@ -39,13 +38,20 @@ import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
import de.bixilon.minosoft.gui.rendering.system.window.CursorShapes 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.Vec2Util.EMPTY
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2Util.MAX import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2Util.MAX
import de.bixilon.minosoft.gui.rendering.util.vec.vec4.Vec4Util.bottom
import de.bixilon.minosoft.gui.rendering.util.vec.vec4.Vec4Util.offset
import de.bixilon.minosoft.gui.rendering.util.vec.vec4.Vec4Util.vertical
import de.bixilon.minosoft.gui.rendering.util.vec.vec4.Vec4iUtil.offset import de.bixilon.minosoft.gui.rendering.util.vec.vec4.Vec4iUtil.offset
import de.bixilon.minosoft.util.KUtil.charCount import de.bixilon.minosoft.util.KUtil.charCount
/**
* A simple UI element that draws text on the screen
* A background color is supported, if set
*/
open class TextElement( open class TextElement(
guiRenderer: GUIRenderer, guiRenderer: GUIRenderer,
text: Any, text: Any,
background: RGBColor? = RenderConstants.TEXT_BACKGROUND_COLOR, background: TextBackground? = TextBackground.DEFAULT,
parent: Element? = null, parent: Element? = null,
properties: TextRenderProperties = TextRenderProperties.DEFAULT, properties: TextRenderProperties = TextRenderProperties.DEFAULT,
) : Element(guiRenderer, text.charCount * 6 * GUIMesh.GUIMeshStruct.FLOATS_PER_VERTEX), Labeled { ) : Element(guiRenderer, text.charCount * 6 * GUIMesh.GUIMeshStruct.FLOATS_PER_VERTEX), Labeled {
@ -53,13 +59,13 @@ open class TextElement(
lateinit var info: TextRenderInfo lateinit var info: TextRenderInfo
private set private set
var background: RGBColor? = background var background: TextBackground? = background
set(value) { set(value) {
if (field == value) { if (field == value) {
return return
} }
field = value field = value
cacheUpToDate = false forceApply()
} }
var properties: TextRenderProperties = properties var properties: TextRenderProperties = properties
set(value) { set(value) {
@ -132,7 +138,7 @@ open class TextElement(
override fun onChildChange(child: Element) = Broken("A TextElement can not have a child!") override fun onChildChange(child: Element) = Broken("A TextElement can not have a child!")
private fun GUIVertexConsumer.renderBackground(color: RGBColor, properties: TextRenderProperties, info: TextRenderInfo, offset: Vec2, options: GUIVertexOptions?) { private fun GUIVertexConsumer.renderBackground(background: TextBackground, properties: TextRenderProperties, info: TextRenderInfo, offset: Vec2, options: GUIVertexOptions?) {
val start = Vec2() val start = Vec2()
val end = Vec2() val end = Vec2()
@ -142,10 +148,15 @@ open class TextElement(
start.x = offset.x + properties.alignment.getOffset(line.width, info.size.x) start.x = offset.x + properties.alignment.getOffset(line.width, info.size.x)
start.y = offset.y + (index * lineHeight) + (maxOf(index - 1, 0) * properties.lineSpacing) start.y = offset.y + (index * lineHeight) + (maxOf(index - 1, 0) * properties.lineSpacing)
end.x = start.x + line.width end.x = start.x + line.width + background.size.vertical
end.y = start.y + lineHeight end.y = start.y + lineHeight
addQuad(start, end, context.textureManager.whiteTexture, color, options) if (index == info.lines.size - 1) {
// last line
end.y += background.size.bottom
}
addQuad(start, end, context.textureManager.whiteTexture, background.color, options)
} }
} }
@ -154,8 +165,12 @@ open class TextElement(
val info = this.info val info = this.info
val properties = this.properties val properties = this.properties
val initialOffset = Vec2(offset + margin.offset) val initialOffset = Vec2(offset + margin.offset)
val textOffset = Vec2(initialOffset)
this.background?.let { consumer.renderBackground(it, properties, info, initialOffset, options) } this.background?.let {
consumer.renderBackground(it, properties, info, initialOffset, options)
textOffset += it.size.offset
}
var vertices = ChatComponentRenderer.calculatePrimitiveCount(chatComponent) * consumer.order.size * GUIMesh.GUIMeshStruct.FLOATS_PER_VERTEX var vertices = ChatComponentRenderer.calculatePrimitiveCount(chatComponent) * consumer.order.size * GUIMesh.GUIMeshStruct.FLOATS_PER_VERTEX
if (properties.shadow) { if (properties.shadow) {
@ -163,7 +178,7 @@ open class TextElement(
} }
consumer.ensureSize(vertices) consumer.ensureSize(vertices)
ChatComponentRenderer.render(TextOffset(Vec2(initialOffset)), context.font, properties, info, consumer, options, chatComponent) ChatComponentRenderer.render(TextOffset(textOffset), context.font, properties, info, consumer, options, chatComponent)
info.rewind() info.rewind()
} }
@ -220,7 +235,7 @@ open class TextElement(
private fun TextRenderInfo.getLineAt(lineHeight: Float, lineSpacing: Float, offset: Float): Pair<LineRenderInfo, Float>? { private fun TextRenderInfo.getLineAt(lineHeight: Float, lineSpacing: Float, offset: Float): Pair<LineRenderInfo, Float>? {
var offset = offset var offset = offset
for ((index, line) in info.lines.withIndex()) { for ((index, line) in lines.withIndex()) {
if (offset in 0.0f..lineHeight) { if (offset in 0.0f..lineHeight) {
return Pair(line, offset) return Pair(line, offset)
} }

View File

@ -0,0 +1,28 @@
/*
* 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 <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.background
import de.bixilon.kotlinglm.vec4.Vec4
import de.bixilon.minosoft.data.text.formatting.color.RGBColor
import de.bixilon.minosoft.gui.rendering.RenderConstants
data class TextBackground(
val color: RGBColor = RenderConstants.TEXT_BACKGROUND_COLOR,
val size: Vec4 = Vec4(1.0f),
) {
companion object {
val DEFAULT = TextBackground()
}
}

View File

@ -17,13 +17,12 @@ import de.bixilon.kotlinglm.vec2.Vec2i
import de.bixilon.minosoft.config.key.KeyCodes import de.bixilon.minosoft.config.key.KeyCodes
import de.bixilon.minosoft.data.text.ChatComponent import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.data.text.formatting.color.ChatColors import de.bixilon.minosoft.data.text.formatting.color.ChatColors
import de.bixilon.minosoft.data.text.formatting.color.RGBColor
import de.bixilon.minosoft.gui.rendering.RenderConstants
import de.bixilon.minosoft.gui.rendering.font.renderer.element.TextRenderProperties import de.bixilon.minosoft.gui.rendering.font.renderer.element.TextRenderProperties
import de.bixilon.minosoft.gui.rendering.gui.GUIRenderer import de.bixilon.minosoft.gui.rendering.gui.GUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.elements.Element import de.bixilon.minosoft.gui.rendering.gui.elements.Element
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.ColorElement import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.ColorElement
import de.bixilon.minosoft.gui.rendering.gui.elements.text.TextElement import de.bixilon.minosoft.gui.rendering.gui.elements.text.TextElement
import de.bixilon.minosoft.gui.rendering.gui.elements.text.background.TextBackground
import de.bixilon.minosoft.gui.rendering.gui.input.ModifierKeys import de.bixilon.minosoft.gui.rendering.gui.input.ModifierKeys
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
@ -32,7 +31,7 @@ import de.bixilon.minosoft.gui.rendering.system.window.KeyChangeTypes
class MarkTextElement( class MarkTextElement(
guiRenderer: GUIRenderer, guiRenderer: GUIRenderer,
text: Any, text: Any,
background: RGBColor? = RenderConstants.TEXT_BACKGROUND_COLOR, background: TextBackground? = TextBackground.DEFAULT,
parent: Element? = null, parent: Element? = null,
properties: TextRenderProperties = TextRenderProperties.DEFAULT, properties: TextRenderProperties = TextRenderProperties.DEFAULT,
) : TextElement(guiRenderer, text, background, parent, properties) { ) : TextElement(guiRenderer, text, background, parent, properties) {

View File

@ -13,6 +13,7 @@
package de.bixilon.minosoft.gui.rendering.util.vec.vec4 package de.bixilon.minosoft.gui.rendering.util.vec.vec4
import de.bixilon.kotlinglm.vec2.Vec2
import de.bixilon.kotlinglm.vec4.Vec4 import de.bixilon.kotlinglm.vec4.Vec4
object Vec4Util { object Vec4Util {
@ -26,5 +27,30 @@ object Vec4Util {
val Vec4.Companion.MAX: Vec4 val Vec4.Companion.MAX: Vec4
get() = Vec4(Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE) get() = Vec4(Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE)
val Vec4.top: Float
get() = this.x
val Vec4.right: Float
get() = this.y
val Vec4.bottom: Float
get() = this.z
val Vec4.left: Float
get() = this.w
val Vec4.horizontal: Float
get() = right + left
val Vec4.vertical: Float
get() = top + bottom
val Vec4.spaceSize: Vec2
get() = Vec2(horizontal, vertical)
val Vec4.offset: Vec2
get() = Vec2(left, top)
fun FloatArray.dot(x: Float, y: Float, z: Float) = this[0] * x + this[1] * y + this[2] * z + this[3] fun FloatArray.dot(x: Float, y: Float, z: Float) = this[0] * x + this[1] * y + this[2] * z + this[3]
} }