diff --git a/src/net/torvald/btex/BTeXDocument.kt b/src/net/torvald/btex/BTeXDocument.kt index 9dc2aad2f..46721e561 100644 --- a/src/net/torvald/btex/BTeXDocument.kt +++ b/src/net/torvald/btex/BTeXDocument.kt @@ -343,6 +343,24 @@ data class BTeXClickable( ) { var deltaX = 0 var deltaY = 0 + + fun debugDrawHitboxToPixmap(pixmap: Pixmap, doc: BTeXDocument) { + pixmap.drawRectangle( + posX - HBPADH + doc.pageMarginH, + posY - HBPADV + doc.pageMarginV, + width + 2 * HBPADH, + doc.lineHeightInPx + 2 * HBPADV + ) + } + + fun pointInHitbox(doc: BTeXDocument, x: Int, y: Int) = + (x in posX - HBPADH + doc.pageMarginH until posX - HBPADH + doc.pageMarginH + width + 2 * HBPADH && + y in posY - HBPADV + doc.pageMarginV until posY - HBPADV + doc.pageMarginV + doc.lineHeightInPx + 2 * HBPADV) + + companion object { + private const val HBPADH = 0 + private const val HBPADV = 1 + } } class BTeXPage( @@ -407,7 +425,7 @@ class BTeXPage( // debug underlines on clickableElements clickableElements.forEach { pixmap.setColor(HREF_UNDERLINE) - pixmap.drawRectangle(it.posX + doc.pageMarginH, it.posY + doc.pageMarginV, it.width, doc.lineHeightInPx) + it.debugDrawHitboxToPixmap(pixmap, doc) } // print texts diff --git a/src/net/torvald/btex/BTeXParser.kt b/src/net/torvald/btex/BTeXParser.kt index e6c006a88..d3a6bca82 100644 --- a/src/net/torvald/btex/BTeXParser.kt +++ b/src/net/torvald/btex/BTeXParser.kt @@ -1653,10 +1653,10 @@ object BTeXParser { val indexOfSequence = str.indexOfSequence(objSeq) - val theIndex = if (objectIsSplit) -(objSeq.size + 4) else indexOfSequence + val theIndex = if (objectIsSplit) -(objSeq.size) else indexOfSequence theIndex?.let { index -> // we never know which line the object appears - val wordOffset = index + objSeq.size + 4 // must be index of starting NUL + val wordOffset = index + objSeq.size // must be index of starting NUL // target word is on the current line if (wordOffset < str.size) { var wordEnd = wordOffset + 1 // will be right on the ending NUL @@ -1724,10 +1724,10 @@ object BTeXParser { val indexOfSequence = str.indexOfSequence(objSeq) - val theIndex = if (objectIsSplit) -(objSeq.size + 4) else indexOfSequence + val theIndex = if (objectIsSplit) -(objSeq.size) else indexOfSequence theIndex?.let { index -> // we never know which line the object appears - val wordOffset = index + objSeq.size + 4 // must be index of starting NUL + val wordOffset = index + objSeq.size // must be index of starting NUL // target word is on the current line if (wordOffset < str.size) { var wordEnd = wordOffset + 1 // will be right on the ending NUL @@ -1735,6 +1735,10 @@ object BTeXParser { while (!(wordEnd >= str.size || str[wordEnd] == OBJ)) { wordEnd++ } + // if searching finished without finding OBJ, mark it + val objectIsSplit2 = (wordEnd >= str.size) + + // retrieve the actual word val substr = CodepointSequence(str.subList(wordOffset + 1, wordEnd)) printdbg("2HREF word: ${substr.toReadable()}") @@ -1748,7 +1752,7 @@ object BTeXParser { } doc.appendClickable(doc.pages[pageNum], clickable); clickables.add(clickable) - objectIsSplit = false + objectIsSplit = objectIsSplit2 } // target word is on the next line (probably) else { @@ -2083,7 +2087,11 @@ object BTeXParser { if (pattern.isEmpty()) throw IllegalArgumentException("Pattern is empty") if (this.isEmpty()) - throw IllegalArgumentException("Pattern is empty") + throw IllegalArgumentException("String is empty") + + // pattern cannot exist because the string is shorter than the pattern + if (this.size < pattern.size) + return null // next[i] stores the index of the next best partial match val next = IntArray(pattern.size + 1) diff --git a/src/net/torvald/terrarum/tests/BTeXTest.kt b/src/net/torvald/terrarum/tests/BTeXTest.kt index a1384e0c5..96d21ff26 100644 --- a/src/net/torvald/terrarum/tests/BTeXTest.kt +++ b/src/net/torvald/terrarum/tests/BTeXTest.kt @@ -8,17 +8,20 @@ import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.OrthographicCamera import com.badlogic.gdx.graphics.Texture +import com.badlogic.gdx.graphics.g2d.SpriteBatch import com.badlogic.gdx.graphics.g2d.TextureRegion import com.badlogic.gdx.graphics.glutils.ShaderProgram import net.torvald.btex.BTeXDocViewer import net.torvald.btex.BTeXParser -import net.torvald.terrarum.* +import net.torvald.terrarum.FlippingSpriteBatch import net.torvald.terrarum.btex.BTeXDocument +import net.torvald.terrarum.gdxClearAndEnableBlend import net.torvald.terrarum.imagefont.TinyAlphNum +import net.torvald.terrarum.inUse import net.torvald.terrarum.langpack.Lang import net.torvald.terrarum.ui.Toolkit import net.torvald.unicode.EMDASH -import java.io.File +import java.util.concurrent.atomic.AtomicReference import kotlin.system.measureTimeMillis @@ -27,8 +30,8 @@ import kotlin.system.measureTimeMillis */ class BTeXTest : ApplicationAdapter() { -// val filePath = "btex.xml" - val filePath = "btex_ko.xml" + val filePath = "btex.xml" +// val filePath = "btex_ko.xml" // val filePath = "test.xml" // val filePath = "literature/en/daniel_defoe_robinson_crusoe.xml" // val filePath = "literature/ruRU/anton_chekhov_palata_no_6.xml" @@ -47,6 +50,10 @@ class BTeXTest : ApplicationAdapter() { "bucks" to "121687" ) + private val errorInfo = AtomicReference().also { + it.set(null) + } + override fun create() { Lang TinyAlphNum @@ -65,25 +72,31 @@ class BTeXTest : ApplicationAdapter() { if (!isBookFinalised) { Thread { - measureTimeMillis { - val f = BTeXParser.invoke(Gdx.files.internal("./assets/mods/basegame/books/$filePath"), varMap) - document = f.first - documentHandler = f.second - }.also { - println("Time spent on typesetting [ms]: $it") - } + try { + measureTimeMillis { + val f = BTeXParser.invoke(Gdx.files.internal("./assets/mods/basegame/books/$filePath"), varMap) + document = f.first + documentHandler = f.second + }.also { + println("Time spent on typesetting [ms]: $it") + } - measureTimeMillis { - document.finalise(true) - }.also { - println("Time spent on finalising [ms]: $it") - } + measureTimeMillis { + document.finalise(true) + }.also { + println("Time spent on finalising [ms]: $it") + } - /*measureTimeMillis { - document.serialise(File("./assets/mods/basegame/books/${filePath.replace(".xml", ".btxbook")}")) - }.also { - println("Time spent on serialisation [ms]: $it") - }*/ + /*measureTimeMillis { + document.serialise(File("./assets/mods/basegame/books/${filePath.replace(".xml", ".btxbook")}")) + }.also { + println("Time spent on serialisation [ms]: $it") + }*/ + } + catch (e: Throwable) { + errorInfo.set(e) + e.printStackTrace() + } }.start() } else { @@ -100,6 +113,30 @@ class BTeXTest : ApplicationAdapter() { private val drawY = 24 + private fun drawLoadingMsg(batch: SpriteBatch, stage: String) { + val e = errorInfo.get() + if (e != null) { + val st = e.message!!.split('\n').let { + val idx = it.indexOfFirst { it.startsWith("Caused by: ") } + it.subList(idx, it.size) + } + val th = 14 * st.size + val tw = st.maxOf { it.length } * 7 + + val tx = (1280 - tw) / 2 + val ty = (720 - th) / 2 + + batch.color = Color.CORAL + st.forEachIndexed { i, s -> + TinyAlphNum.draw(batch, s, tx.toFloat(), ty + 14f*i) + } + } + else { + batch.color = Color.WHITE + Toolkit.drawTextCentered(batch, TinyAlphNum, stage, 1280, 0, 354) + } + } + override fun render() { Gdx.graphics.setTitle("BTeXTest $EMDASH F: ${Gdx.graphics.framesPerSecond}") @@ -127,8 +164,7 @@ class BTeXTest : ApplicationAdapter() { } else { batch.inUse { - batch.color = Color.WHITE - Toolkit.drawTextCentered(batch, TinyAlphNum, "Rendering...", 1280, 0, 354) + drawLoadingMsg(batch, "Rendering...") } } @@ -145,8 +181,7 @@ class BTeXTest : ApplicationAdapter() { } else { batch.inUse { - batch.color = Color.WHITE - Toolkit.drawTextCentered(batch, TinyAlphNum, "Typesetting...", 1280, 0, 354) + drawLoadingMsg(batch, "Typesetting...") } } }