package net.torvald.imagefont import net.torvald.terrarum.Terrarum import org.lwjgl.opengl.GL11 import org.newdawn.slick.* /** * Created by minjaesong on 16-01-27. */ open class GameFontBase @Throws(SlickException::class) constructor() : 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) 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 isAsciiEF(c: Char) = asciiEFList.contains(c) private fun isExtAEF(c: Char) = extAEFList.contains(c) private fun isHangul(c: Char) = c.toInt() >= 0xAC00 && c.toInt() < 0xD7A4 private fun isAscii(c: Char) = c.toInt() > 0x20 && c.toInt() <= 0xFF private fun isRunic(c: Char) = runicList.contains(c) private fun isExtA(c: Char) = c.toInt() >= 0x100 && c.toInt() < 0x180 private fun isKana(c: Char) = c.toInt() >= 0x3040 && c.toInt() < 0x3100 private fun isCJKPunct(c: Char) = c.toInt() >= 0x3000 && c.toInt() < 0x3040 private fun isUniHan(c: Char) = c.toInt() >= 0x3400 && c.toInt() < 0xA000 private fun isCyrilic(c: Char) = c.toInt() >= 0x400 && c.toInt() < 0x460 private fun isCyrilicEF(c: Char) = cyrilecEFList.contains(c) private fun isFullwidthUni(c: Char) = c.toInt() >= 0xFF00 && c.toInt() < 0xFF20 private fun isUniPunct(c: Char) = c.toInt() >= 0x2000 && c.toInt() < 0x2070 private fun isWenQuanYi1(c: Char) = c.toInt() >= 0x33F3 && c.toInt() <= 0x69FC private fun isWenQuanYi2(c: Char) = c.toInt() >= 0x69FD && c.toInt() <= 0x9FDC private fun isGreek(c: Char) = c.toInt() >= 0x370 && c.toInt() <= 0x3CE private fun isGreekEF(c: Char) = greekEFList.contains(c) private fun isRomanian(c: Char) = c.toInt() >= 0x218 && c.toInt() <= 0x21A private fun isRomanianEF(c: Char) = c.toInt() == 0x21B private fun isThai(c: Char) = c.toInt() >= 0xE00 && c.toInt() <= 0xE7F private fun isThaiDiacritics(c: Char) = (c.toInt() >= 0xE34 && c.toInt() <= 0xE3A) || (c.toInt() >= 0xE47 && c.toInt() <= 0xE4E) || (c.toInt() == 0xE31) private fun isThaiEF(c: Char) = c.toInt() == 0xE40 private fun asciiEFindexX(c: Char) = asciiEFList.indexOf(c) % 16 private fun asciiEFindexY(c: Char) = asciiEFList.indexOf(c) / 16 private fun extAindexX(c: Char) = (c.toInt() - 0x100) % 16 private fun extAindexY(c: Char) = (c.toInt() - 0x100) / 16 private fun extAEFindexX(c: Char) = if (isThaiEF(c)) 3 // thai เ else extAEFList.indexOf(c) % 16 private fun extAEFindexY(c: Char) = if (isThaiEF(c)) 0 // thai เ else extAEFList.indexOf(c) / 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 uniHanIndexX(c: Char) = (c.toInt() - 0x3400) % 256 private fun uniHanIndexY(c: Char) = (c.toInt() - 0x3400) / 256 private fun cyrilicIndexX(c: Char) = (c.toInt() - 0x400) % 16 private fun cyrilicIndexY(c: Char) = (c.toInt() - 0x400) / 16 private fun cyrilicEFindexX(c: Char) = cyrilecEFList.indexOf(c) % 16 private fun cyrilicEFindexY(c: Char) = cyrilecEFList.indexOf(c) / 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 wenQuanYiIndexX(c: Char) = (c.toInt() - if (c.toInt() <= 0x4DB5) 0x33F3 else 0x33F3 + 0x4A) % 32 private fun wenQuanYi1IndexY(c: Char) = (c.toInt() - (0x33F3 + 0x4A)) / 32 private fun wenQuanYi2IndexY(c: Char) = (c.toInt() - 0x69FD) / 32 private fun greekIndexX(c: Char) = (c.toInt() - 0x370) % 16 private fun greekIndexY(c: Char) = (c.toInt() - 0x370) / 16 private fun greekEFIndexX(c: Char) = greekEFList.indexOf(c) % 16 private fun greekEFIndexY(c: Char) = greekEFList.indexOf(c) / 16 private fun romanianIndexX(c: Char) = c.toInt() - 0x218 private fun romanianIndexY(c: Char) = 0 private fun thaiIndexX(c: Char) = (c.toInt() - 0xE00) % 16 private fun thaiIndexY(c: Char) = (c.toInt() - 0xE00) / 16 private fun thaiEFIndexX(c: Char) = 3 private fun thaiEFIndexY(c: Char) = 0 private val narrowWidthSheets = arrayOf( SHEET_ASCII_EF, SHEET_EXTA_EF, SHEET_CYRILIC_EF, SHEET_GREEK_EF, SHEET_EXTB_ROMANIAN_EF ) private val unihanWidthSheets = arrayOf( SHEET_UNIHAN, SHEET_FW_UNI, SHEET_WENQUANYI_1, SHEET_WENQUANYI_2 ) private val zeroWidthSheets = arrayOf( SHEET_COLOURCODE ) override fun getWidth(s: String) = getWidthSubstr(s, s.length) private fun getWidthSubstr(s: String, endIndex: Int): Int { var len = 0 for (i in 0..endIndex - 1) { val ctype = getSheetType(s[i]) /*if (i > 0 && s[i].toInt() > 0x20) { // inter-Unihan-hangul Kerning val cpre = getSheetType(s[i - 1]) if ((unihanWidthSheets.contains(cpre) || cpre == SHEET_HANGUL) && !(unihanWidthSheets.contains(ctype) || ctype == SHEET_HANGUL) || (unihanWidthSheets.contains(ctype) || ctype == SHEET_HANGUL) && !(unihanWidthSheets.contains(cpre) || cpre == SHEET_HANGUL)) { // margin after/before hangul/unihan len += 2 } else if ((ctype == SHEET_HANGUL || ctype == SHEET_KANA) && (cpre == SHEET_HANGUL || cpre == SHEET_KANA)) { // margin between hangul/kana len += 1 } }*/ if (zeroWidthSheets.contains(ctype)) len += 0 else if (narrowWidthSheets.contains(ctype)) len += W_LATIN_NARROW else if (ctype == SHEET_CJK_PUNCT) len += W_ASIAN_PUNCT else if (ctype == SHEET_HANGUL) len += W_HANGUL else if (ctype == SHEET_KANA) len += W_KANA else if (unihanWidthSheets.contains(ctype)) len += W_UNIHAN else if (isThaiDiacritics(s[i])) len += 0 // set width of the glyph as -W_LATIN_WIDE else len += W_LATIN_WIDE if (i < endIndex - 1) len += interchar } return len * scale } override fun getHeight(s: String) = H * scale override fun getLineHeight() = H * scale override fun drawString(x: Float, y: Float, s: String) = drawString(x, y, s, Color.white) override fun drawString(x: Float, y: Float, s: String, color: Color) { GL11.glEnable(GL11.GL_BLEND) GL11.glColorMask(true, true, true, true) GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA) var thisCol = color // hangul fonts first //hangulSheet.startUse() // disabling texture binding to make the font coloured // JOHAB for (i in 0..s.length - 1) { val ch = s[i] if (ch.isColourCode()) { thisCol = colourKey[ch]!! continue } if (isHangul(ch)) { val hIndex = ch.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) val glyphW = getWidth(ch.toString()) /*// initials hangulSheet.renderInUse( Math.round(x + getWidthSubstr(s, i + 1) - glyphW), Math.round(((H - H_HANGUL) / 2).toFloat() + y + 1f), indexCho, choRow ) // medials hangulSheet.renderInUse( Math.round(x + getWidthSubstr(s, i + 1) - glyphW), Math.round(((H - H_HANGUL) / 2).toFloat() + y + 1f), indexJung, jungRow ) // finals hangulSheet.renderInUse( Math.round(x + getWidthSubstr(s, i + 1) - glyphW), Math.round(((H - H_HANGUL) / 2).toFloat() + y + 1f), indexJong, jongRow )*/ hangulSheet.getSubImage(indexCho, choRow).draw( Math.round(x + getWidthSubstr(s, i + 1) - glyphW).toFloat(), Math.round(((H - H_HANGUL) / 2).toFloat() + y + 1f).toFloat(), scale.toFloat(), thisCol ) hangulSheet.getSubImage(indexJung, jungRow).draw( Math.round(x + getWidthSubstr(s, i + 1) - glyphW).toFloat(), Math.round(((H - H_HANGUL) / 2).toFloat() + y + 1f).toFloat(), scale.toFloat(), thisCol ) hangulSheet.getSubImage(indexJong, jongRow).draw( Math.round(x + getWidthSubstr(s, i + 1) - glyphW).toFloat(), Math.round(((H - H_HANGUL) / 2).toFloat() + y + 1f).toFloat(), scale.toFloat(), thisCol ) } } //hangulSheet.endUse() // unihan fonts /*uniHan.startUse(); for (int i = 0; i < s.length(); i++) { char ch = s.charAt(i); if (isUniHan(ch)) { int glyphW = getWidth("" + ch); uniHan.renderInUse( Math.round(x + getWidthSubstr(s, i + 1) - glyphW ) , Math.round((H - H_UNIHAN) / 2 + y) , uniHanIndexX(ch) , uniHanIndexY(ch) ); } } uniHan.endUse();*/ // WenQuanYi 1 //wenQuanYi_1.startUse() for (i in 0..s.length - 1) { val ch = s[i] if (ch.isColourCode()) { thisCol = colourKey[ch]!! continue } if (isWenQuanYi1(ch)) { val glyphW = getWidth("" + ch) /*wenQuanYi_1.renderInUse( Math.round(x + getWidthSubstr(s, i + 1) - glyphW), Math.round((H - H_UNIHAN) / 2 + y), wenQuanYiIndexX(ch), wenQuanYi1IndexY(ch) )*/ wenQuanYi_1.getSubImage(wenQuanYiIndexX(ch), wenQuanYi1IndexY(ch)).draw( Math.round(x + getWidthSubstr(s, i + 1) - glyphW).toFloat(), Math.round((H - H_UNIHAN) / 2 + y).toFloat(), scale.toFloat(), thisCol ) } } //wenQuanYi_1.endUse() // WenQuanYi 2 //wenQuanYi_2.startUse() for (i in 0..s.length - 1) { val ch = s[i] if (ch.isColourCode()) { thisCol = colourKey[ch]!! continue } if (isWenQuanYi2(ch)) { val glyphW = getWidth("" + ch) /*wenQuanYi_2.renderInUse( Math.round(x + getWidthSubstr(s, i + 1) - glyphW), Math.round((H - H_UNIHAN) / 2 + y), wenQuanYiIndexX(ch), wenQuanYi2IndexY(ch) )*/ wenQuanYi_2.getSubImage(wenQuanYiIndexX(ch), wenQuanYi2IndexY(ch)).draw( Math.round(x + getWidthSubstr(s, i + 1) - glyphW).toFloat(), Math.round((H - H_UNIHAN) / 2 + y).toFloat(), scale.toFloat(), thisCol ) } } //wenQuanYi_2.endUse() // regular fonts var prevInstance = -1 for (i in 0..s.length - 1) { val ch = s[i] if (ch.isColourCode()) { thisCol = colourKey[ch]!! continue } if (!isHangul(ch) && !isUniHan(ch)) { // if not init, endUse first if (prevInstance != -1) { //sheetKey[prevInstance].endUse() } //sheetKey[getSheetType(ch)].startUse() prevInstance = getSheetType(ch) val sheetX: Int val sheetY: Int when (prevInstance) { SHEET_ASCII_EF -> { sheetX = asciiEFindexX(ch) sheetY = asciiEFindexY(ch) } SHEET_EXTA_EF -> { sheetX = extAEFindexX(ch) sheetY = extAEFindexY(ch) } SHEET_RUNIC -> { sheetX = runicIndexX(ch) sheetY = runicIndexY(ch) } SHEET_EXTA_EM -> { sheetX = extAindexX(ch) sheetY = extAindexY(ch) } SHEET_KANA -> { sheetX = kanaIndexX(ch) sheetY = kanaIndexY(ch) } SHEET_CJK_PUNCT -> { sheetX = cjkPunctIndexX(ch) sheetY = cjkPunctIndexY(ch) } SHEET_CYRILIC_EM -> { sheetX = cyrilicIndexX(ch) sheetY = cyrilicIndexY(ch) } SHEET_CYRILIC_EF -> { sheetX = cyrilicEFindexX(ch) sheetY = cyrilicEFindexY(ch) } SHEET_FW_UNI -> { sheetX = fullwidthUniIndexX(ch) sheetY = fullwidthUniIndexY(ch) } SHEET_UNI_PUNCT -> { sheetX = uniPunctIndexX(ch) sheetY = uniPunctIndexY(ch) } SHEET_GREEK_EM -> { sheetX = greekIndexX(ch) sheetY = greekIndexY(ch) } SHEET_GREEK_EF -> { sheetX = greekEFIndexX(ch) sheetY = greekEFIndexY(ch) } SHEET_EXTB_ROMANIAN_EM -> { sheetX = romanianIndexX(ch) sheetY = romanianIndexY(ch) } SHEET_EXTB_ROMANIAN_EF -> { sheetX = 0 sheetY = 0 } SHEET_THAI_EM -> { sheetX = thaiIndexX(ch) sheetY = thaiIndexY(ch) } else -> { sheetX = ch.toInt() % 16 sheetY = ch.toInt() / 16 } } val glyphW = getWidth("" + ch) try { /*sheetKey[prevInstance].renderInUse( Math.round(x + getWidthSubstr(s, i + 1) - glyphW) // Interchar: pull punct right next to hangul to the left + if (i > 0 && isHangul(s[i - 1])) -3 else 0, Math.round(y) + if (prevInstance == SHEET_CJK_PUNCT) -1 else if (prevInstance == SHEET_FW_UNI) (H - H_HANGUL) / 2 else 0, sheetX, sheetY )*/ sheetKey[prevInstance]!!.getSubImage(sheetX, sheetY).draw( Math.round(x + getWidthSubstr(s, i + 1) - glyphW).toFloat(), // to deal with the height difference of the sheets Math.round(y).toFloat() + (if (prevInstance == SHEET_CJK_PUNCT) -1 else if (prevInstance == SHEET_FW_UNI) (H - H_HANGUL) / 2 else 0).toFloat(), scale.toFloat(), thisCol ) } catch (e: ArrayIndexOutOfBoundsException) { // character that does not exist in the sheet. No render, pass. } catch (e1: RuntimeException) { // System.err.println("[GameFontBase] RuntimeException raised while processing character '$ch' (U+${Integer.toHexString(ch.toInt()).toUpperCase()})") // e1.printStackTrack() } } } if (prevInstance != -1) { //sheetKey[prevInstance].endUse() } GL11.glEnd() } private fun getSheetType(c: Char): Int { // EFs if (isAsciiEF(c)) return SHEET_ASCII_EF else if (isExtAEF(c)) return SHEET_EXTA_EF else if (isCyrilicEF(c)) return SHEET_CYRILIC_EF else if (isGreekEF(c)) return SHEET_GREEK_EF else if (isRomanianEF(c)) return SHEET_EXTB_ROMANIAN_EF else if (isThaiEF(c)) return SHEET_EXTA_EF // will use fourth glyph in EXTA_EF else if (isRunic(c)) return SHEET_RUNIC else 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_EM else if (isExtA(c)) return SHEET_EXTA_EM else if (isCyrilic(c)) return SHEET_CYRILIC_EM 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_EM else if (isRomanian(c)) return SHEET_EXTB_ROMANIAN_EM else if (isThai(c)) return SHEET_THAI_EM else if (c.isColourCode()) return SHEET_COLOURCODE else return SHEET_ASCII_EM// fixed width punctuations // fixed width // fallback } /** * Draw part of a string to the screen. Note that this will still position the text as though * it's part of the bigger string. * @param x * * * @param y * * * @param s * * * @param color * * * @param startIndex * * * @param endIndex */ override fun drawString(x: Float, y: Float, s: String, color: Color, startIndex: Int, endIndex: Int) { val unprintedHead = s.substring(0, startIndex) val printedBody = s.substring(startIndex, endIndex) val xoff = getWidth(unprintedHead) drawString(x + xoff, y, printedBody, color) } private fun setBlendModeMul() { GL11.glEnable(GL11.GL_BLEND) GL11.glBlendFunc(GL11.GL_DST_COLOR, GL11.GL_ONE_MINUS_SRC_ALPHA) } private fun setBlendModeNormal() { GL11.glDisable(GL11.GL_BLEND) Terrarum.appgc.graphics.setDrawMode(Graphics.MODE_NORMAL) } fun Char.isColourCode() = colourKey.containsKey(this) companion object { lateinit internal var hangulSheet: SpriteSheet lateinit internal var asciiSheet: SpriteSheet lateinit internal var asciiSheetEF: SpriteSheet lateinit internal var runicSheet: SpriteSheet lateinit internal var extASheet: SpriteSheet lateinit internal var extASheetEF: SpriteSheet lateinit internal var kanaSheet: SpriteSheet lateinit internal var cjkPunct: SpriteSheet // static SpriteSheet uniHan; lateinit internal var cyrilic: SpriteSheet lateinit internal var cyrilicEF: SpriteSheet lateinit internal var fullwidthForms: SpriteSheet lateinit internal var uniPunct: SpriteSheet lateinit internal var wenQuanYi_1: SpriteSheet lateinit internal var wenQuanYi_2: SpriteSheet lateinit internal var greekSheet: SpriteSheet lateinit internal var greekSheetEF: SpriteSheet lateinit internal var romanianSheet: SpriteSheet lateinit internal var romanianSheetEF: SpriteSheet lateinit internal var thaiSheet: SpriteSheet internal val JUNG_COUNT = 21 internal val JONG_COUNT = 28 internal val W_ASIAN_PUNCT = 10 internal val W_HANGUL = 11 internal val W_KANA = 12 internal val W_UNIHAN = 16 internal val W_LATIN_WIDE = 9 // width of regular letters, including m internal val W_LATIN_NARROW = 5 // width of letter f, t, i, l internal val H = 20 internal val H_HANGUL = 16 internal val H_UNIHAN = 16 internal val H_KANA = 20 internal val SHEET_ASCII_EM = 0 internal val SHEET_ASCII_EF = 1 internal val SHEET_HANGUL = 2 internal val SHEET_RUNIC = 3 internal val SHEET_EXTA_EM = 4 internal val SHEET_EXTA_EF = 5 internal val SHEET_KANA = 6 internal val SHEET_CJK_PUNCT = 7 internal val SHEET_UNIHAN = 8 internal val SHEET_CYRILIC_EM = 9 internal val SHEET_CYRILIC_EF = 10 internal val SHEET_FW_UNI = 11 internal val SHEET_UNI_PUNCT = 12 internal val SHEET_WENQUANYI_1 = 13 internal val SHEET_WENQUANYI_2 = 14 internal val SHEET_GREEK_EM = 15 internal val SHEET_GREEK_EF = 16 internal val SHEET_EXTB_ROMANIAN_EM = 17 internal val SHEET_EXTB_ROMANIAN_EF = 18 internal val SHEET_THAI_EM = 19 internal val SHEET_THAI_EF = 20 internal val SHEET_COLOURCODE = 255 lateinit internal var sheetKey: Array internal val asciiEFList = arrayOf(' ', '!', '"', '\'', '(', ')', ',', '.', ':', ';', 'I', '[', ']', '`', 'f', 'i', 'j', 'l', 't', '{', '|', '}', 0xA1.toChar(), 'Ì', 'Í', 'Î', 'Ï', 'ì', 'í', 'î', 'ï', '·') internal val extAEFList = arrayOf( 0x12E.toChar(), 0x12F.toChar(), 0x130.toChar(), 0x131.toChar(), 0x135.toChar(), 0x13A.toChar(), 0x13C.toChar(), 0x142.toChar(), 0x163.toChar(), 0x167.toChar(), 0x17F.toChar() ) internal val cyrilecEFList = arrayOf( 0x406.toChar(), 0x407.toChar(), 0x456.toChar(), 0x457.toChar(), 0x458.toChar() ) internal val greekEFList = arrayOf( 0x390.toChar(), 0x399.toChar(), 0x3AA.toChar(), 0x3AF.toChar(), 0x3B9.toChar(), 0x3CA.toChar() ) /** * 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('ᚠ', 'ᚢ', 'ᚦ', 'ᚬ', 'ᚱ', 'ᚴ', 'ᚼ', 'ᚾ', 'ᛁ', 'ᛅ', 'ᛋ', 'ᛏ', 'ᛒ', 'ᛘ', 'ᛚ', 'ᛦ', 'ᛂ', '᛬', '᛫', '᛭', 'ᛮ', 'ᛯ', 'ᛰ') internal var interchar = 0 internal var scale = 1 set(value) { if (value > 0) field = value else throw IllegalArgumentException("Font scale cannot be zero or negative (input: $value)") } val colourKey = hashMapOf( Pair(0x10.toChar(), Color(0xFFFFFF)), //*w hite Pair(0x11.toChar(), Color(0xFFE080)), //*y ellow Pair(0x12.toChar(), Color(0xFFB020)), //o range Pair(0x13.toChar(), Color(0xFF8080)), //*r ed Pair(0x14.toChar(), Color(0xFFA0E0)), //f uchsia Pair(0x15.toChar(), Color(0xE0A0FF)), //*m agenta (purple) Pair(0x16.toChar(), Color(0x8080FF)), //*b lue Pair(0x17.toChar(), Color(0xFF80FF)), //c yan Pair(0x18.toChar(), Color(0x80FF80)), //*g reen Pair(0x19.toChar(), Color(0x008000)), //v iridian Pair(0x1A.toChar(), Color(0x805030)), //x (khaki) Pair(0x1B.toChar(), Color(0x808080)) //*k //* marked: commonly used ) val colToCode = hashMapOf( Pair("w", 0x10.toChar()), Pair("y", 0x11.toChar()), Pair("o", 0x12.toChar()), Pair("r", 0x13.toChar()), Pair("f", 0x14.toChar()), Pair("m", 0x15.toChar()), Pair("b", 0x16.toChar()), Pair("c", 0x17.toChar()), Pair("g", 0x18.toChar()), Pair("v", 0x19.toChar()), Pair("x", 0x1A.toChar()), Pair("k", 0x1B.toChar()) ) val codeToCol = hashMapOf( Pair("w", colourKey[0x10.toChar()]), Pair("y", colourKey[0x11.toChar()]), Pair("o", colourKey[0x12.toChar()]), Pair("r", colourKey[0x13.toChar()]), Pair("f", colourKey[0x14.toChar()]), Pair("m", colourKey[0x15.toChar()]), Pair("b", colourKey[0x16.toChar()]), Pair("c", colourKey[0x17.toChar()]), Pair("g", colourKey[0x18.toChar()]), Pair("v", colourKey[0x19.toChar()]), Pair("x", colourKey[0x1A.toChar()]), Pair("k", colourKey[0x1B.toChar()]) ) } }