From c4b355f64800db7074d7ddc3899b7dcfa61c19dd Mon Sep 17 00:00:00 2001 From: IntelOrca Date: Sun, 26 Jul 2015 00:55:17 +0100 Subject: [PATCH] implement utf8, part 1 --- projects/libs/libs.vcxproj | 18 +-- projects/openrct2.vcxproj | 6 +- src/drawing/drawing.h | 3 + src/drawing/string.c | 274 +++++++++++++++++++++++++++++++- src/interface/widget.c | 13 +- src/localisation/language.c | 44 ++++- src/localisation/language.h | 3 + src/localisation/localisation.c | 16 +- src/title.c | 10 +- 9 files changed, 354 insertions(+), 33 deletions(-) diff --git a/projects/libs/libs.vcxproj b/projects/libs/libs.vcxproj index bbad0231d7..5a518056a2 100644 --- a/projects/libs/libs.vcxproj +++ b/projects/libs/libs.vcxproj @@ -55,20 +55,20 @@ $(SolutionDir)..\build\$(Configuration)\ $(SolutionDir)..\obj\$(ProjectName)\$(Configuration)\ - ..\..\lib\libcurl\include;..\..\lib\jansson;..\..\lib\cutest\CuTest.h;$(IncludePath) - ..\..\lib\libcurl\lib;$(LibraryPath) + ..\..\lib\libcurl\include;..\..\lib\jansson;..\..\lib\cutest\CuTest.h;..\..\lib\SDL2_ttf\include;$(IncludePath) + ..\..\lib\libcurl\lib;..\..\lib\SDL2_ttf\lib\x86;$(LibraryPath) $(SolutionDir)..\build\$(Configuration)\ $(SolutionDir)..\obj\$(ProjectName)\$(Configuration)\ - ..\..\lib\libcurl\include;..\..\lib\jansson;..\..\lib\cutest\CuTest.h;$(IncludePath) - ..\..\lib\libcurl\lib;$(LibraryPath) + ..\..\lib\libcurl\include;..\..\lib\jansson;..\..\lib\cutest\CuTest.h;..\..\lib\SDL2_ttf\include;$(IncludePath) + ..\..\lib\libcurl\lib;..\..\lib\SDL2_ttf\lib\x86;$(LibraryPath) $(SolutionDir)..\build\Release\ $(SolutionDir)..\obj\$(ProjectName)\Release\ - ..\..\lib\libcurl\include;..\..\lib\jansson;..\..\lib\cutest\CuTest.h;$(IncludePath) - ..\..\lib\libcurl\lib;$(LibraryPath) + ..\..\lib\libcurl\include;..\..\lib\jansson;..\..\lib\cutest\CuTest.h;..\..\lib\SDL2_ttf\include;$(IncludePath) + ..\..\lib\libcurl\lib;..\..\lib\SDL2_ttf\lib\x86;$(LibraryPath) @@ -83,7 +83,7 @@ true - libcurl.lib;Ws2_32.lib;%(AdditionalDependencies) + libcurl.lib;Ws2_32.lib;SDL2_ttf.lib;%(AdditionalDependencies) Powershell -NonInteractive -ExecutionPolicy "ByPass" -File "$(ProjectDir)../../pre-build.ps1" @@ -108,7 +108,7 @@ true - libcurl.lib;Ws2_32.lib;%(AdditionalDependencies) + libcurl.lib;Ws2_32.lib;SDL2_ttf.lib;%(AdditionalDependencies) Powershell -NonInteractive -ExecutionPolicy "ByPass" -File "$(ProjectDir)../../pre-build.ps1" @@ -133,7 +133,7 @@ true - libcurl.lib;Ws2_32.lib;%(AdditionalDependencies) + libcurl.lib;Ws2_32.lib;SDL2_ttf.lib;%(AdditionalDependencies) Powershell -NonInteractive -ExecutionPolicy "ByPass" -File "$(ProjectDir)../../pre-build.ps1" diff --git a/projects/openrct2.vcxproj b/projects/openrct2.vcxproj index 645c2c5455..ebf89bf5f7 100644 --- a/projects/openrct2.vcxproj +++ b/projects/openrct2.vcxproj @@ -310,13 +310,13 @@ - $(SolutionDir)..\lib;$(SolutionDir)..\lib\libspeex;$(SolutionDir)..\lib\sdl\include;$(SolutionDir)..\lib\libcurl\include;$(SolutionDir)..\lib\jansson;$(SolutionDir)..\lib\cutest;$(IncludePath) + $(SolutionDir)..\lib;$(SolutionDir)..\lib\libspeex;$(SolutionDir)..\lib\sdl\include;$(SolutionDir)..\lib\libcurl\include;$(SolutionDir)..\lib\jansson;$(SolutionDir)..\lib\cutest;$(SolutionDir)..\lib\SDL2_ttf\include;$(IncludePath) $(SolutionDir)..\lib\sdl\lib\x86;$(SolutionDir)..\lib\libcurl\lib;$(LibraryPath) $(SolutionDir)..\build\$(Configuration)\ $(SolutionDir)..\obj\$(ProjectName)\$(Configuration)\ - $(SolutionDir)..\lib;$(SolutionDir)..\lib\libspeex;$(SolutionDir)..\lib\sdl\include;$(SolutionDir)..\lib\libcurl\include;$(SolutionDir)..\lib\jansson;$(SolutionDir)..\lib\cutest;$(IncludePath) + $(SolutionDir)..\lib;$(SolutionDir)..\lib\libspeex;$(SolutionDir)..\lib\sdl\include;$(SolutionDir)..\lib\libcurl\include;$(SolutionDir)..\lib\jansson;$(SolutionDir)..\lib\cutest;$(SolutionDir)..\lib\SDL2_ttf\include;$(IncludePath) $(SolutionDir)..\lib\sdl\lib\x86;$(SolutionDir)..\lib\libcurl\lib;$(LibraryPath) $(SolutionDir)..\build\$(Configuration)\ $(SolutionDir)..\obj\$(ProjectName)\$(Configuration)\ @@ -324,7 +324,7 @@ - $(SolutionDir)..\lib;$(SolutionDir)..\lib\libspeex;$(SolutionDir)..\lib\sdl\include;$(SolutionDir)..\lib\libcurl\include;$(SolutionDir)..\lib\jansson;$(SolutionDir)..\lib\cutest;$(IncludePath) + $(SolutionDir)..\lib;$(SolutionDir)..\lib\libspeex;$(SolutionDir)..\lib\sdl\include;$(SolutionDir)..\lib\libcurl\include;$(SolutionDir)..\lib\jansson;$(SolutionDir)..\lib\cutest;$(SolutionDir)..\lib\SDL2_ttf\include;$(IncludePath) $(SolutionDir)..\lib\sdl\lib\x86;$(SolutionDir)..\lib\libcurl\lib;$(LibraryPath) $(SolutionDir)..\build\Release\ $(SolutionDir)..\obj\$(ProjectName)\Release\ diff --git a/src/drawing/drawing.h b/src/drawing/drawing.h index 6da2217523..9ed88c96f1 100644 --- a/src/drawing/drawing.h +++ b/src/drawing/drawing.h @@ -134,6 +134,9 @@ void draw_string_right_underline(rct_drawpixelinfo *dpi, int format, void *args, int string_get_height_raw(char *buffer); void sub_6C1F57(rct_drawpixelinfo *dpi, int x, int y, int width, int colour, rct_string_id format, void *args, int ticks); +bool ttf_initialise(); +void ttf_dispose(); + // rain void update_rain_animation(); void redraw_rain(); diff --git a/src/drawing/string.c b/src/drawing/string.c index ebf4c47f23..820bd80be1 100644 --- a/src/drawing/string.c +++ b/src/drawing/string.c @@ -18,11 +18,18 @@ * along with this program. If not, see . *****************************************************************************/ +#include #include "../addresses.h" #include "../localisation/localisation.h" #include "../sprites.h" #include "drawing.h" +static int ttf_get_string_width(const utf8 *text); +static void ttf_draw_string(rct_drawpixelinfo *dpi, char *buffer, int colour, int x, int y); + +static bool _ttfInitialised = false; +static TTF_Font *_ttfFont = NULL; + /** * * rct2: 0x006C19AC @@ -166,6 +173,10 @@ int gfx_get_string_width_new_lined(char* buffer){ */ int gfx_get_string_width(char* buffer) { + if (_ttfInitialised) { + return ttf_get_string_width(buffer); + } + // Current font sprites uint16* current_font_sprite_base; // Width of string @@ -766,7 +777,6 @@ void colour_char_window(uint8 colour, uint16* current_font_flags,uint8* palette_ RCT2_GLOBAL(0x009ABDA4, uint32) = (uint32)palette_pointer; } - /** * * rct2: 0x00682702 @@ -778,6 +788,10 @@ void colour_char_window(uint8 colour, uint16* current_font_flags,uint8* palette_ */ void gfx_draw_string(rct_drawpixelinfo *dpi, char *buffer, int colour, int x, int y) { + if (_ttfInitialised) { + ttf_draw_string(dpi, buffer, colour, x, y); + return; + } int eax, ebx, ebp; rct_g1_element* g1_element; @@ -1057,7 +1071,7 @@ void gfx_draw_string(rct_drawpixelinfo *dpi, char *buffer, int colour, int x, in uint32 char_offset = al - 0x20 + *current_font_sprite_base; RCT2_GLOBAL(0x00EDF81C, uint32) = (IMAGE_TYPE_USE_PALETTE << 28); - + gfx_draw_sprite_palette_set(dpi, ((IMAGE_TYPE_USE_PALETTE << 28) | char_offset) + SPR_CHAR_START, max_x, max_y, palette_pointer, NULL); max_x += (RCT2_ADDRESS(RCT2_ADDRESS_FONT_CHAR_WIDTH, uint8)[char_offset] & 0xFF); continue; @@ -1245,4 +1259,258 @@ void sub_6C1F57(rct_drawpixelinfo *dpi, int x, int y, int width, int colour, rct (int)dpi, (width & 0xFFFF) | (ticks << 16) ); -} \ No newline at end of file +} + +bool ttf_initialise() +{ + if (!_ttfInitialised) { + if (TTF_Init() != 0) + return false; + + _ttfFont = TTF_OpenFont("C:\\Windows\\Fonts\\tahoma.ttf", 11); + if (_ttfFont == NULL) { + TTF_Quit(); + return false; + } + + _ttfInitialised = true; + } + return true; +} + +void ttf_dispose() +{ + if (!_ttfInitialised) + return; + + if (_ttfFont != NULL) + TTF_CloseFont(_ttfFont); + + TTF_Quit(); +} + +enum { + TEXT_DRAW_FLAG_NO_DRAW = 1 << 31 +}; + +typedef struct { + int x; + int y; + int flags; + uint8 colour; +} text_draw_info; + +static void ttf_draw_string_raw(rct_drawpixelinfo *dpi, const utf8 *text, text_draw_info *info) +{ + if (!_ttfInitialised && !ttf_initialise()) + return; + + if (info->flags & TEXT_DRAW_FLAG_NO_DRAW) { + int width, height; + + TTF_SizeUTF8(_ttfFont, text, &width, &height); + info->x += width; + return; + } else { + uint8 colour = info->colour; + SDL_Color c = { 0, 0, 0, 255 }; + SDL_Surface *surface = TTF_RenderUTF8_Solid(_ttfFont, text, c); + if (surface == NULL) + return; + + if (SDL_LockSurface(surface) != 0) { + SDL_FreeSurface(surface); + return; + } + + int width = surface->w; + int height = surface->h; + int skipX = info->x - dpi->x; + int skipY = info->y - dpi->y; + info->x += width; + + uint8 *src = surface->pixels; + uint8 *dst = dpi->bits; + + if (skipX < 0) { + width += skipX; + src += -skipX; + } + if (skipY < 0) { + height += skipY; + src += (-skipY * surface->pitch); + } + dst += skipX; + dst += skipY * (dpi->width + dpi->pitch); + + int srcScanSkip = surface->pitch - width; + int dstScanSkip = dpi->width + dpi->pitch - width; + for (int yy = 0; yy < height; yy++) { + for (int xx = 0; xx < width; xx++) { + if (*src != 0) *dst = colour; + src++; + dst++; + } + src += srcScanSkip; + dst += dstScanSkip; + } + SDL_UnlockSurface(surface); + + SDL_FreeSurface(surface); + } +} + +static bool utf8_is_format_code(int codepoint) +{ + if (codepoint < 32) return true; + if (codepoint >= 123 && codepoint <= 155) return true; + return false; +} + +static const utf8 *ttf_process_format_code(rct_drawpixelinfo *dpi, const utf8 *text, text_draw_info *info) +{ + const utf8 *nextCh; + int codepoint; + + codepoint = utf8_get_next(text, &nextCh); + switch (codepoint) { + case FORMAT_MOVE_X: + info->x += *nextCh++; + break; + case FORMAT_ADJUST_PALETTE: + case 3: + case 4: + nextCh++; + break; + case FORMAT_NEWLINE: + case FORMAT_NEWLINE_SMALLER: + break; + case FORMAT_TINYFONT: + break; + case FORMAT_BIGFONT: + break; + case FORMAT_MEDIUMFONT: + break; + case FORMAT_SMALLFONT: + break; + case FORMAT_OUTLINE: + case FORMAT_OUTLINE_OFF: + 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]; + 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]; + 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]; + break; + } + case 0x10: + break; + case FORMAT_INLINE_SPRITE: + // g1Element = g1Elements[*((uint32*)(nextCh)) & 0x7FFFF]; + // width += g1Element.width; + nextCh += 4; + 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]; + } else if (codepoint <= 0x16) { //case 0x11? FORMAT_NEW_LINE_X_Y + nextCh += 2; + } else { + nextCh += 4;//never happens? + } + break; + } + return nextCh; +} + +static const utf8 *ttf_process_glyph_run(rct_drawpixelinfo *dpi, const utf8 *text, text_draw_info *info) +{ + utf8 buffer[512]; + const utf8 *ch = text; + int codepoint; + + do { + codepoint = utf8_get_next(ch, &ch); + } while (!utf8_is_format_code(codepoint)); + if (codepoint == 0) { + ttf_draw_string_raw(dpi, text, info); + return ch - 1; + } else { + int length = ch - text - 1; + memcpy(buffer, text, length); + buffer[length] = 0; + ttf_draw_string_raw(dpi, buffer, info); + return ch; + } +} + +static void ttf_draw_string(rct_drawpixelinfo *dpi, char *text, int colour, int x, int y) +{ + 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); + } else { + ch = ttf_process_glyph_run(dpi, ch, &info); + } + } + + gLastDrawStringX = info.x; + gLastDrawStringY = info.y; +} + +static int ttf_get_string_width(const utf8 *text) +{ + text_draw_info info; + info.colour = 0; + info.flags = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16); + info.x = 0; + info.y = 0; + + 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); + } + } + + return info.x; +} diff --git a/src/interface/widget.c b/src/interface/widget.c index 02ddf9ad14..9069c4b0af 100644 --- a/src/interface/widget.c +++ b/src/interface/widget.c @@ -848,6 +848,11 @@ static void widget_scroll_draw(rct_drawpixelinfo *dpi, rct_window *w, int widget window_event_scroll_paint_call(w, &scroll_dpi, scrollIndex); } +static utf8 BlackUpArrowString[] = { 0xC2, 0x8E, 0xC2, 0xA0, 0x00 }; +static utf8 BlackDownArrowString[] = { 0xC2, 0x8E, 0xC2, 0xAA, 0x00 }; +static utf8 BlackLeftArrowString[] = { 0xC2, 0x8E, 0xC2, 0xBE, 0x00 }; +static utf8 BlackRightArrowString[] = { 0xC2, 0x8E, 0xC2, 0xAF, 0x00 }; + static void widget_hscrollbar_draw(rct_drawpixelinfo *dpi, rct_scroll *scroll, int l, int t, int r, int b, int colour) { colour &= 0x7F; @@ -861,7 +866,7 @@ static void widget_hscrollbar_draw(rct_drawpixelinfo *dpi, rct_scroll *scroll, i // Left button gfx_fill_rect_inset(dpi, l, t, l + 9, b, colour, (scroll->flags & HSCROLLBAR_LEFT_PRESSED ? 0x20 : 0)); - gfx_draw_string(dpi, (char*)0x009DED6C, 0, l + 1, t); + gfx_draw_string(dpi, BlackLeftArrowString, 0, l + 1, t); // Thumb gfx_fill_rect_inset(dpi, @@ -871,7 +876,7 @@ static void widget_hscrollbar_draw(rct_drawpixelinfo *dpi, rct_scroll *scroll, i // Right button gfx_fill_rect_inset(dpi, r - 9, t, r, b, colour, (scroll->flags & HSCROLLBAR_RIGHT_PRESSED ? 0x20 : 0)); - gfx_draw_string(dpi, (char*)0x009DED6F, 0, r - 6, t); + gfx_draw_string(dpi, BlackRightArrowString, 0, r - 6, t); } static void widget_vscrollbar_draw(rct_drawpixelinfo *dpi, rct_scroll *scroll, int l, int t, int r, int b, int colour) @@ -887,7 +892,7 @@ static void widget_vscrollbar_draw(rct_drawpixelinfo *dpi, rct_scroll *scroll, i // Up button gfx_fill_rect_inset(dpi, l, t, r, t + 9, colour, (scroll->flags & VSCROLLBAR_UP_PRESSED ? 0x20 : 0)); - gfx_draw_string(dpi, (char*)0x009DED66, 0, l + 1, t - 1); + gfx_draw_string(dpi, BlackUpArrowString, 0, l + 1, t - 1); // Thumb gfx_fill_rect_inset(dpi, @@ -897,7 +902,7 @@ static void widget_vscrollbar_draw(rct_drawpixelinfo *dpi, rct_scroll *scroll, i // Down button gfx_fill_rect_inset(dpi, l, b - 9, r, b, colour, (scroll->flags & VSCROLLBAR_DOWN_PRESSED ? 0x20 : 0)); - gfx_draw_string(dpi, (char*)0x009DED69, 0, l + 1, b - 9); + gfx_draw_string(dpi, BlackDownArrowString, 0, l + 1, b - 9); } /** diff --git a/src/localisation/language.c b/src/localisation/language.c index 05c7eae239..07e468076b 100644 --- a/src/localisation/language.c +++ b/src/localisation/language.c @@ -19,10 +19,11 @@ *****************************************************************************/ #include "../addresses.h" +#include "../drawing/drawing.h" #include "../object.h" +#include "../openrct2.h" #include "../util/util.h" #include "localisation.h" -#include "../openrct2.h" typedef struct { int id; @@ -72,7 +73,7 @@ const char **_languageOriginal = (char**)0x009BF2D4; static int language_open_file(const char *filename, language_data *language); static void language_close(language_data *language); -static int utf8_get_next(char *char_ptr, char **nextchar_ptr) +uint32 utf8_get_next(const utf8 *char_ptr, const utf8 **nextchar_ptr) { int result; int numBytes; @@ -80,10 +81,15 @@ static int utf8_get_next(char *char_ptr, char **nextchar_ptr) if (!(char_ptr[0] & 0x80)) { result = char_ptr[0]; numBytes = 1; - } else if (!(char_ptr[0] & 0x20)) { + } else if ((char_ptr[0] & 0xE0) == 0xC0) { result = ((char_ptr[0] & 0x1F) << 6) | (char_ptr[1] & 0x3F); numBytes = 2; + } else if ((char_ptr[0] & 0xF0) == 0xE0) { + result = ((char_ptr[0] & 0x0F) << 12) | ((char_ptr[1] & 0x3F) << 6) | (char_ptr[2] & 0x3F); + numBytes = 3; } else { + // TODO 4 bytes + result = ' '; numBytes = 1; } @@ -92,6 +98,29 @@ static int utf8_get_next(char *char_ptr, char **nextchar_ptr) return result; } +utf8 *utf8_write_codepoint(utf8 *dst, uint32 codepoint) +{ + if (codepoint <= 0x7F) { + dst[0] = codepoint; + return dst + 1; + } else if (codepoint <= 0x7FF) { + dst[0] = 0xC0 | ((codepoint >> 6) & 0x1F); + dst[1] = 0x80 | (codepoint & 0x3F); + return dst + 2; + } else if (codepoint <= 0xFFFF) { + dst[0] = 0xE0 | ((codepoint >> 12) & 0x0F); + dst[1] = 0x80 | ((codepoint >> 6) & 0x3F); + dst[2] = 0x80 | (codepoint & 0x3F); + return dst + 3; + } else { + dst[0] = 0xF0 | ((codepoint >> 18) & 0x07); + dst[1] = 0x80 | ((codepoint >> 12) & 0x3F); + dst[2] = 0x80 | ((codepoint >> 6) & 0x3F); + dst[3] = 0x80 | (codepoint & 0x3F); + return dst + 4; + } +} + const char *language_get_string(rct_string_id id) { const char *openrctString = NULL; @@ -133,6 +162,11 @@ int language_open(int id) if (language_open_file(filename, &_languageCurrent)) { _languageCurrent.id = id; gCurrentLanguage = id; + + if (!ttf_initialise()) { + log_warning("Unable to initialise TrueType fonts."); + } + return 1; } @@ -242,10 +276,10 @@ static int language_open_file(const char *filename, language_data *language) int tokenLength = min(src - token, sizeof(tokenBuffer) - 1); memcpy(tokenBuffer, token, tokenLength); tokenBuffer[tokenLength] = 0; - char code = format_get_code(tokenBuffer); + uint8 code = (uint8)format_get_code(tokenBuffer); if (code == 0) code = atoi(tokenBuffer); - *dst++ = code; + dst = utf8_write_codepoint(dst, code); mode = 1; } break; diff --git a/src/localisation/language.h b/src/localisation/language.h index a8eeb81f5d..f51c02f8a3 100644 --- a/src/localisation/language.h +++ b/src/localisation/language.h @@ -48,4 +48,7 @@ void language_close_all(); rct_string_id object_get_localised_text(uint8_t** pStringTable/*ebp*/, int type/*ecx*/, int index/*ebx*/, int tableindex/*edx*/); +uint32 utf8_get_next(const utf8 *char_ptr, const utf8 **nextchar_ptr); +utf8 *utf8_write_codepoint(utf8 *dst, uint32 codepoint); + #endif diff --git a/src/localisation/localisation.c b/src/localisation/localisation.c index 312c5215f3..4eb6e6e0a0 100644 --- a/src/localisation/localisation.c +++ b/src/localisation/localisation.c @@ -579,11 +579,11 @@ void format_string_code(unsigned char format_code, char **dest, char **args) } } -void format_string_part_from_raw(char **dest, const char *src, char **args) +void format_string_part_from_raw(utf8 **dest, const utf8 *src, char **args) { - unsigned char code; + unsigned int code; while (1) { - code = *src++; + code = utf8_get_next(src, &src); if (code < ' ') { if (code == 0) { *(*dest)++ = code; @@ -609,12 +609,12 @@ void format_string_part_from_raw(char **dest, const char *src, char **args) } else if (code < 142) { format_string_code(code, dest, args); } else { - *(*dest)++ = code; + *dest = utf8_write_codepoint(*dest, code); } } } -void format_string_part(char **dest, rct_string_id format, char **args) +void format_string_part(utf8 **dest, rct_string_id format, char **args) { if (format == (rct_string_id)STR_NONE) { **dest = 0; @@ -654,12 +654,12 @@ void format_string_part(char **dest, rct_string_id format, char **args) * format (ax) * args (ecx) */ -void format_string(char *dest, rct_string_id format, void *args) +void format_string(utf8 *dest, rct_string_id format, void *args) { format_string_part(&dest, format, (char**)&args); } -void format_string_raw(char *dest, char *src, void *args) +void format_string_raw(utf8 *dest, utf8 *src, void *args) { format_string_part_from_raw(&dest, src, (char**)&args); } @@ -671,7 +671,7 @@ void format_string_raw(char *dest, char *src, void *args) * format (ax) * args (ecx) */ -void format_string_to_upper(char *dest, rct_string_id format, void *args) +void format_string_to_upper(utf8 *dest, rct_string_id format, void *args) { format_string(dest, format, args); diff --git a/src/title.c b/src/title.c index 838e8924c7..e875ecfd19 100644 --- a/src/title.c +++ b/src/title.c @@ -436,7 +436,15 @@ void DrawOpenRCT2(int x, int y) gfx_fill_rect_inset(dpi, x, y, x + 128, y + 20, 0x80 | 12, 0x8); // Format text (name and version) - sprintf(buffer, "%c%c%c%s, v%s", FORMAT_MEDIUMFONT, FORMAT_OUTLINE, FORMAT_WHITE, OPENRCT2_NAME, OPENRCT2_VERSION); + char *ch = buffer;; + ch = utf8_write_codepoint(ch, FORMAT_MEDIUMFONT); + ch = utf8_write_codepoint(ch, FORMAT_OUTLINE); + ch = utf8_write_codepoint(ch, FORMAT_WHITE); + strcpy(ch, OPENRCT2_NAME); + strcat(buffer, ", v"); + strcat(buffer, OPENRCT2_VERSION); + + // sprintf(buffer, "%c%c%c%s, v%s", FORMAT_MEDIUMFONT, FORMAT_OUTLINE, FORMAT_WHITE, OPENRCT2_NAME, OPENRCT2_VERSION); if (!str_is_null_or_empty(OPENRCT2_BRANCH)) sprintf(strchr(buffer, 0), "-%s", OPENRCT2_BRANCH); if (!str_is_null_or_empty(OPENRCT2_BUILD_NUMBER))