[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