From e21bea62cefcda4edf845c152b870a253d978b4d Mon Sep 17 00:00:00 2001 From: IntelOrca Date: Sun, 26 Jul 2015 13:58:53 +0100 Subject: [PATCH] implement utf8, part 2 --- projects/language/language.vcxproj | 1 + projects/language/language.vcxproj.filters | 3 + src/drawing/string.c | 227 ++++++++++++++++----- src/localisation/language.c | 60 +++--- src/localisation/language.h | 1 + 5 files changed, 213 insertions(+), 79 deletions(-) diff --git a/projects/language/language.vcxproj b/projects/language/language.vcxproj index 69620f3659..232d4f6509 100644 --- a/projects/language/language.vcxproj +++ b/projects/language/language.vcxproj @@ -112,6 +112,7 @@ + diff --git a/projects/language/language.vcxproj.filters b/projects/language/language.vcxproj.filters index 0c3b4d393c..6810d604ae 100644 --- a/projects/language/language.vcxproj.filters +++ b/projects/language/language.vcxproj.filters @@ -37,5 +37,8 @@ Resource Files\Language + + Resource Files\Language + \ No newline at end of file diff --git a/src/drawing/string.c b/src/drawing/string.c index 820bd80be1..545c2cbe05 100644 --- a/src/drawing/string.c +++ b/src/drawing/string.c @@ -29,6 +29,8 @@ static void ttf_draw_string(rct_drawpixelinfo *dpi, char *buffer, int colour, in static bool _ttfInitialised = false; static TTF_Font *_ttfFont = NULL; +static int _ttfFontOffsetX = 0; +static int _ttfFontOffsetY = 0; /** * @@ -1267,12 +1269,14 @@ bool ttf_initialise() if (TTF_Init() != 0) return false; - _ttfFont = TTF_OpenFont("C:\\Windows\\Fonts\\tahoma.ttf", 11); + _ttfFont = TTF_OpenFont("C:\\Windows\\Fonts\\msyh.ttc", 11); if (_ttfFont == NULL) { TTF_Quit(); return false; } + _ttfFontOffsetX = 0; + _ttfFontOffsetY = -2; _ttfInitialised = true; } return true; @@ -1290,6 +1294,8 @@ void ttf_dispose() } enum { + TEXT_DRAW_FLAG_OUTLINE = 1 << 1, + TEXT_DRAW_FLAG_TTF = 1 << 30, TEXT_DRAW_FLAG_NO_DRAW = 1 << 31 }; @@ -1297,14 +1303,50 @@ typedef struct { int x; int y; int flags; - uint8 colour; + uint8 palette[8]; + uint16 font_sprite_base; } text_draw_info; -static void ttf_draw_string_raw(rct_drawpixelinfo *dpi, const utf8 *text, text_draw_info *info) +static bool utf8_is_format_code(int codepoint) +{ + if (codepoint < 32) return true; + if (codepoint >= 123 && codepoint <= 155) return true; + return false; +} + +static void ttf_draw_string_raw_sprite(rct_drawpixelinfo *dpi, const utf8 *text, text_draw_info *info) +{ + const utf8 *ch = text; + int codepoint; + + while (!utf8_is_format_code(codepoint = utf8_get_next(ch, &ch))) { + uint32 charOffset = info->font_sprite_base + codepoint - 32; + int charWidth = RCT2_ADDRESS(RCT2_ADDRESS_FONT_CHAR_WIDTH, uint8)[charOffset] & 0xFF; + + if (!(info->flags & TEXT_DRAW_FLAG_NO_DRAW)) { + RCT2_GLOBAL(0x009ABDA4, uint8*) = (uint8*)&info->palette; + RCT2_GLOBAL(0x00EDF81C, uint32) = (IMAGE_TYPE_USE_PALETTE << 28); + gfx_draw_sprite_palette_set(dpi, SPR_CHAR_START + ((IMAGE_TYPE_USE_PALETTE << 28) | charOffset), info->x, info->y, info->palette, NULL); + } + + info->x += charWidth; + }; +} + +static void ttf_draw_string_raw_ttf(rct_drawpixelinfo *dpi, const utf8 *text, text_draw_info *info) { if (!_ttfInitialised && !ttf_initialise()) return; + int fontStyle = TTF_GetFontStyle(_ttfFont); + int newFontStyle = 0; + if (info->flags & TEXT_DRAW_FLAG_OUTLINE) { + newFontStyle |= TTF_STYLE_BOLD; + } + if (fontStyle != newFontStyle) { + TTF_SetFontStyle(_ttfFont, newFontStyle); + } + if (info->flags & TEXT_DRAW_FLAG_NO_DRAW) { int width, height; @@ -1312,7 +1354,7 @@ static void ttf_draw_string_raw(rct_drawpixelinfo *dpi, const utf8 *text, text_d info->x += width; return; } else { - uint8 colour = info->colour; + uint8 colour = info->palette[1]; SDL_Color c = { 0, 0, 0, 255 }; SDL_Surface *surface = TTF_RenderUTF8_Solid(_ttfFont, text, c); if (surface == NULL) @@ -1323,10 +1365,17 @@ static void ttf_draw_string_raw(rct_drawpixelinfo *dpi, const utf8 *text, text_d return; } + int drawX = info->x + _ttfFontOffsetX; + int drawY = info->y + _ttfFontOffsetY; int width = surface->w; int height = surface->h; - int skipX = info->x - dpi->x; - int skipY = info->y - dpi->y; + + int overflowX = (dpi->x + dpi->width) - (drawX + width); + int overflowY = (dpi->y + dpi->height) - (drawY + height); + if (overflowX < 0) width += overflowX; + if (overflowY < 0) height += overflowY; + int skipX = drawX - dpi->x; + int skipY = drawY - dpi->y; info->x += width; uint8 *src = surface->pixels; @@ -1335,11 +1384,14 @@ static void ttf_draw_string_raw(rct_drawpixelinfo *dpi, const utf8 *text, text_d if (skipX < 0) { width += skipX; src += -skipX; + skipX = 0; } if (skipY < 0) { height += skipY; src += (-skipY * surface->pitch); + skipY = 0; } + dst += skipX; dst += skipY * (dpi->width + dpi->pitch); @@ -1360,11 +1412,13 @@ static void ttf_draw_string_raw(rct_drawpixelinfo *dpi, const utf8 *text, text_d } } -static bool utf8_is_format_code(int codepoint) +static void ttf_draw_string_raw(rct_drawpixelinfo *dpi, const utf8 *text, text_draw_info *info) { - if (codepoint < 32) return true; - if (codepoint >= 123 && codepoint <= 155) return true; - return false; + if (info->flags & TEXT_DRAW_FLAG_TTF) { + ttf_draw_string_raw_ttf(dpi, text, info); + } else { + ttf_draw_string_raw_sprite(dpi, text, info); + } } static const utf8 *ttf_process_format_code(rct_drawpixelinfo *dpi, const utf8 *text, text_draw_info *info) @@ -1378,65 +1432,88 @@ static const utf8 *ttf_process_format_code(rct_drawpixelinfo *dpi, const utf8 *t info->x += *nextCh++; break; case FORMAT_ADJUST_PALETTE: + { + uint16 eax = palette_to_g1_offset[*nextCh++]; + rct_g1_element *g1Element = &g1Elements[eax]; + uint32 ebx = g1Element->offset[249] + 256; + if (!(info->flags & TEXT_DRAW_FLAG_OUTLINE)) { + ebx = ebx & 0xFF; + } + info->palette[1] = ebx & 0xFF; + info->palette[2] = (ebx >> 8) & 0xFF; + + // Adjust the text palette + memcpy(info->palette + 3, &(g1Element->offset[247]), 2); + memcpy(info->palette + 5, &(g1Element->offset[250]), 2); + + // Set the palette pointer + RCT2_GLOBAL(0x009ABDA4, uint32) = (uint32)&info->palette; + break; + } case 3: case 4: nextCh++; break; case FORMAT_NEWLINE: + if (info->font_sprite_base <= 224) { info->y += 28; } + else if (info->font_sprite_base <= 448) { info->y += 24; } + else { info->y += 18; } + break; case FORMAT_NEWLINE_SMALLER: break; case FORMAT_TINYFONT: + info->font_sprite_base = 448; break; case FORMAT_BIGFONT: + info->font_sprite_base = 672; break; case FORMAT_MEDIUMFONT: + info->font_sprite_base = 224; break; case FORMAT_SMALLFONT: + info->font_sprite_base = 0; break; case FORMAT_OUTLINE: + info->flags |= TEXT_DRAW_FLAG_OUTLINE; + break; case FORMAT_OUTLINE_OFF: + info->flags &= ~TEXT_DRAW_FLAG_OUTLINE; break; case FORMAT_WINDOW_COLOUR_1: { - uint8 palette[5]; uint16 flags = info->flags; - colour_char_window(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WINDOW_COLOUR_1, uint8) - FORMAT_COLOUR_CODE_START, &flags, palette); - info->colour = palette[1]; + colour_char_window(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WINDOW_COLOUR_1, uint8), &flags, info->palette); break; } case FORMAT_WINDOW_COLOUR_2: { - uint8 palette[5]; uint16 flags = info->flags; - colour_char_window(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WINDOW_COLOUR_2, uint8) - FORMAT_COLOUR_CODE_START, &flags, palette); - info->colour = palette[1]; + colour_char_window(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WINDOW_COLOUR_2, uint8), &flags, info->palette); break; } case FORMAT_WINDOW_COLOUR_3: { - uint8 palette[5]; uint16 flags = info->flags; - colour_char_window(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WINDOW_COLOUR_3, uint8) - FORMAT_COLOUR_CODE_START, &flags, palette); - info->colour = palette[1]; + colour_char_window(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WINDOW_COLOUR_3, uint8), &flags, info->palette); break; } case 0x10: break; case FORMAT_INLINE_SPRITE: - // g1Element = g1Elements[*((uint32*)(nextCh)) & 0x7FFFF]; - // width += g1Element.width; + { nextCh += 4; + uint32 imageId = *((uint32*)(nextCh - 3)); + rct_g1_element *g1Element = &g1Elements[imageId & 0x7FFFF]; + if (!(info->flags & TEXT_DRAW_FLAG_NO_DRAW)) { + gfx_draw_sprite(dpi, imageId, info->x, info->y, 0); + } + info->x += g1Element->width; break; + } default: if (codepoint >= FORMAT_COLOUR_CODE_START && codepoint <= FORMAT_COLOUR_CODE_END) { - if (info->flags == 1) { - - } - - uint8 palette[5]; uint16 flags = info->flags; - colour_char(codepoint - FORMAT_COLOUR_CODE_START, &flags, palette); - info->colour = palette[1]; + colour_char(codepoint - FORMAT_COLOUR_CODE_START, &flags, info->palette); } else if (codepoint <= 0x16) { //case 0x11? FORMAT_NEW_LINE_X_Y nextCh += 2; } else { @@ -1468,24 +1545,86 @@ static const utf8 *ttf_process_glyph_run(rct_drawpixelinfo *dpi, const utf8 *tex } } -static void ttf_draw_string(rct_drawpixelinfo *dpi, char *text, int colour, int x, int y) +static void ttf_process_string(rct_drawpixelinfo *dpi, const utf8 *text, text_draw_info *info) { - text_draw_info info; - info.colour = colour; - info.flags = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16); - info.x = x; - info.y = y; - const utf8 *ch = text; const utf8 *nextCh; int codepoint; while ((codepoint = utf8_get_next(ch, &nextCh)) != 0) { if (utf8_is_format_code(codepoint)) { - ch = ttf_process_format_code(dpi, ch, &info); + ch = ttf_process_format_code(dpi, ch, info); } else { - ch = ttf_process_glyph_run(dpi, ch, &info); + ch = ttf_process_glyph_run(dpi, ch, info); } } +} + +static void ttf_process_initial_colour(int colour, text_draw_info *info) +{ + if (colour != 254 && colour != 255) { + info->flags &= ~(1 | 2 | 4 | 8); + if (info->font_sprite_base < 0) { + info->flags |= 4; + if (info->font_sprite_base != -1) { + info->flags |= 8; + } + info->font_sprite_base = 224; + } + if (colour & (1 << 5)) { + info->flags |= TEXT_DRAW_FLAG_OUTLINE; + } + colour &= ~(1 << 5); + if (!(colour & (1 << 6))) { + if (!(info->flags & 1)) { + uint16 flags = info->flags; + colour_char_window(colour, &flags, (uint8*)&info->palette); + } + } else { + info->flags |= 1; + colour &= 0x1F; + + uint32 eax; + if (info->flags & 4) { + if (info->flags & 8) { + eax = RCT2_ADDRESS(0x0141FC48, uint8)[colour * 8]; + eax = eax << 16; + eax = eax | RCT2_ADDRESS(0x0141FC46, uint8)[colour * 8]; + } else { + eax = RCT2_ADDRESS(0x0141FC49, uint8)[colour * 8]; + eax = eax << 16; + eax = eax | RCT2_ADDRESS(0x0141FC47, uint8)[colour * 8]; + } + } else { + eax = RCT2_ADDRESS(0x0141FC4A, uint8)[colour * 8]; + eax = eax << 16; + eax = eax | RCT2_ADDRESS(0x0141FC48, uint8)[colour * 8]; + } + + // Adjust text palette. Store current colour? ; + info->palette[1] = eax & 0xFF; + info->palette[2] = (eax >> 8) & 0xFF; + info->palette[3] = (eax >> 16) & 0xFF; + info->palette[4] = (eax >> 24) & 0xFF; + RCT2_GLOBAL(0x009ABDA4, uint8*) = (uint8*)&info->palette; + eax = 0; + } + } +} + +static void ttf_draw_string(rct_drawpixelinfo *dpi, char *text, int colour, int x, int y) +{ + text_draw_info info; + info.font_sprite_base = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16); + info.flags = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16); + info.x = x; + info.y = y; + + info.flags |= TEXT_DRAW_FLAG_TTF; + + memset(info.palette, 0, sizeof(info.palette)); + + ttf_process_initial_colour(colour, &info); + ttf_process_string(dpi, text, &info); gLastDrawStringX = info.x; gLastDrawStringY = info.y; @@ -1494,23 +1633,15 @@ static void ttf_draw_string(rct_drawpixelinfo *dpi, char *text, int colour, int static int ttf_get_string_width(const utf8 *text) { text_draw_info info; - info.colour = 0; + info.font_sprite_base = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16); info.flags = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16); info.x = 0; info.y = 0; + info.flags |= TEXT_DRAW_FLAG_TTF; info.flags |= TEXT_DRAW_FLAG_NO_DRAW; - const utf8 *ch = text; - const utf8 *nextCh; - int codepoint; - while ((codepoint = utf8_get_next(ch, &nextCh)) != 0) { - if (utf8_is_format_code(codepoint)) { - ch = ttf_process_format_code(NULL, ch, &info); - } else { - ch = ttf_process_glyph_run(NULL, ch, &info); - } - } + ttf_process_string(NULL, text, &info); return info.x; } diff --git a/src/localisation/language.c b/src/localisation/language.c index 07e468076b..f620661168 100644 --- a/src/localisation/language.c +++ b/src/localisation/language.c @@ -34,33 +34,35 @@ typedef struct { } language_data; const char *language_names[LANGUAGE_COUNT] = { - "", // LANGUAGE_UNDEFINED - "English (UK)", // LANGUAGE_ENGLISH_UK - "English (US)", // LANGUAGE_ENGLISH_US - "Deutsch", // LANGUAGE_GERMAN - "Nederlands", // LANGUAGE_DUTCH - "Fran\u00E7ais", // LANGUAGE_FRENCH - "Magyar", // LANGUAGE_HUNGARIAN - "Polski", // LANGUAGE_POLISH - "Espa\u00F1ol", // LANGUAGE_SPANISH - "Svenska", // LANGUAGE_SWEDISH - "Italiano", // LANGUAGE_ITALIAN - "Portug\u00CAs (BR)"// LANGUAGE_PORTUGUESE_BR + "", // LANGUAGE_UNDEFINED + "English (UK)", // LANGUAGE_ENGLISH_UK + "English (US)", // LANGUAGE_ENGLISH_US + "Deutsch", // LANGUAGE_GERMAN + "Nederlands", // LANGUAGE_DUTCH + "Fran\u00E7ais", // LANGUAGE_FRENCH + "Magyar", // LANGUAGE_HUNGARIAN + "Polski", // LANGUAGE_POLISH + "Espa\u00F1ol", // LANGUAGE_SPANISH + "Svenska", // LANGUAGE_SWEDISH + "Italiano", // LANGUAGE_ITALIAN + "Portug\u00CAs (BR)", // LANGUAGE_PORTUGUESE_BR + "Chinese Traditional" // LANGUAGE_CHINESE_TRADITIONAL }; const char *language_filenames[LANGUAGE_COUNT] = { - "", // LANGUAGE_UNDEFINED - "english_uk", // LANGUAGE_ENGLISH_UK - "english_us", // LANGUAGE_ENGLISH_US - "german", // LANGUAGE_GERMAN - "dutch", // LANGUAGE_DUTCH - "french", // LANGUAGE_FRENCH - "hungarian", // LANGUAGE_HUNGARIAN - "polish", // LANGUAGE_POLISH - "spanish_sp", // LANGUAGE_SPANISH - "swedish", // LANGUAGE_SWEDISH - "italian", // LANGUAGE_ITALIAN - "portuguese_br" // LANGUAGE_PORTUGUESE_BR + "", // LANGUAGE_UNDEFINED + "english_uk", // LANGUAGE_ENGLISH_UK + "english_us", // LANGUAGE_ENGLISH_US + "german", // LANGUAGE_GERMAN + "dutch", // LANGUAGE_DUTCH + "french", // LANGUAGE_FRENCH + "hungarian", // LANGUAGE_HUNGARIAN + "polish", // LANGUAGE_POLISH + "spanish_sp", // LANGUAGE_SPANISH + "swedish", // LANGUAGE_SWEDISH + "italian", // LANGUAGE_ITALIAN + "portuguese_br", // LANGUAGE_PORTUGUESE_BR + "chinese_traditional" // LANGUAGE_CHINESE_TRADITIONAL }; int gCurrentLanguage = LANGUAGE_UNDEFINED; @@ -101,7 +103,7 @@ uint32 utf8_get_next(const utf8 *char_ptr, const utf8 **nextchar_ptr) utf8 *utf8_write_codepoint(utf8 *dst, uint32 codepoint) { if (codepoint <= 0x7F) { - dst[0] = codepoint; + dst[0] = (utf8)codepoint; return dst + 1; } else if (codepoint <= 0x7FF) { dst[0] = 0xC0 | ((codepoint >> 6) & 0x1F); @@ -231,12 +233,8 @@ static int language_open_file(const char *filename, language_data *language) // Handle UTF-8 char *srcNext; - int utf8Char = utf8_get_next(src, &srcNext); + uint32 utf8Char = utf8_get_next(src, &srcNext); i += srcNext - src - 1; - if (utf8Char > 0xFF) - utf8Char = '?'; - else if (utf8Char > 0x7F) - utf8Char &= 0xFF; switch (mode) { case 0: @@ -267,7 +265,7 @@ static int language_open_file(const char *filename, language_data *language) *dst = 0; mode = 0; } else { - *dst++ = utf8Char; + dst = utf8_write_codepoint(dst, utf8Char); } break; case 2: diff --git a/src/localisation/language.h b/src/localisation/language.h index f51c02f8a3..2999ec9d6b 100644 --- a/src/localisation/language.h +++ b/src/localisation/language.h @@ -36,6 +36,7 @@ enum { LANGUAGE_SWEDISH, LANGUAGE_ITALIAN, LANGUAGE_PORTUGUESE_BR, + LANGUAGE_CHINESE_TRADITIONAL, LANGUAGE_COUNT };