mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-15 18:34:56 -04:00
font rendering: underline, strikethrough
This commit is contained in:
parent
77b9af81a9
commit
6dc3002528
@ -382,5 +382,54 @@ class ChatComponentRendererTest {
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: shadow, underline, strikethrough, formatting (just basic, that is code point renderer's job)
|
||||
|
||||
fun `single strikethrough rendering`() {
|
||||
val consumer = DummyComponentConsumer()
|
||||
render(TextComponent("bcd").strikethrough(), fontManager = FontManager(consumer.Font()), consumer = consumer)
|
||||
|
||||
consumer.assert(
|
||||
DummyComponentConsumer.RendererdQuad(Vec2(10.0f, 14.0f), Vec2(15.0f, 15.0f)),
|
||||
)
|
||||
}
|
||||
|
||||
fun `multiline strikethrough rendering`() {
|
||||
val consumer = DummyComponentConsumer()
|
||||
render(TextComponent("bcd\ncde").strikethrough(), fontManager = FontManager(consumer.Font()), consumer = consumer)
|
||||
|
||||
consumer.assert(
|
||||
DummyComponentConsumer.RendererdQuad(Vec2(10.0f, 14.0f), Vec2(15.0f, 15.0f)),
|
||||
DummyComponentConsumer.RendererdQuad(Vec2(10.0f, 25.0f), Vec2(16.5f, 26.0f)),
|
||||
)
|
||||
}
|
||||
|
||||
fun `single underline rendering`() {
|
||||
val consumer = DummyComponentConsumer()
|
||||
render(TextComponent("bcd").underline(), fontManager = FontManager(consumer.Font()), consumer = consumer)
|
||||
|
||||
consumer.assert(
|
||||
DummyComponentConsumer.RendererdQuad(Vec2(10.0f, 19.0f), Vec2(15.0f, 20.0f)),
|
||||
)
|
||||
}
|
||||
|
||||
fun `multiline underline rendering`() {
|
||||
val consumer = DummyComponentConsumer()
|
||||
render(TextComponent("bcd\ncde").underline(), fontManager = FontManager(consumer.Font()), consumer = consumer)
|
||||
|
||||
consumer.assert(
|
||||
DummyComponentConsumer.RendererdQuad(Vec2(10.0f, 19.0f), Vec2(15.0f, 20.0f)),
|
||||
DummyComponentConsumer.RendererdQuad(Vec2(10.0f, 30.0f), Vec2(16.5f, 31.0f)),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
fun `mixed text strikethrough rendering`() {
|
||||
val consumer = DummyComponentConsumer()
|
||||
render(BaseComponent(TextComponent("bcd").strikethrough(), TextComponent("bcd")), fontManager = FontManager(consumer.Font()), consumer = consumer)
|
||||
|
||||
consumer.assert(
|
||||
DummyComponentConsumer.RendererdQuad(Vec2(10.0f, 14.0f), Vec2(15.0f, 15.0f)),
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: shadow, formatting (just basic, that is code point renderer's job)
|
||||
}
|
||||
|
@ -19,7 +19,6 @@ 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.element.TextRenderProperties
|
||||
import de.bixilon.minosoft.gui.rendering.font.types.FontType
|
||||
import de.bixilon.minosoft.gui.rendering.gui.atlas.TexturePart
|
||||
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIMeshCache
|
||||
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
|
||||
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
|
||||
@ -35,7 +34,7 @@ class DummyComponentConsumer : GUIVertexConsumer {
|
||||
override fun addCache(cache: GUIMeshCache) = Broken()
|
||||
override fun ensureSize(size: Int) = Unit
|
||||
|
||||
override fun addQuad(start: Vec2, end: Vec2, texture: TexturePart, tint: RGBColor, options: GUIVertexOptions?) {
|
||||
override fun addQuad(start: Vec2, end: Vec2, texture: ShaderIdentifiable?, uvStart: Vec2, uvEnd: Vec2, tint: RGBColor, options: GUIVertexOptions?) {
|
||||
quads += RendererdQuad(Vec2(start), Vec2(end))
|
||||
}
|
||||
|
||||
|
@ -13,12 +13,14 @@
|
||||
|
||||
package de.bixilon.minosoft.gui.rendering.font.renderer.component
|
||||
|
||||
import de.bixilon.kotlinglm.vec2.Vec2
|
||||
import de.bixilon.minosoft.data.text.TextComponent
|
||||
import de.bixilon.minosoft.data.text.formatting.FormattingCodes
|
||||
import de.bixilon.minosoft.data.text.formatting.color.RGBColor
|
||||
import de.bixilon.minosoft.gui.rendering.font.manager.FontManager
|
||||
import de.bixilon.minosoft.gui.rendering.font.renderer.CodePointAddResult
|
||||
import de.bixilon.minosoft.gui.rendering.font.renderer.code.CodePointRenderer
|
||||
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.TextRenderInfo
|
||||
import de.bixilon.minosoft.gui.rendering.font.renderer.element.TextRenderProperties
|
||||
@ -51,14 +53,40 @@ object TextComponentRenderer : ChatComponentRenderer<TextComponent> {
|
||||
return false
|
||||
}
|
||||
|
||||
private fun renderStrikethrough() {
|
||||
TODO()
|
||||
private fun renderStrikethrough(offset: Vec2, width: Float, italic: Boolean, color: RGBColor, properties: TextRenderProperties, consumer: GUIVertexConsumer, options: GUIVertexOptions?) {
|
||||
val y = offset.y + properties.charSpacing.top + properties.charBaseHeight / 2.0f - 1.0f
|
||||
|
||||
// TODO: italic
|
||||
consumer.addQuad(Vec2(offset.x, y), Vec2(offset.x + width, y + 1.0f), color, options)
|
||||
}
|
||||
|
||||
private fun renderUnderline() {
|
||||
TODO()
|
||||
private fun renderUnderline(offset: Vec2, width: Float, italic: Boolean, color: RGBColor, properties: TextRenderProperties, consumer: GUIVertexConsumer, options: GUIVertexOptions?) {
|
||||
val y = offset.y + properties.charSpacing.top + properties.charBaseHeight
|
||||
|
||||
// TODO: italic
|
||||
consumer.addQuad(Vec2(offset.x, y), Vec2(offset.x + width, y + 1.0f), color, options)
|
||||
}
|
||||
|
||||
private fun renderFormatting(offset: Vec2, text: TextComponent, width: Float, color: RGBColor, properties: TextRenderProperties, consumer: GUIVertexConsumer, options: GUIVertexOptions?) {
|
||||
if (width <= 0.0f) return
|
||||
val italic = FormattingCodes.ITALIC in text.formatting
|
||||
if (FormattingCodes.UNDERLINED in text.formatting) {
|
||||
renderUnderline(offset, width, italic, color, properties, consumer, options)
|
||||
}
|
||||
if (FormattingCodes.STRIKETHROUGH in text.formatting) {
|
||||
renderStrikethrough(offset, width, italic, color, properties, consumer, options)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun LineRenderInfo.pushAndRender(offset: Vec2, text: TextComponent, line: StringBuilder, width: Float, color: RGBColor, properties: TextRenderProperties, consumer: GUIVertexConsumer?, options: GUIVertexOptions?) {
|
||||
push(text, line)
|
||||
if (consumer != null) {
|
||||
renderFormatting(offset, text, width, color, properties, consumer, options)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun render(offset: TextOffset, fontManager: FontManager, properties: TextRenderProperties, info: TextRenderInfo, consumer: GUIVertexConsumer?, options: GUIVertexOptions?, text: TextComponent): Boolean {
|
||||
if (text.message.isEmpty()) return false
|
||||
|
||||
@ -75,6 +103,8 @@ object TextComponentRenderer : ChatComponentRenderer<TextComponent> {
|
||||
|
||||
val line = StringBuilder()
|
||||
var filled = false
|
||||
val lineStart = Vec2(offset.offset)
|
||||
|
||||
|
||||
val stream = text.message.codePoints().iterator()
|
||||
while (stream.hasNext()) {
|
||||
@ -82,10 +112,12 @@ object TextComponentRenderer : ChatComponentRenderer<TextComponent> {
|
||||
if (codePoint == '\n'.code) {
|
||||
if (!properties.allowNewLine) continue
|
||||
val lineIndex = info.lineIndex
|
||||
val width = offset.offset.x - lineStart.x
|
||||
filled = renderNewline(properties, offset, info, consumer != null)
|
||||
if (line.isNotEmpty()) {
|
||||
info.lines[lineIndex].push(text, line)
|
||||
info.lines[lineIndex].pushAndRender(lineStart, text, line, width, color, properties, consumer, options)
|
||||
}
|
||||
lineStart(offset.offset)
|
||||
skipWhitespaces = true
|
||||
if (filled) break else continue
|
||||
}
|
||||
@ -104,22 +136,31 @@ object TextComponentRenderer : ChatComponentRenderer<TextComponent> {
|
||||
|
||||
val lineIndex = info.lineIndex
|
||||
|
||||
val width = offset.offset.x - lineStart.x
|
||||
|
||||
val lineInfo = renderer.render(offset, color, properties, info, formatting, codePoint, consumer, options)
|
||||
if (lineIndex != info.lineIndex && info.lines.isNotEmpty() && consumer != null) {
|
||||
renderFormatting(lineStart, text, width, color, properties, consumer, options)
|
||||
lineStart(offset.offset)
|
||||
}
|
||||
if (lineInfo == CodePointAddResult.BREAK) {
|
||||
filled = true
|
||||
break
|
||||
}
|
||||
if (consumer != null) continue // already know that information
|
||||
|
||||
if (lineIndex != info.lineIndex) {
|
||||
// new line started
|
||||
info.lines[lineIndex].push(text, line) // previous line
|
||||
if (consumer == null) {
|
||||
info.lines[lineIndex].push(text, line) // previous line
|
||||
} else {
|
||||
line.clear()
|
||||
}
|
||||
}
|
||||
|
||||
line.appendCodePoint(codePoint)
|
||||
}
|
||||
|
||||
if (line.isNotEmpty()) {
|
||||
info.lines[info.lineIndex].push(text, line)
|
||||
info.lines[info.lineIndex].pushAndRender(lineStart, text, line, offset.offset.x - lineStart.x, color, properties, consumer, options)
|
||||
}
|
||||
|
||||
return filled
|
||||
|
@ -30,7 +30,7 @@ interface GUIVertexConsumer {
|
||||
addVertex(Vec2(position), texture, uv, tint, options)
|
||||
}
|
||||
|
||||
fun addQuad(start: Vec2, end: Vec2, texture: ShaderIdentifiable, uvStart: Vec2 = UV_START, uvEnd: Vec2 = UV_END, tint: RGBColor, options: GUIVertexOptions?) {
|
||||
fun addQuad(start: Vec2, end: Vec2, texture: ShaderIdentifiable?, uvStart: Vec2 = UV_START, uvEnd: Vec2 = UV_END, tint: RGBColor, options: GUIVertexOptions?) {
|
||||
val positions = arrayOf(
|
||||
start,
|
||||
Vec2(end.x, start.y),
|
||||
@ -53,6 +53,10 @@ interface GUIVertexConsumer {
|
||||
addQuad(start, end, texture.texture, texture.uvStart, texture.uvEnd, tint, options)
|
||||
}
|
||||
|
||||
fun addQuad(start: Vec2, end: Vec2, tint: RGBColor, options: GUIVertexOptions?) {
|
||||
addQuad(start, end, null, tint = tint, options = options)
|
||||
}
|
||||
|
||||
|
||||
fun addChar(start: Vec2, end: Vec2, texture: Texture?, 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
|
||||
|
Loading…
x
Reference in New Issue
Block a user