Files
Terrarum/src/com/Torvald/ImageFont/GameFontBase.java
Song Minjae 3f49a8aebe Joise, Kotlin (it's working at least)
Former-commit-id: d5be0e95ba259d566d6d5d20eb576010a149ae7d
Former-commit-id: 9502c7cd7e738147e31d2e9824e48bea24d00abf
2016-03-14 22:43:28 +09:00

622 lines
19 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package com.Torvald.ImageFont;
import com.Torvald.Terrarum.Terrarum;
import org.lwjgl.opengl.GL11;
import org.newdawn.slick.*;
import java.util.Arrays;
/**
* Created by minjaesong on 16-01-27.
*/
public class GameFontBase implements Font {
static SpriteSheet hangulSheet;
static SpriteSheet asciiSheet;
static SpriteSheet asciiSheetEF;
static SpriteSheet runicSheet;
static SpriteSheet extASheet;
static SpriteSheet extASheetEF;
static SpriteSheet kanaSheet;
static SpriteSheet cjkPunct;
// static SpriteSheet uniHan;
static SpriteSheet cyrilic;
static SpriteSheet cyrilicEF;
static SpriteSheet fullwidthForms;
static SpriteSheet uniPunct;
static SpriteSheet wenQuanYi_1;
static SpriteSheet wenQuanYi_2;
static final int JUNG_COUNT = 21;
static final int JONG_COUNT = 28;
static final int W_CJK = 10;
static final int W_UNIHAN = 16;
static final int W_LATIN_WIDE = 9; // width of regular letters, including m
static final int W_LATIN_NARROW = 5; // width of letter f, t, i, l
static final int H = 20;
static final int H_HANGUL = 16;
static final int H_UNIHAN = 16;
static final int H_KANA = 20;
static final int SHEET_ASCII_EM = 0;
static final int SHEET_ASCII_EF = 1;
static final int SHEET_HANGUL = 2;
static final int SHEET_RUNIC = 3;
static final int SHEET_EXTA_EM = 4;
static final int SHEET_EXTA_EF = 5;
static final int SHEET_KANA = 6;
static final int SHEET_CJK_PUNCT = 7;
static final int SHEET_UNIHAN = 8;
static final int SHEET_CYRILIC_EM = 9;
static final int SHEET_CYRILIC_EF = 10;
static final int SHEET_FW_UNI = 11;
static final int SHEET_UNI_PUNCT = 12;
static final int SHEET_WENQUANYI_1 = 13;
static final int SHEET_WENQUANYI_2 = 14;
static SpriteSheet[] sheetKey;
static final Character[] asciiEFList = {
' ','!','"','\'','(',')',',','.',':',';','I','[',']','`','f','i'
,'j','l','t','{','|','}',0xA1,'Ì','Í','Î','Ï','ì','í','î','ï','·'
};
static final Character[] extAEFList = {
0x12E, 0x12F, 0x130, 0x131, 0x135, 0x13A, 0x13C, 0x142, 0x163, 0x167, 0x17F
};
static final Character[] cyrilecEFList = {
0x406, 0x407, 0x456, 0x457, 0x458
};
/**
* 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:
* ᛭ᛋᛁᚴᚱᛁᚦᛦ᛭
* ᛭ᛂᛚᛋᛅ᛭ᛏᚱᚢᛏᚾᛁᚾᚴᚢᚾᛅ᛬ᛅᚱᚾᛅᛏᛅᛚᛋ
*/
static final Character[] runicList = {
'ᚠ','ᚢ','ᚦ','ᚬ','ᚱ','ᚴ','ᚼ','ᚾ','','ᛅ','ᛋ','ᛏ','ᛒ','ᛘ','ᛚ','ᛦ'
,'ᛂ','','᛫','','ᛮ','ᛯ','ᛰ'
};
static int interchar = 0;
public GameFontBase() throws SlickException {
}
private int[] getHan(int hanIndex) {
int han_x = hanIndex % JONG_COUNT;
int han_y = hanIndex / JONG_COUNT;
int[] ret = {han_x, han_y};
return ret;
}
private int getHanChosung(int hanIndex) {
return hanIndex / (JUNG_COUNT * JONG_COUNT);
}
private int getHanJungseong(int hanIndex) {
return hanIndex / (JONG_COUNT) % JUNG_COUNT;
}
private int getHanJongseong(int hanIndex) {
return hanIndex % JONG_COUNT;
}
private int getHanChoseongRow(int hanIndex) {
int jungseongIndex = getHanJungseong(hanIndex);
Integer[] jungseongWide = {8, 12, 13, 17, 18, 21};
Integer[] jungseongComplex = {9, 10, 11, 14, 15, 16, 22};
int ret;
if (Arrays.asList(jungseongWide).contains(jungseongIndex)) {
ret = 2;
}
else if (Arrays.asList(jungseongComplex).contains(jungseongIndex)) {
ret = 4;
}
else {
ret = 0;
}
return (getHanJongseong(hanIndex) == 0) ? ret : ret + 1;
}
private int getHanJungseongRow(int hanIndex) {
return (getHanJongseong(hanIndex) == 0) ? 6 : 7;
}
private int getHanJongseongRow() {
return 8;
}
private boolean isAsciiEF(char c) {
return (Arrays.asList(asciiEFList).contains(c));
}
private boolean isExtAEF(char c) {
return (Arrays.asList(extAEFList).contains(c));
}
private boolean isHangul(char c) {
return (c >= 0xAC00 && c < 0xD7A4);
}
private boolean isAscii(char c) { return (c > 0 && c <= 0xFF); }
private boolean isRunic(char c) {
return (Arrays.asList(runicList).contains(c));
}
private boolean isExtA(char c) {
return (c >= 0x100 && c < 0x180);
}
private boolean isKana(char c) {
return (c >= 0x3040 && c < 0x3100);
}
private boolean isCJKPunct(char c) {
return (c >= 0x3000 && c < 0x3040);
}
private boolean isUniHan(char c) {
return (c >= 0x3400 && c < 0xA000);
}
private boolean isCyrilic(char c) {
return (c >= 0x400 && c < 0x460);
}
private boolean isCyrilicEF(char c) {
return (Arrays.asList(cyrilecEFList).contains(c));
}
private boolean isFullwidthUni(char c) {
return (c >= 0xFF00 && c < 0xFF20);
}
private boolean isUniPunct(char c) {
return (c >= 0x2000 && c < 0x2070);
}
private boolean isWenQuanYi1(char c) {
return (c >= 0x33F3 && c <= 0x69FC);
}
private boolean isWenQuanYi2(char c) {
return (c >= 0x69FD && c <= 0x9FDC);
}
/** */
private int asciiEFindexX(char c) {
return (Arrays.asList(asciiEFList).indexOf(c) % 16);
}
private int asciiEFindexY(char c) {
return (Arrays.asList(asciiEFList).indexOf(c) / 16);
}
private int extAEFindexX(char c) {
return (Arrays.asList(extAEFList).indexOf(c) % 16);
}
private int extAEFindexY(char c) {
return (Arrays.asList(extAEFList).indexOf(c) / 16);
}
private int runicIndexX(char c) {
return (Arrays.asList(runicList).indexOf(c) % 16);
}
private int runicIndexY(char c) {
return (Arrays.asList(runicList).indexOf(c) / 16);
}
private int kanaIndexX(char c) {
return (c - 0x3040) % 16;
}
private int kanaIndexY(char c) {
return (c - 0x3040) / 16;
}
private int cjkPunctIndexX(char c) {
return (c - 0x3000) % 16;
}
private int cjkPunctIndexY(char c) {
return (c - 0x3000) / 16;
}
private int uniHanIndexX(char c) {
return (c - 0x3400) % 256;
}
private int uniHanIndexY(char c) {
return (c - 0x3400) / 256;
}
private int cyrilicIndexX(char c) {
return (c - 0x400) % 16;
}
private int cyrilicIndexY(char c) {
return (c - 0x400) / 16;
}
private int cyrilicEFindexX(char c) {
return (Arrays.asList(cyrilecEFList).indexOf(c) % 16);
}
private int cyrilicEFindexY(char c) {
return (Arrays.asList(cyrilecEFList).indexOf(c) / 16);
}
private int fullwidthUniIndexX(char c) {
return (c - 0xFF00) % 16;
}
private int fullwidthUniIndexY(char c) {
return (c - 0xFF00) / 16;
}
private int uniPunctIndexX(char c) {
return (c - 0x2000) % 16;
}
private int uniPunctIndexY(char c) {
return (c - 0x2000) / 16;
}
private int wenQuanYiIndexX(char c) {
// v Ext1 v Unihan
return (c - (c <= 0x4DB5 ? 0x33F3 : 0x33F3 + 0x4A)) % 32;
}
private int wenQuanYi1IndexY(char c) {
return (c - (0x33F3 + 0x4A)) / 32;
}
private int wenQuanYi2IndexY(char c) {
return (c - 0x69FD) / 32;
}
@Override
public int getWidth(String s) {
return getWidthSubstr(s, s.length());
}
private int getWidthSubstr(String s, int endIndex) {
int len = 0;
for (int i = 0; i < endIndex; i++) {
int c = getSheetType(s.charAt(i));
if (i > 0 && s.charAt(i) > 0x20) { // Kerning
int cpre = getSheetType(s.charAt(i - 1));
if (
((cpre == SHEET_UNIHAN || cpre == SHEET_HANGUL)
&& !(c == SHEET_UNIHAN || c == SHEET_HANGUL))
|| ((c == SHEET_UNIHAN || c == SHEET_HANGUL)
&& !(cpre == SHEET_UNIHAN || cpre == SHEET_HANGUL))
) {
// margin after/before hangul/unihan
len += 2;
}
else if ((c == SHEET_HANGUL || c == SHEET_KANA)
&& (cpre == SHEET_HANGUL || cpre == SHEET_KANA)) {
// margin between hangul/kana
len += 1;
}
}
if (c == SHEET_ASCII_EF || c == SHEET_EXTA_EF || c == SHEET_CYRILIC_EF)
len += W_LATIN_NARROW;
else if (c == SHEET_KANA || c == SHEET_HANGUL || c == SHEET_CJK_PUNCT)
len += W_CJK;
else if (c == SHEET_UNIHAN || c == SHEET_FW_UNI || c == SHEET_WENQUANYI_1 || c == SHEET_WENQUANYI_2)
len += W_UNIHAN;
else
len += W_LATIN_WIDE;
if (i < endIndex - 1) len += interchar;
}
return len;
}
@Override
public int getHeight(String s) {
return H;
}
@Override
public int getLineHeight() {
return H;
}
@Override
public void drawString(float x, float y, String s) {
drawString(x, y, s, Color.white);
}
@Override
public void drawString(float x, float y, String s, Color color) {
// hangul fonts first
hangulSheet.startUse();
// JOHAB
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (isHangul(ch)) {
int hIndex = ch - 0xAC00;
int indexCho = getHanChosung(hIndex);
int indexJung = getHanJungseong(hIndex);
int indexJong = getHanJongseong(hIndex);
int choRow = getHanChoseongRow(hIndex);
int jungRow = getHanJungseongRow(hIndex);
int jongRow = getHanJongseongRow();
int glyphW = getWidth("" + ch);
// chosung
hangulSheet.renderInUse(
Math.round(x
+ getWidthSubstr(s, i + 1) - glyphW
)
, Math.round((H - H_HANGUL) / 2 + y + 1)
, indexCho
, choRow
);
// jungseong
hangulSheet.renderInUse(
Math.round(x
+ getWidthSubstr(s, i + 1) - glyphW
)
, Math.round((H - H_HANGUL) / 2 + y + 1)
, indexJung
, jungRow
);
// jongseong
hangulSheet.renderInUse(
Math.round(x
+ getWidthSubstr(s, i + 1) - glyphW
)
, Math.round((H - H_HANGUL) / 2 + y + 1)
, indexJong
, jongRow
);
}
}
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 (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (isWenQuanYi1(ch)) {
int glyphW = getWidth("" + ch);
wenQuanYi_1.renderInUse(
Math.round(x
+ getWidthSubstr(s, i + 1) - glyphW
)
, Math.round((H - H_UNIHAN) / 2 + y - 1)
, wenQuanYiIndexX(ch)
, wenQuanYi1IndexY(ch)
);
}
}
wenQuanYi_1.endUse();
wenQuanYi_2.startUse();
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (isWenQuanYi2(ch)) {
int glyphW = getWidth("" + ch);
wenQuanYi_2.renderInUse(
Math.round(x
+ getWidthSubstr(s, i + 1) - glyphW
)
, Math.round((H - H_UNIHAN) / 2 + y - 1)
, wenQuanYiIndexX(ch)
, wenQuanYi2IndexY(ch)
);
}
}
wenQuanYi_2.endUse();
//ascii fonts
int prevInstance = -1;
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (!isHangul(ch) && !isUniHan(ch)) {
// if not init, enduse first
if (prevInstance != -1) {
sheetKey[prevInstance].endUse();
}
sheetKey[getSheetType(ch)].startUse();
prevInstance = getSheetType(ch);
int sheetX;
int sheetY;
switch (prevInstance) {
case SHEET_ASCII_EF:
sheetX = asciiEFindexX(ch);
sheetY = asciiEFindexY(ch);
break;
case SHEET_EXTA_EF:
sheetX = extAEFindexX(ch);
sheetY = extAEFindexY(ch);
break;
case SHEET_RUNIC:
sheetX = runicIndexX(ch);
sheetY = runicIndexY(ch);
break;
case SHEET_EXTA_EM:
sheetX = (ch - 0x100) % 16;
sheetY = (ch - 0x100) / 16;
break;
case SHEET_KANA:
sheetX = kanaIndexX(ch);
sheetY = kanaIndexY(ch);
break;
case SHEET_CJK_PUNCT:
sheetX = cjkPunctIndexX(ch);
sheetY = cjkPunctIndexY(ch);
break;
case SHEET_CYRILIC_EM:
sheetX = cyrilicIndexX(ch);
sheetY = cyrilicIndexY(ch);
break;
case SHEET_CYRILIC_EF:
sheetX = cyrilicEFindexX(ch);
sheetY = cyrilicEFindexY(ch);
break;
case SHEET_FW_UNI:
sheetX = fullwidthUniIndexX(ch);
sheetY = fullwidthUniIndexY(ch);
break;
case SHEET_UNI_PUNCT:
sheetX = uniPunctIndexX(ch);
sheetY = uniPunctIndexY(ch);
break;
default:
sheetX = ch % 16;
sheetY = ch / 16;
break;
}
try {
int glyphW = getWidth("" + ch);
sheetKey[prevInstance].renderInUse(
Math.round(x + getWidthSubstr(s, i + 1) - glyphW)
// Interchar: pull punct right next to hangul to the left
+ ((i > 0 && isHangul(s.charAt(i - 1))) ? -3 : 0)
, Math.round(y)
+ ((prevInstance == SHEET_CJK_PUNCT) ? -1 :
(prevInstance == SHEET_FW_UNI) ? (H - H_HANGUL) / 2 : 0)
, sheetX
, sheetY
);
}
catch (ArrayIndexOutOfBoundsException e) {
// System.out.println("ArrayIndexOutOfBoundsException")
// System.out.println("char: '" + ch + "' (" + String.valueOf((int) ch) + ")");
// System.out.println("sheet: " + prevInstance);
// System.out.println("sheetX: " + sheetX);
// System.out.println("sheetY: " + sheetY);
}
}
}
if (prevInstance != -1) {
sheetKey[prevInstance].endUse();
}
}
private int getSheetType(char c) {
// EFs
if (isAsciiEF(c)) return SHEET_ASCII_EF;
else if (isExtAEF(c)) return SHEET_EXTA_EF;
else if (isCyrilicEF(c)) return SHEET_CYRILIC_EF;
// fixed width
else if (isRunic(c)) return SHEET_RUNIC;
else if (isHangul(c)) return SHEET_HANGUL;
else if (isKana(c)) return SHEET_KANA;
else if (isUniHan(c)) return SHEET_UNIHAN;
else if (isAscii(c)) return SHEET_ASCII_EM;
else if (isExtA(c)) return SHEET_EXTA_EM;
else if (isCyrilic(c)) return SHEET_CYRILIC_EM;
else if (isUniPunct(c)) return SHEET_UNI_PUNCT;
// fixed width punctuations
else if (isCJKPunct(c)) return SHEET_CJK_PUNCT;
else if (isFullwidthUni(c)) return SHEET_FW_UNI;
else return SHEET_ASCII_EM; // 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
public void drawString(float x, float y, String s, Color color, int startIndex, int endIndex) {
String unprintedHead = s.substring(0, startIndex);
String printedBody = s.substring(startIndex, endIndex);
int xoff = getWidth(unprintedHead);
drawString(x + xoff, y, printedBody, color);
}
public void reloadUnihan() throws SlickException {
}
/**
* Set margin between characters
* @param margin
*/
public void setInterchar(int margin) {
interchar = margin;
}
private void setBlendModeMul() {
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_DST_COLOR, GL11.GL_ONE_MINUS_SRC_ALPHA);
}
private void setBlendModeNormal() {
GL11.glDisable(GL11.GL_BLEND);
Terrarum.appgc.getGraphics().setDrawMode(Graphics.MODE_NORMAL);
}
}