From de7aeee351c0db6a0acd22163dc45dd0ac99a87b Mon Sep 17 00:00:00 2001 From: minjaesong Date: Thu, 2 May 2024 20:18:23 +0900 Subject: [PATCH] btex: partially working --- .../halfwidth_fullwidth_variable.tga | 2 +- assets/mods/basegame/books/btex.xml | 8 +- lib/TerrarumSansBitmap.jar | 4 +- src/net/torvald/btex/BTeXDocument.kt | 24 +- src/net/torvald/btex/BTeXParser.kt | 266 +++++++++++++----- .../torvald/terrarum/TerrarumPostProcessor.kt | 4 +- 6 files changed, 226 insertions(+), 82 deletions(-) diff --git a/assets/graphics/fonts/terrarum-sans-bitmap/halfwidth_fullwidth_variable.tga b/assets/graphics/fonts/terrarum-sans-bitmap/halfwidth_fullwidth_variable.tga index 0af1fec73..bc490583f 100644 --- a/assets/graphics/fonts/terrarum-sans-bitmap/halfwidth_fullwidth_variable.tga +++ b/assets/graphics/fonts/terrarum-sans-bitmap/halfwidth_fullwidth_variable.tga @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5082cefa353f8a7898b64290eecd8e257c0aa1f30d3c9fb4c23e765692bf30ef +oid sha256:425363b576e7858f2831e3543b9d4090ebc248b1887870ebb48205f2e1eeb2ac size 327698 diff --git a/assets/mods/basegame/books/btex.xml b/assets/mods/basegame/books/btex.xml index 7437daf9c..87723c902 100644 --- a/assets/mods/basegame/books/btex.xml +++ b/assets/mods/basegame/books/btex.xml @@ -46,10 +46,10 @@ Introduction -

is a markup language based on XML, with a resemblance of the LaTeX. The - abstracts away the meticulous styling and typesetting configurations, so you can focus on writing - texts than debugging the LaTeX macros. This does come with a downside of not being able to change - the given style.

+

is a markup language based on XML, with a resemblance of the . + abstracts away the meticulous styling and typesetting configurations, so you can focus on + actually writing your texts than debugging the macros. This does come with a downside of + not being able to change the given style.

document is divided up to five parts: the Style Declaration, the Cover, the Table of Contents, the Manuscript, and the Index Page. Of which the diff --git a/lib/TerrarumSansBitmap.jar b/lib/TerrarumSansBitmap.jar index ed0bfe912..3330218f3 100644 --- a/lib/TerrarumSansBitmap.jar +++ b/lib/TerrarumSansBitmap.jar @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f5c8719dea24cc85ea634a168bc7763ca4612030714b7750e54d985630e15cc1 -size 193329 +oid sha256:547caba20ff13472e90b2458865801591cf0f937f5702dc31d4b142b00dd8ea1 +size 193560 diff --git a/src/net/torvald/btex/BTeXDocument.kt b/src/net/torvald/btex/BTeXDocument.kt index 6b285df09..29eb81ecf 100644 --- a/src/net/torvald/btex/BTeXDocument.kt +++ b/src/net/torvald/btex/BTeXDocument.kt @@ -17,6 +17,7 @@ import net.torvald.terrarum.ui.Toolkit import net.torvald.terrarum.utils.JsonFetcher import net.torvald.terrarumsansbitmap.MovableType import net.torvald.terrarumsansbitmap.gdx.CodepointSequence +import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap import java.io.File import java.io.RandomAccessFile import java.util.zip.Deflater @@ -324,17 +325,24 @@ data class TypesetDrawCall(val movableType: MovableType, override val rowStart: } } +interface BTeXBatchDrawCall { + fun getWidth(): Int + fun getLineHeight(): Int + fun draw(doc: BTeXDocument, batch: SpriteBatch, x: Float, y: Float, font: TerrarumSansBitmap? = null) +} + class BTeXDrawCall( val doc: BTeXDocument, var posX: Int, // position relative to the page start (excluding page margin) var posY: Int, // position relative to the page start (excluding page margin) val theme: String, val text: BTeXTextDrawCall? = null, - val texture: TextureRegion? = null, + val cmd: BTeXBatchDrawCall? = null, + val font: TerrarumSansBitmap? = null ) { init { - if (text != null && texture != null) throw IllegalArgumentException("Text and Texture are both non-null") + if (text != null && cmd != null) throw IllegalArgumentException("Text and Texture are both non-null") } fun draw(batch: SpriteBatch, x: Int, y: Int) { @@ -348,11 +356,11 @@ class BTeXDrawCall( batch.color = Color.WHITE - if (text != null && texture == null) { + if (text != null && cmd == null) { text.draw(doc, batch, px, py) } - else if (text == null && texture != null) { - batch.draw(texture, px, py) + else if (text == null && cmd != null) { + cmd.draw(doc, batch, px, py, font) } else throw Error("Text and Texture are both non-null") @@ -360,7 +368,7 @@ class BTeXDrawCall( } fun isNotBlank(): Boolean { - if (text == null && texture == null) return false + if (text == null && cmd == null) return false if (text is TypesetDrawCall && text.movableType.inputText.isBlank()) return false // if (text is RaggedLeftDrawCall && text.raggedType.inputText.isBlank()) return false return true @@ -373,13 +381,13 @@ class BTeXDrawCall( else TODO() else - texture!!.regionWidth + cmd!!.getWidth() internal var extraDrawFun: (SpriteBatch, Float, Float) -> Unit = { _, _, _ ->} internal val lineCount = if (text != null) text.rows else - TODO() + cmd!!.getLineHeight() companion object { private fun CodepointSequence.isBlank() = this.all { whitespaces.contains(it) } diff --git a/src/net/torvald/btex/BTeXParser.kt b/src/net/torvald/btex/BTeXParser.kt index e804ca676..2a5d4a456 100644 --- a/src/net/torvald/btex/BTeXParser.kt +++ b/src/net/torvald/btex/BTeXParser.kt @@ -2,10 +2,12 @@ package net.torvald.btex import com.badlogic.gdx.files.FileHandle import com.badlogic.gdx.graphics.Color +import com.badlogic.gdx.graphics.g2d.SpriteBatch import com.jme3.math.FastMath.DEG_TO_RAD import net.torvald.colourutil.OKLch import net.torvald.colourutil.tosRGB import net.torvald.terrarum.App +import net.torvald.terrarum.btex.BTeXBatchDrawCall import net.torvald.terrarum.btex.BTeXDocument import net.torvald.terrarum.btex.BTeXDocument.Companion.DEFAULT_ORNAMENTS_COL import net.torvald.terrarum.btex.BTeXDrawCall @@ -15,7 +17,6 @@ import net.torvald.terrarum.gameitems.ItemID import net.torvald.terrarum.toHex import net.torvald.terrarum.tryDispose import net.torvald.terrarum.ui.Toolkit -import net.torvald.terrarum.worlddrawer.toRGBA import net.torvald.terrarumsansbitmap.MovableType import net.torvald.terrarumsansbitmap.gdx.CodepointSequence import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap @@ -86,6 +87,12 @@ object BTeXParser { private val paragraphBuffer = StringBuilder() + fun clearParBuffer() { + paragraphBuffer.clear() + } + + private val objDict = HashMap() + private var lastTagAtDepth = Array(24) { "" } private var pTagCntAtDepth = IntArray(24) @@ -108,6 +115,12 @@ object BTeXParser { private val bodyTextShadowAlpha = 0.36f + private fun StringBuilder.appendObject(id: String) { + (objDict[id] ?: throw NullPointerException("No OBJ with id '$id' exists")).let { + this.append(objectMarkerWithWidth(id, it.getWidth())) + } + } + init { BTeXHandler::class.declaredFunctions.filter { it.findAnnotation() != null }.forEach { // println("Tag opener: ${it.name}") @@ -118,6 +131,45 @@ object BTeXParser { // println("Tag closer: ${it.name}") elemClosers[it.name] = it } + + objDict["TAG@BTEX"] = object : BTeXBatchDrawCall { + override fun getWidth() = 32 + override fun getLineHeight() = 0 + override fun draw(doc: BTeXDocument, batch: SpriteBatch, x: Float, y: Float, font: TerrarumSansBitmap?) { + val scale = font!!.scale + val interchar = font.interchar + font.draw(batch, "${ccDefault}B", x + ( 0 + 0*interchar)*scale, y + 0*scale) + font.draw(batch, "${ccDefault}T", x + ( 8 + 1*interchar)*scale, y + 0*scale) + font.draw(batch, "${ccDefault}E", x + (15 + 2*interchar)*scale, y + 4*scale) + font.draw(batch, "${ccDefault}X", x + (23 + 3*interchar)*scale, y + 0*scale) + } + } + + objDict["TAG@LATEX"] = object : BTeXBatchDrawCall { + override fun getWidth() = 36 + override fun getLineHeight() = 0 + override fun draw(doc: BTeXDocument, batch: SpriteBatch, x: Float, y: Float, font: TerrarumSansBitmap?) { + val scale = font!!.scale + val interchar = font.interchar + font.draw(batch, "${ccDefault}L", x + ( 0 + 0*interchar)*scale, y + 0*scale) + font.draw(batch, "${ccDefault}ᴀ", x + ( 4 + 0*interchar)*scale, y + -4*scale) + font.draw(batch, "${ccDefault}T", x + (12 + 1*interchar)*scale, y + 0*scale) + font.draw(batch, "${ccDefault}E", x + (19 + 2*interchar)*scale, y + 4*scale) + font.draw(batch, "${ccDefault}X", x + (27 + 3*interchar)*scale, y + 0*scale) + } + } + + objDict["TAG@TEX"] = object : BTeXBatchDrawCall { + override fun getWidth() = 24 + override fun getLineHeight() = 0 + override fun draw(doc: BTeXDocument, batch: SpriteBatch, x: Float, y: Float, font: TerrarumSansBitmap?) { + val scale = font!!.scale + val interchar = font.interchar + font.draw(batch, "${ccDefault}T", x + ( 0 + 1*interchar)*scale, y + 0*scale) + font.draw(batch, "${ccDefault}E", x + ( 7 + 2*interchar)*scale, y + 4*scale) + font.draw(batch, "${ccDefault}X", x + (15 + 3*interchar)*scale, y + 0*scale) + } + } } fun dispose() { @@ -519,21 +571,21 @@ object BTeXParser { @OpenTag // reflective access is impossible with 'private' fun processElemTITLE(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap) { - handler.paragraphBuffer.clear() + handler.clearParBuffer() } @OpenTag // reflective access is impossible with 'private' fun processElemSUBTITLE(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap) { - handler.paragraphBuffer.clear() + handler.clearParBuffer() } @OpenTag // reflective access is impossible with 'private' fun processElemAUTHOR(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap) { - handler.paragraphBuffer.clear() + handler.clearParBuffer() } @OpenTag // reflective access is impossible with 'private' fun processElemEDITION(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap) { - handler.paragraphBuffer.clear() + handler.clearParBuffer() } @OpenTag // reflective access is impossible with 'private' @@ -568,9 +620,20 @@ object BTeXParser { @OpenTag // reflective access is impossible with 'private' fun processElemBTEX(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap) { - handler.paragraphBuffer.append("BTeX") + handler.paragraphBuffer.appendObject("TAG@BTEX") } + @OpenTag // reflective access is impossible with 'private' + fun processElemLATEX(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap) { + handler.paragraphBuffer.appendObject("TAG@LATEX") + } + + @OpenTag // reflective access is impossible with 'private' + fun processElemTEX(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap) { + handler.paragraphBuffer.appendObject("TAG@TEX") + } + + @OpenTag // reflective access is impossible with 'private' fun processElemCOVER(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap) { hasCover = true @@ -599,12 +662,12 @@ object BTeXParser { @OpenTag // reflective access is impossible with 'private' fun processElemTABLEOFCONTENTS(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap) { tocPage = doc.currentPage - handler.paragraphBuffer.clear() + handler.clearParBuffer() } @OpenTag // reflective access is impossible with 'private' fun processElemTABLEOFINDICES(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap) { - handler.paragraphBuffer.clear() + handler.clearParBuffer() // prepare contents val pageWidth = doc.textWidth @@ -664,10 +727,10 @@ object BTeXParser { val heading = if (part == null && cpt == null && sect == null) "" else if (part != null && cpt == null && sect == null) - "Part ${part.toRomanNum()}.\uDBBF\uDFF8" + "Part ${part.toRomanNum()}.${glueToString(9)}" else - listOfNotNull(cpt, sect).joinToString(".") + "\uDBBF\uDFF8" + - (if (cpt != null && cpt < 10) "\uDBBF\uDFF8" else "") + listOfNotNull(cpt, sect).joinToString(".") + "${glueToString(9)}" + + (if (cpt != null && cpt < 10) "${glueToString(9)}" else "") typesetTOCline("$heading", name, pg, handler, indent, tocPage) } @@ -726,7 +789,7 @@ object BTeXParser { @OpenTag // reflective access is impossible with 'private' fun processElemP(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap) { - handler.paragraphBuffer.clear() + handler.clearParBuffer() } @CloseTag @@ -734,7 +797,7 @@ object BTeXParser { typesetParagraphs("${ccDefault}――――――――――――", handler).also {it.first().let { it.posX += (doc.textWidth - it.width) / 2 } } - handler.paragraphBuffer.clear() + handler.clearParBuffer() } @CloseTag @@ -750,7 +813,7 @@ object BTeXParser { fun closeElemTITLE(handler: BTeXHandler, doc: BTeXDocument, uri: String, siblingIndex: Int) { val thePar = handler.paragraphBuffer.toString().trim() typesetBookTitle(thePar, handler) - handler.paragraphBuffer.clear() + handler.clearParBuffer() doc.theTitle = thePar.replace("\n", " ") } @@ -758,7 +821,7 @@ object BTeXParser { fun closeElemSUBTITLE(handler: BTeXHandler, doc: BTeXDocument, uri: String, siblingIndex: Int) { val thePar = handler.paragraphBuffer.toString().trim() typesetBookEdition(thePar, handler) - handler.paragraphBuffer.clear() + handler.clearParBuffer() doc.theSubtitle = thePar.replace("\n", " ") } @@ -766,7 +829,7 @@ object BTeXParser { fun closeElemAUTHOR(handler: BTeXHandler, doc: BTeXDocument, uri: String, siblingIndex: Int) { val thePar = handler.paragraphBuffer.toString().trim() typesetBookAuthor(thePar, handler) - handler.paragraphBuffer.clear() + handler.clearParBuffer() doc.theAuthor = thePar.replace("\n", " ") } @@ -774,7 +837,7 @@ object BTeXParser { fun closeElemEDITION(handler: BTeXHandler, doc: BTeXDocument, uri: String, siblingIndex: Int) { val thePar = handler.paragraphBuffer.toString().trim() typesetBookEdition(thePar, handler) - handler.paragraphBuffer.clear() + handler.clearParBuffer() doc.theEdition = thePar.replace("\n", " ") } @@ -782,7 +845,7 @@ object BTeXParser { @OpenTag // reflective access is impossible with 'private' fun processElemPART(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap) { - handler.paragraphBuffer.clear() + handler.clearParBuffer() if (attribs["hide"] == null) cptSectStack.add(CptSect("part", attribs["alt"])) @@ -791,7 +854,7 @@ object BTeXParser { } @OpenTag // reflective access is impossible with 'private' fun processElemCHAPTER(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap) { - handler.paragraphBuffer.clear() + handler.clearParBuffer() if (attribs["hide"] == null) cptSectStack.add(CptSect("chapter", attribs["alt"])) @@ -800,7 +863,7 @@ object BTeXParser { } @OpenTag // reflective access is impossible with 'private' fun processElemSECTION(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap) { - handler.paragraphBuffer.clear() + handler.clearParBuffer() if (attribs["hide"] == null) cptSectStack.add(CptSect("section", attribs["alt"])) @@ -820,7 +883,7 @@ object BTeXParser { if (!cptSectInfo.type.endsWith("-hidden")) cptSectMap.add(CptSectInfo("part", cptSectInfo.alt ?: thePar, doc.currentPage, partOrder, null, null)) - handler.paragraphBuffer.clear() + handler.clearParBuffer() } @CloseTag // reflective access is impossible with 'private' fun closeElemCHAPTER(handler: BTeXHandler, doc: BTeXDocument, uri: String, siblingIndex: Int) { @@ -837,7 +900,7 @@ object BTeXParser { if (!cptSectInfo.type.endsWith("-hidden")) cptSectMap.add(CptSectInfo("chapter", cptSectInfo.alt ?: thePar, doc.currentPage, partOrder, cptOrder, null)) - handler.paragraphBuffer.clear() + handler.clearParBuffer() } @CloseTag // reflective access is impossible with 'private' fun closeElemSECTION(handler: BTeXHandler, doc: BTeXDocument, uri: String, siblingIndex: Int) { @@ -865,7 +928,7 @@ object BTeXParser { if (!cptSectInfo.type.endsWith("-hidden")) cptSectMap.add(CptSectInfo("section", cptSectInfo.alt ?: thePar, doc.currentPage, partOrder, cptOrder, sectOrder)) - handler.paragraphBuffer.clear() + handler.clearParBuffer() } @@ -877,12 +940,18 @@ object BTeXParser { val thePar = handler.paragraphBuffer.toString().trim() val text = - if (siblingIndex > 1 && penultTag != "ANONBREAK" && penultTag != "BR") "\u3000$thePar" + // DON't indent on centering context + if (tagStack.contains("CENTER") || tagStack.contains("FULLPAGEBOX")) thePar + // indent the second+ pars (or don't indent first par after cpt/sect, anonbreak and br) + else if (siblingIndex > 1 && penultTag != "ANONBREAK" && penultTag != "BR") "\u3000$thePar" + // if the very first tag within the MANUSCRIPT is par (i.e. no chapter), create a "virtual" chapter else if (penultTag == "MANUSCRIPT") "\n\n$thePar" + // else, print the text normally else thePar typesetParagraphs(ccDefault + text, handler) - handler.paragraphBuffer.clear() + + handler.clearParBuffer() } @CloseTag // reflective access is impossible with 'private' @@ -970,7 +1039,7 @@ object BTeXParser { } private fun typesetChapterHeading(chapNum: Int?, thePar: String, handler: BTeXHandler, indent: Int = 16, width: Int = doc.textWidth) { - val header = if (chapNum == null) thePar else "$chapNum\uDBBF\uDFF8$thePar" + val header = if (chapNum == null) thePar else "$chapNum${glueToString(9)}$thePar" typesetParagraphs("\n$ccDefault$header", handler, width - indent).also { // add indents and adjust text y pos it.forEach { @@ -992,7 +1061,7 @@ object BTeXParser { } private fun typesetSectionHeading(chapNum: Int, sectNum: Int, thePar: String, handler: BTeXHandler, indent: Int = 16, width: Int = doc.textWidth) { - typesetParagraphs("\n$ccDefault$chapNum.$sectNum\uDBBF\uDFF8$thePar", handler, width - indent).also { + typesetParagraphs("\n$ccDefault$chapNum.$sectNum${glueToString(9)}$thePar", handler, width - indent).also { // add indents and adjust text y pos it.forEach { it.posX += indent @@ -1019,16 +1088,13 @@ object BTeXParser { if (slugHeight > remainder) { val subset = linesOut to remainder + val posYline = doc.linesPrintedOnPage[pageNum] - val drawCall = BTeXDrawCall( - doc, - 0, - doc.linesPrintedOnPage[pageNum] * doc.lineHeightInPx, - handler.currentTheme, - TypesetDrawCall(slugs, subset.first, subset.second) - ) - - doc.appendDrawCall(doc.pages[pageNum], drawCall); drawCalls.add(drawCall) + (textToDrawCall(handler, posYline, slugs, subset.first, subset.second) + parseAndGetObjDrawCalls(font, handler, posYline, slugs, subset.first, subset.second)).let { + it.forEach { + doc.appendDrawCall(doc.pages[pageNum], it); drawCalls.add(it) + } + } linesOut += remainder slugHeight -= remainder @@ -1040,16 +1106,13 @@ object BTeXParser { remainder = minOf(slugHeight, doc.pageLines) val subset = linesOut to remainder + val posYline = doc.linesPrintedOnPage[pageNum] - val drawCall = BTeXDrawCall( - doc, - 0, - doc.linesPrintedOnPage[pageNum] * doc.lineHeightInPx, - handler.currentTheme, - TypesetDrawCall(slugs, subset.first, subset.second) - ) - - doc.appendDrawCall(doc.pages[pageNum], drawCall); drawCalls.add(drawCall) + (textToDrawCall(handler, posYline, slugs, subset.first, subset.second) + parseAndGetObjDrawCalls(font, handler, posYline, slugs, subset.first, subset.second)).let { + it.forEach { + doc.appendDrawCall(doc.pages[pageNum], it); drawCalls.add(it) + } + } linesOut += remainder slugHeight -= remainder @@ -1065,6 +1128,53 @@ object BTeXParser { return drawCalls } + private fun textToDrawCall(handler: BTeXHandler, posYline: Int, slugs: MovableType, lineStart: Int, lineEnd: Int): List { + return listOf( + BTeXDrawCall( + doc, + 0, + posYline * doc.lineHeightInPx, + handler.currentTheme, + TypesetDrawCall(slugs, lineStart, lineEnd) + ) + ) + } + + private fun parseAndGetObjDrawCalls(font: TerrarumSansBitmap, handler: BTeXHandler, posYline: Int, slugs: MovableType, lineStart: Int, lineEnd: Int): List { + val out = ArrayList() + + slugs.typesettedSlugs.subList(lineStart, lineEnd).forEachIndexed { lineNumCnt, line -> + line.mapIndexed { i, c -> i to c }.filter { it.second == OBJ }.map { it.first }.forEach { xIndex -> + val x = font.getWidthNormalised(CodepointSequence(line.subList(0, xIndex))) + val y = (posYline + lineNumCnt) * doc.lineHeightInPx + + // get OBJ id + val idbuf = StringBuilder() + + var c = xIndex + 1 + while (true) { + val codepoint = line[c] + if (codepoint == 0xFFF9F) break + idbuf.append(codepointToObjIdChar(codepoint)) + c += 1 + } + + val extraDrawCall = BTeXDrawCall( + doc, + x, + y, + handler.currentTheme, + cmd = objDict[idbuf.toString()] ?: throw NullPointerException("No OBJ with id '$idbuf' exists"), + font = font + ) + + out.add(extraDrawCall) + } + } + + return out + } + private fun CodepointSequence.toReadable() = this.joinToString("") { if (it in 0x00..0x1f) "${(0x2400 + it).toChar()}" @@ -1128,39 +1238,56 @@ object BTeXParser { private const val ZWSP = 0x200B private const val SHY = 0xAD private const val NBSP = 0xA0 - private const val GLUE_POSITIVE_ONE = 0xFFFF0 - private const val GLUE_POSITIVE_SIXTEEN = 0xFFFFF - private const val GLUE_NEGATIVE_ONE = 0xFFFE0 - private const val GLUE_NEGATIVE_SIXTEEN = 0xFFFEF + private const val OBJ = 0xFFFC + private const val SPACING_BLOCK_ONE = 0xFFFD0 + private const val SPACING_BLOCK_SIXTEEN = 0xFFFDF fun glueToString(glue: Int): String { val tokens = CodepointSequence() - if (glue == 0) + if (glue < 0) + throw IllegalArgumentException("Space is less than zero ($glue)") + else if (glue == 0) tokens.add(ZWSP) - else if (glue.absoluteValue <= 16) - if (glue > 0) - tokens.add(GLUE_POSITIVE_ONE + (glue - 1)) - else - tokens.add(GLUE_NEGATIVE_ONE + (glue.absoluteValue - 1)) + else if (glue in 1..16) + tokens.add(SPACING_BLOCK_ONE + (glue - 1)) else { - val fullGlues = glue.absoluteValue / 16 - val smallGlues = glue.absoluteValue % 16 - if (glue > 0) + val fullGlues = glue / 16 + val smallGlues = glue % 16 + if (smallGlues > 0) { tokens.addAll( - List(fullGlues) { GLUE_POSITIVE_SIXTEEN } + - listOf(GLUE_POSITIVE_ONE + (smallGlues - 1)) + List(fullGlues) { SPACING_BLOCK_SIXTEEN } + + listOf(SPACING_BLOCK_ONE + (smallGlues - 1)) ) - else + } + else { tokens.addAll( - List(fullGlues) { GLUE_NEGATIVE_SIXTEEN } + - listOf(GLUE_NEGATIVE_ONE + (smallGlues - 1)) + List(fullGlues) { SPACING_BLOCK_SIXTEEN } ) + } } return tokens.toUTF8Bytes().toString(Charsets.UTF_8) } + fun objectMarkerWithWidth(id: String, width: Int): String { + val idstr = CodepointSequence() + + id.forEach { + idstr.add(when (it) { + '@' -> 0xFFF80 + '-' -> 0xFFF7D + in '0'..'9' -> 0xFFF70 + (it.code - 0x30) + in 'A'..'Z' -> 0xFFF81 + (it.code - 0x41) + else -> throw IllegalArgumentException("Non-object ID char: $it") + }) + } + + idstr.add(0xFFF9F) + + return "\uFFFC" + idstr.toUTF8Bytes().toString(Charsets.UTF_8) + glueToString(width) + } + fun Int.toRomanNum(): String = when (this) { in 1000..3999 -> "M" + (this - 1000).toRomanNum() in 900 until 1000 -> "CM" + (this - 900).toRomanNum() @@ -1178,17 +1305,26 @@ object BTeXParser { 0 -> "" else -> throw IllegalArgumentException("Number out of range: $this") } - } + private fun codepointToObjIdChar(c: Int): Char { + return when (c) { + in 0xFFF70..0xFFF79 -> (0x30 + (c - 0xFFF70)).toChar() + in 0xFFF81..0xFFF9A -> (0x41 + (c - 0xFFF81)).toChar() + 0xFFF7D -> '-' + 0xFFF80 -> '@' + else -> throw IllegalArgumentException("Non-object ID char: $c") + } + } + } } private annotation class OpenTag private annotation class CloseTag - } + class BTeXParsingException(s: String) : RuntimeException(s) { } diff --git a/src/net/torvald/terrarum/TerrarumPostProcessor.kt b/src/net/torvald/terrarum/TerrarumPostProcessor.kt index 61366c4ae..ca3486c21 100644 --- a/src/net/torvald/terrarum/TerrarumPostProcessor.kt +++ b/src/net/torvald/terrarum/TerrarumPostProcessor.kt @@ -122,7 +122,7 @@ object TerrarumPostProcessor : Disposable { if (App.scr.magn % 1.0 < 0.0001) Texture.TextureFilter.Nearest else Texture.TextureFilter.Linear ) - postShader(projMat, fbo) + drawFBOwithDither(projMat, fbo) // draw things when F keys are on if (App.IS_DEVELOPMENT_BUILD && KeyToggler.isOn(Input.Keys.F11)) { @@ -243,7 +243,7 @@ object TerrarumPostProcessor : Disposable { 0f,0f,0f,1f, 0f,0f,1f,0f, 0f,1f,0f,0f, 1f,0f,0f,0f, ) - private fun postShader(projMat: Matrix4, fbo: FrameBuffer) { + private fun drawFBOwithDither(projMat: Matrix4, fbo: FrameBuffer) { val shader = if (App.getConfigBoolean("fx_dither")) shaderPostDither