diff --git a/src/openrct2/paint/Paint.cpp b/src/openrct2/paint/Paint.cpp index f88b011bf7..f4d9913b37 100644 --- a/src/openrct2/paint/Paint.cpp +++ b/src/openrct2/paint/Paint.cpp @@ -178,7 +178,6 @@ static paint_struct* CreateNormalPaintStruct( ps->attached_ps = nullptr; ps->children = nullptr; ps->sprite_type = session->InteractionType; - ps->var_29 = 0; ps->map_x = session->MapPosition.x; ps->map_y = session->MapPosition.y; ps->tileElement = reinterpret_cast(const_cast(session->CurrentlyDrawnItem)); @@ -298,11 +297,21 @@ template<> bool CheckBoundingBox<3>(const paint_struct_bound_box& initialBBox, c return false; } +namespace PaintSortFlags +{ + static constexpr uint8_t None = 0; + static constexpr uint8_t PendingVisit = (1U << 0); + static constexpr uint8_t Neighbour = (1U << 1); + static constexpr uint8_t OutsideQuadrant = (1U << 7); +} // namespace PaintSortFlags + template static paint_struct* PaintArrangeStructsHelperRotation(paint_struct* ps_next, uint16_t quadrantIndex, uint8_t flag) { paint_struct* ps; paint_struct* ps_temp; + + // Get the first node in the specified quadrant. do { ps = ps_next; @@ -311,9 +320,12 @@ static paint_struct* PaintArrangeStructsHelperRotation(paint_struct* ps_next, ui return ps; } while (quadrantIndex > ps_next->quadrant_index); - // Cache the last visited node so we don't have to walk the whole list again - paint_struct* ps_cache = ps; + // We keep track of the first node in the quadrant so the next call with a higher quadrant index + // can use this node to skip some iterations. + paint_struct* psQuadrantEntry = ps; + // Visit all nodes in the linked quadrant list and determine their current + // sorting relevancy. ps_temp = ps; do { @@ -323,47 +335,63 @@ static paint_struct* PaintArrangeStructsHelperRotation(paint_struct* ps_next, ui if (ps->quadrant_index > quadrantIndex + 1) { - ps->quadrant_flags = PAINT_QUADRANT_FLAG_BIGGER; + // Outside of the range. + ps->SortFlags = PaintSortFlags::OutsideQuadrant; } else if (ps->quadrant_index == quadrantIndex + 1) { - ps->quadrant_flags = PAINT_QUADRANT_FLAG_NEXT | PAINT_QUADRANT_FLAG_IDENTICAL; + // Is neighbour and requires a visit. + ps->SortFlags = PaintSortFlags::Neighbour | PaintSortFlags::PendingVisit; } else if (ps->quadrant_index == quadrantIndex) { - ps->quadrant_flags = flag | PAINT_QUADRANT_FLAG_IDENTICAL; + // In specified quadrant, requires visit. + ps->SortFlags = flag | PaintSortFlags::PendingVisit; } } while (ps->quadrant_index <= quadrantIndex + 1); ps = ps_temp; + // Iterate all nodes in the current list and re-order them based on + // the current rotation and their bounding box. while (true) { + // Get the first pending node in the quadrant list while (true) { ps_next = ps->next_quadrant_ps; if (ps_next == nullptr) - return ps_cache; - if (ps_next->quadrant_flags & PAINT_QUADRANT_FLAG_BIGGER) - return ps_cache; - if (ps_next->quadrant_flags & PAINT_QUADRANT_FLAG_IDENTICAL) + { + // End of the current list. + return psQuadrantEntry; + } + if (ps_next->SortFlags & PaintSortFlags::OutsideQuadrant) + { + // Reached point outside of specified quadrant. + return psQuadrantEntry; + } + if (ps_next->SortFlags & PaintSortFlags::PendingVisit) + { + // Found node to check on. break; + } ps = ps_next; } - ps_next->quadrant_flags &= ~PAINT_QUADRANT_FLAG_IDENTICAL; + // Mark visited. + ps_next->SortFlags &= ~PaintSortFlags::PendingVisit; ps_temp = ps; + // Compare current node against the remaining children. const paint_struct_bound_box& initialBBox = ps_next->bounds; - while (true) { ps = ps_next; ps_next = ps_next->next_quadrant_ps; if (ps_next == nullptr) break; - if (ps_next->quadrant_flags & PAINT_QUADRANT_FLAG_BIGGER) + if (ps_next->SortFlags & PaintSortFlags::OutsideQuadrant) break; - if (!(ps_next->quadrant_flags & PAINT_QUADRANT_FLAG_NEXT)) + if (!(ps_next->SortFlags & PaintSortFlags::Neighbour)) continue; const paint_struct_bound_box& currentBBox = ps_next->bounds; @@ -372,6 +400,7 @@ static paint_struct* PaintArrangeStructsHelperRotation(paint_struct* ps_next, ui if (compareResult) { + // Child node intersects with current node, move behind. ps->next_quadrant_ps = ps_next->next_quadrant_ps; paint_struct* ps_temp2 = ps_temp->next_quadrant_ps; ps_temp->next_quadrant_ps = ps_next; @@ -410,12 +439,12 @@ template static void PaintSessionArrange(PaintSessionCore* sessio } while (++quadrantIndex <= session->QuadrantFrontIndex); paint_struct* ps_cache = PaintArrangeStructsHelperRotation( - psHead, session->QuadrantBackIndex & 0xFFFF, PAINT_QUADRANT_FLAG_NEXT); + psHead, session->QuadrantBackIndex & 0xFFFF, PaintSortFlags::Neighbour); quadrantIndex = session->QuadrantBackIndex; while (++quadrantIndex < session->QuadrantFrontIndex) { - ps_cache = PaintArrangeStructsHelperRotation(ps_cache, quadrantIndex & 0xFFFF, 0); + ps_cache = PaintArrangeStructsHelperRotation(ps_cache, quadrantIndex & 0xFFFF, PaintSortFlags::None); } } } diff --git a/src/openrct2/paint/Paint.h b/src/openrct2/paint/Paint.h index 87dfaee9cc..9fbd29d124 100644 --- a/src/openrct2/paint/Paint.h +++ b/src/openrct2/paint/Paint.h @@ -23,6 +23,7 @@ enum class ViewportInteractionItem : uint8_t; struct attached_paint_struct { + attached_paint_struct* next; uint32_t image_id; union { @@ -33,15 +34,6 @@ struct attached_paint_struct int32_t x; int32_t y; uint8_t flags; - uint8_t pad_0D; - attached_paint_struct* next; -}; - -enum PAINT_QUADRANT_FLAGS -{ - PAINT_QUADRANT_FLAG_IDENTICAL = (1 << 0), - PAINT_QUADRANT_FLAG_BIGGER = (1 << 7), - PAINT_QUADRANT_FLAG_NEXT = (1 << 1), }; struct paint_struct_bound_box @@ -56,6 +48,11 @@ struct paint_struct_bound_box struct paint_struct { + paint_struct_bound_box bounds; + attached_paint_struct* attached_ps; + paint_struct* children; + paint_struct* next_quadrant_ps; + TileElement* tileElement; uint32_t image_id; union { @@ -63,31 +60,24 @@ struct paint_struct // If masked image_id is masked_id uint32_t colour_image_id; }; - paint_struct_bound_box bounds; int32_t x; int32_t y; - uint16_t quadrant_index; - uint8_t flags; - uint8_t quadrant_flags; - attached_paint_struct* attached_ps; - paint_struct* children; - paint_struct* next_quadrant_ps; - ViewportInteractionItem sprite_type; - uint8_t var_29; - uint16_t pad_2A; int32_t map_x; int32_t map_y; - TileElement* tileElement; + uint16_t quadrant_index; + uint8_t flags; + uint8_t SortFlags; + ViewportInteractionItem sprite_type; }; struct paint_string_struct { - rct_string_id string_id; // 0x00 - paint_string_struct* next; // 0x02 - int32_t x; // 0x06 - int32_t y; // 0x08 - uint32_t args[4]; // 0x0A - uint8_t* y_offsets; // 0x1A + rct_string_id string_id; + paint_string_struct* next; + int32_t x; + int32_t y; + uint32_t args[4]; + uint8_t* y_offsets; }; union paint_entry