gdx font almost working

- TODO: bulgarian/serbian, shadow
This commit is contained in:
minjaesong
2017-06-16 18:52:03 +09:00
parent 6e403f97f8
commit e07e321ee3
4 changed files with 153 additions and 93 deletions

Binary file not shown.

View File

@@ -29,15 +29,50 @@ class TestTestTest : ApplicationAdapter() {
//gameFont = BitmapFont() //gameFont = BitmapFont()
} }
val text = arrayOf(
"x64またはx86-64とは、x86アーキテクチャを64ビットに拡張した命令セットアーキテクチャ。",
"実際には、AMDが発表したAMD64命令セット、続けてインテルが採用したIntel 64命令セット (かつてIA-32eまたはEM64Tと呼ばれていた)",
"などを含む、各社のAMD64互換命令セットの総称である。x86命令セットと互換性を持っていることから、広義にはx86にx64を含む場合がある。",
"",
"x86-64는 x86 명령어 집합 아키텍처의 64비트 모임이다. x86-64 명령어 집합은 에뮬레이션 없이 인텔의 x86를 지원하며 AMD64로 이름 붙인",
"AMD에 의해 고안되었다. 이 아키텍처는 인텔 64라는 이름으로 인텔에 의해 복제되기도 했다. (옘힐, 클래카마스 기술, CT, IA-32e, EM64T 등으로",
"불렸음) 이로써 x86-64 또는 x64의 이름을 일상적으로 사용하기에 이르렀다.",
"",
"x86-64 (также AMD64/Intel64/EM64T) — 64-битное расширение, набор команд для архитектуры x86, разработанное",
"компанией AMD, позволяющее выполнять программы в 64-разрядном режиме. Это расширение архитектуры x86 с",
"почти полной обратной совместимостью.",
"",
"Επίσης η x86-64 έχει καταχωρητές γενικής χρήσης 64-bit και πολλές άλλες βελτιώσεις. Η αρχική προδιαγραφή",
"δημιουργήθηκε από την AMD και έχει υλοποιηθεί από την AMD, την Intel, τη VIA και άλλες εταιρείες. Διατηρεί πλήρη",
"συμβατότητα προς τα πίσω με κώδικα 32-bit.",
"",
"x86-64 (簡稱x64) 是64位版本的x86指令集向后相容於16位及32位的x86架構。x64於1999年由AMD設計AMD首次公開",
"64位元集以擴充給x86稱為「AMD64」。其後也為英特爾所採用現時英特爾稱之為「Intel 64」在之前曾使用過「Clackamas",
"Technology」 (CT)、「IA-32e」及「EM64T」",
"",
"x86-64, ou x64, est une extension du jeu d'instructions x86 d'Intel, introduite par la société AMD avec la gamme",
"AMD64. Intel utilisera cette extension en l'appelant initialement EM64T renommé aujourd'hui en Intel 64.",
"",
"Amd64 (також x86-64/intel64/em64t/x64) — 64-бітова архітектура мікропроцесора і відповідний набір інструкцій,",
"розроблені компанією AMD. Це розширення архітектури x86 з повною зворотною сумісністю.",
"",
"x86-64 е наименованието на наборът от 64-битови разширения към x86 процесорната архитектура. Като синоним",
"на това наименование, се използват и съкращенията AMD64 (използвано от AMD), EM64T и IA-32e (използвани от",
"Intel) и x64 (използвано от Microsoft)."
)
override fun render() { override fun render() {
Gdx.gl.glClearColor(0f, 0f, 0f, 1f) Gdx.gl.glClearColor(.157f, .157f, .157f, 0f)
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT) Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
Gdx.graphics.setTitle("$GAME_NAME — F: ${Gdx.graphics.framesPerSecond}") Gdx.graphics.setTitle("$GAME_NAME — F: ${Gdx.graphics.framesPerSecond}")
batch.inBatch { batch.inBatch {
gameFont.draw(batch, "Hello, world!", 10f, 30f) text.forEachIndexed { index, s ->
gameFont.draw(batch, s, 10f, 10 + (20 * text.size) - 20f * index)
}
} }
} }
@@ -58,6 +93,9 @@ fun main(args: Array<String>) { // LWJGL 3 won't work? java.lang.VerifyError
val config = LwjglApplicationConfiguration() val config = LwjglApplicationConfiguration()
config.useGL30 = true config.useGL30 = true
config.vSyncEnabled = false config.vSyncEnabled = false
config.resizable = false
config.width = 1072
config.height = 742
//config.foregroundFPS = 9999 //config.foregroundFPS = 9999
LwjglApplication(TestTestTest(), config) LwjglApplication(TestTestTest(), config)
} }

View File

@@ -1,12 +1,9 @@
package net.torvald.terrarumsansbitmap.gdx package net.torvald.terrarumsansbitmap.gdx
import com.badlogic.gdx.Gdx import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.Pixmap import com.badlogic.gdx.graphics.Pixmap
import com.badlogic.gdx.graphics.Texture import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.* import com.badlogic.gdx.graphics.g2d.*
import com.badlogic.gdx.utils.Array
import net.torvald.spriteanimation.TextureRegionPack
import java.io.BufferedOutputStream import java.io.BufferedOutputStream
import java.io.File import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
@@ -74,14 +71,14 @@ class GameFontBase(val noShadow: Boolean) : BitmapFont() {
} }
private fun isHangul(c: Char) = c.toInt() in 0xAC00..0xD7A3 private fun isHangul(c: Char) = c.toInt() in 0xAC00..0xD7A3
private fun isAscii(c: Char) = c.toInt() in 0x20..0xFF private fun isAscii(c: Char) = c.toInt() in 0..0xFF
//private fun isRunic(c: Char) = runicList.contains(c) //private fun isRunic(c: Char) = runicList.contains(c)
private fun isExtA(c: Char) = c.toInt() in 0x100..0x17F private fun isExtA(c: Char) = c.toInt() in 0x100..0x17F
private fun isExtB(c: Char) = c.toInt() in 0x180..0x24F private fun isExtB(c: Char) = c.toInt() in 0x180..0x24F
private fun isKana(c: Char) = c.toInt() in 0x3040..0x30FF private fun isKana(c: Char) = c.toInt() in 0x3040..0x30FF
private fun isCJKPunct(c: Char) = c.toInt() in 0x3000..0x303F private fun isCJKPunct(c: Char) = c.toInt() in 0x3000..0x303F
private fun isUniHan(c: Char) = c.toInt() in 0x3400..0x9FFF private fun isUniHan(c: Char) = c.toInt() in 0x3400..0x9FFF
private fun isCyrilic(c: Char) = c.toInt() in 0x400..0x45F private fun isCyrilic(c: Char) = c.toInt() in 0x400..0x4FF // 4FF: futureproof; currently only up to 45F is supported
private fun isFullwidthUni(c: Char) = c.toInt() in 0xFF00..0xFF1F private fun isFullwidthUni(c: Char) = c.toInt() in 0xFF00..0xFF1F
private fun isUniPunct(c: Char) = c.toInt() in 0x2000..0x206F private fun isUniPunct(c: Char) = c.toInt() in 0x2000..0x206F
private fun isGreek(c: Char) = c.toInt() in 0x370..0x3CE private fun isGreek(c: Char) = c.toInt() in 0x370..0x3CE
@@ -131,15 +128,15 @@ class GameFontBase(val noShadow: Boolean) : BitmapFont() {
private val unihanWidthSheets = arrayOf( private val unihanWidthSheets = arrayOf(
SHEET_UNIHAN, SHEET_UNIHAN,
SHEET_FW_UNI, SHEET_FW_UNI
SHEET_UNIHAN
) )
private val variableWidthSheets = arrayOf( private val variableWidthSheets = arrayOf(
SHEET_ASCII_VARW, SHEET_ASCII_VARW,
SHEET_CYRILIC_VARW,
SHEET_EXTA_VARW, SHEET_EXTA_VARW,
SHEET_GREEK_VARW,
SHEET_EXTB_VARW, SHEET_EXTB_VARW,
SHEET_CYRILIC_VARW,
SHEET_UNI_PUNCT,
SHEET_GREEK_VARW,
SHEET_THAI_VARW SHEET_THAI_VARW
) )
@@ -161,42 +158,42 @@ class GameFontBase(val noShadow: Boolean) : BitmapFont() {
) )
private val codeRange = arrayOf( // MUST BE MATCHING WITH SHEET INDICES!! private val codeRange = arrayOf( // MUST BE MATCHING WITH SHEET INDICES!!
0..0xFF, 0..0xFF,
0xAC00..0xD7A4, 0xAC00..0xD7A3,
0x100..0x17F, 0x100..0x17F,
0x180..0x24F, 0x180..0x24F,
0x3040..0x30FF, 0x3040..0x30FF,
0x3000..0x303F, 0x3000..0x303F,
0x3400..0x9FFF, 0x3400..0x9FFF,
0x400..0x45F, 0x400..0x4FF,
0xFF00..0xFF1F, 0xFF00..0xFF1F,
0x2000..0x206F, 0x2000..0x206F,
0x370..0x3CE, 0x370..0x3CE,
0xE00..0xE7F, 0xE00..0xE7F,
0xE000..0xE0FF 0xE000..0xE0FF
) )
private val sheets = arrayOf( // MUST BE MATCHING WITH SHEET INDICES!! private val glyphWidths: HashMap<Int, Int> = HashMap()
asciiSheet, private val sheets: Array<TextureRegionPack>
hangulSheet,
extASheet,
extBSheet,
kanaSheet,
cjkPunct,
uniHan,
cyrilic,
fullwidthForms,
uniPunct,
greekSheet,
thaiSheet,
customSheet
)
init { init {
val sheetsPack = ArrayList<TextureRegionPack>()
// first we create pixmap to read pixels, then make texture using pixmap // first we create pixmap to read pixels, then make texture using pixmap
fileList.forEachIndexed { index, it -> fileList.forEachIndexed { index, it ->
val isVariable = it.endsWith("_variable.tga") val isVariable1 = it.endsWith("_variable.tga")
val isVariable2 = variableWidthSheets.contains(index)
val isVariable = isVariable1 && isVariable2
// idiocity check
if (isVariable1 && !isVariable2)
throw Error("[TerrarumSansBitmap] font is named as variable on the name but not enlisted as")
else if (!isVariable1 && isVariable2)
throw Error("[TerrarumSansBitmap] font is enlisted as variable on the name but not named as")
val pixmap: Pixmap val pixmap: Pixmap
// unpack gz if applicable // unpack gz if applicable
if (it.endsWith(".gz")) { if (it.endsWith(".gz")) {
val gzi = GZIPInputStream(Gdx.files.internal(fontParentDir + it).read(8192)) val gzi = GZIPInputStream(Gdx.files.internal(fontParentDir + it).read(8192))
@@ -217,16 +214,23 @@ class GameFontBase(val noShadow: Boolean) : BitmapFont() {
if (isVariable) { if (isVariable) {
buildWidthTable(pixmap, codeRange[index].first, codeRange[index]) println("[TerrarumSansBitmap] loading texture $it [VARIABLE]")
buildWidthTable(pixmap, codeRange[index], 16)
}
else {
println("[TerrarumSansBitmap] loading texture $it")
} }
val texture = Texture(pixmap) val texture = Texture(pixmap)
val texRegPack = if (isVariable) { val texRegPack = if (isVariable) {
TextureRegionPack(texture, W_VAR_INIT, H, HGAP_VAR, 0) TextureRegionPack(texture, W_VAR_INIT, H, HGAP_VAR, 0)
} }
else if (index == SHEET_UNIHAN || index == SHEET_FW_UNI) { else if (index == SHEET_UNIHAN) {
TextureRegionPack(texture, W_UNIHAN, H_UNIHAN) TextureRegionPack(texture, W_UNIHAN, H_UNIHAN) // the only exception that is height is 16
}
// below they all have height of 20 'H'
else if (index == SHEET_FW_UNI) {
TextureRegionPack(texture, W_UNIHAN, H)
} }
else if (index == SHEET_CJK_PUNCT) { else if (index == SHEET_CJK_PUNCT) {
TextureRegionPack(texture, W_ASIAN_PUNCT, H) TextureRegionPack(texture, W_ASIAN_PUNCT, H)
@@ -240,13 +244,15 @@ class GameFontBase(val noShadow: Boolean) : BitmapFont() {
else if (index == SHEET_CUSTOM_SYM) { else if (index == SHEET_CUSTOM_SYM) {
TextureRegionPack(texture, SIZE_CUSTOM_SYM, SIZE_CUSTOM_SYM) // TODO variable TextureRegionPack(texture, SIZE_CUSTOM_SYM, SIZE_CUSTOM_SYM) // TODO variable
} }
else throw IllegalArgumentException("Unknown sheet index: $index") else throw IllegalArgumentException("[TerrarumSansBitmap] Unknown sheet index: $index")
sheets[index] = texRegPack sheetsPack.add(texRegPack)
pixmap.dispose() // you are terminated pixmap.dispose() // you are terminated
} }
sheets = sheetsPack.toTypedArray()
} }
@@ -259,7 +265,6 @@ class GameFontBase(val noShadow: Boolean) : BitmapFont() {
override fun isFlipped() = false override fun isFlipped() = false
override fun setFixedWidthGlyphs(glyphs: CharSequence) { override fun setFixedWidthGlyphs(glyphs: CharSequence) {
throw UnsupportedOperationException("Nope, no monospace, and figures are already fixed width, bruv.") throw UnsupportedOperationException("Nope, no monospace, and figures are already fixed width, bruv.")
} }
@@ -270,15 +275,18 @@ class GameFontBase(val noShadow: Boolean) : BitmapFont() {
setOwnsTexture(true) setOwnsTexture(true)
} }
private var microBuffer: CharSequence = "" private val offsetUnihan = (H - H_UNIHAN) / 2
private var microBWidth = intArrayOf() // absolute posX of glyphs from print-origin private val offsetCustomSym = (H - SIZE_CUSTOM_SYM) / 2
private var textBuffer: CharSequence = ""
private var textBWidth = intArrayOf() // absolute posX of glyphs from print-origin
override fun draw(batch: Batch, str: CharSequence, x: Float, y: Float): GlyphLayout? { override fun draw(batch: Batch, str: CharSequence, x: Float, y: Float): GlyphLayout? {
if (microBuffer != str) { if (textBuffer != str) {
microBuffer = str textBuffer = str
val widths = getWidthOfCharSeq(str) val widths = getWidthOfCharSeq(str)
microBWidth = Array(str.length, { charIndex -> textBWidth = Array(str.length, { charIndex ->
if (charIndex == 0) if (charIndex == 0)
0 0
else { else {
@@ -290,16 +298,43 @@ class GameFontBase(val noShadow: Boolean) : BitmapFont() {
} }
//print("[gamefontbase] widthTable for $microBuffer: ") //print("[TerrarumSansBitmap] widthTable for $textBuffer: ")
//microBWidth.forEach { print("$it ") }; println() //textBWidth.forEach { print("$it ") }; println()
microBuffer.forEachIndexed { index, c -> textBuffer.forEachIndexed { index, c ->
val sheetID = getSheetType(c) val sheetID = getSheetType(c)
val sheetXY = getSheetwisePosition(c) val sheetXY = getSheetwisePosition(c)
batch.draw(
sheets[sheetID]!!.get(sheetXY[0], sheetXY[1]), //println("[TerrarumSansBitmap] sprite: $sheetID:${sheetXY[0]}x${sheetXY[1]}")
x + microBWidth[index], y
) if (sheetID != SHEET_HANGUL) {
batch.draw(
sheets[sheetID].get(sheetXY[0], sheetXY[1]),
x + textBWidth[index],
y +
if (sheetID == SHEET_UNIHAN) // evil exceptions
offsetUnihan
else if (sheetID == SHEET_CUSTOM_SYM)
offsetCustomSym
else 0
)
}
else { // JOHAB (assemble) HANGUL
val hangulSheet = sheets[1]
val hIndex = c.toInt() - 0xAC00
val indexCho = getHanChosung(hIndex)
val indexJung = getHanJungseong(hIndex)
val indexJong = getHanJongseong(hIndex)
val choRow = getHanInitialRow(hIndex)
val jungRow = getHanMedialRow(hIndex)
val jongRow = getHanFinalRow(hIndex)
batch.draw(hangulSheet.get(indexCho, choRow), x + textBWidth[index], y)
batch.draw(hangulSheet.get(indexJung, jungRow), x + textBWidth[index], y)
batch.draw(hangulSheet.get(indexJong, jongRow), x + textBWidth[index], y)
}
} }
return null return null
@@ -309,7 +344,7 @@ class GameFontBase(val noShadow: Boolean) : BitmapFont() {
override fun dispose() { override fun dispose() {
super.dispose() super.dispose()
sheets.forEach { it!!.dispose() } sheets.forEach { it.dispose() }
} }
private fun getWidthOfCharSeq(s: CharSequence): IntArray { private fun getWidthOfCharSeq(s: CharSequence): IntArray {
@@ -323,7 +358,7 @@ class GameFontBase(val noShadow: Boolean) : BitmapFont() {
glyphWidths[chr.toInt()]!! glyphWidths[chr.toInt()]!!
} }
catch (e: kotlin.KotlinNullPointerException) { catch (e: kotlin.KotlinNullPointerException) {
println("KotlinNullPointerException on glyph number ${Integer.toHexString(chr.toInt()).toUpperCase()}") println("[TerrarumSansBitmap] no width data for glyph number ${Integer.toHexString(chr.toInt()).toUpperCase()}")
//System.exit(1) //System.exit(1)
W_LATIN_WIDE // failsafe W_LATIN_WIDE // failsafe
} }
@@ -378,7 +413,7 @@ class GameFontBase(val noShadow: Boolean) : BitmapFont() {
else if (isCustomSym(c)) else if (isCustomSym(c))
return SHEET_CUSTOM_SYM return SHEET_CUSTOM_SYM
else else
return SHEET_UNKNOWN// fixed width punctuations return SHEET_UNKNOWN
// fixed width // fixed width
// fallback // fallback
} }
@@ -386,19 +421,23 @@ class GameFontBase(val noShadow: Boolean) : BitmapFont() {
private fun getSheetwisePosition(ch: Char): IntArray { private fun getSheetwisePosition(ch: Char): IntArray {
val sheetX: Int; val sheetY: Int val sheetX: Int; val sheetY: Int
when (getSheetType(ch)) { when (getSheetType(ch)) {
SHEET_EXTA_VARW -> { SHEET_UNIHAN -> {
sheetX = unihanIndexX(ch)
sheetY = unihanIndexY(ch)
}
SHEET_EXTA_VARW -> {
sheetX = extAindexX(ch) sheetX = extAindexX(ch)
sheetY = extAindexY(ch) sheetY = extAindexY(ch)
} }
SHEET_EXTB_VARW -> { SHEET_EXTB_VARW -> {
sheetX = extBindexX(ch) sheetX = extBindexX(ch)
sheetY = extBindexY(ch) sheetY = extBindexY(ch)
} }
SHEET_KANA -> { SHEET_KANA -> {
sheetX = kanaIndexX(ch) sheetX = kanaIndexX(ch)
sheetY = kanaIndexY(ch) sheetY = kanaIndexY(ch)
} }
SHEET_CJK_PUNCT -> { SHEET_CJK_PUNCT -> {
sheetX = cjkPunctIndexX(ch) sheetX = cjkPunctIndexX(ch)
sheetY = cjkPunctIndexY(ch) sheetY = cjkPunctIndexY(ch)
} }
@@ -406,27 +445,27 @@ class GameFontBase(val noShadow: Boolean) : BitmapFont() {
sheetX = cyrilicIndexX(ch) sheetX = cyrilicIndexX(ch)
sheetY = cyrilicIndexY(ch) sheetY = cyrilicIndexY(ch)
} }
SHEET_FW_UNI -> { SHEET_FW_UNI -> {
sheetX = fullwidthUniIndexX(ch) sheetX = fullwidthUniIndexX(ch)
sheetY = fullwidthUniIndexY(ch) sheetY = fullwidthUniIndexY(ch)
} }
SHEET_UNI_PUNCT -> { SHEET_UNI_PUNCT -> {
sheetX = uniPunctIndexX(ch) sheetX = uniPunctIndexX(ch)
sheetY = uniPunctIndexY(ch) sheetY = uniPunctIndexY(ch)
} }
SHEET_GREEK_VARW -> { SHEET_GREEK_VARW -> {
sheetX = greekIndexX(ch) sheetX = greekIndexX(ch)
sheetY = greekIndexY(ch) sheetY = greekIndexY(ch)
} }
SHEET_THAI_VARW -> { SHEET_THAI_VARW -> {
sheetX = thaiIndexX(ch) sheetX = thaiIndexX(ch)
sheetY = thaiIndexY(ch) sheetY = thaiIndexY(ch)
} }
SHEET_CUSTOM_SYM -> { SHEET_CUSTOM_SYM -> {
sheetX = symbolIndexX(ch) sheetX = symbolIndexX(ch)
sheetY = symbolIndexY(ch) sheetY = symbolIndexY(ch)
} }
else -> { else -> {
sheetX = ch.toInt() % 16 sheetX = ch.toInt() % 16
sheetY = ch.toInt() / 16 sheetY = ch.toInt() / 16
} }
@@ -435,19 +474,19 @@ class GameFontBase(val noShadow: Boolean) : BitmapFont() {
return intArrayOf(sheetX, sheetY) return intArrayOf(sheetX, sheetY)
} }
fun buildWidthTable(pixmap: Pixmap, codeOffset: Int, codeRange: IntRange, rows: Int = 16) { fun buildWidthTable(pixmap: Pixmap, codeRange: IntRange, cols: Int = 16) {
val binaryCodeOffset = 15 val binaryCodeOffset = W_VAR_INIT
val cellW = 16 val cellW = W_VAR_INIT + 1
val cellH = 20 val cellH = H
// control chars for (code in codeRange) {
for (ccode in codeRange) {
val glyphX = ccode % rows
val glyphY = ccode / rows
val codeStartX = (glyphX * cellW) + binaryCodeOffset val cellX = ((code - codeRange.start) % cols) * cellW
val codeStartY = (glyphY * cellH) val cellY = ((code - codeRange.start) / cols) * cellH
val codeStartX = cellX + binaryCodeOffset
val codeStartY = cellY
var glyphWidth = 0 var glyphWidth = 0
for (downCtr in 0..3) { for (downCtr in 0..3) {
@@ -457,30 +496,13 @@ class GameFontBase(val noShadow: Boolean) : BitmapFont() {
} }
} }
glyphWidths[codeOffset + ccode] = glyphWidth glyphWidths[code] = glyphWidth
} }
} }
companion object { 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 JUNG_COUNT = 21
internal val JONG_COUNT = 28 internal val JONG_COUNT = 28