hangul: some of the microkerning implemented in dirty way

This commit is contained in:
minjaesong
2020-05-03 18:13:17 +09:00
parent b5dd744bd5
commit 7bb92d1b4e
3 changed files with 27 additions and 60 deletions

View File

@@ -105,9 +105,6 @@ class GameFontBase(
val debug: Boolean = false val debug: Boolean = false
) : BitmapFont() { ) : BitmapFont() {
/** /**
* lowercase AND the height is equal to x-height (e.g. lowercase B, D, F, H, K, L, ... does not count * lowercase AND the height is equal to x-height (e.g. lowercase B, D, F, H, K, L, ... does not count
*/ */
@@ -342,7 +339,7 @@ class GameFontBase(
PixmapRegionPack(pixmap, W_KANA, H) PixmapRegionPack(pixmap, W_KANA, H)
} }
else if (index == SHEET_HANGUL) { else if (index == SHEET_HANGUL) {
PixmapRegionPack(pixmap, W_HANGUL, H) PixmapRegionPack(pixmap, W_HANGUL_BASE, H)
} }
else if (index == SHEET_CUSTOM_SYM) { else if (index == SHEET_CUSTOM_SYM) {
PixmapRegionPack(pixmap, SIZE_CUSTOM_SYM, SIZE_CUSTOM_SYM) // TODO variable PixmapRegionPack(pixmap, SIZE_CUSTOM_SYM, SIZE_CUSTOM_SYM) // TODO variable
@@ -567,49 +564,6 @@ class GameFontBase(
sheets.forEach { it.dispose() } sheets.forEach { it.dispose() }
} }
/**
* Used for positioning letters, NOT for the actual width.
*
* For actual width, use `getWidth()`
*/
private fun getWidthOfCharSeq(s: CodepointSequence): IntArray {
val len = IntArray(s.size)
for (i in 0..s.lastIndex) {
val chr = s[i]
val ctype = getSheetType(s[i])
if (variableWidthSheets.contains(ctype)) {
if (!glyphProps.containsKey(chr)) {
System.err.println("[TerrarumSansBitmap] no width data for glyph number ${Integer.toHexString(chr.toInt()).toUpperCase()}")
len[i] = W_LATIN_WIDE
}
val prop = glyphProps[chr] ?: nullProp
//println("${chr.toInt()} -> $prop")
len[i] = prop.width * (if (prop.writeOnTop) -1 else 1)
}
else if (isColourCode(chr) || isCharsetOverride(chr))
len[i] = 0
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: CodePoint): Int { private fun getSheetType(c: CodePoint): Int {
if (charsetOverride == 1 && isBulgarian(c)) if (charsetOverride == 1 && isBulgarian(c))
return SHEET_BULGARIAN_VARW return SHEET_BULGARIAN_VARW
@@ -846,13 +800,13 @@ class GameFontBase(
} }
} }
fun buildWidthTableFixed() { private fun buildWidthTableFixed() {
// fixed-width props // fixed-width props
codeRange[SHEET_CJK_PUNCT].forEach { glyphProps[it] = GlyphProps(W_ASIAN_PUNCT, 0) } codeRange[SHEET_CJK_PUNCT].forEach { glyphProps[it] = GlyphProps(W_ASIAN_PUNCT, 0) }
codeRange[SHEET_CUSTOM_SYM].forEach { glyphProps[it] = GlyphProps(20, 0) } codeRange[SHEET_CUSTOM_SYM].forEach { glyphProps[it] = GlyphProps(20, 0) }
codeRange[SHEET_FW_UNI].forEach { glyphProps[it] = GlyphProps(W_UNIHAN, 0) } codeRange[SHEET_FW_UNI].forEach { glyphProps[it] = GlyphProps(W_UNIHAN, 0) }
codeRange[SHEET_HANGUL].forEach { glyphProps[it] = GlyphProps(W_HANGUL, 0) } codeRange[SHEET_HANGUL].forEach { glyphProps[it] = GlyphProps(W_HANGUL_BASE, 0) }
codeRangeHangulCompat.forEach { glyphProps[it] = GlyphProps(W_HANGUL, 0) } codeRangeHangulCompat.forEach { glyphProps[it] = GlyphProps(W_HANGUL_BASE, 0) }
codeRange[SHEET_KANA].forEach { glyphProps[it] = GlyphProps(W_KANA, 0) } codeRange[SHEET_KANA].forEach { glyphProps[it] = GlyphProps(W_KANA, 0) }
codeRange[SHEET_RUNIC].forEach { glyphProps[it] = GlyphProps(9, 0) } codeRange[SHEET_RUNIC].forEach { glyphProps[it] = GlyphProps(9, 0) }
codeRange[SHEET_UNIHAN].forEach { glyphProps[it] = GlyphProps(W_UNIHAN, 0) } codeRange[SHEET_UNIHAN].forEach { glyphProps[it] = GlyphProps(W_UNIHAN, 0) }
@@ -869,6 +823,7 @@ class GameFontBase(
// U+007F is DEL originally, but this font stores bitmap of Replacement Character (U+FFFD) // U+007F is DEL originally, but this font stores bitmap of Replacement Character (U+FFFD)
// to this position. String replacer will replace U+FFFD into U+007F. // to this position. String replacer will replace U+FFFD into U+007F.
glyphProps[0x7F] = GlyphProps(15, 0) glyphProps[0x7F] = GlyphProps(15, 0)
} }
private val glyphLayout = GlyphLayout() private val glyphLayout = GlyphLayout()
@@ -902,6 +857,10 @@ class GameFontBase(
val HALF_VAR_INIT = W_VAR_INIT.minus(1).div(2) val HALF_VAR_INIT = W_VAR_INIT.minus(1).div(2)
// this is starting to get dirty...
// persisting value. the value is set a few characters before the actual usage
var extraWidth = 0
for (charIndex in 0 until posXbuffer.size - 1) { for (charIndex in 0 until posXbuffer.size - 1) {
if (charIndex > 0) { if (charIndex > 0) {
// nonDiacriticCounter allows multiple diacritics // nonDiacriticCounter allows multiple diacritics
@@ -923,7 +882,7 @@ class GameFontBase(
//println("char: ${thisChar.charInfo()}\nproperties: $thisProp") //println("char: ${thisChar.charInfo()}\nproperties: $thisProp")
val alignmentOffset = when (thisProp.alignWhere) { var alignmentOffset = when (thisProp.alignWhere) {
GlyphProps.ALIGN_LEFT -> 0 GlyphProps.ALIGN_LEFT -> 0
GlyphProps.ALIGN_RIGHT -> thisProp.width - W_VAR_INIT GlyphProps.ALIGN_RIGHT -> thisProp.width - W_VAR_INIT
GlyphProps.ALIGN_CENTRE -> Math.ceil((thisProp.width - W_VAR_INIT) / 2.0).toInt() GlyphProps.ALIGN_CENTRE -> Math.ceil((thisProp.width - W_VAR_INIT) / 2.0).toInt()
@@ -931,27 +890,31 @@ class GameFontBase(
} }
// shoehorn the wider-hangul-width thingamajig
if (toHangulJungseongIndex(thisChar) in hangulPeaksWithExtraWidth) {
//println("char: ${thisChar.charInfo()}\nproperties: $thisProp")
extraWidth += 1
}
if (isHangul(thisChar) && !isHangulChoseong(thisChar) && !isHangulCompat(thisChar)) { if (isHangul(thisChar) && !isHangulChoseong(thisChar) && !isHangulCompat(thisChar)) {
posXbuffer[charIndex] = if (isHangulChoseong(lastNonDiacriticChar) || isHangulCompat(lastNonDiacriticChar)) posXbuffer[charIndex] = posXbuffer[nonDiacriticCounter]
posXbuffer[nonDiacriticCounter]
else
posXbuffer[nonDiacriticCounter] + W_HANGUL
} }
else if (!thisProp.writeOnTop) { else if (!thisProp.writeOnTop) {
posXbuffer[charIndex] = when (itsProp.alignWhere) { posXbuffer[charIndex] = when (itsProp.alignWhere) {
GlyphProps.ALIGN_RIGHT -> GlyphProps.ALIGN_RIGHT ->
posXbuffer[nonDiacriticCounter] + W_VAR_INIT + alignmentOffset + interchar + kerning posXbuffer[nonDiacriticCounter] + W_VAR_INIT + alignmentOffset + interchar + kerning + extraWidth
GlyphProps.ALIGN_CENTRE -> GlyphProps.ALIGN_CENTRE ->
posXbuffer[nonDiacriticCounter] + HALF_VAR_INIT + itsProp.width + alignmentOffset + interchar + kerning posXbuffer[nonDiacriticCounter] + HALF_VAR_INIT + itsProp.width + alignmentOffset + interchar + kerning + extraWidth
else -> else ->
posXbuffer[nonDiacriticCounter] + itsProp.width + alignmentOffset + interchar + kerning posXbuffer[nonDiacriticCounter] + itsProp.width + alignmentOffset + interchar + kerning + extraWidth
} }
nonDiacriticCounter = charIndex nonDiacriticCounter = charIndex
stackUpwardCounter = 0 stackUpwardCounter = 0
stackDownwardCounter = 0 stackDownwardCounter = 0
extraWidth = 0
} }
else if (thisProp.writeOnTop && thisProp.alignXPos == GlyphProps.DIA_JOINER) { else if (thisProp.writeOnTop && thisProp.alignXPos == GlyphProps.DIA_JOINER) {
posXbuffer[charIndex] = when (itsProp.alignWhere) { posXbuffer[charIndex] = when (itsProp.alignWhere) {
@@ -1363,7 +1326,7 @@ class GameFontBase(
internal val JONG_COUNT = 28 internal val JONG_COUNT = 28
internal val W_ASIAN_PUNCT = 10 internal val W_ASIAN_PUNCT = 10
internal val W_HANGUL = 13 internal val W_HANGUL_BASE = 13
internal val W_KANA = 12 internal val W_KANA = 12
internal val W_UNIHAN = 16 internal val W_UNIHAN = 16
internal val W_LATIN_WIDE = 9 // width of regular letters internal val W_LATIN_WIDE = 9 // width of regular letters
@@ -1526,6 +1489,7 @@ class GameFontBase(
private fun getWanseongHanJungseong(hanIndex: Int) = hanIndex / JONG_COUNT % JUNG_COUNT private fun getWanseongHanJungseong(hanIndex: Int) = hanIndex / JONG_COUNT % JUNG_COUNT
private fun getWanseongHanJongseong(hanIndex: Int) = hanIndex % JONG_COUNT private fun getWanseongHanJongseong(hanIndex: Int) = hanIndex % JONG_COUNT
// THESE ARRAYS MUST BE SORTED
// ㅣ // ㅣ
private val jungseongI: Array<Int> = arrayOf(21,61) private val jungseongI: Array<Int> = arrayOf(21,61)
// ㅗ ㅛ ㅜ ㅠ // ㅗ ㅛ ㅜ ㅠ
@@ -1540,6 +1504,9 @@ class GameFontBase(
private val jungseongEU: Array<Int> = arrayOf(19,62,66) private val jungseongEU: Array<Int> = arrayOf(19,62,66)
// ㅢ // ㅢ
private val jungseongYI: Array<Int> = arrayOf(20,60,65) private val jungseongYI: Array<Int> = arrayOf(20,60,65)
// index of the peak, 0 being blank, 1 being ㅏ
// indices of peaks that number of lit pixels (vertically counted) on x=11 is greater than 7
private val hangulPeaksWithExtraWidth = arrayOf(2,4,6,8,11,16,32,33,37,42,44,48,50,71,75,78,79,83,86,87,88,94)
private fun isJungseongI(hanIndex: Int) = jungseongI.binarySearch(hanIndex) >= 0 private fun isJungseongI(hanIndex: Int) = jungseongI.binarySearch(hanIndex) >= 0
private fun isJungseongOU(hanIndex: Int) = jungseongOU.binarySearch(hanIndex) >= 0 private fun isJungseongOU(hanIndex: Int) = jungseongOU.binarySearch(hanIndex) >= 0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 59 KiB