From de0fbbd8e22d9a9798d35d343af3b9446f92551a Mon Sep 17 00:00:00 2001 From: mix Date: Mon, 28 Apr 2025 21:36:30 +0100 Subject: [PATCH 1/2] Revert "Fix sprite culling glitching by culling sprites at full column width" This reverts commit b5c925da3676e9601d12f80918e1507c2985ee4a. --- src/openrct2/paint/Paint.cpp | 49 ++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/src/openrct2/paint/Paint.cpp b/src/openrct2/paint/Paint.cpp index e2d653d13f..2f13fdf333 100644 --- a/src/openrct2/paint/Paint.cpp +++ b/src/openrct2/paint/Paint.cpp @@ -103,23 +103,40 @@ static void PaintSessionAddPSToQuadrant(PaintSession& session, PaintStruct* ps) session.QuadrantFrontIndex = std::max(session.QuadrantFrontIndex, paintQuadrantIndex); } -static constexpr bool imageWithinColumn(const ScreenCoordsXY& imagePos, const G1Element& g1, const DrawPixelInfo& dpi) +static constexpr bool ImageWithinDPI(const ScreenCoordsXY& imagePos, const G1Element& g1, const DrawPixelInfo& dpi) { - const int32_t left = imagePos.x + g1.x_offset; - const int32_t right = left + g1.width; + int32_t left = imagePos.x + g1.x_offset; + int32_t bottom = imagePos.y + g1.y_offset; - const int32_t columnWidth = dpi.zoom_level.ApplyInversedTo(kCoordsXYStep); - const int32_t alignedX = floor2(dpi.x, columnWidth); - - // check if a sprite is within the full unclipped column width - // culling sprites outside the clipped column causes sorting differences between invalidation blocks - // not culling sprites outside the full column width also causes a different kind of glitching - - if (dpi.zoom_level.ApplyInversedTo(right) <= alignedX) - return false; - if (dpi.zoom_level.ApplyInversedTo(left) >= alignedX + columnWidth) - return false; + int32_t right = left + g1.width; + int32_t top = bottom + g1.height; + // mber: It is possible to use only the bottom else block here if you change <= and >= to simply < and >. + // However, since this is used to cull paint structs, I'd prefer to keep the condition strict and calculate + // the culling differently for minifying and magnifying. + auto zoom = dpi.zoom_level; + if (zoom > ZoomLevel{ 0 }) + { + if (right <= dpi.WorldX()) + return false; + if (top <= dpi.WorldY()) + return false; + if (left >= dpi.WorldX() + dpi.WorldWidth()) + return false; + if (bottom >= dpi.WorldY() + dpi.WorldHeight()) + return false; + } + else + { + if (zoom.ApplyInversedTo(right) <= dpi.x) + return false; + if (zoom.ApplyInversedTo(top) <= dpi.y) + return false; + if (zoom.ApplyInversedTo(left) >= dpi.x + dpi.width) + return false; + if (zoom.ApplyInversedTo(bottom) >= dpi.y + dpi.height) + return false; + } return true; } @@ -167,7 +184,7 @@ static PaintStruct* CreateNormalPaintStruct( const auto imagePos = Translate3DTo2DWithZ(session.CurrentRotation, swappedRotCoord); - if (!imageWithinColumn(imagePos, *g1, session.DPI)) + if (!ImageWithinDPI(imagePos, *g1, session.DPI)) { return nullptr; } @@ -215,7 +232,7 @@ static PaintStruct* CreateNormalPaintStructHeight( const auto imagePos = Translate3DTo2DWithZ(session.CurrentRotation, swappedRotCoord); - if (!imageWithinColumn(imagePos, *g1, session.DPI)) + if (!ImageWithinDPI(imagePos, *g1, session.DPI)) { return nullptr; } From 9ace1a8a2b9210057c0be51cb7bcf4a3fe5f3d70 Mon Sep 17 00:00:00 2001 From: mix Date: Mon, 28 Apr 2025 23:01:05 +0100 Subject: [PATCH 2/2] Fix #24303: Track pieces do not draw in the ride construction window --- src/openrct2-ui/windows/RideConstruction.cpp | 5 +++ src/openrct2/drawing/Drawing.h | 4 +++ src/openrct2/drawing/LightFX.cpp | 5 +++ src/openrct2/interface/Viewport.cpp | 14 ++++++++ src/openrct2/paint/Paint.cpp | 34 +++++++++++--------- 5 files changed, 46 insertions(+), 16 deletions(-) diff --git a/src/openrct2-ui/windows/RideConstruction.cpp b/src/openrct2-ui/windows/RideConstruction.cpp index f2900d2d67..9959badf2b 100644 --- a/src/openrct2-ui/windows/RideConstruction.cpp +++ b/src/openrct2-ui/windows/RideConstruction.cpp @@ -2670,6 +2670,11 @@ namespace OpenRCT2::Ui::Windows dpi.x += rotatedScreenCoords.x - widgetWidth / 2; dpi.y += rotatedScreenCoords.y - widgetHeight / 2 - 16; + dpi.cullingX = dpi.x; + dpi.cullingY = dpi.y; + dpi.cullingWidth = dpi.width; + dpi.cullingHeight = dpi.height; + DrawTrackPieceHelper(dpi, rideIndex, trackType, trackDirection, liftHillAndInvertedState, { 4096, 4096 }, 1024); } diff --git a/src/openrct2/drawing/Drawing.h b/src/openrct2/drawing/Drawing.h index d91fcc1e29..e3daed764d 100644 --- a/src/openrct2/drawing/Drawing.h +++ b/src/openrct2/drawing/Drawing.h @@ -76,6 +76,10 @@ struct DrawPixelInfo int32_t width{}; int32_t height{}; int32_t pitch{}; // note: this is actually (pitch - width) + int32_t cullingX{}; + int32_t cullingY{}; + int32_t cullingWidth{}; + int32_t cullingHeight{}; ZoomLevel zoom_level{}; // Last position of drawn text. diff --git a/src/openrct2/drawing/LightFX.cpp b/src/openrct2/drawing/LightFX.cpp index f3c0083b9e..f18182b74c 100644 --- a/src/openrct2/drawing/LightFX.cpp +++ b/src/openrct2/drawing/LightFX.cpp @@ -305,6 +305,11 @@ namespace OpenRCT2::Drawing::LightFx dpi.height = 1; dpi.width = 1; + dpi.cullingX = dpi.x; + dpi.cullingY = dpi.y; + dpi.cullingWidth = dpi.width; + dpi.cullingHeight = dpi.height; + PaintSession* session = PaintSessionAlloc(dpi, w->viewport->flags, w->viewport->rotation); PaintSessionGenerate(*session); PaintSessionArrange(*session); diff --git a/src/openrct2/interface/Viewport.cpp b/src/openrct2/interface/Viewport.cpp index f40c5a8b3c..be058a19dd 100644 --- a/src/openrct2/interface/Viewport.cpp +++ b/src/openrct2/interface/Viewport.cpp @@ -1063,6 +1063,15 @@ namespace OpenRCT2 } columnDpi.width = paintRight - columnDpi.x; + // culling sprites outside the clipped column causes sorting differences between invalidation blocks + // not culling sprites outside the full column width also causes a different kind of glitching + constexpr int32_t cullingY = ZoomLevel::max().ApplyInversedTo(std::numeric_limits::max()) / 2; + + columnDpi.cullingX = floor2(columnDpi.x, columnWidth); + columnDpi.cullingY = -cullingY; + columnDpi.cullingWidth = columnWidth; + columnDpi.cullingHeight = cullingY * 2; + if (useMultithreading) { _paintJobs->AddTask([session]() -> void { ViewportFillColumn(*session); }); @@ -1813,6 +1822,11 @@ namespace OpenRCT2 dpi.height = 1; dpi.width = 1; + dpi.cullingX = dpi.x; + dpi.cullingY = dpi.y; + dpi.cullingWidth = dpi.width; + dpi.cullingHeight = dpi.height; + PaintSession* session = PaintSessionAlloc(dpi, viewport->flags, viewport->rotation); PaintSessionGenerate(*session); PaintSessionArrange(*session); diff --git a/src/openrct2/paint/Paint.cpp b/src/openrct2/paint/Paint.cpp index 2f13fdf333..a8afdc3d80 100644 --- a/src/openrct2/paint/Paint.cpp +++ b/src/openrct2/paint/Paint.cpp @@ -103,38 +103,40 @@ static void PaintSessionAddPSToQuadrant(PaintSession& session, PaintStruct* ps) session.QuadrantFrontIndex = std::max(session.QuadrantFrontIndex, paintQuadrantIndex); } -static constexpr bool ImageWithinDPI(const ScreenCoordsXY& imagePos, const G1Element& g1, const DrawPixelInfo& dpi) +static constexpr bool imageWithinDPI(const ScreenCoordsXY& imagePos, const G1Element& g1, const DrawPixelInfo& dpi) { - int32_t left = imagePos.x + g1.x_offset; - int32_t bottom = imagePos.y + g1.y_offset; + const int32_t left = imagePos.x + g1.x_offset; + const int32_t bottom = imagePos.y + g1.y_offset; - int32_t right = left + g1.width; - int32_t top = bottom + g1.height; + const int32_t right = left + g1.width; + const int32_t top = bottom + g1.height; // mber: It is possible to use only the bottom else block here if you change <= and >= to simply < and >. // However, since this is used to cull paint structs, I'd prefer to keep the condition strict and calculate // the culling differently for minifying and magnifying. - auto zoom = dpi.zoom_level; + const auto zoom = dpi.zoom_level; if (zoom > ZoomLevel{ 0 }) { - if (right <= dpi.WorldX()) + const int32_t x = zoom.ApplyTo(dpi.cullingX); + const int32_t y = zoom.ApplyTo(dpi.cullingY); + if (right <= x) return false; - if (top <= dpi.WorldY()) + if (top <= y) return false; - if (left >= dpi.WorldX() + dpi.WorldWidth()) + if (left >= x + zoom.ApplyTo(dpi.cullingWidth)) return false; - if (bottom >= dpi.WorldY() + dpi.WorldHeight()) + if (bottom >= y + zoom.ApplyTo(dpi.cullingHeight)) return false; } else { - if (zoom.ApplyInversedTo(right) <= dpi.x) + if (zoom.ApplyInversedTo(right) <= dpi.cullingX) return false; - if (zoom.ApplyInversedTo(top) <= dpi.y) + if (zoom.ApplyInversedTo(top) <= dpi.cullingY) return false; - if (zoom.ApplyInversedTo(left) >= dpi.x + dpi.width) + if (zoom.ApplyInversedTo(left) >= dpi.cullingX + dpi.cullingWidth) return false; - if (zoom.ApplyInversedTo(bottom) >= dpi.y + dpi.height) + if (zoom.ApplyInversedTo(bottom) >= dpi.cullingY + dpi.cullingHeight) return false; } return true; @@ -184,7 +186,7 @@ static PaintStruct* CreateNormalPaintStruct( const auto imagePos = Translate3DTo2DWithZ(session.CurrentRotation, swappedRotCoord); - if (!ImageWithinDPI(imagePos, *g1, session.DPI)) + if (!imageWithinDPI(imagePos, *g1, session.DPI)) { return nullptr; } @@ -232,7 +234,7 @@ static PaintStruct* CreateNormalPaintStructHeight( const auto imagePos = Translate3DTo2DWithZ(session.CurrentRotation, swappedRotCoord); - if (!ImageWithinDPI(imagePos, *g1, session.DPI)) + if (!imageWithinDPI(imagePos, *g1, session.DPI)) { return nullptr; }