Browse Source

Version of UVec4::sSort4True that is faster (#40)

Jorrit Rouwe 3 years ago
parent
commit
0e3f28e61b

+ 4 - 3
Jolt/Math/UVec4.h

@@ -78,9 +78,10 @@ public:
 	/// Logical not (component wise)
 	/// Logical not (component wise)
 	static JPH_INLINE UVec4		sNot(UVec4Arg inV1);
 	static JPH_INLINE UVec4		sNot(UVec4Arg inV1);
 
 
-	/// Sorts 4 elements so that the True values go first (highest bit set), sorts ioIndex at the same time.
-	/// Based on a sorting network: http://en.wikipedia.org/wiki/Sorting_network
-	static JPH_INLINE void		sSort4True(UVec4 &ioValue, UVec4 &ioIndex);
+	/// Sorts the elements in inIndex so that the values that correspond to trues in inValue are the first elements.
+	/// The remaining elements will be set to inValue.w.
+	/// I.e. if inValue = (true, false, true, false) and inIndex = (1, 2, 3, 4) the function returns (1, 3, 4, 4).
+	static JPH_INLINE UVec4		sSort4True(UVec4Arg inValue, UVec4Arg inIndex);
 
 
 	/// Get individual components
 	/// Get individual components
 #if defined(JPH_USE_SSE)
 #if defined(JPH_USE_SSE)

+ 8 - 29
Jolt/Math/UVec4.inl

@@ -192,39 +192,18 @@ UVec4 UVec4::sNot(UVec4Arg inV1)
 #endif
 #endif
 }
 }
 
 
-void UVec4::sSort4True(UVec4 &ioValue, UVec4 &ioIndex)
+UVec4 UVec4::sSort4True(UVec4Arg inValue, UVec4Arg inIndex)
 {
 {
-	// We didn't expose the less operator on UVec4 since X64 doesn't offer an unsigned one, we're comparing true and false here so we know that we only have 2 values
-#if defined(JPH_USE_SSE)
-	#define S4T_COMPARE _mm_cmplt_epi32
-#elif defined(JPH_USE_NEON)
-	#define S4T_COMPARE vcltq_s32
-#else
-	#error Unsupported CPU architecture
-#endif
-
-	// Pass 1, test 1st vs 3rd, 2nd vs 4th
-	UVec4 v1 = ioValue.Swizzle<SWIZZLE_Z, SWIZZLE_W, SWIZZLE_X, SWIZZLE_Y>();
-	UVec4 i1 = ioIndex.Swizzle<SWIZZLE_Z, SWIZZLE_W, SWIZZLE_X, SWIZZLE_Y>();
-	UVec4 c1 = UVec4(S4T_COMPARE(ioValue.mValue, v1.mValue)).Swizzle<SWIZZLE_Z, SWIZZLE_W, SWIZZLE_Z, SWIZZLE_W>();
-	ioValue = sSelect(ioValue, v1, c1);
-	ioIndex = sSelect(ioIndex, i1, c1);
+	// If inValue.z is false then shift W to Z
+	UVec4 v = UVec4::sSelect(inIndex.Swizzle<SWIZZLE_X, SWIZZLE_Y, SWIZZLE_W, SWIZZLE_W>(), inIndex, inValue.SplatZ());
 
 
-	// Pass 2, test 1st vs 2nd, 3rd vs 4th
-	UVec4 v2 = ioValue.Swizzle<SWIZZLE_Y, SWIZZLE_X, SWIZZLE_W, SWIZZLE_Z>();
-	UVec4 i2 = ioIndex.Swizzle<SWIZZLE_Y, SWIZZLE_X, SWIZZLE_W, SWIZZLE_Z>();
-	UVec4 c2 = UVec4(S4T_COMPARE(ioValue.mValue, v2.mValue)).Swizzle<SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_W, SWIZZLE_W>();
-	ioValue = sSelect(ioValue, v2, c2);
-	ioIndex = sSelect(ioIndex, i2, c2);
+	// If inValue.y is false then shift Z and further to Y and further
+	v = UVec4::sSelect(v.Swizzle<SWIZZLE_X, SWIZZLE_Z, SWIZZLE_W, SWIZZLE_W>(), v, inValue.SplatY());
 
 
-	// Pass 3, test 2nd vs 3rd component
-	UVec4 v3 = ioValue.Swizzle<SWIZZLE_X, SWIZZLE_Z, SWIZZLE_Y, SWIZZLE_W>();
-	UVec4 i3 = ioIndex.Swizzle<SWIZZLE_X, SWIZZLE_Z, SWIZZLE_Y, SWIZZLE_W>();
-	UVec4 c3 = UVec4(S4T_COMPARE(ioValue.mValue, v3.mValue)).Swizzle<SWIZZLE_X, SWIZZLE_Z, SWIZZLE_Z, SWIZZLE_W>();
-	ioValue = sSelect(ioValue, v3, c3);
-	ioIndex = sSelect(ioIndex, i3, c3);
+	// If inValue.x is false then shift X and furhter to Y and furhter
+	v = UVec4::sSelect(v.Swizzle<SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W, SWIZZLE_W>(), v, inValue.SplatX());
 
 
-#undef S4T_COMPARE
+	return v;
 }
 }
 
 
 UVec4 UVec4::operator * (UVec4Arg inV2) const
 UVec4 UVec4::operator * (UVec4Arg inV2) const

+ 5 - 41
Jolt/Physics/Collision/BroadPhase/QuadTree.cpp

@@ -1123,16 +1123,7 @@ void QuadTree::CollideAABox(const AABox &inBox, CollideShapeBodyCollector &ioCol
 		{
 		{
 			// Test the box vs 4 boxes
 			// Test the box vs 4 boxes
 			UVec4 hitting = AABox4VsBox(mBox, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
 			UVec4 hitting = AABox4VsBox(mBox, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
-
-			// Count how many results are hitting
-			int num_results = hitting.CountTrues();
-			if (num_results > 0)
-			{
-				// Sort trues first
-				UVec4::sSort4True(hitting, ioChildNodeIDs);
-			}
-
-			return num_results;
+			return CountAndSortTrues(hitting, ioChildNodeIDs);
 		}
 		}
 
 
 		/// Visit a body, returns false if the algorithm should terminate because no hits can be generated anymore
 		/// Visit a body, returns false if the algorithm should terminate because no hits can be generated anymore
@@ -1183,16 +1174,7 @@ void QuadTree::CollideSphere(Vec3Arg inCenter, float inRadius, CollideShapeBodyC
 		{
 		{
 			// Test 4 boxes vs sphere
 			// Test 4 boxes vs sphere
 			UVec4 hitting = AABox4VsSphere(mCenterX, mCenterY, mCenterZ, mRadiusSq, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
 			UVec4 hitting = AABox4VsSphere(mCenterX, mCenterY, mCenterZ, mRadiusSq, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
-
-			// Count how many results are hitting
-			int num_results = hitting.CountTrues();
-			if (num_results > 0)
-			{
-				// Sort trues first
-				UVec4::sSort4True(hitting, ioChildNodeIDs);
-			}
-
-			return num_results;
+			return CountAndSortTrues(hitting, ioChildNodeIDs);
 		}
 		}
 
 
 		/// Visit a body, returns false if the algorithm should terminate because no hits can be generated anymore
 		/// Visit a body, returns false if the algorithm should terminate because no hits can be generated anymore
@@ -1243,16 +1225,7 @@ void QuadTree::CollidePoint(Vec3Arg inPoint, CollideShapeBodyCollector &ioCollec
 		{
 		{
 			// Test if point overlaps with box
 			// Test if point overlaps with box
 			UVec4 hitting = AABox4VsPoint(mPoint, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
 			UVec4 hitting = AABox4VsPoint(mPoint, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
-
-			// Count how many results are hitting
-			int num_results = hitting.CountTrues();
-			if (num_results > 0)
-			{
-				// Sort trues first
-				UVec4::sSort4True(hitting, ioChildNodeIDs);
-			}
-
-			return num_results;
+			return CountAndSortTrues(hitting, ioChildNodeIDs);
 		}
 		}
 
 
 		/// Visit a body, returns false if the algorithm should terminate because no hits can be generated anymore
 		/// Visit a body, returns false if the algorithm should terminate because no hits can be generated anymore
@@ -1300,16 +1273,7 @@ void QuadTree::CollideOrientedBox(const OrientedBox &inBox, CollideShapeBodyColl
 		{
 		{
 			// Test if point overlaps with box
 			// Test if point overlaps with box
 			UVec4 hitting = AABox4VsBox(mBox, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
 			UVec4 hitting = AABox4VsBox(mBox, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
-
-			// Count how many results are hitting
-			int num_results = hitting.CountTrues();
-			if (num_results > 0)
-			{
-				// Sort trues first
-				UVec4::sSort4True(hitting, ioChildNodeIDs);
-			}
-
-			return num_results;
+			return CountAndSortTrues(hitting, ioChildNodeIDs);
 		}
 		}
 
 
 		/// Visit a body, returns false if the algorithm should terminate because no hits can be generated anymore
 		/// Visit a body, returns false if the algorithm should terminate because no hits can be generated anymore
@@ -1463,7 +1427,7 @@ void QuadTree::FindCollidingPairs(const BodyVector &inBodies, const BodyID *inAc
 					UVec4 child_ids = UVec4::sLoadInt4Aligned((const uint32 *)&node.mChildNodeID[0]);
 					UVec4 child_ids = UVec4::sLoadInt4Aligned((const uint32 *)&node.mChildNodeID[0]);
 
 
 					// Sort so that overlaps are first
 					// Sort so that overlaps are first
-					UVec4::sSort4True(overlap, child_ids);
+					child_ids = UVec4::sSort4True(overlap, child_ids);
 
 
 					// Push them onto the stack
 					// Push them onto the stack
 					if (top + 4 < cStackSize)
 					if (top + 4 < cStackSize)

+ 4 - 20
Jolt/Physics/Collision/Shape/HeightFieldShape.cpp

@@ -988,8 +988,7 @@ void HeightFieldShape::Draw(DebugRenderer *inRenderer, Mat44Arg inCenterOfMassTr
 			JPH_INLINE int			VisitRangeBlock(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioProperties, [[maybe_unused]] int inStackTop) const
 			JPH_INLINE int			VisitRangeBlock(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioProperties, [[maybe_unused]] int inStackTop) const
 			{
 			{
 				UVec4 valid = UVec4::sOr(UVec4::sOr(Vec4::sLess(inBoundsMinX, inBoundsMaxX), Vec4::sLess(inBoundsMinY, inBoundsMaxY)), Vec4::sLess(inBoundsMinZ, inBoundsMaxZ));
 				UVec4 valid = UVec4::sOr(UVec4::sOr(Vec4::sLess(inBoundsMinX, inBoundsMaxX), Vec4::sLess(inBoundsMinY, inBoundsMaxY)), Vec4::sLess(inBoundsMinZ, inBoundsMaxZ));
-				UVec4::sSort4True(valid, ioProperties);
-				return valid.CountTrues();
+				return CountAndSortTrues(valid, ioProperties);
 			}
 			}
 
 
 			JPH_INLINE void			VisitTriangle(uint inX, uint inY, uint inTriangle, Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2) const
 			JPH_INLINE void			VisitTriangle(uint inX, uint inY, uint inTriangle, Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2) const
@@ -1665,12 +1664,7 @@ struct HeightFieldShape::HSGetTrianglesContext
 
 
 		// Test which nodes collide
 		// Test which nodes collide
 		UVec4 collides = AABox4VsBox(mLocalBox, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
 		UVec4 collides = AABox4VsBox(mLocalBox, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
-
-		// Sort so the colliding ones go first
-		UVec4::sSort4True(collides, ioProperties);
-
-		// Return number of hits
-		return collides.CountTrues();
+		return CountAndSortTrues(collides, ioProperties);
 	}
 	}
 
 
 	void	VisitTriangle(uint inX, uint inY, [[maybe_unused]] uint inTriangle, Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2) 
 	void	VisitTriangle(uint inX, uint inY, [[maybe_unused]] uint inTriangle, Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2) 
@@ -1781,12 +1775,7 @@ void HeightFieldShape::sCollideConvexVsHeightField(const Shape *inShape1, const
 
 
 			// Test which nodes collide
 			// Test which nodes collide
 			UVec4 collides = AABox4VsBox(mBoundsOf1InSpaceOf2, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
 			UVec4 collides = AABox4VsBox(mBoundsOf1InSpaceOf2, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
-
-			// Sort so the colliding ones go first
-			UVec4::sSort4True(collides, ioProperties);
-
-			// Return number of hits
-			return collides.CountTrues();
+			return CountAndSortTrues(collides, ioProperties);
 		}
 		}
 
 
 		JPH_INLINE void				VisitTriangle(uint inX, uint inY, uint inTriangle, Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2)
 		JPH_INLINE void				VisitTriangle(uint inX, uint inY, uint inTriangle, Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2)
@@ -1842,12 +1831,7 @@ void HeightFieldShape::sCollideSphereVsHeightField(const Shape *inShape1, const
 
 
 			// Test which nodes collide
 			// Test which nodes collide
 			UVec4 collides = AABox4VsSphere(mSphereCenterIn2, mRadiusPlusMaxSeparationSq, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
 			UVec4 collides = AABox4VsSphere(mSphereCenterIn2, mRadiusPlusMaxSeparationSq, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
-
-			// Sort so the colliding ones go first
-			UVec4::sSort4True(collides, ioProperties);
-
-			// Return number of hits
-			return collides.CountTrues();
+			return CountAndSortTrues(collides, ioProperties);
 		}
 		}
 
 
 		JPH_INLINE void				VisitTriangle(uint inX, uint inY, uint inTriangle, Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2)
 		JPH_INLINE void				VisitTriangle(uint inX, uint inY, uint inTriangle, Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2)

+ 6 - 24
Jolt/Physics/Collision/Shape/MeshShape.cpp

@@ -475,8 +475,7 @@ void MeshShape::Draw(DebugRenderer *inRenderer, Mat44Arg inCenterOfMassTransform
 			JPH_INLINE int		VisitNodes(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioProperties, int inStackTop) 
 			JPH_INLINE int		VisitNodes(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioProperties, int inStackTop) 
 			{
 			{
 				UVec4 valid = UVec4::sOr(UVec4::sOr(Vec4::sLess(inBoundsMinX, inBoundsMaxX), Vec4::sLess(inBoundsMinY, inBoundsMaxY)), Vec4::sLess(inBoundsMinZ, inBoundsMaxZ));
 				UVec4 valid = UVec4::sOr(UVec4::sOr(Vec4::sLess(inBoundsMinX, inBoundsMaxX), Vec4::sLess(inBoundsMinY, inBoundsMaxY)), Vec4::sLess(inBoundsMinZ, inBoundsMaxZ));
-				UVec4::sSort4True(valid, ioProperties);
-				return valid.CountTrues();
+				return CountAndSortTrues(valid, ioProperties);
 			}
 			}
 
 
 			JPH_INLINE void		VisitTriangles(const TriangleCodec::DecodingContext &ioContext, Vec3Arg inRootBoundsMin, Vec3Arg inRootBoundsMax, const void *inTriangles, int inNumTriangles, [[maybe_unused]] uint32 inTriangleBlockID) 
 			JPH_INLINE void		VisitTriangles(const TriangleCodec::DecodingContext &ioContext, Vec3Arg inRootBoundsMin, Vec3Arg inRootBoundsMax, const void *inTriangles, int inNumTriangles, [[maybe_unused]] uint32 inTriangleBlockID) 
@@ -549,8 +548,7 @@ void MeshShape::Draw(DebugRenderer *inRenderer, Mat44Arg inCenterOfMassTransform
 			JPH_INLINE int		VisitNodes(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioProperties, int inStackTop) 
 			JPH_INLINE int		VisitNodes(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioProperties, int inStackTop) 
 			{
 			{
 				UVec4 valid = UVec4::sOr(UVec4::sOr(Vec4::sLess(inBoundsMinX, inBoundsMaxX), Vec4::sLess(inBoundsMinY, inBoundsMaxY)), Vec4::sLess(inBoundsMinZ, inBoundsMaxZ));
 				UVec4 valid = UVec4::sOr(UVec4::sOr(Vec4::sLess(inBoundsMinX, inBoundsMaxX), Vec4::sLess(inBoundsMinY, inBoundsMaxY)), Vec4::sLess(inBoundsMinZ, inBoundsMaxZ));
-				UVec4::sSort4True(valid, ioProperties);
-				return valid.CountTrues();
+				return CountAndSortTrues(valid, ioProperties);
 			}
 			}
 
 
 			JPH_INLINE void		VisitTriangles(const TriangleCodec::DecodingContext &ioContext, Vec3Arg inRootBoundsMin, Vec3Arg inRootBoundsMax, const void *inTriangles, int inNumTriangles, uint32 inTriangleBlockID) 
 			JPH_INLINE void		VisitTriangles(const TriangleCodec::DecodingContext &ioContext, Vec3Arg inRootBoundsMin, Vec3Arg inRootBoundsMax, const void *inTriangles, int inNumTriangles, uint32 inTriangleBlockID) 
@@ -890,12 +888,7 @@ struct MeshShape::MSGetTrianglesContext
 
 
 		// Test which nodes collide
 		// Test which nodes collide
 		UVec4 collides = AABox4VsBox(mLocalBox, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
 		UVec4 collides = AABox4VsBox(mLocalBox, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
-
-		// Sort so the colliding ones go first
-		UVec4::sSort4True(collides, ioProperties);
-
-		// Return number of hits
-		return collides.CountTrues();
+		return CountAndSortTrues(collides, ioProperties);
 	}
 	}
 
 
 	JPH_INLINE void	VisitTriangles(const TriangleCodec::DecodingContext &ioContext, Vec3Arg inRootBoundsMin, Vec3Arg inRootBoundsMax, const void *inTriangles, int inNumTriangles, [[maybe_unused]] uint32 inTriangleBlockID) 
 	JPH_INLINE void	VisitTriangles(const TriangleCodec::DecodingContext &ioContext, Vec3Arg inRootBoundsMin, Vec3Arg inRootBoundsMax, const void *inTriangles, int inNumTriangles, [[maybe_unused]] uint32 inTriangleBlockID) 
@@ -1032,12 +1025,7 @@ void MeshShape::sCollideConvexVsMesh(const Shape *inShape1, const Shape *inShape
 
 
 			// Test which nodes collide
 			// Test which nodes collide
 			UVec4 collides = AABox4VsBox(mBoundsOf1InSpaceOf2, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
 			UVec4 collides = AABox4VsBox(mBoundsOf1InSpaceOf2, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
-
-			// Sort so the colliding ones go first
-			UVec4::sSort4True(collides, ioProperties);
-
-			// Return number of hits
-			return collides.CountTrues();
+			return CountAndSortTrues(collides, ioProperties);
 		}
 		}
 
 
 		JPH_INLINE void	VisitTriangle(Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2, uint8 inActiveEdges, SubShapeID inSubShapeID2) 
 		JPH_INLINE void	VisitTriangle(Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2, uint8 inActiveEdges, SubShapeID inSubShapeID2) 
@@ -1082,12 +1070,7 @@ void MeshShape::sCollideSphereVsMesh(const Shape *inShape1, const Shape *inShape
 
 
 			// Test which nodes collide
 			// Test which nodes collide
 			UVec4 collides = AABox4VsSphere(mSphereCenterIn2, mRadiusPlusMaxSeparationSq, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
 			UVec4 collides = AABox4VsSphere(mSphereCenterIn2, mRadiusPlusMaxSeparationSq, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
-
-			// Sort so the colliding ones go first
-			UVec4::sSort4True(collides, ioProperties);
-
-			// Return number of hits
-			return collides.CountTrues();
+			return CountAndSortTrues(collides, ioProperties);
 		}
 		}
 
 
 		JPH_INLINE void	VisitTriangle(Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2, uint8 inActiveEdges, SubShapeID inSubShapeID2) 
 		JPH_INLINE void	VisitTriangle(Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2, uint8 inActiveEdges, SubShapeID inSubShapeID2) 
@@ -1143,8 +1126,7 @@ Shape::Stats MeshShape::GetStats() const
 		{
 		{
 			// Visit all valid children
 			// Visit all valid children
 			UVec4 valid = UVec4::sOr(UVec4::sOr(Vec4::sLess(inBoundsMinX, inBoundsMaxX), Vec4::sLess(inBoundsMinY, inBoundsMaxY)), Vec4::sLess(inBoundsMinZ, inBoundsMaxZ));
 			UVec4 valid = UVec4::sOr(UVec4::sOr(Vec4::sLess(inBoundsMinX, inBoundsMaxX), Vec4::sLess(inBoundsMinY, inBoundsMaxY)), Vec4::sLess(inBoundsMinZ, inBoundsMaxZ));
-			UVec4::sSort4True(valid, ioProperties);
-			return valid.CountTrues();
+			return CountAndSortTrues(valid, ioProperties);
 		}
 		}
 
 
 		JPH_INLINE void		VisitTriangles([[maybe_unused]] const TriangleCodec::DecodingContext &ioContext, [[maybe_unused]] Vec3Arg inRootBoundsMin, [[maybe_unused]] Vec3Arg inRootBoundsMax, [[maybe_unused]] const void *inTriangles, int inNumTriangles, [[maybe_unused]] uint32 inTriangleBlockID) 
 		JPH_INLINE void		VisitTriangles([[maybe_unused]] const TriangleCodec::DecodingContext &ioContext, [[maybe_unused]] Vec3Arg inRootBoundsMin, [[maybe_unused]] Vec3Arg inRootBoundsMax, [[maybe_unused]] const void *inTriangles, int inNumTriangles, [[maybe_unused]] uint32 inTriangleBlockID) 

+ 4 - 24
Jolt/Physics/Collision/Shape/StaticCompoundShape.cpp

@@ -6,7 +6,6 @@
 #include <Physics/Collision/Shape/StaticCompoundShape.h>
 #include <Physics/Collision/Shape/StaticCompoundShape.h>
 #include <Physics/Collision/Shape/RotatedTranslatedShape.h>
 #include <Physics/Collision/Shape/RotatedTranslatedShape.h>
 #include <Physics/Collision/Shape/CompoundShapeVisitors.h>
 #include <Physics/Collision/Shape/CompoundShapeVisitors.h>
-#include <Physics/Collision/SortReverseAndStore.h>
 #include <Core/Profiler.h>
 #include <Core/Profiler.h>
 #include <Core/StreamIn.h>
 #include <Core/StreamIn.h>
 #include <Core/StreamOut.h>
 #include <Core/StreamOut.h>
@@ -482,11 +481,7 @@ void StaticCompoundShape::CollidePoint(Vec3Arg inPoint, const SubShapeIDCreator
 		{
 		{
 			// Test if point overlaps with box
 			// Test if point overlaps with box
 			UVec4 collides = TestBounds(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
 			UVec4 collides = TestBounds(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
-
-			// Sort so the colliding ones go first
-			UVec4::sSort4True(collides, ioProperties);
-
-			return collides.CountTrues();
+			return CountAndSortTrues(collides, ioProperties);
 		}
 		}
 	};
 	};
 
 
@@ -543,12 +538,7 @@ void StaticCompoundShape::CollectTransformedShapes(const AABox &inBox, Vec3Arg i
 		{
 		{
 			// Test which nodes collide
 			// Test which nodes collide
 			UVec4 collides = TestBounds(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
 			UVec4 collides = TestBounds(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
-
-			// Sort so the colliding ones go first
-			UVec4::sSort4True(collides, ioProperties);
-
-			// Return number of hits
-			return collides.CountTrues();
+			return CountAndSortTrues(collides, ioProperties);
 		}
 		}
 	};
 	};
 
 
@@ -594,12 +584,7 @@ void StaticCompoundShape::sCollideCompoundVsShape(const Shape *inShape1, const S
 		{
 		{
 			// Test which nodes collide
 			// Test which nodes collide
 			UVec4 collides = TestBounds(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
 			UVec4 collides = TestBounds(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
-
-			// Sort so the colliding ones go first
-			UVec4::sSort4True(collides, ioProperties);
-
-			// Return number of hits
-			return collides.CountTrues();
+			return CountAndSortTrues(collides, ioProperties);
 		}
 		}
 	};
 	};
 
 
@@ -624,12 +609,7 @@ void StaticCompoundShape::sCollideShapeVsCompound(const Shape *inShape1, const S
 		{
 		{
 			// Test which nodes collide
 			// Test which nodes collide
 			UVec4 collides = TestBounds(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
 			UVec4 collides = TestBounds(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
-
-			// Sort so the colliding ones go first
-			UVec4::sSort4True(collides, ioProperties);
-
-			// Return number of hits
-			return collides.CountTrues();
+			return CountAndSortTrues(collides, ioProperties);
 		}
 		}
 	};
 	};
 
 

+ 2 - 5
Jolt/Physics/Collision/Shape/StaticCompoundShape.h

@@ -4,6 +4,7 @@
 #pragma once
 #pragma once
 
 
 #include <Physics/Collision/Shape/CompoundShape.h>
 #include <Physics/Collision/Shape/CompoundShape.h>
+#include <Physics/Collision/SortReverseAndStore.h>
 #include <Math/HalfFloat.h>
 #include <Math/HalfFloat.h>
 
 
 namespace JPH {
 namespace JPH {
@@ -79,11 +80,7 @@ private:
 		{
 		{
 			// Test if point overlaps with box
 			// Test if point overlaps with box
 			UVec4 collides = GetIntersectingSubShapesVisitor<BoxType>::TestBounds(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
 			UVec4 collides = GetIntersectingSubShapesVisitor<BoxType>::TestBounds(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
-
-			// Sort so the colliding ones go first
-			UVec4::sSort4True(collides, ioProperties);
-
-			return collides.CountTrues();
+			return CountAndSortTrues(collides, ioProperties);
 		}
 		}
 	};
 	};
 
 

+ 13 - 0
Jolt/Physics/Collision/SortReverseAndStore.h

@@ -30,4 +30,17 @@ JPH_INLINE int SortReverseAndStore(Vec4Arg inValues, float inMaxValue, UVec4 &io
 	return num_results;
 	return num_results;
 }
 }
 
 
+/// Shift the elements so that the identifiers that correspond with the trues in inValue come first
+/// @param inValue Values to test for true or false
+/// @param ioIdentifiers the identifiers that are shifted, on return they are shifted
+/// @return The number of trues
+JPH_INLINE int CountAndSortTrues(UVec4Arg inValue, UVec4 &ioIdentifiers)
+{
+	// Sort the hits
+	ioIdentifiers = UVec4::sSort4True(inValue, ioIdentifiers);
+
+	// Return the amount of hits
+	return inValue.CountTrues();
+}
+
 } // JPH
 } // JPH

+ 20 - 0
UnitTests/Math/UVec4Tests.cpp

@@ -450,4 +450,24 @@ TEST_SUITE("UVec4Tests")
 		CHECK(v.ShiftComponents4Minus(1) == UVec4(4, 0, 0, 0));
 		CHECK(v.ShiftComponents4Minus(1) == UVec4(4, 0, 0, 0));
 		CHECK(v.ShiftComponents4Minus(0) == UVec4(0, 0, 0, 0));
 		CHECK(v.ShiftComponents4Minus(0) == UVec4(0, 0, 0, 0));
 	}		
 	}		
+
+	TEST_CASE("TestUVec4Sort4True")
+	{
+		CHECK(UVec4::sSort4True(UVec4(0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U), UVec4(1, 2, 3, 4)) == UVec4(4, 4, 4, 4));
+		CHECK(UVec4::sSort4True(UVec4(0xffffffffU, 0x00000000U, 0x00000000U, 0x00000000U), UVec4(1, 2, 3, 4)) == UVec4(1, 4, 4, 4));
+		CHECK(UVec4::sSort4True(UVec4(0x00000000U, 0xffffffffU, 0x00000000U, 0x00000000U), UVec4(1, 2, 3, 4)) == UVec4(2, 4, 4, 4));
+		CHECK(UVec4::sSort4True(UVec4(0xffffffffU, 0xffffffffU, 0x00000000U, 0x00000000U), UVec4(1, 2, 3, 4)) == UVec4(1, 2, 4, 4));
+		CHECK(UVec4::sSort4True(UVec4(0x00000000U, 0x00000000U, 0xffffffffU, 0x00000000U), UVec4(1, 2, 3, 4)) == UVec4(3, 4, 4, 4));
+		CHECK(UVec4::sSort4True(UVec4(0xffffffffU, 0x00000000U, 0xffffffffU, 0x00000000U), UVec4(1, 2, 3, 4)) == UVec4(1, 3, 4, 4));
+		CHECK(UVec4::sSort4True(UVec4(0x00000000U, 0xffffffffU, 0xffffffffU, 0x00000000U), UVec4(1, 2, 3, 4)) == UVec4(2, 3, 4, 4));
+		CHECK(UVec4::sSort4True(UVec4(0xffffffffU, 0xffffffffU, 0xffffffffU, 0x00000000U), UVec4(1, 2, 3, 4)) == UVec4(1, 2, 3, 4));
+		CHECK(UVec4::sSort4True(UVec4(0x00000000U, 0x00000000U, 0x00000000U, 0xffffffffU), UVec4(1, 2, 3, 4)) == UVec4(4, 4, 4, 4));
+		CHECK(UVec4::sSort4True(UVec4(0xffffffffU, 0x00000000U, 0x00000000U, 0xffffffffU), UVec4(1, 2, 3, 4)) == UVec4(1, 4, 4, 4));
+		CHECK(UVec4::sSort4True(UVec4(0x00000000U, 0xffffffffU, 0x00000000U, 0xffffffffU), UVec4(1, 2, 3, 4)) == UVec4(2, 4, 4, 4));
+		CHECK(UVec4::sSort4True(UVec4(0xffffffffU, 0xffffffffU, 0x00000000U, 0xffffffffU), UVec4(1, 2, 3, 4)) == UVec4(1, 2, 4, 4));
+		CHECK(UVec4::sSort4True(UVec4(0x00000000U, 0x00000000U, 0xffffffffU, 0xffffffffU), UVec4(1, 2, 3, 4)) == UVec4(3, 4, 4, 4));
+		CHECK(UVec4::sSort4True(UVec4(0xffffffffU, 0x00000000U, 0xffffffffU, 0xffffffffU), UVec4(1, 2, 3, 4)) == UVec4(1, 3, 4, 4));
+		CHECK(UVec4::sSort4True(UVec4(0x00000000U, 0xffffffffU, 0xffffffffU, 0xffffffffU), UVec4(1, 2, 3, 4)) == UVec4(2, 3, 4, 4));
+		CHECK(UVec4::sSort4True(UVec4(0xffffffffU, 0xffffffffU, 0xffffffffU, 0xffffffffU), UVec4(1, 2, 3, 4)) == UVec4(1, 2, 3, 4));
+	}		
 }
 }