From 6889ce34a7f528b02928f2f0400409e073a52789 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Sun, 28 Apr 2024 01:21:29 +0900 Subject: [PATCH] btex: text colouring via emph/itemname/targetname/span --- lib/TerrarumSansBitmap.jar | 4 +- src/net/torvald/btex/BTeXDocument.kt | 2 +- src/net/torvald/btex/BTeXParser.kt | 150 ++++++++++++++++----- src/net/torvald/terrarum/tests/BTeXTest.kt | 4 +- 4 files changed, 123 insertions(+), 37 deletions(-) diff --git a/lib/TerrarumSansBitmap.jar b/lib/TerrarumSansBitmap.jar index ef7cbf17a..5afe1caf2 100644 --- a/lib/TerrarumSansBitmap.jar +++ b/lib/TerrarumSansBitmap.jar @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0dcb0794a13e90e145cc57669c8952c424c8db556704181c24596ab4c62325fd -size 190137 +oid sha256:2bb352175a4d7a0b52287c97a4905eaf8d3089789dacccef03c453c632cf8aaa +size 190865 diff --git a/src/net/torvald/btex/BTeXDocument.kt b/src/net/torvald/btex/BTeXDocument.kt index 12e033afe..2bbbc07bc 100644 --- a/src/net/torvald/btex/BTeXDocument.kt +++ b/src/net/torvald/btex/BTeXDocument.kt @@ -128,7 +128,7 @@ class BTeXDrawCall( 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 colour: Color, + var colour: Color, val text: BTeXTextDrawCall? = null, val texture: TextureRegion? = null, ) { diff --git a/src/net/torvald/btex/BTeXParser.kt b/src/net/torvald/btex/BTeXParser.kt index 3dfcd59da..73ae5dcae 100644 --- a/src/net/torvald/btex/BTeXParser.kt +++ b/src/net/torvald/btex/BTeXParser.kt @@ -12,7 +12,9 @@ import net.torvald.terrarum.btex.BTeXDrawCall import net.torvald.terrarum.btex.MovableTypeDrawCall import net.torvald.terrarum.ceilToFloat import net.torvald.terrarum.gameitems.ItemID +import net.torvald.terrarum.toHex 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 @@ -77,9 +79,6 @@ object BTeXParser { private var spanColour: String? = null - private var typeX = 0 - private var typeY = 0 - private val elemOpeners: HashMap> = HashMap() private val elemClosers: HashMap> = HashMap() @@ -97,6 +96,8 @@ object BTeXParser { private val cptSectMap = ArrayList() private var tocPage: Int? = null + private var hasCover = false + init { BTeXHandler::class.declaredFunctions.filter { it.findAnnotation() != null }.forEach { // println("Tag opener: ${it.name}") @@ -187,34 +188,45 @@ object BTeXParser { // printdbg(" End element \t($popped)") } + private var oldSpanColour: String? = null + override fun characters(ch: CharArray, start: Int, length: Int) { val str = String(ch.sliceArray(start until start + length)).replace('\n', ' ').replace(Regex(" +"), " ")//.trim() if (str.isNotEmpty()) { -// printdbg("Characters \t\"$str\"") - paragraphBuffer.append(str) +// printdbg("Characters [col:${spanColour}] \t\"$str\"") + + if (spanColour != oldSpanColour || spanColour != null) { + val col = getSpanColourOrNull().toInternalColourCodeStr() + + if (spanColour != null && paragraphBuffer.last() == '\u000E') { + paragraphBuffer.deleteAt(paragraphBuffer.lastIndex) + } + + paragraphBuffer.append(col) + paragraphBuffer.append(str.replace(" ", " $col")) + } + else { + paragraphBuffer.append(str) + } + + oldSpanColour = spanColour } } - private fun advanceCursorPre(w: Int, h: Int) { - if (typeX + w > pageWidth) { - typeY += LINE_HEIGHT - typeX = 0 - } + private fun Color?.toInternalColourCodeStr(): String { + return if (this == null) "\u000E" + else { + val rgba = this.toRGBA() + val r = rgba.ushr(24).and(255) + 0xF800 + val g = rgba.ushr(16).and(255) + 0xF800 + val b = rgba.ushr(8).and(255) + 0xF800 - if (typeY + h > pageHeight) { - typeX = 0 - typeY = 0 - doc.addNewPage() + return "\u000F" + Char(r) + Char(g) + Char(b) } } - private fun advanceCursorPost(w: Int, h: Int) { - typeX += w - typeY += h - } - private lateinit var testFont: TerrarumSansBitmap private lateinit var titleFont: TerrarumSansBitmap private lateinit var subtitleFont: TerrarumSansBitmap @@ -247,6 +259,8 @@ object BTeXParser { private val hexColRegexRGBshort = Regex("#[0-9a-fA-F]{3,3}") private val hexColRegexRGB = Regex("#[0-9a-fA-F]{6,6}") + private fun getSpanColourOrNull() = if (spanColour == null) null else getSpanColour() + private fun getSpanColour(): Color = if (spanColour == null) DEFAULT_FONTCOL else if (spanColour!!.matches(hexColRegexRGB)) { val rs = spanColour!!.substring(1,3) @@ -451,10 +465,10 @@ object BTeXParser { "examination" to 18, ) - private val ccEmph = TerrarumSansBitmap.toColorCode(0xfd44) - private val ccItemName = TerrarumSansBitmap.toColorCode(0xf37d) - private val ccTargetName = TerrarumSansBitmap.toColorCode(0xf3c4) - private val ccReset = TerrarumSansBitmap.toColorCode(0) + private val ccEmph = "#C11"// TerrarumSansBitmap.toColorCode(0xfd44) + private val ccItemName = "#14C" // TerrarumSansBitmap.toColorCode(0xf37d) + private val ccTargetName = "#170" // TerrarumSansBitmap.toColorCode(0xf3c4) +// private val ccReset = TerrarumSansBitmap.toColorCode(0) @OpenTag // reflective access is impossible with 'private' @@ -496,17 +510,22 @@ object BTeXParser { @OpenTag // reflective access is impossible with 'private' fun processElemEMPH(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap, siblingIndex: Int) { - handler.paragraphBuffer.append(ccEmph) + handler.spanColour = ccEmph } @OpenTag // reflective access is impossible with 'private' fun processElemITEMNAME(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap, siblingIndex: Int) { - handler.paragraphBuffer.append(ccItemName) + handler.spanColour = ccItemName } @OpenTag // reflective access is impossible with 'private' fun processElemTARGETNAME(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap, siblingIndex: Int) { - handler.paragraphBuffer.append(ccTargetName) + handler.spanColour = ccTargetName + } + + @OpenTag // reflective access is impossible with 'private' + fun processElemSPAN(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap, siblingIndex: Int) { + handler.spanColour = attribs["colour"] ?: attribs["color"] } @CloseTag @@ -515,7 +534,7 @@ object BTeXParser { fun closeElemITEMNAME(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, siblingIndex: Int) = closeElemEMPH(handler, doc, theTag, uri, siblingIndex) @CloseTag fun closeElemEMPH(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, siblingIndex: Int) { - handler.paragraphBuffer.append(ccReset) + handler.spanColour = null } @@ -526,11 +545,12 @@ object BTeXParser { @OpenTag // reflective access is impossible with 'private' fun processElemCOVER(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap, siblingIndex: Int) { + hasCover = true val hue = (attribs["hue"]?.toFloatOrNull() ?: 28f) * DEG_TO_RAD val coverCol = OKLch(hue, 0.05f, 0.36f) val (r, g, b) = coverCol.tosRGB() doc.addNewPage(Color(r, g, b, 1f)) - handler.spanColour = "white" +// handler.spanColour = "white" } @OpenTag // reflective access is impossible with 'private' @@ -673,6 +693,12 @@ object BTeXParser { @CloseTag fun closeElemCOVER(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, siblingIndex: Int) { handler.spanColour = null + + if (hasCover) { + doc.pages[0].drawCalls.forEach { + it.colour = Color.WHITE + } + } } @CloseTag // reflective access is impossible with 'private' @@ -697,11 +723,17 @@ object BTeXParser { @OpenTag // reflective access is impossible with 'private' fun processElemCHAPTER(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap, siblingIndex: Int) { - cptSectStack.add(CptSect("chapter", attribs["alt"], doc.currentPage)) + if (attribs["hide"] == null) + cptSectStack.add(CptSect("chapter", attribs["alt"], doc.currentPage)) + else + cptSectStack.add(CptSect("chapter-hidden", attribs["alt"], doc.currentPage)) } @OpenTag // reflective access is impossible with 'private' fun processElemSECTION(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap, siblingIndex: Int) { - cptSectStack.add(CptSect("section", attribs["alt"], doc.currentPage)) + if (attribs["hide"] == null) + cptSectStack.add(CptSect("section", attribs["alt"], doc.currentPage)) + else + cptSectStack.add(CptSect("section-hidden", attribs["alt"], doc.currentPage)) } @CloseTag // reflective access is impossible with 'private' fun closeElemCHAPTER(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, siblingIndex: Int) { @@ -712,7 +744,8 @@ object BTeXParser { typesetChapterHeading(thePar, handler, 16) val cptSectInfo = cptSectStack.removeLast() - cptSectMap.add(CptSectInfo("chapter", cptSectInfo.alt ?: thePar, cptSectInfo.pagenum)) + if (!cptSectInfo.type.endsWith("-hidden")) + cptSectMap.add(CptSectInfo("chapter", cptSectInfo.alt ?: thePar, cptSectInfo.pagenum)) handler.paragraphBuffer.clear() } @@ -725,7 +758,8 @@ object BTeXParser { typesetSectionHeading(thePar, handler, 8) val cptSectInfo = cptSectStack.removeLast() - cptSectMap.add(CptSectInfo("section", cptSectInfo.alt ?: thePar, cptSectInfo.pagenum)) + if (!cptSectInfo.type.endsWith("-hidden")) + cptSectMap.add(CptSectInfo("section", cptSectInfo.alt ?: thePar, cptSectInfo.pagenum)) handler.paragraphBuffer.clear() } @@ -863,12 +897,64 @@ object BTeXParser { } } + // apply internal colour codes + // grammar: + // [0-9A-F]{6,6} : apply colour code + // : remove colour code + drawCalls.forEach { + if (it.text != null && it.text is MovableTypeDrawCall) { + it.text.movableType.typesettedSlugs.forEach { slug -> slug.forEach { block -> + val blockText = block.block.text + +// println(blockText.toReadable()) + + if (blockText.startsWithColourCode()) { + block.colour = blockText.getCCorNull() + } + } } + } + } + // if typesetting the paragraph leaves the first line of new page empty, move the "row cursor" back up if (doc.linesPrintedOnPage[pageNum] == 1 && doc.pages[pageNum].isEmpty()) doc.linesPrintedOnPage[pageNum] = 0 // '\n' adds empty draw call to the page, which makes isEmpty() to return false return drawCalls } + /*private fun CodepointSequence.toReadable() = this.joinToString("") { + if (it in 0x00..0x1f) + "${(0x2400 + it).toChar()}" + else if (it == 0x20) + "\u2423" + else if (it == NBSP) + "{NBSP}" + else if (it == SHY) + "{SHY}" + else if (it == ZWSP) + "{ZWSP}" + else if (it >= 0xF0000) + it.toHex() + " " + else + Character.toString(it.toChar()) + }*/ + + private fun CodepointSequence.startsWithColourCode() = (this.size > 5 && + this[1] == 0x0F && + (this[2] in 0xF800..0xF8FF) && + (this[3] in 0xF800..0xF8FF) && + (this[4] in 0xF800..0xF8FF)) || + (this.size > 3 && this[0] == 0x0E) + + private fun CodepointSequence.getCCorNull(): Color? { + if (this[1] == 0x0F) { + val r = this[2] - 0xF800 + val g = this[3] - 0xF800 + val b = this[4] - 0xF800 + return Color(r / 255f, g / 255f, b / 255f, 1f) + } + else return null + } + private fun typesetTOCline(name: String, pageNum: Int, handler: BTeXHandler, indentation: Int = 0, pageToWrite: Int? = null) { val pageNum = pageNum.plus(1).toString() val pageNumWidth = getFont().getWidth(pageNum) diff --git a/src/net/torvald/terrarum/tests/BTeXTest.kt b/src/net/torvald/terrarum/tests/BTeXTest.kt index 51afb2d8d..84a4d9041 100644 --- a/src/net/torvald/terrarum/tests/BTeXTest.kt +++ b/src/net/torvald/terrarum/tests/BTeXTest.kt @@ -44,7 +44,7 @@ class BTeXTest : ApplicationAdapter() {

This example book is designed to give you the example of the Book Language.

-
What Really Is a Book
+
What Really Is a Book

A book is a collection of texts printed in a special way that allows them to be read easily, with enumerable pages and insertion of other helpful resources, such as illustrations and hyperlinks.

@@ -56,7 +56,7 @@ class BTeXTest : ApplicationAdapter() { -

text emph and 􏃯item􀀀 on target

+

text emph and item on target