mirror of
https://github.com/curioustorvald/Terrarum-sans-bitmap.git
synced 2026-03-07 11:51:50 +09:00
ext-a and readme update
This commit is contained in:
10
README.md
10
README.md
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
**Font demo** — head to the **Release** tab
|
**Font demo** — head to the **Release** tab
|
||||||
|
|
||||||
This font is a bitmap font used in my game project, Terrarum (hence the name). It Supports ExtA, Romanian (subset of ExtB), Cyrillic (Russian, Bulgarian, Serbian), Greek, Chinese, Japanese and Korean.
|
This font is a bitmap font used in my game project, Terrarum (hence the name). It Supports Latin-1 Supplement, Latin Ext-A, Latin Ext-B (already covers more than 90% of european languages), Cyrillic (Russian, Bulgarian, Serbian), Greek, Chinese, Japanese and Korean.
|
||||||
|
|
||||||
The code for the fonts are meant to be used with Slick2d (extends ```Font``` class). If you are not using the framework, please refer to the __Font metrics__ section to implement the font metrics correctly on your system.
|
The code for the fonts are meant to be used with Slick2d (extends ```Font``` class). If you are not using the framework, please refer to the __Font metrics__ section to implement the font metrics correctly on your system.
|
||||||
|
|
||||||
@@ -15,9 +15,9 @@ The issue page is open. If you have some issues to submit, or have a question, p
|
|||||||
|
|
||||||
## Contribution guidelines
|
## Contribution guidelines
|
||||||
|
|
||||||
You can contribute to the font by fixing wrong glyphs, suggesting better ones, extending character set (like Latin Extended B), or code for other game frameworks such as LibGDX. Please leave pull request for that.
|
You can contribute to the font by fixing wrong glyphs, suggesting better ones, extending character set (like Georgian and Thai), or code for other game frameworks such as LibGDX. Please leave pull request for that.
|
||||||
|
|
||||||
Font images 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.
|
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 Slick2d
|
## Using on Slick2d
|
||||||
@@ -58,11 +58,11 @@ On your code (Java):
|
|||||||
|
|
||||||
## Font metrics
|
## Font metrics
|
||||||
|
|
||||||
The font expects both variable widths and fixed width to be supported. Any images with ```_variable``` means it expects variable widths. Anything else expects fixed width. ```romana_narrow``` has width of 6 (no, not 5), ```romana_wide``` has width of 9, ```cjkpunct``` has width of 10, ```kana``` has width of 12, ```hangul_johab``` has width of 11, ```wenquanyi``` has width of 16.
|
Although the font is basically a Spritesheet, some of the sheet expects variable widths to be supported. Any sheets with ```_variable``` means it expects variable widths. Anything else expects fixed width (regular Spritesheet behaviour). ```cjkpunct``` has width of 10, ```kana``` has width of 12, ```hangul_johab``` has width of 11, ```wenquanyi``` has width of 16.
|
||||||
|
|
||||||
### Parsing glyph widths for variable font sheets
|
### Parsing glyph widths for variable font sheets
|
||||||
|
|
||||||
Width is encoded in binary number, on pixels. On the font image, every glyph has vertical dots on their right side (to be exact, every (16k - 1)th pixel on x axis). From top to bottom, each dot represents 1, 2, 4 and 8. For example, ASCII glyph 'C' has width of 9, 'W' has width of 11, " (double quote) has width of 6.
|
Width is encoded in binary number, on pixels. On the font spritesheet, every glyph has vertical dots on their right side (to be exact, every (16k - 1)th pixel on x axis). From top to bottom, each dot represents 1, 2, 4 and 8. For example, ASCII glyph 'C' has width of 9, 'W' has width of 11, " (double quote) has width of 6.
|
||||||
|
|
||||||
### Implementing the Korean writing system
|
### Implementing the Korean writing system
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 160 KiB After Width: | Height: | Size: 160 KiB |
552
code_for_Slick2d/GameFontBase.kt
Normal file
552
code_for_Slick2d/GameFontBase.kt
Normal file
@@ -0,0 +1,552 @@
|
|||||||
|
package net.torvald.imagefont
|
||||||
|
|
||||||
|
import org.lwjgl.opengl.GL11
|
||||||
|
import org.newdawn.slick.*
|
||||||
|
import org.newdawn.slick.opengl.Texture
|
||||||
|
import java.nio.ByteOrder
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by minjaesong on 16-01-27.
|
||||||
|
*/
|
||||||
|
open class GameFontBase : Font {
|
||||||
|
|
||||||
|
private fun getHan(hanIndex: Int): IntArray {
|
||||||
|
val han_x = hanIndex % JONG_COUNT
|
||||||
|
val han_y = hanIndex / JONG_COUNT
|
||||||
|
val ret = intArrayOf(han_x, han_y)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getHanChosung(hanIndex: Int) = hanIndex / (JUNG_COUNT * JONG_COUNT)
|
||||||
|
|
||||||
|
private fun getHanJungseong(hanIndex: Int) = hanIndex / JONG_COUNT % JUNG_COUNT
|
||||||
|
|
||||||
|
private fun getHanJongseong(hanIndex: Int) = hanIndex % JONG_COUNT
|
||||||
|
|
||||||
|
private val jungseongWide = arrayOf(8, 12, 13, 17, 18, 21)
|
||||||
|
private val jungseongComplex = arrayOf(9, 10, 11, 14, 15, 16, 22)
|
||||||
|
|
||||||
|
private fun isJungseongWide(hanIndex: Int) = jungseongWide.contains(getHanJungseong(hanIndex))
|
||||||
|
private fun isJungseongComplex(hanIndex: Int) = jungseongComplex.contains(getHanJungseong(hanIndex))
|
||||||
|
|
||||||
|
private fun getHanInitialRow(hanIndex: Int): Int {
|
||||||
|
val ret: Int
|
||||||
|
|
||||||
|
if (isJungseongWide(hanIndex))
|
||||||
|
ret = 2
|
||||||
|
else if (isJungseongComplex(hanIndex))
|
||||||
|
ret = 4
|
||||||
|
else
|
||||||
|
ret = 0
|
||||||
|
|
||||||
|
return if (getHanJongseong(hanIndex) == 0) ret else ret + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getHanMedialRow(hanIndex: Int) = if (getHanJongseong(hanIndex) == 0) 6 else 7
|
||||||
|
|
||||||
|
private fun getHanFinalRow(hanIndex: Int): Int {
|
||||||
|
val jungseongIndex = getHanJungseong(hanIndex)
|
||||||
|
|
||||||
|
return if (jungseongWide.contains(jungseongIndex))
|
||||||
|
8
|
||||||
|
else
|
||||||
|
9
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isHangul(c: Char) = c.toInt() >= 0xAC00 && c.toInt() < 0xD7A4
|
||||||
|
private fun isAscii(c: Char) = c.toInt() >= 0x20 && c.toInt() <= 0xFF
|
||||||
|
private fun isExtA(c: Char) = c.toInt() >= 0x100 && c.toInt() < 0x180
|
||||||
|
private fun isKana(c: Char) = c.toInt() >= 0x3040 && c.toInt() < 0x3100
|
||||||
|
private fun isCJKPunct(c: Char) = c.toInt() >= 0x3000 && c.toInt() < 0x3040
|
||||||
|
private fun isUniHan(c: Char) = c.toInt() >= 0x3400 && c.toInt() < 0xA000
|
||||||
|
private fun isCyrilic(c: Char) = c.toInt() >= 0x400 && c.toInt() < 0x460
|
||||||
|
private fun isFullwidthUni(c: Char) = c.toInt() >= 0xFF00 && c.toInt() < 0xFF20
|
||||||
|
private fun isUniPunct(c: Char) = c.toInt() >= 0x2000 && c.toInt() < 0x2070
|
||||||
|
private fun isWenQuanYi1(c: Char) = c.toInt() >= 0x33F3 && c.toInt() <= 0x69FC
|
||||||
|
private fun isWenQuanYi2(c: Char) = c.toInt() >= 0x69FD && c.toInt() <= 0x9FDC
|
||||||
|
private fun isGreek(c: Char) = c.toInt() >= 0x370 && c.toInt() <= 0x3CE
|
||||||
|
private fun isRomanian(c: Char) = c.toInt() >= 0x218 && c.toInt() <= 0x21A
|
||||||
|
private fun isRomanianNarrow(c: Char) = c.toInt() == 0x21B
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private fun extAindexX(c: Char) = (c.toInt() - 0x100) % 16
|
||||||
|
private fun extAindexY(c: Char) = (c.toInt() - 0x100) / 16
|
||||||
|
|
||||||
|
private fun kanaIndexX(c: Char) = (c.toInt() - 0x3040) % 16
|
||||||
|
private fun kanaIndexY(c: Char) = (c.toInt() - 0x3040) / 16
|
||||||
|
|
||||||
|
private fun cjkPunctIndexX(c: Char) = (c.toInt() - 0x3000) % 16
|
||||||
|
private fun cjkPunctIndexY(c: Char) = (c.toInt() - 0x3000) / 16
|
||||||
|
|
||||||
|
private fun uniHanIndexX(c: Char) = (c.toInt() - 0x3400) % 256
|
||||||
|
private fun uniHanIndexY(c: Char) = (c.toInt() - 0x3400) / 256
|
||||||
|
|
||||||
|
private fun cyrilicIndexX(c: Char) = (c.toInt() - 0x400) % 16
|
||||||
|
private fun cyrilicIndexY(c: Char) = (c.toInt() - 0x400) / 16
|
||||||
|
|
||||||
|
private fun fullwidthUniIndexX(c: Char) = (c.toInt() - 0xFF00) % 16
|
||||||
|
private fun fullwidthUniIndexY(c: Char) = (c.toInt() - 0xFF00) / 16
|
||||||
|
|
||||||
|
private fun uniPunctIndexX(c: Char) = (c.toInt() - 0x2000) % 16
|
||||||
|
private fun uniPunctIndexY(c: Char) = (c.toInt() - 0x2000) / 16
|
||||||
|
|
||||||
|
private fun wenQuanYiIndexX(c: Char) =
|
||||||
|
(c.toInt() - if (c.toInt() <= 0x4DB5) 0x33F3 else 0x33F3 + 0x4A) % 32
|
||||||
|
private fun wenQuanYi1IndexY(c: Char) = (c.toInt() - (0x33F3 + 0x4A)) / 32
|
||||||
|
private fun wenQuanYi2IndexY(c: Char) = (c.toInt() - 0x69FD) / 32
|
||||||
|
|
||||||
|
private fun greekIndexX(c: Char) = (c.toInt() - 0x370) % 16
|
||||||
|
private fun greekIndexY(c: Char) = (c.toInt() - 0x370) / 16
|
||||||
|
|
||||||
|
private fun romanianIndexX(c: Char) = c.toInt() - 0x218
|
||||||
|
private fun romanianIndexY(c: Char) = 0
|
||||||
|
|
||||||
|
private fun thaiIndexX(c: Char) = (c.toInt() - 0xE00) % 16
|
||||||
|
private fun thaiIndexY(c: Char) = (c.toInt() - 0xE00) / 16
|
||||||
|
|
||||||
|
private fun thaiNarrowIndexX(c: Char) = 3
|
||||||
|
private fun thaiNarrowIndexY(c: Char) = 0
|
||||||
|
|
||||||
|
|
||||||
|
private val narrowWidthSheets = arrayOf(
|
||||||
|
SHEET_EXTB_ROMANIAN_NARROW
|
||||||
|
)
|
||||||
|
private val unihanWidthSheets = arrayOf(
|
||||||
|
SHEET_UNIHAN,
|
||||||
|
SHEET_FW_UNI,
|
||||||
|
SHEET_WENQUANYI_1,
|
||||||
|
SHEET_WENQUANYI_2
|
||||||
|
)
|
||||||
|
private val zeroWidthSheets = arrayOf(
|
||||||
|
SHEET_COLOURCODE
|
||||||
|
)
|
||||||
|
private val variableWidthSheets = arrayOf(
|
||||||
|
SHEET_ASCII_VARW,
|
||||||
|
SHEET_CYRILIC_VARW,
|
||||||
|
SHEET_EXTA_VARW,
|
||||||
|
SHEET_GREEK_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 (chr.toInt() == 0x21B) // Romanian t; HAX!
|
||||||
|
len += 6
|
||||||
|
else if (variableWidthSheets.contains(ctype)) {
|
||||||
|
try {
|
||||||
|
len += asciiWidths[chr.toInt()]!!
|
||||||
|
}
|
||||||
|
catch (e: kotlin.KotlinNullPointerException) {
|
||||||
|
println("KotlinNullPointerException on glyph number ${Integer.toHexString(chr.toInt()).toUpperCase()}")
|
||||||
|
System.exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (zeroWidthSheets.contains(ctype))
|
||||||
|
len += 0
|
||||||
|
else if (narrowWidthSheets.contains(ctype))
|
||||||
|
len += W_LATIN_NARROW
|
||||||
|
else if (ctype == SHEET_CJK_PUNCT)
|
||||||
|
len += W_ASIAN_PUNCT
|
||||||
|
else if (ctype == SHEET_HANGUL)
|
||||||
|
len += W_HANGUL
|
||||||
|
else if (ctype == SHEET_KANA)
|
||||||
|
len += W_KANA
|
||||||
|
else if (unihanWidthSheets.contains(ctype))
|
||||||
|
len += W_UNIHAN
|
||||||
|
else
|
||||||
|
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 (isHangul(ch)) {
|
||||||
|
val hIndex = ch.toInt() - 0xAC00
|
||||||
|
|
||||||
|
val indexCho = getHanChosung(hIndex)
|
||||||
|
val indexJung = getHanJungseong(hIndex)
|
||||||
|
val indexJong = getHanJongseong(hIndex)
|
||||||
|
|
||||||
|
val choRow = getHanInitialRow(hIndex)
|
||||||
|
val jungRow = getHanMedialRow(hIndex)
|
||||||
|
val jongRow = getHanFinalRow(hIndex)
|
||||||
|
|
||||||
|
val glyphW = getWidth(ch.toString())
|
||||||
|
|
||||||
|
hangulSheet.getSubImage(indexCho, choRow).drawWithShadow(
|
||||||
|
Math.round(x + getWidthSubstr(s, i + 1) - glyphW).toFloat(),
|
||||||
|
Math.round(((H - H_HANGUL) / 2).toFloat() + y + 1f).toFloat(),
|
||||||
|
scale.toFloat(), thisCol
|
||||||
|
)
|
||||||
|
hangulSheet.getSubImage(indexJung, jungRow).drawWithShadow(
|
||||||
|
Math.round(x + getWidthSubstr(s, i + 1) - glyphW).toFloat(),
|
||||||
|
Math.round(((H - H_HANGUL) / 2).toFloat() + y + 1f).toFloat(),
|
||||||
|
scale.toFloat(), thisCol
|
||||||
|
)
|
||||||
|
hangulSheet.getSubImage(indexJong, jongRow).drawWithShadow(
|
||||||
|
Math.round(x + getWidthSubstr(s, i + 1) - glyphW).toFloat(),
|
||||||
|
Math.round(((H - H_HANGUL) / 2).toFloat() + y + 1f).toFloat(),
|
||||||
|
scale.toFloat(), thisCol
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//hangulSheet.endUse()
|
||||||
|
|
||||||
|
// unihan fonts
|
||||||
|
/*uniHan.startUse();
|
||||||
|
for (int i = 0; i < s.length(); i++) {
|
||||||
|
char ch = s.charAt(i);
|
||||||
|
|
||||||
|
if (isUniHan(ch)) {
|
||||||
|
int glyphW = getWidth("" + ch);
|
||||||
|
uniHan.renderInUse(
|
||||||
|
Math.round(x
|
||||||
|
+ getWidthSubstr(s, i + 1) - glyphW
|
||||||
|
)
|
||||||
|
, Math.round((H - H_UNIHAN) / 2 + y)
|
||||||
|
, uniHanIndexX(ch)
|
||||||
|
, uniHanIndexY(ch)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uniHan.endUse();*/
|
||||||
|
|
||||||
|
// WenQuanYi 1
|
||||||
|
//wenQuanYi_1.startUse()
|
||||||
|
|
||||||
|
for (i in 0..s.length - 1) {
|
||||||
|
val ch = s[i]
|
||||||
|
|
||||||
|
if (isWenQuanYi1(ch)) {
|
||||||
|
val glyphW = getWidth("" + ch)
|
||||||
|
wenQuanYi_1.getSubImage(wenQuanYiIndexX(ch), wenQuanYi1IndexY(ch)).drawWithShadow(
|
||||||
|
Math.round(x + getWidthSubstr(s, i + 1) - glyphW).toFloat(),
|
||||||
|
Math.round((H - H_UNIHAN) / 2 + y).toFloat(),
|
||||||
|
scale.toFloat(), thisCol
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//wenQuanYi_1.endUse()
|
||||||
|
// WenQuanYi 2
|
||||||
|
//wenQuanYi_2.startUse()
|
||||||
|
|
||||||
|
for (i in 0..s.length - 1) {
|
||||||
|
val ch = s[i]
|
||||||
|
|
||||||
|
if (isWenQuanYi2(ch)) {
|
||||||
|
val glyphW = getWidth("" + ch)
|
||||||
|
wenQuanYi_2.getSubImage(wenQuanYiIndexX(ch), wenQuanYi2IndexY(ch)).drawWithShadow(
|
||||||
|
Math.round(x + getWidthSubstr(s, i + 1) - glyphW).toFloat(),
|
||||||
|
Math.round((H - H_UNIHAN) / 2 + y).toFloat(),
|
||||||
|
scale.toFloat(), thisCol
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//wenQuanYi_2.endUse()
|
||||||
|
|
||||||
|
// regular fonts
|
||||||
|
var prevInstance = -1
|
||||||
|
for (i in 0..s.length - 1) {
|
||||||
|
val ch = s[i]
|
||||||
|
|
||||||
|
if (!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_EXTA_VARW -> {
|
||||||
|
sheetX = extAindexX(ch)
|
||||||
|
sheetY = extAindexY(ch)
|
||||||
|
}
|
||||||
|
SHEET_KANA -> {
|
||||||
|
sheetX = kanaIndexX(ch)
|
||||||
|
sheetY = kanaIndexY(ch)
|
||||||
|
}
|
||||||
|
SHEET_CJK_PUNCT -> {
|
||||||
|
sheetX = cjkPunctIndexX(ch)
|
||||||
|
sheetY = cjkPunctIndexY(ch)
|
||||||
|
}
|
||||||
|
SHEET_CYRILIC_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_EXTB_ROMANIAN_WIDE -> {
|
||||||
|
sheetX = romanianIndexX(ch)
|
||||||
|
sheetY = romanianIndexY(ch)
|
||||||
|
}
|
||||||
|
SHEET_EXTB_ROMANIAN_NARROW -> {
|
||||||
|
sheetX = 0
|
||||||
|
sheetY = 0
|
||||||
|
}
|
||||||
|
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_CJK_PUNCT) -1 // height hack
|
||||||
|
else if (prevInstance == SHEET_FW_UNI) (H - H_HANGUL) / 2 // completely legit height adjustment
|
||||||
|
else 0).toFloat(),
|
||||||
|
|
||||||
|
scale.toFloat(), thisCol
|
||||||
|
)
|
||||||
|
}
|
||||||
|
catch (e: ArrayIndexOutOfBoundsException) {
|
||||||
|
// character that does not exist in the sheet. No render, pass.
|
||||||
|
}
|
||||||
|
catch (e1: RuntimeException) {
|
||||||
|
// System.err.println("[GameFontBase] RuntimeException raised while processing character '$ch' (U+${Integer.toHexString(ch.toInt()).toUpperCase()})")
|
||||||
|
// e1.printStackTrack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (prevInstance != -1) {
|
||||||
|
//sheetKey[prevInstance].endUse()
|
||||||
|
}
|
||||||
|
|
||||||
|
GL11.glEnd()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getSheetType(c: Char): Int {
|
||||||
|
// EFs
|
||||||
|
if (isRomanianNarrow(c))
|
||||||
|
return SHEET_EXTB_ROMANIAN_NARROW
|
||||||
|
else if (isHangul(c))
|
||||||
|
return SHEET_HANGUL
|
||||||
|
else if (isKana(c))
|
||||||
|
return SHEET_KANA
|
||||||
|
else if (isUniHan(c))
|
||||||
|
return SHEET_UNIHAN
|
||||||
|
else if (isAscii(c))
|
||||||
|
return SHEET_ASCII_VARW
|
||||||
|
else if (isExtA(c))
|
||||||
|
return SHEET_EXTA_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 (isRomanian(c))
|
||||||
|
return SHEET_EXTB_ROMANIAN_WIDE
|
||||||
|
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 buildWidthTable(sheet: SpriteSheet, codeOffset: Int, codeRange: IntRange, rows: Int = 16) {
|
||||||
|
fun Byte.toUint() = java.lang.Byte.toUnsignedInt(this)
|
||||||
|
|
||||||
|
/** @return Intarray(R, G, B, A) */
|
||||||
|
fun Texture.getPixel(x: Int, y: Int): IntArray {
|
||||||
|
val textureWidth = this.textureWidth
|
||||||
|
val hasAlpha = this.hasAlpha()
|
||||||
|
|
||||||
|
val offset = (if (hasAlpha) 4 else 3) * (textureWidth * y + x) // 4: # of channels (RGBA)
|
||||||
|
|
||||||
|
if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
|
||||||
|
return intArrayOf(
|
||||||
|
this.textureData[offset].toUint(),
|
||||||
|
this.textureData[offset + 1].toUint(),
|
||||||
|
this.textureData[offset + 2].toUint(),
|
||||||
|
if (hasAlpha)
|
||||||
|
this.textureData[offset + 3].toUint()
|
||||||
|
else 255
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return intArrayOf(
|
||||||
|
this.textureData[offset + 2].toUint(),
|
||||||
|
this.textureData[offset + 1].toUint(),
|
||||||
|
this.textureData[offset].toUint(),
|
||||||
|
if (hasAlpha)
|
||||||
|
this.textureData[offset + 3].toUint()
|
||||||
|
else 255
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
asciiWidths[codeOffset + ccode] = glyphWidth
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
lateinit internal var hangulSheet: SpriteSheet
|
||||||
|
lateinit internal var asciiSheet: SpriteSheet
|
||||||
|
|
||||||
|
internal val asciiWidths: HashMap<Int, Int> = HashMap()
|
||||||
|
|
||||||
|
lateinit internal var extASheet: SpriteSheet
|
||||||
|
lateinit internal var kanaSheet: SpriteSheet
|
||||||
|
lateinit internal var cjkPunct: SpriteSheet
|
||||||
|
// static SpriteSheet uniHan;
|
||||||
|
lateinit internal var cyrilic: SpriteSheet
|
||||||
|
lateinit internal var fullwidthForms: SpriteSheet
|
||||||
|
lateinit internal var uniPunct: SpriteSheet
|
||||||
|
lateinit internal var wenQuanYi_1: SpriteSheet
|
||||||
|
lateinit internal var wenQuanYi_2: SpriteSheet
|
||||||
|
lateinit internal var greekSheet: SpriteSheet
|
||||||
|
lateinit internal var romanianSheet: SpriteSheet
|
||||||
|
lateinit internal var romanianSheetNarrow: SpriteSheet
|
||||||
|
|
||||||
|
internal val JUNG_COUNT = 21
|
||||||
|
internal val JONG_COUNT = 28
|
||||||
|
|
||||||
|
internal val W_ASIAN_PUNCT = 10
|
||||||
|
internal val W_HANGUL = 11
|
||||||
|
internal val W_KANA = 12
|
||||||
|
internal val W_UNIHAN = 16
|
||||||
|
internal val W_LATIN_WIDE = 9 // width of regular letters, including m
|
||||||
|
internal val W_LATIN_NARROW = 5 // width of letter f, t, i, l
|
||||||
|
|
||||||
|
internal val H = 20
|
||||||
|
internal val H_HANGUL = 16
|
||||||
|
internal val H_UNIHAN = 16
|
||||||
|
internal val H_KANA = 20
|
||||||
|
|
||||||
|
internal val SHEET_ASCII_VARW = 0
|
||||||
|
internal val SHEET_HANGUL = 1
|
||||||
|
internal val SHEET_EXTA_VARW = 2
|
||||||
|
internal val SHEET_KANA = 3
|
||||||
|
internal val SHEET_CJK_PUNCT = 4
|
||||||
|
internal val SHEET_UNIHAN = 5
|
||||||
|
internal val SHEET_CYRILIC_VARW = 6
|
||||||
|
internal val SHEET_FW_UNI = 7
|
||||||
|
internal val SHEET_UNI_PUNCT = 8
|
||||||
|
internal val SHEET_WENQUANYI_1 = 9
|
||||||
|
internal val SHEET_WENQUANYI_2 = 10
|
||||||
|
internal val SHEET_GREEK_VARW = 11
|
||||||
|
internal val SHEET_EXTB_ROMANIAN_WIDE = 12
|
||||||
|
internal val SHEET_EXTB_ROMANIAN_NARROW = 13
|
||||||
|
|
||||||
|
internal val SHEET_UNKNOWN = 254
|
||||||
|
internal val SHEET_COLOURCODE = 255
|
||||||
|
|
||||||
|
lateinit internal var sheetKey: Array<SpriteSheet?>
|
||||||
|
|
||||||
|
internal var interchar = 0
|
||||||
|
internal var scale = 1
|
||||||
|
set(value) {
|
||||||
|
if (value > 0) field = value
|
||||||
|
else throw IllegalArgumentException("Font scale cannot be zero or negative (input: $value)")
|
||||||
|
}
|
||||||
|
|
||||||
|
}// end of companion object
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Image.drawWithShadow(x: Float, y: Float, color: Color) =
|
||||||
|
this.drawWithShadow(x, y, 1f, color)
|
||||||
|
|
||||||
|
fun Image.drawWithShadow(x: Float, y: Float, scale: Float, color: Color) {
|
||||||
|
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)
|
||||||
|
}
|
||||||
75
code_for_Slick2d/GameFontImpl.kt
Normal file
75
code_for_Slick2d/GameFontImpl.kt
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
package net.torvald.imagefont
|
||||||
|
|
||||||
|
import net.torvald.terrarum.imagefont.GameFontDemo
|
||||||
|
import org.newdawn.slick.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by minjaesong on 16-01-20.
|
||||||
|
*/
|
||||||
|
class GameFontImpl : GameFontBase() {
|
||||||
|
|
||||||
|
init {
|
||||||
|
|
||||||
|
GameFontBase.hangulSheet = SpriteSheet(
|
||||||
|
"./assets/graphics/fonts/hangul_johab.tga", GameFontBase.W_HANGUL, GameFontBase.H_HANGUL)
|
||||||
|
GameFontBase.asciiSheet = SpriteSheet(
|
||||||
|
"./assets/graphics/fonts/ascii_variable.tga", 15, 19, 1)
|
||||||
|
GameFontBase.extASheet = SpriteSheet(
|
||||||
|
"./assets/graphics/fonts/LatinExtA_variable.tga", 15, 19, 1)
|
||||||
|
GameFontBase.kanaSheet = SpriteSheet(
|
||||||
|
"./assets/graphics/fonts/kana.tga", GameFontBase.W_KANA, GameFontBase.H_KANA)
|
||||||
|
GameFontBase.cjkPunct = SpriteSheet(
|
||||||
|
"./assets/graphics/fonts/cjkpunct.tga", GameFontBase.W_ASIAN_PUNCT, GameFontBase.H_KANA)
|
||||||
|
/*uniHan = new SpriteSheet(
|
||||||
|
"./assets/graphics/fonts/unifont_unihan"
|
||||||
|
+ ((!terrarum.gameLocale.contains("zh"))
|
||||||
|
? "_ja" : "")
|
||||||
|
+".tga"
|
||||||
|
, W_UNIHAN, H_UNIHAN
|
||||||
|
);*/
|
||||||
|
GameFontBase.cyrilic = SpriteSheet(
|
||||||
|
when (GameFontDemo.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 = SpriteSheet(
|
||||||
|
"./assets/graphics/fonts/fullwidth_forms.tga", GameFontBase.W_UNIHAN, GameFontBase.H_UNIHAN)
|
||||||
|
GameFontBase.uniPunct = SpriteSheet(
|
||||||
|
"./assets/graphics/fonts/unipunct.tga", GameFontBase.W_LATIN_WIDE, GameFontBase.H)
|
||||||
|
GameFontBase.wenQuanYi_1 = SpriteSheet(
|
||||||
|
"./assets/graphics/fonts/wenquanyi_11pt_part1.tga", 16, 18, 2)
|
||||||
|
GameFontBase.wenQuanYi_2 = SpriteSheet(
|
||||||
|
"./assets/graphics/fonts/wenquanyi_11pt_part2.tga", 16, 18, 2)
|
||||||
|
GameFontBase.greekSheet = SpriteSheet(
|
||||||
|
"./assets/graphics/fonts/greek_variable.tga", 15, 19, 1)
|
||||||
|
GameFontBase.romanianSheet = SpriteSheet(
|
||||||
|
"./assets/graphics/fonts/romana_wide.tga", GameFontBase.W_LATIN_WIDE, GameFontBase.H)
|
||||||
|
GameFontBase.romanianSheetNarrow = SpriteSheet(
|
||||||
|
"./assets/graphics/fonts/romana_narrow.tga", GameFontBase.W_LATIN_NARROW, GameFontBase.H)
|
||||||
|
|
||||||
|
val shk = arrayOf(
|
||||||
|
GameFontBase.asciiSheet,
|
||||||
|
GameFontBase.hangulSheet,
|
||||||
|
GameFontBase.extASheet,
|
||||||
|
GameFontBase.kanaSheet,
|
||||||
|
GameFontBase.cjkPunct,
|
||||||
|
null, // Full unihan, filler because we're using WenQuanYi
|
||||||
|
GameFontBase.cyrilic,
|
||||||
|
GameFontBase.fullwidthForms,
|
||||||
|
GameFontBase.uniPunct,
|
||||||
|
GameFontBase.wenQuanYi_1,
|
||||||
|
GameFontBase.wenQuanYi_2,
|
||||||
|
GameFontBase.greekSheet,
|
||||||
|
GameFontBase.romanianSheet,
|
||||||
|
GameFontBase.romanianSheetNarrow
|
||||||
|
)
|
||||||
|
GameFontBase.sheetKey = shk
|
||||||
|
|
||||||
|
|
||||||
|
buildWidthTable(asciiSheet, 0, 0..0xFF)
|
||||||
|
buildWidthTable(extASheet, 0x100, 0..0x7F)
|
||||||
|
buildWidthTable(cyrilic, 0x400, 0..0x5F)
|
||||||
|
buildWidthTable(greekSheet, 0x370, 0..0x5F)
|
||||||
|
}
|
||||||
|
}
|
||||||
1
code_for_Slick2d/README.md
Normal file
1
code_for_Slick2d/README.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Font implementations for Slick2d
|
||||||
Reference in New Issue
Block a user