From 49e9b6bcdc99e4159b80524c36a6343b37265fb6 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Sat, 18 May 2024 22:22:00 +0900 Subject: [PATCH] progress indicator for the tester --- src/net/torvald/btex/BTeXDocument.kt | 12 +++- src/net/torvald/btex/BTeXParser.kt | 65 +++++++++++----------- src/net/torvald/terrarum/tests/BTeXTest.kt | 18 +++++- 3 files changed, 58 insertions(+), 37 deletions(-) diff --git a/src/net/torvald/btex/BTeXDocument.kt b/src/net/torvald/btex/BTeXDocument.kt index f6e03ac64..e5ed616b9 100644 --- a/src/net/torvald/btex/BTeXDocument.kt +++ b/src/net/torvald/btex/BTeXDocument.kt @@ -26,6 +26,7 @@ import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap import java.io.File import java.io.RandomAccessFile import java.util.concurrent.Callable +import java.util.concurrent.atomic.AtomicInteger import java.util.zip.Deflater /** @@ -149,14 +150,16 @@ class BTeXDocument : Disposable { @Transient private val fontNum = TinyAlphNum - fun addNewPage(back: Color = DEFAULT_PAGE_BACK) { + fun addNewPage(progressIndicator: AtomicInteger, back: Color = DEFAULT_PAGE_BACK) { pages.add(BTeXPage(this, back, pageDimensionWidth, pageDimensionHeight)) linesPrintedOnPage.add(0) + progressIndicator.getAndAdd(1) } - fun addNewPageAt(index: Int, back: Color = DEFAULT_PAGE_BACK) { + fun addNewPageAt(progressIndicator: AtomicInteger, index: Int, back: Color = DEFAULT_PAGE_BACK) { pages.add(index, BTeXPage(this, back, pageDimensionWidth, pageDimensionHeight)) linesPrintedOnPage.add(index, 0) + progressIndicator.getAndAdd(1) } private val lock = Any() @@ -165,7 +168,7 @@ class BTeXDocument : Disposable { /** * Must be called on a thread with GL context! */ - fun finalise(multithread: Boolean = false) { + fun finalise(progressIndicator: AtomicInteger, multithread: Boolean = false) { synchronized(lock) { if (fromArchive) throw IllegalStateException("Document is loaded from the archive and thus cannot be finalised") if (isFinalised) throw IllegalStateException("Page is already been finalised") @@ -184,6 +187,7 @@ class BTeXDocument : Disposable { page.renderToPixmap(pixmap, 0, 0, pageMarginH, pageMarginV) printPageNumber(pixmap, pageNum, 0, 0) pagePixmaps[pageNum] = pixmap + progressIndicator.getAndAdd(1) } } else { @@ -196,6 +200,8 @@ class BTeXDocument : Disposable { page.renderToPixmap(pixmap, 0, 0, pageMarginH, pageMarginV) printPageNumber(pixmap, pageNum, 0, 0) pagePixmaps[pageNum] = pixmap + progressIndicator.getAndAdd(1) + Unit } } // my experiment tells 4, 8, 16, 32 threads all perform the same diff --git a/src/net/torvald/btex/BTeXParser.kt b/src/net/torvald/btex/BTeXParser.kt index ed2e6f542..e5c605175 100644 --- a/src/net/torvald/btex/BTeXParser.kt +++ b/src/net/torvald/btex/BTeXParser.kt @@ -31,6 +31,7 @@ import org.xml.sax.helpers.DefaultHandler import java.awt.SystemColor.text import java.io.* import java.net.URL +import java.util.concurrent.atomic.AtomicInteger import javax.xml.parsers.SAXParserFactory import kotlin.math.roundToInt import kotlin.reflect.KFunction @@ -46,9 +47,9 @@ object BTeXParser { internal val textTags = hashSetOf("P", "CALLOUT", "TITLE", "AUTHOR", "EDITION", "CHAPTER", "SECTION", "LI") internal val textDecorTags = hashSetOf("SPAN", "CODE") - operator fun invoke(file: FileHandle, varMap: Map) = invoke(file.file(), varMap) + operator fun invoke(file: FileHandle, varMap: Map, progressIndicator: AtomicInteger) = invoke(file.file(), varMap, progressIndicator) - operator fun invoke(file: File, varMap: Map): Pair { + operator fun invoke(file: File, varMap: Map, progressIndicator: AtomicInteger): Pair { val doc = BTeXDocument() val parser = SAXParserFactory.newInstance().let { it.isNamespaceAware = true @@ -56,24 +57,24 @@ object BTeXParser { it.newSAXParser() } val stream = FileInputStream(file) - val handler = BTeXHandler(doc, varMap) + val handler = BTeXHandler(doc, varMap, progressIndicator) parser.parse(stream, handler) return doc to handler } - operator fun invoke(string: String, varMap: Map): Pair { + operator fun invoke(string: String, varMap: Map, progressIndicator: AtomicInteger): Pair { val doc = BTeXDocument() val parser = SAXParserFactory.newInstance().let { it.isNamespaceAware = true it.isValidating = true it.newSAXParser() } - val handler = BTeXHandler(doc, varMap) + val handler = BTeXHandler(doc, varMap, progressIndicator) parser.parse(InputSource(StringReader(string)), handler) return doc to handler } - class BTeXHandler(val doc: BTeXDocument, val varMap: Map) : DefaultHandler() { + class BTeXHandler(val doc: BTeXDocument, val varMap: Map, val progressIndicator: AtomicInteger) : DefaultHandler() { private var cover = "" private var inner = "" private var papersize = "" @@ -787,19 +788,19 @@ object BTeXParser { val coverColLCH = OKLch(hue, 0.05f, 0.36f) val (r, g, b) = coverColLCH.tosRGB() coverCol = Color(r, g, b, 1f) - doc.addNewPage(coverCol!!) + doc.addNewPage(progressIndicator, coverCol!!) } @OpenTag // reflective access is impossible with 'private' fun processElemTOCPAGE(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap) { - doc.addNewPage() // toc: openright + doc.addNewPage(progressIndicator) // toc: openright val header = attribs["title"] ?: "Table of Contents" typesetChapterHeading(null, header, handler, PAR_INDENTATION) } @OpenTag // reflective access is impossible with 'private' fun processElemINDEXPAGE(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap) { - if (doc.currentPageObj.isNotEmpty()) doc.addNewPage() + if (doc.currentPageObj.isNotEmpty()) doc.addNewPage(progressIndicator) val header = attribs["title"] ?: "Index" typesetChapterHeading(null, header, handler, PAR_INDENTATION) } @@ -828,7 +829,7 @@ object BTeXParser { @OpenTag // reflective access is impossible with 'private' fun processElemMANUSCRIPT(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap) { - doc.addNewPage() + doc.addNewPage(progressIndicator) } @CloseTag @@ -854,7 +855,7 @@ object BTeXParser { // insert new pages repeat(pageDelta) { - doc.addNewPageAt(tocPage!! + 1) + doc.addNewPageAt(progressIndicator, tocPage!! + 1) } } @@ -979,7 +980,7 @@ object BTeXParser { // image overflowing? if (doc.pageLines - doc.linesPrintedOnPage.last() < heightInLines) - doc.addNewPage() + doc.addNewPage(progressIndicator) val tempFile = FileHandle.tempFile("btex_$btexObjName") try { @@ -1059,7 +1060,7 @@ object BTeXParser { @OpenTag // reflective access is impossible with 'private' fun processElemNEWPAGE(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap) { - doc.addNewPage() + doc.addNewPage(progressIndicator) } @CloseTag // reflective access is impossible with 'private' @@ -1085,7 +1086,7 @@ object BTeXParser { } } - doc.addNewPage() + doc.addNewPage(progressIndicator) } @OpenTag // reflective access is impossible with 'private' @@ -1237,7 +1238,7 @@ object BTeXParser { @CloseTag fun closeElemCOVER(handler: BTeXHandler, doc: BTeXDocument, uri: String, siblingIndex: Int) { if (hasCover) { - doc.addNewPage() + doc.addNewPage(progressIndicator) } } @@ -1305,7 +1306,7 @@ object BTeXParser { @CloseTag // reflective access is impossible with 'private' fun closeElemPART(handler: BTeXHandler, doc: BTeXDocument, uri: String, siblingIndex: Int) { // if the last page is not empty, create new one - if (doc.currentPageObj.isNotEmpty()) doc.addNewPage() + if (doc.currentPageObj.isNotEmpty()) doc.addNewPage(progressIndicator) val partOrder = cptSectMap.count { it.type.startsWith("part") } + 1 val thePar = paragraphBuffer.toString().trim() @@ -1343,10 +1344,10 @@ object BTeXParser { // if current line is the last line, proceed to the next page - if (doc.linesPrintedOnPage.last() >= doc.pageLines - 2) doc.addNewPage() + if (doc.linesPrintedOnPage.last() >= doc.pageLines - 2) doc.addNewPage(progressIndicator) // if defined by the macro, proceed to the next page if (macrodefs["chapteronnewpage"] != "0" && cptSibling > 1) - doc.addNewPage() + doc.addNewPage(progressIndicator) typesetChapterHeading(invokeMacro("thechapter", cptNumStr), thePar, handler, 16) @@ -1358,7 +1359,7 @@ object BTeXParser { @CloseTag // reflective access is impossible with 'private' fun closeElemSECTION(handler: BTeXHandler, doc: BTeXDocument, uri: String, siblingIndex: Int) { // if current line is the last line, proceed to the next page - if (doc.linesPrintedOnPage.last() >= doc.pageLines - 1) doc.addNewPage() + if (doc.linesPrintedOnPage.last() >= doc.pageLines - 1) doc.addNewPage(progressIndicator) val partOrder = cptSectMap.count { it.type.startsWith("part") } val cptOrder = cptSectMap.count { it.type.startsWith("chapter") } @@ -1421,8 +1422,8 @@ object BTeXParser { fun closeElemBTEXDOC(handler: BTeXHandler, doc: BTeXDocument, uri: String, siblingIndex: Int) { // make sure the last pair ends with paper and end-cover doc.endOfPageStart = doc.currentPage + 1 - if (doc.pages.size % 2 == 1) doc.addNewPage() - doc.addNewPage() + if (doc.pages.size % 2 == 1) doc.addNewPage(progressIndicator) + doc.addNewPage(progressIndicator) } @@ -1523,9 +1524,9 @@ object BTeXParser { // make sure page after the part always openright if (doc.currentPage % 2 == 1) - doc.addNewPage() + doc.addNewPage(progressIndicator) - doc.addNewPage() + doc.addNewPage(progressIndicator) } private fun typesetChapterHeading(num: String?, thePar: String, handler: BTeXHandler, indent: Int = 16, width: Int = doc.textWidth) { @@ -1622,7 +1623,7 @@ object BTeXParser { // printdbg("Page: ${doc.currentPage+1}, Line: ${doc.currentLine}") if (remainder <= 0) { - doc.addNewPage(); pageNum += 1 + doc.addNewPage(progressIndicator); pageNum += 1 } else if (slugHeight > remainder) { val subset = linesOut to remainder @@ -1692,7 +1693,7 @@ object BTeXParser { linesOut += remainder slugHeight -= remainder - doc.addNewPage(); pageNum += 1 + doc.addNewPage(progressIndicator); pageNum += 1 } while (slugHeight > 0) { @@ -1717,8 +1718,8 @@ object BTeXParser { // get width of "word" val searchStrs = slugs.typesettedSlugs.subList(subset.first, subset.first + subset.second) searchStrs.forEach { str -> - printdbg("2HREF searchStr: ${str.toReadable()}") - printdbg("2HREF object: ${objSeq.toReadable()} (id=${hrefDict[objSeq.toReadable()]})") +// printdbg("2HREF searchStr: ${str.toReadable()}") +// printdbg("2HREF object: ${objSeq.toReadable()} (id=${hrefDict[objSeq.toReadable()]})") val indexOfSequence = str.indexOfSequence(objSeq) @@ -1739,8 +1740,8 @@ object BTeXParser { // retrieve the actual word val substr = CodepointSequence(str.subList(wordOffset + 1, wordEnd)) - printdbg("2HREF word: ${substr.toReadable()}") - printdbg("2HREF hrefObj: ${hrefObj}") +// printdbg("2HREF word: ${substr.toReadable()}") +// printdbg("2HREF hrefObj: ${hrefObj}") val hrefX = if (objectIsSplit) 0 else hrefObj.x var hrefY = hrefObj.y; if (objectIsSplit) hrefY += doc.lineHeightInPx @@ -1754,7 +1755,7 @@ object BTeXParser { } // target word is on the next line (probably) else { - printdbg("2HREF object was cut off by the linebreak") +// printdbg("2HREF object was cut off by the linebreak") objectIsSplit = true } } @@ -1768,7 +1769,7 @@ object BTeXParser { slugHeight -= remainder if (remainder == height) { - doc.addNewPage(); pageNum += 1 + doc.addNewPage(progressIndicator); pageNum += 1 } } @@ -1947,7 +1948,7 @@ object BTeXParser { if (doc.linesPrintedOnPage[doc.currentPage] < doc.pageLines) doc.linesPrintedOnPage[doc.currentPage] += 1 else - doc.addNewPage() + doc.addNewPage(progressIndicator) } private data class _HrefObject(val x: Int, val y: Int, val hrefTarget: String) diff --git a/src/net/torvald/terrarum/tests/BTeXTest.kt b/src/net/torvald/terrarum/tests/BTeXTest.kt index 5dfdeffd8..f443a5874 100644 --- a/src/net/torvald/terrarum/tests/BTeXTest.kt +++ b/src/net/torvald/terrarum/tests/BTeXTest.kt @@ -23,6 +23,7 @@ import net.torvald.terrarum.inUse import net.torvald.terrarum.langpack.Lang import net.torvald.terrarum.ui.Toolkit import net.torvald.unicode.EMDASH +import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicReference import kotlin.system.measureTimeMillis @@ -56,6 +57,9 @@ class BTeXTest : ApplicationAdapter() { it.set(null) } + private val typesetProgress = AtomicInteger(0) + private val renderProgress = AtomicInteger(0) + override fun create() { Lang TinyAlphNum @@ -76,7 +80,7 @@ class BTeXTest : ApplicationAdapter() { Thread { try { measureTimeMillis { - val f = BTeXParser.invoke(Gdx.files.internal("./assets/mods/basegame/books/$filePath"), varMap) + val f = BTeXParser.invoke(Gdx.files.internal("./assets/mods/basegame/books/$filePath"), varMap, typesetProgress) document = f.first documentHandler = f.second }.also { @@ -84,7 +88,7 @@ class BTeXTest : ApplicationAdapter() { } measureTimeMillis { - document.finalise(true) + document.finalise(renderProgress, true) }.also { println("Time spent on finalising [ms]: $it") } @@ -151,6 +155,16 @@ class BTeXTest : ApplicationAdapter() { else { batch.color = Color.WHITE Toolkit.drawTextCentered(batch, TinyAlphNum, stage, 1280, 0, 354) + + if (stage.lowercase().startsWith("typesetting")) { + val pgCnt = typesetProgress.get() + Toolkit.drawTextCentered(batch, TinyAlphNum, "Pages: $pgCnt", 1280, 0, 375) + } + else if (stage.lowercase().startsWith("rendering")) { + val pgCnt = document.pages.size + val renderCnt = renderProgress.get() + Toolkit.drawTextCentered(batch, TinyAlphNum, "Pages: $renderCnt/$pgCnt", 1280, 0, 375) + } } }