ULTIMA8: Add more sort item tests and fixes for flat items

This commit is contained in:
Matthew Jimenez 2023-09-29 17:24:44 -05:00
parent 7882f7d496
commit 3bd21ab50c
2 changed files with 126 additions and 65 deletions

View File

@ -416,51 +416,42 @@ inline bool SortItem::below(const SortItem &si2) const {
if (si1._sprite != si2._sprite)
return si1._sprite < si2._sprite;
// Clearly in z and lower is non-flat?
if (si1._z < si2._z && si1._zTop <= si2._z)
// Clearly in Z and one must not be flat - lower cannot be inventory
if (si1._zTop <= si2._z && !(si1._flat && si2._flat) && !si1._invitem)
return true;
if (si1._z > si2._z && si1._z >= si2._zTop)
if (si1._z >= si2._zTop && !(si1._flat && si2._flat) && !si2._invitem)
return false;
// Clearly in y?
if (si1._y <= si2._yFar)
// Clearly in Y and one must not be flat
bool yFlat1 = si1._yFar == si1._y;
bool yFlat2 = si2._yFar == si2._y;
if (si1._y <= si2._yFar && !(yFlat1 && yFlat2))
return true;
if (si1._yFar >= si2._y)
if (si1._yFar >= si2._y && !(yFlat1 && yFlat2))
return false;
// Clearly in x?
if (si1._x <= si2._xLeft)
// Clearly in X and one must not be flat
bool xFlat1 = si1._xLeft == si1._x;
bool xFlat2 = si2._xLeft == si2._x;
if (si1._x <= si2._xLeft && !(xFlat1 && xFlat2))
return true;
if (si1._xLeft >= si2._x)
if (si1._xLeft >= si2._x && !(xFlat1 && xFlat2))
return false;
// Overlapping z-bottom check
// If an object's base (z-bottom) is higher another's, it should be rendered after.
// This check must be on the z-bottom and not the z-top because two objects with the
// same z-position may have different heights (think of a mouse sorting vs the Avatar).
if (si1._z != si2._z && si1._solid == si2._solid)
return si1._z < si2._z;
// Are overlapping in all 3 dimensions if we come here
// Inv items always drawn after
if (si1._invitem != si2._invitem)
return si1._invitem < si2._invitem;
// Flat always gets drawn before
if (si1._flat != si2._flat)
return si1._flat > si2._flat;
// Specialist handling for same location
if (si1._x == si2._x && si1._y == si2._y) {
// Trans always gets drawn after
if (si1._trans != si2._trans)
return si1._trans < si2._trans;
}
// Specialist z flat handling
if (si1._flat && si2._flat) {
if (si1._flat || si2._flat) {
// Lower z-bottom drawn before
if (si1._z != si2._z)
return si1._z < si2._z;
// Inv items always drawn after
if (si1._invitem != si2._invitem)
return si1._invitem < si2._invitem;
// Flat gets drawn before
if (si1._flat != si2._flat)
return si1._flat > si2._flat;
// Trans always gets drawn after
if (si1._trans != si2._trans)
return si1._trans < si2._trans;
@ -486,21 +477,24 @@ inline bool SortItem::below(const SortItem &si2) const {
return si1._fbigsq > si2._fbigsq;
}
// Disabled: Land always gets drawn first
//if (si1._land != si2._land)
// return si1._land > si2._land;
// Y-flat vs non-flat handling
if (yFlat1 != yFlat2 && si1._fixed == si2._fixed) {
if (yFlat1) {
if (si2._y - 32 > si2._yFar) {
int32 yCenter2 = (si2._yFar + si2._y) / 2;
return si1._y <= yCenter2;
}
return false;
} else {
if (si1._y - 32 > si1._yFar) {
int32 yCenter1 = (si1._yFar + si1._y) / 2;
return yCenter1 < si2._y;
}
return true;
}
}
// Land always gets drawn before roof
if (si1._land && si2._land && si1._roof != si2._roof)
return si1._roof < si2._roof;
// Roof always gets drawn first
if (si1._roof != si2._roof)
return si1._roof > si2._roof;
// X-Flat gets drawn after under specific conditions
bool xFlat1 = si1._xLeft == si1._x;
bool xFlat2 = si2._xLeft == si2._x;
// X-flat vs non-flat handling
if (xFlat1 != xFlat2 && si1._fixed == si2._fixed) {
if (xFlat1) {
if (si2._x - 32 > si2._xLeft) {
@ -517,25 +511,37 @@ inline bool SortItem::below(const SortItem &si2) const {
}
}
// Y-Flat gets drawn after under specific conditions
bool yFlat1 = si1._yFar == si1._y;
bool yFlat2 = si2._yFar == si2._y;
if (yFlat1 != yFlat2 && si1._fixed == si2._fixed) {
if (yFlat1) {
if (si2._y - 32 > si2._yFar) {
int32 yCenter2 = (si2._yFar + si2._y) / 2;
return si1._y <= yCenter2;
}
return false;
} else {
if (si1._y - 32 > si1._yFar) {
int32 yCenter1 = (si1._yFar + si1._y) / 2;
return yCenter1 < si2._y;
}
// Check z-bottom with a tolerance
if (si1._z != si2._z) {
if (si1._z < si2._z - 8)
return true;
}
else if (si1._z - 8 > si2._z)
return false;
}
// Specialist handling for same location
if (si1._x == si2._x && si1._y == si2._y) {
// Trans always gets drawn after
if (si1._trans != si2._trans)
return si1._trans < si2._trans;
}
// Disabled: Land always gets drawn first
// if (si1._land != si2._land)
// return si1._land > si2._land;
// Land always gets drawn before roof
if (si1._land && si2._land && si1._roof != si2._roof)
return si1._roof < si2._roof;
// Roof always gets drawn first
if (si1._roof != si2._roof)
return si1._roof > si2._roof;
// Lower z-bottom drawn before
if (si1._z != si2._z)
return si1._z < si2._z;
// Partial in X + Y front
if (si1._x + si1._y != si2._x + si2._y)
return (si1._x + si1._y < si2._x + si2._y);

View File

@ -368,6 +368,33 @@ class U8SortItemTestSuite : public CxxTest::TestSuite {
TS_ASSERT(si2.below(si1));
}
/**
* Completely Overlapping y-flats differing only in item number and frame
* Test case for rendering issue at MainActor::teleport 37 17628 19668 56
*/
void test_y_flat_layered_sort() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(17599, 19455, 56, 128, 0, 40);
si1.setBoxBounds(b1, 0, 0);
si1._fixed = true;
si1._shapeNum = 322;
si1._frame = 1;
Ultima::Ultima8::Box b2(17599, 19455, 56, 128, 0, 40);
si2.setBoxBounds(b2, 0, 0);
si2._fixed = true;
si2._shapeNum = 322;
si2._frame = 3;
TS_ASSERT(si1.overlap(si2));
TS_ASSERT(si2.overlap(si1));
TS_ASSERT(si1.below(si2));
TS_ASSERT(!si2.below(si1));
}
/**
* Overlapping y-flat vs non-flat items
* Test case for rendering issue at MainActor::teleport 37 18992 17664 104
@ -445,6 +472,34 @@ class U8SortItemTestSuite : public CxxTest::TestSuite {
TS_ASSERT(!si2.below(si1));
}
/**
* Overlapping z-flat vs x-flat items
* Test case for rendering issue at MainActor::teleport 37 17736 18320 144
*/
void test_z_flat_vs_x_flat_sort() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(17535, 18559, 144, 128, 128, 0);
si1.setBoxBounds(b1, 0, 0);
si1._flat = true;
si1._solid = true;
si1._occl = true;
si1._fbigsq = true;
si1._roof = true;
si1._land = true;
si1._fixed = true;
Ultima::Ultima8::Box b2(17440, 18448, 106, 0, 96, 40);
si2.setBoxBounds(b2, 0, 0);
si2._fixed = true;
TS_ASSERT(si1.overlap(si2));
TS_ASSERT(si2.overlap(si1));
TS_ASSERT(!si1.below(si2));
TS_ASSERT(si2.below(si1));
}
/**
* Overlapping non-flat items clearly in z - avatar above candle
* Test case for rendering issue at MainActor::teleport 6 7774 19876 48