From 06579b45d2ed41fb6714986328a18accc373fb9a Mon Sep 17 00:00:00 2001 From: mix Date: Wed, 27 Aug 2025 08:57:39 +0100 Subject: [PATCH 1/4] Calculate zoom to cursor based on mouse coordinates --- distribution/changelog.txt | 1 + src/openrct2/interface/Window.cpp | 25 ++++++++++++++----------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 0886c28936..9795e4b203 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -9,6 +9,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). diff --git a/src/openrct2/interface/Window.cpp b/src/openrct2/interface/Window.cpp index 08be8c8628..0341e15da2 100644 --- a/src/openrct2/interface/Window.cpp +++ b/src/openrct2/interface/Window.cpp @@ -490,15 +490,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,10 +508,21 @@ 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); + } } // HACK: Prevents the redraw from failing when there is From fa920085484d488ca88579824434507722fd5445 Mon Sep 17 00:00:00 2001 From: mix Date: Wed, 27 Aug 2025 09:10:00 +0100 Subject: [PATCH 2/4] Remove unused function WindowViewportGetMapCoordsByCursor --- src/openrct2/interface/Window.cpp | 32 ------------------------------- src/openrct2/interface/Window.h | 2 -- 2 files changed, 34 deletions(-) diff --git a/src/openrct2/interface/Window.cpp b/src/openrct2/interface/Window.cpp index 0341e15da2..0e2ca2c856 100644 --- a/src/openrct2/interface/Window.cpp +++ b/src/openrct2/interface/Window.cpp @@ -411,38 +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. diff --git a/src/openrct2/interface/Window.h b/src/openrct2/interface/Window.h index 233a18bab0..b5608b393c 100644 --- a/src/openrct2/interface/Window.h +++ b/src/openrct2/interface/Window.h @@ -306,8 +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); From 677f6c0717779f101632b63df1084ca353fb4f06 Mon Sep 17 00:00:00 2001 From: mix Date: Wed, 27 Aug 2025 09:13:05 +0100 Subject: [PATCH 3/4] Remove unused function WindowViewportCentreTileAroundCursor --- src/openrct2/interface/Window.cpp | 24 ------------------------ src/openrct2/interface/Window.h | 1 - 2 files changed, 25 deletions(-) diff --git a/src/openrct2/interface/Window.cpp b/src/openrct2/interface/Window.cpp index 0e2ca2c856..956ec265ec 100644 --- a/src/openrct2/interface/Window.cpp +++ b/src/openrct2/interface/Window.cpp @@ -411,30 +411,6 @@ static constexpr float kWindowScrollLocations[][2] = { } } - 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. */ diff --git a/src/openrct2/interface/Window.h b/src/openrct2/interface/Window.h index b5608b393c..8c896b3e13 100644 --- a/src/openrct2/interface/Window.h +++ b/src/openrct2/interface/Window.h @@ -306,7 +306,6 @@ namespace OpenRCT2 WindowBase* WindowGetMain(); void WindowScrollToLocation(WindowBase& w, const CoordsXYZ& coords); - 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); From dd1cc48ce3945045f61a924db72d98f38eecfa44 Mon Sep 17 00:00:00 2001 From: mix Date: Wed, 27 Aug 2025 12:07:35 +0100 Subject: [PATCH 4/4] Set viewport pos on zoom to avoid unnecessary draw and shift --- src/openrct2/interface/Window.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/openrct2/interface/Window.cpp b/src/openrct2/interface/Window.cpp index 956ec265ec..bc46338c49 100644 --- a/src/openrct2/interface/Window.cpp +++ b/src/openrct2/interface/Window.cpp @@ -469,6 +469,9 @@ static constexpr float kWindowScrollLocations[][2] = { } } + 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();