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))