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