From a963935c111978b59b851727c01eeeecbe4e062d Mon Sep 17 00:00:00 2001 From: zsilencer Date: Wed, 18 May 2016 12:31:40 -0600 Subject: [PATCH 1/4] Decompile scenery_multiple_paint --- src/drawing/scrolling_text.c | 2 +- src/object.c | 10 +- src/paint/map_element/scenery.c | 2 +- src/paint/map_element/scenery_multiple.c | 309 ++++++++++++++++++++++- src/world/scenery.h | 19 +- 5 files changed, 331 insertions(+), 11 deletions(-) diff --git a/src/drawing/scrolling_text.c b/src/drawing/scrolling_text.c index 4ba9537cd7..aae6b4c5f7 100644 --- a/src/drawing/scrolling_text.c +++ b/src/drawing/scrolling_text.c @@ -109,7 +109,7 @@ static int scrolling_text_get_matching_or_oldest(rct_string_id stringId, uint16 static uint8 scrolling_text_get_colour(uint32 character) { int colour = character & 0x7F; - if (colour & (1 << 7)) { + if (character & (1 << 7)) { return ColourMapA[colour].light; } else { return ColourMapA[colour].mid_dark; diff --git a/src/object.c b/src/object.c index 05c1b6084f..479db16da8 100644 --- a/src/object.c +++ b/src/object.c @@ -974,7 +974,7 @@ static bool object_type_large_scenery_load(void *objectEntry, uint32 entryIndex) extendedEntryData += sizeof(rct_object_entry); if (sceneryEntry->large_scenery.flags & (1 << 2)) { - sceneryEntry->large_scenery.var_12 = (uint32)extendedEntryData; + sceneryEntry->large_scenery.text = (rct_large_scenery_text*)extendedEntryData; extendedEntryData += 1038; } @@ -989,9 +989,9 @@ static bool object_type_large_scenery_load(void *objectEntry, uint32 entryIndex) int imageId = object_chunk_load_image_directory(&extendedEntryData); if (sceneryEntry->large_scenery.flags & (1 << 2)){ - sceneryEntry->large_scenery.var_16 = imageId; + sceneryEntry->large_scenery.text_image = imageId; - uint8* edx = (uint8*)sceneryEntry->large_scenery.var_12; + uint8* edx = (uint8*)sceneryEntry->large_scenery.text; if (!(edx[0xC] & 1)) { imageId += edx[0xD] * 4; } else{ @@ -1013,8 +1013,8 @@ static void object_type_large_scenery_unload(void *objectEntry) sceneryEntry->image = 0; sceneryEntry->large_scenery.tiles = 0; sceneryEntry->large_scenery.scenery_tab_id = 0; - sceneryEntry->large_scenery.var_12 = 0; - sceneryEntry->large_scenery.var_16 = 0; + sceneryEntry->large_scenery.text = 0; + sceneryEntry->large_scenery.text_image = 0; } static bool object_type_large_scenery_test(void *objectEntry) diff --git a/src/paint/map_element/scenery.c b/src/paint/map_element/scenery.c index d0fde736fe..87519f5ec0 100644 --- a/src/paint/map_element/scenery.c +++ b/src/paint/map_element/scenery.c @@ -39,7 +39,7 @@ void scenery_paint(uint8 direction, int height, rct_map_element* mapElement) { boxoffset.z = height; int baseImageid = 0; if (RCT2_GLOBAL(0x009DEA6F, uint8) & 1) { - if (track_design_save_contains_map_element(mapElement)) { + if (!track_design_save_contains_map_element(mapElement)) { baseImageid = 0x21700000; } } diff --git a/src/paint/map_element/scenery_multiple.c b/src/paint/map_element/scenery_multiple.c index 45653506d3..610d0f9872 100644 --- a/src/paint/map_element/scenery_multiple.c +++ b/src/paint/map_element/scenery_multiple.c @@ -15,9 +15,314 @@ #pragma endregion #include "map_element.h" +#include "../paint.h" +#include "../supports.h" #include "../../addresses.h" +#include "../../config.h" +#include "../../game.h" +#include "../../interface/viewport.h" +#include "../../localisation/localisation.h" #include "../../world/map.h" +#include "../../world/scenery.h" -void scenery_multiple_paint(uint8 direction, uint16 height, rct_map_element *mapElement) { - RCT2_CALLPROC_X(0x6B7F0C, 0, 0, direction, height, (int)mapElement, 0, 0); +// 6B8172: +void scenery_multiple_paint_supports(uint8 direction, uint16 height, rct_map_element *mapElement, uint32 dword_F4387C, rct_scenery_entry *entry) +{ + if (entry->large_scenery.flags & 0x20) { + return; + } + + int ax = 0; + int supportHeight = height; + + if (supportHeight & 0xF) { + supportHeight &= 0xFFFFFFF0; + ax = 49; + } + + int supportImageColourFlags = 0x20000000; + + if (dword_F4387C) { + supportImageColourFlags = dword_F4387C; + } + + wooden_b_supports_paint_setup((direction & 1), ax, supportHeight, supportImageColourFlags); + + int clearanceHeight = ceil2(mapElement->clearance_height * 8 + 15, 16); + + if (entry->large_scenery.flags & 0x40) { + paint_util_set_segment_support_height(SEGMENTS_ALL, clearanceHeight, 0x20); + } else { + paint_util_set_segment_support_height(SEGMENTS_ALL, 0xFFFF, 0); + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PAINT_TILE_MAX_HEIGHT, sint16) < clearanceHeight) { + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PAINT_TILE_MAX_HEIGHT, sint16) = clearanceHeight; + RCT2_GLOBAL(0x141E9DA, uint8) = 0x20; + } +} + +int scenery_multiple_sign_text_width(const char *str, rct_large_scenery_text *text) +{ + int width = 0; + for(size_t i = 0; i < strlen(str); i++) { + width += text->glyphs[str[i]].width; + } + return width; +} + +int scenery_multiple_sign_text_height(const char *str, rct_large_scenery_text *text) +{ + int height = 0; + for(size_t i = 0; i < strlen(str); i++) { + height += text->glyphs[str[i]].height; + } + return height; +} + +const char *scenery_multiple_sign_fit_text(const char *str, rct_large_scenery_text *text, bool height) +{ + static char fitStr[32] = {0}; + char *fitStrEnd = fitStr; + strncpy(fitStr, str, sizeof(fitStr) - 1); + int w = 0; + do { + if (height) { + w += text->glyphs[*fitStrEnd].height; + } else { + w += text->glyphs[*fitStrEnd].width; + } + } while (w < text->max_width && *fitStrEnd++); + *fitStrEnd = 0; + return fitStr; +} + +void scenery_multiple_sign_paint_line(const char *str, rct_large_scenery_text *text, int textImage, int textColour, uint8 direction, int y_offset) +{ + const char *fitStr = scenery_multiple_sign_fit_text(str, text, false); + int width = scenery_multiple_sign_text_width(fitStr, text); + int x_offset = text->offset[(direction & 1)].x; + int acc = 0; + if (!(text->var_C & 0x1)) { + // sign is horizontal, center text: + x_offset -= (width / 2); + if (direction & 1) { + y_offset += ((width / 2) / 2); + } else { + y_offset -= ((width / 2) / 2); + } + } + for (size_t i = 0; i < strlen(fitStr); i++) { + int glyph_offset = text->glyphs[fitStr[i]].image_offset; + uint8 glyph_type = direction & 1; + if (text->var_C & 0x1) { // vertical sign + glyph_offset *= 2; + } else { + glyph_offset *= 4; + // set slightly different glyph on horizontal sign, which was rendered 1/2 pixel lower to deal with aliasing: + if (direction & 1) { + if (!(acc % 2)) { + glyph_type += 2; + } + } else { + if (acc % 2) { + glyph_type += 2; + } + } + } + int image_id = textImage + glyph_offset + glyph_type | textColour; + if (direction == 3) { + paint_attach_to_previous_ps(image_id, x_offset, y_offset - (acc / 2)); + } else { + paint_attach_to_previous_attach(image_id, x_offset, y_offset + (acc / 2)); + } + x_offset += text->glyphs[fitStr[i]].width; + acc += text->glyphs[fitStr[i]].width; + } +} + +/* +* +* rct2: 0x006B7F0C +*/ +void scenery_multiple_paint(uint8 direction, uint16 height, rct_map_element *mapElement) { + //RCT2_CALLPROC_X(0x6B7F0C, 0, 0, direction, height, (int)mapElement, 0, 0); return; + RCT2_GLOBAL(RCT2_ADDRESS_PAINT_SETUP_CURRENT_TYPE, uint8_t) = VIEWPORT_INTERACTION_ITEM_LARGE_SCENERY; + uint32 ebp = mapElement->properties.scenerymultiple.type >> 10; + rct_scenery_entry *entry = get_large_scenery_entry(mapElement->properties.scenerymultiple.type & 0x3FF); + uint32 image_id = (ebp << 2) + entry->image + 4 + direction; + rct_large_scenery_tile *tile = &entry->large_scenery.tiles[ebp]; + uint32 dword_F4387C = 0; + image_id |= ((mapElement->properties.scenerymultiple.colour[0] & 0x1F) << 19) | ((mapElement->properties.scenerymultiple.colour[1] & 0x1F) << 24) | 0xA0000000; + rct_xyz16 boxlength; + rct_xyz16 boxoffset; + if (RCT2_GLOBAL(0x009DEA6F, uint8) & 1) { + if (!track_design_save_contains_map_element(mapElement)) { + ebp = 0x21700000; + image_id &= 0x7FFFF; + dword_F4387C = ebp; + image_id |= dword_F4387C; + } + } + if (mapElement->flags & MAP_ELEMENT_FLAG_GHOST) { + RCT2_GLOBAL(RCT2_ADDRESS_PAINT_SETUP_CURRENT_TYPE, uint8_t) = VIEWPORT_INTERACTION_ITEM_NONE; + ebp = RCT2_ADDRESS(0x993CC4, uint32_t)[gConfigGeneral.construction_marker_colour]; + image_id &= 0x7FFFF; + dword_F4387C = ebp; + image_id |= dword_F4387C; + } + int ah = tile->z_clearance; + if (ah > 0x80) { + ah = 0x80; + } + ah -= 3; + uint16 edi = tile->var_7; + int esi = 16; + if (edi & 0xF00) { + edi &= 0xF000; + edi = (edi << direction) | (edi >> (16 - direction)); // rol + esi = (edi & 0xF) | (edi >> 12); + } + boxoffset.x = RCT2_ADDRESS(0x0098E3C4, uint16)[esi * 4]; + boxoffset.y = RCT2_ADDRESS(0x0098E3C6, uint16)[esi * 4]; + boxoffset.z = height; + boxlength.x = RCT2_ADDRESS(0x0098E3C8, uint16)[esi * 4]; + boxlength.y = RCT2_ADDRESS(0x0098E3CA, uint16)[esi * 4]; + boxlength.z = ah; + sub_98197C(image_id, 0, 0, boxlength.x, boxlength.y, ah, height, boxoffset.x, boxoffset.y, boxoffset.z, get_current_rotation()); + if (entry->large_scenery.var_11 == 0xFF || direction == 1 || direction == 2) { + scenery_multiple_paint_supports(direction, height, mapElement, dword_F4387C, entry); + return; + } + if (entry->large_scenery.flags & 0x4) { + int al; + if (entry->large_scenery.tiles[1].x_offset != (sint16)0xFFFF) { + al = ((mapElement->properties.surface.terrain >> 2) - 1) & 3; + if (al != direction) { + scenery_multiple_paint_supports(direction, height, mapElement, dword_F4387C, entry); + return; + } + } + rct_drawpixelinfo* dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); + if (dpi->zoom_level > 1) { + scenery_multiple_paint_supports(direction, height, mapElement, dword_F4387C, entry); + return; + } + // 6B8331: + // Draw sign text: + set_format_arg(0, uint32, 0); + set_format_arg(4, uint32, 0); + int textColour = mapElement->properties.scenerymultiple.colour[1] & 0x1F; + if (dword_F4387C) { + textColour = COLOUR_GREY; + } + textColour = (textColour << 19) | 0x20000000; + uint32 dword_F4388A = textColour; + uint32 bannerIndex = (mapElement->type & 0xC0) | ((mapElement->properties.scenerymultiple.colour[0] & 0xE0) >> 2) | ((mapElement->properties.scenerymultiple.colour[1] & 0xE0) >> 5); + rct_banner *banner = &gBanners[bannerIndex]; + rct_string_id stringId = banner->string_idx; + if (banner->flags & BANNER_FLAG_2) { + rct_ride * ride = get_ride(banner->colour); + stringId = ride->name; + set_format_arg(0, uint32, ride->name_arguments); + } + utf8 signString[MAX_PATH] = {0}; + format_string(signString, stringId, gCommonFormatArgs); + rct_large_scenery_text *text = entry->large_scenery.text; + int y_offset = text->offset[(direction & 1)].y; + if (text->var_C & 0x1) { + // Draw vertical sign: + char fitStr[32] = {0}; + strncpy(fitStr, scenery_multiple_sign_fit_text(signString, text, true), sizeof(fitStr) - 1); + int height = scenery_multiple_sign_text_height(fitStr, text); + char str[2] = {0}; + for (size_t i = 0; i < strlen(fitStr); i++) { + str[0] = fitStr[i]; + scenery_multiple_sign_paint_line(str, entry->large_scenery.text, entry->large_scenery.text_image, textColour, direction, y_offset - (height / 2)); + y_offset += text->glyphs[fitStr[i]].height; + } + } else { + if (text->var_C & 0x2) { + // Draw two-line sign: + int width = scenery_multiple_sign_text_width(signString, text); + if (width > text->max_width) { + y_offset -= (text->glyphs['A'].height / 2); + char *src = signString; + for (int i = 0; i < 2; i++) { + char str1[32] = {0}; + char *dst = str1; + char *srcold = src; + int space = -1; + int w = 0; + int j = 0; + do { + w += text->glyphs[*src].width; + if (*src == ' ') { + space = j; + } + j++; + } while(w < text->max_width && j < sizeof(str1) && (*dst++ = *src++)); + if (space != -1 && *src) { + str1[space] = 0; + src = &srcold[space + 1]; + } + scenery_multiple_sign_paint_line(str1, entry->large_scenery.text, entry->large_scenery.text_image, textColour, direction, y_offset); + y_offset += text->glyphs['A'].height; + } + } else { + scenery_multiple_sign_paint_line(signString, entry->large_scenery.text, entry->large_scenery.text_image, textColour, direction, y_offset); + } + } else { + // Draw one-line sign: + scenery_multiple_sign_paint_line(signString, entry->large_scenery.text, entry->large_scenery.text_image, textColour, direction, y_offset); + } + } + return; + } + rct_drawpixelinfo* dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); + if (dpi->zoom_level > 0) { + scenery_multiple_paint_supports(direction, height, mapElement, dword_F4387C, entry); + return; + } + uint8 al = ((mapElement->properties.surface.terrain >> 2) - 1) & 3; + if (al != direction) { + scenery_multiple_paint_supports(direction, height, mapElement, dword_F4387C, entry); + return; + } + // Draw scrolling text: + set_format_arg(0, uint32, 0); + set_format_arg(4, uint32, 0); + uint8 textColour = mapElement->properties.banner.unused & 0x1F; + if (dword_F4387C) { + textColour = COLOUR_GREY; + } + if (direction == 3) { + textColour |= (1 << 7); + } + // 6B809A: + set_format_arg(7, uint8, textColour); + uint32 bannerIndex = (mapElement->type & 0xC0) | ((mapElement->properties.scenerymultiple.colour[0] & 0xE0) >> 2) | ((mapElement->properties.scenerymultiple.colour[1] & 0xE0) >> 5); + uint16 scrollMode = entry->large_scenery.var_11 + ((direction + 1) & 0x3); + rct_banner *banner = &gBanners[bannerIndex]; + set_format_arg(0, rct_string_id, banner->string_idx); + if (banner->flags & BANNER_FLAG_2) { + rct_ride * ride = get_ride(banner->colour); + set_format_arg(0, rct_string_id, ride->name); + set_format_arg(2, uint32, ride->name_arguments); + } + utf8 signString[MAX_PATH]; + rct_string_id stringId = STR_SCROLLING_SIGN_TEXT; + if (gConfigGeneral.upper_case_banners) { + format_string_to_upper(signString, stringId, gCommonFormatArgs); + } else { + format_string(signString, stringId, gCommonFormatArgs); + } + + gCurrentFontSpriteBase = FONT_SPRITE_BASE_TINY; + + uint16 string_width = gfx_get_string_width(signString); + uint16 scroll = (gCurrentTicks / 2) % string_width; + sub_98199C(scrolling_text_setup(stringId, scroll, scrollMode), 0, 0, 1, 1, 21, height + 25, boxoffset.x, boxoffset.y, boxoffset.z, get_current_rotation()); + + scenery_multiple_paint_supports(direction, height, mapElement, dword_F4387C, entry); } diff --git a/src/world/scenery.h b/src/world/scenery.h index 121b0e9961..0cdc474b25 100644 --- a/src/world/scenery.h +++ b/src/world/scenery.h @@ -73,6 +73,21 @@ typedef struct rct_large_scenery_tile { uint16 var_7; } rct_large_scenery_tile; +typedef struct rct_large_scenery_text_glyph { + uint8 image_offset; + uint8 width; + uint8 height; + uint8 var_3; +} rct_large_scenery_text_glyph; + +typedef struct rct_large_scenery_text { + rct_xy16 offset[2]; // 0x0 + uint16 max_width; // 0x8 + uint16 var_A; // 0xA + uint16 var_C; // 0xC + rct_large_scenery_text_glyph glyphs[256]; // 0xE +} rct_large_scenery_text; + typedef struct rct_large_scenery_entry { uint8 tool_id; // 0x06 uint8 flags; // 0x07 @@ -81,8 +96,8 @@ typedef struct rct_large_scenery_entry { rct_large_scenery_tile* tiles; // 0x0C uint8 scenery_tab_id; // 0x10 uint8 var_11; - uint32 var_12; - uint32 var_16; + rct_large_scenery_text* text; // 0x12 + uint32 text_image; // 0x16 } rct_large_scenery_entry; From 1685d8e3f141b6d0091c3833db3fc1a2b7c20ed0 Mon Sep 17 00:00:00 2001 From: zsilencer Date: Sat, 21 May 2016 20:17:56 -0600 Subject: [PATCH 2/4] Review changes --- src/paint/map_element/scenery_multiple.c | 51 +++++++++++++----------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/src/paint/map_element/scenery_multiple.c b/src/paint/map_element/scenery_multiple.c index 610d0f9872..f79cfae0f5 100644 --- a/src/paint/map_element/scenery_multiple.c +++ b/src/paint/map_element/scenery_multiple.c @@ -28,7 +28,7 @@ // 6B8172: void scenery_multiple_paint_supports(uint8 direction, uint16 height, rct_map_element *mapElement, uint32 dword_F4387C, rct_scenery_entry *entry) { - if (entry->large_scenery.flags & 0x20) { + if (!(entry->large_scenery.flags & 0x20)) { return; } @@ -56,10 +56,7 @@ void scenery_multiple_paint_supports(uint8 direction, uint16 height, rct_map_ele paint_util_set_segment_support_height(SEGMENTS_ALL, 0xFFFF, 0); } - if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PAINT_TILE_MAX_HEIGHT, sint16) < clearanceHeight) { - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PAINT_TILE_MAX_HEIGHT, sint16) = clearanceHeight; - RCT2_GLOBAL(0x141E9DA, uint8) = 0x20; - } + paint_util_set_general_support_height(clearanceHeight, 0x20); } int scenery_multiple_sign_text_width(const char *str, rct_large_scenery_text *text) @@ -92,25 +89,25 @@ const char *scenery_multiple_sign_fit_text(const char *str, rct_large_scenery_te } else { w += text->glyphs[*fitStrEnd].width; } - } while (w < text->max_width && *fitStrEnd++); + } while (w <= text->max_width && *fitStrEnd++); *fitStrEnd = 0; return fitStr; } +int div_to_minus_infinity(int a, int b) { + return (a / b) - (a % b < 0); +} + void scenery_multiple_sign_paint_line(const char *str, rct_large_scenery_text *text, int textImage, int textColour, uint8 direction, int y_offset) { const char *fitStr = scenery_multiple_sign_fit_text(str, text, false); int width = scenery_multiple_sign_text_width(fitStr, text); int x_offset = text->offset[(direction & 1)].x; - int acc = 0; + int acc = y_offset * (direction & 1 ? -1 : 1); if (!(text->var_C & 0x1)) { // sign is horizontal, center text: x_offset -= (width / 2); - if (direction & 1) { - y_offset += ((width / 2) / 2); - } else { - y_offset -= ((width / 2) / 2); - } + acc -= (width / 2); } for (size_t i = 0; i < strlen(fitStr); i++) { int glyph_offset = text->glyphs[fitStr[i]].image_offset; @@ -121,20 +118,24 @@ void scenery_multiple_sign_paint_line(const char *str, rct_large_scenery_text *t glyph_offset *= 4; // set slightly different glyph on horizontal sign, which was rendered 1/2 pixel lower to deal with aliasing: if (direction & 1) { - if (!(acc % 2)) { + if (!(acc & 1)) { glyph_type += 2; } } else { - if (acc % 2) { + if ((acc & 1)) { glyph_type += 2; } } } int image_id = textImage + glyph_offset + glyph_type | textColour; if (direction == 3) { - paint_attach_to_previous_ps(image_id, x_offset, y_offset - (acc / 2)); + paint_attach_to_previous_ps(image_id, x_offset, -div_to_minus_infinity(acc, 2)); } else { - paint_attach_to_previous_attach(image_id, x_offset, y_offset + (acc / 2)); + if (text->var_C & 0x1) { + paint_attach_to_previous_ps(image_id, x_offset, div_to_minus_infinity(acc, 2)); + } else { + paint_attach_to_previous_attach(image_id, x_offset, div_to_minus_infinity(acc, 2)); + } } x_offset += text->glyphs[fitStr[i]].width; acc += text->glyphs[fitStr[i]].width; @@ -147,7 +148,7 @@ void scenery_multiple_sign_paint_line(const char *str, rct_large_scenery_text *t */ void scenery_multiple_paint(uint8 direction, uint16 height, rct_map_element *mapElement) { //RCT2_CALLPROC_X(0x6B7F0C, 0, 0, direction, height, (int)mapElement, 0, 0); return; - RCT2_GLOBAL(RCT2_ADDRESS_PAINT_SETUP_CURRENT_TYPE, uint8_t) = VIEWPORT_INTERACTION_ITEM_LARGE_SCENERY; + gPaintInteractionType = VIEWPORT_INTERACTION_ITEM_LARGE_SCENERY; uint32 ebp = mapElement->properties.scenerymultiple.type >> 10; rct_scenery_entry *entry = get_large_scenery_entry(mapElement->properties.scenerymultiple.type & 0x3FF); uint32 image_id = (ebp << 2) + entry->image + 4 + direction; @@ -165,7 +166,7 @@ void scenery_multiple_paint(uint8 direction, uint16 height, rct_map_element *map } } if (mapElement->flags & MAP_ELEMENT_FLAG_GHOST) { - RCT2_GLOBAL(RCT2_ADDRESS_PAINT_SETUP_CURRENT_TYPE, uint8_t) = VIEWPORT_INTERACTION_ITEM_NONE; + gPaintInteractionType = VIEWPORT_INTERACTION_ITEM_NONE; ebp = RCT2_ADDRESS(0x993CC4, uint32_t)[gConfigGeneral.construction_marker_colour]; image_id &= 0x7FFFF; dword_F4387C = ebp; @@ -229,24 +230,26 @@ void scenery_multiple_paint(uint8 direction, uint16 height, rct_map_element *map utf8 signString[MAX_PATH] = {0}; format_string(signString, stringId, gCommonFormatArgs); rct_large_scenery_text *text = entry->large_scenery.text; - int y_offset = text->offset[(direction & 1)].y; + int y_offset = (text->offset[(direction & 1)].y * 2); if (text->var_C & 0x1) { // Draw vertical sign: + y_offset += 1; char fitStr[32] = {0}; strncpy(fitStr, scenery_multiple_sign_fit_text(signString, text, true), sizeof(fitStr) - 1); int height = scenery_multiple_sign_text_height(fitStr, text); char str[2] = {0}; for (size_t i = 0; i < strlen(fitStr); i++) { str[0] = fitStr[i]; - scenery_multiple_sign_paint_line(str, entry->large_scenery.text, entry->large_scenery.text_image, textColour, direction, y_offset - (height / 2)); - y_offset += text->glyphs[fitStr[i]].height; + scenery_multiple_sign_paint_line(str, entry->large_scenery.text, entry->large_scenery.text_image, textColour, direction, y_offset - height); + y_offset += text->glyphs[fitStr[i]].height * 2; } } else { + y_offset -= (direction & 1); if (text->var_C & 0x2) { // Draw two-line sign: int width = scenery_multiple_sign_text_width(signString, text); if (width > text->max_width) { - y_offset -= (text->glyphs['A'].height / 2); + y_offset -= text->glyphs['A'].height + 1; char *src = signString; for (int i = 0; i < 2; i++) { char str1[32] = {0}; @@ -261,13 +264,13 @@ void scenery_multiple_paint(uint8 direction, uint16 height, rct_map_element *map space = j; } j++; - } while(w < text->max_width && j < sizeof(str1) && (*dst++ = *src++)); + } while(w <= text->max_width && j < sizeof(str1) && (*dst++ = *src++)); if (space != -1 && *src) { str1[space] = 0; src = &srcold[space + 1]; } scenery_multiple_sign_paint_line(str1, entry->large_scenery.text, entry->large_scenery.text_image, textColour, direction, y_offset); - y_offset += text->glyphs['A'].height; + y_offset += (text->glyphs['A'].height + 1) * 2; } } else { scenery_multiple_sign_paint_line(signString, entry->large_scenery.text, entry->large_scenery.text_image, textColour, direction, y_offset); From 1db90a20720a6cdc576ef8face7a0f1f4761be3a Mon Sep 17 00:00:00 2001 From: zsilencer Date: Sun, 22 May 2016 14:53:18 -0600 Subject: [PATCH 3/4] utf8 support on 3d signs --- src/paint/map_element/scenery_multiple.c | 97 ++++++++++++++---------- 1 file changed, 57 insertions(+), 40 deletions(-) diff --git a/src/paint/map_element/scenery_multiple.c b/src/paint/map_element/scenery_multiple.c index f79cfae0f5..96f9860fcf 100644 --- a/src/paint/map_element/scenery_multiple.c +++ b/src/paint/map_element/scenery_multiple.c @@ -59,37 +59,48 @@ void scenery_multiple_paint_supports(uint8 direction, uint16 height, rct_map_ele paint_util_set_general_support_height(clearanceHeight, 0x20); } -int scenery_multiple_sign_text_width(const char *str, rct_large_scenery_text *text) +rct_large_scenery_text_glyph *scenery_multiple_sign_get_glyph(rct_large_scenery_text *text, uint32 codepoint) +{ + if (codepoint >= countof(text->glyphs)) { + return &text->glyphs['?']; + } + return &text->glyphs[codepoint]; +} + +int scenery_multiple_sign_text_width(const utf8 *str, rct_large_scenery_text *text) { int width = 0; - for(size_t i = 0; i < strlen(str); i++) { - width += text->glyphs[str[i]].width; + uint32 codepoint; + while ((codepoint = utf8_get_next(str, &str)) != 0) { + width += scenery_multiple_sign_get_glyph(text, codepoint)->width; } return width; } -int scenery_multiple_sign_text_height(const char *str, rct_large_scenery_text *text) +int scenery_multiple_sign_text_height(const utf8 *str, rct_large_scenery_text *text) { int height = 0; - for(size_t i = 0; i < strlen(str); i++) { - height += text->glyphs[str[i]].height; + uint32 codepoint; + while ((codepoint = utf8_get_next(str, &str)) != 0) { + height += scenery_multiple_sign_get_glyph(text, codepoint)->height; } return height; } -const char *scenery_multiple_sign_fit_text(const char *str, rct_large_scenery_text *text, bool height) +const utf8 *scenery_multiple_sign_fit_text(const utf8 *str, rct_large_scenery_text *text, bool height) { - static char fitStr[32] = {0}; - char *fitStrEnd = fitStr; + static utf8 fitStr[32] = {0}; + utf8 *fitStrEnd = fitStr; strncpy(fitStr, str, sizeof(fitStr) - 1); int w = 0; - do { + uint32 codepoint; + while (w <= text->max_width && (codepoint = utf8_get_next(fitStrEnd, &fitStrEnd)) != 0) { if (height) { - w += text->glyphs[*fitStrEnd].height; + w += scenery_multiple_sign_get_glyph(text, codepoint)->height; } else { - w += text->glyphs[*fitStrEnd].width; + w += scenery_multiple_sign_get_glyph(text, codepoint)->width; } - } while (w <= text->max_width && *fitStrEnd++); + } *fitStrEnd = 0; return fitStr; } @@ -98,9 +109,9 @@ int div_to_minus_infinity(int a, int b) { return (a / b) - (a % b < 0); } -void scenery_multiple_sign_paint_line(const char *str, rct_large_scenery_text *text, int textImage, int textColour, uint8 direction, int y_offset) +void scenery_multiple_sign_paint_line(const utf8 *str, rct_large_scenery_text *text, int textImage, int textColour, uint8 direction, int y_offset) { - const char *fitStr = scenery_multiple_sign_fit_text(str, text, false); + const utf8 *fitStr = scenery_multiple_sign_fit_text(str, text, false); int width = scenery_multiple_sign_text_width(fitStr, text); int x_offset = text->offset[(direction & 1)].x; int acc = y_offset * (direction & 1 ? -1 : 1); @@ -109,8 +120,9 @@ void scenery_multiple_sign_paint_line(const char *str, rct_large_scenery_text *t x_offset -= (width / 2); acc -= (width / 2); } - for (size_t i = 0; i < strlen(fitStr); i++) { - int glyph_offset = text->glyphs[fitStr[i]].image_offset; + uint32 codepoint; + while ((codepoint = utf8_get_next(fitStr, &fitStr)) != 0) { + int glyph_offset = scenery_multiple_sign_get_glyph(text, codepoint)->image_offset; uint8 glyph_type = direction & 1; if (text->var_C & 0x1) { // vertical sign glyph_offset *= 2; @@ -137,8 +149,8 @@ void scenery_multiple_sign_paint_line(const char *str, rct_large_scenery_text *t paint_attach_to_previous_attach(image_id, x_offset, div_to_minus_infinity(acc, 2)); } } - x_offset += text->glyphs[fitStr[i]].width; - acc += text->glyphs[fitStr[i]].width; + x_offset += scenery_multiple_sign_get_glyph(text, codepoint)->width; + acc += scenery_multiple_sign_get_glyph(text, codepoint)->width; } } @@ -234,14 +246,16 @@ void scenery_multiple_paint(uint8 direction, uint16 height, rct_map_element *map if (text->var_C & 0x1) { // Draw vertical sign: y_offset += 1; - char fitStr[32] = {0}; + utf8 fitStr[32] = {0}; + const utf8 *fitStrPtr = fitStr; strncpy(fitStr, scenery_multiple_sign_fit_text(signString, text, true), sizeof(fitStr) - 1); int height = scenery_multiple_sign_text_height(fitStr, text); - char str[2] = {0}; - for (size_t i = 0; i < strlen(fitStr); i++) { - str[0] = fitStr[i]; + utf8 str[5] = {0}; + uint32 codepoint; + while ((codepoint = utf8_get_next(fitStrPtr, &fitStrPtr)) != 0) { + utf8_write_codepoint(str, codepoint); scenery_multiple_sign_paint_line(str, entry->large_scenery.text, entry->large_scenery.text_image, textColour, direction, y_offset - height); - y_offset += text->glyphs[fitStr[i]].height * 2; + y_offset += scenery_multiple_sign_get_glyph(text, codepoint)->height * 2; } } else { y_offset -= (direction & 1); @@ -249,28 +263,31 @@ void scenery_multiple_paint(uint8 direction, uint16 height, rct_map_element *map // Draw two-line sign: int width = scenery_multiple_sign_text_width(signString, text); if (width > text->max_width) { - y_offset -= text->glyphs['A'].height + 1; - char *src = signString; + y_offset -= scenery_multiple_sign_get_glyph(text, 'A')->height + 1; + utf8 *src = signString; for (int i = 0; i < 2; i++) { - char str1[32] = {0}; - char *dst = str1; - char *srcold = src; - int space = -1; + utf8 str1[64] = {0}; + utf8 *dst = str1; + const utf8 *dstend = dst + sizeof(str1); + utf8 *srcold = src; + utf8 *spacesrc = 0; + utf8 *spacedst = 0; int w = 0; - int j = 0; + uint32 codepoint = utf8_get_next(src, &src); do { - w += text->glyphs[*src].width; - if (*src == ' ') { - space = j; + w += scenery_multiple_sign_get_glyph(text, codepoint)->width; + if (codepoint == ' ') { + spacesrc = src; + spacedst = dst; } - j++; - } while(w <= text->max_width && j < sizeof(str1) && (*dst++ = *src++)); - if (space != -1 && *src) { - str1[space] = 0; - src = &srcold[space + 1]; + } while(w <= text->max_width && (dst = utf8_write_codepoint(dst, codepoint)) && (srcold = src) && (codepoint = utf8_get_next(src, &src))); + src = srcold; + if (spacesrc && codepoint) { + *spacedst = 0; + src = spacesrc; } scenery_multiple_sign_paint_line(str1, entry->large_scenery.text, entry->large_scenery.text_image, textColour, direction, y_offset); - y_offset += (text->glyphs['A'].height + 1) * 2; + y_offset += (scenery_multiple_sign_get_glyph(text, 'A')->height + 1) * 2; } } else { scenery_multiple_sign_paint_line(signString, entry->large_scenery.text, entry->large_scenery.text_image, textColour, direction, y_offset); From 990024f2e483da6bb2fdab02cdfb3d2796b1062e Mon Sep 17 00:00:00 2001 From: zsilencer Date: Sun, 22 May 2016 15:20:47 -0600 Subject: [PATCH 4/4] Fix support drawing issue --- src/paint/map_element/scenery_multiple.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/paint/map_element/scenery_multiple.c b/src/paint/map_element/scenery_multiple.c index 96f9860fcf..a622a0f959 100644 --- a/src/paint/map_element/scenery_multiple.c +++ b/src/paint/map_element/scenery_multiple.c @@ -26,9 +26,9 @@ #include "../../world/scenery.h" // 6B8172: -void scenery_multiple_paint_supports(uint8 direction, uint16 height, rct_map_element *mapElement, uint32 dword_F4387C, rct_scenery_entry *entry) +void scenery_multiple_paint_supports(uint8 direction, uint16 height, rct_map_element *mapElement, uint32 dword_F4387C, rct_large_scenery_tile *tile) { - if (!(entry->large_scenery.flags & 0x20)) { + if (tile->var_7 & 0x20) { return; } @@ -50,7 +50,7 @@ void scenery_multiple_paint_supports(uint8 direction, uint16 height, rct_map_ele int clearanceHeight = ceil2(mapElement->clearance_height * 8 + 15, 16); - if (entry->large_scenery.flags & 0x40) { + if (tile->var_7 & 0x40) { paint_util_set_segment_support_height(SEGMENTS_ALL, clearanceHeight, 0x20); } else { paint_util_set_segment_support_height(SEGMENTS_ALL, 0xFFFF, 0); @@ -204,7 +204,7 @@ void scenery_multiple_paint(uint8 direction, uint16 height, rct_map_element *map boxlength.z = ah; sub_98197C(image_id, 0, 0, boxlength.x, boxlength.y, ah, height, boxoffset.x, boxoffset.y, boxoffset.z, get_current_rotation()); if (entry->large_scenery.var_11 == 0xFF || direction == 1 || direction == 2) { - scenery_multiple_paint_supports(direction, height, mapElement, dword_F4387C, entry); + scenery_multiple_paint_supports(direction, height, mapElement, dword_F4387C, tile); return; } if (entry->large_scenery.flags & 0x4) { @@ -212,13 +212,13 @@ void scenery_multiple_paint(uint8 direction, uint16 height, rct_map_element *map if (entry->large_scenery.tiles[1].x_offset != (sint16)0xFFFF) { al = ((mapElement->properties.surface.terrain >> 2) - 1) & 3; if (al != direction) { - scenery_multiple_paint_supports(direction, height, mapElement, dword_F4387C, entry); + scenery_multiple_paint_supports(direction, height, mapElement, dword_F4387C, tile); return; } } rct_drawpixelinfo* dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); if (dpi->zoom_level > 1) { - scenery_multiple_paint_supports(direction, height, mapElement, dword_F4387C, entry); + scenery_multiple_paint_supports(direction, height, mapElement, dword_F4387C, tile); return; } // 6B8331: @@ -301,12 +301,12 @@ void scenery_multiple_paint(uint8 direction, uint16 height, rct_map_element *map } rct_drawpixelinfo* dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); if (dpi->zoom_level > 0) { - scenery_multiple_paint_supports(direction, height, mapElement, dword_F4387C, entry); + scenery_multiple_paint_supports(direction, height, mapElement, dword_F4387C, tile); return; } uint8 al = ((mapElement->properties.surface.terrain >> 2) - 1) & 3; if (al != direction) { - scenery_multiple_paint_supports(direction, height, mapElement, dword_F4387C, entry); + scenery_multiple_paint_supports(direction, height, mapElement, dword_F4387C, tile); return; } // Draw scrolling text: @@ -344,5 +344,5 @@ void scenery_multiple_paint(uint8 direction, uint16 height, rct_map_element *map uint16 scroll = (gCurrentTicks / 2) % string_width; sub_98199C(scrolling_text_setup(stringId, scroll, scrollMode), 0, 0, 1, 1, 21, height + 25, boxoffset.x, boxoffset.y, boxoffset.z, get_current_rotation()); - scenery_multiple_paint_supports(direction, height, mapElement, dword_F4387C, entry); + scenery_multiple_paint_supports(direction, height, mapElement, dword_F4387C, tile); }