From 42c72a6a90c9485c3998b735ea005525a02f4182 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Thu, 16 May 2024 01:35:16 +0900 Subject: [PATCH] drawing text without GPU --- .../torvald/terrarumsansbitmap/MovableType.kt | 19 ++- .../gdx/TerrarumSansBitmap.kt | 145 ++++++++++++++++++ 2 files changed, 159 insertions(+), 5 deletions(-) diff --git a/src/net/torvald/terrarumsansbitmap/MovableType.kt b/src/net/torvald/terrarumsansbitmap/MovableType.kt index f45e311..cf43259 100644 --- a/src/net/torvald/terrarumsansbitmap/MovableType.kt +++ b/src/net/torvald/terrarumsansbitmap/MovableType.kt @@ -1,7 +1,8 @@ package net.torvald.terrarumsansbitmap import com.badlogic.gdx.graphics.Color -import com.badlogic.gdx.graphics.g2d.Batch +import com.badlogic.gdx.graphics.Pixmap +import com.badlogic.gdx.graphics.g2d.SpriteBatch import com.badlogic.gdx.utils.Disposable import net.torvald.terrarumsansbitmap.gdx.CodePoint import net.torvald.terrarumsansbitmap.gdx.CodepointSequence @@ -429,20 +430,20 @@ class MovableType( height = typesettedSlugs.size } } - fun draw(batch: Batch, x: Int, y: Int, lineStart: Int = 0, linesToDraw: Int = 2147483647, lineHeight: Int = TerrarumSansBitmap.LINE_HEIGHT) = + fun draw(batch: SpriteBatch, x: Int, y: Int, lineStart: Int = 0, linesToDraw: Int = 2147483647, lineHeight: Int = TerrarumSansBitmap.LINE_HEIGHT) = draw(batch, x.toFloat(), y.toFloat(), lineStart, linesToDraw, lineHeight) - fun draw(batch: Batch, x: Int, y: Int) = + fun draw(batch: SpriteBatch, x: Int, y: Int) = draw(batch, x.toFloat(), y.toFloat(), 0, 2147483647, TerrarumSansBitmap.LINE_HEIGHT) - fun draw(batch: Batch, x: Float, y: Float) = + fun draw(batch: SpriteBatch, x: Float, y: Float) = draw(batch, x, y, 0, 2147483647, TerrarumSansBitmap.LINE_HEIGHT) /** * @param drawJobs Draw call for specific lines (absolute line). This takes the form of Map from linnumber to draw function, * which has three arguments: (line's top-left position-x, line's top-left position-y, absolute line number) */ - fun draw(batch: Batch, x: Float, y: Float, lineStart: Int = 0, linesToDraw: Int = 2147483647, lineHeight: Int = TerrarumSansBitmap.LINE_HEIGHT) { + fun draw(batch: SpriteBatch, x: Float, y: Float, lineStart: Int = 0, linesToDraw: Int = 2147483647, lineHeight: Int = TerrarumSansBitmap.LINE_HEIGHT) { if (isNull) return typesettedSlugs.subList(lineStart, minOf(typesettedSlugs.size, lineStart + linesToDraw)).forEachIndexed { lineNum, text -> @@ -450,6 +451,14 @@ class MovableType( } } + fun drawToPixmap(pixmap: Pixmap, x: Int, y: Int, lineStart: Int = 0, linesToDraw: Int = 2147483647, lineHeight: Int = TerrarumSansBitmap.LINE_HEIGHT) { + if (isNull) return + + typesettedSlugs.subList(lineStart, minOf(typesettedSlugs.size, lineStart + linesToDraw)).forEachIndexed { lineNum, text -> + font.drawNormalisedToPixmap(pixmap, text, x, y + lineNum * lineHeight * font.scale) + } + } + data class Block(var posX: Int, val block: NoTexGlyphLayout, var colour: Color? = null) { // a single word fun getEndPos() = this.posX + this.block.width } diff --git a/src/net/torvald/terrarumsansbitmap/gdx/TerrarumSansBitmap.kt b/src/net/torvald/terrarumsansbitmap/gdx/TerrarumSansBitmap.kt index d000e27..35e0161 100755 --- a/src/net/torvald/terrarumsansbitmap/gdx/TerrarumSansBitmap.kt +++ b/src/net/torvald/terrarumsansbitmap/gdx/TerrarumSansBitmap.kt @@ -387,7 +387,150 @@ class TerrarumSansBitmap( return null } + fun drawToPixmap(pixmap: Pixmap, string: String, x: Int, y: Int) { + drawNormalisedToPixmap(pixmap, string.toCodePoints(), x, y) + } + + fun drawNormalisedToPixmap(pixmap: Pixmap, codepoints: CodepointSequence, x: Int, y: Int) { + val charSeqNotBlank = codepoints.size > 0 // determine emptiness BEFORE you hack a null chars in + + if (charSeqNotBlank) { + val (linotypePixmap, _) = createLinotypePixmap(codepoints, false) + linotypePixmap.filter = Pixmap.Filter.NearestNeighbour + + val linotypeScaleOffsetX = -linotypePaddingX * (scale - 1) + val linotypeScaleOffsetY = -linotypePaddingY * (scale - 1) * (if (flipY) -1 else 1) + + pixmap.drawPixmap(linotypePixmap, + 0, 0, linotypePixmap.width, linotypePixmap.height, + (x - linotypePaddingX) + linotypeScaleOffsetX, + (y - linotypePaddingY) + linotypeScaleOffsetY + (if (flipY) (linotypePixmap.height) else 0) * scale, + linotypePixmap.width * scale, + (linotypePixmap.height) * (if (flipY) -1 else 1) * scale + ) + + linotypePixmap.dispose() + } + } + + internal fun createLinotypePixmap(newCodepoints: CodepointSequence, touchTheFlag: Boolean): Pair { + fun Int.flipY() = this * if (flipY) 1 else -1 + + var renderCol = -1 // subject to change with the colour code + + val textBuffer = newCodepoints + + val posmap = buildPosMap(textBuffer) + + if (touchTheFlag) + flagFirstRun = false + + //dbgprn("text not in buffer: $charSeq") + + + //textBuffer.forEach { print("${it.toHex()} ") } + //dbgprn() + + +// resetHash(charSeq, x.toFloat(), y.toFloat()) + + val textWidth = posmap.width + val _pw = textWidth + (linotypePaddingX * 2) + val _ph = H + (linotypePaddingY * 2) + if (_pw < 0 || _ph < 0) throw RuntimeException("Illegal linotype dimension (w: $_pw, h: $_ph)") + val linotypePixmap = Pixmap(_pw, _ph, Pixmap.Format.RGBA8888) + + + var index = 0 + while (index <= textBuffer.lastIndex) { + try { + var c = textBuffer[index] + val sheetID = getSheetType(c) + + val (sheetX, sheetY) = + if (index == 0) getSheetwisePosition(0, c) + else getSheetwisePosition(textBuffer[index - 1], c) + val hash = getHash(c) // to be used with Bad Transmission Modifier + + if (isColourCode(c)) { + if (c == 0x100000) { + renderCol = -1 + } + else { + renderCol = getColour(c) + } + } + else if (sheetID == SHEET_HANGUL) { + // Flookahead for {I, P, F} + + val cNext = if (index + 1 < textBuffer.size) textBuffer[index + 1] else 0 + val cNextNext = if (index + 2 < textBuffer.size) textBuffer[index + 2] else 0 + + val hangulLength = if (isHangulJongseong(cNextNext) && isHangulJungseong(cNext)) + 3 + else if (isHangulJungseong(cNext)) + 2 + else + 1 + + val (indices, rows) = toHangulIndexAndRow(c, cNext, cNextNext) + + val (indexCho, indexJung, indexJong) = indices + val (choRow, jungRow, jongRow) = rows + val hangulSheet = sheets[SHEET_HANGUL] + + + + val choTex = hangulSheet.get(indexCho, choRow) + val jungTex = hangulSheet.get(indexJung, jungRow) + val jongTex = hangulSheet.get(indexJong, jongRow) + + linotypePixmap.drawPixmap(choTex, posmap.x[index] + linotypePaddingX, linotypePaddingY, renderCol) + linotypePixmap.drawPixmap(jungTex, posmap.x[index] + linotypePaddingX, linotypePaddingY, renderCol) + linotypePixmap.drawPixmap(jongTex, posmap.x[index] + linotypePaddingX, linotypePaddingY, renderCol) + + + index += hangulLength - 1 + + } + else { + try { + val posY = posmap.y[index].flipY() + + if (sheetID == SHEET_UNIHAN) // evil exceptions + offsetUnihan + else if (sheetID == SHEET_CUSTOM_SYM) + offsetCustomSym + else 0 + + val posX = posmap.x[index] + val texture = sheets[sheetID].get(sheetX, sheetY) + + linotypePixmap.drawPixmap(texture, posX + linotypePaddingX, posY + linotypePaddingY, renderCol) + + + } + catch (noSuchGlyph: ArrayIndexOutOfBoundsException) { + } + } + + + index++ + } + catch (e: NullPointerException) { + System.err.println("Shit hit the multithreaded fan") + e.printStackTrace() + break + } + } + + + makeShadow(linotypePixmap) + + return linotypePixmap to textWidth + } + internal fun createTextCache(newCodepoints: CodepointSequence): TextCacheObj { + // look, I know it sounds absurd, but having this code NOT duplicated (by moving it into a separate function) will cause most of the text to turn into a black rectange fun Int.flipY() = this * if (flipY) 1 else -1 var renderCol = -1 // subject to change with the colour code @@ -498,6 +641,8 @@ class TerrarumSansBitmap( makeShadow(linotypePixmap) + // end of duplicated code + //val (linotypePixmap, textWidth) = createLinotypePixmap(newCodepoints, true) val tempLinotype = Texture(linotypePixmap) tempLinotype.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest)