1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-16 03:23:15 +01:00

Merge pull request #3702 from zsilencer/paint-setup/scenery_multiple_paint

Decompile scenery_multiple_paint
This commit is contained in:
Ted John
2016-05-23 08:09:38 +01:00
5 changed files with 351 additions and 11 deletions

View File

@@ -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;

View File

@@ -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)

View File

@@ -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;
}
}

View File

@@ -15,9 +15,334 @@
#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_large_scenery_tile *tile)
{
if (tile->var_7 & 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 (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);
}
paint_util_set_general_support_height(clearanceHeight, 0x20);
}
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;
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 utf8 *str, rct_large_scenery_text *text)
{
int height = 0;
uint32 codepoint;
while ((codepoint = utf8_get_next(str, &str)) != 0) {
height += scenery_multiple_sign_get_glyph(text, codepoint)->height;
}
return height;
}
const utf8 *scenery_multiple_sign_fit_text(const utf8 *str, rct_large_scenery_text *text, bool height)
{
static utf8 fitStr[32] = {0};
utf8 *fitStrEnd = fitStr;
strncpy(fitStr, str, sizeof(fitStr) - 1);
int w = 0;
uint32 codepoint;
while (w <= text->max_width && (codepoint = utf8_get_next(fitStrEnd, &fitStrEnd)) != 0) {
if (height) {
w += scenery_multiple_sign_get_glyph(text, codepoint)->height;
} else {
w += scenery_multiple_sign_get_glyph(text, codepoint)->width;
}
}
*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 utf8 *str, rct_large_scenery_text *text, int textImage, int textColour, uint8 direction, int y_offset)
{
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);
if (!(text->var_C & 0x1)) {
// sign is horizontal, center text:
x_offset -= (width / 2);
acc -= (width / 2);
}
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;
} 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 & 1)) {
glyph_type += 2;
}
} else {
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, -div_to_minus_infinity(acc, 2));
} else {
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 += scenery_multiple_sign_get_glyph(text, codepoint)->width;
acc += scenery_multiple_sign_get_glyph(text, codepoint)->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;
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;
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) {
gPaintInteractionType = 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, tile);
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, tile);
return;
}
}
rct_drawpixelinfo* dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*);
if (dpi->zoom_level > 1) {
scenery_multiple_paint_supports(direction, height, mapElement, dword_F4387C, tile);
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 * 2);
if (text->var_C & 0x1) {
// Draw vertical sign:
y_offset += 1;
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);
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 += scenery_multiple_sign_get_glyph(text, codepoint)->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 -= scenery_multiple_sign_get_glyph(text, 'A')->height + 1;
utf8 *src = signString;
for (int i = 0; i < 2; i++) {
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;
uint32 codepoint = utf8_get_next(src, &src);
do {
w += scenery_multiple_sign_get_glyph(text, codepoint)->width;
if (codepoint == ' ') {
spacesrc = src;
spacedst = dst;
}
} 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 += (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);
}
} 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, tile);
return;
}
uint8 al = ((mapElement->properties.surface.terrain >> 2) - 1) & 3;
if (al != direction) {
scenery_multiple_paint_supports(direction, height, mapElement, dword_F4387C, tile);
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, tile);
}

View File

@@ -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;