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
+
+
+ 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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -445,18 +465,10 @@
-
-
-
-
-
-
-
-
-
+
@@ -481,18 +493,10 @@
-
-
-
-
-
-
-
-
-
+
@@ -517,18 +521,10 @@
-
-
-
-
-
-
-
-
-
+
@@ -549,19 +545,11 @@
-
-
-
-
-
-
-
-
+
-
@@ -595,14 +583,7 @@
-
-
-
-
-
-
-
-
+
@@ -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)
- }
-}