mirror of
https://github.com/kichikuou/system3-sdl2.git
synced 2026-09-27 09:28:06 +03:00
538 lines
14 KiB
C++
538 lines
14 KiB
C++
/*
|
||
ALICE SOFT SYSTEM 3 for Win32
|
||
|
||
[ AGS - text ]
|
||
*/
|
||
|
||
#include <algorithm>
|
||
#include <limits.h>
|
||
#include <string.h>
|
||
#include "ags.h"
|
||
#include "nact.h"
|
||
#include "encoding.h"
|
||
#include "texthook.h"
|
||
|
||
namespace {
|
||
|
||
bool antialias = true;
|
||
|
||
int convert_to_zenkaku(int code)
|
||
{
|
||
switch(code) {
|
||
case u' ': return u' ';
|
||
case u'!': return u'!';
|
||
case u'"': return u'”';
|
||
case u'#': return u'#';
|
||
case u'$': return u'$';
|
||
case u'%': return u'%';
|
||
case u'&': return u'&';
|
||
case u'\'': return u'’';
|
||
case u'(': return u'(';
|
||
case u')': return u')';
|
||
case u'*': return u'*';
|
||
case u'+': return u'+';
|
||
case u',': return u',';
|
||
case u'-': return u'-';
|
||
case u'.': return u'.';
|
||
case u'/': return u'/';
|
||
case u'0': return u'0';
|
||
case u'1': return u'1';
|
||
case u'2': return u'2';
|
||
case u'3': return u'3';
|
||
case u'4': return u'4';
|
||
case u'5': return u'5';
|
||
case u'6': return u'6';
|
||
case u'7': return u'7';
|
||
case u'8': return u'8';
|
||
case u'9': return u'9';
|
||
case u':': return u':';
|
||
case u';': return u';';
|
||
case u'<': return u'<';
|
||
case u'=': return u'=';
|
||
case u'>': return u'>';
|
||
case u'?': return u'?';
|
||
case u'@': return u'@';
|
||
case u'A': return u'A';
|
||
case u'B': return u'B';
|
||
case u'C': return u'C';
|
||
case u'D': return u'D';
|
||
case u'E': return u'E';
|
||
case u'F': return u'F';
|
||
case u'G': return u'G';
|
||
case u'H': return u'H';
|
||
case u'I': return u'I';
|
||
case u'J': return u'J';
|
||
case u'K': return u'K';
|
||
case u'L': return u'L';
|
||
case u'M': return u'M';
|
||
case u'N': return u'N';
|
||
case u'O': return u'O';
|
||
case u'P': return u'P';
|
||
case u'Q': return u'Q';
|
||
case u'R': return u'R';
|
||
case u'S': return u'S';
|
||
case u'T': return u'T';
|
||
case u'U': return u'U';
|
||
case u'V': return u'V';
|
||
case u'W': return u'W';
|
||
case u'X': return u'X';
|
||
case u'Y': return u'Y';
|
||
case u'Z': return u'Z';
|
||
case u'[': return u'[';
|
||
case u'\\': return u'¥';
|
||
case u']': return u']';
|
||
case u'^': return u'^';
|
||
case u'_': return u'_';
|
||
case u'`': return u'‘';
|
||
case u'a': return u'a';
|
||
case u'b': return u'b';
|
||
case u'c': return u'c';
|
||
case u'd': return u'd';
|
||
case u'e': return u'e';
|
||
case u'f': return u'f';
|
||
case u'g': return u'g';
|
||
case u'h': return u'h';
|
||
case u'i': return u'i';
|
||
case u'j': return u'j';
|
||
case u'k': return u'k';
|
||
case u'l': return u'l';
|
||
case u'm': return u'm';
|
||
case u'n': return u'n';
|
||
case u'o': return u'o';
|
||
case u'p': return u'p';
|
||
case u'q': return u'q';
|
||
case u'r': return u'r';
|
||
case u's': return u's';
|
||
case u't': return u't';
|
||
case u'u': return u'u';
|
||
case u'v': return u'v';
|
||
case u'w': return u'w';
|
||
case u'x': return u'x';
|
||
case u'y': return u'y';
|
||
case u'z': return u'z';
|
||
case u'{': return u'{';
|
||
case u'|': return u'|';
|
||
case u'}': return u'}';
|
||
case u'~': return u'~';
|
||
case u'。': return u'。';
|
||
case u'「': return u'「';
|
||
case u'」': return u'」';
|
||
case u'、': return u'、';
|
||
case u'・': return u'・';
|
||
case u'ヲ': return u'を';
|
||
case u'ァ': return u'ぁ';
|
||
case u'ィ': return u'ぃ';
|
||
case u'ゥ': return u'ぅ';
|
||
case u'ェ': return u'ぇ';
|
||
case u'ォ': return u'ぉ';
|
||
case u'ャ': return u'ゃ';
|
||
case u'ュ': return u'ゅ';
|
||
case u'ョ': return u'ょ';
|
||
case u'ッ': return u'っ';
|
||
case u'ー': return u'ー';
|
||
case u'ア': return u'あ';
|
||
case u'イ': return u'い';
|
||
case u'ウ': return u'う';
|
||
case u'エ': return u'え';
|
||
case u'オ': return u'お';
|
||
case u'カ': return u'か';
|
||
case u'キ': return u'き';
|
||
case u'ク': return u'く';
|
||
case u'ケ': return u'け';
|
||
case u'コ': return u'こ';
|
||
case u'サ': return u'さ';
|
||
case u'シ': return u'し';
|
||
case u'ス': return u'す';
|
||
case u'セ': return u'せ';
|
||
case u'ソ': return u'そ';
|
||
case u'タ': return u'た';
|
||
case u'チ': return u'ち';
|
||
case u'ツ': return u'つ';
|
||
case u'テ': return u'て';
|
||
case u'ト': return u'と';
|
||
case u'ナ': return u'な';
|
||
case u'ニ': return u'に';
|
||
case u'ヌ': return u'ぬ';
|
||
case u'ネ': return u'ね';
|
||
case u'ノ': return u'の';
|
||
case u'ハ': return u'は';
|
||
case u'ヒ': return u'ひ';
|
||
case u'フ': return u'ふ';
|
||
case u'ヘ': return u'へ';
|
||
case u'ホ': return u'ほ';
|
||
case u'マ': return u'ま';
|
||
case u'ミ': return u'み';
|
||
case u'ム': return u'む';
|
||
case u'メ': return u'め';
|
||
case u'モ': return u'も';
|
||
case u'ヤ': return u'や';
|
||
case u'ユ': return u'ゆ';
|
||
case u'ヨ': return u'よ';
|
||
case u'ラ': return u'ら';
|
||
case u'リ': return u'り';
|
||
case u'ル': return u'る';
|
||
case u'レ': return u'れ';
|
||
case u'ロ': return u'ろ';
|
||
case u'ワ': return u'わ';
|
||
case u'ン': return u'ん';
|
||
case u'゙': return u'゛';
|
||
case u'゚': return u'゜';
|
||
}
|
||
return code;
|
||
}
|
||
|
||
int convert_to_hankaku(int code)
|
||
{
|
||
switch(code) {
|
||
case u' ': return u' ';
|
||
case u'!': return u'!';
|
||
case u'”': return u'"';
|
||
case u'#': return u'#';
|
||
case u'$': return u'$';
|
||
case u'%': return u'%';
|
||
case u'&': return u'&';
|
||
case u'’': return u'\'';
|
||
case u'(': return u'(';
|
||
case u')': return u')';
|
||
case u'*': return u'*';
|
||
case u'+': return u'+';
|
||
case u',': return u',';
|
||
case u'-': return u'-';
|
||
case u'.': return u'.';
|
||
case u'/': return u'/';
|
||
case u'0': return u'0';
|
||
case u'1': return u'1';
|
||
case u'2': return u'2';
|
||
case u'3': return u'3';
|
||
case u'4': return u'4';
|
||
case u'5': return u'5';
|
||
case u'6': return u'6';
|
||
case u'7': return u'7';
|
||
case u'8': return u'8';
|
||
case u'9': return u'9';
|
||
case u':': return u':';
|
||
case u';': return u';';
|
||
case u'<': return u'<';
|
||
case u'=': return u'=';
|
||
case u'>': return u'>';
|
||
case u'?': return u'?';
|
||
case u'@': return u'@';
|
||
case u'A': return u'A';
|
||
case u'B': return u'B';
|
||
case u'C': return u'C';
|
||
case u'D': return u'D';
|
||
case u'E': return u'E';
|
||
case u'F': return u'F';
|
||
case u'G': return u'G';
|
||
case u'H': return u'H';
|
||
case u'I': return u'I';
|
||
case u'J': return u'J';
|
||
case u'K': return u'K';
|
||
case u'L': return u'L';
|
||
case u'M': return u'M';
|
||
case u'N': return u'N';
|
||
case u'O': return u'O';
|
||
case u'P': return u'P';
|
||
case u'Q': return u'Q';
|
||
case u'R': return u'R';
|
||
case u'S': return u'S';
|
||
case u'T': return u'T';
|
||
case u'U': return u'U';
|
||
case u'V': return u'V';
|
||
case u'W': return u'W';
|
||
case u'X': return u'X';
|
||
case u'Y': return u'Y';
|
||
case u'Z': return u'Z';
|
||
case u'[': return u'[';
|
||
case u'¥': return u'\\';
|
||
case u']': return u']';
|
||
case u'^': return u'^';
|
||
case u'_': return u'_';
|
||
case u'‘': return u'`';
|
||
case u'a': return u'a';
|
||
case u'b': return u'b';
|
||
case u'c': return u'c';
|
||
case u'd': return u'd';
|
||
case u'e': return u'e';
|
||
case u'f': return u'f';
|
||
case u'g': return u'g';
|
||
case u'h': return u'h';
|
||
case u'i': return u'i';
|
||
case u'j': return u'j';
|
||
case u'k': return u'k';
|
||
case u'l': return u'l';
|
||
case u'm': return u'm';
|
||
case u'n': return u'n';
|
||
case u'o': return u'o';
|
||
case u'p': return u'p';
|
||
case u'q': return u'q';
|
||
case u'r': return u'r';
|
||
case u's': return u's';
|
||
case u't': return u't';
|
||
case u'u': return u'u';
|
||
case u'v': return u'v';
|
||
case u'w': return u'w';
|
||
case u'x': return u'x';
|
||
case u'y': return u'y';
|
||
case u'z': return u'z';
|
||
case u'{': return u'{';
|
||
case u'|': return u'|';
|
||
case u'}': return u'}';
|
||
case u'~': return u'~';
|
||
case u'。': return u'。';
|
||
case u'「': return u'「';
|
||
case u'」': return u'」';
|
||
case u'、': return u'、';
|
||
case u'・': return u'・';
|
||
case u'を': return u'ヲ';
|
||
case u'ぁ': return u'ァ';
|
||
case u'ぃ': return u'ィ';
|
||
case u'ぅ': return u'ゥ';
|
||
case u'ぇ': return u'ェ';
|
||
case u'ぉ': return u'ォ';
|
||
case u'ゃ': return u'ャ';
|
||
case u'ゅ': return u'ュ';
|
||
case u'ょ': return u'ョ';
|
||
case u'っ': return u'ッ';
|
||
case u'ー': return u'ー';
|
||
case u'あ': return u'ア';
|
||
case u'い': return u'イ';
|
||
case u'う': return u'ウ';
|
||
case u'え': return u'エ';
|
||
case u'お': return u'オ';
|
||
case u'か': return u'カ';
|
||
case u'き': return u'キ';
|
||
case u'く': return u'ク';
|
||
case u'け': return u'ケ';
|
||
case u'こ': return u'コ';
|
||
case u'さ': return u'サ';
|
||
case u'し': return u'シ';
|
||
case u'す': return u'ス';
|
||
case u'せ': return u'セ';
|
||
case u'そ': return u'ソ';
|
||
case u'た': return u'タ';
|
||
case u'ち': return u'チ';
|
||
case u'つ': return u'ツ';
|
||
case u'て': return u'テ';
|
||
case u'と': return u'ト';
|
||
case u'な': return u'ナ';
|
||
case u'に': return u'ニ';
|
||
case u'ぬ': return u'ヌ';
|
||
case u'ね': return u'ネ';
|
||
case u'の': return u'ノ';
|
||
case u'は': return u'ハ';
|
||
case u'ひ': return u'ヒ';
|
||
case u'ふ': return u'フ';
|
||
case u'へ': return u'ヘ';
|
||
case u'ほ': return u'ホ';
|
||
case u'ま': return u'マ';
|
||
case u'み': return u'ミ';
|
||
case u'む': return u'ム';
|
||
case u'め': return u'メ';
|
||
case u'も': return u'モ';
|
||
case u'や': return u'ヤ';
|
||
case u'ゆ': return u'ユ';
|
||
case u'よ': return u'ヨ';
|
||
case u'ら': return u'ラ';
|
||
case u'り': return u'リ';
|
||
case u'る': return u'ル';
|
||
case u'れ': return u'レ';
|
||
case u'ろ': return u'ロ';
|
||
case u'わ': return u'ワ';
|
||
case u'ん': return u'ン';
|
||
case u'゛': return u'゙';
|
||
case u'゜': return u'゚';
|
||
}
|
||
return code;
|
||
}
|
||
|
||
} // namespace
|
||
|
||
void AGS::draw_text(const char* string, bool text_wait)
|
||
{
|
||
if (!*string)
|
||
return;
|
||
uint8 antialias_cache[256*7];
|
||
if (antialias)
|
||
memset(antialias_cache, 0, 256);
|
||
|
||
TextContext& ctx = draw_menu ? menu : text;
|
||
int screen = draw_menu ? 2 : dest_screen;
|
||
int dest_x = ctx.pos.x;
|
||
int dest_y = ctx.pos.y;
|
||
if (ctx.current_line_height < ctx.font_size)
|
||
ctx.current_line_height = ctx.font_size;
|
||
|
||
TTF_Font* font = NULL;
|
||
switch (ctx.font_size) {
|
||
case 16: font = hFont16; break;
|
||
case 24: font = hFont24; break;
|
||
case 32: font = hFont32; break;
|
||
case 48: font = hFont48; break;
|
||
case 64: font = hFont64; break;
|
||
}
|
||
int ascent = TTF_FontAscent(font);
|
||
int descent = TTF_FontDescent(font);
|
||
// Adjust dest_y if the font height is larger than the specified size.
|
||
dest_y -= (ascent - descent - ctx.font_size) / 2;
|
||
|
||
while (*string) {
|
||
int code = g_nact->encoding->next_codepoint(&string);
|
||
if(draw_hankaku) {
|
||
code = convert_to_hankaku(code);
|
||
} else {
|
||
code = convert_to_zenkaku(code);
|
||
}
|
||
|
||
// 文字出力
|
||
if (GAIJI_FIRST <= code && code <= GAIJI_LAST) {
|
||
// Use unadjusted dest_y here.
|
||
draw_gaiji(screen, dest_x, ctx.pos.y, gaiji[code - GAIJI_FIRST], ctx.font_size, ctx.font_color);
|
||
dest_x += ctx.font_size;
|
||
} else {
|
||
if (!draw_menu)
|
||
texthook_character(g_nact->get_scenario_page(), code);
|
||
|
||
if (antialias)
|
||
draw_char_antialias(screen, dest_x, dest_y, code, font, ctx.font_color, antialias_cache);
|
||
else
|
||
draw_char(screen, dest_x, dest_y, code, font, ctx.font_color);
|
||
|
||
int miny, maxy, advance;
|
||
TTF_GlyphMetrics(font, code, NULL, NULL, &miny, &maxy, &advance);
|
||
// Some fonts report incorrect Ascent/Descent value so we need to fix them.
|
||
if (miny < descent) descent = miny;
|
||
if (maxy > ascent) ascent = maxy;
|
||
dest_x += advance;
|
||
}
|
||
|
||
if (!draw_menu && text_wait && code != ' ') {
|
||
// 画面更新
|
||
if(screen == 0)
|
||
draw_screen(ctx.pos.x, dest_y, dest_x - ctx.pos.x, ascent - descent);
|
||
ctx.pos.x = dest_x;
|
||
// Wait
|
||
g_nact->text_wait();
|
||
}
|
||
}
|
||
if (!draw_menu && !text_wait) {
|
||
// 画面更新
|
||
if(screen == 0)
|
||
draw_screen(ctx.pos.x, dest_y, dest_x - ctx.pos.x, ascent - descent);
|
||
}
|
||
ctx.pos.x = dest_x;
|
||
}
|
||
|
||
void AGS::draw_char(int dest, int dest_x, int dest_y, uint16 code, TTF_Font* font, uint8 color)
|
||
{
|
||
// パターン取得
|
||
SDL_Color white = {0xff, 0xff, 0xff};
|
||
SDL_Surface* fs = TTF_RenderGlyph_Solid(font, code, white);
|
||
|
||
// パターン出力
|
||
for (int y = std::max(0, -dest_y); y < fs->h && dest_y + y < 480; y++) {
|
||
uint8_t* pattern = (uint8_t*)fs->pixels + fs->pitch * y;
|
||
for(int x = 0; x < fs->w && dest_x + x < 640; x++) {
|
||
if(pattern[x] != 0) {
|
||
vram[dest][dest_y + y][dest_x + x] = color;
|
||
}
|
||
}
|
||
}
|
||
|
||
SDL_FreeSurface(fs);
|
||
}
|
||
|
||
int AGS::nearest_color(int r, int g, int b) {
|
||
int i, col, mind = INT_MAX;
|
||
for (i = 0; i < 256; i++) {
|
||
int dr = r - palR(i);
|
||
int dg = g - palG(i);
|
||
int db = b - palB(i);
|
||
int d = dr*dr*30 + dg*dg*59 + db*db*11;
|
||
if (d < mind) {
|
||
mind = d;
|
||
col = i;
|
||
}
|
||
}
|
||
return col;
|
||
}
|
||
|
||
void AGS::draw_char_antialias(int dest, int dest_x, int dest_y, uint16 code, TTF_Font* font, uint8 color, uint8 cache[])
|
||
{
|
||
// パターン取得
|
||
SDL_Color black = {0, 0, 0};
|
||
SDL_Color white = {0xff, 0xff, 0xff};
|
||
SDL_Surface* fs = TTF_RenderGlyph_Shaded(font, code, white, black);
|
||
|
||
// パターン出力
|
||
for (int y = std::max(0, -dest_y); y < fs->h && dest_y + y < 480; y++) {
|
||
uint8_t* pattern = (uint8_t*)fs->pixels + fs->pitch * y;
|
||
uint8_t* dp = &vram[dest][dest_y + y][dest_x];
|
||
for(int x = 0; x < fs->w && dest_x + x < 640; x++, dp++) {
|
||
uint8 bg = *dp;
|
||
int alpha = pattern[x] >> 5;
|
||
if (alpha == 0) {
|
||
// Transparent, do nothing
|
||
} else if (alpha == 7) {
|
||
*dp = color;
|
||
} else if (cache[bg] & 1 << alpha) {
|
||
*dp = cache[alpha << 8 | bg];
|
||
} else {
|
||
cache[bg] |= 1 << alpha;
|
||
int c = nearest_color((palR(color) * alpha + palR(bg) * (7 - alpha)) / 7,
|
||
(palG(color) * alpha + palG(bg) * (7 - alpha)) / 7,
|
||
(palB(color) * alpha + palB(bg) * (7 - alpha)) / 7);
|
||
cache[alpha << 8 | bg] = c;
|
||
*dp = c;
|
||
}
|
||
}
|
||
}
|
||
|
||
SDL_FreeSurface(fs);
|
||
}
|
||
|
||
void AGS::draw_gaiji(int dest, int dest_x, int dest_y, const uint8_t bitmap[32], int size, uint8 color)
|
||
{
|
||
bool pattern[16][16];
|
||
|
||
// パターン取得
|
||
for(int y = 0; y < 16; y++) {
|
||
uint8 l = bitmap[y * 2 + 0];
|
||
uint8 r = bitmap[y * 2 + 1];
|
||
|
||
pattern[y][ 0] = ((l & 0x80) != 0);
|
||
pattern[y][ 1] = ((l & 0x40) != 0);
|
||
pattern[y][ 2] = ((l & 0x20) != 0);
|
||
pattern[y][ 3] = ((l & 0x10) != 0);
|
||
pattern[y][ 4] = ((l & 0x08) != 0);
|
||
pattern[y][ 5] = ((l & 0x04) != 0);
|
||
pattern[y][ 6] = ((l & 0x02) != 0);
|
||
pattern[y][ 7] = ((l & 0x01) != 0);
|
||
pattern[y][ 8] = ((r & 0x80) != 0);
|
||
pattern[y][ 9] = ((r & 0x40) != 0);
|
||
pattern[y][10] = ((r & 0x20) != 0);
|
||
pattern[y][11] = ((r & 0x10) != 0);
|
||
pattern[y][12] = ((r & 0x08) != 0);
|
||
pattern[y][13] = ((r & 0x04) != 0);
|
||
pattern[y][14] = ((r & 0x02) != 0);
|
||
pattern[y][15] = ((r & 0x01) != 0);
|
||
}
|
||
|
||
// パターン出力
|
||
for(int y = 0; y < size && dest_y + y < 480; y++) {
|
||
for(int x = 0; x < size && dest_x + x < 640; x++) {
|
||
if(pattern[(y * 16) / size][(x * 16) / size]) {
|
||
vram[dest][dest_y + y][dest_x + x] = color;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
extern "C" {
|
||
|
||
void EMSCRIPTEN_KEEPALIVE ags_setAntialiasedStringMode(int on) {
|
||
antialias = on != 0;
|
||
}
|
||
|
||
}
|