implement utf8, part 5

This commit is contained in:
IntelOrca 2015-07-27 01:09:24 +01:00
parent 1682eae048
commit 795c01cab5
10 changed files with 222 additions and 71 deletions

View File

@ -138,6 +138,7 @@ config_enum_definition _languageEnum[] = {
{ "sv-SE", LANGUAGE_SWEDISH },
{ "it-IT", LANGUAGE_ITALIAN },
{ "pt-BR", LANGUAGE_PORTUGUESE_BR },
{ "zh-Hant", LANGUAGE_CHINESE_TRADITIONAL },
END_OF_ENUM
};

View File

@ -933,7 +933,7 @@ bool ttf_initialise()
}
}
_ttfFontOffsetX = 0;
_ttfFontOffsetX = 1;
_ttfFontOffsetY = -3;
_ttfInitialised = true;
}
@ -972,22 +972,27 @@ typedef struct {
uint16 font_sprite_base;
} text_draw_info;
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;
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);
}
info->x += charWidth;
}
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 + 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;
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);
}
info->x += charWidth;
ttf_draw_character_sprite(dpi, codepoint, info);
};
}
@ -1206,7 +1211,11 @@ static const utf8 *ttf_process_glyph_run(rct_drawpixelinfo *dpi, const utf8 *tex
const utf8 *lastCh;
int codepoint;
bool isTTF = info->flags & TEXT_DRAW_FLAG_TTF;
while (!utf8_is_format_code(codepoint = utf8_get_next(ch, &lastCh))) {
if (isTTF && utf8_should_use_sprite_for_codepoint(codepoint)) {
break;
}
ch = lastCh;
}
if (codepoint == 0) {
@ -1233,9 +1242,8 @@ static void ttf_process_string(rct_drawpixelinfo *dpi, const utf8 *text, text_dr
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;
ttf_draw_character_sprite(dpi, codepoint, info);
ch = nextCh;
} else {
ch = ttf_process_glyph_run(dpi, ch, info);
}
@ -1246,9 +1254,9 @@ static void ttf_process_initial_colour(int colour, text_draw_info *info)
{
if (colour != 254 && colour != 255) {
info->flags &= ~(1 | 2 | 4 | 8);
if (info->font_sprite_base < 0) {
if ((sint16)info->font_sprite_base < 0) {
info->flags |= 4;
if (info->font_sprite_base != -1) {
if ((sint16)info->font_sprite_base != -1) {
info->flags |= 8;
}
info->font_sprite_base = 224;

View File

@ -725,8 +725,6 @@ static void widget_closebox_draw(rct_drawpixelinfo *dpi, rct_window *w, int widg
gfx_draw_string_centred_clipped(dpi, widget->image, (void*)0x013CE952, colour, l, t, widget->right - widget->left - 2);
}
static const utf8 CheckBoxMarkString[] = { 0xE2, 0x9C, 0x93, 0x00 };
/**
*
* rct2: 0x006EBAD9
@ -850,11 +848,6 @@ static void widget_scroll_draw(rct_drawpixelinfo *dpi, rct_window *w, int widget
window_event_scroll_paint_call(w, &scroll_dpi, scrollIndex);
}
static const utf8 BlackUpArrowString[] = { 0xC2, 0x8E, 0xE2, 0x96, 0xB2, 0x00 };
static const utf8 BlackDownArrowString[] = { 0xC2, 0x8E, 0xE2, 0x96, 0xBC, 0x00 };
static const utf8 BlackLeftArrowString[] = { 0xC2, 0x8E, 0xE2, 0x96, 0x80, 0x00 };
static const 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)
{
colour &= 0x7F;

View File

@ -33,20 +33,38 @@ typedef struct {
char *string_data;
} language_data;
enum {
RCT2_LANGUAGE_ID_ENGLISH_UK,
RCT2_LANGUAGE_ID_ENGLISH_US,
RCT2_LANGUAGE_ID_FRENCH,
RCT2_LANGUAGE_ID_GERMAN,
RCT2_LANGUAGE_ID_SPANISH,
RCT2_LANGUAGE_ID_ITALIAN,
RCT2_LANGUAGE_ID_DUTCH,
RCT2_LANGUAGE_ID_SWEDISH,
RCT2_LANGUAGE_ID_8,
RCT2_LANGUAGE_ID_KOREAN,
RCT2_LANGUAGE_ID_CHINESE_TRADITIONAL,
RCT2_LANGUAGE_ID_CHINESE_SIMPLIFIED,
RCT2_LANGUAGE_ID_12,
RCT2_LANGUAGE_ID_PORTUGESE,
RCT2_LANGUAGE_ID_END = 255
};
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
{ "", "", "", "", FONT_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_ENGLISH_UK }, // LANGUAGE_UNDEFINED
{ "en-GB", "English (UK)", "English (UK)", "english_uk", FONT_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_ENGLISH_UK }, // LANGUAGE_ENGLISH_UK
{ "en-US", "English (US)", "English (US)", "english_us", FONT_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_ENGLISH_US }, // LANGUAGE_ENGLISH_US
{ "de-DE", "German", "Deutsch", "german", FONT_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_GERMAN }, // LANGUAGE_GERMAN
{ "nl-NL", "Dutch", "Nederlands", "dutch", FONT_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_DUTCH }, // LANGUAGE_DUTCH
{ "fr-FR", "French", "Fran\xC3\xA7" "ais", "french", FONT_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_FRENCH }, // LANGUAGE_FRENCH
{ "hu-HU", "Hungarian", "Magyar", "hungarian", FONT_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_ENGLISH_UK }, // LANGUAGE_HUNGARIAN
{ "pl-PL", "Polish", "Polski", "polish", FONT_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_ENGLISH_UK }, // LANGUAGE_POLISH
{ "es-ES", "Spanish", "Espa\xC3\xB1ol", "spanish_sp", FONT_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_SPANISH }, // LANGUAGE_SPANISH
{ "sv-SE", "Swedish", "Svenska", "swedish", FONT_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_SWEDISH }, // LANGUAGE_SWEDISH
{ "it-IT", "Italian", "Italiano", "italian", FONT_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_ITALIAN }, // LANGUAGE_ITALIAN
{ "pt-BR", "Portuguese (BR)", "Portug\xC3\xAAs (BR)", "portuguese_br", FONT_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_PORTUGESE }, // LANGUAGE_PORTUGUESE_BR
{ "zh-Hant", "Chinese (Traditional)", "Chinese (Traditional)", "chinese_traditional", "msjh.ttc", RCT2_LANGUAGE_ID_CHINESE_TRADITIONAL }, // LANGUAGE_CHINESE_TRADITIONAL
};
int gCurrentLanguage = LANGUAGE_UNDEFINED;
@ -58,6 +76,12 @@ language_data _languageCurrent = { 0 };
const char **_languageOriginal = (char**)0x009BF2D4;
const utf8 BlackUpArrowString[] = { 0xC2, 0x8E, 0xE2, 0x96, 0xB2, 0x00 };
const utf8 BlackDownArrowString[] = { 0xC2, 0x8E, 0xE2, 0x96, 0xBC, 0x00 };
const utf8 BlackLeftArrowString[] = { 0xC2, 0x8E, 0xE2, 0x97, 0x80, 0x00 };
const utf8 BlackRightArrowString[] = { 0xC2, 0x8E, 0xE2, 0x96, 0xB6, 0x00 };
const utf8 CheckBoxMarkString[] = { 0xE2, 0x9C, 0x93, 0x00 };
static int language_open_file(const char *filename, language_data *language);
static void language_close(language_data *language);
@ -299,56 +323,141 @@ static void language_close(language_data *language)
}
const int OpenRCT2LangIdToObjectLangId[] = {
0, 0, 1, 3, 6, 2, 0, 0, 4, 7, 5, 13
0,
0,
1,
3,
6,
2,
0,
0,
4,
7,
5,
13
};
#define STEX_BASE_STRING_ID 3447
#define NONSTEX_BASE_STRING_ID 3463
#define MAX_OBJECT_CACHED_STRINGS 2048
/* rct2: 0x0098DA16 */
uint16 ObjectTypeStringTableCount[] = { 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3 };
utf8 *_cachedObjectStrings[MAX_OBJECT_CACHED_STRINGS] = { NULL };
void utf8_trim_string(utf8 *text)
{
utf8 *src = text;
utf8 *dst = text;
utf8 *last = text;
int codepoint;
// Trim left
while ((codepoint = utf8_get_next(src, &src)) != 0) {
if (codepoint != ' ') {
dst = utf8_write_codepoint(dst, codepoint);
last = dst;
break;
}
}
if (codepoint != 0) {
// Trim right
while ((codepoint = utf8_get_next(src, &src)) != 0) {
dst = utf8_write_codepoint(dst, codepoint);
if (codepoint != ' ') {
last = dst;
}
}
}
*last = 0;
}
static utf8 *convert_multibyte_charset(const char *src)
{
int reservedLength = (strlen(src) * 4) + 1;
utf8 *buffer = malloc(reservedLength);
utf8 *dst = buffer;
for (const uint8 *ch = src; *ch != 0;) {
if (*ch == 0xFF) {
ch++;
uint8 a = *ch++;
uint8 b = *ch++;
uint16 codepoint = (a << 8) | b;
dst = utf8_write_codepoint(dst, codepoint);
} else {
*dst++ = *ch++;
}
}
*dst++ = 0;
int actualLength = dst - buffer;
return realloc(buffer, actualLength);
}
static bool rct2_language_is_multibyte_charset(int languageId)
{
switch (languageId) {
case RCT2_LANGUAGE_ID_KOREAN:
case RCT2_LANGUAGE_ID_CHINESE_TRADITIONAL:
case RCT2_LANGUAGE_ID_CHINESE_SIMPLIFIED:
return true;
default:
return false;
}
}
/* rct2: 0x006A9E24*/
rct_string_id object_get_localised_text(uint8_t** pStringTable/*ebp*/, int type/*ecx*/, int index/*ebx*/, int tableindex/*edx*/)
{
char* pString = NULL;
uint8 languageId, chosenLanguageId;
char *pString = NULL;
int result = 0;
while (true)
{
uint8_t language_code = *(*pStringTable)++;
if (language_code == 0xFF) //end of string table
break;
bool isBlank;
while ((languageId = *(*pStringTable)++) != RCT2_LANGUAGE_ID_END) {
isBlank = true;
// Strings that are just ' ' are set as invalid langauges.
// But if there is no real string then it will set the string as
// the blank string
for (char *ch = *pStringTable; *ch != 0; ch++) {
if (!isblank(*ch)) {
isBlank = false;
break;
}
}
if (isBlank) languageId = 0xFE;
// This is the ideal situation. Language found
if (language_code == OpenRCT2LangIdToObjectLangId[gCurrentLanguage])//1)
{
if (languageId == LanguagesDescriptors[gCurrentLanguage].rct2_original_id) {
chosenLanguageId = languageId;
pString = *pStringTable;
result |= 1;
}
// Just in case always load english into pString
if (language_code == 0 && !(result & 1))
{
if (languageId == RCT2_LANGUAGE_ID_ENGLISH_UK && !(result & 1)) {
chosenLanguageId = languageId;
pString = *pStringTable;
result |= 2;
}
// Failing that fall back to whatever is first string
if (!(result & 7))
{
if (!(result & 7)) {
chosenLanguageId = languageId;
pString = *pStringTable;
result |= 4;
if (!isBlank) result |= 4;
}
// Skip over the actual string entry to get to the next
// entry
// Skip over the actual string entry to get to the next entry
while (*(*pStringTable)++ != 0);
}
// If not scenario text
if (RCT2_GLOBAL(0x9ADAFC, uint8_t) == 0)
{
int stringid = 3463;
for (int i = 0; i < type; i++)
{
if (RCT2_GLOBAL(0x009ADAFC, uint8) == 0) {
int stringid = NONSTEX_BASE_STRING_ID;
for (int i = 0; i < type; i++) {
int nrobjects = object_entry_group_counts[i];
int nrstringtables = ObjectTypeStringTableCount[i];
stringid += nrobjects * nrstringtables;
@ -358,23 +467,48 @@ rct_string_id object_get_localised_text(uint8_t** pStringTable/*ebp*/, int type/
RCT2_GLOBAL(RCT2_ADDRESS_CURR_OBJECT_BASE_STRING_ID, uint32) = stringid;
stringid += tableindex;
// cache UTF-8 string
int cacheStringOffset = stringid - STEX_BASE_STRING_ID;
utf8 **cacheString = &_cachedObjectStrings[cacheStringOffset];
if (*cacheString != NULL) {
free(*cacheString);
}
if (rct2_language_is_multibyte_charset(chosenLanguageId)) {
*cacheString = convert_multibyte_charset(pString);
} else {
*cacheString = win1252_to_utf8_alloc(pString);
}
utf8_trim_string(*cacheString);
//put pointer in stringtable
if (_languageCurrent.num_strings > stringid)
_languageCurrent.strings[stringid] = pString;
_languageCurrent.strings[stringid] = *cacheString;
// Until all string related functions are finished copy
// to old array as well.
_languageOriginal[stringid] = pString;
_languageOriginal[stringid] = *cacheString;
return stringid;
}
else
{
int stringid = 3447 + tableindex;
} else {
int stringid = STEX_BASE_STRING_ID + tableindex;
// cache UTF-8 string
int cacheStringOffset = stringid - STEX_BASE_STRING_ID;
utf8 **cacheString = &_cachedObjectStrings[cacheStringOffset];
if (*cacheString != NULL) {
free(*cacheString);
}
if (rct2_language_is_multibyte_charset(chosenLanguageId)) {
*cacheString = convert_multibyte_charset(pString);
} else {
*cacheString = win1252_to_utf8_alloc(pString);
}
utf8_trim_string(*cacheString);
//put pointer in stringtable
if (_languageCurrent.num_strings > stringid)
_languageCurrent.strings[stringid] = pString;
_languageCurrent.strings[stringid] = *cacheString;
// Until all string related functions are finished copy
// to old array as well.
_languageOriginal[stringid] = pString;
_languageOriginal[stringid] = *cacheString;
return stringid;
}
}

View File

@ -48,6 +48,7 @@ typedef struct {
const utf8 *native_name;
const utf8 *path;
const utf8 *font;
uint8 rct2_original_id;
} language_descriptor;
extern const language_descriptor LanguagesDescriptors[LANGUAGE_COUNT];
@ -56,6 +57,12 @@ extern int gCurrentLanguage;
extern bool gUseTrueTypeFont;
extern const utf8 *gTrueTypeFontPath;
extern const utf8 BlackUpArrowString[];
extern const utf8 BlackDownArrowString[];
extern const utf8 BlackLeftArrowString[];
extern const utf8 BlackRightArrowString[];
extern const utf8 CheckBoxMarkString[];
const char *language_get_string(rct_string_id id);
int language_open(int id);
void language_close_all();

View File

@ -833,6 +833,14 @@ int get_string_length(const utf8* text)
return ch - text - 1;
}
utf8 *win1252_to_utf8_alloc(const char *src)
{
int reservedSpace = (strlen(src) * 4) + 1;
utf8 *result = malloc(reservedSpace);
int actualSpace = win1252_to_utf8(result, src, reservedSpace);
return (utf8*)realloc(result, actualSpace);
}
int win1252_to_utf8(utf8string dst, const char *src, int maxBufferLength)
{
utf16 stackBuffer[256];

View File

@ -42,6 +42,7 @@ rct_string_id user_string_allocate(int base, const char *text);
void user_string_free(rct_string_id id);
bool is_user_string_id(rct_string_id stringId);
utf8 *win1252_to_utf8_alloc(const char *src);
int win1252_to_utf8(utf8string dst, const char *src, int maxBufferLength);
#define MAX_USER_STRINGS 1024

View File

@ -1439,14 +1439,13 @@ static void window_editor_object_selection_scrollpaint(rct_window *w, rct_drawpi
if (*listItem->flags & (OBJECT_SELECTION_FLAG_IN_USE | OBJECT_SELECTION_FLAG_REQUIRED | OBJECT_SELECTION_FLAG_ALWAYS_REQUIRED))
colour2 |= 0x40;
gfx_draw_string(dpi, (char*)0x009DED72, colour2, x, y);
gfx_draw_string(dpi, (char*)CheckBoxMarkString, colour2, x, y);
}
x = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER ? 0 : 15;
char *bufferWithColour = (char*)0x0141ED68;
char *buffer = bufferWithColour + 1;
bufferWithColour[0] = colour;
char *buffer = utf8_write_codepoint(bufferWithColour, colour);
if (*listItem->flags & OBJECT_SELECTION_FLAG_6) {
colour = w->colours[1] & 0x7F;
RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, sint16) = -1;

View File

@ -1200,7 +1200,7 @@ static void window_editor_objective_options_rides_scrollpaint(rct_window *w, rct
ride = GET_RIDE(i);
if (ride->lifecycle_flags & RIDE_LIFECYCLE_INDESTRUCTIBLE) {
RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = stringId == 1193 ? 0xFFFE : 0xFFFF;
gfx_draw_string(dpi, (char*)0x009DED72, w->colours[1] & 0x7F, 2, y);
gfx_draw_string(dpi, (char*)CheckBoxMarkString, w->colours[1] & 0x7F, 2, y);
}
// Ride name

View File

@ -881,7 +881,7 @@ void window_themes_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scroll
gfx_fill_rect_inset(dpi, _button_offset_x + 12 * j, y + _check_offset_y, _button_offset_x + 12 * j + 9, y + _check_offset_y + 10, w->colours[1], 0xE0);
if (get_colour_scheme_tab_by_index(i)->colours[j] & 0x80) {
RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, sint16) = -1;
gfx_draw_string(dpi, (char*)0x009DED72, w->colours[1] & 0x7F, _button_offset_x + 12 * j, y + _check_offset_y);
gfx_draw_string(dpi, (char*)CheckBoxMarkString, w->colours[1] & 0x7F, _button_offset_x + 12 * j, y + _check_offset_y);
}
}