From 3d1c2f4e29f7389462ae0f77c8dd5021bc2d3251 Mon Sep 17 00:00:00 2001 From: mix Date: Sun, 27 Apr 2025 02:16:25 +0100 Subject: [PATCH 1/2] Revert "Nuke the bad culling, causes just odd artifacts, fast enough now" This reverts commit 105d0e6c4ff5763610b2d42281a74f9a4655a061. --- src/openrct2/paint/Paint.cpp | 49 ++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/openrct2/paint/Paint.cpp b/src/openrct2/paint/Paint.cpp index 58f94b666c..2f13fdf333 100644 --- a/src/openrct2/paint/Paint.cpp +++ b/src/openrct2/paint/Paint.cpp @@ -103,6 +103,43 @@ 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) +{ + int32_t left = imagePos.x + g1.x_offset; + int32_t bottom = imagePos.y + g1.y_offset; + + 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; +} + static constexpr CoordsXYZ RotateBoundBoxSize(const CoordsXYZ& bbSize, const uint8_t rotation) { auto output = bbSize; @@ -146,6 +183,12 @@ static PaintStruct* CreateNormalPaintStruct( swappedRotCoord += session.SpritePosition; const auto imagePos = Translate3DTo2DWithZ(session.CurrentRotation, swappedRotCoord); + + if (!ImageWithinDPI(imagePos, *g1, session.DPI)) + { + return nullptr; + } + const auto rotBoundBoxOffset = CoordsXYZ{ boundBox.offset.Rotate(swappedRotation), boundBox.offset.z }; const auto rotBoundBoxSize = RotateBoundBoxSize(boundBox.length, session.CurrentRotation); @@ -188,6 +231,12 @@ static PaintStruct* CreateNormalPaintStructHeight( swappedRotCoord += session.SpritePosition; const auto imagePos = Translate3DTo2DWithZ(session.CurrentRotation, swappedRotCoord); + + if (!ImageWithinDPI(imagePos, *g1, session.DPI)) + { + return nullptr; + } + const auto rotBoundBoxOffset = CoordsXYZ{ boundBox.offset.Rotate(swappedRotation), boundBox.offset.z + height }; const auto rotBoundBoxSize = RotateBoundBoxSize(boundBox.length, session.CurrentRotation); From b5c925da3676e9601d12f80918e1507c2985ee4a Mon Sep 17 00:00:00 2001 From: mix Date: Sun, 27 Apr 2025 02:16:58 +0100 Subject: [PATCH 2/2] Fix sprite culling glitching by culling sprites at full column width --- src/openrct2/paint/Paint.cpp | 49 ++++++++++++------------------------ 1 file changed, 16 insertions(+), 33 deletions(-) diff --git a/src/openrct2/paint/Paint.cpp b/src/openrct2/paint/Paint.cpp index 2f13fdf333..e2d653d13f 100644 --- a/src/openrct2/paint/Paint.cpp +++ b/src/openrct2/paint/Paint.cpp @@ -103,40 +103,23 @@ 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 imageWithinColumn(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 right = left + g1.width; - int32_t right = left + g1.width; - int32_t top = bottom + g1.height; + 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; - // 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; } @@ -184,7 +167,7 @@ static PaintStruct* CreateNormalPaintStruct( const auto imagePos = Translate3DTo2DWithZ(session.CurrentRotation, swappedRotCoord); - if (!ImageWithinDPI(imagePos, *g1, session.DPI)) + if (!imageWithinColumn(imagePos, *g1, session.DPI)) { return nullptr; } @@ -232,7 +215,7 @@ static PaintStruct* CreateNormalPaintStructHeight( const auto imagePos = Translate3DTo2DWithZ(session.CurrentRotation, swappedRotCoord); - if (!ImageWithinDPI(imagePos, *g1, session.DPI)) + if (!imageWithinColumn(imagePos, *g1, session.DPI)) { return nullptr; }