1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-20 13:33:02 +01:00

Fix #12831: Zooming to cursor on land edges sometimes moves the camera incorrectly (#25042)

* Calculate zoom to cursor based on mouse coordinates

* Remove unused function WindowViewportGetMapCoordsByCursor

* Remove unused function WindowViewportCentreTileAroundCursor

* Set viewport pos on zoom to avoid unnecessary draw and shift
This commit is contained in:
Michael Steenbeek
2025-08-28 00:11:47 +02:00
committed by GitHub
3 changed files with 18 additions and 70 deletions

View File

@@ -10,6 +10,7 @@
- Change: [#23351] Diagonal sloped Go-Kart track can no longer be built without cheats if the karts do not have sprites for them.
- Change: [#24606] Increase Misc Entity limit from 1600 to 3200.
- Change: [#24974] Raise the Go-Karts maximum support height to allow 2 large sloped turns to be built on flat ground.
- Fix: [#12831] Zooming to cursor on land edges sometimes causes the camera to move to the wrong position.
- Fix: [#16988] AppImage version does not show changelog.
- Fix: [#18048] Play music from all ride's stations.
- Fix: [#19137] Non-inverted left corkscrew supports are incorrect at one angle (original bug).

View File

@@ -411,62 +411,6 @@ static constexpr float kWindowScrollLocations[][2] = {
}
}
void WindowViewportGetMapCoordsByCursor(
const WindowBase& w, int32_t* map_x, int32_t* map_y, int32_t* offset_x, int32_t* offset_y)
{
// Get mouse position to offset against.
auto mouseCoords = ContextGetCursorPositionScaled();
// Compute map coordinate by mouse position.
auto viewportPos = w.viewport->ScreenToViewportCoord(mouseCoords);
auto coordsXYZ = ViewportAdjustForMapHeight(viewportPos, w.viewport->rotation);
auto mapCoords = ViewportPosToMapPos(viewportPos, coordsXYZ.z, w.viewport->rotation);
*map_x = mapCoords.x;
*map_y = mapCoords.y;
// Get viewport coordinates centring around the tile.
int32_t z = TileElementHeight(mapCoords);
auto centreLoc = centre_2d_coordinates({ mapCoords.x, mapCoords.y, z }, w.viewport);
if (!centreLoc)
{
LOG_ERROR("Invalid location.");
return;
}
// Rebase mouse position onto centre of window, and compensate for zoom level.
int32_t rebased_x = w.viewport->zoom.ApplyTo(w.width / 2 - mouseCoords.x);
int32_t rebased_y = w.viewport->zoom.ApplyTo(w.height / 2 - mouseCoords.y);
// Compute cursor offset relative to tile.
*offset_x = w.viewport->zoom.ApplyTo(w.savedViewPos.x - (centreLoc->x + rebased_x));
*offset_y = w.viewport->zoom.ApplyTo(w.savedViewPos.y - (centreLoc->y + rebased_y));
}
void WindowViewportCentreTileAroundCursor(WindowBase& w, int32_t map_x, int32_t map_y, int32_t offset_x, int32_t offset_y)
{
// Get viewport coordinates centring around the tile.
int32_t z = TileElementHeight({ map_x, map_y });
auto centreLoc = centre_2d_coordinates({ map_x, map_y, z }, w.viewport);
if (!centreLoc.has_value())
{
LOG_ERROR("Invalid location.");
return;
}
// Get mouse position to offset against.
auto mouseCoords = ContextGetCursorPositionScaled();
// Rebase mouse position onto centre of window, and compensate for zoom level.
int32_t rebased_x = w.viewport->zoom.ApplyTo((w.width >> 1) - mouseCoords.x);
int32_t rebased_y = w.viewport->zoom.ApplyTo((w.height >> 1) - mouseCoords.y);
// Apply offset to the viewport.
w.savedViewPos = { centreLoc->x + rebased_x + w.viewport->zoom.ApplyInversedTo(offset_x),
centreLoc->y + rebased_y + w.viewport->zoom.ApplyInversedTo(offset_y) };
}
/**
* For all windows with viewports, ensure they do not have a zoom level less than the minimum.
*/
@@ -490,15 +434,7 @@ static constexpr float kWindowScrollLocations[][2] = {
if (v->zoom == zoomLevel)
return;
// Zooming to cursor? Remember where we're pointing at the moment.
int32_t saved_map_x = 0;
int32_t saved_map_y = 0;
int32_t offset_x = 0;
int32_t offset_y = 0;
if (Config::Get().general.ZoomToCursor && atCursor)
{
WindowViewportGetMapCoordsByCursor(w, &saved_map_x, &saved_map_y, &offset_x, &offset_y);
}
const ZoomLevel previousZoomLevel = v->zoom;
// Zoom in
while (v->zoom > zoomLevel)
@@ -516,12 +452,26 @@ static constexpr float kWindowScrollLocations[][2] = {
w.savedViewPos.y -= v->ViewHeight() / 4;
}
// Zooming to cursor? Centre around the tile we were hovering over just now.
if (Config::Get().general.ZoomToCursor && atCursor)
{
WindowViewportCentreTileAroundCursor(w, saved_map_x, saved_map_y, offset_x, offset_y);
const auto mouseCoords = ContextGetCursorPositionScaled() - v->pos;
const int32_t diffX = (mouseCoords.x - (zoomLevel.ApplyInversedTo(v->ViewWidth()) / 2));
const int32_t diffY = (mouseCoords.y - (zoomLevel.ApplyInversedTo(v->ViewHeight()) / 2));
if (previousZoomLevel > zoomLevel)
{
w.savedViewPos.x += zoomLevel.ApplyTo(diffX);
w.savedViewPos.y += zoomLevel.ApplyTo(diffY);
}
else
{
w.savedViewPos.x -= previousZoomLevel.ApplyTo(diffX);
w.savedViewPos.y -= previousZoomLevel.ApplyTo(diffY);
}
}
v->viewPos.x = w.savedViewPos.x;
v->viewPos.y = w.savedViewPos.y;
// HACK: Prevents the redraw from failing when there is
// a window on top of the viewport.
auto* windowMgr = Ui::GetWindowManager();

View File

@@ -306,9 +306,6 @@ namespace OpenRCT2
WindowBase* WindowGetMain();
void WindowScrollToLocation(WindowBase& w, const CoordsXYZ& coords);
void WindowViewportGetMapCoordsByCursor(
const WindowBase& w, int32_t* map_x, int32_t* map_y, int32_t* offset_x, int32_t* offset_y);
void WindowViewportCentreTileAroundCursor(WindowBase& w, int32_t map_x, int32_t map_y, int32_t offset_x, int32_t offset_y);
void WindowCheckAllValidZoom();
void WindowZoomSet(WindowBase& w, ZoomLevel zoomLevel, bool atCursor);