faster typesetting by not creating glyph caches

This commit is contained in:
minjaesong
2024-04-28 21:18:44 +09:00
parent ee51cafa6c
commit 2196a4b2e7

View File

@@ -7,7 +7,6 @@ import net.torvald.terrarumsansbitmap.gdx.CodePoint
import net.torvald.terrarumsansbitmap.gdx.CodepointSequence import net.torvald.terrarumsansbitmap.gdx.CodepointSequence
import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap
import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap.Companion.getHash import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap.Companion.getHash
import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap.Companion.TextCacheObj
import java.lang.Math.pow import java.lang.Math.pow
import kotlin.math.* import kotlin.math.*
@@ -37,11 +36,6 @@ class MovableType(
override fun dispose() { override fun dispose() {
if (!disposed) { if (!disposed) {
disposed = true disposed = true
typesettedSlugs.forEach {
it.forEach {
it.block.dispose()
}
}
} }
} }
@@ -57,14 +51,14 @@ class MovableType(
lines.forEachIndexed { linenum, it -> lines.forEachIndexed { linenum, it ->
// println("Processing input text line ${linenum + 1} (word count: ${it.size})...") // println("Processing input text line ${linenum + 1} (word count: ${it.size})...")
val boxes: MutableList<TextCacheObj> = it.map { font.createTextCache(it) }.toMutableList() val boxes: MutableList<NoTexGlyphLayout> = it.map { createGlyphLayout(font, it) }.toMutableList()
var slug = ArrayList<Block>() // slug of the linotype machine var slug = ArrayList<Block>() // slug of the linotype machine
var slugWidth = 0 var slugWidth = 0
var ignoreThisLine = false var ignoreThisLine = false
fun dequeue() = boxes.removeFirst() fun dequeue() = boxes.removeFirst()
fun addHyphenatedTail(box: TextCacheObj) = boxes.add(0, box) fun addHyphenatedTail(box: NoTexGlyphLayout) = boxes.add(0, box)
fun addToSlug(box: TextCacheObj) { fun addToSlug(box: NoTexGlyphLayout) {
val nextPosX = (slug.lastOrNull()?.getEndPos() ?: 0) val nextPosX = (slug.lastOrNull()?.getEndPos() ?: 0)
slug.add(Block(nextPosX, box)) slug.add(Block(nextPosX, box))
slugWidth += box.width slugWidth += box.width
@@ -81,7 +75,7 @@ class MovableType(
/////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////
// the slug is likely end with a glue, must take care of it (but don't modify the slug itself) // the slug is likely end with a glue, must take care of it (but don't modify the slug itself)
fun getBadnessW(box: TextCacheObj): Pair<Float, Int> { fun getBadnessW(box: NoTexGlyphLayout): Pair<Float, Int> {
val slug = slug.toMutableList() val slug = slug.toMutableList()
// remove the trailing glue(s?) in the slug copy // remove the trailing glue(s?) in the slug copy
@@ -101,7 +95,7 @@ class MovableType(
return badness to difference return badness to difference
} }
fun getBadnessT(box: TextCacheObj): Pair<Float, Int> { fun getBadnessT(box: NoTexGlyphLayout): Pair<Float, Int> {
val slug = slug.toMutableList() val slug = slug.toMutableList()
// add the box to the slug copy // add the box to the slug copy
@@ -120,7 +114,7 @@ class MovableType(
return badness to difference return badness to difference
} }
fun getBadnessH(box: TextCacheObj): Pair<Float, Int> { fun getBadnessH(box: NoTexGlyphLayout): Pair<Float, Int> {
// don't hyphenate if: // don't hyphenate if:
// - the word is too short (5 chars or less) // - the word is too short (5 chars or less)
// - the word is pre-hyphenated (ends with hyphen-null) // - the word is pre-hyphenated (ends with hyphen-null)
@@ -128,7 +122,7 @@ class MovableType(
return 10000f to 10000 return 10000f to 10000
val slug = slug.toMutableList() val slug = slug.toMutableList()
val (hyphHead, hyphTail) = box.text.hyphenate().toList().map { font.createTextCache(it) } val (hyphHead, hyphTail) = box.text.hyphenate().toList().map { createGlyphLayout(font, it) }
// add the hyphHead to the slug copy // add the hyphHead to the slug copy
val nextPosX = (slug.lastOrNull()?.getEndPos() ?: 0) val nextPosX = (slug.lastOrNull()?.getEndPos() ?: 0)
@@ -220,7 +214,7 @@ class MovableType(
// widen/tighten the spacing between blocks using widthDeltaH // widen/tighten the spacing between blocks using widthDeltaH
// insert hyphen-tail to the list of upcoming boxes // insert hyphen-tail to the list of upcoming boxes
val (hyphHead, hyphTail) = box.text.hyphenate().toList().map { font.createTextCache(it) } val (hyphHead, hyphTail) = box.text.hyphenate().toList().map { createGlyphLayout(font, it) }
// widen: 1, tighten: -1 // widen: 1, tighten: -1
val operation = widthDeltaH.sign val operation = widthDeltaH.sign
@@ -257,7 +251,6 @@ class MovableType(
height = typesettedSlugs.size height = typesettedSlugs.size
} } } }
fun draw(batch: Batch, x: Int, y: Int, lineStart: Int = 0, linesToDraw: Int = 2147483647, lineHeight: Int = TerrarumSansBitmap.LINE_HEIGHT, drawJobs: Map<Int, (Float, Float, Int) -> Unit> = HashMap()) = fun draw(batch: Batch, x: Int, y: Int, lineStart: Int = 0, linesToDraw: Int = 2147483647, lineHeight: Int = TerrarumSansBitmap.LINE_HEIGHT, drawJobs: Map<Int, (Float, Float, Int) -> Unit> = HashMap()) =
draw(batch, x.toFloat(), y.toFloat(), lineStart, linesToDraw, lineHeight, drawJobs) draw(batch, x.toFloat(), y.toFloat(), lineStart, linesToDraw, lineHeight, drawJobs)
@@ -282,9 +275,6 @@ class MovableType(
drawJobs[absoluteLineNum]?.invoke(x, y + lineNum * lineHeight, absoluteLineNum) drawJobs[absoluteLineNum]?.invoke(x, y + lineNum * lineHeight, absoluteLineNum)
lineBlocks.forEach { lineBlocks.forEach {
val tex = it.block.glyphLayout!!.linotype
val linotypeScaleOffsetX = -TerrarumSansBitmap.linotypePaddingX * (font.scale - 1)
val linotypeScaleOffsetY = -TerrarumSansBitmap.linotypePaddingY * (font.scale - 1) * (if (font.flipY) -1 else 1)
lateinit var oldColour: Color lateinit var oldColour: Color
if (it.colour != null) { if (it.colour != null) {
@@ -292,22 +282,19 @@ class MovableType(
batch.color = it.colour batch.color = it.colour
} }
batch.draw(tex, font.drawNormalised(batch,
x + it.posX * font.scale - 16 + linotypeScaleOffsetX.toFloat(), it.block.text,
y + lineNum * (lineHeight * font.scale) - 8 + linotypeScaleOffsetY.toFloat(), x + it.posX,
tex.width * font.scale.toFloat(), y + lineNum * lineHeight
tex.height * font.scale.toFloat()
) )
if (it.colour != null) if (it.colour != null)
batch.color = oldColour batch.color = oldColour
} }
// font.draw(batch, "I", x, y + lineNum * lineHeight + 14)
} }
} }
data class Block(var posX: Int, val block: TextCacheObj, var colour: Color? = null) { // a single word data class Block(var posX: Int, val block: NoTexGlyphLayout, var colour: Color? = null) { // a single word
fun getEndPos() = this.posX + this.block.width fun getEndPos() = this.posX + this.block.width
} }
@@ -899,13 +886,24 @@ class MovableType(
} }
} }
private fun TextCacheObj.isNotGlue(): Boolean { private fun NoTexGlyphLayout.isNotGlue(): Boolean {
return this.glyphLayout!!.textBuffer.isNotGlue() return this.text.isNotGlue()
} }
private fun TextCacheObj.isGlue(): Boolean { private fun NoTexGlyphLayout.isGlue(): Boolean {
return this.glyphLayout!!.textBuffer.isGlue() return this.text.isGlue()
} }
} // end of companion object } // end of companion object
data class NoTexGlyphLayout(val text: CodepointSequence, val width: Int) {
val penultimateCharOrNull: CodePoint?
get() = text.getOrNull(text.size - 2)
}
private fun createGlyphLayout(font: TerrarumSansBitmap, str: CodepointSequence): NoTexGlyphLayout {
return NoTexGlyphLayout(str, font.getWidth(str))
}
} }