mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-06 06:32:56 +01:00
Add stable paint sort (as a debug option)
This commit is contained in:
@@ -3785,3 +3785,4 @@ STR_6706 :{WINDOW_COLOUR_2}Current image file: {BLACK}{STRING}
|
||||
STR_6707 :(none selected)
|
||||
STR_6708 :Smooth Strength
|
||||
STR_6709 :Enter Smooth Strength between {COMMA16} and {COMMA16}
|
||||
STR_6710 :Stable sort
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
- Improved: [#23051] Add large sloped turns and new inversions to the Twister, Vertical Drop, Hyper and Flying Roller Coasters.
|
||||
- Improved: [#23123] Improve sorting of roller coasters in build new ride menu.
|
||||
- Improved: [#23211] Add boosters to classic wooden roller coaster (cheats only).
|
||||
- Improved: [#23229] Add debug option for making the sprite sorting algorithm stable.
|
||||
- Improved: [#23233] Add diagonal booster to LSM Launched Coaster.
|
||||
- Fix: [#20070, #22972] Missing and mismatched flat and sloped footpaths on several scenarios.
|
||||
- Fix: [#22726] ‘Force park rating’ cheat is not saved with the park.
|
||||
|
||||
@@ -455,6 +455,7 @@ namespace OpenRCT2
|
||||
STR_DEBUG_PAINT_SHOW_DIRTY_VISUALS = 6144,
|
||||
STR_DEBUG_PAINT_SHOW_SEGMENT_HEIGHTS = 5901,
|
||||
STR_DEBUG_PAINT_SHOW_WIDE_PATHS = 6261,
|
||||
STR_DEBUG_PAINT_STABLE_SORT = 6710,
|
||||
|
||||
// Window: DemolishRidePrompt
|
||||
STR_DEMOLISH = 994,
|
||||
|
||||
@@ -27,10 +27,11 @@ namespace OpenRCT2::Ui::Windows
|
||||
WIDX_TOGGLE_SHOW_SEGMENT_HEIGHTS,
|
||||
WIDX_TOGGLE_SHOW_BOUND_BOXES,
|
||||
WIDX_TOGGLE_SHOW_DIRTY_VISUALS,
|
||||
WIDX_TOGGLE_STABLE_PAINT_SORT,
|
||||
};
|
||||
|
||||
constexpr int32_t WINDOW_WIDTH = 200;
|
||||
constexpr int32_t WINDOW_HEIGHT = 8 + 15 + 15 + 15 + 15 + 11 + 8;
|
||||
constexpr int32_t WINDOW_HEIGHT = 8 + (15 * 6) + 8;
|
||||
|
||||
// clang-format off
|
||||
static Widget window_debug_paint_widgets[] = {
|
||||
@@ -40,6 +41,7 @@ namespace OpenRCT2::Ui::Windows
|
||||
MakeWidget({8, 8 + 15 * 2}, { 185, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_DEBUG_PAINT_SHOW_SEGMENT_HEIGHTS),
|
||||
MakeWidget({8, 8 + 15 * 3}, { 185, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_DEBUG_PAINT_SHOW_BOUND_BOXES ),
|
||||
MakeWidget({8, 8 + 15 * 4}, { 185, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_DEBUG_PAINT_SHOW_DIRTY_VISUALS ),
|
||||
MakeWidget({8, 8 + 15 * 5}, { 185, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_DEBUG_PAINT_STABLE_SORT ),
|
||||
kWidgetsEnd,
|
||||
};
|
||||
// clang-format on
|
||||
@@ -91,6 +93,11 @@ namespace OpenRCT2::Ui::Windows
|
||||
gShowDirtyVisuals = !gShowDirtyVisuals;
|
||||
GfxInvalidateScreen();
|
||||
break;
|
||||
|
||||
case WIDX_TOGGLE_STABLE_PAINT_SORT:
|
||||
gPaintStableSort = !gPaintStableSort;
|
||||
GfxInvalidateScreen();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,6 +143,7 @@ namespace OpenRCT2::Ui::Windows
|
||||
WidgetSetCheckboxValue(*this, WIDX_TOGGLE_SHOW_SEGMENT_HEIGHTS, gShowSupportSegmentHeights);
|
||||
WidgetSetCheckboxValue(*this, WIDX_TOGGLE_SHOW_BOUND_BOXES, gPaintBoundingBoxes);
|
||||
WidgetSetCheckboxValue(*this, WIDX_TOGGLE_SHOW_DIRTY_VISUALS, gShowDirtyVisuals);
|
||||
WidgetSetCheckboxValue(*this, WIDX_TOGGLE_STABLE_PAINT_SORT, gPaintStableSort);
|
||||
}
|
||||
|
||||
void OnDraw(DrawPixelInfo& dpi) override
|
||||
|
||||
@@ -57,6 +57,7 @@ static constexpr uint8_t BoundBoxDebugColours[] = {
|
||||
bool gShowDirtyVisuals;
|
||||
bool gPaintBoundingBoxes;
|
||||
bool gPaintBlockedTiles;
|
||||
bool gPaintStableSort;
|
||||
|
||||
static void PaintAttachedPS(DrawPixelInfo& dpi, PaintStruct* ps, uint32_t viewFlags);
|
||||
static void PaintPSImageWithBoundingBoxes(PaintSession& session, PaintStruct* ps, ImageId imageId, int32_t x, int32_t y);
|
||||
@@ -403,13 +404,14 @@ static std::pair<PaintStruct*, PaintStruct*> PaintStructsGetNextPending(PaintStr
|
||||
// Re-orders all nodes after the specified child node and marks the child node as traversed. The resulting
|
||||
// order of the children is the depth based on rotation and dimensions of the bounding box.
|
||||
template<uint8_t TRotation>
|
||||
static void PaintStructsSortQuadrant(PaintStruct* parent, PaintStruct* child)
|
||||
static void PaintStructsSortQuadrantLegacy(PaintStruct* parent, PaintStruct* child)
|
||||
{
|
||||
// Mark visited.
|
||||
child->SortFlags &= ~PaintSortFlags::PendingVisit;
|
||||
|
||||
// Compare all the children below the first child and move them up in the list if they intersect.
|
||||
const PaintStructBoundBox& initialBBox = child->Bounds;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
auto* ps = child;
|
||||
@@ -443,7 +445,78 @@ static void PaintStructsSortQuadrant(PaintStruct* parent, PaintStruct* child)
|
||||
}
|
||||
}
|
||||
|
||||
// Re-orders all nodes after the specified child node and marks the child node as traversed. The resulting
|
||||
// order of the children is the depth based on rotation and dimensions of the bounding box.
|
||||
template<uint8_t TRotation>
|
||||
static void PaintStructsSortQuadrantStable(PaintStruct* parent, PaintStruct* child)
|
||||
{
|
||||
// Mark visited.
|
||||
child->SortFlags &= ~PaintSortFlags::PendingVisit;
|
||||
|
||||
// Compare all the children below the first child and move them up in the list if they intersect.
|
||||
const PaintStructBoundBox& initialBBox = child->Bounds;
|
||||
|
||||
// Create a temporary list to collect sorted nodes in stable order.
|
||||
PaintStruct* sortedHead = nullptr;
|
||||
PaintStruct* sortedTail = nullptr;
|
||||
|
||||
// Traverse the list and reorder based on intersection.
|
||||
for (;;)
|
||||
{
|
||||
PaintStruct* next = child->NextQuadrantEntry;
|
||||
|
||||
if (next != nullptr)
|
||||
{
|
||||
PREFETCH(&next->Bounds);
|
||||
}
|
||||
|
||||
// Stop if at the end of the list or outside the quadrant range.
|
||||
if (next == nullptr || next->SortFlags & PaintSortFlags::OutsideQuadrant)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Ignore nodes that are not neighbors.
|
||||
if (!(next->SortFlags & PaintSortFlags::Neighbour))
|
||||
{
|
||||
child = next;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Detach the current node from the list if it intersects.
|
||||
if (CheckBoundingBox<TRotation>(initialBBox, next->Bounds))
|
||||
{
|
||||
child->NextQuadrantEntry = next->NextQuadrantEntry;
|
||||
|
||||
if (sortedHead == nullptr)
|
||||
{
|
||||
sortedHead = next;
|
||||
sortedTail = next;
|
||||
next->NextQuadrantEntry = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
sortedTail->NextQuadrantEntry = next;
|
||||
sortedTail = next;
|
||||
next->NextQuadrantEntry = nullptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
child = next;
|
||||
}
|
||||
}
|
||||
|
||||
// Merge the sorted list back into the main list after parent.
|
||||
if (sortedHead != nullptr)
|
||||
{
|
||||
PaintStruct* originalNext = parent->NextQuadrantEntry;
|
||||
parent->NextQuadrantEntry = sortedHead;
|
||||
sortedTail->NextQuadrantEntry = originalNext;
|
||||
}
|
||||
}
|
||||
|
||||
template<bool TStableSort, uint8_t TRotation>
|
||||
static PaintStruct* PaintArrangeStructsHelperRotation(PaintStruct* psQuadrantEntry, uint16_t quadrantIndex, uint8_t flag)
|
||||
{
|
||||
// We keep track of the first node in the quadrant so the next call with a higher quadrant index
|
||||
@@ -464,7 +537,15 @@ static PaintStruct* PaintArrangeStructsHelperRotation(PaintStruct* psQuadrantEnt
|
||||
break;
|
||||
}
|
||||
|
||||
PaintStructsSortQuadrant<TRotation>(parent, child);
|
||||
if constexpr (TStableSort)
|
||||
{
|
||||
PaintStructsSortQuadrantStable<TRotation>(parent, child);
|
||||
}
|
||||
else
|
||||
{
|
||||
PaintStructsSortQuadrantLegacy<TRotation>(parent, child);
|
||||
}
|
||||
|
||||
ps = parent;
|
||||
}
|
||||
|
||||
@@ -496,7 +577,7 @@ static void PaintStructsLinkQuadrants(PaintSessionCore& session, PaintStruct& ps
|
||||
} while (++quadrantIndex <= session.QuadrantFrontIndex);
|
||||
}
|
||||
|
||||
template<int TRotation>
|
||||
template<bool TStableSort, int TRotation>
|
||||
static void PaintSessionArrangeImpl(PaintSessionCore& session)
|
||||
{
|
||||
uint32_t quadrantIndex = session.QuadrantBackIndex;
|
||||
@@ -511,12 +592,13 @@ static void PaintSessionArrangeImpl(PaintSessionCore& session)
|
||||
PaintStruct psHead{};
|
||||
PaintStructsLinkQuadrants(session, psHead);
|
||||
|
||||
PaintStruct* psNextQuadrant = PaintArrangeStructsHelperRotation<TRotation>(
|
||||
PaintStruct* psNextQuadrant = PaintArrangeStructsHelperRotation<TStableSort, TRotation>(
|
||||
&psHead, session.QuadrantBackIndex, PaintSortFlags::Neighbour);
|
||||
|
||||
while (++quadrantIndex < session.QuadrantFrontIndex)
|
||||
{
|
||||
psNextQuadrant = PaintArrangeStructsHelperRotation<TRotation>(psNextQuadrant, quadrantIndex, PaintSortFlags::None);
|
||||
psNextQuadrant = PaintArrangeStructsHelperRotation<TStableSort, TRotation>(
|
||||
psNextQuadrant, quadrantIndex, PaintSortFlags::None);
|
||||
}
|
||||
|
||||
session.PaintHead = psHead.NextQuadrantEntry;
|
||||
@@ -524,11 +606,18 @@ static void PaintSessionArrangeImpl(PaintSessionCore& session)
|
||||
|
||||
using PaintArrangeWithRotation = void (*)(PaintSessionCore& session);
|
||||
|
||||
constexpr std::array _paintArrangeFuncs = {
|
||||
PaintSessionArrangeImpl<0>,
|
||||
PaintSessionArrangeImpl<1>,
|
||||
PaintSessionArrangeImpl<2>,
|
||||
PaintSessionArrangeImpl<3>,
|
||||
constexpr std::array _paintArrangeFuncsLegacy = {
|
||||
PaintSessionArrangeImpl<false, 0>,
|
||||
PaintSessionArrangeImpl<false, 1>,
|
||||
PaintSessionArrangeImpl<false, 2>,
|
||||
PaintSessionArrangeImpl<false, 3>,
|
||||
};
|
||||
|
||||
constexpr std::array _paintArrangeFuncsStable = {
|
||||
PaintSessionArrangeImpl<true, 0>,
|
||||
PaintSessionArrangeImpl<true, 1>,
|
||||
PaintSessionArrangeImpl<true, 2>,
|
||||
PaintSessionArrangeImpl<true, 3>,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -538,7 +627,11 @@ constexpr std::array _paintArrangeFuncs = {
|
||||
void PaintSessionArrange(PaintSessionCore& session)
|
||||
{
|
||||
PROFILED_FUNCTION();
|
||||
return _paintArrangeFuncs[session.CurrentRotation](session);
|
||||
if (gPaintStableSort)
|
||||
{
|
||||
return _paintArrangeFuncsStable[session.CurrentRotation](session);
|
||||
}
|
||||
return _paintArrangeFuncsLegacy[session.CurrentRotation](session);
|
||||
}
|
||||
|
||||
static void PaintDrawStruct(PaintSession& session, PaintStruct* ps)
|
||||
|
||||
@@ -284,6 +284,7 @@ extern bool gShowDirtyVisuals;
|
||||
extern bool gPaintBoundingBoxes;
|
||||
extern bool gPaintBlockedTiles;
|
||||
extern bool gPaintWidePathsAsGhost;
|
||||
extern bool gPaintStableSort;
|
||||
|
||||
PaintStruct* PaintAddImageAsParent(
|
||||
PaintSession& session, const ImageId image_id, const CoordsXYZ& offset, const BoundBoxXYZ& boundBox);
|
||||
|
||||
Reference in New Issue
Block a user