mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-16 10:55:01 -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.code.CodePointRenderer
|
||||||
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.font.types.FontType
|
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.GUIMeshCache
|
||||||
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
|
||||||
@ -35,7 +34,7 @@ class DummyComponentConsumer : GUIVertexConsumer {
|
|||||||
override fun addCache(cache: GUIMeshCache) = Broken()
|
override fun addCache(cache: GUIMeshCache) = Broken()
|
||||||
override fun ensureSize(size: Int) = Unit
|
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))
|
quads += RendererdQuad(Vec2(start), Vec2(end))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,12 +13,14 @@
|
|||||||
|
|
||||||
package de.bixilon.minosoft.gui.rendering.font.renderer.component
|
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.TextComponent
|
||||||
import de.bixilon.minosoft.data.text.formatting.FormattingCodes
|
import de.bixilon.minosoft.data.text.formatting.FormattingCodes
|
||||||
import de.bixilon.minosoft.data.text.formatting.color.RGBColor
|
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.manager.FontManager
|
||||||
import de.bixilon.minosoft.gui.rendering.font.renderer.CodePointAddResult
|
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.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.TextOffset
|
||||||
import de.bixilon.minosoft.gui.rendering.font.renderer.element.TextRenderInfo
|
import de.bixilon.minosoft.gui.rendering.font.renderer.element.TextRenderInfo
|
||||||
import de.bixilon.minosoft.gui.rendering.font.renderer.element.TextRenderProperties
|
import de.bixilon.minosoft.gui.rendering.font.renderer.element.TextRenderProperties
|
||||||
@ -51,14 +53,40 @@ object TextComponentRenderer : ChatComponentRenderer<TextComponent> {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderStrikethrough() {
|
private fun renderStrikethrough(offset: Vec2, width: Float, italic: Boolean, color: RGBColor, properties: TextRenderProperties, consumer: GUIVertexConsumer, options: GUIVertexOptions?) {
|
||||||
TODO()
|
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() {
|
private fun renderUnderline(offset: Vec2, width: Float, italic: Boolean, color: RGBColor, properties: TextRenderProperties, consumer: GUIVertexConsumer, options: GUIVertexOptions?) {
|
||||||
TODO()
|
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 {
|
override fun render(offset: TextOffset, fontManager: FontManager, properties: TextRenderProperties, info: TextRenderInfo, consumer: GUIVertexConsumer?, options: GUIVertexOptions?, text: TextComponent): Boolean {
|
||||||
if (text.message.isEmpty()) return false
|
if (text.message.isEmpty()) return false
|
||||||
|
|
||||||
@ -75,6 +103,8 @@ object TextComponentRenderer : ChatComponentRenderer<TextComponent> {
|
|||||||
|
|
||||||
val line = StringBuilder()
|
val line = StringBuilder()
|
||||||
var filled = false
|
var filled = false
|
||||||
|
val lineStart = Vec2(offset.offset)
|
||||||
|
|
||||||
|
|
||||||
val stream = text.message.codePoints().iterator()
|
val stream = text.message.codePoints().iterator()
|
||||||
while (stream.hasNext()) {
|
while (stream.hasNext()) {
|
||||||
@ -82,10 +112,12 @@ object TextComponentRenderer : ChatComponentRenderer<TextComponent> {
|
|||||||
if (codePoint == '\n'.code) {
|
if (codePoint == '\n'.code) {
|
||||||
if (!properties.allowNewLine) continue
|
if (!properties.allowNewLine) continue
|
||||||
val lineIndex = info.lineIndex
|
val lineIndex = info.lineIndex
|
||||||
|
val width = offset.offset.x - lineStart.x
|
||||||
filled = renderNewline(properties, offset, info, consumer != null)
|
filled = renderNewline(properties, offset, info, consumer != null)
|
||||||
if (line.isNotEmpty()) {
|
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
|
skipWhitespaces = true
|
||||||
if (filled) break else continue
|
if (filled) break else continue
|
||||||
}
|
}
|
||||||
@ -104,22 +136,31 @@ object TextComponentRenderer : ChatComponentRenderer<TextComponent> {
|
|||||||
|
|
||||||
val lineIndex = info.lineIndex
|
val lineIndex = info.lineIndex
|
||||||
|
|
||||||
|
val width = offset.offset.x - lineStart.x
|
||||||
|
|
||||||
val lineInfo = renderer.render(offset, color, properties, info, formatting, codePoint, consumer, options)
|
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) {
|
if (lineInfo == CodePointAddResult.BREAK) {
|
||||||
filled = true
|
filled = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if (consumer != null) continue // already know that information
|
|
||||||
|
|
||||||
if (lineIndex != info.lineIndex) {
|
if (lineIndex != info.lineIndex) {
|
||||||
// new line started
|
// 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)
|
line.appendCodePoint(codePoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (line.isNotEmpty()) {
|
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
|
return filled
|
||||||
|
@ -30,7 +30,7 @@ interface GUIVertexConsumer {
|
|||||||
addVertex(Vec2(position), texture, uv, tint, options)
|
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(
|
val positions = arrayOf(
|
||||||
start,
|
start,
|
||||||
Vec2(end.x, start.y),
|
Vec2(end.x, start.y),
|
||||||
@ -53,6 +53,10 @@ interface GUIVertexConsumer {
|
|||||||
addQuad(start, end, texture.texture, texture.uvStart, texture.uvEnd, tint, options)
|
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?) {
|
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
|
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