/* ALICE SOFT SYSTEM 3 for Win32 [ AGS - text ] */ #include #include "ags.h" #include "s2utbl.h" static bool antialias = false; inline uint16 sjis_to_unicode(uint16 code) { if (code >= 0xa0 && code <= 0xdf) return 0xff60 + code - 0xa0; if (code < 0x100) return code; return s2u[(code >> 8) - 0x80][(code & 0xff) - 0x40]; } void AGS::draw_text(char string[]) { int p = 0; int screen, dest_x, dest_y, font_size; uint8 font_color; uint8 antialias_cache[256*7]; if (antialias) memset(antialias_cache, 0, 256); if (draw_menu) { screen = 2; dest_x = menu_dest_x; dest_y = menu_dest_y; font_size = menu_font_size; font_color = menu_font_color; } else { screen = dest_screen; dest_x = text_dest_x; dest_y = text_dest_y; font_size = text_font_size; font_color = text_font_color; if (*string && text_font_maxsize < text_font_size) text_font_maxsize = text_font_size; } while(string[p] != '\0') { // 文字コード取得 uint16 code = (uint8)string[p++]; if((0x81 <= code && code <= 0x9f) || 0xe0 <= code) { code = (code << 8) | (uint8)string[p++]; } if(draw_hankaku) { code = convert_hankaku(code); } else { code = convert_zenkaku(code); } // 文字出力 if((0xeb9f <= code && code <= 0xebfc) || (0xec40 <= code && code <= 0xec9e)) { draw_gaiji(screen, dest_x, dest_y, code, font_size, font_color); } else { if (antialias) draw_char_antialias(screen, dest_x, dest_y, code, font_size, font_color, antialias_cache); else draw_char(screen, dest_x, dest_y, code, font_size, font_color); } // 出力位置の更新 dest_x += (code & 0xff00) ? font_size : (font_size >> 1); } if (draw_menu) menu_dest_x = dest_x; else { // 画面更新 if(screen == 0) draw_screen(text_dest_x, dest_y, dest_x - text_dest_x, font_size); text_dest_x = dest_x; } } void AGS::draw_char(int dest, int dest_x, int dest_y, uint16 code, int size, uint8 color) { // パターン取得 TTF_Font* font = NULL; switch (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; } SDL_Color white = {0xff, 0xff, 0xff}; SDL_Surface* fs = TTF_RenderGlyph_Solid(font, sjis_to_unicode(code), white); // パターン出力 for(int y = 0; y < size && y < fs->w && dest_y + y < 480; y++) { uint8 *pattern = (uint8*)surface_line(fs, y); // FIXME: do not assume 8bpp for(int x = 0; x < size && x < fs->h && 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, int size, uint8 color, uint8 cache[]) { // パターン取得 TTF_Font* font = NULL; switch (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; } SDL_Color black = {0, 0, 0}; SDL_Color white = {0xff, 0xff, 0xff}; SDL_Surface* fs = TTF_RenderGlyph_Shaded(font, sjis_to_unicode(code), white, black); // パターン出力 for(int y = 0; y < size && y < fs->w && dest_y + y < 480; y++) { uint8 *pattern = (uint8*)surface_line(fs, y); uint32 *dp = &vram[dest][dest_y + y][dest_x]; for(int x = 0; x < size && x < fs->h && 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, uint16 code, int size, uint8 color) { int index = (0xeb9f <= code && code <= 0xebfc) ? code - 0xeb9f : (0xec40 <= code && code <= 0xec9e) ? code - 0xec40 + 94 : 0; bool pattern[16][16]; // パターン取得 for(int y = 0; y < 16; y++) { uint8 l = gaiji[index][y * 2 + 0]; uint8 r = gaiji[index][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; } } } } uint16 AGS::convert_zenkaku(uint16 code) { switch(code) { case 0x20: return 0x8140; // ' ' case 0x21: return 0x8149; // '!' case 0x22: return 0x8168; // '”' case 0x23: return 0x8194; // '#' case 0x24: return 0x8190; // '$' case 0x25: return 0x8193; // '%' case 0x26: return 0x8195; // '&' case 0x27: return 0x8166; // '’' case 0x28: return 0x8169; // '(' case 0x29: return 0x816a; // ')' case 0x2a: return 0x8196; // '*' case 0x2b: return 0x817b; // '+' case 0x2c: return 0x8143; // ',' case 0x2d: return 0x817c; // '−' case 0x2e: return 0x8144; // '.' case 0x2f: return 0x815e; // '/' case 0x30: return 0x824f; // '0' case 0x31: return 0x8250; // '1' case 0x32: return 0x8251; // '2' case 0x33: return 0x8252; // '3' case 0x34: return 0x8253; // '4' case 0x35: return 0x8254; // '5' case 0x36: return 0x8255; // '6' case 0x37: return 0x8256; // '7' case 0x38: return 0x8257; // '8' case 0x39: return 0x8258; // '9' case 0x3a: return 0x8146; // ':' case 0x3b: return 0x8147; // ';' case 0x3c: return 0x8183; // '<' case 0x3d: return 0x8181; // '=' case 0x3e: return 0x8184; // '>' case 0x3f: return 0x8148; // '?' case 0x40: return 0x8197; // '@' case 0x41: return 0x8260; // 'A' case 0x42: return 0x8261; // 'B' case 0x43: return 0x8262; // 'C' case 0x44: return 0x8263; // 'D' case 0x45: return 0x8264; // 'E' case 0x46: return 0x8265; // 'F' case 0x47: return 0x8266; // 'G' case 0x48: return 0x8267; // 'H' case 0x49: return 0x8268; // 'I' case 0x4a: return 0x8269; // 'J' case 0x4b: return 0x826a; // 'K' case 0x4c: return 0x826b; // 'L' case 0x4d: return 0x826c; // 'M' case 0x4e: return 0x826d; // 'N' case 0x4f: return 0x826e; // 'O' case 0x50: return 0x826f; // 'P' case 0x51: return 0x8270; // 'Q' case 0x52: return 0x8271; // 'R' case 0x53: return 0x8272; // 'S' case 0x54: return 0x8273; // 'T' case 0x55: return 0x8274; // 'U' case 0x56: return 0x8275; // 'V' case 0x57: return 0x8276; // 'W' case 0x58: return 0x8277; // 'X' case 0x59: return 0x8278; // 'Y' case 0x5a: return 0x8279; // 'Z' case 0x5b: return 0x816d; // '[' case 0x5c: return 0x818f; // '¥' case 0x5d: return 0x816e; // ']' case 0x5e: return 0x814f; // '^' case 0x5f: return 0x8151; // '_' case 0x60: return 0x8165; // '‘' case 0x61: return 0x8281; // 'a' case 0x62: return 0x8282; // 'b' case 0x63: return 0x8283; // 'c' case 0x64: return 0x8284; // 'd' case 0x65: return 0x8285; // 'e' case 0x66: return 0x8286; // 'f' case 0x67: return 0x8287; // 'g' case 0x68: return 0x8288; // 'h' case 0x69: return 0x8289; // 'i' case 0x6a: return 0x828a; // 'j' case 0x6b: return 0x828b; // 'k' case 0x6c: return 0x828c; // 'l' case 0x6d: return 0x828d; // 'm' case 0x6e: return 0x828e; // 'n' case 0x6f: return 0x828f; // 'o' case 0x70: return 0x8290; // 'p' case 0x71: return 0x8291; // 'q' case 0x72: return 0x8292; // 'r' case 0x73: return 0x8293; // 's' case 0x74: return 0x8294; // 't' case 0x75: return 0x8295; // 'u' case 0x76: return 0x8296; // 'v' case 0x77: return 0x8297; // 'w' case 0x78: return 0x8298; // 'x' case 0x79: return 0x8299; // 'y' case 0x7a: return 0x829a; // 'z' case 0x7b: return 0x816f; // '{' case 0x7c: return 0x8162; // '|' case 0x7d: return 0x8170; // '}' case 0x7e: return 0x8160; // '〜' case 0xa1: return 0x8142; // '。' case 0xa2: return 0x8175; // '「' case 0xa3: return 0x8176; // '」' case 0xa4: return 0x8141; // '、' case 0xa5: return 0x8145; // '・' case 0xa6: return 0x82f0; // 'を' case 0xa7: return 0x829f; // 'ぁ' case 0xa8: return 0x82a1; // 'ぃ' case 0xa9: return 0x82a3; // 'ぅ' case 0xaa: return 0x82a5; // 'ぇ' case 0xab: return 0x82a7; // 'ぉ' case 0xac: return 0x82e1; // 'ゃ' case 0xad: return 0x82e3; // 'ゅ' case 0xae: return 0x82e5; // 'ょ' case 0xaf: return 0x82c1; // 'っ' case 0xb0: return 0x815b; // 'ー' case 0xb1: return 0x82a0; // 'あ' case 0xb2: return 0x82a2; // 'い' case 0xb3: return 0x82a4; // 'う' case 0xb4: return 0x82a6; // 'え' case 0xb5: return 0x82a8; // 'お' case 0xb6: return 0x82a9; // 'か' case 0xb7: return 0x82ab; // 'き' case 0xb8: return 0x82ad; // 'く' case 0xb9: return 0x82af; // 'け' case 0xba: return 0x82b1; // 'こ' case 0xbb: return 0x82b3; // 'さ' case 0xbc: return 0x82b5; // 'し' case 0xbd: return 0x82b7; // 'す' case 0xbe: return 0x82b9; // 'せ' case 0xbf: return 0x82bb; // 'そ' case 0xc0: return 0x82bd; // 'た' case 0xc1: return 0x82bf; // 'ち' case 0xc2: return 0x82c2; // 'つ' case 0xc3: return 0x82c4; // 'て' case 0xc4: return 0x82c6; // 'と' case 0xc5: return 0x82c8; // 'な' case 0xc6: return 0x82c9; // 'に' case 0xc7: return 0x82ca; // 'ぬ' case 0xc8: return 0x82cb; // 'ね' case 0xc9: return 0x82cc; // 'の' case 0xca: return 0x82cd; // 'は' case 0xcb: return 0x82d0; // 'ひ' case 0xcc: return 0x82d3; // 'ふ' case 0xcd: return 0x82d6; // 'へ' case 0xce: return 0x82d9; // 'ほ' case 0xcf: return 0x82dc; // 'ま' case 0xd0: return 0x82dd; // 'み' case 0xd1: return 0x82de; // 'む' case 0xd2: return 0x82df; // 'め' case 0xd3: return 0x82e0; // 'も' case 0xd4: return 0x82e2; // 'や' case 0xd5: return 0x82e4; // 'ゆ' case 0xd6: return 0x82e6; // 'よ' case 0xd7: return 0x82e7; // 'ら' case 0xd8: return 0x82e8; // 'り' case 0xd9: return 0x82e9; // 'る' case 0xda: return 0x82ea; // 'れ' case 0xdb: return 0x82eb; // 'ろ' case 0xdc: return 0x82ed; // 'わ' case 0xdd: return 0x82f1; // 'ん' case 0xde: return 0x814a; // '゛' case 0xdf: return 0x814b; // '゜' } return code; } uint16 AGS::convert_hankaku(uint16 code) { switch(code) { case 0x8140: return 0x20; // ' ' case 0x8149: return 0x21; // '!' case 0x8168: return 0x22; // '”' case 0x8194: return 0x23; // '#' case 0x8190: return 0x24; // '$' case 0x8193: return 0x25; // '%' case 0x8195: return 0x26; // '&' case 0x8166: return 0x27; // '’' case 0x8169: return 0x28; // '(' case 0x816a: return 0x29; // ')' case 0x8196: return 0x2a; // '*' case 0x817b: return 0x2b; // '+' case 0x8143: return 0x2c; // ',' case 0x817c: return 0x2d; // '−' case 0x8144: return 0x2e; // '.' case 0x815e: return 0x2f; // '/' case 0x824f: return 0x30; // '0' case 0x8250: return 0x31; // '1' case 0x8251: return 0x32; // '2' case 0x8252: return 0x33; // '3' case 0x8253: return 0x34; // '4' case 0x8254: return 0x35; // '5' case 0x8255: return 0x36; // '6' case 0x8256: return 0x37; // '7' case 0x8257: return 0x38; // '8' case 0x8258: return 0x39; // '9' case 0x8146: return 0x3a; // ':' case 0x8147: return 0x3b; // ';' case 0x8183: return 0x3c; // '<' case 0x8181: return 0x3d; // '=' case 0x8184: return 0x3e; // '>' case 0x8148: return 0x3f; // '?' case 0x8197: return 0x40; // '@' case 0x8260: return 0x41; // 'A' case 0x8261: return 0x42; // 'B' case 0x8262: return 0x43; // 'C' case 0x8263: return 0x44; // 'D' case 0x8264: return 0x45; // 'E' case 0x8265: return 0x46; // 'F' case 0x8266: return 0x47; // 'G' case 0x8267: return 0x48; // 'H' case 0x8268: return 0x49; // 'I' case 0x8269: return 0x4a; // 'J' case 0x826a: return 0x4b; // 'K' case 0x826b: return 0x4c; // 'L' case 0x826c: return 0x4d; // 'M' case 0x826d: return 0x4e; // 'N' case 0x826e: return 0x4f; // 'O' case 0x826f: return 0x50; // 'P' case 0x8270: return 0x51; // 'Q' case 0x8271: return 0x52; // 'R' case 0x8272: return 0x53; // 'S' case 0x8273: return 0x54; // 'T' case 0x8274: return 0x55; // 'U' case 0x8275: return 0x56; // 'V' case 0x8276: return 0x57; // 'W' case 0x8277: return 0x58; // 'X' case 0x8278: return 0x59; // 'Y' case 0x8279: return 0x5a; // 'Z' case 0x816d: return 0x5b; // '[' case 0x818f: return 0x5c; // '¥' case 0x816e: return 0x5d; // ']' case 0x814f: return 0x5e; // '^' case 0x8151: return 0x5f; // '_' case 0x8165: return 0x60; // '‘' case 0x8281: return 0x61; // 'a' case 0x8282: return 0x62; // 'b' case 0x8283: return 0x63; // 'c' case 0x8284: return 0x64; // 'd' case 0x8285: return 0x65; // 'e' case 0x8286: return 0x66; // 'f' case 0x8287: return 0x67; // 'g' case 0x8288: return 0x68; // 'h' case 0x8289: return 0x69; // 'i' case 0x828a: return 0x6a; // 'j' case 0x828b: return 0x6b; // 'k' case 0x828c: return 0x6c; // 'l' case 0x828d: return 0x6d; // 'm' case 0x828e: return 0x6e; // 'n' case 0x828f: return 0x6f; // 'o' case 0x8290: return 0x70; // 'p' case 0x8291: return 0x71; // 'q' case 0x8292: return 0x72; // 'r' case 0x8293: return 0x73; // 's' case 0x8294: return 0x74; // 't' case 0x8295: return 0x75; // 'u' case 0x8296: return 0x76; // 'v' case 0x8297: return 0x77; // 'w' case 0x8298: return 0x78; // 'x' case 0x8299: return 0x79; // 'y' case 0x829a: return 0x7a; // 'z' case 0x816f: return 0x7b; // '{' case 0x8162: return 0x7c; // '|' case 0x8170: return 0x7d; // '}' case 0x8160: return 0x7e; // '〜' case 0x8142: return 0xa1; // '。' case 0x8175: return 0xa2; // '「' case 0x8176: return 0xa3; // '」' case 0x8141: return 0xa4; // '、' case 0x8145: return 0xa5; // '・' case 0x82f0: return 0xa6; // 'を' case 0x829f: return 0xa7; // 'ぁ' case 0x82a1: return 0xa8; // 'ぃ' case 0x82a3: return 0xa9; // 'ぅ' case 0x82a5: return 0xaa; // 'ぇ' case 0x82a7: return 0xab; // 'ぉ' case 0x82e1: return 0xac; // 'ゃ' case 0x82e3: return 0xad; // 'ゅ' case 0x82e5: return 0xae; // 'ょ' case 0x82c1: return 0xaf; // 'っ' case 0x815b: return 0xb0; // 'ー' case 0x82a0: return 0xb1; // 'あ' case 0x82a2: return 0xb2; // 'い' case 0x82a4: return 0xb3; // 'う' case 0x82a6: return 0xb4; // 'え' case 0x82a8: return 0xb5; // 'お' case 0x82a9: return 0xb6; // 'か' case 0x82ab: return 0xb7; // 'き' case 0x82ad: return 0xb8; // 'く' case 0x82af: return 0xb9; // 'け' case 0x82b1: return 0xba; // 'こ' case 0x82b3: return 0xbb; // 'さ' case 0x82b5: return 0xbc; // 'し' case 0x82b7: return 0xbd; // 'す' case 0x82b9: return 0xbe; // 'せ' case 0x82bb: return 0xbf; // 'そ' case 0x82bd: return 0xc0; // 'た' case 0x82bf: return 0xc1; // 'ち' case 0x82c2: return 0xc2; // 'つ' case 0x82c4: return 0xc3; // 'て' case 0x82c6: return 0xc4; // 'と' case 0x82c8: return 0xc5; // 'な' case 0x82c9: return 0xc6; // 'に' case 0x82ca: return 0xc7; // 'ぬ' case 0x82cb: return 0xc8; // 'ね' case 0x82cc: return 0xc9; // 'の' case 0x82cd: return 0xca; // 'は' case 0x82d0: return 0xcb; // 'ひ' case 0x82d3: return 0xcc; // 'ふ' case 0x82d6: return 0xcd; // 'へ' case 0x82d9: return 0xce; // 'ほ' case 0x82dc: return 0xcf; // 'ま' case 0x82dd: return 0xd0; // 'み' case 0x82de: return 0xd1; // 'む' case 0x82df: return 0xd2; // 'め' case 0x82e0: return 0xd3; // 'も' case 0x82e2: return 0xd4; // 'や' case 0x82e4: return 0xd5; // 'ゆ' case 0x82e6: return 0xd6; // 'よ' case 0x82e7: return 0xd7; // 'ら' case 0x82e8: return 0xd8; // 'り' case 0x82e9: return 0xd9; // 'る' case 0x82ea: return 0xda; // 'れ' case 0x82eb: return 0xdb; // 'ろ' case 0x82ed: return 0xdc; // 'わ' case 0x82f1: return 0xdd; // 'ん' case 0x814a: return 0xde; // '゛' case 0x814b: return 0xdf; // '゜' } return code; } extern "C" { void ags_setAntialiasedStringMode(int on) { antialias = on != 0; } #ifdef __EMSCRIPTEN__ char* sjis2utf(char* str) { unsigned char* src = (unsigned char*)str; unsigned char* dst = (unsigned char*)malloc(strlen(str) * 3 + 1); unsigned char* dstp = dst; while (*src) { if (*src <= 0x7f) { *dstp++ = *src++; continue; } int c; if (*src >= 0xa0 && *src <= 0xdf) { c = 0xff60 + *src - 0xa0; src++; } else { c = s2u[*src - 0x80][*(src+1) - 0x40]; src += 2; } if (c <= 0x7f) { *dstp++ = c; } else if (c <= 0x7ff) { *dstp++ = 0xc0 | c >> 6; *dstp++ = 0x80 | (c & 0x3f); } else { *dstp++ = 0xe0 | c >> 12; *dstp++ = 0x80 | (c >> 6 & 0x3f); *dstp++ = 0x80 | (c & 0x3f); } } *dstp = '\0'; return (char*)dst; } static int unicode_to_sjis(int u) { for (int b1 = 0x80; b1 <= 0xff; b1++) { if (b1 >= 0xa0 && b1 <= 0xdf) continue; for (int b2 = 0x40; b2 <= 0xff; b2++) { if (u == s2u[b1 - 0x80][b2 - 0x40]) return b1 << 8 | b2; } } return 0; } char* utf2sjis(char* str) { unsigned char* src = (unsigned char*)str; unsigned char* dst = (unsigned char*)malloc(strlen(str) + 1); unsigned char* dstp = dst; while (*src) { if (*src <= 0x7f) { *dstp++ = *src++; continue; } int u; if (*src <= 0xdf) { u = (src[0] & 0x1f) << 6 | (src[1] & 0x3f); src += 2; } else if (*src <= 0xef) { u = (src[0] & 0xf) << 12 | (src[1] & 0x3f) << 6 | (src[2] & 0x3f); src += 3; } else { *dstp++ = '?'; do src++; while ((*src & 0xc0) == 0x80); continue; } if (u > 0xff60 && u <= 0xff9f) { *dstp++ = u - 0xff60 + 0xa0; } else { int c = unicode_to_sjis(u); if (c) { *dstp++ = c >> 8; *dstp++ = c & 0xff; } else { *dstp++ = '?'; } } } *dstp = '\0'; return (char*)dst; } #endif }