Terrarum Sans Bitmap imple on GDX -- wip

This commit is contained in:
minjaesong
2017-06-16 15:09:19 +09:00
parent 12c6f6fd04
commit 87242da9cc
6 changed files with 673 additions and 91 deletions

View File

@@ -0,0 +1,7 @@
package net.torvald.terrarum
/**
* Created by minjaesong on 2017-06-15.
*/
object TerrarumGDX {
}

View File

@@ -6,8 +6,9 @@ import com.badlogic.gdx.backends.lwjgl.LwjglApplication
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration
import com.badlogic.gdx.graphics.GL20
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.BitmapFont
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import net.torvald.terrarumsansbitmap.gdx.GameFontBase
/**
@@ -18,17 +19,26 @@ class TestTestTest : ApplicationAdapter() {
lateinit var batch: SpriteBatch
lateinit var img: Texture
lateinit var gameFont: BitmapFont
override fun create() {
batch = SpriteBatch()
img = Texture("assets/test_texture.tga")
gameFont = GameFontBase(false)
//gameFont = BitmapFont()
}
override fun render() {
Gdx.gl.glClearColor(1f, 0f, 0f, 1f)
Gdx.gl.glClearColor(0f, 0f, 0f, 1f)
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
batch.begin()
batch.draw(img, 0f, 0f)
batch.end()
Gdx.graphics.setTitle("$GAME_NAME — F: ${Gdx.graphics.framesPerSecond}")
batch.inBatch {
gameFont.draw(batch, "Hello, world!", 10f, 30f)
}
}
override fun dispose() {
@@ -36,9 +46,18 @@ class TestTestTest : ApplicationAdapter() {
img.dispose()
}
private inline fun SpriteBatch.inBatch(action: () -> Unit) {
this.begin()
action()
this.end()
}
}
fun main(args: Array<String>) { // LWJGL 3 won't work? java.lang.VerifyError
val config = LwjglApplicationConfiguration()
config.useGL30 = true
config.vSyncEnabled = false
//config.foregroundFPS = 9999
LwjglApplication(TestTestTest(), config)
}

View File

@@ -0,0 +1,544 @@
package net.torvald.terrarumsansbitmap.gdx
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.Pixmap
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.*
import com.badlogic.gdx.utils.Array
import net.torvald.spriteanimation.TextureRegionPack
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileOutputStream
import java.util.zip.GZIPInputStream
/**
* LibGDX port of Terrarum Sans Bitmap implementation
*
* Filename and Extension for the spritesheet is hard-coded, which are:
*
* - ascii_variable.tga
* - hangul_johab.tga
* - LatinExtA_variable.tga
* - LatinExtB_variable.tga
* - kana.tga
* - cjkpunct.tga
* - wenquanyi.tga.gz
* - cyrillic_variable.tga
* - fullwidth_forms.tga
* - unipunct_variable.tga
* - greek_variable.tga
* - thai_variable.tga
* - puae000-e0ff.tga
*
*
* Glyphs are drawn lazily (calculated on-the-fly, rather than load up all), which is inevitable as we just can't load
* up 40k+ characters on the machine, which will certainly make loading time painfully long.
*
* Created by minjaesong on 2017-06-15.
*/
class GameFontBase(val noShadow: Boolean) : BitmapFont() {
private fun getHanChosung(hanIndex: Int) = hanIndex / (JUNG_COUNT * JONG_COUNT)
private fun getHanJungseong(hanIndex: Int) = hanIndex / JONG_COUNT % JUNG_COUNT
private fun getHanJongseong(hanIndex: Int) = hanIndex % JONG_COUNT
private val jungseongWide = arrayOf(8, 12, 13, 17, 18, 21)
private val jungseongComplex = arrayOf(9, 10, 11, 14, 15, 16, 22)
private fun isJungseongWide(hanIndex: Int) = jungseongWide.contains(getHanJungseong(hanIndex))
private fun isJungseongComplex(hanIndex: Int) = jungseongComplex.contains(getHanJungseong(hanIndex))
private fun getHanInitialRow(hanIndex: Int): Int {
val ret: Int
if (isJungseongWide(hanIndex))
ret = 2
else if (isJungseongComplex(hanIndex))
ret = 4
else
ret = 0
return if (getHanJongseong(hanIndex) == 0) ret else ret + 1
}
private fun getHanMedialRow(hanIndex: Int) = if (getHanJongseong(hanIndex) == 0) 6 else 7
private fun getHanFinalRow(hanIndex: Int): Int {
val jungseongIndex = getHanJungseong(hanIndex)
return if (jungseongWide.contains(jungseongIndex))
8
else
9
}
private fun isHangul(c: Char) = c.toInt() in 0xAC00..0xD7A3
private fun isAscii(c: Char) = c.toInt() in 0x20..0xFF
//private fun isRunic(c: Char) = runicList.contains(c)
private fun isExtA(c: Char) = c.toInt() in 0x100..0x17F
private fun isExtB(c: Char) = c.toInt() in 0x180..0x24F
private fun isKana(c: Char) = c.toInt() in 0x3040..0x30FF
private fun isCJKPunct(c: Char) = c.toInt() in 0x3000..0x303F
private fun isUniHan(c: Char) = c.toInt() in 0x3400..0x9FFF
private fun isCyrilic(c: Char) = c.toInt() in 0x400..0x45F
private fun isFullwidthUni(c: Char) = c.toInt() in 0xFF00..0xFF1F
private fun isUniPunct(c: Char) = c.toInt() in 0x2000..0x206F
private fun isGreek(c: Char) = c.toInt() in 0x370..0x3CE
private fun isThai(c: Char) = c.toInt() in 0xE00..0xE7F
private fun isThaiDiacritics(c: Char) = c.toInt() in 0xE34..0xE3A
|| c.toInt() in 0xE47..0xE4E
|| c.toInt() == 0xE31
private fun isCustomSym(c: Char) = c.toInt() in 0xE000..0xE0FF
private fun extAindexX(c: Char) = (c.toInt() - 0x100) % 16
private fun extAindexY(c: Char) = (c.toInt() - 0x100) / 16
private fun extBindexX(c: Char) = (c.toInt() - 0x180) % 16
private fun extBindexY(c: Char) = (c.toInt() - 0x180) / 16
//private fun runicIndexX(c: Char) = runicList.indexOf(c) % 16
//private fun runicIndexY(c: Char) = runicList.indexOf(c) / 16
private fun kanaIndexX(c: Char) = (c.toInt() - 0x3040) % 16
private fun kanaIndexY(c: Char) = (c.toInt() - 0x3040) / 16
private fun cjkPunctIndexX(c: Char) = (c.toInt() - 0x3000) % 16
private fun cjkPunctIndexY(c: Char) = (c.toInt() - 0x3000) / 16
private fun cyrilicIndexX(c: Char) = (c.toInt() - 0x400) % 16
private fun cyrilicIndexY(c: Char) = (c.toInt() - 0x400) / 16
private fun fullwidthUniIndexX(c: Char) = (c.toInt() - 0xFF00) % 16
private fun fullwidthUniIndexY(c: Char) = (c.toInt() - 0xFF00) / 16
private fun uniPunctIndexX(c: Char) = (c.toInt() - 0x2000) % 16
private fun uniPunctIndexY(c: Char) = (c.toInt() - 0x2000) / 16
private fun unihanIndexX(c: Char) = (c.toInt() - 0x3400) % 256
private fun unihanIndexY(c: Char) = (c.toInt() - 0x3400) / 256
private fun greekIndexX(c: Char) = (c.toInt() - 0x370) % 16
private fun greekIndexY(c: Char) = (c.toInt() - 0x370) / 16
private fun thaiIndexX(c: Char) = (c.toInt() - 0xE00) % 16
private fun thaiIndexY(c: Char) = (c.toInt() - 0xE00) / 16
private fun symbolIndexX(c: Char) = (c.toInt() - 0xE000) % 16
private fun symbolIndexY(c: Char) = (c.toInt() - 0xE000) / 16
private val unihanWidthSheets = arrayOf(
SHEET_UNIHAN,
SHEET_FW_UNI,
SHEET_UNIHAN
)
private val variableWidthSheets = arrayOf(
SHEET_ASCII_VARW,
SHEET_CYRILIC_VARW,
SHEET_EXTA_VARW,
SHEET_GREEK_VARW,
SHEET_EXTB_VARW,
SHEET_THAI_VARW
)
private val fontParentDir = "assets/graphics/fonts/"
private val fileList = arrayOf( // MUST BE MATCHING WITH SHEET INDICES!!
"ascii_variable.tga",
"hangul_johab.tga",
"LatinExtA_variable.tga",
"LatinExtB_variable.tga",
"kana.tga",
"cjkpunct.tga",
"wenquanyi.tga.gz",
"cyrilic_variable.tga",
"fullwidth_forms.tga",
"unipunct_variable.tga",
"greek_variable.tga",
"thai_variable.tga",
"puae000-e0ff.tga"
)
private val codeRange = arrayOf( // MUST BE MATCHING WITH SHEET INDICES!!
0..0xFF,
0xAC00..0xD7A4,
0x100..0x17F,
0x180..0x24F,
0x3040..0x30FF,
0x3000..0x303F,
0x3400..0x9FFF,
0x400..0x45F,
0xFF00..0xFF1F,
0x2000..0x206F,
0x370..0x3CE,
0xE00..0xE7F,
0xE000..0xE0FF
)
private val sheets = arrayOf( // MUST BE MATCHING WITH SHEET INDICES!!
asciiSheet,
hangulSheet,
extASheet,
extBSheet,
kanaSheet,
cjkPunct,
uniHan,
cyrilic,
fullwidthForms,
uniPunct,
greekSheet,
thaiSheet,
customSheet
)
init {
// first we create pixmap to read pixels, then make texture using pixmap
fileList.forEachIndexed { index, it ->
val isVariable = it.endsWith("_variable.tga")
val pixmap: Pixmap
// unpack gz if applicable
if (it.endsWith(".gz")) {
val gzi = GZIPInputStream(Gdx.files.internal(fontParentDir + it).read(8192))
val wholeFile = gzi.readBytes()
gzi.close()
val fos = BufferedOutputStream(FileOutputStream("tmp_wenquanyi.tga"))
fos.write(wholeFile)
fos.flush()
fos.close()
pixmap = Pixmap(Gdx.files.internal("tmp_wenquanyi.tga"))
File("tmp_wenquanyi.tga").delete()
}
else {
pixmap = Pixmap(Gdx.files.internal(fontParentDir + it))
}
if (isVariable) {
buildWidthTable(pixmap, codeRange[index].first, codeRange[index])
}
val texture = Texture(pixmap)
val texRegPack = if (isVariable) {
TextureRegionPack(texture, W_VAR_INIT, H, HGAP_VAR, 0)
}
else if (index == SHEET_UNIHAN || index == SHEET_FW_UNI) {
TextureRegionPack(texture, W_UNIHAN, H_UNIHAN)
}
else if (index == SHEET_CJK_PUNCT) {
TextureRegionPack(texture, W_ASIAN_PUNCT, H)
}
else if (index == SHEET_KANA) {
TextureRegionPack(texture, W_KANA, H)
}
else if (index == SHEET_HANGUL) {
TextureRegionPack(texture, W_HANGUL, H)
}
else if (index == SHEET_CUSTOM_SYM) {
TextureRegionPack(texture, SIZE_CUSTOM_SYM, SIZE_CUSTOM_SYM) // TODO variable
}
else throw IllegalArgumentException("Unknown sheet index: $index")
sheets[index] = texRegPack
pixmap.dispose() // you are terminated
}
}
override fun getLineHeight(): Float = H.toFloat()
override fun getXHeight() = lineHeight
override fun getCapHeight() = lineHeight
override fun getAscent() = 0f
override fun getDescent() = 0f
override fun isFlipped() = false
override fun setFixedWidthGlyphs(glyphs: CharSequence) {
throw UnsupportedOperationException("Nope, no monospace, and figures are already fixed width, bruv.")
}
init {
setUseIntegerPositions(true)
setOwnsTexture(true)
}
private var microBuffer: CharSequence = ""
private var microBWidth = intArrayOf() // absolute posX of glyphs from print-origin
override fun draw(batch: Batch, str: CharSequence, x: Float, y: Float): GlyphLayout? {
if (microBuffer != str) {
microBuffer = str
val widths = getWidthOfCharSeq(str)
microBWidth = Array(str.length, { charIndex ->
if (charIndex == 0)
0
else {
var acc = 0
(0..charIndex - 1).forEach { acc += widths[it] }
/*return*/acc
}
}).toIntArray()
}
//print("[gamefontbase] widthTable for $microBuffer: ")
//microBWidth.forEach { print("$it ") }; println()
microBuffer.forEachIndexed { index, c ->
val sheetID = getSheetType(c)
val sheetXY = getSheetwisePosition(c)
batch.draw(
sheets[sheetID]!!.get(sheetXY[0], sheetXY[1]),
x + microBWidth[index], y
)
}
return null
}
override fun dispose() {
super.dispose()
sheets.forEach { it!!.dispose() }
}
private fun getWidthOfCharSeq(s: CharSequence): IntArray {
val len = IntArray(s.length)
for (i in 0..s.lastIndex) {
val chr = s[i]
val ctype = getSheetType(s[i])
if (variableWidthSheets.contains(ctype)) {
len[i] = try {
glyphWidths[chr.toInt()]!!
}
catch (e: kotlin.KotlinNullPointerException) {
println("KotlinNullPointerException on glyph number ${Integer.toHexString(chr.toInt()).toUpperCase()}")
//System.exit(1)
W_LATIN_WIDE // failsafe
}
}
else if (ctype == SHEET_CJK_PUNCT)
len[i] = W_ASIAN_PUNCT
else if (ctype == SHEET_HANGUL)
len[i] = W_HANGUL
else if (ctype == SHEET_KANA)
len[i] = W_KANA
else if (unihanWidthSheets.contains(ctype))
len[i] = W_UNIHAN
else if (isThaiDiacritics(s[i]))
len[i] = 0 // set width of the glyph as -W_LATIN_WIDE
else if (ctype == SHEET_CUSTOM_SYM)
len[i] = SIZE_CUSTOM_SYM
else
len[i] = W_LATIN_WIDE
if (scale > 1) len[i] *= scale
if (i < s.lastIndex) len[i] += interchar
}
return len
}
private fun getSheetType(c: Char): Int {
if (isHangul(c))
return SHEET_HANGUL
else if (isKana(c))
return SHEET_KANA
else if (isUniHan(c))
return SHEET_UNIHAN
else if (isAscii(c))
return SHEET_ASCII_VARW
else if (isExtA(c))
return SHEET_EXTA_VARW
else if (isExtB(c))
return SHEET_EXTB_VARW
else if (isCyrilic(c))
return SHEET_CYRILIC_VARW
else if (isUniPunct(c))
return SHEET_UNI_PUNCT
else if (isCJKPunct(c))
return SHEET_CJK_PUNCT
else if (isFullwidthUni(c))
return SHEET_FW_UNI
else if (isGreek(c))
return SHEET_GREEK_VARW
else if (isThai(c))
return SHEET_THAI_VARW
else if (isCustomSym(c))
return SHEET_CUSTOM_SYM
else
return SHEET_UNKNOWN// fixed width punctuations
// fixed width
// fallback
}
private fun getSheetwisePosition(ch: Char): IntArray {
val sheetX: Int; val sheetY: Int
when (getSheetType(ch)) {
SHEET_EXTA_VARW -> {
sheetX = extAindexX(ch)
sheetY = extAindexY(ch)
}
SHEET_EXTB_VARW -> {
sheetX = extBindexX(ch)
sheetY = extBindexY(ch)
}
SHEET_KANA -> {
sheetX = kanaIndexX(ch)
sheetY = kanaIndexY(ch)
}
SHEET_CJK_PUNCT -> {
sheetX = cjkPunctIndexX(ch)
sheetY = cjkPunctIndexY(ch)
}
SHEET_CYRILIC_VARW -> {
sheetX = cyrilicIndexX(ch)
sheetY = cyrilicIndexY(ch)
}
SHEET_FW_UNI -> {
sheetX = fullwidthUniIndexX(ch)
sheetY = fullwidthUniIndexY(ch)
}
SHEET_UNI_PUNCT -> {
sheetX = uniPunctIndexX(ch)
sheetY = uniPunctIndexY(ch)
}
SHEET_GREEK_VARW -> {
sheetX = greekIndexX(ch)
sheetY = greekIndexY(ch)
}
SHEET_THAI_VARW -> {
sheetX = thaiIndexX(ch)
sheetY = thaiIndexY(ch)
}
SHEET_CUSTOM_SYM -> {
sheetX = symbolIndexX(ch)
sheetY = symbolIndexY(ch)
}
else -> {
sheetX = ch.toInt() % 16
sheetY = ch.toInt() / 16
}
}
return intArrayOf(sheetX, sheetY)
}
fun buildWidthTable(pixmap: Pixmap, codeOffset: Int, codeRange: IntRange, rows: Int = 16) {
val binaryCodeOffset = 15
val cellW = 16
val cellH = 20
// control chars
for (ccode in codeRange) {
val glyphX = ccode % rows
val glyphY = ccode / rows
val codeStartX = (glyphX * cellW) + binaryCodeOffset
val codeStartY = (glyphY * cellH)
var glyphWidth = 0
for (downCtr in 0..3) {
// if ALPHA is not zero, assume it's 1
if (pixmap.getPixel(codeStartX, codeStartY + downCtr).and(0xFF) != 0) {
glyphWidth = glyphWidth or (1 shl downCtr)
}
}
glyphWidths[codeOffset + ccode] = glyphWidth
}
}
companion object {
internal val glyphWidths: HashMap<Int, Int> = HashMap()
internal var hangulSheet: TextureRegionPack? = null
internal var asciiSheet: TextureRegionPack? = null
internal var runicSheet: TextureRegionPack? = null
internal var extASheet: TextureRegionPack? = null
internal var extBSheet: TextureRegionPack? = null
internal var kanaSheet: TextureRegionPack? = null
internal var cjkPunct: TextureRegionPack? = null
internal var uniHan: TextureRegionPack? = null
internal var cyrilic: TextureRegionPack? = null
internal var fullwidthForms: TextureRegionPack? = null
internal var uniPunct: TextureRegionPack? = null
internal var greekSheet: TextureRegionPack? = null
internal var thaiSheet: TextureRegionPack? = null
internal var customSheet: TextureRegionPack? = null
internal val JUNG_COUNT = 21
internal val JONG_COUNT = 28
internal val W_ASIAN_PUNCT = 10
internal val W_HANGUL = 12
internal val W_KANA = 12
internal val W_UNIHAN = 16
internal val W_LATIN_WIDE = 9 // width of regular letters
internal val W_VAR_INIT = 15
internal val HGAP_VAR = 1
internal val H = 20
internal val H_UNIHAN = 16
internal val SIZE_CUSTOM_SYM = 18
internal val SHEET_ASCII_VARW = 0
internal val SHEET_HANGUL = 1
internal val SHEET_EXTA_VARW = 2
internal val SHEET_EXTB_VARW = 3
internal val SHEET_KANA = 4
internal val SHEET_CJK_PUNCT = 5
internal val SHEET_UNIHAN = 6
internal val SHEET_CYRILIC_VARW = 7
internal val SHEET_FW_UNI = 8
internal val SHEET_UNI_PUNCT = 9
internal val SHEET_GREEK_VARW = 10
internal val SHEET_THAI_VARW = 11
internal val SHEET_CUSTOM_SYM = 12
internal val SHEET_UNKNOWN = 254
/**
* Runic letters list used for game. The set is
* Younger Futhark + Medieval rune 'e' + Punct + Runic Almanac
* BEWARE OF SIMILAR-LOOKING RUNES, especially:
* * Algiz ᛉ instead of Maðr ᛘ
* * Short-Twig Hagall ᚽ instead of Runic Letter E ᛂ
* * Runic Letter OE ᚯ instead of Óss ᚬ
* Examples:
* ᛭ᛋᛁᚴᚱᛁᚦᛦ᛭
* ᛭ᛂᛚᛋᛅ᛭ᛏᚱᚢᛏᚾᛁᚾᚴᚢᚾᛅ᛬ᛅᚱᚾᛅᛏᛅᛚᛋ
*/
//internal val runicList = arrayOf('ᚠ', 'ᚢ', 'ᚦ', 'ᚬ', 'ᚱ', 'ᚴ', 'ᚼ', 'ᚾ', '', 'ᛅ', 'ᛋ', 'ᛏ', 'ᛒ', 'ᛘ', 'ᛚ', 'ᛦ', 'ᛂ', '', '᛫', '', 'ᛮ', 'ᛯ', 'ᛰ')
// TODO expand to full Unicode runes
var interchar = 0
var scale = 1
set(value) {
if (value > 0) field = value
else throw IllegalArgumentException("Font scale cannot be zero or negative (input: $value)")
}
}
}

View File

@@ -0,0 +1,45 @@
package net.torvald.terrarumsansbitmap.gdx
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.TextureRegion
/**
* Created by minjaesong on 2017-06-15.
*/
class TextureRegionPack(
val texture: Texture,
val tileW: Int,
val tileH: Int,
val hGap: Int = 0,
val vGap: Int = 0,
val hFrame: Int = 0,
val vFrame: Int = 0
) {
val regions: Array<TextureRegion>
private val horizontalCount = (texture.width - 2 * hFrame + hGap) / (tileW + hGap)
private val verticalCount = (texture.height - 2 * vFrame + vGap) / (tileH + vGap)
init {
println("texture: $texture, dim: ${texture.width} x ${texture.height}, grid: $horizontalCount x $verticalCount, cellDim: $tileW x $tileH")
regions = Array<TextureRegion>(horizontalCount * verticalCount, {
val region = TextureRegion()
val rx = (it % horizontalCount * (tileW + hGap)) + hFrame
val ry = (it / horizontalCount * (tileH + vGap)) + vFrame
region.setRegion(texture)
region.setRegion(rx, ry, tileW, tileH)
/*return*/region
})
}
fun get(x: Int, y: Int) = regions[y * horizontalCount + x]
fun dispose() {
texture.dispose()
}
}

View File

@@ -1,6 +1,5 @@
package net.torvald.imagefont
package net.torvald.terrarumsansbitmap.slick2d
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.getPixel
import org.lwjgl.opengl.GL11
import org.newdawn.slick.*
@@ -11,17 +10,8 @@ import java.util.*
*/
open class GameFontBase(val noShadow: Boolean) : Font {
private fun getHan(hanIndex: Int): IntArray {
val han_x = hanIndex % JONG_COUNT
val han_y = hanIndex / JONG_COUNT
val ret = intArrayOf(han_x, han_y)
return ret
}
private fun getHanChosung(hanIndex: Int) = hanIndex / (JUNG_COUNT * JONG_COUNT)
private fun getHanJungseong(hanIndex: Int) = hanIndex / JONG_COUNT % JUNG_COUNT
private fun getHanJongseong(hanIndex: Int) = hanIndex % JONG_COUNT
private val jungseongWide = arrayOf(8, 12, 13, 17, 18, 21)
@@ -70,8 +60,7 @@ open class GameFontBase(val noShadow: Boolean) : Font {
private fun isThaiDiacritics(c: Char) = c.toInt() in 0xE34..0xE3A
|| c.toInt() in 0xE47..0xE4E
|| c.toInt() == 0xE31
private fun isThaiEF(c: Char) = c.toInt() == 0xE40
private fun isKeycap(c: Char) = c.toInt() in 0xE000..0xE0FF
private fun isCustomSym(c: Char) = c.toInt() in 0xE000..0xE0FF
@@ -108,9 +97,6 @@ open class GameFontBase(val noShadow: Boolean) : Font {
private fun thaiIndexX(c: Char) = (c.toInt() - 0xE00) % 16
private fun thaiIndexY(c: Char) = (c.toInt() - 0xE00) / 16
private fun thaiNarrowIndexX(c: Char) = 3
private fun thaiNarrowIndexY(c: Char) = 0
private fun keycapIndexX(c: Char) = (c.toInt() - 0xE000) % 16
private fun keycapIndexY(c: Char) = (c.toInt() - 0xE000) / 16
@@ -119,15 +105,13 @@ open class GameFontBase(val noShadow: Boolean) : Font {
SHEET_FW_UNI,
SHEET_UNIHAN
)
private val zeroWidthSheets = arrayOf(
SHEET_COLOURCODE
)
private val variableWidthSheets = arrayOf(
SHEET_ASCII_VARW,
SHEET_CYRILIC_VARW,
SHEET_EXTA_VARW,
SHEET_GREEK_VARW,
SHEET_EXTB_VARW
SHEET_EXTB_VARW,
SHEET_THAI_VARW
)
@@ -141,7 +125,7 @@ open class GameFontBase(val noShadow: Boolean) : Font {
if (variableWidthSheets.contains(ctype)) {
len += try {
asciiWidths[chr.toInt()]!!
glyphWidths[chr.toInt()]!!
}
catch (e: kotlin.KotlinNullPointerException) {
println("KotlinNullPointerException on glyph number ${Integer.toHexString(chr.toInt()).toUpperCase()}")
@@ -149,8 +133,6 @@ open class GameFontBase(val noShadow: Boolean) : Font {
W_LATIN_WIDE // failsafe
}
}
else if (zeroWidthSheets.contains(ctype))
len += 0
else if (ctype == SHEET_CJK_PUNCT)
len += W_ASIAN_PUNCT
else if (ctype == SHEET_HANGUL)
@@ -161,7 +143,7 @@ open class GameFontBase(val noShadow: Boolean) : Font {
len += W_UNIHAN
else if (isThaiDiacritics(s[i]))
len += 0 // set width of the glyph as -W_LATIN_WIDE
else if (ctype == SHEET_KEYCAP)
else if (ctype == SHEET_CUSTOM_SYM)
len += SIZE_KEYCAP
else
len += W_LATIN_WIDE
@@ -272,10 +254,6 @@ open class GameFontBase(val noShadow: Boolean) : Font {
val sheetX: Int
val sheetY: Int
when (prevInstance) {
SHEET_RUNIC -> {
sheetX = runicIndexX(ch)
sheetY = runicIndexY(ch)
}
SHEET_EXTA_VARW -> {
sheetX = extAindexX(ch)
sheetY = extAindexY(ch)
@@ -308,11 +286,11 @@ open class GameFontBase(val noShadow: Boolean) : Font {
sheetX = greekIndexX(ch)
sheetY = greekIndexY(ch)
}
SHEET_THAI_WIDE -> {
SHEET_THAI_VARW -> {
sheetX = thaiIndexX(ch)
sheetY = thaiIndexY(ch)
}
SHEET_KEYCAP -> {
SHEET_CUSTOM_SYM -> {
sheetX = keycapIndexX(ch)
sheetY = keycapIndexY(ch)
}
@@ -329,7 +307,7 @@ open class GameFontBase(val noShadow: Boolean) : Font {
// to deal with the height difference of the sheets
Math.round(y).toFloat() +
(if (prevInstance == SHEET_KEYCAP) (H - SIZE_KEYCAP) / 2 // completely legit height adjustment
(if (prevInstance == SHEET_CUSTOM_SYM) (H - SIZE_KEYCAP) / 2 // completely legit height adjustment
else 0).toFloat(),
scale.toFloat(), thisCol, noShadow
@@ -353,11 +331,7 @@ open class GameFontBase(val noShadow: Boolean) : Font {
}
private fun getSheetType(c: Char): Int {
if (isThaiEF(c))
return SHEET_EXTA_VARW // will use fourth glyph in EXTA_EF
else if (isRunic(c))
return SHEET_RUNIC
else if (isHangul(c))
if (isHangul(c))
return SHEET_HANGUL
else if (isKana(c))
return SHEET_KANA
@@ -380,11 +354,9 @@ open class GameFontBase(val noShadow: Boolean) : Font {
else if (isGreek(c))
return SHEET_GREEK_VARW
else if (isThai(c))
return SHEET_THAI_WIDE
else if (c.isColourCode())
return SHEET_COLOURCODE
else if (isKeycap(c))
return SHEET_KEYCAP
return SHEET_THAI_VARW
else if (isCustomSym(c))
return SHEET_CUSTOM_SYM
else
return SHEET_UNKNOWN// fixed width punctuations
// fixed width
@@ -437,17 +409,16 @@ open class GameFontBase(val noShadow: Boolean) : Font {
}
}
asciiWidths[codeOffset + ccode] = glyphWidth
glyphWidths[codeOffset + ccode] = glyphWidth
}
}
companion object {
internal val glyphWidths: HashMap<Int, Int> = HashMap()
lateinit internal var hangulSheet: SpriteSheet
lateinit internal var asciiSheet: SpriteSheet
internal val asciiWidths: HashMap<Int, Int> = HashMap()
lateinit internal var runicSheet: SpriteSheet
lateinit internal var extASheet: SpriteSheet
lateinit internal var extBSheet: SpriteSheet
@@ -459,7 +430,7 @@ open class GameFontBase(val noShadow: Boolean) : Font {
lateinit internal var uniPunct: SpriteSheet
lateinit internal var greekSheet: SpriteSheet
lateinit internal var thaiSheet: SpriteSheet
lateinit internal var keycapSheet: SpriteSheet
lateinit internal var customSheet: SpriteSheet
internal val JUNG_COUNT = 21
internal val JONG_COUNT = 28
@@ -475,24 +446,21 @@ open class GameFontBase(val noShadow: Boolean) : Font {
internal val SIZE_KEYCAP = 18
internal val SHEET_ASCII_VARW = 0
internal val SHEET_HANGUL = 1
internal val SHEET_RUNIC = 2
internal val SHEET_EXTA_VARW = 3
internal val SHEET_EXTB_VARW = 4
internal val SHEET_KANA = 5
internal val SHEET_CJK_PUNCT = 6
internal val SHEET_UNIHAN = 7
internal val SHEET_CYRILIC_VARW = 8
internal val SHEET_FW_UNI = 9
internal val SHEET_UNI_PUNCT = 10
internal val SHEET_GREEK_VARW = 11
internal val SHEET_THAI_WIDE = 12
internal val SHEET_THAI_NARROW = 13
internal val SHEET_KEYCAP = 14
internal val SHEET_ASCII_VARW = 0
internal val SHEET_HANGUL = 1
internal val SHEET_EXTA_VARW = 2
internal val SHEET_EXTB_VARW = 3
internal val SHEET_KANA = 4
internal val SHEET_CJK_PUNCT = 5
internal val SHEET_UNIHAN = 6
internal val SHEET_CYRILIC_VARW = 7
internal val SHEET_FW_UNI = 8
internal val SHEET_UNI_PUNCT = 9
internal val SHEET_GREEK_VARW = 10
internal val SHEET_THAI_VARW = 11
internal val SHEET_CUSTOM_SYM = 12
internal val SHEET_UNKNOWN = 254
internal val SHEET_COLOURCODE = 255
lateinit internal var sheetKey: Array<SpriteSheet?>

View File

@@ -1,7 +1,6 @@
package net.torvald.imagefont
package net.torvald.terrarumsansbitmap.slick2d
import net.torvald.terrarum.Terrarum
import org.newdawn.slick.*
/**
* Created by minjaesong on 16-01-20.
@@ -10,37 +9,37 @@ class GameFontImpl(noShadow: Boolean = false) : GameFontBase(noShadow = noShadow
init {
GameFontBase.hangulSheet = SpriteSheet(
GameFontBase.hangulSheet = org.newdawn.slick.SpriteSheet(
"./assets/graphics/fonts/hangul_johab.tga", GameFontBase.W_HANGUL, GameFontBase.H)
GameFontBase.asciiSheet = SpriteSheet(
GameFontBase.asciiSheet = org.newdawn.slick.SpriteSheet(
"./assets/graphics/fonts/ascii_variable.tga", 15, 19, 1)
GameFontBase.runicSheet = SpriteSheet(
GameFontBase.runicSheet = org.newdawn.slick.SpriteSheet(
"./assets/graphics/fonts/futhark.tga", GameFontBase.W_LATIN_WIDE, GameFontBase.H)
GameFontBase.extASheet = SpriteSheet(
GameFontBase.extASheet = org.newdawn.slick.SpriteSheet(
"./assets/graphics/fonts/LatinExtA_variable.tga", 15, 19, 1)
GameFontBase.extBSheet = SpriteSheet(
GameFontBase.extBSheet = org.newdawn.slick.SpriteSheet(
"./assets/graphics/fonts/LatinExtB_variable.tga", 15, 19, 1)
GameFontBase.kanaSheet = SpriteSheet(
GameFontBase.kanaSheet = org.newdawn.slick.SpriteSheet(
"./assets/graphics/fonts/kana.tga", GameFontBase.W_KANA, GameFontBase.H)
GameFontBase.cjkPunct = SpriteSheet(
GameFontBase.cjkPunct = org.newdawn.slick.SpriteSheet(
"./assets/graphics/fonts/cjkpunct.tga", GameFontBase.W_ASIAN_PUNCT, GameFontBase.H)
GameFontBase.cyrilic = SpriteSheet(
GameFontBase.cyrilic = org.newdawn.slick.SpriteSheet(
when (Terrarum.gameLocale.substring(0..1)) {
"bg" -> "./assets/graphics/fonts/cyrilic_bulgarian_variable.tga"
"sr" -> "./assets/graphics/fonts/cyrilic_serbian_variable.tga"
else -> "./assets/graphics/fonts/cyrilic_variable.tga"
}, 15, 19, 1)
GameFontBase.fullwidthForms = SpriteSheet(
GameFontBase.fullwidthForms = org.newdawn.slick.SpriteSheet(
"./assets/graphics/fonts/fullwidth_forms.tga", GameFontBase.W_UNIHAN, GameFontBase.H_UNIHAN)
GameFontBase.uniPunct = SpriteSheet(
GameFontBase.uniPunct = org.newdawn.slick.SpriteSheet(
"./assets/graphics/fonts/unipunct.tga", GameFontBase.W_LATIN_WIDE, GameFontBase.H)
GameFontBase.uniHan = SpriteSheet(
GameFontBase.uniHan = org.newdawn.slick.SpriteSheet(
"./assets/graphics/fonts/wenquanyi.tga.gz", 16, 16) // ~32 MB
GameFontBase.greekSheet = SpriteSheet(
GameFontBase.greekSheet = org.newdawn.slick.SpriteSheet(
"./assets/graphics/fonts/greek_variable.tga", 15, 19, 1)
GameFontBase.thaiSheet = SpriteSheet(
"./assets/graphics/fonts/thai_variable.tga",15, 19, 1)
GameFontBase.keycapSheet = SpriteSheet(
GameFontBase.thaiSheet = org.newdawn.slick.SpriteSheet(
"./assets/graphics/fonts/thai_variable.tga", 15, 19, 1)
GameFontBase.customSheet = org.newdawn.slick.SpriteSheet(
"./assets/graphics/fonts/puae000-e0ff.tga", GameFontBase.SIZE_KEYCAP, GameFontBase.SIZE_KEYCAP)
val shk = arrayOf(
@@ -58,21 +57,21 @@ class GameFontImpl(noShadow: Boolean = false) : GameFontBase(noShadow = noShadow
GameFontBase.greekSheet,
GameFontBase.thaiSheet,
null, // Thai EF, filler because not being used right now
GameFontBase.keycapSheet
GameFontBase.customSheet
)
GameFontBase.sheetKey = shk
buildWidthTable(asciiSheet, 0, 0..0xFF)
buildWidthTable(extASheet, 0x100, 0..0x7F)
buildWidthTable(extBSheet, 0x180, 0..0xCF)
buildWidthTable(cyrilic, 0x400, 0..0x5F)
buildWidthTable(greekSheet, 0x370, 0..0x5F)
buildWidthTable(GameFontBase.asciiSheet, 0, 0..0xFF)
buildWidthTable(GameFontBase.extASheet, 0x100, 0..0x7F)
buildWidthTable(GameFontBase.extBSheet, 0x180, 0..0xCF)
buildWidthTable(GameFontBase.cyrilic, 0x400, 0..0x5F)
buildWidthTable(GameFontBase.greekSheet, 0x370, 0..0x5F)
}
fun reload() {
GameFontBase.cyrilic.destroy()
GameFontBase.cyrilic = SpriteSheet(
GameFontBase.cyrilic = org.newdawn.slick.SpriteSheet(
when (Terrarum.gameLocale.substring(0..1)) {
"bg" -> "./assets/graphics/fonts/cyrilic_bulgarian_variable.tga"
"sr" -> "./assets/graphics/fonts/cyrilic_serbian_variable.tga"