From fa87d8e9997809279ba9fd6f78e3e051bdc33648 Mon Sep 17 00:00:00 2001 From: IntelOrca Date: Wed, 29 Jul 2015 14:36:21 +0100 Subject: [PATCH] implement utf8, part 14 --- projects/openrct2.vcxproj | 2 + projects/openrct2.vcxproj.filters | 6 + src/drawing/drawing.h | 2 +- src/drawing/font.c | 94 ++++++++++++++ src/drawing/font.h | 28 ++++ src/drawing/scrolling_text.c | 209 +++++++++++++++++++++++------- src/drawing/string.c | 68 ++-------- src/localisation/language.c | 26 ++++ src/localisation/language.h | 2 + src/localisation/localisation.c | 44 ------- src/localisation/localisation.h | 2 +- src/rct2.c | 2 +- src/windows/banner.c | 32 ++--- src/windows/text_input.c | 2 + 14 files changed, 346 insertions(+), 173 deletions(-) create mode 100644 src/drawing/font.c create mode 100644 src/drawing/font.h diff --git a/projects/openrct2.vcxproj b/projects/openrct2.vcxproj index 495391fc30..3108569a3c 100644 --- a/projects/openrct2.vcxproj +++ b/projects/openrct2.vcxproj @@ -33,6 +33,7 @@ + @@ -195,6 +196,7 @@ + diff --git a/projects/openrct2.vcxproj.filters b/projects/openrct2.vcxproj.filters index 0c74f0bb5e..a714ad89d1 100644 --- a/projects/openrct2.vcxproj.filters +++ b/projects/openrct2.vcxproj.filters @@ -501,6 +501,9 @@ Source\Drawing + + Source\Drawing + @@ -731,5 +734,8 @@ Source + + Source\Drawing + \ No newline at end of file diff --git a/src/drawing/drawing.h b/src/drawing/drawing.h index cf0450d3d2..83f5fa864c 100644 --- a/src/drawing/drawing.h +++ b/src/drawing/drawing.h @@ -22,6 +22,7 @@ #define _DRAWING_H_ #include "../common.h" +#include "font.h" // Size: 0x10 typedef struct { @@ -113,7 +114,6 @@ void gfx_draw_sprite(rct_drawpixelinfo *dpi, int image_id, int x, int y, uint32 void gfx_draw_sprite_palette_set(rct_drawpixelinfo *dpi, int image_id, int x, int y, uint8* palette_pointer, uint8* unknown_pointer); // string -void gfx_load_character_widths(); int clip_text(char *buffer, int width); int gfx_wrap_string(char* buffer, int width, int* num_lines, int* font_height); int gfx_get_string_width(char *buffer); diff --git a/src/drawing/font.c b/src/drawing/font.c new file mode 100644 index 0000000000..39c19f1a5d --- /dev/null +++ b/src/drawing/font.c @@ -0,0 +1,94 @@ +#include "../addresses.h" +#include "../localisation/localisation.h" +#include "../sprites.h" +#include "drawing.h" +#include "font.h" + +static uint8 *_spriteFontCharacterWidths = (uint8*)RCT2_ADDRESS_FONT_CHAR_WIDTH; + +/** + * + * rct2: 0x006C19AC + */ +void font_sprite_initialise_characters() +{ + uint8* pCharacterWidth = _spriteFontCharacterWidths; + for (int fontSize = 0; fontSize < FONT_SIZE_COUNT; fontSize++) { + int glyphOffset = fontSize * FONT_SPRITE_GLYPH_COUNT; + for (uint8 glyphIndex = 0; glyphIndex < FONT_SPRITE_GLYPH_COUNT; glyphIndex++) { + rct_g1_element g1 = g1Elements[glyphIndex + SPR_CHAR_START + glyphOffset]; + + int width = fontSize == FONT_SIZE_BIG ? g1.width + 1 : g1.width - 1; + if (glyphIndex >= (FORMAT_ARGUMENT_CODE_START - 32) && glyphIndex < (FORMAT_COLOUR_CODE_END - 32)) { + width = 0; + } + *pCharacterWidth++ = (uint8)width; + } + } + + scrolling_text_initialise_bitmaps(); + + for (int i = 0; i < 32; i++) { + rct_g1_element* g1 = &g1Elements[0x606 + i]; + uint8* unknown_pointer = RCT2_ADDRESS(0x009C3852, uint8) + 0xA12 * i; + g1->offset = unknown_pointer; + g1->width = 64; + g1->height = 40; + *((uint16*)unknown_pointer) = 0xFFFF; + *((uint32*)(unknown_pointer + 0x0E)) = 0; + } +} + +int font_sprite_get_codepoint_offset(int codepoint) +{ + switch (codepoint) { + case FORMAT_ENDQUOTES: return 34 - 32; + + case FORMAT_AMINUSCULE: return 159 - 32; + case FORMAT_UP: return 160 - 32; + case FORMAT_SYMBOL_i: return 160 - 32; + case FORMAT_CENT: return 162 - 32; + case FORMAT_POUND: return 163 - 32; + + case FORMAT_YEN: return 165 - 32; + + + + case FORMAT_COPYRIGHT: return 169 - 32; + case FORMAT_DOWN: return 170 - 32; + case FORMAT_LEFTGUILLEMET: return 171 - 32; + case FORMAT_TICK: return 172 - 32; + case FORMAT_CROSS: return 173 - 32; + + case FORMAT_RIGHT: return 175 - 32; + case FORMAT_DEGREE: return 176 - 32; + case FORMAT_SYMBOL_RAILWAY: return 177 - 32; + case FORMAT_SQUARED: return 178 - 32; + + case FORMAT_OPENQUOTES: return 180 - 32; + case FORMAT_EURO: return 181 - 32; + case FORMAT_SYMBOL_ROAD: return 182 - 32; + case FORMAT_SYMBOL_FLAG: return 183 - 32; + case FORMAT_APPROX: return 184 - 32; + case FORMAT_POWERNEGATIVEONE: return 185 - 32; + case FORMAT_BULLET: return 186 - 32; + case FORMAT_RIGHTGUILLEMET: return 187 - 32; + case FORMAT_SMALLUP: return 188 - 32; + case FORMAT_SMALLDOWN: return 189 - 32; + case FORMAT_LEFT: return 190 - 32; + case FORMAT_INVERTEDQUESTION: return 191 - 32; + default: + if (codepoint < 32 || codepoint >= 256) codepoint = '?'; + return codepoint - 32; + } +} + +int font_sprite_get_codepoint_width(int fontSpriteBase, int codepoint) +{ + return _spriteFontCharacterWidths[fontSpriteBase + font_sprite_get_codepoint_offset(codepoint)]; +} + +int font_sprite_get_codepoint_sprite(int fontSpriteBase, int codepoint) +{ + return SPR_CHAR_START + ((IMAGE_TYPE_USE_PALETTE << 28) | (fontSpriteBase + font_sprite_get_codepoint_offset(codepoint))); +} diff --git a/src/drawing/font.h b/src/drawing/font.h new file mode 100644 index 0000000000..33fd8345e8 --- /dev/null +++ b/src/drawing/font.h @@ -0,0 +1,28 @@ +#ifndef _DRAWING_FONT_H_ +#define _DRAWING_FONT_H_ + +#include "../common.h" + +enum { + FONT_SIZE_TINY = 2, + FONT_SIZE_SMALL = 0, + FONT_SIZE_MEDIUM = 1, + FONT_SIZE_BIG = 3, + FONT_SIZE_COUNT = 4 +}; + +enum { + FONT_SPRITE_GLYPH_COUNT = 224, + + FONT_SPRITE_BASE_TINY = 448, + FONT_SPRITE_BASE_SMALL = 0, + FONT_SPRITE_BASE_MEDIUM = 224, + FONT_SPRITE_BASE_BIG = 672 +}; + +void font_sprite_initialise_characters(); +int font_sprite_get_codepoint_offset(int codepoint); +int font_sprite_get_codepoint_width(int fontSpriteBase, int codepoint); +int font_sprite_get_codepoint_sprite(int fontSpriteBase, int codepoint); + +#endif \ No newline at end of file diff --git a/src/drawing/scrolling_text.c b/src/drawing/scrolling_text.c index 188defc574..4b421b9e5d 100644 --- a/src/drawing/scrolling_text.c +++ b/src/drawing/scrolling_text.c @@ -1,3 +1,4 @@ +#include #include "../addresses.h" #include "../config.h" #include "../localisation/localisation.h" @@ -15,6 +16,10 @@ typedef struct { } rct_draw_scroll_text; rct_draw_scroll_text *gDrawScrollTextList = RCT2_ADDRESS(RCT2_ADDRESS_DRAW_SCROLL_LIST, rct_draw_scroll_text); +uint8 *gCharacterBitmaps = RCT2_ADDRESS(RCT2_ADDRESS_CHARACTER_BITMAP, uint8); + +void scrolling_text_set_bitmap_for_sprite(utf8 *text, int scroll, uint8 *bitmap, sint16 *scrollPositionOffsets); +void scrolling_text_set_bitmap_for_ttf(utf8 *text, int scroll, uint8 *bitmap, sint16 *scrollPositionOffsets); void scrolling_text_initialise_bitmaps() { @@ -42,27 +47,22 @@ void scrolling_text_initialise_bitmaps() val |= 0x80; } } - RCT2_ADDRESS(RCT2_ADDRESS_CHARACTER_BITMAP, uint8)[i * 8 + x] = val; + gCharacterBitmaps[i * 8 + x] = val; } } } -/** - * - * rct2: 0x006C42D9 - */ -int scrolling_text_setup(rct_string_id stringId, uint16 scroll, uint16 scrollingMode) +static uint8 *font_sprite_get_codepoint_bitmap(int codepoint) { - rct_drawpixelinfo* dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); + return &gCharacterBitmaps[font_sprite_get_codepoint_offset(codepoint) * 8]; +} - if (dpi->zoom_level != 0) return 0x626; - RCT2_GLOBAL(RCT2_ADDRESS_DRAW_SCROLL_NEXT_ID, uint32)++; - - // Find the oldest scroll for use as the newest +static int scrolling_text_get_matching_or_oldest(rct_string_id stringId, uint16 scroll, uint16 scrollingMode) +{ uint32 oldestId = 0xFFFFFFFF; - uint8 scrollIndex = 0xFF; + int scrollIndex = -1; rct_draw_scroll_text* oldestScroll = NULL; for (int i = 0; i < 32; i++) { rct_draw_scroll_text *scrollText = &gDrawScrollTextList[i]; @@ -84,70 +84,103 @@ int scrolling_text_setup(rct_string_id stringId, uint16 scroll, uint16 scrolling return i + 0x606; } } + return scrollIndex; +} + +static uint8 scrolling_text_get_colour(uint32 character) +{ + int edi = character & 0x7F; + int offset = 0; + if (character >= 0x80) offset = 2; + return RCT2_ADDRESS(0x0141FC47, uint8)[offset + (edi * 8)]; +} + +static void scrolling_text_format(utf8 *dst, rct_draw_scroll_text *scrollText) +{ + if (gConfigGeneral.upper_case_banners) { + format_string_to_upper(dst, scrollText->string_id, &scrollText->string_args_0); + } else { + format_string(dst, scrollText->string_id, &scrollText->string_args_0); + } +} + +/** + * + * rct2: 0x006C42D9 + */ +int scrolling_text_setup(rct_string_id stringId, uint16 scroll, uint16 scrollingMode) +{ + rct_drawpixelinfo* dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); + + if (dpi->zoom_level != 0) return 0x626; + + RCT2_GLOBAL(RCT2_ADDRESS_DRAW_SCROLL_NEXT_ID, uint32)++; + + int scrollIndex = scrolling_text_get_matching_or_oldest(stringId, scroll, scrollingMode); + if (scrollIndex >= 0x606) return scrollIndex; // Setup scrolling text - rct_draw_scroll_text* scrollText = oldestScroll; + rct_draw_scroll_text* scrollText = &gDrawScrollTextList[scrollIndex]; scrollText->string_id = stringId; - scrollText->string_args_0 = RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint32); - scrollText->string_args_1 = RCT2_GLOBAL(0x13CE956, uint32); + scrollText->string_args_0 = RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint32); + scrollText->string_args_1 = RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 4, uint32); scrollText->position = scroll; scrollText->mode = scrollingMode; - scrollText->id = RCT2_GLOBAL(RCT2_ADDRESS_DRAW_SCROLL_NEXT_ID, uint32_t); + scrollText->id = RCT2_GLOBAL(RCT2_ADDRESS_DRAW_SCROLL_NEXT_ID, uint32); - uint8* scrollPixelPointer = scrollText->bitmap; - memset(scrollPixelPointer, 0, 320 * 8); + // Create the string to draw + utf8 scrollString[256]; + scrolling_text_format(scrollString, scrollText); - // Convert string id back into a string for processing - utf8 scrollString[MAX_PATH]; - if (gConfigGeneral.upper_case_banners) - format_string_to_upper(scrollString, stringId, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS); - else - format_string(scrollString, stringId, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS); + sint16* scrollingModePositions = RCT2_ADDRESS(RCT2_ADDRESS_SCROLLING_MODE_POSITIONS, uint16*)[scrollingMode]; + + memset(scrollText->bitmap, 0, 320 * 8); + if (gUseTrueTypeFont) { + scrolling_text_set_bitmap_for_ttf(scrollString, scroll, scrollText->bitmap, scrollingModePositions); + } else { + scrolling_text_set_bitmap_for_sprite(scrollString, scroll, scrollText->bitmap, scrollingModePositions); + } - // Setup character colour from ??? - uint32 character = RCT2_GLOBAL(0x13CE959, uint8); - int edi = character & 0x7F; - int offs = 0; - if (character >= 0x80) offs = 2; - uint8 characterColour = RCT2_ADDRESS(0x0141FC47, uint8)[offs + edi * 8]; + return scrollIndex + 0x606; +} - sint16* scrollingModePositions = RCT2_ADDRESS(RCT2_ADDRESS_SCROLLING_MODE_POSITIONS, uint16_t*)[scrollingMode]; - uint8* formatResult = scrollString; +void scrolling_text_set_bitmap_for_sprite(utf8 *text, int scroll, uint8 *bitmap, sint16 *scrollPositionOffsets) +{ + uint8 characterColour = scrolling_text_get_colour(RCT2_GLOBAL(0x013CE959, uint8)); + + utf8 *ch = text; while (true) { - character = utf8_get_next(formatResult, &formatResult); + uint32 codepoint = utf8_get_next(ch, &ch); // If at the end of the string loop back to the start - if (character == 0) { - formatResult = scrollString; + if (codepoint == 0) { + ch = text; continue; } // Set any change in colour - if (character <= FORMAT_COLOUR_CODE_END && character >= FORMAT_COLOUR_CODE_START){ - character -= FORMAT_COLOUR_CODE_START; - characterColour = RCT2_GLOBAL(0x009FF048, uint8*)[character * 4]; + if (codepoint <= FORMAT_COLOUR_CODE_END && codepoint >= FORMAT_COLOUR_CODE_START){ + codepoint -= FORMAT_COLOUR_CODE_START; + characterColour = RCT2_GLOBAL(0x009FF048, uint8*)[codepoint * 4]; continue; } // If another type of control character ignore - if (character < 32) continue; + if (codepoint < 32) continue; - // Convert to an indexable character - character = utf8_get_sprite_offset_for_codepoint(character); - - uint8 characterWidth = RCT2_ADDRESS(RCT2_ADDRESS_FONT_CHAR_WIDTH + 448, uint8)[character]; - uint8* characterBitmap = &(RCT2_ADDRESS(RCT2_ADDRESS_CHARACTER_BITMAP, uint8)[character * 8]); + int characterWidth = font_sprite_get_codepoint_width(FONT_SPRITE_BASE_TINY, codepoint); + uint8 *characterBitmap = font_sprite_get_codepoint_bitmap(codepoint); for (; characterWidth != 0; characterWidth--, characterBitmap++) { // Skip any none displayed columns - if (scroll != 0){ + if (scroll != 0) { scroll--; continue; } - sint16 scrollPosition = *scrollingModePositions; - if (scrollPosition == -1) return scrollIndex + 0x606; + sint16 scrollPosition = *scrollPositionOffsets; + if (scrollPosition == -1) return; if (scrollPosition > -1) { - uint8* dst = &scrollPixelPointer[scrollPosition]; + uint8 *dst = &bitmap[scrollPosition]; for (uint8 char_bitmap = *characterBitmap; char_bitmap != 0; char_bitmap >>= 1){ if (char_bitmap & 1) *dst = characterColour; @@ -155,7 +188,83 @@ int scrolling_text_setup(rct_string_id stringId, uint16 scroll, uint16 scrolling dst += 64; } } - scrollingModePositions++; + scrollPositionOffsets++; } } -} \ No newline at end of file +} + +TTF_Font *ttf_get_font_from_sprite_base(uint16 spriteBase); +SDL_Surface *_ttf_surface_cache_get_or_add(TTF_Font *font, const utf8 *text); + +void scrolling_text_set_bitmap_for_ttf(utf8 *text, int scroll, uint8 *bitmap, sint16 *scrollPositionOffsets) +{ + // Currently only supports one colour + uint8 colour = 0; + + utf8 *dstCh = text; + utf8 *ch = text; + int codepoint; + while ((codepoint = utf8_get_next(ch, &ch)) != 0) { + if (utf8_is_format_code(codepoint)) { + if (colour == 0 && codepoint >= FORMAT_COLOUR_CODE_START && codepoint <= FORMAT_COLOUR_CODE_END) { + colour = (uint8)codepoint; + } + } else { + dstCh = utf8_write_codepoint(dstCh, codepoint); + } + } + *dstCh = 0; + + if (colour == 0) { + colour = scrolling_text_get_colour(RCT2_GLOBAL(0x013CE959, uint8)); + } else { + colour = RCT2_GLOBAL(0x009FF048, uint8*)[(colour - FORMAT_COLOUR_CODE_START) * 4]; + } + + TTF_Font *font = ttf_get_font_from_sprite_base(FONT_SPRITE_BASE_TINY); + SDL_Surface *surface = _ttf_surface_cache_get_or_add(font, text); + if (surface == NULL) { + return; + } + + if (SDL_MUSTLOCK(surface) && SDL_LockSurface(surface) == -1) { + return; + } + + int pitch = surface->pitch; + int width = surface->w; + int height = surface->h; + uint8 *src = surface->pixels; + + // Offset + height -= 3; + src += 3 * pitch; + height = min(height, 8); + + int x = 0; + while (true) { + // Skip any none displayed columns + if (scroll == 0) { + sint16 scrollPosition = *scrollPositionOffsets; + if (scrollPosition == -1) return; + if (scrollPosition > -1) { + uint8 *dst = &bitmap[scrollPosition]; + + for (int y = 0; y < height; y++) { + if (src[y * pitch + x] != 0) *dst = colour; + + // Jump to next row + dst += 64; + } + } + scrollPositionOffsets++; + } else { + scroll--; + } + + x++; + if (x >= width) x = 0; + } + + if (SDL_MUSTLOCK(surface)) SDL_UnlockSurface(surface); +} diff --git a/src/drawing/string.c b/src/drawing/string.c index e930480be5..2422155d54 100644 --- a/src/drawing/string.c +++ b/src/drawing/string.c @@ -29,10 +29,10 @@ static void ttf_draw_string(rct_drawpixelinfo *dpi, char *buffer, int colour, in static bool _ttfInitialised = false; static TTF_Font *_ttfFont[4] = { NULL }; -static int _ttfFontOffsetX = 0; -static int _ttfFontOffsetY = 0; +int _ttfFontOffsetX = 0; +int _ttfFontOffsetY = 0; -static const int TTFFontSizes[] = { 7, 9, 11, 13 }; +static const int TTFFontSizes[] = { 9, 9, 11, 13 }; #define TTF_SURFACE_CACHE_SIZE 256 #define TTF_GETWIDTH_CACHE_SIZE 1024 @@ -61,58 +61,6 @@ static int _ttfGetWidthCacheCount = 0; static int _ttfGetWidthCacheHitCount = 0; static int _ttfGetWidthCacheMissCount = 0; -enum { - FONT_SIZE_TINY = 2, - FONT_SIZE_SMALL = 0, - FONT_SIZE_MEDIUM = 1, - FONT_SIZE_BIG = 3, - FONT_SIZE_COUNT = 4 -}; - -enum { - FONT_SPRITE_GLYPH_COUNT = 224, - - FONT_SPRITE_BASE_TINY = 448, - FONT_SPRITE_BASE_SMALL = 0, - FONT_SPRITE_BASE_MEDIUM = 224, - FONT_SPRITE_BASE_BIG = 672 -}; - -static uint8 *_spriteFontCharacterWidths = (uint8*)RCT2_ADDRESS_FONT_CHAR_WIDTH; - -/** - * - * rct2: 0x006C19AC - */ -void gfx_load_character_widths() -{ - uint8* pCharacterWidth = _spriteFontCharacterWidths; - for (int fontSize = 0; fontSize < FONT_SIZE_COUNT; fontSize++) { - int glyphOffset = fontSize * FONT_SPRITE_GLYPH_COUNT; - for (uint8 glyphIndex = 0; glyphIndex < FONT_SPRITE_GLYPH_COUNT; glyphIndex++) { - rct_g1_element g1 = g1Elements[glyphIndex + SPR_CHAR_START + glyphOffset]; - - int width = fontSize == FONT_SIZE_BIG ? g1.width + 1 : g1.width - 1; - if (glyphIndex >= (FORMAT_ARGUMENT_CODE_START - 32) && glyphIndex < (FORMAT_COLOUR_CODE_END - 32)) { - width = 0; - } - *pCharacterWidth++ = (uint8)width; - } - } - - scrolling_text_initialise_bitmaps(); - - for (int i = 0; i < 32; i++) { - rct_g1_element* g1 = &g1Elements[0x606 + i]; - uint8* unknown_pointer = RCT2_ADDRESS(0x009C3852, uint8) + 0xA12 * i; - g1->offset = unknown_pointer; - g1->width = 64; - g1->height = 40; - *((uint16*)unknown_pointer) = 0xFFFF; - *((uint32*)(unknown_pointer + 0x0E)) = 0; - } -} - /** * * rct2: 0x006C23B1 @@ -802,7 +750,7 @@ static void _ttf_surface_cache_dispose_all() } } -static SDL_Surface *_ttf_surface_cache_get_or_add(TTF_Font *font, const utf8 *text) +SDL_Surface *_ttf_surface_cache_get_or_add(TTF_Font *font, const utf8 *text) { ttf_cache_entry *entry; @@ -987,16 +935,16 @@ typedef struct { static void ttf_draw_character_sprite(rct_drawpixelinfo *dpi, int codepoint, text_draw_info *info) { - uint32 charOffset = info->font_sprite_base + utf8_get_sprite_offset_for_codepoint(codepoint); - int charWidth = _spriteFontCharacterWidths[charOffset] & 0xFF; + int characterWidth = font_sprite_get_codepoint_width(info->font_sprite_base, codepoint); + int sprite = font_sprite_get_codepoint_sprite(info->font_sprite_base, codepoint); 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); + gfx_draw_sprite_palette_set(dpi, sprite, info->x, info->y, info->palette, NULL); } - info->x += charWidth; + info->x += characterWidth; } static void ttf_draw_string_raw_sprite(rct_drawpixelinfo *dpi, const utf8 *text, text_draw_info *info) diff --git a/src/localisation/language.c b/src/localisation/language.c index 12ed327753..022c93ee18 100644 --- a/src/localisation/language.c +++ b/src/localisation/language.c @@ -144,6 +144,32 @@ bool utf8_is_codepoint_start(utf8 *text) return false; } +void utf8_remove_format_codes(utf8 *text) +{ + utf8 *dstCh = text; + utf8 *ch = text; + int codepoint; + while ((codepoint = utf8_get_next(ch, &ch)) != 0) { + if (!utf8_is_format_code(codepoint)) { + dstCh = utf8_write_codepoint(dstCh, codepoint); + } + } + *dstCh = 0; +} + +int utf8_get_codepoint_length(int codepoint) +{ + if (codepoint <= 0x7F) { + return 1; + } else if (codepoint <= 0x7FF) { + return 2; + } else if (codepoint <= 0xFFFF) { + return 3; + } else { + return 4; + } +} + const char *language_get_string(rct_string_id id) { const char *openrctString = NULL; diff --git a/src/localisation/language.h b/src/localisation/language.h index fbc01b32a3..69358349bd 100644 --- a/src/localisation/language.h +++ b/src/localisation/language.h @@ -73,5 +73,7 @@ rct_string_id object_get_localised_text(uint8_t** pStringTable/*ebp*/, int type/ uint32 utf8_get_next(const utf8 *char_ptr, const utf8 **nextchar_ptr); utf8 *utf8_write_codepoint(utf8 *dst, uint32 codepoint); bool utf8_is_codepoint_start(utf8 *text); +void utf8_remove_format_codes(utf8 *text); +int utf8_get_codepoint_length(int codepoint); #endif diff --git a/src/localisation/localisation.c b/src/localisation/localisation.c index 49a11bc1bb..82ea9f0f54 100644 --- a/src/localisation/localisation.c +++ b/src/localisation/localisation.c @@ -154,50 +154,6 @@ bool utf8_should_use_sprite_for_codepoint(int codepoint) } } -int utf8_get_sprite_offset_for_codepoint(int codepoint) -{ - switch (codepoint) { - case FORMAT_ENDQUOTES: return 34 - 32; - - case FORMAT_AMINUSCULE: return 159 - 32; - case FORMAT_UP: return 160 - 32; - case FORMAT_SYMBOL_i: return 160 - 32; - case FORMAT_CENT: return 162 - 32; - case FORMAT_POUND: return 163 - 32; - - case FORMAT_YEN: return 165 - 32; - - - - case FORMAT_COPYRIGHT: return 169 - 32; - case FORMAT_DOWN: return 170 - 32; - case FORMAT_LEFTGUILLEMET: return 171 - 32; - case FORMAT_TICK: return 172 - 32; - case FORMAT_CROSS: return 173 - 32; - - case FORMAT_RIGHT: return 175 - 32; - case FORMAT_DEGREE: return 176 - 32; - case FORMAT_SYMBOL_RAILWAY: return 177 - 32; - case FORMAT_SQUARED: return 178 - 32; - - case FORMAT_OPENQUOTES: return 180 - 32; - case FORMAT_EURO: return 181 - 32; - case FORMAT_SYMBOL_ROAD: return 182 - 32; - case FORMAT_SYMBOL_FLAG: return 183 - 32; - case FORMAT_APPROX: return 184 - 32; - case FORMAT_POWERNEGATIVEONE: return 185 - 32; - case FORMAT_BULLET: return 186 - 32; - case FORMAT_RIGHTGUILLEMET: return 187 - 32; - case FORMAT_SMALLUP: return 188 - 32; - case FORMAT_SMALLDOWN: return 189 - 32; - case FORMAT_LEFT: return 190 - 32; - case FORMAT_INVERTEDQUESTION: return 191 - 32; - default: - if (codepoint < 32 || codepoint >= 256) codepoint = '?'; - return codepoint - 32; - } -} - int utf8_get_format_code_arg_length(int codepoint) { switch (codepoint) { diff --git a/src/localisation/localisation.h b/src/localisation/localisation.h index f2025b44cd..6ffbfcfef8 100644 --- a/src/localisation/localisation.h +++ b/src/localisation/localisation.h @@ -28,7 +28,7 @@ bool utf8_is_format_code(int codepoint); bool utf8_should_use_sprite_for_codepoint(int codepoint); -int utf8_get_sprite_offset_for_codepoint(int codepoint); +int font_sprite_get_codepoint_offset(int codepoint); int utf8_get_format_code_arg_length(int codepoint); void format_string(char *dest, rct_string_id format, void *args); diff --git a/src/rct2.c b/src/rct2.c index 1294860c2b..14c69eef5a 100644 --- a/src/rct2.c +++ b/src/rct2.c @@ -99,7 +99,7 @@ int rct2_init() gfx_load_g1(); gfx_load_g2(); - gfx_load_character_widths(); + font_sprite_initialise_characters(); if (!gOpenRCT2Headless) { platform_init(); audio_init1(); diff --git a/src/windows/banner.c b/src/windows/banner.c index 6116d0ac0c..251d0dd9c8 100644 --- a/src/windows/banner.c +++ b/src/windows/banner.c @@ -263,21 +263,21 @@ static void window_banner_dropdown(rct_window *w, int widgetIndex, int dropdownI banner->text_colour = dropdownIndex + 1; + int colourCodepoint = FORMAT_COLOUR_CODE_START + banner->text_colour; + // Can be replaced with a buffer 34 chars wide ( 32 character + 1 colour_format + 1 '\0') - uint8* text_buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, uint8); + uint8* buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, uint8); + format_string(buffer, banner->string_idx, 0); - format_string(text_buffer, banner->string_idx, 0); - - if (text_buffer[0] < FORMAT_COLOUR_CODE_START - || text_buffer[0] > FORMAT_COLOUR_CODE_END){ - int end_point = strlen(text_buffer) + 1; - strncpy(text_buffer + 1, text_buffer, 32); - text_buffer[end_point] = '\0'; + int firstCodepoint = utf8_get_next(buffer, NULL); + if (!(firstCodepoint >= FORMAT_COLOUR_CODE_START && firstCodepoint <= FORMAT_COLOUR_CODE_END)) { + utf8 *endPoint = get_string_end(buffer) + utf8_get_codepoint_length(colourCodepoint); + memmove(buffer + utf8_get_codepoint_length(colourCodepoint), buffer, endPoint - buffer); + *endPoint = 0; } + utf8_write_codepoint(buffer, colourCodepoint); - text_buffer[0] = banner->text_colour + FORMAT_COLOUR_CODE_START; - - rct_string_id stringId = user_string_allocate(128, text_buffer); + rct_string_id stringId = user_string_allocate(128, buffer); if (stringId != 0) { rct_string_id prev_string_id = banner->string_idx; banner->string_idx = stringId; @@ -296,12 +296,12 @@ static void window_banner_textinput(rct_window *w, int widgetIndex, char *text) if (widgetIndex == WIDX_BANNER_TEXT && text != NULL) { rct_banner* banner = &gBanners[w->number]; - uint8* text_buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, uint8); + utf8 *buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, uint8); + utf8 *dst = buffer; + dst = utf8_write_codepoint(dst, FORMAT_COLOUR_CODE_START + banner->text_colour); + strncpy(dst, text, 32); - text_buffer[0] = banner->text_colour + FORMAT_COLOUR_CODE_START; - strncpy(text_buffer + 1, text, 32); - - rct_string_id stringId = user_string_allocate(128, text_buffer); + rct_string_id stringId = user_string_allocate(128, buffer); if (stringId) { rct_string_id prev_string_id = banner->string_idx; banner->string_idx = stringId; diff --git a/src/windows/text_input.c b/src/windows/text_input.c index 983f563de8..b2df708142 100644 --- a/src/windows/text_input.c +++ b/src/windows/text_input.c @@ -118,6 +118,8 @@ void window_text_input_open(rct_window* call_w, int call_widget, rct_string_id t // from crashing the game. text_input[maxLength - 1] = '\0'; + utf8_remove_format_codes(text_input); + // This is the text displayed above the input box input_text_description = description;