diff --git a/.gitignore b/.gitignore index 51eb804..0698352 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ demo/out/* demo/lib/* +demo/assets/* +out/* +lib/* \ No newline at end of file diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..ec36fc9 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +BuildJAR_TerrarumSansBitmap \ No newline at end of file diff --git a/.idea/artifacts/TerrarumSansBitmap.xml b/.idea/artifacts/TerrarumSansBitmap.xml new file mode 100644 index 0000000..551cf89 --- /dev/null +++ b/.idea/artifacts/TerrarumSansBitmap.xml @@ -0,0 +1,11 @@ + + + $PROJECT_DIR$/out/artifacts/TerrarumSansBitmap + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/KotlinJavaRuntime.xml b/.idea/libraries/KotlinJavaRuntime.xml new file mode 100644 index 0000000..c630c0b --- /dev/null +++ b/.idea/libraries/KotlinJavaRuntime.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..fa8838a --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..cac86c6 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..e68d521 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..65ee9a9 --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,511 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1497950823354 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TerrarumSansBitmap + + + + + + + + No facets are configured + + + + + + + + + + + + + + + 1.8 + + + + + + + + BuildJAR_TerrarumSansBitmap + + + + + + + + lib + + + + + + + + \ No newline at end of file diff --git a/BuildJAR_TerrarumSansBitmap.iml b/BuildJAR_TerrarumSansBitmap.iml new file mode 100644 index 0000000..c33f24f --- /dev/null +++ b/BuildJAR_TerrarumSansBitmap.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/META-INF/MANIFEST.MF b/META-INF/MANIFEST.MF new file mode 100644 index 0000000..59499bc --- /dev/null +++ b/META-INF/MANIFEST.MF @@ -0,0 +1,2 @@ +Manifest-Version: 1.0 + diff --git a/README.md b/README.md index 9e5576e..e3fd143 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,49 @@ You can contribute to the font by fixing wrong glyphs, suggesting better ones, e Font Spritesheets are stored in ```assets/graphics/fonts``` directory. Image format must be TGA with Alpha — no PNG. If someone needs PNG, they can batch-convert the font using utils like ImageMagick. +## Using on LibGDX + +On your code (Kotlin): + + class YourGame : Game() { + + lateinit var fontGame: Font + + override fun create() { + fontGame = GameFontBase(path_to_assets) + ... + } + + override fun render() { + batch.begin() + ... + fontGame.draw(batch, text, ...) + ... + batch.end() + } + } + +On your code (Java): + + class YourGame extends BasicGame { + + Font fontGame; + + @Override void create() { + fontGame = new GameFontBase(path_to_assets); + ... + } + + @Override void render() { + batch.begin(); + ... + fontGame.draw(batch, text, ...); + ... + batch.end(); + } + } + + ## Using on Slick2d On your code (Kotlin): @@ -31,7 +74,7 @@ On your code (Kotlin): lateinit var fontGame: Font override fun init(gc: GameContainer) { - fontGame = GameFontImpl() + fontGame = GameFontBase(path_to_assets) ... } @@ -48,7 +91,7 @@ On your code (Java): Font fontGame; @Override void init(GameContainer gc) { - fontGame = new GameFontImpl(); + fontGame = new GameFontBase(path_to_assets); ... } diff --git a/TerrarumSansBitmap.jar b/TerrarumSansBitmap.jar new file mode 100644 index 0000000..608dbc5 Binary files /dev/null and b/TerrarumSansBitmap.jar differ diff --git a/assets/hangul_johab.tga b/assets/hangul_johab.tga index 64b3207..6bf0995 100644 Binary files a/assets/hangul_johab.tga and b/assets/hangul_johab.tga differ diff --git a/demo/.idea/kotlinc.xml b/demo/.idea/kotlinc.xml new file mode 100644 index 0000000..0dd4b35 --- /dev/null +++ b/demo/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/demo/.idea/workspace.xml b/demo/.idea/workspace.xml index 9aa6736..5e92d94 100644 --- a/demo/.idea/workspace.xml +++ b/demo/.idea/workspace.xml @@ -25,7 +25,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -389,7 +389,6 @@ - @@ -410,6 +409,7 @@ + @@ -431,6 +431,26 @@ - - - - - - - - + @@ -634,18 +615,10 @@ - - - - - - - - - + @@ -668,19 +641,11 @@ - - - - - - - - + - @@ -688,7 +653,6 @@ - @@ -710,7 +674,7 @@ - + @@ -721,7 +685,7 @@ - + diff --git a/terrarumsansbitmap/gdx/GameFontBase.kt b/src/net/torvald/terrarumsansbitmap/gdx/GameFontBase.kt similarity index 95% rename from terrarumsansbitmap/gdx/GameFontBase.kt rename to src/net/torvald/terrarumsansbitmap/gdx/GameFontBase.kt index 970d46c..1828324 100644 --- a/terrarumsansbitmap/gdx/GameFontBase.kt +++ b/src/net/torvald/terrarumsansbitmap/gdx/GameFontBase.kt @@ -1,3 +1,27 @@ +/* + * Terrarum Sans Bitmap + * + * Copyright (c) 2017 Minjae Song (Torvald) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package net.torvald.terrarumsansbitmap.gdx import com.badlogic.gdx.Gdx diff --git a/terrarumsansbitmap/gdx/TextureRegionPack.kt b/src/net/torvald/terrarumsansbitmap/gdx/TextureRegionPack.kt similarity index 62% rename from terrarumsansbitmap/gdx/TextureRegionPack.kt rename to src/net/torvald/terrarumsansbitmap/gdx/TextureRegionPack.kt index 9e9aed6..f7675a9 100644 --- a/terrarumsansbitmap/gdx/TextureRegionPack.kt +++ b/src/net/torvald/terrarumsansbitmap/gdx/TextureRegionPack.kt @@ -1,3 +1,27 @@ +/* + * Terrarum Sans Bitmap + * + * Copyright (c) 2017 Minjae Song (Torvald) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package net.torvald.terrarumsansbitmap.gdx import com.badlogic.gdx.files.FileHandle diff --git a/terrarumsansbitmap/readme.md b/src/net/torvald/terrarumsansbitmap/readme.md similarity index 100% rename from terrarumsansbitmap/readme.md rename to src/net/torvald/terrarumsansbitmap/readme.md diff --git a/src/net/torvald/terrarumsansbitmap/slick2d/GameFontBase.kt b/src/net/torvald/terrarumsansbitmap/slick2d/GameFontBase.kt new file mode 100644 index 0000000..af0b683 --- /dev/null +++ b/src/net/torvald/terrarumsansbitmap/slick2d/GameFontBase.kt @@ -0,0 +1,724 @@ +/* + * Terrarum Sans Bitmap + * + * Copyright (c) 2017 Minjae Song (Torvald) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.torvald.terrarumsansbitmap.slick2d + +import org.newdawn.slick.Color +import org.newdawn.slick.Font +import org.newdawn.slick.Image +import org.newdawn.slick.SpriteSheet +import org.newdawn.slick.opengl.Texture +import java.io.BufferedOutputStream +import java.io.File +import java.io.FileInputStream +import java.io.FileOutputStream +import java.util.* +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. + * + * @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```. + * + * Created by minjaesong on 2017-06-15. + */ +class GameFontBase(fontDir: String, val noShadow: Boolean = false) : Font { + + 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 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 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] + private fun isCJKPunct(c: Char) = c.toInt() in codeRange[SHEET_CJK_PUNCT] + private fun isUniHan(c: Char) = c.toInt() in codeRange[SHEET_UNIHAN] + private fun isCyrilic(c: Char) = c.toInt() in codeRange[SHEET_CYRILIC_VARW] + private fun isFullwidthUni(c: Char) = c.toInt() in codeRange[SHEET_FW_UNI] + private fun isUniPunct(c: Char) = c.toInt() in codeRange[SHEET_UNI_PUNCT] + private fun isGreek(c: Char) = c.toInt() in codeRange[SHEET_GREEK_VARW] + private fun isThai(c: Char) = c.toInt() in codeRange[SHEET_THAI_VARW] + private fun isDiacritics(c: Char) = c.toInt() in 0xE34..0xE3A + || c.toInt() in 0xE47..0xE4E + || c.toInt() == 0xE31 + private fun isCustomSym(c: Char) = c.toInt() in codeRange[SHEET_CUSTOM_SYM] + 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 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 fun armenianIndexX(c: Char) = (c.toInt() - 0x530) % 16 + private fun armenianIndexY(c: Char) = (c.toInt() - 0x530) / 16 + + private fun kartvelianIndexX(c: Char) = (c.toInt() - 0x10D0) % 16 + private fun kartvelianIndexY(c: Char) = (c.toInt() - 0x10D0) / 16 + + private fun ipaIndexX(c: Char) = (c.toInt() - 0x250) % 16 + private fun ipaIndexY(c: Char) = (c.toInt() - 0x250) / 16 + + private val unihanWidthSheets = arrayOf( + SHEET_UNIHAN, + SHEET_FW_UNI + ) + private val variableWidthSheets = arrayOf( + SHEET_ASCII_VARW, + SHEET_EXTA_VARW, + SHEET_EXTB_VARW, + SHEET_CYRILIC_VARW, + SHEET_UNI_PUNCT, + SHEET_GREEK_VARW, + SHEET_THAI_VARW, + SHEET_HAYEREN_VARW, + SHEET_KARTULI_VARW, + SHEET_IPA_VARW + ) + + private val fontParentDir = if (fontDir.endsWith('/') || fontDir.endsWith('\\')) fontDir else "$fontDir/" + 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", + "hayeren_variable.tga", + "kartuli_variable.tga", + "ipa_ext_variable.tga", + "puae000-e0ff.tga" + ) + private val cyrilic_bg = "cyrilic_bulgarian_variable.tga" + private val cyrilic_sr = "cyrilic_serbian_variable.tga" + private val codeRange = arrayOf( // MUST BE MATCHING WITH SHEET INDICES!! + 0..0xFF, + 0xAC00..0xD7A3, + 0x100..0x17F, + 0x180..0x24F, + 0x3040..0x30FF, + 0x3000..0x303F, + 0x3400..0x9FFF, + 0x400..0x52F, + 0xFF00..0xFF1F, + 0x2000..0x205F, + 0x370..0x3CE, + 0xE00..0xE5F, + 0x530..0x58F, + 0x10D0..0x10FF, + 0x250..0x2AF, + 0xE000..0xE0FF + ) + private val glyphWidths: HashMap = HashMap() // if the value is negative, it's diacritics + private val sheets: Array + + + init { + val sheetsPack = ArrayList() + + // first we create pixmap to read pixels, then make texture using pixmap + fileList.forEachIndexed { index, it -> + 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 image: Image + + + // unpack gz if applicable + if (it.endsWith(".gz")) { + val gzi = GZIPInputStream(FileInputStream(fontParentDir + it)) + val wholeFile = gzi.readBytes() + gzi.close() + val fos = BufferedOutputStream(FileOutputStream("tmp_wenquanyi.tga")) + fos.write(wholeFile) + fos.flush() + fos.close() + + image = Image("tmp_wenquanyi.tga") + + File("tmp_wenquanyi.tga").delete() + } + else { + image = Image(fontParentDir + it) + } + + val texture = image.texture + + if (isVariable) { + println("[TerrarumSansBitmap] loading texture $it [VARIABLE]") + buildWidthTable(texture, codeRange[index], 16) + } + else { + println("[TerrarumSansBitmap] loading texture $it") + } + + val texRegPack = if (isVariable) { + SpriteSheet(image, W_VAR_INIT, H - 1, HGAP_VAR) + } + else if (index == SHEET_UNIHAN) { + SpriteSheet(image, 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) { + SpriteSheet(image, W_UNIHAN, H) + } + else if (index == SHEET_CJK_PUNCT) { + SpriteSheet(image, W_ASIAN_PUNCT, H) + } + else if (index == SHEET_KANA) { + SpriteSheet(image, W_KANA, H) + } + else if (index == SHEET_HANGUL) { + SpriteSheet(image, W_HANGUL, H) + } + else if (index == SHEET_CUSTOM_SYM) { + SpriteSheet(image, SIZE_CUSTOM_SYM, SIZE_CUSTOM_SYM) // TODO variable + } + else throw IllegalArgumentException("[TerrarumSansBitmap] Unknown sheet index: $index") + + + sheetsPack.add(texRegPack) + } + + sheets = sheetsPack.toTypedArray() + } + + private var localeBuffer = "" + + fun reload(locale: String) { + if (!localeBuffer.startsWith("ru") && locale.startsWith("ru")) { + val image = Image(fontParentDir + fileList[SHEET_CYRILIC_VARW]) + sheets[SHEET_CYRILIC_VARW].destroy() + sheets[SHEET_CYRILIC_VARW] = SpriteSheet(image, W_VAR_INIT, H, HGAP_VAR, 0) + } + else if (!localeBuffer.startsWith("bg") && locale.startsWith("bg")) { + val image = Image(fontParentDir + cyrilic_bg) + sheets[SHEET_CYRILIC_VARW].destroy() + sheets[SHEET_CYRILIC_VARW] = SpriteSheet(image, W_VAR_INIT, H, HGAP_VAR, 0) + } + else if (!localeBuffer.startsWith("sr") && locale.startsWith("sr")) { + val image = Image(fontParentDir + cyrilic_sr) + sheets[SHEET_CYRILIC_VARW].destroy() + sheets[SHEET_CYRILIC_VARW] = SpriteSheet(image, W_VAR_INIT, H, HGAP_VAR, 0) + } + + localeBuffer = locale + } + + override fun getLineHeight(): Int = H + override fun getHeight(p0: String) = lineHeight + + + + + private val offsetUnihan = (H - H_UNIHAN) / 2 + private val offsetCustomSym = (H - SIZE_CUSTOM_SYM) / 2 + + private var textBuffer: CharSequence = "" + private var textBWidth = intArrayOf() // absolute posX of glyphs from print-origin + private var textBGSize = intArrayOf() // width of each glyph + + override fun drawString(x: Float, y: Float, str: String) { + drawString(x, y, str, Color.white) + } + + override fun drawString(p0: Float, p1: Float, p2: String?, p3: Color?, p4: Int, p5: Int) { + throw UnsupportedOperationException() + } + + override fun drawString(x: Float, y: Float, str: String, color: Color) { + if (textBuffer != str) { + textBuffer = str + val widths = getWidthOfCharSeq(str) + + textBGSize = widths + + textBWidth = IntArray(str.length, { charIndex -> + if (charIndex == 0) + 0 + else { + var acc = 0 + (0..charIndex - 1).forEach { acc += maxOf(0, widths[it]) } // don't accumulate diacrtics (which has negative value) + /*return*/acc + } + }) + } + + + //print("[TerrarumSansBitmap] widthTable for $textBuffer: ") + //textBWidth.forEach { print("$it ") }; println() + + + val mainCol = color + val shadowCol = color.darker(0.5f) + + + textBuffer.forEachIndexed { index, c -> + val sheetID = getSheetType(c) + val sheetXY = getSheetwisePosition(c) + + //println("[TerrarumSansBitmap] sprite: $sheetID:${sheetXY[0]}x${sheetXY[1]}") + + if (sheetID == SHEET_HANGUL) { + val hangulSheet = sheets[SHEET_HANGUL] + 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) + + + if (!noShadow) { + hangulSheet.getSubImage(indexCho, choRow ).draw(x + textBWidth[index] + 1, y, shadowCol) + hangulSheet.getSubImage(indexCho, choRow ).draw(x + textBWidth[index] , y, shadowCol) + hangulSheet.getSubImage(indexCho, choRow ).draw(x + textBWidth[index] + 1, y, shadowCol) + + hangulSheet.getSubImage(indexJung, jungRow).draw(x + textBWidth[index] + 1, y, shadowCol) + hangulSheet.getSubImage(indexJung, jungRow).draw(x + textBWidth[index] , y, shadowCol) + hangulSheet.getSubImage(indexJung, jungRow).draw(x + textBWidth[index] + 1, y, shadowCol) + + hangulSheet.getSubImage(indexJong, jongRow).draw(x + textBWidth[index] + 1, y, shadowCol) + hangulSheet.getSubImage(indexJong, jongRow).draw(x + textBWidth[index] , y, shadowCol) + hangulSheet.getSubImage(indexJong, jongRow).draw(x + textBWidth[index] + 1, y, shadowCol) + } + + + hangulSheet.getSubImage(indexCho, choRow ).draw(x + textBWidth[index], y, mainCol) + hangulSheet.getSubImage(indexJung, jungRow).draw(x + textBWidth[index], y, mainCol) + hangulSheet.getSubImage(indexJong, jongRow).draw(x + textBWidth[index], y, mainCol) + } + else { + try { + val offset = if (!isDiacritics(c)) 0 else { + if (index > 0) // LIMITATION: does not support double (or more) diacritics properly + (textBGSize[index] - textBGSize[index - 1]) / 2 + else + textBGSize[index] + } + + if (!noShadow) { + sheets[sheetID].getSubImage(sheetXY[0], sheetXY[1]).draw( + x + textBWidth[index] + 1 + offset, + y + (if (sheetID == SHEET_UNIHAN) // evil exceptions + offsetUnihan + else if (sheetID == SHEET_CUSTOM_SYM) + offsetCustomSym + else + 0), + shadowCol + ) + sheets[sheetID].getSubImage(sheetXY[0], sheetXY[1]).draw( + x + textBWidth[index] + offset, + y + (if (sheetID == SHEET_UNIHAN) // evil exceptions + offsetUnihan + 1 + else if (sheetID == SHEET_CUSTOM_SYM) + offsetCustomSym + 1 + else + 1), + shadowCol + ) + sheets[sheetID].getSubImage(sheetXY[0], sheetXY[1]).draw( + x + textBWidth[index] + 1 + offset, + y + (if (sheetID == SHEET_UNIHAN) // evil exceptions + offsetUnihan + 1 + else if (sheetID == SHEET_CUSTOM_SYM) + offsetCustomSym + 1 + else + 1), + shadowCol + ) + } + + + sheets[sheetID].getSubImage(sheetXY[0], sheetXY[1]).draw( + x + textBWidth[index] + offset, + y + if (sheetID == SHEET_UNIHAN) // evil exceptions + offsetUnihan + else if (sheetID == SHEET_CUSTOM_SYM) + offsetCustomSym + else 0, + mainCol + ) + } + catch (noSuchGlyph: ArrayIndexOutOfBoundsException) { + } + } + } + + } + + + fun dispose() { + sheets.forEach { it.destroy() } + } + + 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)) { + if (!glyphWidths.containsKey(chr.toInt())) { + println("[TerrarumSansBitmap] no width data for glyph number ${Integer.toHexString(chr.toInt()).toUpperCase()}") + len[i] = W_LATIN_WIDE + } + + len[i] = glyphWidths[chr.toInt()]!! + } + 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 (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 if (isArmenian(c)) + return SHEET_HAYEREN_VARW + else if (isKartvelian(c)) + return SHEET_KARTULI_VARW + else if (isIPA(c)) + return SHEET_IPA_VARW + else + return SHEET_UNKNOWN + // fixed width + // fallback + } + + private fun getSheetwisePosition(ch: Char): IntArray { + val sheetX: Int; val sheetY: Int + when (getSheetType(ch)) { + SHEET_UNIHAN -> { + sheetX = unihanIndexX(ch) + sheetY = unihanIndexY(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) + } + SHEET_HAYEREN_VARW -> { + sheetX = armenianIndexX(ch) + sheetY = armenianIndexY(ch) + } + SHEET_KARTULI_VARW -> { + sheetX = kartvelianIndexX(ch) + sheetY = kartvelianIndexY(ch) + } + SHEET_IPA_VARW -> { + sheetX = ipaIndexX(ch) + sheetY = ipaIndexY(ch) + } + else -> { + sheetX = ch.toInt() % 16 + sheetY = ch.toInt() / 16 + } + } + + return intArrayOf(sheetX, sheetY) + } + + fun buildWidthTable(texture: Texture, codeRange: IntRange, cols: Int = 16) { + val binaryCodeOffset = W_VAR_INIT + + val cellW = W_VAR_INIT + 1 + val cellH = H + + for (code in codeRange) { + + val cellX = ((code - codeRange.start) % cols) * cellW + val cellY = ((code - codeRange.start) / cols) * cellH + + val codeStartX = cellX + binaryCodeOffset + val codeStartY = cellY + + var glyphWidth = 0 + + for (downCtr in 0..3) { + // if ALPHA is not zero, assume it's 1 + if (texture.textureData[4 * (codeStartX + (codeStartY + downCtr) * texture.textureWidth) + 3] != 0.toByte()) { + glyphWidth = glyphWidth or (1 shl downCtr) + } + } + + val isDiacritics = texture.textureData[4 * (codeStartX + (codeStartY + H - 1) * texture.textureWidth) + 3] != 0.toByte() + if (isDiacritics) + glyphWidth = -glyphWidth + + glyphWidths[code] = glyphWidth + } + } + + + override fun getWidth(text: String): Int { + 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 + + 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 diff --git a/terrarumsansbitmap/slick2d/GameFontBase.kt b/terrarumsansbitmap/slick2d/GameFontBase.kt deleted file mode 100644 index b1443dc..0000000 --- a/terrarumsansbitmap/slick2d/GameFontBase.kt +++ /dev/null @@ -1,551 +0,0 @@ -package net.torvald.terrarumsansbitmap.slick2d - -import net.torvald.terrarum.getPixel -import org.lwjgl.opengl.GL11 -import org.newdawn.slick.* -import java.util.* - -/** - * Created by minjaesong on 16-01-27. - */ -open class GameFontBase(val noShadow: Boolean) : Font { - - 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 - ) - - - 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 chr = s[i] - val ctype = getSheetType(s[i]) - - if (variableWidthSheets.contains(ctype)) { - len += 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 += 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 if (ctype == SHEET_CUSTOM_SYM) - len += SIZE_KEYCAP - 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) - - hangulSheet.getSubImage(indexCho, choRow).drawWithShadow( - Math.round(x + getWidthSubstr(s, i + 1) - W_HANGUL).toFloat(), - Math.round(y).toFloat(), - scale.toFloat(), thisCol, noShadow - ) - hangulSheet.getSubImage(indexJung, jungRow).drawWithShadow( - Math.round(x + getWidthSubstr(s, i + 1) - W_HANGUL).toFloat(), - Math.round(y).toFloat(), - scale.toFloat(), thisCol, noShadow - ) - hangulSheet.getSubImage(indexJong, jongRow).drawWithShadow( - Math.round(x + getWidthSubstr(s, i + 1) - W_HANGUL).toFloat(), - Math.round(y).toFloat(), - scale.toFloat(), thisCol, noShadow - ) - } - } - //hangulSheet.endUse() - - // WenQuanYi - //uniHan.startUse() - - for (i in 0..s.length - 1) { - val ch = s[i] - - if (ch.isColourCode()) { - thisCol = colourKey[ch]!! - continue - } - - if (isUniHan(ch)) { - val glyphW = getWidth("" + ch) - uniHan.getSubImage(unihanIndexX(ch), unihanIndexY(ch)).drawWithShadow( - Math.round(x + getWidthSubstr(s, i + 1) - glyphW).toFloat(), - Math.round((H - H_UNIHAN) / 2 + y).toFloat(), - scale.toFloat(), thisCol, noShadow - ) - } - } - - //uniHan.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_UNIHAN -> { - sheetX = unihanIndexX(ch) - sheetY = unihanIndexY(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 - } - } - - val glyphW = getWidth("" + ch) - try { - sheetKey[prevInstance]!!.getSubImage(sheetX, sheetY).drawWithShadow( - 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_CUSTOM_SYM) (H - SIZE_KEYCAP) / 2 // completely legit height adjustment - else 0).toFloat(), - - scale.toFloat(), thisCol, noShadow - ) - } - 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 { - 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 - } - - /** - * 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) - } - - fun Char.isColourCode() = colourKey.containsKey(this) - - fun buildWidthTable(sheet: SpriteSheet, codeOffset: Int, codeRange: IntRange, rows: Int = 16) { - val binaryCodeOffset = 15 - - val cellW = sheet.getSubImage(0, 0).width + 1 // should be 16 - val cellH = sheet.getSubImage(0, 0).height + 1 // should be 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 (sheet.texture.getPixel(codeStartX, codeStartY + downCtr)[3] == 255) { - glyphWidth = glyphWidth or (1 shl downCtr) - } - } - - glyphWidths[codeOffset + ccode] = glyphWidth - } - } - - companion object { - - internal val glyphWidths: HashMap = HashMap() - - lateinit internal var hangulSheet: SpriteSheet - lateinit internal var asciiSheet: SpriteSheet - lateinit internal var runicSheet: SpriteSheet - lateinit internal var extASheet: SpriteSheet - lateinit internal var extBSheet: SpriteSheet - lateinit internal var kanaSheet: SpriteSheet - lateinit internal var cjkPunct: SpriteSheet - lateinit internal var uniHan: SpriteSheet - lateinit internal var cyrilic: SpriteSheet - lateinit internal var fullwidthForms: SpriteSheet - lateinit internal var uniPunct: SpriteSheet - lateinit internal var greekSheet: SpriteSheet - lateinit internal var thaiSheet: SpriteSheet - lateinit internal var customSheet: SpriteSheet - - 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 H = 20 - internal val H_UNIHAN = 16 - - internal val SIZE_KEYCAP = 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 - - lateinit internal var sheetKey: Array - - /** - * 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('ᚠ', 'ᚢ', 'ᚦ', 'ᚬ', 'ᚱ', 'ᚴ', 'ᚼ', 'ᚾ', 'ᛁ', 'ᛅ', 'ᛋ', 'ᛏ', 'ᛒ', 'ᛘ', 'ᛚ', 'ᛦ', 'ᛂ', '᛬', '᛫', '᛭', 'ᛮ', 'ᛯ', 'ᛰ') - - 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)") - } - - 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(0x80FFFF)), //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()]) - ) - }// end of companion object -} - -fun Image.drawWithShadow(x: Float, y: Float, color: Color, noShadow: Boolean) = - this.drawWithShadow(x, y, 1f, color, noShadow) - -fun Image.drawWithShadow(x: Float, y: Float, scale: Float, color: Color, noShadow: Boolean) { - if (!noShadow) { - this.draw(x + 1, y + 1, scale, color.darker(0.5f)) - this.draw(x, y + 1, scale, color.darker(0.5f)) - this.draw(x + 1, y, scale, color.darker(0.5f)) - } - - this.draw(x, y, scale, color) -} \ No newline at end of file diff --git a/terrarumsansbitmap/slick2d/GameFontImpl.kt b/terrarumsansbitmap/slick2d/GameFontImpl.kt deleted file mode 100644 index e09e284..0000000 --- a/terrarumsansbitmap/slick2d/GameFontImpl.kt +++ /dev/null @@ -1,81 +0,0 @@ -package net.torvald.terrarumsansbitmap.slick2d - -import net.torvald.terrarum.Terrarum - -/** - * Created by minjaesong on 16-01-20. - */ -class GameFontImpl(noShadow: Boolean = false) : GameFontBase(noShadow = noShadow) { - - init { - - GameFontBase.hangulSheet = org.newdawn.slick.SpriteSheet( - "./assets/graphics/fonts/hangul_johab.tga", GameFontBase.W_HANGUL, GameFontBase.H) - GameFontBase.asciiSheet = org.newdawn.slick.SpriteSheet( - "./assets/graphics/fonts/ascii_variable.tga", 15, 19, 1) - GameFontBase.runicSheet = org.newdawn.slick.SpriteSheet( - "./assets/graphics/fonts/futhark.tga", GameFontBase.W_LATIN_WIDE, GameFontBase.H) - GameFontBase.extASheet = org.newdawn.slick.SpriteSheet( - "./assets/graphics/fonts/LatinExtA_variable.tga", 15, 19, 1) - GameFontBase.extBSheet = org.newdawn.slick.SpriteSheet( - "./assets/graphics/fonts/LatinExtB_variable.tga", 15, 19, 1) - GameFontBase.kanaSheet = org.newdawn.slick.SpriteSheet( - "./assets/graphics/fonts/kana.tga", GameFontBase.W_KANA, GameFontBase.H) - GameFontBase.cjkPunct = org.newdawn.slick.SpriteSheet( - "./assets/graphics/fonts/cjkpunct.tga", GameFontBase.W_ASIAN_PUNCT, GameFontBase.H) - 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 = org.newdawn.slick.SpriteSheet( - "./assets/graphics/fonts/fullwidth_forms.tga", GameFontBase.W_UNIHAN, GameFontBase.H_UNIHAN) - GameFontBase.uniPunct = org.newdawn.slick.SpriteSheet( - "./assets/graphics/fonts/unipunct.tga", GameFontBase.W_LATIN_WIDE, GameFontBase.H) - GameFontBase.uniHan = org.newdawn.slick.SpriteSheet( - "./assets/graphics/fonts/wenquanyi.tga.gz", 16, 16) // ~32 MB - GameFontBase.greekSheet = org.newdawn.slick.SpriteSheet( - "./assets/graphics/fonts/greek_variable.tga", 15, 19, 1) - 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( - GameFontBase.asciiSheet, - GameFontBase.hangulSheet, - GameFontBase.runicSheet, - GameFontBase.extASheet, - GameFontBase.extBSheet, - GameFontBase.kanaSheet, - GameFontBase.cjkPunct, - GameFontBase.uniHan, - GameFontBase.cyrilic, - GameFontBase.fullwidthForms, - GameFontBase.uniPunct, - GameFontBase.greekSheet, - GameFontBase.thaiSheet, - null, // Thai EF, filler because not being used right now - GameFontBase.customSheet - ) - GameFontBase.sheetKey = shk - - - 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 = 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) - } -}