From 4cd29b5230097e814640c47dc2bcc1c892cb9ec2 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Sun, 2 Jul 2017 03:29:11 +0900 Subject: [PATCH] Color codes (RGBA4444), NOT tested with Slick2D --- .idea/artifacts/TerrarumSansBitmap.xml | 2 +- .idea/workspace.xml | 230 +++++++++++++----- assets/futhark.tga | Bin 0 -> 69138 bytes demo/.idea/workspace.xml | 74 ++++-- .../terrarumsansbitmap/gdx/GameFontBase.kt | 115 ++++++--- .../slick2d/GameFontBase.kt | 169 +++++++------ 6 files changed, 410 insertions(+), 180 deletions(-) create mode 100644 assets/futhark.tga diff --git a/.idea/artifacts/TerrarumSansBitmap.xml b/.idea/artifacts/TerrarumSansBitmap.xml index 9a0f0c5..e693b18 100644 --- a/.idea/artifacts/TerrarumSansBitmap.xml +++ b/.idea/artifacts/TerrarumSansBitmap.xml @@ -1,6 +1,6 @@ - $PROJECT_DIR$/out/artifacts/TerrarumSansBitmap + $PROJECT_DIR$ diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 65ee9a9..a0ae531 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -7,14 +7,12 @@ - - - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + getWidth + getG + getWidt + batch.color = + - @@ -87,7 +107,6 @@ - @@ -164,8 +183,9 @@ - + + @@ -364,31 +384,31 @@ - + - + - - - - + + + + - - - - + + + + - + - + - - + + @@ -403,20 +423,23 @@ - + - - - + + + + + - - + + - + + @@ -425,10 +448,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/futhark.tga b/assets/futhark.tga new file mode 100644 index 0000000000000000000000000000000000000000..4ae836c6e6e3b9ec7f3fdec0cf65c3d6b44fb4b8 GIT binary patch literal 69138 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 j8SmaR?TmM?ov;1 - + @@ -36,8 +36,8 @@ - - + + @@ -92,10 +92,10 @@ - @@ -112,6 +112,8 @@ + + @@ -158,9 +160,7 @@ - - @@ -384,11 +384,12 @@ - + + @@ -396,11 +397,11 @@ - + - + @@ -409,7 +410,6 @@ - @@ -431,6 +431,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -660,7 +700,6 @@ - @@ -668,14 +707,13 @@ - - - + + @@ -684,7 +722,7 @@ - + diff --git a/src/net/torvald/terrarumsansbitmap/gdx/GameFontBase.kt b/src/net/torvald/terrarumsansbitmap/gdx/GameFontBase.kt index d3ace50..cf27a71 100644 --- a/src/net/torvald/terrarumsansbitmap/gdx/GameFontBase.kt +++ b/src/net/torvald/terrarumsansbitmap/gdx/GameFontBase.kt @@ -25,6 +25,7 @@ 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.* @@ -56,6 +57,8 @@ import java.util.zip.GZIPInputStream * 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. * + * Color Codes have following Unicode mapping: U+10RGBA, A must be non-zero to be visible. U+100000 reverts any colour code effects. + * * @param noShadow Self-explanatory * @param flipY If you have Y-down coord system implemented on your GDX (e.g. legacy codebase), set this to ```true``` so that the shadow won't be upside-down. For glyph getting upside-down, set ```TextureRegionPack.globalFlipY = true```. * @@ -99,7 +102,7 @@ class GameFontBase(fontDir: String, val noShadow: Boolean = false, val flipY: Bo private fun isHangul(c: Char) = c.toInt() in codeRange[SHEET_HANGUL] private fun isAscii(c: Char) = c.toInt() in codeRange[SHEET_ASCII_VARW] - //private fun isRunic(c: Char) = runicList.contains(c) + private fun isRunic(c: Char) = c.toInt() in codeRange[SHEET_RUNIC] private fun isExtA(c: Char) = c.toInt() in codeRange[SHEET_EXTA_VARW] private fun isExtB(c: Char) = c.toInt() in codeRange[SHEET_EXTB_VARW] private fun isKana(c: Char) = c.toInt() in codeRange[SHEET_KANA] @@ -117,6 +120,8 @@ class GameFontBase(fontDir: String, val noShadow: Boolean = false, val flipY: Bo private fun isArmenian(c: Char) = c.toInt() in codeRange[SHEET_HAYEREN_VARW] private fun isKartvelian(c: Char) = c.toInt() in codeRange[SHEET_KARTULI_VARW] private fun isIPA(c: Char) = c.toInt() in codeRange[SHEET_IPA_VARW] + private fun isColourCodeHigh(c: Char) = c.toInt() in 0b110110_1111000000..0b110110_1111111111 + private fun isColourCodeLow(c: Char) = c.toInt() in 0b110111_0000000000..0b110111_1111111111 @@ -126,8 +131,8 @@ class GameFontBase(fontDir: String, val noShadow: Boolean = false, val flipY: Bo 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 runicIndexX(c: Char) = (c.toInt() - 0x16A0) % 16 + private fun runicIndexY(c: Char) = (c.toInt() - 0x16A0) / 16 private fun kanaIndexX(c: Char) = (c.toInt() - 0x3040) % 16 private fun kanaIndexY(c: Char) = (c.toInt() - 0x3040) / 16 @@ -165,6 +170,26 @@ class GameFontBase(fontDir: String, val noShadow: Boolean = false, val flipY: Bo private fun ipaIndexX(c: Char) = (c.toInt() - 0x250) % 16 private fun ipaIndexY(c: Char) = (c.toInt() - 0x250) / 16 + private fun getColour(charHigh: Char, charLow: Char): Color { // input: 0x10ARGB, out: RGBA8888 + val codePoint = Character.toCodePoint(charHigh, charLow) + + if (colourBuffer.containsKey(codePoint)) + return colourBuffer[codePoint]!! + + val r = codePoint.and(0xF000).ushr(12) + val g = codePoint.and(0x0F00).ushr(8) + val b = codePoint.and(0x00F0).ushr(4) + val a = codePoint.and(0x000F) + + val col = Color(r.shl(28) or r.shl(24) or g.shl(20) or g.shl(16) or b.shl(12) or b.shl(8) or a.shl(4) or a) + + + colourBuffer[codePoint] = col + return col + } + + private val colourBuffer = HashMap() + private val unihanWidthSheets = arrayOf( SHEET_UNIHAN, SHEET_FW_UNI @@ -199,6 +224,7 @@ class GameFontBase(fontDir: String, val noShadow: Boolean = false, val flipY: Bo "hayeren_variable.tga", "kartuli_variable.tga", "ipa_ext_variable.tga", + "futhark.tga", "puae000-e0ff.tga" ) private val cyrilic_bg = "cyrilic_bulgarian_variable.tga" @@ -219,6 +245,7 @@ class GameFontBase(fontDir: String, val noShadow: Boolean = false, val flipY: Bo 0x530..0x58F, 0x10D0..0x10FF, 0x250..0x2AF, + 0x16A0..0x16FF, 0xE000..0xE0FF ) private val glyphWidths: HashMap = HashMap() // if the value is negative, it's diacritics @@ -294,6 +321,9 @@ class GameFontBase(fontDir: String, val noShadow: Boolean = false, val flipY: Bo else if (index == SHEET_CUSTOM_SYM) { TextureRegionPack(texture, SIZE_CUSTOM_SYM, SIZE_CUSTOM_SYM) // TODO variable } + else if (index == SHEET_RUNIC) { + TextureRegionPack(texture, W_LATIN_WIDE, H) + } else throw IllegalArgumentException("[TerrarumSansBitmap] Unknown sheet index: $index") @@ -359,6 +389,8 @@ class GameFontBase(fontDir: String, val noShadow: Boolean = false, val flipY: Bo private var textBWidth = intArrayOf() // absolute posX of glyphs from print-origin private var textBGSize = intArrayOf() // width of each glyph + private lateinit var originalColour: Color + override fun draw(batch: Batch, str: CharSequence, x: Float, y: Float): GlyphLayout? { if (textBuffer != str) { textBuffer = str @@ -382,17 +414,38 @@ class GameFontBase(fontDir: String, val noShadow: Boolean = false, val flipY: Bo //textBWidth.forEach { print("$it ") }; println() - val mainCol = batch.color.cpy() - val shadowCol = batch.color.cpy().mul(0.5f,0.5f,0.5f,1f) + originalColour = batch.color.cpy() + var mainCol = originalColour + var shadowCol = mainCol.cpy().mul(0.5f,0.5f,0.5f,1f) - textBuffer.forEachIndexed { index, c -> + var index = 0 + while (index <= textBuffer.lastIndex) { + val c = textBuffer[index] val sheetID = getSheetType(c) val (sheetX, sheetY) = getSheetwisePosition(c) //println("[TerrarumSansBitmap] sprite: $sheetID:${sheetX}x${sheetY}") - if (sheetID == SHEET_HANGUL) { + if (isColourCodeHigh(c)) { + val cchigh = c + val cclow = textBuffer[index + 1] + + if (Character.toCodePoint(cchigh, cclow) == 0x100000) { + mainCol = originalColour + shadowCol = mainCol.cpy().mul(0.5f,0.5f,0.5f,1f) + } + else { + mainCol = getColour(cchigh, cclow) + shadowCol = mainCol.cpy().mul(0.5f, 0.5f, 0.5f, 1f) + } + + index += 1 + } + else if (isColourCodeLow(c)) { + throw Error("Unexpected encounter of ColourCodeLow at index $index of String '$textBuffer'") + } + else if (sheetID == SHEET_HANGUL) { val hangulSheet = sheets[SHEET_HANGUL] val hIndex = c.toInt() - 0xAC00 @@ -487,8 +540,13 @@ class GameFontBase(fontDir: String, val noShadow: Boolean = false, val flipY: Bo batch.color = mainCol } } + + + index += 1 } + batch.color = originalColour + return null } @@ -513,6 +571,8 @@ class GameFontBase(fontDir: String, val noShadow: Boolean = false, val flipY: Bo len[i] = glyphWidths[chr.toInt()]!! } + else if (isColourCodeHigh(chr) || isColourCodeLow(chr)) + len[i] = 0 else if (ctype == SHEET_CJK_PUNCT) len[i] = W_ASIAN_PUNCT else if (ctype == SHEET_HANGUL) @@ -566,6 +626,8 @@ class GameFontBase(fontDir: String, val noShadow: Boolean = false, val flipY: Bo return SHEET_KARTULI_VARW else if (isIPA(c)) return SHEET_IPA_VARW + else if (isRunic(c)) + return SHEET_RUNIC else return SHEET_UNKNOWN // fixed width @@ -677,8 +739,16 @@ class GameFontBase(fontDir: String, val noShadow: Boolean = false, val flipY: Bo return glyphLayout.width.toInt() } - companion object { + + 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)") + } + + companion object { internal val JUNG_COUNT = 21 internal val JONG_COUNT = 28 @@ -711,35 +781,10 @@ class GameFontBase(fontDir: String, val noShadow: Boolean = false, val flipY: Bo internal val SHEET_HAYEREN_VARW = 12 internal val SHEET_KARTULI_VARW = 13 internal val SHEET_IPA_VARW = 14 - internal val SHEET_CUSTOM_SYM = 15 + internal val SHEET_RUNIC = 15 + internal val SHEET_CUSTOM_SYM = 16 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)") - } } } \ No newline at end of file diff --git a/src/net/torvald/terrarumsansbitmap/slick2d/GameFontBase.kt b/src/net/torvald/terrarumsansbitmap/slick2d/GameFontBase.kt index af0b683..9d2bad9 100644 --- a/src/net/torvald/terrarumsansbitmap/slick2d/GameFontBase.kt +++ b/src/net/torvald/terrarumsansbitmap/slick2d/GameFontBase.kt @@ -24,6 +24,37 @@ package net.torvald.terrarumsansbitmap.slick2d +import net.torvald.terrarumsansbitmap.gdx.GameFontBase +import net.torvald.terrarumsansbitmap.gdx.GameFontBase.Companion.JUNG_COUNT +import net.torvald.terrarumsansbitmap.gdx.GameFontBase.Companion.JONG_COUNT +import net.torvald.terrarumsansbitmap.gdx.GameFontBase.Companion.W_ASIAN_PUNCT +import net.torvald.terrarumsansbitmap.gdx.GameFontBase.Companion.W_HANGUL +import net.torvald.terrarumsansbitmap.gdx.GameFontBase.Companion.W_KANA +import net.torvald.terrarumsansbitmap.gdx.GameFontBase.Companion.W_UNIHAN +import net.torvald.terrarumsansbitmap.gdx.GameFontBase.Companion.W_LATIN_WIDE +import net.torvald.terrarumsansbitmap.gdx.GameFontBase.Companion.W_VAR_INIT +import net.torvald.terrarumsansbitmap.gdx.GameFontBase.Companion.HGAP_VAR +import net.torvald.terrarumsansbitmap.gdx.GameFontBase.Companion.H +import net.torvald.terrarumsansbitmap.gdx.GameFontBase.Companion.H_UNIHAN +import net.torvald.terrarumsansbitmap.gdx.GameFontBase.Companion.SIZE_CUSTOM_SYM +import net.torvald.terrarumsansbitmap.gdx.GameFontBase.Companion.SHEET_ASCII_VARW +import net.torvald.terrarumsansbitmap.gdx.GameFontBase.Companion.SHEET_HANGUL +import net.torvald.terrarumsansbitmap.gdx.GameFontBase.Companion.SHEET_EXTA_VARW +import net.torvald.terrarumsansbitmap.gdx.GameFontBase.Companion.SHEET_EXTB_VARW +import net.torvald.terrarumsansbitmap.gdx.GameFontBase.Companion.SHEET_KANA +import net.torvald.terrarumsansbitmap.gdx.GameFontBase.Companion.SHEET_CJK_PUNCT +import net.torvald.terrarumsansbitmap.gdx.GameFontBase.Companion.SHEET_UNIHAN +import net.torvald.terrarumsansbitmap.gdx.GameFontBase.Companion.SHEET_CYRILIC_VARW +import net.torvald.terrarumsansbitmap.gdx.GameFontBase.Companion.SHEET_FW_UNI +import net.torvald.terrarumsansbitmap.gdx.GameFontBase.Companion.SHEET_UNI_PUNCT +import net.torvald.terrarumsansbitmap.gdx.GameFontBase.Companion.SHEET_GREEK_VARW +import net.torvald.terrarumsansbitmap.gdx.GameFontBase.Companion.SHEET_THAI_VARW +import net.torvald.terrarumsansbitmap.gdx.GameFontBase.Companion.SHEET_HAYEREN_VARW +import net.torvald.terrarumsansbitmap.gdx.GameFontBase.Companion.SHEET_KARTULI_VARW +import net.torvald.terrarumsansbitmap.gdx.GameFontBase.Companion.SHEET_IPA_VARW +import net.torvald.terrarumsansbitmap.gdx.GameFontBase.Companion.SHEET_CUSTOM_SYM +import net.torvald.terrarumsansbitmap.gdx.GameFontBase.Companion.SHEET_UNKNOWN +import net.torvald.terrarumsansbitmap.gdx.GameFontBase.Companion.SHEET_RUNIC import org.newdawn.slick.Color import org.newdawn.slick.Font import org.newdawn.slick.Image @@ -59,6 +90,8 @@ import java.util.zip.GZIPInputStream * 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. * + * Color Codes have following Unicode mapping: U+10RGBA, A must be non-zero to be visible. U+100000 reverts any colour code effects. + * * @param noShadow Self-explanatory * @param flipY If you have Y-down coord system implemented on your GDX (e.g. legacy codebase), set this to ```true``` so that the shadow won't be upside-down. For glyph getting upside-down, set ```TextureRegionPack.globalFlipY = true```. * @@ -102,7 +135,7 @@ class GameFontBase(fontDir: String, val noShadow: Boolean = false) : Font { private fun isHangul(c: Char) = c.toInt() in codeRange[SHEET_HANGUL] private fun isAscii(c: Char) = c.toInt() in codeRange[SHEET_ASCII_VARW] - //private fun isRunic(c: Char) = runicList.contains(c) + private fun isRunic(c: Char) = c.toInt() in codeRange[SHEET_RUNIC] private fun isExtA(c: Char) = c.toInt() in codeRange[SHEET_EXTA_VARW] private fun isExtB(c: Char) = c.toInt() in codeRange[SHEET_EXTB_VARW] private fun isKana(c: Char) = c.toInt() in codeRange[SHEET_KANA] @@ -120,6 +153,9 @@ class GameFontBase(fontDir: String, val noShadow: Boolean = false) : Font { private fun isArmenian(c: Char) = c.toInt() in codeRange[SHEET_HAYEREN_VARW] private fun isKartvelian(c: Char) = c.toInt() in codeRange[SHEET_KARTULI_VARW] private fun isIPA(c: Char) = c.toInt() in codeRange[SHEET_IPA_VARW] + private fun isColourCodeHigh(c: Char) = c.toInt() in 0b110110_1111000000..0b110110_1111111111 + private fun isColourCodeLow(c: Char) = c.toInt() in 0b110111_0000000000..0b110111_1111111111 + @@ -129,8 +165,8 @@ class GameFontBase(fontDir: String, val noShadow: Boolean = false) : Font { 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 runicIndexX(c: Char) = (c.toInt() - 0x16A0) % 16 + private fun runicIndexY(c: Char) = (c.toInt() - 0x16A0) / 16 private fun kanaIndexX(c: Char) = (c.toInt() - 0x3040) % 16 private fun kanaIndexY(c: Char) = (c.toInt() - 0x3040) / 16 @@ -168,6 +204,26 @@ class GameFontBase(fontDir: String, val noShadow: Boolean = false) : Font { private fun ipaIndexX(c: Char) = (c.toInt() - 0x250) % 16 private fun ipaIndexY(c: Char) = (c.toInt() - 0x250) / 16 + private fun getColour(charHigh: Char, charLow: Char): Color { // input: 0x10ARGB, out: RGBA8888 + val codePoint = Character.toCodePoint(charHigh, charLow) + + if (colourBuffer.containsKey(codePoint)) + return colourBuffer[codePoint]!! + + val r = codePoint.and(0xF000).ushr(12) + val g = codePoint.and(0x0F00).ushr(8) + val b = codePoint.and(0x00F0).ushr(4) + val a = codePoint.and(0x000F) + + val col = Color(a.shl(28) or a.shl(24) or r.shl(20) or r.shl(16) or g.shl(12) or g.shl(8) or b.shl(4) or b) + + + colourBuffer[codePoint] = col + return col + } + + private val colourBuffer = HashMap() + private val unihanWidthSheets = arrayOf( SHEET_UNIHAN, SHEET_FW_UNI @@ -202,6 +258,7 @@ class GameFontBase(fontDir: String, val noShadow: Boolean = false) : Font { "hayeren_variable.tga", "kartuli_variable.tga", "ipa_ext_variable.tga", + "futhark.tga", "puae000-e0ff.tga" ) private val cyrilic_bg = "cyrilic_bulgarian_variable.tga" @@ -222,6 +279,7 @@ class GameFontBase(fontDir: String, val noShadow: Boolean = false) : Font { 0x530..0x58F, 0x10D0..0x10FF, 0x250..0x2AF, + 0x16A0..0x16FF, 0xE000..0xE0FF ) private val glyphWidths: HashMap = HashMap() // if the value is negative, it's diacritics @@ -297,6 +355,9 @@ class GameFontBase(fontDir: String, val noShadow: Boolean = false) : Font { else if (index == SHEET_CUSTOM_SYM) { SpriteSheet(image, SIZE_CUSTOM_SYM, SIZE_CUSTOM_SYM) // TODO variable } + else if (index == SHEET_RUNIC) { + SpriteSheet(image, W_LATIN_WIDE, H) + } else throw IllegalArgumentException("[TerrarumSansBitmap] Unknown sheet index: $index") @@ -372,17 +433,37 @@ class GameFontBase(fontDir: String, val noShadow: Boolean = false) : Font { //textBWidth.forEach { print("$it ") }; println() - val mainCol = color - val shadowCol = color.darker(0.5f) + var mainCol = color + var shadowCol = color.darker(0.5f) - textBuffer.forEachIndexed { index, c -> + var index = 0 + while (index <= textBuffer.lastIndex) { + val c = textBuffer[index] val sheetID = getSheetType(c) val sheetXY = getSheetwisePosition(c) //println("[TerrarumSansBitmap] sprite: $sheetID:${sheetXY[0]}x${sheetXY[1]}") - if (sheetID == SHEET_HANGUL) { + if (isColourCodeHigh(c)) { + val cchigh = c + val cclow = textBuffer[index + 1] + + if (Character.toCodePoint(cchigh, cclow) == 0x100000) { + mainCol = color + shadowCol = color.darker(0.5f) + } + else { + mainCol = getColour(cchigh, cclow) + shadowCol = mainCol.darker(0.5f) + } + + index += 1 + } + else if (isColourCodeLow(c)) { + throw Error("Unexpected encounter of ColourCodeLow at index $index of String '$textBuffer'") + } + else if (sheetID == SHEET_HANGUL) { val hangulSheet = sheets[SHEET_HANGUL] val hIndex = c.toInt() - 0xAC00 @@ -470,6 +551,9 @@ class GameFontBase(fontDir: String, val noShadow: Boolean = false) : Font { catch (noSuchGlyph: ArrayIndexOutOfBoundsException) { } } + + + index += 1 } } @@ -493,6 +577,8 @@ class GameFontBase(fontDir: String, val noShadow: Boolean = false) : Font { len[i] = glyphWidths[chr.toInt()]!! } + else if (isColourCodeHigh(chr) || isColourCodeLow(chr)) + len[i] = 0 else if (ctype == SHEET_CJK_PUNCT) len[i] = W_ASIAN_PUNCT else if (ctype == SHEET_HANGUL) @@ -546,6 +632,8 @@ class GameFontBase(fontDir: String, val noShadow: Boolean = false) : Font { return SHEET_KARTULI_VARW else if (isIPA(c)) return SHEET_IPA_VARW + else if (isRunic(c)) + return SHEET_RUNIC else return SHEET_UNKNOWN // fixed width @@ -656,69 +744,14 @@ class GameFontBase(fontDir: String, val noShadow: Boolean = false) : Font { return getWidthOfCharSeq(text).sum() } - companion object { - 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 + 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)") + } - 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_HAYEREN_VARW = 12 - internal val SHEET_KARTULI_VARW = 13 - internal val SHEET_IPA_VARW = 14 - internal val SHEET_CUSTOM_SYM = 15 - - 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)") - } - } } \ No newline at end of file