btex using xml wip

This commit is contained in:
minjaesong
2023-10-28 16:51:23 +09:00
parent 76d6579ce9
commit 991a16e6a7
6 changed files with 518 additions and 0 deletions

View File

@@ -0,0 +1,93 @@
package net.torvald.terrarum.btex
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.g2d.BitmapFont
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.graphics.g2d.TextureRegion
import net.torvald.terrarum.App
import net.torvald.terrarum.ui.Toolkit
/**
* Created by minjaesong on 2023-10-28.
*/
class BTeXDocument {
var context = "tome" // tome (cover=hardcover), sheets (cover=typewriter or cover=printout), examination (def=examination)
var font = "default" // default or typewriter
var inner = "standard"
var papersize = "standard"
var pageWidth = 420
var pageHeight = 25 * 24
companion object {
val DEFAULT_PAGE_BACK = Color(0xe1e1d7ff.toInt())
val DEFAULT_PAGE_FORE = Color(0x131311ff)
}
private val pages = ArrayList<BTeXPage>()
fun addNewPage(back: Color = DEFAULT_PAGE_BACK) {
pages.add(BTeXPage(back, pageWidth, pageHeight))
}
fun appendDrawCall(drawCall: BTeXDrawCall) {
pages.last().appendDrawCall(drawCall)
}
fun render(batch: SpriteBatch, page: Int, x: Int, y: Int) {
pages[page].render(batch, x, y)
}
}
class BTeXPage(
val back: Color,
val width: Int,
val height: Int,
) {
private val drawCalls = ArrayList<BTeXDrawCall>()
fun appendDrawCall(drawCall: BTeXDrawCall) {
drawCalls.add(drawCall)
}
fun render(batch: SpriteBatch, x: Int, y: Int) {
batch.color = back
Toolkit.fillArea(batch, x, y, width, height)
drawCalls.forEach {
it.draw(batch, x, y)
}
}
}
class BTeXDrawCall(
val posX: Int,
val posY: Int,
val theme: String,
val colour: Color,
val font: BitmapFont,
val text: String? = null,
val texture: TextureRegion? = null,
) {
fun draw(batch: SpriteBatch, x: Int, y: Int) {
val px = (posX + x).toFloat()
val py = (posY + y).toFloat()
if (theme == "code") {
// todo draw code background
}
batch.color = colour
if (text != null && texture == null) {
font.draw(batch, text, px, py)
}
else if (text == null && texture != null) {
batch.draw(texture, px, py)
}
else throw Error("Text and Texture are both non-null")
}
}

View File

@@ -0,0 +1,159 @@
package net.torvald.btex
import com.badlogic.gdx.files.FileHandle
import com.badlogic.gdx.graphics.Color
import net.torvald.terrarum.App
import net.torvald.terrarum.btex.BTeXDocument
import net.torvald.terrarum.btex.BTeXDrawCall
import net.torvald.terrarum.gameitems.ItemID
import org.xml.sax.Attributes
import org.xml.sax.helpers.DefaultHandler
import java.io.*
import java.util.*
import javax.xml.parsers.SAXParserFactory
/**
* Created by minjaesong on 2023-10-28.
*/
object BTeXParser {
operator fun invoke(file: FileHandle) = invoke(file.file())
operator fun invoke(file: File): BTeXDocument {
val doc = BTeXDocument()
val parser = SAXParserFactory.newDefaultInstance().newSAXParser()
val stream = FileInputStream(file)
parser.parse(stream, BTeXHandler(doc))
return doc
}
private class BTeXHandler(val doc: BTeXDocument) : DefaultHandler() {
private val DEFAULT_FONTCOL = Color(0x222222ff)
private val LINE_HEIGHT = 24
private var cover = ""
private var inner = ""
private var papersize = ""
private var def = ""
private var pageWidth = 420
private var pageLines = 25
private var pageHeight = 25 * LINE_HEIGHT
private val blockLut = HashMap<String, ItemID>()
private val tagStack = ArrayList<String>() // index zero should be "btex"
private var spanColour: String? = null
private var typeX = 0
private var typeY = 0
override fun startElement(uri: String, localName: String, qName: String, attributes: Attributes) {
val tag = qName; if (tagStack.isEmpty() && tag != "btex") throw BTeXParsingException("Document is not btex")
tagStack.add(tag)
val attribs = HashMap<String, String>().also {
it.putAll((0 until attributes.length).map { attributes.getQName(it) to attributes.getValue(it) })
}
val mode = tagStack.getOrNull(1)
when (tag) {
"btex" -> {
if (attribs.containsKey("def"))
def = attribs["def"]!!
else {
cover = attribs["cover"] ?: "printout"
inner = attribs["inner"] ?: "standard"
papersize = attribs["papersize"] ?: "standard"
pageWidth = pageWidthMap[papersize]!!
pageLines = pageHeightMap[papersize]!!
pageHeight = pageLines * LINE_HEIGHT
doc.pageWidth = pageWidth
doc.pageHeight = pageHeight
}
}
"pair" -> {
if (tagStack.size == 3 && mode == "blocklut") {
blockLut[attribs["key"]!!] = attribs["value"]!!
}
else {
throw BTeXParsingException("<pair> used outside of <blocklut>")
}
}
"span" -> {
attribs["span"]?.let {
spanColour = it
}
}
}
}
override fun endElement(uri: String, localName: String, qName: String) {
tagStack.removeLast()
when (qName) {
"span" -> {
spanColour = null
}
}
}
override fun characters(ch: CharArray, start: Int, length: Int) {
val str = String(ch.sliceArray(start until start+length)).replace('\n',' ').replace(Regex(" +"), " ").trim()
val font = getFont()
advanceCursorPre(font.getWidth(str), 0)
doc.appendDrawCall(BTeXDrawCall(typeX, typeY, inner, getSpanColour(), font, str))
advanceCursorPost(font.getWidth(str), 0)
}
private fun advanceCursorPre(w: Int, h: Int) {
if (typeX + w > pageWidth) {
typeY += LINE_HEIGHT
typeX = 0
}
if (typeY + h > pageHeight) {
typeX = 0
typeY = 0
doc.addNewPage()
}
}
private fun advanceCursorPost(w: Int, h: Int) {
typeX += w
typeY += h
}
private fun getFont() = when (cover) {
"typewriter" -> TODO()
else -> App.fontGame
}
private fun getSpanColour(): Color = spanColourMap.getOrDefault(spanColour, DEFAULT_FONTCOL)
private val spanColourMap = hashMapOf(
"grey" to Color.LIGHT_GRAY
)
private val pageWidthMap = hashMapOf(
"standard" to 420
)
private val pageHeightMap = hashMapOf(
"standard" to 25
)
}
}
class BTeXParsingException(s: String) : RuntimeException(s) {
}