MCPcopy Create free account
hub / github.com/TombEngine/TombEngine / GetBridgeItemIntersect

Function GetBridgeItemIntersect

TombEngine/Game/collision/floordata.cpp:763–819  ·  view source on GitHub ↗

TODO: Load anim frame AABBs as DX BoundingBox objects and do regular ray test for gain of 3-5 frames. -- Sezz 2024.11.07 TODO: Try querying collision mesh instead. Get precise floor/ceiling height from object's bounding box. Animated objects are also supported, although horizontal collision shifting is unstable. Method: get accurate bounds in world transform by converting to OBB, then do a ray tes

Source from the content-addressed store, hash-verified

761 // Method: get accurate bounds in world transform by converting to OBB, then do a ray test
762 // on top or bottom (depending on test side) to determine if box is present at a particular point.
763 std::optional<int> GetBridgeItemIntersect(const ItemInfo& item, const Vector3i& pos, bool useBottomHeight)
764 {
765 constexpr auto VERTICAL_MARGIN = 4;
766
767 // Check bridge cache for existing entry.
768 for (const auto& entry : BridgeCache)
769 {
770 if (entry.BridgeItemNumber == item.Index && entry.BridgePose == item.Pose &&
771 entry.UseBottomHeight == useBottomHeight && entry.Position == pos)
772 {
773 return entry.Height;
774 }
775 }
776
777 auto box = GameBoundingBox(&item);
778 auto extents = box.GetExtents();
779
780 // Test rough circle intersection to discard bridges not intersecting on XZ plane.
781 auto circle1 = Vector3(pos.x, pos.z, BLOCK(1));
782 auto circle2 = Vector3(item.Pose.Position.x, item.Pose.Position.z, std::hypot(extents.x, extents.z));
783
784 auto height = std::optional<int>();
785 if (Geometry::CircleIntersects(circle1, circle2))
786 {
787 auto origin = Vector3i(pos.x, pos.y + (useBottomHeight ? VERTICAL_MARGIN : -VERTICAL_MARGIN), pos.z) - item.Pose.Position;
788
789 float sinAngle = phd_sin(item.Pose.Orientation.y);
790 float cosAngle = phd_cos(item.Pose.Orientation.y);
791
792 auto localOrigin = Vector3i(
793 (origin.x * cosAngle) - (origin.z * sinAngle),
794 origin.y,
795 (origin.x * sinAngle) + (origin.z * cosAngle));
796
797 // Calculate intersection distance.
798 auto direction = useBottomHeight ? -Vector3::UnitY : Vector3::UnitY;
799 float targetY = useBottomHeight ? box.Y2 : box.Y1;
800 float dist = (targetY - localOrigin.y) / direction.y;
801
802 // Compute intersection point.
803 auto intersectionPoint = Geometry::TranslatePoint(localOrigin, direction, dist);
804
805 // Check if intersection point is within bounding box's X and Z extents.
806 if (intersectionPoint.x >= box.X1 && intersectionPoint.x <= box.X2 &&
807 intersectionPoint.z >= box.Z1 && intersectionPoint.z <= box.Z2)
808 {
809 // Transform intersection point back to world coordinates.
810 height = item.Pose.Position.y + intersectionPoint.y;
811 }
812 }
813
814 // Cache bridge data.
815 BridgeCache[BridgeCacheSlotID] = BridgeCacheEntry{ item.Index, item.Pose, useBottomHeight, pos, height };
816 BridgeCacheSlotID = (BridgeCacheSlotID + 1) % BRIDGE_CACHE_SIZE; // Wrap to next slot ID.
817
818 return height;
819 }
820

Calls 8

CircleIntersectsFunction · 0.85
phd_sinFunction · 0.85
phd_cosFunction · 0.85
TranslatePointFunction · 0.85
GetExtentsMethod · 0.80
GameBoundingBoxClass · 0.50
Vector3Function · 0.50
Vector3iClass · 0.50

Tested by

no test coverage detected