/***************************************************************************** * Copyright (c) 2014 Ted John * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. * * This file is part of OpenRCT2. * * OpenRCT2 is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . *****************************************************************************/ #include #include "addresses.h" #include "config.h" #include "gfx.h" #include "map.h" #include "string_ids.h" #include "sprite.h" #include "sprites.h" #include "viewport.h" #include "window.h" #define RCT2_FIRST_VIEWPORT (RCT2_ADDRESS(RCT2_ADDRESS_VIEWPORT_LIST, rct_viewport)) #define RCT2_LAST_VIEWPORT (RCT2_GLOBAL(RCT2_ADDRESS_NEW_VIEWPORT_PTR, rct_viewport*) - 1) #define RCT2_NEW_VIEWPORT (RCT2_GLOBAL(RCT2_ADDRESS_NEW_VIEWPORT_PTR, rct_viewport*)) rct_viewport* g_viewport_list = RCT2_ADDRESS(RCT2_ADDRESS_VIEWPORT_LIST, rct_viewport); typedef struct paint_struct paint_struct; struct paint_struct{ uint32 image_id; // 0x00 uint32 var_04; uint16 attached_x; // 0x08 uint16 attached_y; // 0x0A uint8 var_0C; uint8 pad_0D; paint_struct* next_attached_ps; //0x0E uint8 pad_12[2]; uint16 x; // 0x14 uint16 y; // 0x16 uint8 pad_18[2]; uint8 var_1A; uint8 pad_1B; paint_struct* attached_ps; //0x1C paint_struct* var_20; paint_struct* var_24; uint8 sprite_type; //0x28 }; /** * This is not a viewport function. It is used to setup many variables for * multiple things. * rct2: 0x006E6EAC */ void viewport_init_all() { int i, d; rct_g1_element *g1_element; // Palette from sprites? d = 0; for (i = 4915; i < 4947; i++) { g1_element = &(RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[i]); *((int*)(0x0141FC44 + d)) = *((int*)(&g1_element->offset[0xF5])); *((int*)(0x0141FC48 + d)) = *((int*)(&g1_element->offset[0xF9])); *((int*)(0x0141FD44 + d)) = *((int*)(&g1_element->offset[0xFD])); d += 8; } // Setting up windows RCT2_GLOBAL(RCT2_ADDRESS_NEW_WINDOW_PTR, rct_window*) = g_window_list; RCT2_GLOBAL(0x01423604, sint32) = 0; // Setting up viewports for (i = 0; i < 9; i++) g_viewport_list[i].width = 0; RCT2_NEW_VIEWPORT = NULL; // ? RCT2_GLOBAL(0x009DE518, sint32) = 0; RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, sint8) = INPUT_STATE_RESET; RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWCLASS, rct_windowclass) = -1; RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, sint32) = -1; RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_NOT_SHOWN_TICKS, sint16) = -1; RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, sint16) = 0; RCT2_GLOBAL(0x009DEA50, sint16) = -1; RCT2_CALLPROC_EBPSAFE(0x006EE3C3); format_string((char*)0x0141FA44, STR_CANCEL, NULL); format_string((char*)0x0141F944, STR_OK, NULL); } /** * rct:0x006EB0C1 * x : ax * y : bx * z : cx * out_x : ax * out_y : bx * Converts between 3d point of a sprite to 2d coordinates for centering on that sprite */ void center_2d_coordinates(int x, int y, int z, int* out_x, int* out_y, rct_viewport* viewport){ int start_x = x; switch (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32)){ case 0: x = y - x; y = (y + start_x) / 2 - z; break; case 1: x = -y - x; y = (y - start_x) / 2 - z; break; case 2: x = -y + x; y = (-y - start_x) / 2 - z; break; case 3: x = y + x; y = (-y + start_x) / 2 - z; break; } *out_x = x - viewport->view_width/2; *out_y = y - viewport->view_height/2; } /** * * rct2: 0x006EB009 * x: ax * y: eax (top 16) * width: bx * height: ebx (top 16) * zoom: cl (8 bits) * center_x: edx lower 16 bits * center_y: edx upper 16 bits * center_z: ecx upper 16 bits * sprite: edx lower 16 bits * flags: edx top most 2 bits 0b_X1 for zoom clear see below for 2nd bit. * w: esi * * Viewport will look at sprite or at coordinates as specified in flags 0b_1X for sprite 0b_0X for coordinates */ void viewport_create(rct_window *w, int x, int y, int width, int height, int zoom, int center_x, int center_y, int center_z, char flags, sint16 sprite) { rct_viewport* viewport; for (viewport = g_viewport_list; viewport->width != 0; viewport++){ if (viewport >= RCT2_ADDRESS(RCT2_ADDRESS_NEW_VIEWPORT_PTR, rct_viewport)){ error_string_quit(0xFF000001, -1); } } viewport->x = x; viewport->y = y; viewport->width = width; viewport->height = height; if (!(flags & VIEWPORT_FOCUS_TYPE_COORDINATE)){ zoom = 0; } viewport->view_width = width << zoom; viewport->view_height = height << zoom; viewport->zoom = zoom; viewport->flags = 0; if (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_KEYBOARD_SHORTCUTS, uint8) & 1){ viewport->flags |= VIEWPORT_FLAG_GRIDLINES; } w->viewport = viewport; if (flags & VIEWPORT_FOCUS_TYPE_SPRITE){ w->viewport_target_sprite = sprite; rct_sprite* center_sprite = &g_sprite_list[sprite]; center_x = center_sprite->unknown.x; center_y = center_sprite->unknown.y; center_z = center_sprite->unknown.z; } else{ w->viewport_target_sprite = SPR_NONE; } int view_x, view_y; center_2d_coordinates(center_x, center_y, center_z, &view_x, &view_y, viewport); w->saved_view_x = view_x; w->saved_view_y = view_y; viewport->view_x = view_x; viewport->view_y = view_y; viewport_update_pointers(); //x &= 0xFFFF; //y &= 0xFFFF; //RCT2_CALLPROC_X(0x006EB009, (y << 16) | x, (height << 16) | width, zoom, edx, (int)w, 0, 0); } /** * * rct2: 0x006EE510 */ void viewport_update_pointers() { rct_viewport *viewport; rct_viewport **vp = RCT2_ADDRESS(RCT2_ADDRESS_NEW_VIEWPORT_PTR, rct_viewport*); if (*vp == NULL) *vp = g_viewport_list; for (viewport = g_viewport_list; viewport <= RCT2_NEW_VIEWPORT; viewport++) if (viewport->width != 0) *vp++ = viewport; *vp = NULL; } void sub_689174(sint16* x, sint16* y, sint16 *z, uint8 curr_rotation){ //RCT2_CALLFUNC_X(0x00689174, (int*)&x, (int*)&y, (int*)&z, &curr_rotation, (int*)&window, (int*)&viewport, &ebp); sint16 start_x = *x; sint16 start_y = *y; sint16 height = 0; switch (curr_rotation){ case 0: for (int i = 0; i < 6; ++i){ *x = start_y - start_x / 2 + height; *y = start_y + start_x / 2 + height; height = map_element_height((0xFFFF) & *x, (0xFFFF) & *y); } break; case 1: for (int i = 0; i < 6; ++i){ *x = -start_y - start_x / 2 - height; *y = start_y - start_x / 2 + height; height = map_element_height((0xFFFF) & *x, (0xFFFF) & *y); } break; case 2: for (int i = 0; i < 6; ++i){ *x = -start_y + start_x / 2 - height; *y = -start_y - start_x / 2 - height; height = map_element_height((0xFFFF) & *x, (0xFFFF) & *y); } break; case 3: for (int i = 0; i < 6; ++i){ *x = start_x / 2 + start_y + height; *y = start_x / 2 - start_y - height; height = map_element_height((0xFFFF) & *x, (0xFFFF) & *y); } break; } *z = height; } /** * * rct2: 0x006E7A3A */ void viewport_update_position(rct_window *window) { //RCT2_CALLPROC_X(0x006E7A3A, 0, 0, 0, 0, (int)window, 0, 0); RCT2_CALLPROC_X(window->event_handlers[WE_RESIZE], 0, 0, 0, 0, (int)window, 0, 0); rct_viewport* viewport = window->viewport; if (!viewport)return; if (window->viewport_target_sprite != -1){ rct_sprite* sprite = &g_sprite_list[window->viewport_target_sprite]; int height = map_element_height(0xFFFF & sprite->unknown.x, 0xFFFF & sprite->unknown.y) - 16; int underground = sprite->unknown.z < height; RCT2_CALLPROC_X(0x6E7A15, sprite->unknown.x, sprite->unknown.y, sprite->unknown.z, underground, (int)window, (int)viewport, 0); int center_x, center_y; center_2d_coordinates(sprite->unknown.x, sprite->unknown.y, sprite->unknown.z, ¢er_x, ¢er_y, window->viewport); RCT2_CALLPROC_X(0x6E7DE1, center_x, center_y, 0, 0, (int)window, (int)viewport, 0); window_invalidate(window);//Added to force a redraw. return; } sint16 x = viewport->view_width / 2 + window->saved_view_x; sint16 y = viewport->view_height / 2 + window->saved_view_y; sint16 z; int curr_rotation = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32); sub_689174(&x, &y, &z, curr_rotation); RCT2_CALLPROC_X(0x006E7A15, x, y, z, 0, (int)window, (int)viewport, 0); //Clamp to the map minimum value int at_map_edge = 0; if (x < MAP_MINIMUM_X_Y){ x = MAP_MINIMUM_X_Y; at_map_edge = 1; } if (y < MAP_MINIMUM_X_Y){ y = MAP_MINIMUM_X_Y; at_map_edge = 1; } //Clamp to the map maximum value (scenario specific) if (x > RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAXIMUM_X_Y, sint16)){ x = RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAXIMUM_X_Y, sint16); at_map_edge = 1; } if (y > RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAXIMUM_X_Y, sint16)){ y = RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAXIMUM_X_Y, sint16); at_map_edge = 1; } if (at_map_edge) { // The &0xFFFF is to prevent the sign extension messing the // function up. int z = map_element_height(x & 0xFFFF, y & 0xFFFF); int _2d_x, _2d_y; center_2d_coordinates(x, y, z, &_2d_x, &_2d_y, viewport); if (window->saved_view_x > 0){ _2d_x = min(_2d_x, window->saved_view_x); } else{ _2d_x = max(_2d_x, window->saved_view_x); } if (window->saved_view_y > 0){ _2d_y = min(_2d_y, window->saved_view_y); } else{ _2d_y = max(_2d_y, window->saved_view_y); } window->saved_view_x = _2d_x; window->saved_view_y = _2d_y; } x = window->saved_view_x; y = window->saved_view_y; if (window->flags & WF_SCROLLING_TO_LOCATION){ // Moves the viewport if focusing in on an item uint8 flags = 0; x -= viewport->view_x; if (x < 0){ x = -x; flags |= 1; } y -= viewport->view_y; if (y < 0){ y = -y; flags |= 2; } x = (x + 7)/8; y = (y + 7)/8; //If we are at the final zoom position if (!x && !y){ window->flags &= ~WF_SCROLLING_TO_LOCATION; } if (flags & 1){ x = -x; } if (flags & 2){ y = -y; } x += viewport->view_x; y += viewport->view_y; } RCT2_CALLPROC_X(0x6E7DE1, x, y, 0, 0, (int)window, (int)viewport, 0); } void viewport_paint(rct_viewport* viewport, rct_drawpixelinfo* dpi, int left, int top, int right, int bottom); /** * * rct2: 0x00685C02 * ax: left * bx: top * dx: right * esi: viewport * edi: dpi * ebp: bottom */ void viewport_render(rct_drawpixelinfo *dpi, rct_viewport *viewport, int left, int top, int right, int bottom) { if (right <= viewport->x) return; if (bottom <= viewport->y) return; if (left >= viewport->x + viewport->width )return; if (top >= viewport->y + viewport->height )return; left = max(left - viewport->x, 0); right = min(right - viewport->x, viewport->width); top = max(top - viewport->y, 0); bottom = min(bottom - viewport->y, viewport->height); left <<= viewport->zoom; right <<= viewport->zoom; top <<= viewport->zoom; bottom <<= viewport->zoom; left += viewport->view_x; right += viewport->view_x; top += viewport->view_y; bottom += viewport->view_y; int height = bottom - top; if (height > 384){ //Paint viewport_paint(viewport, dpi, left, top, right, top + 384); top += 384; } //Paint viewport_paint(viewport, dpi, left, top, right, bottom); } /** * * rct2: 0x0068615B * ebp: ebp */ void sub_0x68615B(int ebp){ RCT2_GLOBAL(0xEE7888, uint32) = ebp; RCT2_GLOBAL(0xF1AD28, uint32) = 0; RCT2_GLOBAL(0xF1AD2C, uint32) = 0; uint8* edi = RCT2_ADDRESS(0xF1A50C, uint8); memset(edi, 0, 2048); RCT2_GLOBAL(0xF1AD0C, sint32) = -1; RCT2_GLOBAL(0xF1AD10, uint32) = 0; RCT2_GLOBAL(0xF1AD20, uint32) = 0; RCT2_GLOBAL(0xF1AD24, uint32) = 0; } /*** * * rct2: 0x00688596 * Part of 0x688485 */ void paint_attached_ps(paint_struct* ps, paint_struct* attached_ps, rct_drawpixelinfo* dpi){ for (; attached_ps; attached_ps = attached_ps->next_attached_ps){ sint16 x = attached_ps->attached_x + ps->x; sint16 y = attached_ps->attached_y + ps->y; int image_id = attached_ps->image_id; if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_VIEWPORT_FLAGS, uint16) & VIEWPORT_FLAG_SEETHROUGH_RIDES){ if (ps->sprite_type == 3){ if (image_id & 0x40000000){ image_id &= 0x7FFFF; image_id |= 0x41880000; } } } if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_VIEWPORT_FLAGS, uint16) & VIEWPORT_FLAG_SEETHROUGH_SCENERY){ if (ps->sprite_type == 5){ if (image_id & 0x40000000){ image_id &= 0x7FFFF; image_id |= 0x41880000; } } } if (!(attached_ps->var_0C & 1)){ gfx_draw_sprite(dpi, image_id, x, y, ps->var_04); } else{ RCT2_CALLPROC_X(0x00681DE2, 0, image_id, x, y, 0, (int)dpi, attached_ps->var_04); } } } void sub_688485(){ //RCT2_CALLPROC_EBPSAFE(0x688485); //return; rct_drawpixelinfo* dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); paint_struct* ps = RCT2_GLOBAL(0xEE7884, paint_struct*); paint_struct* previous_ps = ps->var_24; for (ps = ps->var_24; ps;){ sint16 x = ps->x; sint16 y = ps->y; if (ps->sprite_type == 2){ if (dpi->zoom_level >= 1){ x &= 0xFFFE; y &= 0xFFFE; if (dpi->zoom_level >= 2){ x &= 0xFFFC; y &= 0xFFFC; } } } int image_id = ps->image_id; if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_VIEWPORT_FLAGS, uint16) & VIEWPORT_FLAG_SEETHROUGH_RIDES){ if (ps->sprite_type == 3){ if (!(image_id & 0x40000000)){ image_id &= 0x7FFFF; image_id |= 0x41880000; } } } if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_VIEWPORT_FLAGS, uint16) & VIEWPORT_FLAG_UNDERGROUND_INSIDE){ if (ps->sprite_type == 9){ if (!(image_id & 0x40000000)){ image_id &= 0x7FFFF; image_id |= 0x41880000; } } } if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_VIEWPORT_FLAGS, uint16) & VIEWPORT_FLAG_SEETHROUGH_SCENERY){ if (ps->sprite_type == 10 || ps->sprite_type == 12 || ps->sprite_type == 9 || ps->sprite_type == 5){ if (!(image_id & 0x40000000)){ image_id &= 0x7FFFF; image_id |= 0x41880000; } } } if (!(ps->var_1A & 1)) gfx_draw_sprite(dpi, image_id, x, y, ps->var_04); else RCT2_CALLPROC_X(0x00681DE2, 0, image_id, x, y, 0, (int)dpi, ps->var_04); if (ps->var_20 != 0){ ps = ps->var_20; continue; } paint_attached_ps(ps, ps->attached_ps, dpi); ps = previous_ps->var_24; previous_ps = ps; } } int sub_0x686806(rct_sprite* sprite, int eax, int ecx, int edx){ int ebp = (eax >> 8) & 0xFF; edx <<= 16; ebp += RCT2_GLOBAL(0x9DEA56, uint16); RCT2_GLOBAL(0xF1AD28, uint32) = 0; RCT2_GLOBAL(0xF1AD2C, uint32) = 0; edx = (edx >> 16) | (ebp << 16); ebp = RCT2_GLOBAL(0xEE7888, uint32); if ((uint32)ebp >= RCT2_GLOBAL(0xEE7880, uint32)) return 1; //686840 not finished return 0; } /** * Litter Paint Setup?? * rct2: 0x006736FC */ void sub_0x6736FC(rct_litter* litter, int ebx, int edx){ rct_drawpixelinfo* dpi; dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); if (dpi->zoom_level != 0)return; //If zoomed at all no litter drawn int ebp = litter->var_01; //push litter ebx >>= 3; ebx &= RCT2_ADDRESS(0x97EF6C, uint32)[ebp * 2 + 1]; ebx += RCT2_ADDRESS(0x97EF6C, uint32)[ebp * 2]; int ecx = 0; int edi = 4; int esi = 4; int eax = 0xFF00; RCT2_GLOBAL(0x9DEA52, uint16) = 0xFFFC; RCT2_GLOBAL(0x9DEA54, uint16) = 0xFFFC; RCT2_GLOBAL(0x9DEA56, uint16) = edx + 2; switch (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION,uint32)){ case 0: //0x686806 break; case 1: //0x6869b2 break; case 2: //0x686b6f break; case 3: //0x686d31 break; } } /** * Paint Quadrant * rct2: 0x0069E8B0 */ void sub_0x69E8B0(uint32 eax, uint32 ecx){ uint32 _eax = eax, _ecx = ecx; rct_drawpixelinfo* dpi; if (RCT2_GLOBAL(0x9DEA6F,uint8) & 1) return; dpi = RCT2_GLOBAL(0x140E9A8,rct_drawpixelinfo*); if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_VIEWPORT_FLAGS, uint16) & 0x4000)return; if (dpi->zoom_level > 2) return; if (eax > 0x2000)return; if (ecx > 0x2000)return; //push eax, ecx eax = (eax&0x1FE0)<<3 | (ecx>>5); int sprite_idx = RCT2_ADDRESS(0xF1EF60, uint16)[eax]; if (sprite_idx == SPRITE_INDEX_NULL) return; for (rct_sprite* spr = &g_sprite_list[sprite_idx]; sprite_idx != SPRITE_INDEX_NULL; sprite_idx = spr->unknown.var_02){ spr = &g_sprite_list[sprite_idx]; dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); if (dpi->y + dpi->height <= spr->unknown.var_18) continue; if (spr->unknown.var_1C <= dpi->y)continue; if (dpi->x + dpi->width <= spr->unknown.var_16)continue; if (spr->unknown.var_1A <= dpi->x)continue; int ebx = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32); RCT2_GLOBAL(0x9DE578, uint32) = (uint32)spr; int ebp = spr->unknown.sprite_identifier; ebx <<= 3; eax = spr->unknown.x; ebx += spr->unknown.sprite_direction; ecx = spr->unknown.y; ebx &= 0x1F; RCT2_GLOBAL(0x9DE568, uint16) = spr->unknown.x; RCT2_GLOBAL(0x9DE570, uint8) = 2; RCT2_GLOBAL(0x9DE56C, uint16) = spr->unknown.y; int edx = spr->unknown.z; switch (spr->unknown.sprite_identifier){ case SPRITE_IDENTIFIER_VEHICLE: RCT2_CALLPROC_X(0x6D4244, eax, ebx, ecx, edx, (int)spr, (int)dpi, ebp); break; case SPRITE_IDENTIFIER_PEEP: RCT2_CALLPROC_X(0x68F0FB, eax, ebx, ecx, edx, (int)spr, (int)dpi, ebp); break; case SPRITE_IDENTIFIER_FLOATING_TEXT: RCT2_CALLPROC_X(0x672AC9, eax, ebx, ecx, edx, (int)spr, (int)dpi, ebp); break; case SPRITE_IDENTIFIER_LITTER: RCT2_CALLPROC_X(0x6736FC, eax, ebx, ecx, edx, (int)spr, (int)dpi, ebp); break; //I am pretty sure there are no other sprite identifier types } //RCT2_CALLPROC_X(RCT2_ADDRESS(0x98BC40,uint32)[spr->unknown.sprite_identifier], eax, ebx, ecx, edx, (int)spr, (int)dpi, ebp); } //RCT2_CALLPROC_X(0x69E8B0, _eax, 0, _ecx, 0, 0, 0, 0); //return; } /** * * rct2: 0x0068B6C2 */ void sub_0x68B6C2(){ rct_drawpixelinfo* dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); sint16 ax, bx, cx, dx; switch (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32)){ case 0: ax = dpi->y; bx = dpi->x; ax -= 16; bx &= 0xFFE0; ax &= 0xFFE0; bx >>= 1; cx = ax; ax -= bx; cx += bx; ax &= 0xFFE0; cx &= 0xFFE0; dx = dpi->height; dx += 2128; dx >>= 5; for (int i = dx; i > 0; --i){ RCT2_CALLPROC_X(0x68B35F, ax, 0, cx, 0, 0, 0, 0); sub_0x69E8B0(ax, cx); cx += 0x20; ax -= 0x20; sub_0x69E8B0(ax, cx); ax += 0x20; RCT2_CALLPROC_X(0x68B35F, ax, 0, cx, 0, 0, 0, 0); sub_0x69E8B0(ax, cx); ax += 0x20; cx -= 0x20; sub_0x69E8B0(ax, cx); cx += 0x20; } break; case 1: ax = dpi->y; bx = dpi->x; ax -= 0x10; bx &= 0xFFE0; ax &= 0xFFE0; bx >>= 1; cx = ax; ax = -ax; ax -= bx; cx -= bx; cx -= 0x10; ax &= 0xFFE0; cx &= 0xFFE0; dx = dpi->height; dx += 0x860; dx >>= 5; for (int i = dx; i > 0; i--){ RCT2_CALLPROC_X(0x68B35F, ax, 0, cx, 0, 0, 0, 0); sub_0x69E8B0(ax, cx); ax -= 0x20; cx -= 0x20; sub_0x69E8B0(ax, cx); cx += 0x20; RCT2_CALLPROC_X(0x68B35F, ax, 0, cx, 0, 0, 0, 0); sub_0x69E8B0(ax, cx); ax += 0x20; cx += 0x20; sub_0x69E8B0(ax, cx); ax -= 0x20; } break; case 2: ax = dpi->y; bx = dpi->x; ax -= 0x10; bx &= 0xFFE0; ax &= 0xFFE0; bx >>= 1; ax = -ax; cx = ax; ax += bx; cx -= bx; ax &= 0xFFE0; cx &= 0xFFE0; dx = dpi->height; dx += 0x860; dx >>= 5; for (int i = dx; i > 0; i--){ RCT2_CALLPROC_X(0x68B35F, ax, 0, cx, 0, 0, 0, 0); sub_0x69E8B0(ax, cx); ax += 0x20; cx -= 0x20; sub_0x69E8B0(ax, cx); ax -= 0x20; RCT2_CALLPROC_X(0x68B35F, ax, 0, cx, 0, 0, 0, 0); sub_0x69E8B0(ax, cx); ax -= 0x20; cx += 0x20; sub_0x69E8B0(ax, cx); cx -= 0x20; } break; case 3: ax = dpi->y; bx = dpi->x; ax -= 0x10; bx &= 0xFFE0; ax &= 0xFFE0; bx >>= 1; cx = ax; ax += bx; cx = -cx; cx += bx; cx -= 0x10; ax &= 0xFFE0; cx &= 0xFFE0; dx = dpi->height; dx += 0x860; dx >>= 5; for (int i = dx; i > 0; i--){ RCT2_CALLPROC_X(0x68B35F, ax, 0, cx, 0, 0, 0, 0); sub_0x69E8B0(ax, cx); ax += 0x20; cx += 0x20; sub_0x69E8B0(ax, cx); cx -= 0x20; RCT2_CALLPROC_X(0x68B35F, ax, 0, cx, 0, 0, 0, 0); sub_0x69E8B0(ax, cx); ax -= 0x20; cx -= 0x20; sub_0x69E8B0(ax, cx); ax += 0x20; } break; } } /** * * rct2:0x00685CBF * eax: left * ebx: top * edx: right * esi: viewport * edi: dpi * ebp: bottom */ void viewport_paint(rct_viewport* viewport, rct_drawpixelinfo* dpi, int left, int top, int right, int bottom){ //RCT2_CALLPROC_X(0x00685CBF, left, top, 0, right, (int)viewport, (int)dpi, bottom); //return; RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_VIEWPORT_FLAGS, uint16) = viewport->flags; RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_ZOOM, uint16) = viewport->zoom; uint16 width = right - left; uint16 height = bottom - top; uint16 bitmask = 0xFFFF & (0xFFFF << viewport->zoom); width &= bitmask; height &= bitmask; left &= bitmask; top &= bitmask; RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_X, uint16) = left; RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_Y, uint16) = top; RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_WIDTH, uint16) = width; RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_HEIGHT, uint16) = height; width >>= viewport->zoom; RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_PITCH, uint16) = (dpi->width + dpi->pitch) - width; int x = (sint16)(left - (sint16)(viewport->view_x & bitmask)); x >>= viewport->zoom; x += viewport->x; int y = (sint16)(top - (sint16)(viewport->view_y & bitmask)); y >>= viewport->zoom; y += viewport->y; uint8* bits_pointer = x - dpi->x + (y - dpi->y)*(dpi->width + dpi->pitch) + dpi->bits; RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_BITS_PTR, uint8*) = bits_pointer; rct_drawpixelinfo* dpi2 = RCT2_ADDRESS(RCT2_ADDRESS_VIEWPORT_DPI, rct_drawpixelinfo); dpi2->y = RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_Y, uint16); dpi2->height = RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_HEIGHT, uint16); dpi2->zoom_level = (uint8)RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_ZOOM, uint16); //Splits the screen into 32 pixel columns and renders them. for (x = RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_X, uint16) & 0xFFFFFFE0; x < RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_X, uint16) + RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_WIDTH, uint16); x += 32){ int start_x = RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_X, uint16); int width_col = RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_WIDTH, uint16); bits_pointer = RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_BITS_PTR, uint8*); int pitch = RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_PITCH, uint16); int zoom = RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_ZOOM, uint16); if (x >= start_x){ int left_pitch = x - start_x; width_col -= left_pitch; bits_pointer += left_pitch >> zoom; pitch += left_pitch >> zoom; start_x = x; } int paint_right = start_x + width_col; if (paint_right >= x + 32){ int right_pitch = paint_right - x - 32; paint_right -= right_pitch; pitch += right_pitch >> zoom; } width_col = paint_right - start_x; dpi2->x = start_x; dpi2->width = width_col; dpi2->bits = bits_pointer; dpi2->pitch = pitch; if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_VIEWPORT_FLAGS, uint16) & 0x3001){ uint8 colour = 0x0A; if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_VIEWPORT_FLAGS, uint16) & 0x4000){ colour = 0; } gfx_clear(dpi2, colour); } RCT2_GLOBAL(0xEE7880, uint32) = 0xF1A4CC; RCT2_GLOBAL(0x140E9A8, uint32) = (int)dpi2; int ebp = 0, ebx = 0, esi = 0, ecx = 0; sub_0x68615B(0xEE788C); //Memory copy sub_0x68B6C2(); //RCT2_CALLPROC_X(0x68B6C2, 0, 0, 0, 0, 0, 0, 0); //Big function call 4 rotation versions RCT2_CALLPROC_X(0x688217, start_x, ebx, ecx, (int)bits_pointer, esi, (int)dpi2, ebp); //Move memory sub_688485(); //RCT2_CALLPROC_EBPSAFE(0x688485); //Big function call int weather_colour = RCT2_ADDRESS(0x98195C, uint32)[RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WEATHER_GLOOM, uint8)]; if ((weather_colour != -1) && (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_VIEWPORT_FLAGS, uint16) & 0x4000) && (RCT2_GLOBAL(0x9DEA6F, uint8) & 1)){ dpi2 = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); gfx_fill_rect(dpi2, dpi2->x, dpi2->y, dpi2->width + dpi2->x - 1, dpi2->height + dpi2->y - 1, weather_colour); } RCT2_CALLPROC_EBPSAFE(0x6860C3); //string related } //RCT2_CALLPROC_X(0x00685CBF, left, top, 0, right, (int)viewport, (int)dpi, bottom); } /** * * rct2: 0x0068958D */ void screen_pos_to_map_pos(short *x, short *y) { int eax, ebx, ecx, edx, esi, edi, ebp; eax = *x; ebx = *y; RCT2_CALLFUNC_X(0x0068958D, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); *x = eax & 0xFFFF; *y = ebx & 0xFFFF; } /** * * rct2: 0x00664689 */ void show_gridlines() { rct_window *mainWindow; if (RCT2_GLOBAL(0x009E32B0, uint8) == 0) { if ((mainWindow = window_get_main()) != NULL) { if (!(mainWindow->viewport->flags & VIEWPORT_FLAG_GRIDLINES)) { mainWindow->viewport->flags |= VIEWPORT_FLAG_GRIDLINES; window_invalidate(mainWindow); } } } RCT2_GLOBAL(0x009E32B0, uint8)++; } /** * * rct2: 0x006646B4 */ void hide_gridlines() { rct_window *mainWindow; RCT2_GLOBAL(0x009E32B0, uint8)--; if (RCT2_GLOBAL(0x009E32B0, uint8) == 0) { if ((mainWindow = window_get_main()) != NULL) { if (!(RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) & CONFIG_FLAG_ALWAYS_SHOW_GRIDLINES)) { mainWindow->viewport->flags &= ~VIEWPORT_FLAG_GRIDLINES; window_invalidate(mainWindow); } } } } /** * * rct2: 0x00664E8E */ void show_land_rights() { rct_window *mainWindow; if (RCT2_GLOBAL(0x009E32B2, uint8) != 0) { if ((mainWindow = window_get_main()) != NULL) { if (!(mainWindow->viewport->flags & VIEWPORT_FLAG_LAND_OWNERSHIP)) { mainWindow->viewport->flags |= VIEWPORT_FLAG_LAND_OWNERSHIP; window_invalidate(mainWindow); } } } RCT2_GLOBAL(0x009E32B2, uint8)++; } /** * * rct2: 0x00664E8E */ void hide_land_rights() { rct_window *mainWindow; RCT2_GLOBAL(0x009E32B2, uint8)--; if (RCT2_GLOBAL(0x009E32B2, uint8) == 0) { if ((mainWindow = window_get_main()) != NULL) { if (mainWindow->viewport->flags & VIEWPORT_FLAG_LAND_OWNERSHIP) { mainWindow->viewport->flags &= ~VIEWPORT_FLAG_LAND_OWNERSHIP; window_invalidate(mainWindow); } } } } /** * * rct2: 0x00664EDD */ void show_construction_rights() { rct_window *mainWindow; if (RCT2_GLOBAL(0x009E32B3, uint8) != 0) { if ((mainWindow = window_get_main()) != NULL) { if (!(mainWindow->viewport->flags & VIEWPORT_FLAG_CONSTRUCTION_RIGHTS)) { mainWindow->viewport->flags |= VIEWPORT_FLAG_CONSTRUCTION_RIGHTS; window_invalidate(mainWindow); } } } RCT2_GLOBAL(0x009E32B3, uint8)++; } /** * * rct2: 0x00664F08 */ void hide_construction_rights() { rct_window *mainWindow; RCT2_GLOBAL(0x009E32B3, uint8)--; if (RCT2_GLOBAL(0x009E32B3, uint8) == 0) { if ((mainWindow = window_get_main()) != NULL) { if (mainWindow->viewport->flags & VIEWPORT_FLAG_CONSTRUCTION_RIGHTS) { mainWindow->viewport->flags &= ~VIEWPORT_FLAG_CONSTRUCTION_RIGHTS; window_invalidate(mainWindow); } } } } /** * * rct2: 0x006CB70A */ void viewport_set_visibility(uint8 mode) { rct_window* window = window_get_main(); if(window != NULL) { rct_viewport* edi = window->viewport; uint32 invalidate = 0; switch(mode) { case 0: { //Set all these flags to 0, and invalidate if any were active uint16 mask = VIEWPORT_FLAG_UNDERGROUND_INSIDE | VIEWPORT_FLAG_SEETHROUGH_RIDES | VIEWPORT_FLAG_SEETHROUGH_SCENERY | VIEWPORT_FLAG_INVISIBLE_SUPPORTS | VIEWPORT_FLAG_LAND_HEIGHTS | VIEWPORT_FLAG_TRACK_HEIGHTS | VIEWPORT_FLAG_PATH_HEIGHTS | VIEWPORT_FLAG_INVISIBLE_PEEPS | VIEWPORT_FLAG_HIDE_BASE | VIEWPORT_FLAG_HIDE_VERTICAL; invalidate += edi->flags & mask; edi->flags &= ~mask; break; } case 1: //6CB79D case 4: //6CB7C4 //Set underground on, invalidate if it was off invalidate += !(edi->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE); edi->flags |= VIEWPORT_FLAG_UNDERGROUND_INSIDE; break; case 2: //6CB7EB //Set track heights on, invalidate if off invalidate += !(edi->flags & VIEWPORT_FLAG_TRACK_HEIGHTS); edi->flags |= VIEWPORT_FLAG_TRACK_HEIGHTS; break; case 3: //6CB7B1 case 5: //6CB7D8 //Set underground off, invalidate if it was on invalidate += edi->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE; edi->flags &= ~((uint16)VIEWPORT_FLAG_UNDERGROUND_INSIDE); break; } if (invalidate != 0) window_invalidate(window); } }