[Scummvm-git-logs] scummvm master -> 0d0555bd14042f735d9d1bd842cc8b9a44527641
OMGPizzaGuy
noreply at scummvm.org
Sat Sep 30 04:29:52 UTC 2023
This automated email contains information about 3 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
b21876bd9d ULTIMA8: Move sort item calculations to setBoxBounds
a899156273 ULTIMA8: Move SortItem methods from the header to a cpp file.
0d0555bd14 ULTIMA8: Add tolerance when comparing Z in sort item.
Commit: b21876bd9da04c5158719e098c513525fe04d7a3
https://github.com/scummvm/scummvm/commit/b21876bd9da04c5158719e098c513525fe04d7a3
Author: Matthew Jimenez (matthew.jimenez at outlook.com)
Date: 2023-09-29T18:11:42-05:00
Commit Message:
ULTIMA8: Move sort item calculations to setBoxBounds
Changed paths:
engines/ultima/ultima8/world/item_sorter.cpp
engines/ultima/ultima8/world/sort_item.h
test/engines/ultima/ultima8/world/sort_item.h
diff --git a/engines/ultima/ultima8/world/item_sorter.cpp b/engines/ultima/ultima8/world/item_sorter.cpp
index f90e6d9246c..66c2933b193 100644
--- a/engines/ultima/ultima8/world/item_sorter.cpp
+++ b/engines/ultima/ultima8/world/item_sorter.cpp
@@ -163,10 +163,6 @@ void ItemSorter::AddItem(int32 x, int32 y, int32 z, uint32 shapeNum, uint32 fram
si->_groupNum = 0;
#endif // SORTITEM_OCCLUSION_EXPERIMENTAL
- // These help out with sorting. We calc them now, so it will be faster
- si->_fbigsq = (xd == 128 && yd == 128) || (xd == 256 && yd == 256) || (xd == 512 && yd == 512);
- si->_flat = zd == 0;
-
si->_draw = info->is_draw();
si->_solid = info->is_solid();
si->_occl = info->is_occl() && !(si->_flags & Item::FLG_INVISIBLE) &&
diff --git a/engines/ultima/ultima8/world/sort_item.h b/engines/ultima/ultima8/world/sort_item.h
index 685e2e934bf..1d4edfb9fda 100644
--- a/engines/ultima/ultima8/world/sort_item.h
+++ b/engines/ultima/ultima8/world/sort_item.h
@@ -288,6 +288,10 @@ inline void SortItem::setBoxBounds(const Box& box, int32 sx, int32 sy) {
_sr.top = _syTop;
_sr.right = _sxRight;
_sr.bottom = _syBot;
+
+ // These help out with sorting. We calc them now, so it will be faster
+ _fbigsq = box._xd == box._yd && box._xd >= 128;
+ _flat = box._zd == 0;
}
inline Box SortItem::getBoxBounds() const {
diff --git a/test/engines/ultima/ultima8/world/sort_item.h b/test/engines/ultima/ultima8/world/sort_item.h
index 264131660e1..3610879ccc6 100644
--- a/test/engines/ultima/ultima8/world/sort_item.h
+++ b/test/engines/ultima/ultima8/world/sort_item.h
@@ -19,10 +19,8 @@ class U8SortItemTestSuite : public CxxTest::TestSuite {
void test_screenspace_position() {
Ultima::Ultima8::SortItem si1;
- si1._flat = true;
si1._solid = true;
si1._occl = true;
- si1._fbigsq = true;
si1._roof = true;
si1._land = true;
@@ -126,7 +124,6 @@ class U8SortItemTestSuite : public CxxTest::TestSuite {
Ultima::Ultima8::Box b2(34110, 41118, 0, 64, 64, 0);
si2.setBoxBounds(b2, 0, 0);
- si2._flat = true;
si2._invitem = true;
TS_ASSERT(si1.overlap(si2));
@@ -146,9 +143,6 @@ class U8SortItemTestSuite : public CxxTest::TestSuite {
si1.setBoxBounds(b1, 0, 0);
si2.setBoxBounds(b2, 0, 0);
- si1._flat = true;
- si2._flat = true;
-
// If one has a higher z, it's above
si2._z = 1;
TS_ASSERT(si1.below(si2));
@@ -482,10 +476,8 @@ class U8SortItemTestSuite : public CxxTest::TestSuite {
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;
Commit: a89915627383d58f6496fde58561fbd469ff756b
https://github.com/scummvm/scummvm/commit/a89915627383d58f6496fde58561fbd469ff756b
Author: Matthew Jimenez (matthew.jimenez at outlook.com)
Date: 2023-09-29T20:47:27-05:00
Commit Message:
ULTIMA8: Move SortItem methods from the header to a cpp file.
Changed paths:
A engines/ultima/ultima8/world/sort_item.cpp
engines/ultima/module.mk
engines/ultima/ultima8/world/sort_item.h
diff --git a/engines/ultima/module.mk b/engines/ultima/module.mk
index 897f5409265..bd09a519b2e 100644
--- a/engines/ultima/module.mk
+++ b/engines/ultima/module.mk
@@ -537,6 +537,7 @@ MODULE_OBJS := \
ultima8/world/missile_tracker.o \
ultima8/world/monster_egg.o \
ultima8/world/snap_process.o \
+ ultima8/world/sort_item.o \
ultima8/world/split_item_process.o \
ultima8/world/sprite_process.o \
ultima8/world/super_sprite_process.o \
diff --git a/engines/ultima/ultima8/world/sort_item.cpp b/engines/ultima/ultima8/world/sort_item.cpp
new file mode 100644
index 00000000000..06d76d646ff
--- /dev/null
+++ b/engines/ultima/ultima8/world/sort_item.cpp
@@ -0,0 +1,253 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "ultima/ultima8/world/sort_item.h"
+
+namespace Ultima {
+namespace Ultima8 {
+
+void SortItem::setBoxBounds(const Box& box, int32 sx, int32 sy) {
+ _x = box._x;
+ _y = box._y;
+ _z = box._z;
+ _xLeft = _x - box._xd;
+ _yFar = _y - box._yd;
+ _zTop = _z + box._zd;
+
+ // NOTE: Precision loss from integer division is intention to fix
+ // rendering issue at MainActor::teleport 37 18168 17656 104
+
+ // Screenspace bounding box left extent (LNT x coord)
+ _sxLeft = _xLeft / 4 - _y / 4 - sx;
+ // Screenspace bounding box right extent (RFT x coord)
+ _sxRight = _x / 4 - _yFar / 4 - sx;
+
+ // Screenspace bounding box top x coord (LFT x coord)
+ _sxTop = _xLeft / 4 - _yFar / 4 - sx;
+ // Screenspace bounding box top extent (LFT y coord)
+ _syTop = _xLeft / 8 + _yFar / 8 - _zTop - sy;
+
+ // Screenspace bounding box bottom x coord (RNB x coord)
+ _sxBot = _x / 4 - _y / 4 - sx;
+ // Screenspace bounding box bottom extent (RNB y coord)
+ _syBot = _x / 8 + _y / 8 - _z - sy;
+
+ // Screenspace rect - replace with shape frame calculations
+ _sr.left = _sxLeft;
+ _sr.top = _syTop;
+ _sr.right = _sxRight;
+ _sr.bottom = _syBot;
+
+ // These help out with sorting. We calc them now, so it will be faster
+ _fbigsq = box._xd == box._yd && box._xd >= 128;
+ _flat = box._zd == 0;
+}
+
+bool SortItem::below(const SortItem &si2) const {
+ const SortItem &si1 = *this;
+
+ if (si1._sprite != si2._sprite)
+ return si1._sprite < si2._sprite;
+
+ // 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._zTop && !(si1._flat && si2._flat) && !si2._invitem)
+ return false;
+
+ // 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 && !(yFlat1 && yFlat2))
+ return false;
+
+ // 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 && !(xFlat1 && xFlat2))
+ return false;
+
+ // Specialist z flat handling
+ 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;
+
+ // Animated always gets drawn after
+ if (si1._anim != si2._anim)
+ return si1._anim < si2._anim;
+
+ // Draw always gets drawn first
+ if (si1._draw != si2._draw)
+ return si1._draw > si2._draw;
+
+ // Solid always gets drawn first
+ if (si1._solid != si2._solid)
+ return si1._solid > si2._solid;
+
+ // Occludes always get drawn first
+ if (si1._occl != si2._occl)
+ return si1._occl > si2._occl;
+
+ // Large flats squares get drawn first
+ if (si1._fbigsq != si2._fbigsq)
+ return si1._fbigsq > si2._fbigsq;
+ }
+
+ // 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;
+ }
+ }
+
+ // X-flat vs non-flat handling
+ if (xFlat1 != xFlat2 && si1._fixed == si2._fixed) {
+ if (xFlat1) {
+ if (si2._x - 32 > si2._xLeft) {
+ int32 xCenter2 = (si2._xLeft + si2._x) / 2;
+ return si1._x <= xCenter2;
+ }
+ return false;
+ } else {
+ if (si1._x - 32 > si1._xLeft) {
+ int32 xCenter1 = (si1._xLeft + si1._x) / 2;
+ return xCenter1 < si2._x;
+ }
+ return true;
+ }
+ }
+
+ // 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);
+
+ // Partial in X + Y back
+ if (si1._xLeft + si1._yFar != si2._xLeft + si2._yFar)
+ return (si1._xLeft + si1._yFar < si2._xLeft + si2._yFar);
+
+ // Partial in y?
+ if (si1._y != si2._y)
+ return si1._y < si2._y;
+
+ // Partial in x?
+ if (si1._x != si2._x)
+ return si1._x < si2._x;
+
+ // Just sort by shape number
+ if (si1._shapeNum != si2._shapeNum)
+ return si1._shapeNum < si2._shapeNum;
+
+ // And then by _frame
+ return si1._frame < si2._frame;
+}
+
+Common::String SortItem::dumpInfo() const {
+ Box b = getBoxBounds();
+ Common::String info = Common::String::format("%u:%u (%d, %d, %d, %d, %d, %d): ",
+ _shapeNum, _frame, b._x, b._y, b._z, b._xd, b._yd, b._zd);
+ if (_sprite)
+ info += "sprite ";
+ if (_flat)
+ info += "flat ";
+ if (_anim)
+ info += "anim ";
+ if (_trans)
+ info += "trans ";
+ if (_draw)
+ info += "draw ";
+ if (_solid)
+ info += "solid ";
+ if (_occl)
+ info += "occl ";
+ if (_fbigsq)
+ info += "fbigsq ";
+ if (_roof)
+ info += "roof ";
+ if (_land)
+ info += "land ";
+ if (_noisy)
+ info += "noisy ";
+ if (_fixed)
+ info += "fixed ";
+
+ return info;
+}
+
+} // End of namespace Ultima8
+} // End of namespace Ultima
diff --git a/engines/ultima/ultima8/world/sort_item.h b/engines/ultima/ultima8/world/sort_item.h
index 1d4edfb9fda..482e3eeeafa 100644
--- a/engines/ultima/ultima8/world/sort_item.h
+++ b/engines/ultima/ultima8/world/sort_item.h
@@ -226,9 +226,18 @@ struct SortItem {
// Functions
// Set worldspace bounds and calculate screenspace at center point
- inline void setBoxBounds(const Box &box, int32 sx, int32 sy);
-
- inline Box getBoxBounds() const;
+ void setBoxBounds(const Box &box, int32 sx, int32 sy);
+
+ inline Box getBoxBounds() const {
+ Box box;
+ box._x = _x;
+ box._y = _y;
+ box._z = _z;
+ box._xd = _x - _xLeft;
+ box._yd = _y - _yFar;
+ box._zd = _zTop - _z;
+ return box;
+ }
// Check if the given point is inside the screenpace bounds.
inline bool contains(int32 sx, int32 sy) const;
@@ -240,7 +249,7 @@ struct SortItem {
inline bool occludes(const SortItem &si2) const;
// Screenspace check to see if this is below si2. Assumes this overlaps si2
- inline bool below(const SortItem &si2) const;
+ bool below(const SortItem &si2) const;
// Comparison for the sorted lists
inline bool listLessThan(const SortItem &si2) const {
@@ -257,54 +266,6 @@ struct SortItem {
Common::String dumpInfo() const;
};
-inline void SortItem::setBoxBounds(const Box& box, int32 sx, int32 sy) {
- _x = box._x;
- _y = box._y;
- _z = box._z;
- _xLeft = _x - box._xd;
- _yFar = _y - box._yd;
- _zTop = _z + box._zd;
-
- // NOTE: Precision loss from integer division is intention to fix
- // rendering issue at MainActor::teleport 37 18168 17656 104
-
- // Screenspace bounding box left extent (LNT x coord)
- _sxLeft = _xLeft / 4 - _y / 4 - sx;
- // Screenspace bounding box right extent (RFT x coord)
- _sxRight = _x / 4 - _yFar / 4 - sx;
-
- // Screenspace bounding box top x coord (LFT x coord)
- _sxTop = _xLeft / 4 - _yFar / 4 - sx;
- // Screenspace bounding box top extent (LFT y coord)
- _syTop = _xLeft / 8 + _yFar / 8 - _zTop - sy;
-
- // Screenspace bounding box bottom x coord (RNB x coord)
- _sxBot = _x / 4 - _y / 4 - sx;
- // Screenspace bounding box bottom extent (RNB y coord)
- _syBot = _x / 8 + _y / 8 - _z - sy;
-
- // Screenspace rect - replace with shape frame calculations
- _sr.left = _sxLeft;
- _sr.top = _syTop;
- _sr.right = _sxRight;
- _sr.bottom = _syBot;
-
- // These help out with sorting. We calc them now, so it will be faster
- _fbigsq = box._xd == box._yd && box._xd >= 128;
- _flat = box._zd == 0;
-}
-
-inline Box SortItem::getBoxBounds() const {
- Box box;
- box._x = _x;
- box._y = _y;
- box._z = _z;
- box._xd = _x - _xLeft;
- box._yd = _y - _yFar;
- box._zd = _zTop - _z;
- return box;
-}
-
inline bool SortItem::contains(int32 sx, int32 sy) const {
if (!_sr.contains(sx, sy))
return false;
@@ -414,194 +375,6 @@ inline bool SortItem::occludes(const SortItem &si2) const {
top_right_res && top_left_res;
}
-inline bool SortItem::below(const SortItem &si2) const {
- const SortItem &si1 = *this;
-
- if (si1._sprite != si2._sprite)
- return si1._sprite < si2._sprite;
-
- // 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._zTop && !(si1._flat && si2._flat) && !si2._invitem)
- return false;
-
- // 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 && !(yFlat1 && yFlat2))
- return false;
-
- // 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 && !(xFlat1 && xFlat2))
- return false;
-
- // Specialist z flat handling
- 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;
-
- // Animated always gets drawn after
- if (si1._anim != si2._anim)
- return si1._anim < si2._anim;
-
- // Draw always gets drawn first
- if (si1._draw != si2._draw)
- return si1._draw > si2._draw;
-
- // Solid always gets drawn first
- if (si1._solid != si2._solid)
- return si1._solid > si2._solid;
-
- // Occludes always get drawn first
- if (si1._occl != si2._occl)
- return si1._occl > si2._occl;
-
- // Large flats squares get drawn first
- if (si1._fbigsq != si2._fbigsq)
- return si1._fbigsq > si2._fbigsq;
- }
-
- // 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;
- }
- }
-
- // X-flat vs non-flat handling
- if (xFlat1 != xFlat2 && si1._fixed == si2._fixed) {
- if (xFlat1) {
- if (si2._x - 32 > si2._xLeft) {
- int32 xCenter2 = (si2._xLeft + si2._x) / 2;
- return si1._x <= xCenter2;
- }
- return false;
- } else {
- if (si1._x - 32 > si1._xLeft) {
- int32 xCenter1 = (si1._xLeft + si1._x) / 2;
- return xCenter1 < si2._x;
- }
- return true;
- }
- }
-
- // 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);
-
- // Partial in X + Y back
- if (si1._xLeft + si1._yFar != si2._xLeft + si2._yFar)
- return (si1._xLeft + si1._yFar < si2._xLeft + si2._yFar);
-
- // Partial in y?
- if (si1._y != si2._y)
- return si1._y < si2._y;
-
- // Partial in x?
- if (si1._x != si2._x)
- return si1._x < si2._x;
-
- // Just sort by shape number
- if (si1._shapeNum != si2._shapeNum)
- return si1._shapeNum < si2._shapeNum;
-
- // And then by _frame
- return si1._frame < si2._frame;
-}
-
-Common::String SortItem::dumpInfo() const {
- Box b = getBoxBounds();
- Common::String info = Common::String::format("%u:%u (%d, %d, %d, %d, %d, %d): ",
- _shapeNum, _frame, b._x, b._y, b._z, b._xd, b._yd, b._zd);
- if (_sprite)
- info += "sprite ";
- if (_flat)
- info += "flat ";
- if (_anim)
- info += "anim ";
- if (_trans)
- info += "trans ";
- if (_draw)
- info += "draw ";
- if (_solid)
- info += "solid ";
- if (_occl)
- info += "occl ";
- if (_fbigsq)
- info += "fbigsq ";
- if (_roof)
- info += "roof ";
- if (_land)
- info += "land ";
- if (_noisy)
- info += "noisy ";
- if (_fixed)
- info += "fixed ";
-
- return info;
-}
-
} // End of namespace Ultima8
} // End of namespace Ultima
Commit: 0d0555bd14042f735d9d1bd842cc8b9a44527641
https://github.com/scummvm/scummvm/commit/0d0555bd14042f735d9d1bd842cc8b9a44527641
Author: Matthew Jimenez (matthew.jimenez at outlook.com)
Date: 2023-09-29T23:02:03-05:00
Commit Message:
ULTIMA8: Add tolerance when comparing Z in sort item.
X & Y flats are often offset below the top of the floor they sit on but by less than the multiplier used when calculating the footpad
Changed paths:
engines/ultima/ultima8/world/sort_item.cpp
test/engines/ultima/ultima8/world/sort_item.h
diff --git a/engines/ultima/ultima8/world/sort_item.cpp b/engines/ultima/ultima8/world/sort_item.cpp
index 06d76d646ff..ce659f73233 100644
--- a/engines/ultima/ultima8/world/sort_item.cpp
+++ b/engines/ultima/ultima8/world/sort_item.cpp
@@ -67,27 +67,44 @@ bool SortItem::below(const SortItem &si2) const {
if (si1._sprite != si2._sprite)
return si1._sprite < si2._sprite;
- // 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._zTop && !(si1._flat && si2._flat) && !si2._invitem)
- return false;
+ // Check clearly in Z
+ if (si1._flat && si2._flat) {
+ if (si1._z != si2._z)
+ return si1._z < si2._z;
+ } else {
+ // Check against z top with a tolerance based on footpad calculations
+ // Lower item cannot be inventory
+ if (si1._zTop - 8 < si2._z && !si1._invitem)
+ return true;
+ if (si1._z > si2._zTop - 8 && !si2._invitem)
+ return false;
+ }
- // Clearly in Y and one must not be flat
+ // Check clearly in Y
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 && !(yFlat1 && yFlat2))
- return false;
+ if (yFlat1 && yFlat2) {
+ if (si1._y != si2._y)
+ return si1._y < si2._y;
+ } else {
+ if (si1._y <= si2._yFar)
+ return true;
+ if (si1._yFar >= si2._y)
+ return false;
+ }
- // Clearly in X and one must not be flat
+ // Check clearly in X
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 && !(xFlat1 && xFlat2))
- return false;
+ if (xFlat1 && xFlat2) {
+ if (si1._x != si2._x)
+ return si1._x < si2._x;
+ } else {
+ if (si1._x <= si2._xLeft)
+ return true;
+ if (si1._xLeft >= si2._x)
+ return false;
+ }
// Specialist z flat handling
if (si1._flat || si2._flat) {
@@ -132,15 +149,15 @@ bool SortItem::below(const SortItem &si2) const {
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;
+ 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;
- }
+ int32 yCenter1 = (si1._yFar + si1._y) / 2;
+ return yCenter1 < si2._y;
+ }
return true;
}
}
@@ -149,15 +166,15 @@ bool SortItem::below(const SortItem &si2) const {
if (xFlat1 != xFlat2 && si1._fixed == si2._fixed) {
if (xFlat1) {
if (si2._x - 32 > si2._xLeft) {
- int32 xCenter2 = (si2._xLeft + si2._x) / 2;
- return si1._x <= xCenter2;
+ int32 xCenter2 = (si2._xLeft + si2._x) / 2;
+ return si1._x <= xCenter2;
}
return false;
} else {
if (si1._x - 32 > si1._xLeft) {
- int32 xCenter1 = (si1._xLeft + si1._x) / 2;
- return xCenter1 < si2._x;
- }
+ int32 xCenter1 = (si1._xLeft + si1._x) / 2;
+ return xCenter1 < si2._x;
+ }
return true;
}
}
diff --git a/test/engines/ultima/ultima8/world/sort_item.h b/test/engines/ultima/ultima8/world/sort_item.h
index 3610879ccc6..addd6e2c6ba 100644
--- a/test/engines/ultima/ultima8/world/sort_item.h
+++ b/test/engines/ultima/ultima8/world/sort_item.h
@@ -94,17 +94,15 @@ class U8SortItemTestSuite : public CxxTest::TestSuite {
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(59454, 49246, 80, 32, 160, 16);
- Ultima::Ultima8::Box b2(59440, 49144, 63, 32, 32, 63);
si1.setBoxBounds(b1, 0, 0);
+
+ Ultima::Ultima8::Box b2(59440, 49144, 63, 32, 32, 63);
si2.setBoxBounds(b2, 0, 0);
+ si2._sprite = true;
TS_ASSERT(si1.overlap(si2));
TS_ASSERT(si2.overlap(si1));
- TS_ASSERT(!si1.below(si2));
- TS_ASSERT(si2.below(si1));
-
- si2._sprite = true;
TS_ASSERT(si1.below(si2));
TS_ASSERT(!si2.below(si1));
}
@@ -315,6 +313,34 @@ class U8SortItemTestSuite : public CxxTest::TestSuite {
TS_ASSERT(!si2.below(si1));
}
+ /**
+ * Overlapping x-flat vs non-flat floor where z order not clear
+ * Test case for rendering issue at MainActor::teleport 40 12311 9415 48
+ * Tapestry should draw after floor
+ */
+ void test_x_flat_z_tolerance_sort() {
+ Ultima::Ultima8::SortItem si1;
+ Ultima::Ultima8::SortItem si2;
+
+ Ultima::Ultima8::Box b1(12543, 9727, 40, 256, 256, 8);
+ si1.setBoxBounds(b1, 0, 0);
+ si1._solid = true;
+ si1._occl = true;
+ si1._roof = true;
+ si1._land = true;
+ si1._fixed = true;
+
+ Ultima::Ultima8::Box b2(12287, 9791, 46, 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 x-flat vs non-flat wall with x-flat far inside wall
* Test case for rendering issue at MainActor::teleport 37 17619 17767 104
More information about the Scummvm-git-logs
mailing list