Remove focus union and replace with typed focus (#15426)

* Remove focus union and replace with typed focus

This if for the NSF to allow for CoordsXYZ

* Remove legacy structures

* Rework viewport_create to deduplicate logic

* Simplify yet further

* Apply review comments

* Remove intermediate
This commit is contained in:
Duncan 2021-09-18 20:34:38 +01:00 committed by GitHub
parent c05068e8d1
commit fa57b6aea0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 140 additions and 270 deletions

View File

@ -274,11 +274,7 @@ rct_window* WindowCreate(
w->min_height = height;
w->max_height = height;
w->viewport_focus_coordinates.var_480 = 0;
w->viewport_focus_coordinates.x = 0;
w->viewport_focus_coordinates.y = 0;
w->viewport_focus_coordinates.z = 0;
w->viewport_focus_coordinates.rotation = 0;
w->focus2 = std::nullopt;
w->page = 0;
w->var_48C = 0;
w->var_492 = 0;

View File

@ -786,12 +786,8 @@ namespace OpenRCT2::Ui::Windows
auto wheight = viewportWidget->height() - 1;
if (viewport == nullptr)
{
auto mapX = 0;
auto mapY = 0;
auto mapZ = 0;
viewport_create(
this, { left, top }, wwidth, wheight, 0, { mapX, mapY, mapZ }, VIEWPORT_FOCUS_TYPE_COORDINATE,
SPRITE_INDEX_NULL);
const auto focus = Focus2(CoordsXYZ(0, 0, 0));
viewport_create(this, { left, top }, wwidth, wheight, focus);
flags |= WF_NO_SCROLLING;
Invalidate();
}

View File

@ -79,9 +79,10 @@ private:
void CreateViewport()
{
rct_widget* viewportWidget = &window_banner_widgets[WIDX_VIEWPORT];
const auto focus = Focus2(_bannerViewPos);
viewport_create(
this, windowPos + ScreenCoordsXY{ viewportWidget->left + 1, viewportWidget->top + 1 },
(viewportWidget->width()) - 1, (viewportWidget->height()) - 1, 0, _bannerViewPos, 0, SPRITE_INDEX_NULL);
(viewportWidget->width()) - 1, (viewportWidget->height()) - 1, focus);
if (viewport != nullptr)
viewport->flags = gConfigGeneral.always_show_gridlines ? VIEWPORT_FLAG_GRIDLINES : 0;

View File

@ -40,7 +40,8 @@ rct_window* window_editor_main_open()
&window_editor_main_events, WC_MAIN_WINDOW, WF_STICK_TO_BACK);
window->widgets = window_editor_main_widgets;
viewport_create(window, window->windowPos, window->width, window->height, 0, { 0x0FFF, 0x0FFF, 0 }, 0x1, SPRITE_INDEX_NULL);
const auto focus = Focus2(CoordsXYZ(0x0FFF, 0x0FFF, 0));
viewport_create(window, window->windowPos, window->width, window->height, focus);
window->viewport->flags |= 0x0400;
gCurrentRotation = 0;

View File

@ -398,7 +398,6 @@ rct_window* window_guest_open(Peep* peep)
window->enabled_widgets = window_guest_page_enabled_widgets[0];
window->number = peep->sprite_index;
window->page = 0;
window->viewport_focus_coordinates.y = 0;
window->frame_no = 0;
window->list_information_type = 0;
window->picked_peep_frame = 0;
@ -410,8 +409,6 @@ rct_window* window_guest_open(Peep* peep)
window->max_height = 450;
window->no_list_items = 0;
window->selected_list_item = -1;
window->viewport_focus_coordinates.y = -1;
}
window->page = 0;
@ -730,16 +727,12 @@ void window_guest_viewport_init(rct_window* w)
return;
}
auto focus = viewport_update_smart_guest_follow(w, peep);
viewport_update_smart_guest_follow(w, peep);
bool reCreateViewport = false;
uint16_t origViewportFlags{};
if (w->viewport != nullptr)
{
// Check all combos, for now skipping y and rot
if (focus.coordinate.x == w->viewport_focus_coordinates.x
&& (focus.coordinate.y & VIEWPORT_FOCUS_Y_MASK) == w->viewport_focus_coordinates.y
&& focus.coordinate.z == w->viewport_focus_coordinates.z
&& focus.coordinate.rotation == w->viewport_focus_coordinates.rotation)
if (w->focus2.has_value())
return;
origViewportFlags = w->viewport->flags;
@ -750,11 +743,6 @@ void window_guest_viewport_init(rct_window* w)
window_event_invalidate_call(w);
w->viewport_focus_coordinates.x = focus.coordinate.x;
w->viewport_focus_coordinates.y = focus.coordinate.y;
w->viewport_focus_coordinates.z = focus.coordinate.z;
w->viewport_focus_coordinates.rotation = focus.coordinate.rotation;
if (peep->State != PeepState::Picked && w->viewport == nullptr)
{
auto view_widget = &w->widgets[WIDX_VIEWPORT];
@ -762,10 +750,7 @@ void window_guest_viewport_init(rct_window* w)
int32_t width = view_widget->width() - 1;
int32_t height = view_widget->height() - 1;
viewport_create(
w, screenPos, width, height, 0,
{ focus.coordinate.x, focus.coordinate.y & VIEWPORT_FOCUS_Y_MASK, focus.coordinate.z },
focus.sprite.type & VIEWPORT_FOCUS_TYPE_MASK, focus.sprite.sprite_id);
viewport_create(w, screenPos, width, height, w->focus2.value());
if (w->viewport != nullptr && reCreateViewport)
{
w->viewport->flags = origViewportFlags;

View File

@ -41,7 +41,8 @@ rct_window* window_main_open()
WF_STICK_TO_BACK);
window->widgets = window_main_widgets;
viewport_create(window, window->windowPos, window->width, window->height, 0, { 0x0FFF, 0x0FFF, 0 }, 0x1, SPRITE_INDEX_NULL);
const auto focus = Focus2(CoordsXYZ(0x0FFF, 0x0FFF, 0));
viewport_create(window, window->windowPos, window->width, window->height, focus);
window->viewport->flags |= VIEWPORT_FLAG_SOUND_ON;
gCurrentRotation = 0;
gShowGridLinesRefCount = 0;

View File

@ -415,7 +415,6 @@ static rct_window* window_park_open()
w->enabled_widgets = window_park_page_enabled_widgets[WINDOW_PARK_PAGE_ENTRANCE];
w->number = 0;
w->page = WINDOW_PARK_PAGE_ENTRANCE;
w->viewport_focus_coordinates.y = 0;
w->frame_no = 0;
w->list_information_type = std::numeric_limits<uint16_t>::max();
w->numberOfStaff = -1;
@ -459,8 +458,6 @@ rct_window* window_park_entrance_open()
if (window == nullptr)
{
window = window_park_open();
window->viewport_focus_coordinates.y = -1;
window->viewport_focus_coordinates.x = -1;
}
window->page = WINDOW_PARK_PAGE_ENTRANCE;
@ -738,22 +735,16 @@ static void window_park_entrance_paint(rct_window* w, rct_drawpixelinfo* dpi)
*/
static void window_park_init_viewport(rct_window* w)
{
int32_t x, y, z, r, xy, zr, viewportFlags;
x = y = z = r = xy = zr = 0;
int32_t viewportFlags;
if (w->page != WINDOW_PARK_PAGE_ENTRANCE)
return;
std::optional<Focus2> focus = std::nullopt;
if (!gParkEntrances.empty())
{
const auto& entrance = gParkEntrances[0];
x = entrance.x + 16;
y = entrance.y + 16;
z = entrance.z + 32;
r = get_current_rotation();
xy = IMAGE_TYPE_TRANSPARENT | (y << 16) | x;
zr = (z << 16) | (r << 8);
focus = Focus2(CoordsXYZ{ entrance.x + 16, entrance.y + 16, entrance.z + 32 });
}
if (w->viewport == nullptr)
@ -769,13 +760,9 @@ static void window_park_init_viewport(rct_window* w)
// Call invalidate event
window_event_invalidate_call(w);
w->viewport_focus_coordinates.x = x;
w->viewport_focus_coordinates.y = y;
w->viewport_focus_sprite.type |= VIEWPORT_FOCUS_TYPE_COORDINATE;
w->viewport_focus_coordinates.z = z;
w->viewport_focus_coordinates.rotation = r;
w->focus2 = focus;
if (zr != 0xFFFF)
if (focus.has_value())
{
// Create viewport
if (w->viewport == nullptr)
@ -783,8 +770,7 @@ static void window_park_init_viewport(rct_window* w)
rct_widget* viewportWidget = &window_park_entrance_widgets[WIDX_VIEWPORT];
viewport_create(
w, w->windowPos + ScreenCoordsXY{ viewportWidget->left + 1, viewportWidget->top + 1 },
viewportWidget->width() - 1, viewportWidget->height() - 1, 0, { x, y, z },
w->viewport_focus_sprite.type & VIEWPORT_FOCUS_TYPE_MASK, SPRITE_INDEX_NULL);
viewportWidget->width() - 1, viewportWidget->height() - 1, focus.value());
w->flags |= (1 << 2);
w->Invalidate();
}
@ -811,8 +797,6 @@ rct_window* window_park_rating_open()
if (window == nullptr)
{
window = window_park_open();
window->viewport_focus_coordinates.x = -1;
window->viewport_focus_coordinates.y = -1;
}
if (input_test_flag(INPUT_FLAG_TOOL_ACTIVE))
@ -947,8 +931,6 @@ rct_window* window_park_guests_open()
if (window == nullptr)
{
window = window_park_open();
window->viewport_focus_coordinates.x = -1;
window->viewport_focus_coordinates.y = -1;
}
if (input_test_flag(INPUT_FLAG_TOOL_ACTIVE))
@ -1356,8 +1338,6 @@ rct_window* window_park_objective_open()
if (window == nullptr)
{
window = window_park_open();
window->viewport_focus_coordinates.x = -1;
window->viewport_focus_coordinates.y = -1;
}
if (input_test_flag(INPUT_FLAG_TOOL_ACTIVE))
@ -1549,8 +1529,6 @@ rct_window* window_park_awards_open()
if (window == nullptr)
{
window = window_park_open();
window->viewport_focus_coordinates.x = -1;
window->viewport_focus_coordinates.y = -1;
}
if (input_test_flag(INPUT_FLAG_TOOL_ACTIVE))

View File

@ -155,7 +155,6 @@ rct_window* window_player_open(uint8_t id)
window = WindowCreateAutoPos(240, 170, &window_player_overview_events, WC_PLAYER, WF_RESIZABLE);
window->number = id;
window->page = 0;
window->viewport_focus_coordinates.y = 0;
window->frame_no = 0;
window->list_information_type = 0;
window->picked_peep_frame = 0;
@ -164,10 +163,9 @@ rct_window* window_player_open(uint8_t id)
window->min_height = 134;
window->max_width = 500;
window->max_height = 450;
window->no_list_items = 0;
window->selected_list_item = -1;
window->viewport_focus_coordinates.y = -1;
}
window->page = 0;
@ -549,8 +547,8 @@ static void window_player_set_page(rct_window* w, int32_t page)
{
if (w->viewport == nullptr)
{
viewport_create(
w, w->windowPos, w->width, w->height, 0, TileCoordsXYZ(128, 128, 0).ToCoordsXYZ(), 1, SPRITE_INDEX_NULL);
const auto focus = Focus2(TileCoordsXYZ(128, 128, 0).ToCoordsXYZ());
viewport_create(w, w->windowPos, w->width, w->height, focus);
w->flags |= WF_NO_SCROLLING;
window_event_invalidate_call(w);
window_player_update_viewport(w, false);

View File

@ -1591,42 +1591,29 @@ static void window_ride_init_viewport(rct_window* w)
if (ride == nullptr)
return;
int32_t viewSelectionIndex = w->viewport_focus_coordinates.var_480 - 1;
int32_t viewSelectionIndex = w->ride.view - 1;
union
{
sprite_focus sprite;
coordinate_focus coordinate;
} focus;
focus.coordinate.x = 0;
focus.coordinate.y = 0;
focus.coordinate.z = 0;
focus.sprite.sprite_id = SPRITE_INDEX_NULL;
focus.coordinate.zoom = 0;
focus.coordinate.rotation = get_current_rotation();
focus.coordinate.width = 0;
focus.coordinate.height = 0;
std::optional<Focus2> focus;
if (viewSelectionIndex >= 0 && viewSelectionIndex < ride->num_vehicles && ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK)
{
focus.sprite.sprite_id = ride->vehicles[viewSelectionIndex];
uint16_t vehId = ride->vehicles[viewSelectionIndex];
rct_ride_entry* ride_entry = ride->GetRideEntry();
if (ride_entry && ride_entry->tab_vehicle != 0)
{
Vehicle* vehicle = GetEntity<Vehicle>(focus.sprite.sprite_id);
Vehicle* vehicle = GetEntity<Vehicle>(vehId);
if (vehicle == nullptr)
{
focus.sprite.sprite_id = SPRITE_INDEX_NULL;
vehId = SPRITE_INDEX_NULL;
}
else if (vehicle->next_vehicle_on_train != SPRITE_INDEX_NULL)
{
focus.sprite.sprite_id = vehicle->next_vehicle_on_train;
vehId = vehicle->next_vehicle_on_train;
}
}
if (focus.sprite.sprite_id != SPRITE_INDEX_NULL)
if (vehId != SPRITE_INDEX_NULL)
{
focus.sprite.type |= VIEWPORT_FOCUS_TYPE_SPRITE;
focus = Focus2(vehId);
}
}
else if (viewSelectionIndex >= ride->num_vehicles && viewSelectionIndex < (ride->num_vehicles + ride->num_stations))
@ -1634,41 +1621,28 @@ static void window_ride_init_viewport(rct_window* w)
auto stationIndex = GetStationIndexFromViewSelection(*w);
if (stationIndex)
{
auto location = ride->stations[*stationIndex].GetStart();
focus.coordinate.x = location.x;
focus.coordinate.y = location.y;
focus.coordinate.z = location.z;
focus.sprite.type |= VIEWPORT_FOCUS_TYPE_COORDINATE;
const auto location = ride->stations[*stationIndex].GetStart();
focus = Focus2(location);
}
}
else
{
if (viewSelectionIndex > 0)
{
w->viewport_focus_coordinates.var_480 = 0;
w->ride.view = 0;
}
if (w->number < ride_overall_views.size())
{
const auto& view = ride_overall_views[w->number];
focus.coordinate.x = view.x;
focus.coordinate.y = view.y;
focus.coordinate.z = view.z;
focus.coordinate.zoom = view.zoom;
focus.sprite.type |= VIEWPORT_FOCUS_TYPE_COORDINATE;
CoordsXYZ loc = { view.x, view.y, view.z };
focus = Focus2(loc, view.zoom);
}
}
focus.coordinate.var_480 = w->viewport_focus_coordinates.var_480;
uint16_t viewport_flags = 0;
if (w->viewport != nullptr)
{
if (focus.coordinate.x == w->viewport_focus_coordinates.x
&& (focus.coordinate.y & VIEWPORT_FOCUS_Y_MASK) == w->viewport_focus_coordinates.y
&& focus.coordinate.z == w->viewport_focus_coordinates.z
&& focus.coordinate.rotation == w->viewport_focus_coordinates.rotation
&& focus.coordinate.zoom == w->viewport_focus_coordinates.zoom && focus.coordinate.width == w->width
&& focus.coordinate.height == w->height)
if (focus == w->focus2)
{
return;
}
@ -1682,13 +1656,7 @@ static void window_ride_init_viewport(rct_window* w)
window_event_invalidate_call(w);
w->viewport_focus_coordinates.x = focus.coordinate.x;
w->viewport_focus_coordinates.y = focus.coordinate.y;
w->viewport_focus_coordinates.z = focus.coordinate.z;
w->viewport_focus_coordinates.rotation = focus.coordinate.rotation;
w->viewport_focus_coordinates.zoom = focus.coordinate.zoom;
w->viewport_focus_coordinates.width = w->width;
w->viewport_focus_coordinates.height = w->height;
w->focus2 = focus;
// rct2: 0x006aec9c only used here so brought it into the function
if (!w->viewport && !ride->overall_view.IsNull())
@ -1698,10 +1666,8 @@ static void window_ride_init_viewport(rct_window* w)
auto screenPos = w->windowPos + ScreenCoordsXY{ view_widget->left + 1, view_widget->top + 1 };
int32_t width = view_widget->width() - 1;
int32_t height = view_widget->height() - 1;
viewport_create(
w, screenPos, width, height, focus.coordinate.zoom,
{ focus.coordinate.x, focus.coordinate.y & VIEWPORT_FOCUS_Y_MASK, focus.coordinate.z },
focus.sprite.type & VIEWPORT_FOCUS_TYPE_MASK, focus.sprite.sprite_id);
viewport_create(w, screenPos, width, height, w->focus2.value());
w->flags |= WF_NO_SCROLLING;
w->Invalidate();

View File

@ -196,7 +196,6 @@ rct_window* window_scenarioselect_open(std::function<void(std::string_view)> cal
initialise_list_items(window);
WindowInitScrollWidgets(window);
window->viewport_focus_coordinates.var_480 = -1;
window->highlighted_scenario = nullptr;
return window;

View File

@ -127,10 +127,10 @@ public:
// Create viewport
rct_widget& viewportWidget = window_sign_widgets[WIDX_VIEWPORT];
const auto focus = Focus2(CoordsXYZ{ signViewPosition, viewZ });
viewport_create(
this, windowPos + ScreenCoordsXY{ viewportWidget.left + 1, viewportWidget.top + 1 }, viewportWidget.width() - 1,
viewportWidget.height() - 1, 0, { signViewPosition, viewZ }, 0, SPRITE_INDEX_NULL);
viewportWidget.height() - 1, focus);
viewport->flags = gConfigGeneral.always_show_gridlines ? VIEWPORT_FLAG_GRIDLINES : 0;
Invalidate();
@ -300,9 +300,10 @@ public:
// Create viewport
rct_widget* viewportWidget = &window_sign_widgets[WIDX_VIEWPORT];
const auto focus = Focus2(CoordsXYZ{ signViewPos });
viewport_create(
this, windowPos + ScreenCoordsXY{ viewportWidget->left + 1, viewportWidget->top + 1 }, viewportWidget->width() - 1,
viewportWidget->height() - 1, 0, signViewPos, 0, SPRITE_INDEX_NULL);
viewportWidget->height() - 1, focus);
if (viewport != nullptr)
viewport->flags = gConfigGeneral.always_show_gridlines ? VIEWPORT_FLAG_GRIDLINES : 0;
Invalidate();

View File

@ -267,7 +267,6 @@ rct_window* window_staff_open(Peep* peep)
w->number = peep->sprite_index;
w->page = 0;
w->viewport_focus_coordinates.y = 0;
w->frame_no = 0;
w->highlighted_item = 0;
@ -1347,9 +1346,7 @@ void window_staff_viewport_init(rct_window* w)
if (w->page != WINDOW_STAFF_OVERVIEW)
return;
sprite_focus focus = {};
focus.sprite_id = w->number;
std::optional<Focus2> focus;
const auto peep = GetStaff(w);
if (peep == nullptr)
@ -1357,23 +1354,16 @@ void window_staff_viewport_init(rct_window* w)
return;
}
if (peep->State == PeepState::Picked)
if (peep->State != PeepState::Picked)
{
focus.sprite_id = SPRITE_INDEX_NULL;
}
else
{
focus.type |= VIEWPORT_FOCUS_TYPE_SPRITE | VIEWPORT_FOCUS_TYPE_COORDINATE;
focus.rotation = get_current_rotation();
focus = Focus2(peep->sprite_index);
}
uint16_t viewport_flags;
if (w->viewport)
{
// Check all combos, for now skipping y and rot
if (focus.sprite_id == w->viewport_focus_sprite.sprite_id && focus.type == w->viewport_focus_sprite.type
&& focus.rotation == w->viewport_focus_sprite.rotation)
if (focus == w->focus2)
return;
viewport_flags = w->viewport->flags;
@ -1388,9 +1378,7 @@ void window_staff_viewport_init(rct_window* w)
window_event_invalidate_call(w);
w->viewport_focus_sprite.sprite_id = focus.sprite_id;
w->viewport_focus_sprite.type = focus.type;
w->viewport_focus_sprite.rotation = focus.rotation;
w->focus2 = focus;
if (peep->State != PeepState::Picked)
{
@ -1402,8 +1390,7 @@ void window_staff_viewport_init(rct_window* w)
int32_t width = view_widget->width() - 1;
int32_t height = view_widget->height() - 1;
viewport_create(
w, screenPos, width, height, 0, { 0, 0, 0 }, focus.type & VIEWPORT_FOCUS_TYPE_MASK, focus.sprite_id);
viewport_create(w, screenPos, width, height, focus.value());
w->flags |= WF_NO_SCROLLING;
w->Invalidate();
}

View File

@ -227,9 +227,10 @@ void window_title_command_editor_open(TitleSequence* sequence, int32_t index, bo
WindowInitScrollWidgets(window);
rct_widget* const viewportWidget = &window_title_command_editor_widgets[WIDX_VIEWPORT];
const auto focus = Focus2(CoordsXYZ{ 0, 0, 0 });
viewport_create(
window, window->windowPos + ScreenCoordsXY{ viewportWidget->left + 1, viewportWidget->top + 1 },
viewportWidget->width() - 1, viewportWidget->height() - 1, 0, { 0, 0, 0 }, 0, SPRITE_INDEX_NULL);
viewportWidget->width() - 1, viewportWidget->height() - 1, focus);
_window_title_command_editor_index = index;
_window_title_command_editor_insert = insert;
@ -476,7 +477,8 @@ static void window_title_command_editor_dropdown(rct_window* w, rct_widgetindex
_command.SpriteIndex = SPRITE_INDEX_NULL;
_command.SpriteName[0] = '\0';
window_unfollow_sprite(w);
w->viewport->flags &= ~VIEWPORT_FOCUS_TYPE_SPRITE;
// This is incorrect
w->viewport->flags &= ~VIEWPORT_FLAG_GRIDLINES;
break;
case TitleScript::Speed:
_command.Speed = 1;

View File

@ -76,7 +76,8 @@ public:
enabled_widgets = (1ULL << WIDX_CLOSE) | (1ULL << WIDX_ZOOM_IN) | (1ULL << WIDX_ZOOM_OUT) | (1ULL << WIDX_LOCATE);
// Create viewport
viewport_create(this, windowPos, width, height, 0, TileCoordsXYZ(128, 128, 0).ToCoordsXYZ(), 1, SPRITE_INDEX_NULL);
const auto focus = Focus2(TileCoordsXYZ(128, 128, 0).ToCoordsXYZ());
viewport_create(this, windowPos, width, height, focus);
if (viewport == nullptr)
{
Close();

View File

@ -117,6 +117,30 @@ std::optional<ScreenCoordsXY> centre_2d_coordinates(const CoordsXYZ& loc, rct_vi
return { screenCoord };
}
CoordsXYZ Focus2::GetPos() const
{
return std::visit(
[](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, Focus2::CoordinateFocus>)
return arg;
else if constexpr (std::is_same_v<T, Focus2::EntityFocus>)
{
auto* centreEntity = GetEntity(arg);
if (centreEntity != nullptr)
{
return CoordsXYZ{ centreEntity->x, centreEntity->y, centreEntity->z };
}
else
{
log_error("Invalid entity for focus.");
return CoordsXYZ{};
}
}
},
data);
}
/**
* Viewport will look at sprite or at coordinates as specified in flags 0b_1X
* for sprite 0b_0X for coordinates
@ -134,9 +158,7 @@ std::optional<ScreenCoordsXY> centre_2d_coordinates(const CoordsXYZ& loc, rct_vi
* flags: edx top most 2 bits 0b_X1 for zoom clear see below for 2nd bit.
* w: esi
*/
void viewport_create(
rct_window* w, const ScreenCoordsXY& screenCoords, int32_t width, int32_t height, int32_t zoom, CoordsXYZ centrePos,
char flags, uint16_t sprite)
void viewport_create(rct_window* w, const ScreenCoordsXY& screenCoords, int32_t width, int32_t height, const Focus2& focus)
{
rct_viewport* viewport = nullptr;
if (_viewports.size() >= MAX_VIEWPORT_COUNT)
@ -151,11 +173,7 @@ void viewport_create(
viewport->pos = screenCoords;
viewport->width = width;
viewport->height = height;
if (!(flags & VIEWPORT_FOCUS_TYPE_COORDINATE))
{
zoom = 0;
}
const auto zoom = focus.zoom;
viewport->view_width = width << zoom;
viewport->view_height = height << zoom;
@ -166,24 +184,16 @@ void viewport_create(
viewport->flags |= VIEWPORT_FLAG_GRIDLINES;
w->viewport = viewport;
if (flags & VIEWPORT_FOCUS_TYPE_SPRITE)
{
w->viewport_target_sprite = sprite;
auto* centreEntity = GetEntity(sprite);
if (centreEntity != nullptr)
{
centrePos = { centreEntity->x, centreEntity->y, centreEntity->z };
}
else
{
log_error("Invalid entity for viewport.");
return;
}
}
else
{
w->viewport_target_sprite = SPRITE_INDEX_NULL;
}
CoordsXYZ centrePos = focus.GetPos();
w->viewport_target_sprite = std::visit(
[](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, Focus2::CoordinateFocus>)
return SPRITE_INDEX_NULL;
else if constexpr (std::is_same_v<T, Focus2::EntityFocus>)
return arg;
},
focus.data);
auto centreLoc = centre_2d_coordinates(centrePos, viewport);
if (!centreLoc.has_value())
@ -692,24 +702,23 @@ void viewport_update_smart_sprite_follow(rct_window* window)
break;
default: // All other types don't need any "smart" following; steam particle, duck, money effect, etc.
window->viewport_focus_sprite.sprite_id = window->viewport_smart_follow_sprite;
window->focus2 = Focus2(window->viewport_smart_follow_sprite);
window->viewport_target_sprite = window->viewport_smart_follow_sprite;
break;
}
}
viewport_focus viewport_update_smart_guest_follow(rct_window* window, const Guest* peep)
void viewport_update_smart_guest_follow(rct_window* window, const Guest* peep)
{
viewport_focus focus{};
focus.type = VIEWPORT_FOCUS_TYPE_SPRITE;
focus.sprite.sprite_id = peep->sprite_index;
Focus2 focus = Focus2(peep->sprite_index);
window->viewport_target_sprite = peep->sprite_index;
if (peep->State == PeepState::Picked)
{
focus.sprite.sprite_id = SPRITE_INDEX_NULL;
window->viewport_smart_follow_sprite = SPRITE_INDEX_NULL;
window->viewport_target_sprite = SPRITE_INDEX_NULL;
return focus;
window->focus2 = std::nullopt; // No focus
return;
}
bool overallFocus = true;
@ -725,8 +734,9 @@ viewport_focus viewport_update_smart_guest_follow(rct_window* window, const Gues
const auto car = train->GetCar(peep->CurrentCar);
if (car != nullptr)
{
focus.sprite.sprite_id = car->sprite_index;
focus = Focus2(car->sprite_index);
overallFocus = false;
window->viewport_target_sprite = car->sprite_index;
}
}
}
@ -738,51 +748,36 @@ viewport_focus viewport_update_smart_guest_follow(rct_window* window, const Gues
if (ride != nullptr)
{
auto xy = ride->overall_view.ToTileCentre();
focus.type = VIEWPORT_FOCUS_TYPE_COORDINATE;
focus.coordinate.x = xy.x;
focus.coordinate.y = xy.y;
focus.coordinate.z = tile_element_height(xy) + (4 * COORDS_Z_STEP);
focus.sprite.type |= VIEWPORT_FOCUS_TYPE_COORDINATE;
CoordsXYZ coordFocus;
coordFocus.x = xy.x;
coordFocus.y = xy.y;
coordFocus.z = tile_element_height(xy) + (4 * COORDS_Z_STEP);
focus = Focus2(coordFocus);
window->viewport_target_sprite = SPRITE_INDEX_NULL;
}
}
else
{
focus.sprite.type |= VIEWPORT_FOCUS_TYPE_SPRITE | VIEWPORT_FOCUS_TYPE_COORDINATE;
focus.sprite.pad_486 &= 0xFFFF;
}
focus.coordinate.rotation = get_current_rotation();
window->viewport_focus_sprite = focus.sprite;
window->viewport_target_sprite = window->viewport_focus_sprite.sprite_id;
return focus;
window->focus2 = focus;
}
void viewport_update_smart_staff_follow(rct_window* window, const Staff* peep)
{
sprite_focus focus = {};
focus.sprite_id = window->viewport_smart_follow_sprite;
if (peep->State == PeepState::Picked)
{
window->viewport_smart_follow_sprite = SPRITE_INDEX_NULL;
window->viewport_target_sprite = SPRITE_INDEX_NULL;
window->focus2 = std::nullopt;
return;
}
focus.type |= VIEWPORT_FOCUS_TYPE_SPRITE | VIEWPORT_FOCUS_TYPE_COORDINATE;
window->viewport_focus_sprite = focus;
window->viewport_target_sprite = window->viewport_focus_sprite.sprite_id;
window->focus2 = Focus2(window->viewport_smart_follow_sprite);
window->viewport_target_sprite = window->viewport_smart_follow_sprite;
}
void viewport_update_smart_vehicle_follow(rct_window* window)
{
sprite_focus focus = {};
focus.sprite_id = window->viewport_smart_follow_sprite;
window->viewport_focus_sprite = focus;
window->viewport_target_sprite = window->viewport_focus_sprite.sprite_id;
window->focus2 = Focus2(window->viewport_smart_follow_sprite);
window->viewport_target_sprite = window->viewport_smart_follow_sprite;
}
/**

View File

@ -104,15 +104,13 @@ extern uint8_t gCurrentRotation;
void viewport_init_all();
std::optional<ScreenCoordsXY> centre_2d_coordinates(const CoordsXYZ& loc, rct_viewport* viewport);
void viewport_create(
rct_window* w, const ScreenCoordsXY& screenCoords, int32_t width, int32_t height, int32_t zoom, CoordsXYZ centrePos,
char flags, uint16_t sprite);
void viewport_create(rct_window* w, const ScreenCoordsXY& screenCoords, int32_t width, int32_t height, const Focus2& focus);
void viewport_remove(rct_viewport* viewport);
void viewports_invalidate(int32_t left, int32_t top, int32_t right, int32_t bottom, int32_t maxZoom = -1);
void viewport_update_position(rct_window* window);
void viewport_update_sprite_follow(rct_window* window);
void viewport_update_smart_sprite_follow(rct_window* window);
viewport_focus viewport_update_smart_guest_follow(rct_window* window, const Guest* peep);
void viewport_update_smart_guest_follow(rct_window* window, const Guest* peep);
void viewport_update_smart_staff_follow(rct_window* window, const Staff* peep);
void viewport_update_smart_vehicle_follow(rct_window* window);
void viewport_render(

View File

@ -20,6 +20,7 @@
#include <limits>
#include <list>
#include <memory>
#include <variant>
struct rct_drawpixelinfo;
struct rct_window;
@ -194,51 +195,34 @@ struct rct_scroll
constexpr auto WINDOW_SCROLL_UNDEFINED = std::numeric_limits<uint16_t>::max();
/**
* Viewport focus structure.
* size: 0xA
* Use sprite.type to work out type.
*/
struct coordinate_focus
struct Focus2
{
int16_t var_480;
int16_t x; // 0x482
int16_t y; // 0x484 & VIEWPORT_FOCUS_Y_MASK
int16_t z; // 0x486
uint8_t rotation; // 0x488
uint8_t zoom; // 0x489
int16_t width;
int16_t height;
};
using CoordinateFocus = CoordsXYZ;
using EntityFocus = uint16_t;
// Type is viewport_target_sprite_id & 0x80000000 != 0
struct sprite_focus
{
int16_t var_480;
uint16_t sprite_id; // 0x482
uint8_t pad_484;
uint8_t type; // 0x485 & VIEWPORT_FOCUS_TYPE_MASK
uint16_t pad_486;
uint8_t rotation; // 0x488
uint8_t zoom; // 0x489
};
uint8_t zoom = 0;
std::variant<CoordinateFocus, EntityFocus> data;
#define VIEWPORT_FOCUS_TYPE_MASK 0xC0
enum VIEWPORT_FOCUS_TYPE : uint8_t
{
VIEWPORT_FOCUS_TYPE_COORDINATE = (1 << 6),
VIEWPORT_FOCUS_TYPE_SPRITE = (1 << 7)
};
#define VIEWPORT_FOCUS_Y_MASK 0x3FFF
struct viewport_focus
{
VIEWPORT_FOCUS_TYPE type{};
union
template<typename T> constexpr explicit Focus2(T newValue, uint8_t newZoom = 0)
{
sprite_focus sprite;
coordinate_focus coordinate;
};
data = newValue;
zoom = newZoom;
}
CoordsXYZ GetPos() const;
constexpr bool operator==(const Focus2& other) const
{
if (zoom != other.zoom)
{
return false;
}
return data == other.data;
}
constexpr bool operator!=(const Focus2& other) const
{
return !(*this == other);
}
};
struct rct_window_event_list

View File

@ -12,28 +12,10 @@ void rct_window::SetLocation(const CoordsXYZ& coords)
void rct_window::ScrollToViewport()
{
// In original checked to make sure x and y were not -1 as well.
if (viewport == nullptr || viewport_focus_coordinates.y == -1)
if (viewport == nullptr || !focus2.has_value())
return;
CoordsXYZ newCoords = {};
if (viewport_focus_sprite.type & VIEWPORT_FOCUS_TYPE_SPRITE)
{
auto* sprite = GetEntity(viewport_focus_sprite.sprite_id);
if (sprite == nullptr)
{
return;
}
newCoords.x = sprite->x;
newCoords.y = sprite->y;
newCoords.z = sprite->z;
}
else
{
newCoords.x = viewport_focus_coordinates.x;
newCoords.y = viewport_focus_coordinates.y & VIEWPORT_FOCUS_Y_MASK;
newCoords.z = viewport_focus_coordinates.z;
}
CoordsXYZ newCoords = focus2.value().GetPos();
auto mainWindow = window_get_main();
if (mainWindow != nullptr)

View File

@ -55,10 +55,9 @@ struct rct_window
uint32_t list_item_positions[1024]{};
uint16_t no_list_items{}; // 0 for no items
int16_t selected_list_item{}; // -1 for none selected
std::optional<Focus2> focus2;
union
{
coordinate_focus viewport_focus_coordinates;
sprite_focus viewport_focus_sprite;
campaign_variables campaign;
new_ride_variables new_ride;
news_variables news;