1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2025-12-23 15:52:55 +01:00

implement utf8, part 3

This commit is contained in:
IntelOrca
2015-07-26 17:50:01 +01:00
parent e21bea62ce
commit 2bb0c6c53f
10 changed files with 329 additions and 581 deletions

View File

@@ -28,17 +28,28 @@ 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;
static TTF_Font *_ttfFont[4] = { NULL };
static int _ttfFontOffsetX = 0;
static int _ttfFontOffsetY = 0;
static const int TTFFontSizes[] = { 7, 9, 11, 13 };
enum {
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* char_width_pointer = RCT2_ADDRESS(RCT2_ADDRESS_FONT_CHAR_WIDTH, uint8);
uint8* char_width_pointer = _spriteFontCharacterWidths;
for (int char_set_offset = 0; char_set_offset < 4*0xE0; char_set_offset+=0xE0){
for (uint8 c = 0; c < 0xE0; c++, char_width_pointer++){
rct_g1_element g1 = g1Elements[c + SPR_CHAR_START + char_set_offset];
@@ -108,7 +119,7 @@ int gfx_get_string_width_new_lined(char* buffer){
for (uint8* curr_char = (uint8*)buffer; *curr_char != (uint8)0; curr_char++) {
if (*curr_char >= 0x20) {
width += RCT2_ADDRESS(RCT2_ADDRESS_FONT_CHAR_WIDTH, uint8)[*current_font_sprite_base + (*curr_char - 0x20)];
width += _spriteFontCharacterWidths[*current_font_sprite_base + (*curr_char - 0x20)];
continue;
}
switch (*curr_char) {
@@ -175,72 +186,7 @@ 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
int width;
rct_g1_element g1_element;
current_font_sprite_base = RCT2_ADDRESS(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16);
width = 0;
for (uint8* curr_char = (uint8*)buffer; *curr_char != (uint8)0; curr_char++) {
if (*curr_char >= 0x20) {
width += RCT2_ADDRESS(RCT2_ADDRESS_FONT_CHAR_WIDTH, uint8)[*current_font_sprite_base + (*curr_char - 0x20)];
continue;
}
switch(*curr_char) {
case FORMAT_MOVE_X:
curr_char++;
width = *curr_char;
break;
case FORMAT_ADJUST_PALETTE:
case 3:
case 4:
curr_char++;
break;
case FORMAT_NEWLINE:
case FORMAT_NEWLINE_SMALLER:
continue;
case FORMAT_TINYFONT:
*current_font_sprite_base = 0x1C0;
break;
case FORMAT_BIGFONT:
*current_font_sprite_base = 0x2A0;
break;
case FORMAT_MEDIUMFONT:
*current_font_sprite_base = 0x0E0;
break;
case FORMAT_SMALLFONT:
*current_font_sprite_base = 0;
break;
case FORMAT_OUTLINE:
case FORMAT_OUTLINE_OFF:
case FORMAT_WINDOW_COLOUR_1:
case FORMAT_WINDOW_COLOUR_2:
case FORMAT_WINDOW_COLOUR_3:
case 0x10:
continue;
case FORMAT_INLINE_SPRITE:
g1_element = g1Elements[*((uint32*)(curr_char + 1)) & 0x7FFFF];
width += g1_element.width;
curr_char += 4;
break;
default:
if (*curr_char <= 0x16) { //case 0x11? FORMAT_NEW_LINE_X_Y
curr_char += 2;
continue;
}
curr_char += 4;//never happens?
break;
}
}
return width;
return ttf_get_string_width(buffer);
}
/**
@@ -250,57 +196,52 @@ int gfx_get_string_width(char* buffer)
* buffer (esi)
* width (edi)
*/
int gfx_clip_string(char* buffer, int width)
int gfx_clip_string(utf8 *text, int width)
{
// Location of font sprites
uint16 current_font_sprite_base;
// Width the string has to fit into
unsigned int max_width;
// Character to change to ellipsis
unsigned char* last_char;
// Width of the string, including ellipsis
unsigned int clipped_width;
rct_g1_element g1_element;
uint16 fontSpriteBase;
int maxWidth;
if (width < 6) {
*buffer = 0;
*text = 0;
return 0;
}
fontSpriteBase = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16);
int dotCharacterWidth = _spriteFontCharacterWidths[fontSpriteBase + ('.' - ' ')];
int elipsisCharacterWidth = dotCharacterWidth * 3;
current_font_sprite_base = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16);
max_width = width - (3 * RCT2_ADDRESS(0x141E9F6, uint8)[current_font_sprite_base]);
maxWidth = width - elipsisCharacterWidth;
clipped_width = 0;
last_char = buffer;
for (unsigned char* curr_char = buffer; *curr_char != (uint8)0; curr_char++) {
if (*curr_char < 0x20) {
switch (*curr_char) {
int clippedWidth = 0;
utf8 *lastCh = text;
utf8 *ch = text;
int codepoint;
while ((codepoint = utf8_get_next(ch, &ch)) != 0) {
if (utf8_is_format_code(codepoint)) {
switch (codepoint) {
case FORMAT_MOVE_X:
curr_char++;
clipped_width = *curr_char;
continue;
clippedWidth = *ch++;
break;
case FORMAT_ADJUST_PALETTE:
case 3:
case 4:
curr_char++;
continue;
ch++;
break;
case FORMAT_NEWLINE:
case FORMAT_NEWLINE_SMALLER:
continue;
break;
case FORMAT_TINYFONT:
current_font_sprite_base = 0x1C0;
break;
case FORMAT_BIGFONT:
current_font_sprite_base = 0x2A0;
break;
case FORMAT_MEDIUMFONT:
current_font_sprite_base = 0x0E0;
fontSpriteBase = 448;
break;
case FORMAT_SMALLFONT:
current_font_sprite_base = 0;
fontSpriteBase = 0;
break;
case FORMAT_MEDIUMFONT:
fontSpriteBase = 224;
break;
case FORMAT_BIGFONT:
fontSpriteBase = 672;
break;
case FORMAT_OUTLINE:
case FORMAT_OUTLINE_OFF:
@@ -308,36 +249,40 @@ int gfx_clip_string(char* buffer, int width)
case FORMAT_WINDOW_COLOUR_2:
case FORMAT_WINDOW_COLOUR_3:
case 0x10:
continue;
break;
case FORMAT_INLINE_SPRITE:
g1_element = g1Elements[*((uint32*)(curr_char + 1)) & 0x7FFFF];
clipped_width += g1_element.width;
curr_char += 4;
continue;
g1_element = g1Elements[*((uint32*)(ch - 1)) & 0x7FFFF];
clippedWidth += g1_element.width;
ch += 4;
break;
default:
if (*curr_char <= 0x16) { //case 0x11? FORMAT_NEW_LINE_X_Y
curr_char += 2;
continue;
if (codepoint >= FORMAT_COLOUR_CODE_START || codepoint <= FORMAT_COLOUR_CODE_END) {
break;
}
curr_char += 4;//never happens?
continue;
if (codepoint <= 22) { //case 0x11? FORMAT_NEW_LINE_X_Y
ch += 2;
} else {
ch += 4;//never happens?
}
break;
}
max_width = width - (3 * RCT2_ADDRESS(0x141E9F6, uint8)[current_font_sprite_base]);
}
clipped_width += RCT2_ADDRESS(RCT2_ADDRESS_FONT_CHAR_WIDTH, uint8)[current_font_sprite_base + (*curr_char - 0x20)];
if ((int)clipped_width > width) {
// *((uint32*)last_char) = '...';
strcpy(last_char-3, "...");
clipped_width = width;
return clipped_width;
}
if (clipped_width <= max_width) {
last_char = curr_char+1;
dotCharacterWidth = _spriteFontCharacterWidths[fontSpriteBase + ('.' - ' ')];
elipsisCharacterWidth = dotCharacterWidth * 3;
maxWidth = width - elipsisCharacterWidth;
} else {
clippedWidth += _spriteFontCharacterWidths[fontSpriteBase + utf8_get_sprite_offset_for_codepoint(codepoint)];
if (clippedWidth > width) {
strcpy(lastCh - 3, "...");
clippedWidth = width;
return clippedWidth;
}
if (clippedWidth <= maxWidth) {
lastCh = ch + 1;
}
}
}
return clipped_width;
return clippedWidth;
}
@@ -423,7 +368,7 @@ int gfx_wrap_string(char* buffer, int width, int* num_lines, int* font_height)
}
}
line_width += RCT2_ADDRESS(RCT2_ADDRESS_FONT_CHAR_WIDTH, uint8)[*font_height + (*curr_char - 0x20)];
line_width += _spriteFontCharacterWidths[*font_height + (*curr_char - 0x20)];
if ((int)line_width <= width) {
continue;
@@ -790,298 +735,7 @@ 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;
// Maximum length/height of string
int max_x = x;
int max_y = y;
//
uint16 *current_font_flags = RCT2_ADDRESS(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16);
sint16 *current_font_sprite_base = RCT2_ADDRESS(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, sint16);
uint8* palette_pointer = text_palette;
// Flag for skipping non-printing characters
int skip_char = 0;
if (colour != 0xFE) {
if (x >= dpi->x + dpi->width)
return;
if (x + 0x280 <= dpi->x)
return;
if (y >= dpi->y + dpi->height)
return;
if (y + 0x5A <= dpi->y) {
return;
}
if (colour != 0xFF) {
// switch_colour:
*current_font_flags = 0;
if (*current_font_sprite_base < 0) {
*current_font_flags |= 4;
if (*current_font_sprite_base != -1) {
*current_font_flags |= 8;
}
*current_font_sprite_base = 224;
}
if (colour & (1 << 5)) {
*current_font_flags |= 2;
}
colour &= ~(1 << 5);
if (!(colour & 0x40)) {
ebp = colour;
if (*current_font_flags & 1) {
if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) {
skip_char = 1;
} else {
skip_char = 0;
}
} else {
colour_char_window(ebp, current_font_flags, palette_pointer);
}
} else {
*current_font_flags |= 1;
colour &= 0x1F;
if (*current_font_flags & 4) {
if (*current_font_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? ;
palette_pointer[1] = eax & 0xFF;
palette_pointer[2] = (eax >> 8) & 0xFF;
palette_pointer[3] = (eax >> 16) & 0xFF;
palette_pointer[4] = (eax >> 24) & 0xFF;
RCT2_GLOBAL(0x009ABDA4, uint32) = (uint32)palette_pointer;
eax = 0;
}
}
}
if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) {
skip_char = 1;
}
for (uint8 al = *buffer; al > 0; ++buffer, al = *buffer) {
// Skip to the next printing character
if (skip_char) {
if (al < 0x20) {
// Control codes
skip_char = 0;
} else if (al >= FORMAT_COLOUR_CODE_START && al <= FORMAT_COLOUR_CODE_END) {
// Colour codes
if (*current_font_flags == 1) {
if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) {
skip_char = 1;
} else {
skip_char = 0;
}
continue;
}
colour_char(al - FORMAT_COLOUR_CODE_START, current_font_flags, palette_pointer);
continue;
} else {
continue;
}
}
// Control codes
switch (al) {
case FORMAT_MOVE_X://Start New Line at start+buffer x, same y. (Overwrite?)
max_x = x + (uint8)*++buffer;
break;
case FORMAT_ADJUST_PALETTE:
al = *++buffer;
if (*current_font_flags & 1) {
if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) {
skip_char = 1;
break;
}
}
eax = palette_to_g1_offset[al]; //RCT2_ADDRESS(0x097FCBC, uint32)[al * 4];
g1_element = &g1Elements[eax];
ebx = g1_element->offset[0xF9] + (1 << 8);
if (!(*current_font_flags & 2)) {
ebx = ebx & 0xFF;
}
palette_pointer[1] = ebx & 0xff;
palette_pointer[2] = (ebx >> 8) & 0xff;
//Adjust the text palette
memcpy(palette_pointer + 3, &(g1_element->offset[0xF7]), 2);
memcpy(palette_pointer + 5, &(g1_element->offset[0xFA]), 2);
//Set the palette pointer
RCT2_GLOBAL(0x009ABDA4, uint32) = (uint32)palette_pointer;
if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) {
skip_char = 1;
}
break;
case FORMAT_NEWLINE://Start New Line at set y lower
max_x = x;
if (*current_font_sprite_base <= 224) {
max_y += 10;
break;
}
else if (*current_font_sprite_base == 448) {
max_y += 6;
break;
}
max_y += 18;
break;
case FORMAT_NEWLINE_SMALLER://Start New Line at set y lower
max_x = x;
if (*current_font_sprite_base <= 224) {
max_y += 5;
break;
}
else if (*current_font_sprite_base == 448) {
max_y += 3;
break;
}
max_y += 9;
break;
case FORMAT_TINYFONT:
*current_font_sprite_base = 448;
break;
case FORMAT_BIGFONT:
*current_font_sprite_base = 672;
break;
case FORMAT_MEDIUMFONT:
*current_font_sprite_base = 224;
break;
case FORMAT_SMALLFONT:
*current_font_sprite_base = 0;
break;
case FORMAT_OUTLINE:
*current_font_flags |= 2;
break;
case FORMAT_OUTLINE_OFF:
*current_font_flags &= 0x0FFFD;
break;
case FORMAT_WINDOW_COLOUR_1:
ebp = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WINDOW_COLOUR_1, uint8);
if (*current_font_flags & 1) {
if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) {
skip_char = 1;
}
else {
skip_char = 0;
}
break;
}
colour_char_window(ebp, current_font_flags, palette_pointer);
break;
case FORMAT_WINDOW_COLOUR_2:
ebp = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WINDOW_COLOUR_2, uint8);
if (*current_font_flags & 1) {
if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) {
skip_char = 1;
}
else {
skip_char = 0;
}
break;
}
colour_char_window(ebp, current_font_flags, palette_pointer);
break;
case FORMAT_WINDOW_COLOUR_3:
ebp = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WINDOW_COLOUR_3, uint8);
if (*current_font_flags & 1) {
if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) {
skip_char = 1;
}
else {
skip_char = 0;
}
break;
}
colour_char_window(ebp, current_font_flags, palette_pointer);
break;
case FORMAT_NEWLINE_X_Y: //Start new line at specified x,y
max_x = x + *++buffer;
max_y = y + *++buffer;
break;
case FORMAT_INLINE_SPRITE:
buffer += 4;
if (max_x >= dpi->x + dpi->width) {
skip_char = 1;
break;
}
uint32 image_id = *((uint32*)(buffer - 3));
uint32 image_offset = image_id & 0x7FFFF;
g1_element = &g1Elements[image_offset];
gfx_draw_sprite(dpi, image_id, max_x, max_y, 0);
max_x = max_x + g1_element->width;
break;
default:
// Colour codes
if ((al >= FORMAT_COLOUR_CODE_START) && (al <= FORMAT_COLOUR_CODE_END)){
if (*current_font_flags == 1) {
if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) {
skip_char = 1;
} else {
skip_char = 0;
}
continue;
}
colour_char(al - FORMAT_COLOUR_CODE_START, current_font_flags, palette_pointer);
continue;
}
// Normal Characters
if (max_x >= dpi->x + dpi->width) {
skip_char = 1;
}
if (max_x + 0x1A < dpi->x) {
ebx = al-0x20;
ebx += *current_font_sprite_base;
max_x = max_x + (RCT2_ADDRESS(RCT2_ADDRESS_FONT_CHAR_WIDTH, uint8)[ebx] & 0xFF);
continue;
}
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;
}
}
gLastDrawStringX = max_x;
gLastDrawStringY = max_y;
ttf_draw_string(dpi, buffer, colour, x, y);
}
void draw_string_left_underline(rct_drawpixelinfo *dpi, int format, void *args, int colour, int x, int y)
@@ -1269,14 +923,18 @@ bool ttf_initialise()
if (TTF_Init() != 0)
return false;
_ttfFont = TTF_OpenFont("C:\\Windows\\Fonts\\msyh.ttc", 11);
if (_ttfFont == NULL) {
TTF_Quit();
return false;
utf8 fontPath[MAX_PATH] = "C:\\Windows\\Fonts\\";
strcat(fontPath, gTrueTypeFontPath);
for (int i = 0; i < 4; i++) {
_ttfFont[i] = TTF_OpenFont(fontPath, TTFFontSizes[i]);
if (_ttfFont[i] == NULL) {
TTF_Quit();
return false;
}
}
_ttfFontOffsetX = 0;
_ttfFontOffsetY = -2;
_ttfFontOffsetY = -3;
_ttfInitialised = true;
}
return true;
@@ -1287,10 +945,15 @@ void ttf_dispose()
if (!_ttfInitialised)
return;
if (_ttfFont != NULL)
TTF_CloseFont(_ttfFont);
if (_ttfFont != NULL) {
for (int i = 0; i < 4; i++) {
TTF_CloseFont(_ttfFont[i]);
_ttfFont[i] = NULL;
}
}
TTF_Quit();
_ttfInitialised = false;
}
enum {
@@ -1300,6 +963,8 @@ enum {
};
typedef struct {
int startX;
int startY;
int x;
int y;
int flags;
@@ -1307,21 +972,14 @@ typedef struct {
uint16 font_sprite_base;
} text_draw_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;
uint32 charOffset = info->font_sprite_base + utf8_get_sprite_offset_for_codepoint(codepoint);
int charWidth = _spriteFontCharacterWidths[charOffset] & 0xFF;
if (!(info->flags & TEXT_DRAW_FLAG_NO_DRAW)) {
RCT2_GLOBAL(0x009ABDA4, uint8*) = (uint8*)&info->palette;
@@ -1338,25 +996,42 @@ static void ttf_draw_string_raw_ttf(rct_drawpixelinfo *dpi, const utf8 *text, te
if (!_ttfInitialised && !ttf_initialise())
return;
int fontStyle = TTF_GetFontStyle(_ttfFont);
TTF_Font *font;
switch (info->font_sprite_base) {
case FONT_SPRITE_BASE_TINY:
font = _ttfFont[0];
break;
case FONT_SPRITE_BASE_SMALL:
font = _ttfFont[1];
break;
default:
case FONT_SPRITE_BASE_MEDIUM:
font = _ttfFont[2];
break;
case FONT_SPRITE_BASE_BIG:
font = _ttfFont[3];
break;
}
int fontStyle = TTF_GetFontStyle(font);
int newFontStyle = 0;
if (info->flags & TEXT_DRAW_FLAG_OUTLINE) {
newFontStyle |= TTF_STYLE_BOLD;
}
if (fontStyle != newFontStyle) {
TTF_SetFontStyle(_ttfFont, newFontStyle);
TTF_SetFontStyle(font, newFontStyle);
}
if (info->flags & TEXT_DRAW_FLAG_NO_DRAW) {
int width, height;
TTF_SizeUTF8(_ttfFont, text, &width, &height);
TTF_SizeUTF8(font, text, &width, &height);
info->x += width;
return;
} else {
uint8 colour = info->palette[1];
SDL_Color c = { 0, 0, 0, 255 };
SDL_Surface *surface = TTF_RenderUTF8_Solid(_ttfFont, text, c);
SDL_Surface *surface = TTF_RenderUTF8_Solid(font, text, c);
if (surface == NULL)
return;
@@ -1429,7 +1104,7 @@ static const utf8 *ttf_process_format_code(rct_drawpixelinfo *dpi, const utf8 *t
codepoint = utf8_get_next(text, &nextCh);
switch (codepoint) {
case FORMAT_MOVE_X:
info->x += *nextCh++;
info->x = info->startX + *nextCh++;
break;
case FORMAT_ADJUST_PALETTE:
{
@@ -1464,14 +1139,14 @@ static const utf8 *ttf_process_format_code(rct_drawpixelinfo *dpi, const utf8 *t
case FORMAT_TINYFONT:
info->font_sprite_base = 448;
break;
case FORMAT_BIGFONT:
info->font_sprite_base = 672;
case FORMAT_SMALLFONT:
info->font_sprite_base = 0;
break;
case FORMAT_MEDIUMFONT:
info->font_sprite_base = 224;
break;
case FORMAT_SMALLFONT:
info->font_sprite_base = 0;
case FORMAT_BIGFONT:
info->font_sprite_base = 672;
break;
case FORMAT_OUTLINE:
info->flags |= TEXT_DRAW_FLAG_OUTLINE;
@@ -1501,13 +1176,13 @@ static const utf8 *ttf_process_format_code(rct_drawpixelinfo *dpi, const utf8 *t
break;
case FORMAT_INLINE_SPRITE:
{
nextCh += 4;
uint32 imageId = *((uint32*)(nextCh - 3));
uint32 imageId = *((uint32*)(nextCh));
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;
nextCh += 4;
break;
}
default:
@@ -1528,16 +1203,17 @@ static const utf8 *ttf_process_glyph_run(rct_drawpixelinfo *dpi, const utf8 *tex
{
utf8 buffer[512];
const utf8 *ch = text;
const utf8 *lastCh;
int codepoint;
do {
codepoint = utf8_get_next(ch, &ch);
} while (!utf8_is_format_code(codepoint));
while (!utf8_is_format_code(codepoint = utf8_get_next(ch, &lastCh))) {
ch = lastCh;
}
if (codepoint == 0) {
ttf_draw_string_raw(dpi, text, info);
return ch - 1;
return ch;
} else {
int length = ch - text - 1;
int length = ch - text;
memcpy(buffer, text, length);
buffer[length] = 0;
ttf_draw_string_raw(dpi, buffer, info);
@@ -1550,9 +1226,16 @@ static void ttf_process_string(rct_drawpixelinfo *dpi, const utf8 *text, text_dr
const utf8 *ch = text;
const utf8 *nextCh;
int codepoint;
bool isTTF = info->flags & TEXT_DRAW_FLAG_TTF;
while ((codepoint = utf8_get_next(ch, &nextCh)) != 0) {
if (utf8_is_format_code(codepoint)) {
ch = ttf_process_format_code(dpi, ch, info);
} else if (isTTF && utf8_should_use_sprite_for_codepoint(codepoint)) {
info->flags &= ~TEXT_DRAW_FLAG_TTF;
ch = ttf_process_glyph_run(dpi, ch, info);
info->flags |= TEXT_DRAW_FLAG_TTF;
} else {
ch = ttf_process_glyph_run(dpi, ch, info);
}
@@ -1616,15 +1299,17 @@ static void ttf_draw_string(rct_drawpixelinfo *dpi, char *text, int colour, int
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.startX = x;
info.startY = x;
info.x = x;
info.y = y;
info.flags |= TEXT_DRAW_FLAG_TTF;
memset(info.palette, 0, sizeof(info.palette));
if (gUseTrueTypeFont) info.flags |= TEXT_DRAW_FLAG_TTF;
memcpy(info.palette, text_palette, sizeof(info.palette));
ttf_process_initial_colour(colour, &info);
ttf_process_string(dpi, text, &info);
memcpy(text_palette, info.palette, sizeof(info.palette));
gLastDrawStringX = info.x;
gLastDrawStringY = info.y;
@@ -1635,11 +1320,13 @@ static int ttf_get_string_width(const utf8 *text)
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.startX = 0;
info.startY = 0;
info.x = 0;
info.y = 0;
info.flags |= TEXT_DRAW_FLAG_TTF;
info.flags |= TEXT_DRAW_FLAG_NO_DRAW;
if (gUseTrueTypeFont) info.flags |= TEXT_DRAW_FLAG_TTF;
ttf_process_string(NULL, text, &info);

View File

@@ -848,10 +848,10 @@ 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 utf8 BlackUpArrowString[] = { 0xC2, 0x8E, 0xE2, 0x96, 0xB2, 0x00 };
static utf8 BlackDownArrowString[] = { 0xC2, 0x8E, 0xE2, 0x96, 0xBC, 0x00 };
static utf8 BlackLeftArrowString[] = { 0xC2, 0x8E, 0xE2, 0x96, 0x80, 0x00 };
static utf8 BlackRightArrowString[] = { 0xC2, 0x8E, 0xE2, 0x96, 0xB6, 0x00 };
static void widget_hscrollbar_draw(rct_drawpixelinfo *dpi, rct_scroll *scroll, int l, int t, int r, int b, int colour)
{

View File

@@ -21,14 +21,14 @@
#include "currency.h"
const rct_currency_spec g_currency_specs[CURRENCY_END] = {
{ 10 , "\xA3" , CURRENCY_PREFIX }, // British Pound
{ 10 , "\x24" , CURRENCY_PREFIX }, // US Dollar
{ 10 , "F" , CURRENCY_SUFFIX }, // French Franc
{ 10 , "DM" , CURRENCY_PREFIX }, // Deutsche Mark
{ 1000 , "\xA5" , CURRENCY_PREFIX }, // Japanese Yen
{ 10 , "Pts" , CURRENCY_SUFFIX }, // Spanish Peseta
{ 1000 , "L" , CURRENCY_PREFIX }, // Italian Lira
{ 10 , "fl. " , CURRENCY_PREFIX }, // Dutch Guilder
{ 10 , "kr." , CURRENCY_SUFFIX }, // Swedish Krona
{ 10 , "\xb5" , CURRENCY_PREFIX }, // Euro
{ 10 , "\xC2\xA3" , CURRENCY_PREFIX }, // British Pound
{ 10 , "$" , CURRENCY_PREFIX }, // US Dollar
{ 10 , "F" , CURRENCY_SUFFIX }, // French Franc
{ 10 , "DM" , CURRENCY_PREFIX }, // Deutsche Mark
{ 1000 , "\xC2\xA5" , CURRENCY_PREFIX }, // Japanese Yen
{ 10 , "Pts" , CURRENCY_SUFFIX }, // Spanish Peseta
{ 1000 , "L" , CURRENCY_PREFIX }, // Italian Lira
{ 10 , "fl. " , CURRENCY_PREFIX }, // Dutch Guilder
{ 10 , "kr." , CURRENCY_SUFFIX }, // Swedish Krona
{ 10 , "\xE2\x82\xAC" , CURRENCY_PREFIX }, // Euro
};

View File

@@ -21,6 +21,8 @@
#ifndef CURRENCY_H
#define CURRENCY_H
#include "../common.h"
// List of currencies
typedef enum {
CURRENCY_POUNDS, // British Pound
@@ -46,7 +48,7 @@ typedef enum {
typedef struct {
// Rate is relative to 0.1 GBP
int rate;
char symbol[8];
utf8 symbol[8];
int affix;
} rct_currency_spec;

View File

@@ -21,8 +21,8 @@
#ifndef _FORMAT_CODES_H_
#define _FORMAT_CODES_H_
char format_get_code(const char *token);
const char *format_get_token(char code);
uint32 format_get_code(const char *token);
const char *format_get_token(uint32 code);
enum {
// Font format codes
@@ -56,9 +56,6 @@ enum {
// The next 4 bytes specify the sprite
FORMAT_INLINE_SPRITE = 23,
// Non ascii-characters
FORMAT_ENDQUOTES = 34,
// Argument format codes
FORMAT_ARGUMENT_CODE_START = 123,
FORMAT_COMMA32 = 123,
@@ -101,27 +98,34 @@ enum {
// Extra non-ascii characters
FORMAT_AMINUSCULE = 159,
FORMAT_UP,
FORMAT_POUND = 163,
FORMAT_YEN = 165,
FORMAT_COPYRIGHT = 169,
FORMAT_DOWN,
FORMAT_LEFTGUILLEMET,
FORMAT_TICK,
FORMAT_CROSS,
FORMAT_RIGHT = 175,
FORMAT_DEGREE,
FORMAT_LEFTGUILLEMET = 171,
FORMAT_DEGREE = 176,
FORMAT_SQUARED = 178,
FORMAT_OPENQUOTES = 180,
FORMAT_EURO = 181,
FORMAT_APPROX = 184,
FORMAT_POWERNEGATIVEONE,
FORMAT_BULLET,
FORMAT_RIGHTGUILLEMET,
FORMAT_SMALLUP,
FORMAT_SMALLDOWN,
FORMAT_LEFT,
FORMAT_INVERTEDQUESTION
FORMAT_RIGHTGUILLEMET = 187,
FORMAT_INVERTEDQUESTION = 191,
FORMAT_OPENQUOTES = 8220,
FORMAT_ENDQUOTES = 8221,
FORMAT_BULLET = 8226,
FORMAT_POWERNEGATIVEONE = 8315,
FORMAT_EURO = 8364,
FORMAT_APPROX = 8776,
FORMAT_UP = 9650,
FORMAT_RIGHT = 9654,
FORMAT_DOWN = 9660,
FORMAT_LEFT = 9664,
FORMAT_SMALLUP = 9652,
FORMAT_SMALLDOWN = 9662,
FORMAT_TICK = 10003,
FORMAT_CROSS = 10005,
};
#endif

View File

@@ -33,39 +33,25 @@ typedef struct {
char *string_data;
} 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
"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
"chinese_traditional" // LANGUAGE_CHINESE_TRADITIONAL
const language_descriptor LanguagesDescriptors[LANGUAGE_COUNT] = {
{ "", "", "", "", FONT_OPENRCT2_SPRITE }, // LANGUAGE_UNDEFINED
{ "en-GB", "English (UK)", "English (UK)", "english_uk", FONT_OPENRCT2_SPRITE }, // LANGUAGE_ENGLISH_UK
{ "en-US", "English (US)", "English (US)", "english_us", FONT_OPENRCT2_SPRITE }, // LANGUAGE_ENGLISH_US
{ "de-DE", "German", "Deutsch", "german", FONT_OPENRCT2_SPRITE }, // LANGUAGE_GERMAN
{ "nl-NL", "Dutch", "Nederlands", "dutch", FONT_OPENRCT2_SPRITE }, // LANGUAGE_DUTCH
{ "fr-FR", "French", "Fran\xC3\xA7" "ais", "french", FONT_OPENRCT2_SPRITE }, // LANGUAGE_FRENCH
{ "hu-HU", "Hungarian", "Magyar", "hungarian", FONT_OPENRCT2_SPRITE }, // LANGUAGE_HUNGARIAN
{ "pl-PL", "Polish", "Polski", "polish", FONT_OPENRCT2_SPRITE }, // LANGUAGE_POLISH
{ "es-ES", "Spanish", "Espa\xC3\xB1ol", "spanish_sp", FONT_OPENRCT2_SPRITE }, // LANGUAGE_SPANISH
{ "sv-SE", "Swedish", "Svenska", "swedish", FONT_OPENRCT2_SPRITE }, // LANGUAGE_SWEDISH
{ "it-IT", "Italian", "Italiano", "italian", FONT_OPENRCT2_SPRITE }, // LANGUAGE_ITALIAN
{ "pt-BR", "Portuguese (BR)", "Portug\xC3\xAAs (BR)", "portuguese_br", FONT_OPENRCT2_SPRITE }, // LANGUAGE_PORTUGUESE_BR
{ "zh-Hant", "Chinese (Traditional)", "Chinese (Traditional)", "chinese_traditional", "msjh.ttc" }, // LANGUAGE_CHINESE_TRADITIONAL
};
int gCurrentLanguage = LANGUAGE_UNDEFINED;
bool gUseTrueTypeFont = false;
const utf8 *gTrueTypeFontPath;
language_data _languageFallback = { 0 };
language_data _languageCurrent = { 0 };
@@ -154,19 +140,27 @@ int language_open(int id)
return 1;
if (id != LANGUAGE_ENGLISH_UK) {
sprintf(filename, languagePath, gExePath, language_filenames[LANGUAGE_ENGLISH_UK]);
sprintf(filename, languagePath, gExePath, LanguagesDescriptors[LANGUAGE_ENGLISH_UK].path);
if (language_open_file(filename, &_languageFallback)) {
_languageFallback.id = LANGUAGE_ENGLISH_UK;
}
}
sprintf(filename, languagePath, gExePath, language_filenames[id]);
sprintf(filename, languagePath, gExePath, LanguagesDescriptors[id].path);
if (language_open_file(filename, &_languageCurrent)) {
_languageCurrent.id = id;
gCurrentLanguage = id;
if (!ttf_initialise()) {
log_warning("Unable to initialise TrueType fonts.");
if (LanguagesDescriptors[id].font == FONT_OPENRCT2_SPRITE) {
gUseTrueTypeFont = false;
gTrueTypeFontPath = NULL;
ttf_dispose();
} else {
gUseTrueTypeFont = true;
gTrueTypeFontPath = LanguagesDescriptors[id].font;
if (!ttf_initialise()) {
log_warning("Unable to initialise TrueType fonts.");
}
}
return 1;
@@ -274,10 +268,13 @@ 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;
uint8 code = (uint8)format_get_code(tokenBuffer);
if (code == 0)
uint32 code = format_get_code(tokenBuffer);
if (code == 0) {
code = atoi(tokenBuffer);
dst = utf8_write_codepoint(dst, code);
*dst++ = code & 0xFF;
} else {
dst = utf8_write_codepoint(dst, code);
}
mode = 1;
}
break;

View File

@@ -40,8 +40,21 @@ enum {
LANGUAGE_COUNT
};
extern const char *language_names[LANGUAGE_COUNT];
#define FONT_OPENRCT2_SPRITE NULL
typedef struct {
const char *locale;
const utf8 *english_name;
const utf8 *native_name;
const utf8 *path;
const utf8 *font;
} language_descriptor;
extern const language_descriptor LanguagesDescriptors[LANGUAGE_COUNT];
extern int gCurrentLanguage;
extern bool gUseTrueTypeFont;
extern const utf8 *gTrueTypeFontPath;
const char *language_get_string(rct_string_id id);
int language_open(int id);

View File

@@ -29,8 +29,8 @@
#pragma region Format codes
typedef struct {
char code;
char *token;
uint32 code;
const char *token;
} format_code_token;
format_code_token format_code_tokens[] = {
@@ -107,7 +107,7 @@ format_code_token format_code_tokens[] = {
{ FORMAT_INVERTEDQUESTION, "INVERTEDQUESTION" }
};
char format_get_code(const char *token)
uint32 format_get_code(const char *token)
{
int i;
for (i = 0; i < countof(format_code_tokens); i++)
@@ -116,7 +116,7 @@ char format_get_code(const char *token)
return 0;
}
const char *format_get_token(char code)
const char *format_get_token(uint32 code)
{
int i;
for (i = 0; i < countof(format_code_tokens); i++)
@@ -125,6 +125,66 @@ const char *format_get_token(char code)
return 0;
}
bool utf8_is_format_code(int codepoint)
{
if (codepoint < 32) return true;
if (codepoint >= 123 && codepoint <= 155) return true;
return false;
}
bool utf8_should_use_sprite_for_codepoint(int codepoint)
{
switch (codepoint) {
case FORMAT_UP:
case FORMAT_DOWN:
case FORMAT_LEFTGUILLEMET:
case FORMAT_TICK:
case FORMAT_CROSS:
case FORMAT_RIGHT:
case FORMAT_RIGHTGUILLEMET:
case FORMAT_SMALLUP:
case FORMAT_SMALLDOWN:
case FORMAT_LEFT:
case FORMAT_OPENQUOTES:
case FORMAT_ENDQUOTES:
return true;
default:
return false;
}
}
int utf8_get_sprite_offset_for_codepoint(int codepoint)
{
switch (codepoint) {
case FORMAT_AMINUSCULE: return 159 - 32;
case FORMAT_POUND: return 163 - 32;
case FORMAT_YEN: return 165 - 32;
case FORMAT_COPYRIGHT: return 169 - 32;
case FORMAT_LEFTGUILLEMET: return 171 - 32;
case FORMAT_DEGREE: return 176 - 32;
case FORMAT_SQUARED: return 178 - 32;
case FORMAT_RIGHTGUILLEMET: return 187 - 32;
case FORMAT_INVERTEDQUESTION: return 191 - 32;
case FORMAT_OPENQUOTES: return 180 - 32;
case FORMAT_ENDQUOTES: return 34 - 32;
case FORMAT_BULLET: return 186 - 32;
case FORMAT_POWERNEGATIVEONE: return 185 - 32;
case FORMAT_EURO: return 181 - 32;
case FORMAT_APPROX: return 184 - 32;
case FORMAT_UP: return 160 - 32;
case FORMAT_RIGHT: return 175 - 32;
case FORMAT_DOWN: return 170 - 32;
case FORMAT_LEFT: return 190 - 32;
case FORMAT_SMALLUP: return 188 - 32;
case FORMAT_SMALLDOWN: return 189 - 32;
case FORMAT_TICK: return 172 - 32;
case FORMAT_CROSS: return 173 - 32;
default:
if (codepoint > 224) codepoint = ' ';
return codepoint - 32;
}
}
#pragma endregion
void format_string_part_from_raw(char **dest, const char *src, char **args);
@@ -312,7 +372,7 @@ void format_currency(char **dest, long long value)
}
// Currency symbol
const char *symbol = currencySpec->symbol;
const utf8 *symbol = currencySpec->symbol;
// Prefix
if (currencySpec->affix == CURRENCY_PREFIX) {
@@ -343,7 +403,7 @@ void format_currency_2dp(char **dest, long long value)
}
// Currency symbol
const char *symbol = currencySpec->symbol;
const utf8 *symbol = currencySpec->symbol;
// Prefix
if (currencySpec->affix == CURRENCY_PREFIX) {
@@ -743,53 +803,34 @@ void generate_string_file()
*
* buffer (esi)
*/
int get_string_length(char* buffer)
int get_string_length(const utf8* text)
{
// Length of string
int length = 0;
int codepoint;
const utf8 *ch = text;
for (uint8* curr_char = (uint8*)buffer; *curr_char != (uint8)0; curr_char++) {
length++;
if (*curr_char >= 0x20) {
continue;
}
switch (*curr_char) {
case FORMAT_MOVE_X:
case FORMAT_ADJUST_PALETTE:
case 3:
case 4:
curr_char++;
length++;
break;
case FORMAT_NEWLINE:
case FORMAT_NEWLINE_SMALLER:
case FORMAT_TINYFONT:
case FORMAT_BIGFONT:
case FORMAT_MEDIUMFONT:
case FORMAT_SMALLFONT:
case FORMAT_OUTLINE:
case FORMAT_OUTLINE_OFF:
case FORMAT_WINDOW_COLOUR_1:
case FORMAT_WINDOW_COLOUR_2:
case FORMAT_WINDOW_COLOUR_3:
case 0x10:
continue;
case FORMAT_INLINE_SPRITE:
length += 4;
curr_char += 4;
break;
default:
if (*curr_char <= 0x16) { //case 0x11? FORMAT_NEW_LINE_X_Y
length += 2;
curr_char += 2;
continue;
while ((codepoint = utf8_get_next(ch, &ch)) != 0) {
if (utf8_is_format_code(codepoint)) {
switch (codepoint) {
case FORMAT_MOVE_X:
case FORMAT_ADJUST_PALETTE:
case 3:
case 4:
ch++;
break;
case FORMAT_INLINE_SPRITE:
ch += 4;
break;
default:
if (codepoint <= 22) {
ch += 2;
} else {
ch += 4;
}
break;
}
length += 4;
curr_char += 4;//never happens?
break;
}
}
return length;
return ch - text - 1;
}
int win1252_to_utf8(utf8string dst, const char *src, int maxBufferLength)

View File

@@ -26,12 +26,16 @@
#include "language.h"
#include "string_ids.h"
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);
void format_string(char *dest, rct_string_id format, void *args);
void format_string_raw(char *dest, char *src, void *args);
void format_string_to_upper(char *dest, rct_string_id format, void *args);
void generate_string_file();
void error_string_quit(int error, rct_string_id format);
int get_string_length(char* buffer);
int get_string_length(const utf8* buffer);
void user_string_clear_all();
rct_string_id user_string_allocate(int base, const char *text);

View File

@@ -759,7 +759,7 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget*
case WIDX_LANGUAGE_DROPDOWN:
for (i = 1; i < LANGUAGE_COUNT; i++) {
gDropdownItemsFormat[i - 1] = 2777;
gDropdownItemsArgs[i - 1] = (sint32)language_names[i];
gDropdownItemsArgs[i - 1] = (sint32)LanguagesDescriptors[i].native_name;
}
window_options_show_dropdown(w, widget, LANGUAGE_COUNT - 1);
gDropdownItemsChecked = 1 << (gCurrentLanguage - 1);
@@ -1289,7 +1289,7 @@ static void window_options_paint(rct_window *w, rct_drawpixelinfo *dpi)
RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224;
gfx_draw_string(
dpi,
(char*)language_names[gCurrentLanguage],
(char*)LanguagesDescriptors[gCurrentLanguage].native_name,
w->colours[1],
w->x + window_options_culture_widgets[WIDX_LANGUAGE].left + 1,
w->y + window_options_culture_widgets[WIDX_LANGUAGE].top