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;