Преглед изворни кода

Jolt: Update to commit f094082aa, adding RISC-V, PPC64 and LoongArch support

Fixes #100557.
Rémi Verschelde пре 8 месеци
родитељ
комит
4727f0707b
49 измењених фајлова са 346 додато и 162 уклоњено
  1. 1 1
      modules/jolt_physics/config.py
  2. 1 1
      thirdparty/README.md
  3. 10 0
      thirdparty/jolt_physics/Jolt/AABBTree/NodeCodec/NodeCodecQuadTreeHalfFloat.h
  4. 27 21
      thirdparty/jolt_physics/Jolt/AABBTree/TriangleCodec/TriangleCodecIndexed8BitPackSOA4Flags.h
  5. 16 1
      thirdparty/jolt_physics/Jolt/ConfigurationString.h
  6. 11 11
      thirdparty/jolt_physics/Jolt/Core/Array.h
  7. 1 1
      thirdparty/jolt_physics/Jolt/Core/ByteBuffer.h
  8. 38 3
      thirdparty/jolt_physics/Jolt/Core/Core.h
  9. 8 0
      thirdparty/jolt_physics/Jolt/Core/FPControlWord.h
  10. 8 0
      thirdparty/jolt_physics/Jolt/Core/FPException.h
  11. 3 1
      thirdparty/jolt_physics/Jolt/Core/FPFlushDenormals.h
  12. 2 2
      thirdparty/jolt_physics/Jolt/Core/FixedSizeFreeList.inl
  13. 42 20
      thirdparty/jolt_physics/Jolt/Core/HashCombine.h
  14. 4 4
      thirdparty/jolt_physics/Jolt/Core/HashTable.h
  15. 5 1
      thirdparty/jolt_physics/Jolt/Core/Memory.h
  16. 13 13
      thirdparty/jolt_physics/Jolt/Core/Result.h
  17. 7 7
      thirdparty/jolt_physics/Jolt/Core/StaticArray.h
  18. 1 3
      thirdparty/jolt_physics/Jolt/Core/TickCounter.h
  19. 3 3
      thirdparty/jolt_physics/Jolt/Core/UnorderedMap.h
  20. 1 1
      thirdparty/jolt_physics/Jolt/Geometry/Ellipse.h
  21. 17 3
      thirdparty/jolt_physics/Jolt/Geometry/IndexedTriangle.h
  22. 4 4
      thirdparty/jolt_physics/Jolt/Geometry/RayAABox.h
  23. 3 3
      thirdparty/jolt_physics/Jolt/Math/EigenValueSymmetric.h
  24. 1 1
      thirdparty/jolt_physics/Jolt/Math/GaussianElimination.h
  25. 5 5
      thirdparty/jolt_physics/Jolt/Math/Math.h
  26. 2 6
      thirdparty/jolt_physics/Jolt/Math/Vec3.inl
  27. 1 1
      thirdparty/jolt_physics/Jolt/Physics/Body/MotionQuality.h
  28. 1 1
      thirdparty/jolt_physics/Jolt/Physics/Character/Character.h
  29. 1 1
      thirdparty/jolt_physics/Jolt/Physics/Collision/BroadPhase/BroadPhase.h
  30. 1 1
      thirdparty/jolt_physics/Jolt/Physics/Collision/BroadPhase/BroadPhaseQuadTree.cpp
  31. 1 1
      thirdparty/jolt_physics/Jolt/Physics/Collision/BroadPhase/QuadTree.cpp
  32. 1 1
      thirdparty/jolt_physics/Jolt/Physics/Collision/CastSphereVsTriangles.cpp
  33. 3 2
      thirdparty/jolt_physics/Jolt/Physics/Collision/CollideShape.h
  34. 1 1
      thirdparty/jolt_physics/Jolt/Physics/Collision/Shape/ConvexHullShape.cpp
  35. 1 1
      thirdparty/jolt_physics/Jolt/Physics/Collision/Shape/Shape.h
  36. 1 16
      thirdparty/jolt_physics/Jolt/Physics/Collision/Shape/SubShapeIDPair.h
  37. 1 1
      thirdparty/jolt_physics/Jolt/Physics/Collision/Shape/TaperedCylinderShape.cpp
  38. 6 6
      thirdparty/jolt_physics/Jolt/Physics/Collision/Shape/TriangleShape.cpp
  39. 1 1
      thirdparty/jolt_physics/Jolt/Physics/Collision/TransformedShape.h
  40. 1 1
      thirdparty/jolt_physics/Jolt/Physics/Constraints/ContactConstraintManager.cpp
  41. 8 2
      thirdparty/jolt_physics/Jolt/Physics/PhysicsSettings.h
  42. 2 2
      thirdparty/jolt_physics/Jolt/Physics/PhysicsSystem.cpp
  43. 3 1
      thirdparty/jolt_physics/Jolt/Physics/PhysicsSystem.h
  44. 6 3
      thirdparty/jolt_physics/Jolt/Physics/SoftBody/SoftBodyMotionProperties.cpp
  45. 1 1
      thirdparty/jolt_physics/Jolt/Physics/SoftBody/SoftBodyMotionProperties.h
  46. 1 1
      thirdparty/jolt_physics/Jolt/Physics/SoftBody/SoftBodySharedSettings.h
  47. 1 1
      thirdparty/jolt_physics/Jolt/Physics/Vehicle/TrackedVehicleController.h
  48. 55 0
      thirdparty/jolt_physics/Jolt/Skeleton/SkeletalAnimation.cpp
  49. 14 0
      thirdparty/jolt_physics/Jolt/Skeleton/SkeletalAnimation.h

+ 1 - 1
modules/jolt_physics/config.py

@@ -1,5 +1,5 @@
 def can_build(env, platform):
-    return not env["disable_3d"]
+    return not env["disable_3d"] and not env["arch"] == "ppc32"
 
 
 def configure(env):

+ 1 - 1
thirdparty/README.md

@@ -436,7 +436,7 @@ Files generated from upstream source:
 ## jolt_physics
 
 - Upstream: https://github.com/jrouwe/JoltPhysics
-- Version: 5.2.1 (e3d3cdf644389b621914bb6e73d52ee3137591a7, 2024)
+- Version: 5.2.1 (f094082aa2bbfcbebc725dbe8b8f65c7d5152886, 2024)
 - License: MIT
 
 Files extracted from upstream source:

+ 10 - 0
thirdparty/jolt_physics/Jolt/AABBTree/NodeCodec/NodeCodecQuadTreeHalfFloat.h

@@ -254,6 +254,15 @@ public:
 					const Node *node = reinterpret_cast<const Node *>(inBufferStart + (node_properties << OFFSET_NON_SIGNIFICANT_BITS));
 
 					// Unpack bounds
+				#ifdef JPH_CPU_BIG_ENDIAN
+					Vec4 bounds_minx = HalfFloatConversion::ToFloat(UVec4(node->mBoundsMinX[0] + (node->mBoundsMinX[1] << 16), node->mBoundsMinX[2] + (node->mBoundsMinX[3] << 16), 0, 0));
+					Vec4 bounds_miny = HalfFloatConversion::ToFloat(UVec4(node->mBoundsMinY[0] + (node->mBoundsMinY[1] << 16), node->mBoundsMinY[2] + (node->mBoundsMinY[3] << 16), 0, 0));
+					Vec4 bounds_minz = HalfFloatConversion::ToFloat(UVec4(node->mBoundsMinZ[0] + (node->mBoundsMinZ[1] << 16), node->mBoundsMinZ[2] + (node->mBoundsMinZ[3] << 16), 0, 0));
+
+					Vec4 bounds_maxx = HalfFloatConversion::ToFloat(UVec4(node->mBoundsMaxX[0] + (node->mBoundsMaxX[1] << 16), node->mBoundsMaxX[2] + (node->mBoundsMaxX[3] << 16), 0, 0));
+					Vec4 bounds_maxy = HalfFloatConversion::ToFloat(UVec4(node->mBoundsMaxY[0] + (node->mBoundsMaxY[1] << 16), node->mBoundsMaxY[2] + (node->mBoundsMaxY[3] << 16), 0, 0));
+					Vec4 bounds_maxz = HalfFloatConversion::ToFloat(UVec4(node->mBoundsMaxZ[0] + (node->mBoundsMaxZ[1] << 16), node->mBoundsMaxZ[2] + (node->mBoundsMaxZ[3] << 16), 0, 0));
+				#else
 					UVec4 bounds_minxy = UVec4::sLoadInt4(reinterpret_cast<const uint32 *>(&node->mBoundsMinX[0]));
 					Vec4 bounds_minx = HalfFloatConversion::ToFloat(bounds_minxy);
 					Vec4 bounds_miny = HalfFloatConversion::ToFloat(bounds_minxy.Swizzle<SWIZZLE_Z, SWIZZLE_W, SWIZZLE_UNUSED, SWIZZLE_UNUSED>());
@@ -265,6 +274,7 @@ public:
 					UVec4 bounds_maxyz = UVec4::sLoadInt4(reinterpret_cast<const uint32 *>(&node->mBoundsMaxY[0]));
 					Vec4 bounds_maxy = HalfFloatConversion::ToFloat(bounds_maxyz);
 					Vec4 bounds_maxz = HalfFloatConversion::ToFloat(bounds_maxyz.Swizzle<SWIZZLE_Z, SWIZZLE_W, SWIZZLE_UNUSED, SWIZZLE_UNUSED>());
+				#endif
 
 					// Load properties for 4 children
 					UVec4 properties = UVec4::sLoadInt4(&node->mNodeProperties[0]);

+ 27 - 21
thirdparty/jolt_physics/Jolt/AABBTree/TriangleCodec/TriangleCodecIndexed8BitPackSOA4Flags.h

@@ -338,7 +338,7 @@ public:
 	class DecodingContext
 	{
 	private:
-		/// Private helper functions to unpack the 1 vertex of 4 triangles (outX contains the x coordinate of triangle 0 .. 3 etc.)
+		/// Private helper function to unpack the 1 vertex of 4 triangles (outX contains the x coordinate of triangle 0 .. 3 etc.)
 		JPH_INLINE void				Unpack(const VertexData *inVertices, UVec4Arg inIndex, Vec4 &outX, Vec4 &outY, Vec4 &outZ) const
 		{
 			// Get compressed data
@@ -356,6 +356,28 @@ public:
 			outZ = Vec4::sFusedMultiplyAdd(zc.ToFloat(), mScaleZ, mOffsetZ);
 		}
 
+		/// Private helper function to unpack 4 triangles from a triangle block
+		JPH_INLINE void				Unpack(const TriangleBlock *inBlock, const VertexData *inVertices, Vec4 &outX1, Vec4 &outY1, Vec4 &outZ1, Vec4 &outX2, Vec4 &outY2, Vec4 &outZ2, Vec4 &outX3, Vec4 &outY3, Vec4 &outZ3) const
+		{
+			// Get the indices for the three vertices (reads 4 bytes extra, but these are the flags so that's ok)
+			UVec4 indices = UVec4::sLoadInt4(reinterpret_cast<const uint32 *>(&inBlock->mIndices[0]));
+			UVec4 iv1 = indices.Expand4Byte0();
+			UVec4 iv2 = indices.Expand4Byte4();
+			UVec4 iv3 = indices.Expand4Byte8();
+
+		#ifdef JPH_CPU_BIG_ENDIAN
+			// On big endian systems we need to reverse the bytes
+			iv1 = iv1.Swizzle<SWIZZLE_W, SWIZZLE_Z, SWIZZLE_Y, SWIZZLE_X>();
+			iv2 = iv2.Swizzle<SWIZZLE_W, SWIZZLE_Z, SWIZZLE_Y, SWIZZLE_X>();
+			iv3 = iv3.Swizzle<SWIZZLE_W, SWIZZLE_Z, SWIZZLE_Y, SWIZZLE_X>();
+		#endif
+
+			// Decompress the triangle data
+			Unpack(inVertices, iv1, outX1, outY1, outZ1);
+			Unpack(inVertices, iv2, outX2, outY2, outZ2);
+			Unpack(inVertices, iv3, outX3, outY3, outZ3);
+		}
+
 	public:
 		JPH_INLINE explicit			DecodingContext(const TriangleHeader *inHeader) :
 			mOffsetX(Vec4::sReplicate(inHeader->mOffset.x)),
@@ -380,17 +402,9 @@ public:
 
 			do
 			{
-				// Get the indices for the three vertices (reads 4 bytes extra, but these are the flags so that's ok)
-				UVec4 indices = UVec4::sLoadInt4(reinterpret_cast<const uint32 *>(&t->mIndices[0]));
-				UVec4 iv1 = indices.Expand4Byte0();
-				UVec4 iv2 = indices.Expand4Byte4();
-				UVec4 iv3 = indices.Expand4Byte8();
-
-				// Decompress the triangle data
+				// Unpack the vertices for 4 triangles
 				Vec4 v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z;
-				Unpack(vertices, iv1, v1x, v1y, v1z);
-				Unpack(vertices, iv2, v2x, v2y, v2z);
-				Unpack(vertices, iv3, v3x, v3y, v3z);
+				Unpack(t, vertices, v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z);
 
 				// Transpose it so we get normal vectors
 				Mat44 v1 = Mat44(v1x, v1y, v1z, Vec4::sZero()).Transposed();
@@ -425,17 +439,9 @@ public:
 			UVec4 start_triangle_idx = UVec4::sZero();
 			do
 			{
-				// Get the indices for the three vertices (reads 4 bytes extra, but these are the flags so that's ok)
-				UVec4 indices = UVec4::sLoadInt4(reinterpret_cast<const uint32 *>(&t->mIndices[0]));
-				UVec4 iv1 = indices.Expand4Byte0();
-				UVec4 iv2 = indices.Expand4Byte4();
-				UVec4 iv3 = indices.Expand4Byte8();
-
-				// Decompress the triangle data
+				// Unpack the vertices for 4 triangles
 				Vec4 v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z;
-				Unpack(vertices, iv1, v1x, v1y, v1z);
-				Unpack(vertices, iv2, v2x, v2y, v2z);
-				Unpack(vertices, iv3, v3x, v3y, v3z);
+				Unpack(t, vertices, v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z);
 
 				// Perform ray vs triangle test
 				Vec4 distance = RayTriangle4(inRayOrigin, inRayDirection, v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z);

+ 16 - 1
thirdparty/jolt_physics/Jolt/ConfigurationString.h

@@ -14,8 +14,23 @@ inline const char *GetConfigurationString()
 		"x86 "
 #elif defined(JPH_CPU_ARM)
 		"ARM "
-#elif defined(JPH_PLATFORM_WASM)
+#elif defined(JPH_CPU_RISCV)
+		"RISC-V "
+#elif defined(JPH_CPU_PPC)
+		"PowerPC "
+	#ifdef JPH_CPU_BIG_ENDIAN
+		"(Big Endian) "
+	#else
+		"(Little Endian) "
+	#endif
+#elif defined(JPH_CPU_LOONGARCH)
+		"LoongArch "
+#elif defined(JPH_CPU_E2K)
+		"E2K "
+#elif defined(JPH_CPU_WASM)
 		"WASM "
+#else
+	#error Unknown CPU architecture
 #endif
 #if JPH_CPU_ADDRESS_BITS == 64
 		"64-bit "

+ 11 - 11
thirdparty/jolt_physics/Jolt/Core/Array.h

@@ -59,7 +59,7 @@ private:
 			{
 				for (T *destination_end = inDestination + inCount; inDestination < destination_end; ++inDestination, ++inSource)
 				{
-					::new (inDestination) T(std::move(*inSource));
+					new (inDestination) T(std::move(*inSource));
 					inSource->~T();
 				}
 			}
@@ -67,7 +67,7 @@ private:
 			{
 				for (T *destination = inDestination + inCount - 1, *source = inSource + inCount - 1; destination >= inDestination; --destination, --source)
 				{
-					::new (destination) T(std::move(*source));
+					new (destination) T(std::move(*source));
 					source->~T();
 				}
 			}
@@ -124,7 +124,7 @@ public:
 
 		if constexpr (!std::is_trivially_constructible<T>())
 			for (T *element = mElements + mSize, *element_end = mElements + inNewSize; element < element_end; ++element)
-				::new (element) T;
+				new (element) T;
 		mSize = inNewSize;
 	}
 
@@ -137,7 +137,7 @@ public:
 		reserve(inNewSize);
 
 		for (T *element = mElements + mSize, *element_end = mElements + inNewSize; element < element_end; ++element)
-			::new (element) T(inValue);
+			new (element) T(inValue);
 		mSize = inNewSize;
 	}
 
@@ -187,7 +187,7 @@ public:
 		reserve(size_type(std::distance(inBegin, inEnd)));
 
 		for (Iterator element = inBegin; element != inEnd; ++element)
-			::new (&mElements[mSize++]) T(*element);
+			new (&mElements[mSize++]) T(*element);
 	}
 
 	/// Replace the contents of this array with inList
@@ -197,7 +197,7 @@ public:
 		reserve(size_type(inList.size()));
 
 		for (const T &v : inList)
-			::new (&mElements[mSize++]) T(v);
+			new (&mElements[mSize++]) T(v);
 	}
 
 	/// Default constructor
@@ -281,7 +281,7 @@ public:
 		grow();
 
 		T *element = mElements + mSize++;
-		::new (element) T(inValue);
+		new (element) T(inValue);
 	}
 
 	inline void				push_back(T &&inValue)
@@ -289,7 +289,7 @@ public:
 		grow();
 
 		T *element = mElements + mSize++;
-		::new (element) T(std::move(inValue));
+		new (element) T(std::move(inValue));
 	}
 
 	/// Construct element at the back of the array
@@ -299,7 +299,7 @@ public:
 		grow();
 
 		T *element = mElements + mSize++;
-		::new (element) T(std::forward<A>(inValue)...);
+		new (element) T(std::forward<A>(inValue)...);
 		return *element;
 	}
 
@@ -365,7 +365,7 @@ public:
 			move(element_end, element_begin, mSize - first_element);
 
 			for (T *element = element_begin; element < element_end; ++element, ++inBegin)
-				::new (element) T(*inBegin);
+				new (element) T(*inBegin);
 
 			mSize += num_elements;
 		}
@@ -383,7 +383,7 @@ public:
 		T *element = mElements + first_element;
 		move(element + 1, element, mSize - first_element);
 
-		::new (element) T(inValue);
+		new (element) T(inValue);
 		mSize++;
 	}
 

+ 1 - 1
thirdparty/jolt_physics/Jolt/Core/ByteBuffer.h

@@ -41,7 +41,7 @@ public:
 
 		// Construct elements
 		for (Type *d = data, *d_end = data + inSize; d < d_end; ++d)
-			::new (d) Type;
+			new (d) Type;
 
 		// Return pointer
 		return data;

+ 38 - 3
thirdparty/jolt_physics/Jolt/Core/Core.h

@@ -180,6 +180,18 @@
 		#define JPH_VECTOR_ALIGNMENT 8 // 32-bit ARM does not support aligning on the stack on 16 byte boundaries
 		#define JPH_DVECTOR_ALIGNMENT 8
 	#endif
+#elif defined(__riscv)
+	// RISC-V CPU architecture
+	#define JPH_CPU_RISCV
+	#if __riscv_xlen == 64
+		#define JPH_CPU_ADDRESS_BITS 64
+		#define JPH_VECTOR_ALIGNMENT 16
+		#define JPH_DVECTOR_ALIGNMENT 32
+	#else
+		#define JPH_CPU_ADDRESS_BITS 32
+		#define JPH_VECTOR_ALIGNMENT 16
+		#define JPH_DVECTOR_ALIGNMENT 8
+	#endif
 #elif defined(JPH_PLATFORM_WASM)
 	// WebAssembly CPU architecture
 	#define JPH_CPU_WASM
@@ -191,6 +203,29 @@
 		#define JPH_USE_SSE4_1
 		#define JPH_USE_SSE4_2
 	#endif
+#elif defined(__powerpc__) || defined(__powerpc64__)
+	// PowerPC CPU architecture
+	#define JPH_CPU_PPC
+	#if defined(__powerpc64__)
+		#define JPH_CPU_ADDRESS_BITS 64
+	#else
+		#define JPH_CPU_ADDRESS_BITS 32
+	#endif
+	#ifdef _BIG_ENDIAN
+		#define JPH_CPU_BIG_ENDIAN
+	#endif
+	#define JPH_VECTOR_ALIGNMENT 16
+	#define JPH_DVECTOR_ALIGNMENT 8
+#elif defined(__loongarch__)
+	// LoongArch CPU architecture
+	#define JPH_CPU_LOONGARCH
+	#if defined(__loongarch64)
+		#define JPH_CPU_ADDRESS_BITS 64
+	#else
+		#define JPH_CPU_ADDRESS_BITS 32
+	#endif
+	#define JPH_VECTOR_ALIGNMENT 16
+	#define JPH_DVECTOR_ALIGNMENT 8
 #elif defined(__e2k__)
 	// E2K CPU architecture (MCST Elbrus 2000)
 	#define JPH_CPU_E2K
@@ -358,10 +393,10 @@
 #elif defined(JPH_PLATFORM_LINUX) || defined(JPH_PLATFORM_ANDROID) || defined(JPH_PLATFORM_MACOS) || defined(JPH_PLATFORM_IOS) || defined(JPH_PLATFORM_FREEBSD)
 	#if defined(JPH_CPU_X86)
 		#define JPH_BREAKPOINT	__asm volatile ("int $0x3")
-	#elif defined(JPH_CPU_ARM)
-		#define JPH_BREAKPOINT	__builtin_trap()
-	#elif defined(JPH_CPU_E2K)
+	#elif defined(JPH_CPU_ARM) || defined(JPH_CPU_RISCV) || defined(JPH_CPU_E2K) || defined(JPH_CPU_PPC) || defined(JPH_CPU_LOONGARCH)
 		#define JPH_BREAKPOINT	__builtin_trap()
+	#else
+		#error Unknown CPU architecture
 	#endif
 #elif defined(JPH_PLATFORM_WASM)
 	#define JPH_BREAKPOINT		do { } while (false) // Not supported

+ 8 - 0
thirdparty/jolt_physics/Jolt/Core/FPControlWord.h

@@ -126,6 +126,14 @@ private:
 	uint32		mPrevState;
 };
 
+#elif defined(JPH_CPU_RISCV)
+
+// RISC-V only implements manually checking if exceptions occurred by reading the fcsr register. It doesn't generate exceptions.
+
+#elif defined(JPH_CPU_PPC) || defined(JPH_CPU_LOONGARCH)
+
+// Not implemented right now
+
 #else
 
 #error Unsupported CPU architecture

+ 8 - 0
thirdparty/jolt_physics/Jolt/Core/FPException.h

@@ -56,6 +56,14 @@ class FPExceptionDisableInvalid : public FPControlWord<0, FP_IOE> { };
 /// Disable division by zero floating point exceptions
 class FPExceptionDisableDivByZero : public FPControlWord<0, FP_DZE> { };
 
+#elif defined(JPH_CPU_RISCV)
+
+#error "RISC-V only implements manually checking if exceptions occurred by reading the fcsr register. It doesn't generate exceptions. JPH_FLOATING_POINT_EXCEPTIONS_ENABLED must be disabled."
+
+#elif defined(JPH_CPU_PPC)
+
+#error PowerPC floating point exception handling to be implemented. JPH_FLOATING_POINT_EXCEPTIONS_ENABLED must be disabled.
+
 #else
 
 #error Unsupported CPU architecture

+ 3 - 1
thirdparty/jolt_physics/Jolt/Core/FPFlushDenormals.h

@@ -8,7 +8,7 @@
 
 JPH_NAMESPACE_BEGIN
 
-#if defined(JPH_CPU_WASM)
+#if defined(JPH_CPU_WASM) || defined(JPH_CPU_RISCV) || defined(JPH_CPU_PPC) || defined(JPH_CPU_LOONGARCH)
 
 // Not supported
 class FPFlushDenormals { };
@@ -21,6 +21,8 @@ class FPFlushDenormals : public FPControlWord<_MM_FLUSH_ZERO_ON, _MM_FLUSH_ZERO_
 
 #elif defined(JPH_CPU_ARM) && defined(JPH_COMPILER_MSVC)
 
+/// Helper class that needs to be put on the stack to enable flushing denormals to zero
+/// This can make floating point operations much faster when working with very small numbers
 class FPFlushDenormals : public FPControlWord<_DN_FLUSH, _MCW_DN> { };
 
 #elif defined(JPH_CPU_ARM)

+ 2 - 2
thirdparty/jolt_physics/Jolt/Core/FixedSizeFreeList.inl

@@ -79,7 +79,7 @@ uint32 FixedSizeFreeList<Object>::ConstructObject(Parameters &&... inParameters)
 			// Allocation successful
 			JPH_IF_ENABLE_ASSERTS(mNumFreeObjects.fetch_sub(1, memory_order_relaxed);)
 			ObjectStorage &storage = GetStorage(first_free);
-			::new (&storage.mObject) Object(std::forward<Parameters>(inParameters)...);
+			new (&storage.mObject) Object(std::forward<Parameters>(inParameters)...);
 			storage.mNextFreeObject.store(first_free, memory_order_release);
 			return first_free;
 		}
@@ -97,7 +97,7 @@ uint32 FixedSizeFreeList<Object>::ConstructObject(Parameters &&... inParameters)
 				// Allocation successful
 				JPH_IF_ENABLE_ASSERTS(mNumFreeObjects.fetch_sub(1, memory_order_relaxed);)
 				ObjectStorage &storage = GetStorage(first_free);
-				::new (&storage.mObject) Object(std::forward<Parameters>(inParameters)...);
+				new (&storage.mObject) Object(std::forward<Parameters>(inParameters)...);
 				storage.mNextFreeObject.store(first_free, memory_order_release);
 				return first_free;
 			}

+ 42 - 20
thirdparty/jolt_physics/Jolt/Core/HashCombine.h

@@ -17,8 +17,8 @@ inline uint64 HashBytes(const void *inData, uint inSize, uint64 inSeed = 0xcbf29
 	uint64 hash = inSeed;
 	for (const uint8 *data = reinterpret_cast<const uint8 *>(inData); data < reinterpret_cast<const uint8 *>(inData) + inSize; ++data)
 	{
-		hash = hash ^ uint64(*data);
-		hash = hash * 0x100000001b3UL;
+		hash ^= uint64(*data);
+		hash *= 0x100000001b3UL;
 	}
 	return hash;
 }
@@ -31,7 +31,7 @@ constexpr uint64 HashString(const char *inString, uint64 inSeed = 0xcbf29ce48422
 	for (const char *c = inString; *c != 0; ++c)
 	{
 		hash ^= uint64(*c);
-		hash = hash * 0x100000001b3UL;
+		hash *= 0x100000001b3UL;
 	}
 	return hash;
 }
@@ -142,12 +142,33 @@ JPH_DEFINE_TRIVIAL_HASH(int)
 JPH_DEFINE_TRIVIAL_HASH(uint32)
 JPH_DEFINE_TRIVIAL_HASH(uint64)
 
-/// @brief Helper function that hashes a single value into ioSeed
-/// Taken from: https://stackoverflow.com/questions/2590677/how-do-i-combine-hash-values-in-c0x
+/// Helper function that hashes a single value into ioSeed
+/// Based on https://github.com/jonmaiga/mx3 by Jon Maiga
 template <typename T>
 inline void HashCombine(uint64 &ioSeed, const T &inValue)
 {
-	ioSeed ^= Hash<T> { } (inValue) + 0x9e3779b9 + (ioSeed << 6) + (ioSeed >> 2);
+	constexpr uint64 c = 0xbea225f9eb34556dUL;
+
+	uint64 h = ioSeed;
+	uint64 x = Hash<T> { } (inValue);
+
+	// See: https://github.com/jonmaiga/mx3/blob/master/mx3.h
+	// mix_stream(h, x)
+	x *= c;
+	x ^= x >> 39;
+	h += x * c;
+	h *= c;
+
+	// mix(h)
+	h ^= h >> 32;
+	h *= c;
+	h ^= h >> 29;
+	h *= c;
+	h ^= h >> 32;
+	h *= c;
+	h ^= h >> 29;
+
+	ioSeed = h;
 }
 
 /// Hash combiner to use a custom struct in an unordered map or set
@@ -174,11 +195,6 @@ inline uint64 HashCombineArgs(const FirstValue &inFirstValue, Values... inValues
 	return seed;
 }
 
-JPH_NAMESPACE_END
-
-JPH_SUPPRESS_WARNING_PUSH
-JPH_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic")
-
 #define JPH_MAKE_HASH_STRUCT(type, name, ...)				\
 	struct [[nodiscard]] name								\
 	{														\
@@ -188,25 +204,31 @@ JPH_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic")
 		}													\
 	};
 
-#define JPH_MAKE_HASHABLE(type, ...)						\
+#define JPH_MAKE_STD_HASH(type)								\
 	JPH_SUPPRESS_WARNING_PUSH								\
 	JPH_SUPPRESS_WARNINGS									\
-	namespace JPH											\
-	{														\
-		template<>											\
-		JPH_MAKE_HASH_STRUCT(type, Hash<type>, __VA_ARGS__) \
-	}														\
 	namespace std											\
 	{														\
 		template<>											\
 		struct [[nodiscard]] hash<type>						\
 		{													\
-			std::size_t operator()(const type &t) const		\
+			size_t operator()(const type &t) const			\
 			{												\
-				return std::size_t(::JPH::Hash<type>{ }(t));\
+				return size_t(::JPH::Hash<type>{ }(t));		\
 			}												\
 		};													\
 	}														\
 	JPH_SUPPRESS_WARNING_POP
 
-JPH_SUPPRESS_WARNING_POP
+#define JPH_MAKE_HASHABLE(type, ...)						\
+	JPH_SUPPRESS_WARNING_PUSH								\
+	JPH_SUPPRESS_WARNINGS									\
+	namespace JPH											\
+	{														\
+		template<>											\
+		JPH_MAKE_HASH_STRUCT(type, Hash<type>, __VA_ARGS__) \
+	}														\
+	JPH_SUPPRESS_WARNING_POP								\
+	JPH_MAKE_STD_HASH(type)
+
+JPH_NAMESPACE_END

+ 4 - 4
thirdparty/jolt_physics/Jolt/Core/HashTable.h

@@ -175,7 +175,7 @@ private:
 		uint index = 0;
 		for (const uint8 *control = mControl, *control_end = mControl + mMaxSize; control != control_end; ++control, ++index)
 			if (*control & cBucketUsed)
-				::new (mData + index) KeyValue(inRHS.mData[index]);
+				new (mData + index) KeyValue(inRHS.mData[index]);
 		mSize = inRHS.mSize;
 	}
 
@@ -216,7 +216,7 @@ private:
 					KeyValue *element = old_data + i;
 					JPH_IF_ENABLE_ASSERTS(bool inserted =) InsertKey</* InsertAfterGrow= */ true>(HashTableDetail::sGetKey(*element), index);
 					JPH_ASSERT(inserted);
-					::new (mData + index) KeyValue(std::move(*element));
+					new (mData + index) KeyValue(std::move(*element));
 					element->~KeyValue();
 				}
 
@@ -601,7 +601,7 @@ public:
 		size_type index;
 		bool inserted = InsertKey(HashTableDetail::sGetKey(inValue), index);
 		if (inserted)
-			::new (mData + index) KeyValue(inValue);
+			new (mData + index) KeyValue(inValue);
 		return std::make_pair(iterator(this, index), inserted);
 	}
 
@@ -800,7 +800,7 @@ public:
 						// There's an empty bucket, move us there
 						SetControlValue(dst, src_control);
 						SetControlValue(src, cBucketEmpty);
-						::new (mData + dst) KeyValue(std::move(mData[src]));
+						new (mData + dst) KeyValue(std::move(mData[src]));
 						mData[src].~KeyValue();
 						break;
 					}

+ 5 - 1
thirdparty/jolt_physics/Jolt/Core/Memory.h

@@ -36,7 +36,11 @@ JPH_EXPORT void RegisterDefaultAllocator();
 	JPH_INLINE void *operator new (size_t inCount, std::align_val_t inAlignment)				{ return JPH::AlignedAllocate(inCount, static_cast<size_t>(inAlignment)); } \
 	JPH_INLINE void operator delete (void *inPointer, [[maybe_unused]] std::align_val_t inAlignment) noexcept	{ JPH::AlignedFree(inPointer); } \
 	JPH_INLINE void *operator new[] (size_t inCount, std::align_val_t inAlignment)				{ return JPH::AlignedAllocate(inCount, static_cast<size_t>(inAlignment)); } \
-	JPH_INLINE void operator delete[] (void *inPointer, [[maybe_unused]] std::align_val_t inAlignment) noexcept	{ JPH::AlignedFree(inPointer); }
+	JPH_INLINE void operator delete[] (void *inPointer, [[maybe_unused]] std::align_val_t inAlignment) noexcept	{ JPH::AlignedFree(inPointer); } \
+	JPH_INLINE void *operator new ([[maybe_unused]] size_t inCount, void *inPointer) noexcept	{ return inPointer; } \
+	JPH_INLINE void operator delete ([[maybe_unused]] void *inPointer, [[maybe_unused]] void *inPlace) noexcept { /* Do nothing */ } \
+	JPH_INLINE void *operator new[] ([[maybe_unused]] size_t inCount, void *inPointer) noexcept	{ return inPointer; } \
+	JPH_INLINE void operator delete[] ([[maybe_unused]] void *inPointer, [[maybe_unused]] void *inPlace) noexcept { /* Do nothing */ }
 
 #else
 

+ 13 - 13
thirdparty/jolt_physics/Jolt/Core/Result.h

@@ -21,11 +21,11 @@ public:
 		switch (inRHS.mState)
 		{
 		case EState::Valid:
-			::new (&mResult) Type (inRHS.mResult);
+			new (&mResult) Type (inRHS.mResult);
 			break;
 
 		case EState::Error:
-			::new (&mError) String(inRHS.mError);
+			new (&mError) String(inRHS.mError);
 			break;
 
 		case EState::Invalid:
@@ -40,11 +40,11 @@ public:
 		switch (inRHS.mState)
 		{
 		case EState::Valid:
-			::new (&mResult) Type (std::move(inRHS.mResult));
+			new (&mResult) Type (std::move(inRHS.mResult));
 			break;
 
 		case EState::Error:
-			::new (&mError) String(std::move(inRHS.mError));
+			new (&mError) String(std::move(inRHS.mError));
 			break;
 
 		case EState::Invalid:
@@ -67,11 +67,11 @@ public:
 		switch (inRHS.mState)
 		{
 		case EState::Valid:
-			::new (&mResult) Type (inRHS.mResult);
+			new (&mResult) Type (inRHS.mResult);
 			break;
 
 		case EState::Error:
-			::new (&mError) String(inRHS.mError);
+			new (&mError) String(inRHS.mError);
 			break;
 
 		case EState::Invalid:
@@ -91,11 +91,11 @@ public:
 		switch (inRHS.mState)
 		{
 		case EState::Valid:
-			::new (&mResult) Type (std::move(inRHS.mResult));
+			new (&mResult) Type (std::move(inRHS.mResult));
 			break;
 
 		case EState::Error:
-			::new (&mError) String(std::move(inRHS.mError));
+			new (&mError) String(std::move(inRHS.mError));
 			break;
 
 		case EState::Invalid:
@@ -137,10 +137,10 @@ public:
 	const Type &		Get() const									{ JPH_ASSERT(IsValid()); return mResult; }
 
 	/// Set the result value
-	void				Set(const Type &inResult)					{ Clear(); ::new (&mResult) Type(inResult); mState = EState::Valid; }
+	void				Set(const Type &inResult)					{ Clear(); new (&mResult) Type(inResult); mState = EState::Valid; }
 
 	/// Set the result value (move value)
-	void				Set(Type &&inResult)						{ Clear(); ::new (&mResult) Type(std::move(inResult)); mState = EState::Valid; }
+	void				Set(Type &&inResult)						{ Clear(); new (&mResult) Type(std::move(inResult)); mState = EState::Valid; }
 
 	/// Check if we had an error
 	bool				HasError() const							{ return mState == EState::Error; }
@@ -149,9 +149,9 @@ public:
 	const String &		GetError() const							{ JPH_ASSERT(HasError()); return mError; }
 
 	/// Set an error value
-	void				SetError(const char *inError)				{ Clear(); ::new (&mError) String(inError); mState = EState::Error; }
-	void				SetError(const string_view &inError)		{ Clear(); ::new (&mError) String(inError); mState = EState::Error; }
-	void				SetError(String &&inError)					{ Clear(); ::new (&mError) String(std::move(inError)); mState = EState::Error; }
+	void				SetError(const char *inError)				{ Clear(); new (&mError) String(inError); mState = EState::Error; }
+	void				SetError(const string_view &inError)		{ Clear(); new (&mError) String(inError); mState = EState::Error; }
+	void				SetError(String &&inError)					{ Clear(); new (&mError) String(std::move(inError)); mState = EState::Error; }
 
 private:
 	union

+ 7 - 7
thirdparty/jolt_physics/Jolt/Core/StaticArray.h

@@ -27,7 +27,7 @@ public:
 	{
 		JPH_ASSERT(inList.size() <= N);
 		for (const T &v : inList)
-			::new (reinterpret_cast<T *>(&mElements[mSize++])) T(v);
+			new (reinterpret_cast<T *>(&mElements[mSize++])) T(v);
 	}
 
 	/// Copy constructor
@@ -35,7 +35,7 @@ public:
 	{
 		while (mSize < inRHS.mSize)
 		{
-			::new (&mElements[mSize]) T(inRHS[mSize]);
+			new (&mElements[mSize]) T(inRHS[mSize]);
 			++mSize;
 		}
 	}
@@ -61,7 +61,7 @@ public:
 	void				push_back(const T &inElement)
 	{
 		JPH_ASSERT(mSize < N);
-		::new (&mElements[mSize++]) T(inElement);
+		new (&mElements[mSize++]) T(inElement);
 	}
 
 	/// Construct element at the back of the array
@@ -69,7 +69,7 @@ public:
 	void				emplace_back(A &&... inElement)
 	{
 		JPH_ASSERT(mSize < N);
-		::new (&mElements[mSize++]) T(std::forward<A>(inElement)...);
+		new (&mElements[mSize++]) T(std::forward<A>(inElement)...);
 	}
 
 	/// Remove element from the back of the array
@@ -103,7 +103,7 @@ public:
 		JPH_ASSERT(inNewSize <= N);
 		if constexpr (!std::is_trivially_constructible<T>())
 			for (T *element = reinterpret_cast<T *>(mElements) + mSize, *element_end = reinterpret_cast<T *>(mElements) + inNewSize; element < element_end; ++element)
-				::new (element) T;
+				new (element) T;
 		if constexpr (!std::is_trivially_destructible<T>())
 			for (T *element = reinterpret_cast<T *>(mElements) + inNewSize, *element_end = reinterpret_cast<T *>(mElements) + mSize; element < element_end; ++element)
 				element->~T();
@@ -232,7 +232,7 @@ public:
 
 			while (mSize < rhs_size)
 			{
-				::new (&mElements[mSize]) T(inRHS[mSize]);
+				new (&mElements[mSize]) T(inRHS[mSize]);
 				++mSize;
 			}
 		}
@@ -253,7 +253,7 @@ public:
 
 			while (mSize < rhs_size)
 			{
-				::new (&mElements[mSize]) T(inRHS[mSize]);
+				new (&mElements[mSize]) T(inRHS[mSize]);
 				++mSize;
 			}
 		}

+ 1 - 3
thirdparty/jolt_physics/Jolt/Core/TickCounter.h

@@ -35,9 +35,7 @@ JPH_INLINE uint64 GetProcessorTickCount()
 	uint64 val;
 	asm volatile("mrs %0, cntvct_el0" : "=r" (val));
 	return val;
-#elif defined(JPH_CPU_ARM)
-	return 0; // Not supported
-#elif defined(JPH_CPU_WASM)
+#elif defined(JPH_CPU_ARM) || defined(JPH_CPU_RISCV) || defined(JPH_CPU_WASM) || defined(JPH_CPU_PPC) || defined(JPH_CPU_LOONGARCH)
 	return 0; // Not supported
 #else
 	#error Undefined

+ 3 - 3
thirdparty/jolt_physics/Jolt/Core/UnorderedMap.h

@@ -42,7 +42,7 @@ public:
 		bool inserted = this->InsertKey(inKey, index);
 		value_type &key_value = this->GetElement(index);
 		if (inserted)
-			::new (&key_value) value_type(inKey, Value());
+			new (&key_value) value_type(inKey, Value());
 		return key_value.second;
 	}
 
@@ -52,7 +52,7 @@ public:
 		size_type index;
 		bool inserted = this->InsertKey(inKey, index);
 		if (inserted)
-			::new (&this->GetElement(index)) value_type(std::piecewise_construct, std::forward_as_tuple(inKey), std::forward_as_tuple(std::forward<Args>(inArgs)...));
+			new (&this->GetElement(index)) value_type(std::piecewise_construct, std::forward_as_tuple(inKey), std::forward_as_tuple(std::forward<Args>(inArgs)...));
 		return std::make_pair(iterator(this, index), inserted);
 	}
 
@@ -62,7 +62,7 @@ public:
 		size_type index;
 		bool inserted = this->InsertKey(inKey, index);
 		if (inserted)
-			::new (&this->GetElement(index)) value_type(std::piecewise_construct, std::forward_as_tuple(std::move(inKey)), std::forward_as_tuple(std::forward<Args>(inArgs)...));
+			new (&this->GetElement(index)) value_type(std::piecewise_construct, std::forward_as_tuple(std::move(inKey)), std::forward_as_tuple(std::forward<Args>(inArgs)...));
 		return std::make_pair(iterator(this, index), inserted);
 	}
 

+ 1 - 1
thirdparty/jolt_physics/Jolt/Geometry/Ellipse.h

@@ -38,7 +38,7 @@ public:
 		// <=> (x', y') = (a^2 x / (t + a^2), b^2 y / (t + b^2))
 		// Requiring point to be on ellipse (substituting into [1]): g(t) = (a x / (t + a^2))^2 + (b y / (t + b^2))^2 - 1 = 0
 
-		// Newton raphson iteration, starting at t = 0
+		// Newton Raphson iteration, starting at t = 0
 		float t = 0.0f;
 		for (;;)
 		{

+ 17 - 3
thirdparty/jolt_physics/Jolt/Geometry/IndexedTriangle.h

@@ -65,6 +65,13 @@ public:
 		return (Vec3(inVertices[mIdx[0]]) + Vec3(inVertices[mIdx[1]]) + Vec3(inVertices[mIdx[2]])) / 3.0f;
 	}
 
+	/// Get the hash value of this structure
+	uint64			GetHash() const
+	{
+		static_assert(sizeof(IndexedTriangleNoMaterial) == 3 * sizeof(uint32), "Class should have no padding");
+		return HashBytes(this, sizeof(IndexedTriangleNoMaterial));
+	}
+
 	uint32			mIdx[3];
 };
 
@@ -102,6 +109,13 @@ public:
 		}
 	}
 
+	/// Get the hash value of this structure
+	uint64			GetHash() const
+	{
+		static_assert(sizeof(IndexedTriangle) == 5 * sizeof(uint32), "Class should have no padding");
+		return HashBytes(this, sizeof(IndexedTriangle));
+	}
+
 	uint32			mMaterialIndex = 0;
 	uint32			mUserData = 0;				///< User data that can be used for anything by the application, e.g. for tracking the original index of the triangle
 };
@@ -111,6 +125,6 @@ using IndexedTriangleList = Array<IndexedTriangle>;
 
 JPH_NAMESPACE_END
 
-// Create a std::hash/JPH::Hash for IndexedTriangleNoMaterial and IndexedTriangle
-JPH_MAKE_HASHABLE(JPH::IndexedTriangleNoMaterial, t.mIdx[0], t.mIdx[1], t.mIdx[2])
-JPH_MAKE_HASHABLE(JPH::IndexedTriangle, t.mIdx[0], t.mIdx[1], t.mIdx[2], t.mMaterialIndex, t.mUserData)
+// Create a std::hash for IndexedTriangleNoMaterial and IndexedTriangle
+JPH_MAKE_STD_HASH(JPH::IndexedTriangleNoMaterial)
+JPH_MAKE_STD_HASH(JPH::IndexedTriangle)

+ 4 - 4
thirdparty/jolt_physics/Jolt/Geometry/RayAABox.h

@@ -36,7 +36,7 @@ JPH_INLINE float RayAABox(Vec3Arg inOrigin, const RayInvDirection &inInvDirectio
 	Vec3 flt_min = Vec3::sReplicate(-FLT_MAX);
 	Vec3 flt_max = Vec3::sReplicate(FLT_MAX);
 
-	// Test against all three axii simultaneously.
+	// Test against all three axes simultaneously.
 	Vec3 t1 = (inBoundsMin - inOrigin) * inInvDirection.mInvDirection;
 	Vec3 t2 = (inBoundsMax - inOrigin) * inInvDirection.mInvDirection;
 
@@ -90,7 +90,7 @@ JPH_INLINE Vec4 RayAABox4(Vec3Arg inOrigin, const RayInvDirection &inInvDirectio
 	Vec4 invdiry = inInvDirection.mInvDirection.SplatY();
 	Vec4 invdirz = inInvDirection.mInvDirection.SplatZ();
 
-	// Test against all three axii simultaneously.
+	// Test against all three axes simultaneously.
 	Vec4 t1x = (inBoundsMinX - originx) * invdirx;
 	Vec4 t1y = (inBoundsMinY - originy) * invdiry;
 	Vec4 t1z = (inBoundsMinZ - originz) * invdirz;
@@ -139,7 +139,7 @@ JPH_INLINE void RayAABox(Vec3Arg inOrigin, const RayInvDirection &inInvDirection
 	Vec3 flt_min = Vec3::sReplicate(-FLT_MAX);
 	Vec3 flt_max = Vec3::sReplicate(FLT_MAX);
 
-	// Test against all three axii simultaneously.
+	// Test against all three axes simultaneously.
 	Vec3 t1 = (inBoundsMin - inOrigin) * inInvDirection.mInvDirection;
 	Vec3 t2 = (inBoundsMax - inOrigin) * inInvDirection.mInvDirection;
 
@@ -178,7 +178,7 @@ JPH_INLINE bool RayAABoxHits(Vec3Arg inOrigin, const RayInvDirection &inInvDirec
 	Vec3 flt_min = Vec3::sReplicate(-FLT_MAX);
 	Vec3 flt_max = Vec3::sReplicate(FLT_MAX);
 
-	// Test against all three axii simultaneously.
+	// Test against all three axes simultaneously.
 	Vec3 t1 = (inBoundsMin - inOrigin) * inInvDirection.mInvDirection;
 	Vec3 t2 = (inBoundsMax - inOrigin) * inInvDirection.mInvDirection;
 

+ 3 - 3
thirdparty/jolt_physics/Jolt/Math/EigenValueSymmetric.h

@@ -11,7 +11,7 @@ JPH_NAMESPACE_BEGIN
 /// Function to determine the eigen vectors and values of a N x N real symmetric matrix
 /// by Jacobi transformations. This method is most suitable for N < 10.
 ///
-/// Taken and adapted from Numerical Recipies paragraph 11.1
+/// Taken and adapted from Numerical Recipes paragraph 11.1
 ///
 /// An eigen vector is a vector v for which \f$A \: v = \lambda \: v\f$
 ///
@@ -95,7 +95,7 @@ bool EigenValueSymmetric(const Matrix &inMatrix, Matrix &outEigVec, Vector &outE
 
 		// On the first three sweeps use a fraction of the sum of the off diagonal elements as threshold
 		// Note that we pick a minimum threshold of FLT_MIN because dividing by a denormalized number is likely to result in infinity.
-		float tresh = sweep < 4? 0.2f * avg_sm : FLT_MIN; // Original code: 0.0f instead of FLT_MIN
+		float thresh = sweep < 4? 0.2f * avg_sm : FLT_MIN; // Original code: 0.0f instead of FLT_MIN
 
 		for (uint ip = 0; ip < n - 1; ++ip)
 			for (uint iq = ip + 1; iq < n; ++iq)
@@ -114,7 +114,7 @@ bool EigenValueSymmetric(const Matrix &inMatrix, Matrix &outEigVec, Vector &outE
 				{
 					a_pq = 0.0f;
 				}
-				else if (abs_a_pq > tresh)
+				else if (abs_a_pq > thresh)
 				{
 					float h = eigval_q - eigval_p;
 					float abs_h = abs(h);

+ 1 - 1
thirdparty/jolt_physics/Jolt/Math/GaussianElimination.h

@@ -14,7 +14,7 @@ JPH_NAMESPACE_BEGIN
 /// Set A to the matrix to invert, set B to identity and let GaussianElimination solve
 /// the equation, on return B will be the inverse of A. And A is destroyed.
 ///
-/// Taken and adapted from Numerical Recipies in C paragraph 2.1
+/// Taken and adapted from Numerical Recipes in C paragraph 2.1
 template <class MatrixA, class MatrixB>
 bool GaussianElimination(MatrixA &ioA, MatrixB &ioB, float inTolerance = 1.0e-16f)
 {

+ 5 - 5
thirdparty/jolt_physics/Jolt/Math/Math.h

@@ -72,7 +72,7 @@ JPH_INLINE constexpr T Sign(T inV)
 template <typename T>
 constexpr bool IsPowerOf2(T inV)
 {
-	return (inV & (inV - 1)) == 0;
+	return inV > 0 && (inV & (inV - 1)) == 0;
 }
 
 /// Align inV up to the next inAlignment bytes
@@ -120,8 +120,8 @@ inline uint CountTrailingZeros(uint32 inValue)
 			return 32;
 		return __builtin_ctz(inValue);
 	#endif
-#elif defined(JPH_CPU_E2K)
-		return inValue ? __builtin_ctz(inValue) : 32;
+#elif defined(JPH_CPU_E2K) || defined(JPH_CPU_RISCV) || defined(JPH_CPU_PPC) || defined(JPH_CPU_LOONGARCH)
+	return inValue ? __builtin_ctz(inValue) : 32;
 #else
 	#error Undefined
 #endif
@@ -150,8 +150,8 @@ inline uint CountLeadingZeros(uint32 inValue)
 	#else
 		return __builtin_clz(inValue);
 	#endif
-#elif defined(JPH_CPU_E2K)
-		return inValue ? __builtin_clz(inValue) : 32;
+#elif defined(JPH_CPU_E2K) || defined(JPH_CPU_RISCV) || defined(JPH_CPU_PPC) || defined(JPH_CPU_LOONGARCH)
+	return inValue ? __builtin_clz(inValue) : 32;
 #else
 	#error Undefined
 #endif

+ 2 - 6
thirdparty/jolt_physics/Jolt/Math/Vec3.inl

@@ -64,9 +64,7 @@ Vec3::Vec3(const Float3 &inV)
 	mF32[0] = inV[0];
 	mF32[1] = inV[1];
 	mF32[2] = inV[2];
-	#ifdef JPH_FLOATING_POINT_EXCEPTIONS_ENABLED
-		mF32[3] = inV[2];
-	#endif
+	mF32[3] = inV[2]; // Not strictly needed when JPH_FLOATING_POINT_EXCEPTIONS_ENABLED is off but prevents warnings about uninitialized variables
 #endif
 }
 
@@ -82,9 +80,7 @@ Vec3::Vec3(float inX, float inY, float inZ)
 	mF32[0] = inX;
 	mF32[1] = inY;
 	mF32[2] = inZ;
-	#ifdef JPH_FLOATING_POINT_EXCEPTIONS_ENABLED
-		mF32[3] = inZ;
-	#endif
+	mF32[3] = inZ; // Not strictly needed when JPH_FLOATING_POINT_EXCEPTIONS_ENABLED is off but prevents warnings about uninitialized variables
 #endif
 }
 

+ 1 - 1
thirdparty/jolt_physics/Jolt/Physics/Body/MotionQuality.h

@@ -9,7 +9,7 @@ JPH_NAMESPACE_BEGIN
 /// Motion quality, or how well it detects collisions when it has a high velocity
 enum class EMotionQuality : uint8
 {
-	/// Update the body in discrete steps. Body will tunnel throuh thin objects if its velocity is high enough.
+	/// Update the body in discrete steps. Body will tunnel through thin objects if its velocity is high enough.
 	/// This is the cheapest way of simulating a body.
 	Discrete,
 

+ 1 - 1
thirdparty/jolt_physics/Jolt/Physics/Character/Character.h

@@ -92,7 +92,7 @@ public:
 	RVec3								GetPosition(bool inLockBodies = true) const;
 
 	/// Set the position of the character, optionally activating it.
-	void								SetPosition(RVec3Arg inPostion, EActivation inActivationMode = EActivation::Activate, bool inLockBodies = true);
+	void								SetPosition(RVec3Arg inPosition, EActivation inActivationMode = EActivation::Activate, bool inLockBodies = true);
 
 	/// Get the rotation of the character
 	Quat								GetRotation(bool inLockBodies = true) const;

+ 1 - 1
thirdparty/jolt_physics/Jolt/Physics/Collision/BroadPhase/BroadPhase.h

@@ -75,7 +75,7 @@ public:
 	virtual void		RemoveBodies(BodyID *ioBodies, int inNumber) = 0;
 
 	/// Call whenever the aabb of a body changes (can change order of ioBodies array)
-	/// inTakeLock should be false if we're between LockModifications/UnlockModificiations in which case care needs to be taken to not call this between UpdatePrepare/UpdateFinalize
+	/// inTakeLock should be false if we're between LockModifications/UnlockModifications, in which case care needs to be taken to not call this between UpdatePrepare/UpdateFinalize
 	virtual void		NotifyBodiesAABBChanged(BodyID *ioBodies, int inNumber, bool inTakeLock = true) = 0;
 
 	/// Call whenever the layer (and optionally the aabb as well) of a body changes (can change order of ioBodies array)

+ 1 - 1
thirdparty/jolt_physics/Jolt/Physics/Collision/BroadPhase/BroadPhaseQuadTree.cpp

@@ -350,7 +350,7 @@ void BroadPhaseQuadTree::NotifyBodiesAABBChanged(BodyID *ioBodies, int inNumber,
 		// Find first body with different layer
 		BodyID *b_mid = std::upper_bound(b_start, b_end, broadphase_layer, [tracking](BroadPhaseLayer::Type inLayer, BodyID inBodyID) { return inLayer < tracking[inBodyID.GetIndex()].mBroadPhaseLayer; });
 
-		// Nodify all bodies of the same layer changed
+		// Notify all bodies of the same layer changed
 		mLayers[broadphase_layer].NotifyBodiesAABBChanged(bodies, mTracking, b_start, int(b_mid - b_start));
 
 		// Repeat

+ 1 - 1
thirdparty/jolt_physics/Jolt/Physics/Collision/BroadPhase/QuadTree.cpp

@@ -702,7 +702,7 @@ void QuadTree::WidenAndMarkNodeAndParentsChanged(uint32 inNodeIndex, const AABox
 
 bool QuadTree::TryInsertLeaf(TrackingVector &ioTracking, int inNodeIndex, NodeID inLeafID, const AABox &inLeafBounds, int inLeafNumBodies)
 {
-	// Tentively assign the node as parent
+	// Tentatively assign the node as parent
 	bool leaf_is_node = inLeafID.IsNode();
 	if (leaf_is_node)
 	{

+ 1 - 1
thirdparty/jolt_physics/Jolt/Physics/Collision/CastSphereVsTriangles.cpp

@@ -104,7 +104,7 @@ float CastSphereVsTriangles::RayCylinder(Vec3Arg inRayDirection, Vec3Arg inCylin
 	float c = axis_len_sq * (start.LengthSq() - Square(inRadius)) - Square(start_dot_axis);
 	float det = Square(b) - a * c; // normally 4 * a * c but since both a and c need to be divided by 2 we lose the 4
 	if (det < 0.0f)
-		return FLT_MAX; // No solution to quadractic equation
+		return FLT_MAX; // No solution to quadratic equation
 
 	// Solve fraction t where the ray hits the cylinder
 	float t = -(b + sqrt(det)) / a; // normally divided by 2 * a but since a should be divided by 2 we lose the 2

+ 3 - 2
thirdparty/jolt_physics/Jolt/Physics/Collision/CollideShape.h

@@ -59,7 +59,7 @@ public:
 	Vec3						mContactPointOn1;			///< Contact point on the surface of shape 1 (in world space or relative to base offset)
 	Vec3						mContactPointOn2;			///< Contact point on the surface of shape 2 (in world space or relative to base offset). If the penetration depth is 0, this will be the same as mContactPointOn1.
 	Vec3						mPenetrationAxis;			///< Direction to move shape 2 out of collision along the shortest path (magnitude is meaningless, in world space). You can use -mPenetrationAxis.Normalized() as contact normal.
-	float						mPenetrationDepth;			///< Penetration depth (move shape 2 by this distance to resolve the collision)
+	float						mPenetrationDepth;			///< Penetration depth (move shape 2 by this distance to resolve the collision). If CollideShapeSettings::mMaxSeparationDistance > 0 this number can be negative to indicate that the objects are separated by -mPenetrationDepth. The contact points are the closest points in that case.
 	SubShapeID					mSubShapeID1;				///< Sub shape ID that identifies the face on shape 1
 	SubShapeID					mSubShapeID2;				///< Sub shape ID that identifies the face on shape 2
 	BodyID						mBodyID2;					///< BodyID to which shape 2 belongs to
@@ -95,7 +95,8 @@ class CollideShapeSettings : public CollideSettingsBase
 public:
 	JPH_OVERRIDE_NEW_DELETE
 
-	/// When > 0 contacts in the vicinity of the query shape can be found. All nearest contacts that are not further away than this distance will be found (unit: meter)
+	/// When > 0 contacts in the vicinity of the query shape can be found. All nearest contacts that are not further away than this distance will be found.
+	/// Note that in this case CollideShapeResult::mPenetrationDepth can become negative to indicate that objects are not overlapping. (unit: meter)
 	float						mMaxSeparationDistance		= 0.0f;
 
 	/// How backfacing triangles should be treated

+ 1 - 1
thirdparty/jolt_physics/Jolt/Physics/Collision/Shape/ConvexHullShape.cpp

@@ -104,7 +104,7 @@ ConvexHullShape::ConvexHullShape(const ConvexHullShapeSettings &inSettings, Shap
 		{
 			Vec3 v3 = inSettings.mPoints[e->mStartIdx] - mCenterOfMass;
 
-			// Affine transform that transforms a unit tetrahedon (with vertices (0, 0, 0), (1, 0, 0), (0, 1, 0) and (0, 0, 1) to this tetrahedron
+			// Affine transform that transforms a unit tetrahedron (with vertices (0, 0, 0), (1, 0, 0), (0, 1, 0) and (0, 0, 1) to this tetrahedron
 			Mat44 a(Vec4(v1, 0), Vec4(v2, 0), Vec4(v3, 0), Vec4(0, 0, 0, 1));
 
 			// Calculate covariance matrix for this tetrahedron

+ 1 - 1
thirdparty/jolt_physics/Jolt/Physics/Collision/Shape/Shape.h

@@ -331,7 +331,7 @@ public:
 	/// Collect the leaf transformed shapes of all leaf shapes of this shape.
 	/// inBox is the world space axis aligned box which leaf shapes should collide with.
 	/// inPositionCOM/inRotation/inScale describes the transform of this shape.
-	/// inSubShapeIDCeator represents the current sub shape ID of this shape.
+	/// inSubShapeIDCreator represents the current sub shape ID of this shape.
 	virtual void					CollectTransformedShapes(const AABox &inBox, Vec3Arg inPositionCOM, QuatArg inRotation, Vec3Arg inScale, const SubShapeIDCreator &inSubShapeIDCreator, TransformedShapeCollector &ioCollector, const ShapeFilter &inShapeFilter) const;
 
 	/// Transforms this shape and all of its children with inTransform, resulting shape(s) are passed to ioCollector.

+ 1 - 16
thirdparty/jolt_physics/Jolt/Physics/Collision/Shape/SubShapeIDPair.h

@@ -62,19 +62,4 @@ static_assert(alignof(SubShapeIDPair) == 4, "Assuming 4 byte aligned");
 
 JPH_NAMESPACE_END
 
-JPH_SUPPRESS_WARNINGS_STD_BEGIN
-
-namespace std
-{
-	/// Declare std::hash for SubShapeIDPair
-	template <>
-	struct hash<JPH::SubShapeIDPair>
-	{
-		inline size_t operator () (const JPH::SubShapeIDPair &inRHS) const
-		{
-			return static_cast<size_t>(inRHS.GetHash());
-		}
-	};
-}
-
-JPH_SUPPRESS_WARNINGS_STD_END
+JPH_MAKE_STD_HASH(JPH::SubShapeIDPair)

+ 1 - 1
thirdparty/jolt_physics/Jolt/Physics/Collision/Shape/TaperedCylinderShape.cpp

@@ -313,7 +313,7 @@ MassProperties TaperedCylinderShape::GetMassProperties() const
 	// Ixx(br,tr,b,t):=integrate(dix(x)+area(x)*x^2,x,b,t)*density(b,t);
 	// Inertia tensor element yy:
 	// Iyy(br,tr,b,t):=integrate(diy(x),x,b,t)*density(b,t);
-	// Note that we can simplfy Ixx by using:
+	// Note that we can simplify Ixx by using:
 	// Ixx_delta(br,tr,b,t):=Ixx(br,tr,b,t)-Iyy(br,tr,b,t)/2;
 	// For a cylinder this formula matches what is listed on the wiki:
 	// factor(Ixx(r,r,-h/2,h/2));

+ 6 - 6
thirdparty/jolt_physics/Jolt/Physics/Collision/Shape/TriangleShape.cpp

@@ -91,7 +91,7 @@ class TriangleShape::TriangleNoConvex final : public Support
 {
 public:
 							TriangleNoConvex(Vec3Arg inV1, Vec3Arg inV2, Vec3Arg inV3) :
-		mTriangleSuport(inV1, inV2, inV3)
+		mTriangleSupport(inV1, inV2, inV3)
 	{
 		static_assert(sizeof(TriangleNoConvex) <= sizeof(SupportBuffer), "Buffer size too small");
 		JPH_ASSERT(IsAligned(this, alignof(TriangleNoConvex)));
@@ -99,7 +99,7 @@ public:
 
 	virtual Vec3			GetSupport(Vec3Arg inDirection) const override
 	{
-		return mTriangleSuport.GetSupport(inDirection);
+		return mTriangleSupport.GetSupport(inDirection);
 	}
 
 	virtual float			GetConvexRadius() const override
@@ -108,7 +108,7 @@ public:
 	}
 
 private:
-	TriangleConvexSupport	mTriangleSuport;
+	TriangleConvexSupport	mTriangleSupport;
 };
 
 class TriangleShape::TriangleWithConvex final : public Support
@@ -116,7 +116,7 @@ class TriangleShape::TriangleWithConvex final : public Support
 public:
 							TriangleWithConvex(Vec3Arg inV1, Vec3Arg inV2, Vec3Arg inV3, float inConvexRadius) :
 		mConvexRadius(inConvexRadius),
-		mTriangleSuport(inV1, inV2, inV3)
+		mTriangleSupport(inV1, inV2, inV3)
 	{
 		static_assert(sizeof(TriangleWithConvex) <= sizeof(SupportBuffer), "Buffer size too small");
 		JPH_ASSERT(IsAligned(this, alignof(TriangleWithConvex)));
@@ -124,7 +124,7 @@ public:
 
 	virtual Vec3			GetSupport(Vec3Arg inDirection) const override
 	{
-		Vec3 support = mTriangleSuport.GetSupport(inDirection);
+		Vec3 support = mTriangleSupport.GetSupport(inDirection);
 		float len = inDirection.Length();
 		if (len > 0.0f)
 			support += (mConvexRadius / len) * inDirection;
@@ -138,7 +138,7 @@ public:
 
 private:
 	float					mConvexRadius;
-	TriangleConvexSupport	mTriangleSuport;
+	TriangleConvexSupport	mTriangleSupport;
 };
 
 const ConvexShape::Support *TriangleShape::GetSupportFunction(ESupportMode inMode, SupportBuffer &inBuffer, Vec3Arg inScale) const

+ 1 - 1
thirdparty/jolt_physics/Jolt/Physics/Collision/TransformedShape.h

@@ -89,7 +89,7 @@ public:
 	inline Vec3					GetShapeScale() const						{ return Vec3::sLoadFloat3Unsafe(mShapeScale); }
 	inline void					SetShapeScale(Vec3Arg inScale)				{ inScale.StoreFloat3(&mShapeScale); }
 
-	/// Calculates the transform for this shapes's center of mass (excluding scale)
+	/// Calculates the transform for this shape's center of mass (excluding scale)
 	inline RMat44				GetCenterOfMassTransform() const			{ return RMat44::sRotationTranslation(mShapeRotation, mShapePositionCOM); }
 
 	/// Calculates the inverse of the transform for this shape's center of mass (excluding scale)

+ 1 - 1
thirdparty/jolt_physics/Jolt/Physics/Constraints/ContactConstraintManager.cpp

@@ -136,7 +136,7 @@ JPH_INLINE void ContactConstraintManager::WorldContactPoint::TemplatedCalculateF
 		float surface_velocity1 = inWorldSpaceTangent1.Dot(ws_surface_velocity);
 		float surface_velocity2 = inWorldSpaceTangent2.Dot(ws_surface_velocity);
 
-		// Implement friction as 2 AxisContraintParts
+		// Implement friction as 2 AxisConstraintParts
 		mFrictionConstraint1.TemplatedCalculateConstraintProperties<Type1, Type2>(inInvM1, inInvI1, r1, inInvM2, inInvI2, r2, inWorldSpaceTangent1, surface_velocity1);
 		mFrictionConstraint2.TemplatedCalculateConstraintProperties<Type1, Type2>(inInvM1, inInvI1, r1, inInvM2, inInvI2, r2, inWorldSpaceTangent2, surface_velocity2);
 	}

+ 8 - 2
thirdparty/jolt_physics/Jolt/Physics/PhysicsSettings.h

@@ -80,13 +80,19 @@ struct PhysicsSettings
 	/// Number of solver position iterations to run
 	uint		mNumPositionSteps = 2;
 
-	/// Minimal velocity needed before a collision can be elastic (unit: m)
+	/// Minimal velocity needed before a collision can be elastic. If the relative velocity between colliding objects
+	/// in the direction of the contact normal is lower than this, the restitution will be zero regardless of the configured
+	/// value. This lets an object settle sooner. Must be a positive number. (unit: m)
 	float		mMinVelocityForRestitution = 1.0f;
 
 	/// Time before object is allowed to go to sleep (unit: seconds)
 	float		mTimeBeforeSleep = 0.5f;
 
-	/// Velocity of points on bounding box of object below which an object can be considered sleeping (unit: m/s)
+	/// To detect if an object is sleeping, we use 3 points:
+	/// - The center of mass.
+	/// - The centers of the faces of the bounding box that are furthest away from the center.
+	/// The movement of these points is tracked and if the velocity of all 3 points is lower than this value,
+	/// the object is allowed to go to sleep. Must be a positive number. (unit: m/s)
 	float		mPointVelocitySleepThreshold = 0.03f;
 
 	/// By default the simulation is deterministic, it is possible to turn this off by setting this setting to false. This will make the simulation run faster but it will no longer be deterministic.

+ 2 - 2
thirdparty/jolt_physics/Jolt/Physics/PhysicsSystem.cpp

@@ -1443,7 +1443,7 @@ void PhysicsSystem::JobSolveVelocityConstraints(PhysicsUpdateContext *ioContext,
 		}
 		else if (check_split_islands)
 		{
-			// If there are split islands, but we did't do any work, give up a time slice
+			// If there are split islands, but we didn't do any work, give up a time slice
 			std::this_thread::yield();
 		}
 		else
@@ -2462,7 +2462,7 @@ void PhysicsSystem::JobSolvePositionConstraints(PhysicsUpdateContext *ioContext,
 		}
 		else if (check_split_islands)
 		{
-			// If there are split islands, but we did't do any work, give up a time slice
+			// If there are split islands, but we didn't do any work, give up a time slice
 			std::this_thread::yield();
 		}
 		else

+ 3 - 1
thirdparty/jolt_physics/Jolt/Physics/PhysicsSystem.h

@@ -65,7 +65,7 @@ public:
 
 	/// Set the function that combines the restitution of two bodies and returns it
 	/// Default method is max(restitution1, restitution1)
-	void						SetCombineRestitution(ContactConstraintManager::CombineFunction inCombineRestition) { mContactManager.SetCombineRestitution(inCombineRestition); }
+	void						SetCombineRestitution(ContactConstraintManager::CombineFunction inCombineRestitution) { mContactManager.SetCombineRestitution(inCombineRestitution); }
 	ContactConstraintManager::CombineFunction GetCombineRestitution() const					{ return mContactManager.GetCombineRestitution(); }
 
 	/// Set/get the shape filter that will be used during simulation. This can be used to exclude shapes within a body from colliding with each other.
@@ -126,6 +126,8 @@ public:
 	/// The world steps for a total of inDeltaTime seconds. This is divided in inCollisionSteps iterations.
 	/// Each iteration consists of collision detection followed by an integration step.
 	/// This function internally spawns jobs using inJobSystem and waits for them to complete, so no jobs will be running when this function returns.
+	/// The temp allocator is used, for example, to store the list of bodies that are in contact, how they form islands together
+	/// and data to solve the contacts between bodies. At the end of the Update call, all allocated memory will have been freed.
 	EPhysicsUpdateError			Update(float inDeltaTime, int inCollisionSteps, TempAllocator *inTempAllocator, JobSystem *inJobSystem);
 
 	/// Saving state for replay

+ 6 - 3
thirdparty/jolt_physics/Jolt/Physics/SoftBody/SoftBodyMotionProperties.cpp

@@ -599,7 +599,7 @@ void SoftBodyMotionProperties::ApplyCollisionConstraintsAndUpdateVelocities(cons
 	JPH_PROFILE_FUNCTION();
 
 	float dt = inContext.mSubStepDeltaTime;
-	float restitution_treshold = -2.0f * inContext.mGravity.Length() * dt;
+	float restitution_threshold = -2.0f * inContext.mGravity.Length() * dt;
 	float vertex_radius = mSettings->mVertexRadius;
 	for (Vertex &v : mVertices)
 		if (v.mInvMass > 0.0f)
@@ -674,7 +674,7 @@ void SoftBodyMotionProperties::ApplyCollisionConstraintsAndUpdateVelocities(cons
 							// Calculate delta relative velocity due to restitution (equation 35)
 							dv += v_normal;
 							float prev_v_normal = (prev_v - v2).Dot(contact_normal);
-							if (prev_v_normal < restitution_treshold)
+							if (prev_v_normal < restitution_threshold)
 								dv += cs.mRestitution * prev_v_normal * contact_normal;
 
 							// Calculate impulse
@@ -707,7 +707,7 @@ void SoftBodyMotionProperties::ApplyCollisionConstraintsAndUpdateVelocities(cons
 						// Apply restitution (equation 35)
 						v.mVelocity -= v_normal;
 						float prev_v_normal = prev_v.Dot(contact_normal);
-						if (prev_v_normal < restitution_treshold)
+						if (prev_v_normal < restitution_threshold)
 							v.mVelocity -= cs.mRestitution * prev_v_normal * contact_normal;
 					}
 				}
@@ -1032,7 +1032,10 @@ void SoftBodyMotionProperties::SkinVertices([[maybe_unused]] RMat44Arg inCenterO
 	const Mat44 *skin_matrices_end = skin_matrices + num_skin_matrices;
 	const InvBind *inv_bind_matrix = mSettings->mInvBindMatrices.data();
 	for (Mat44 *s = skin_matrices; s < skin_matrices_end; ++s, ++inv_bind_matrix)
+	{
+		JPH_ASSERT(inv_bind_matrix->mJointIndex < inNumJoints);
 		*s = inJointMatrices[inv_bind_matrix->mJointIndex] * inv_bind_matrix->mInvBind;
+	}
 
 	// Skin the vertices
 	JPH_IF_DEBUG_RENDERER(mSkinStateTransform = inCenterOfMassTransform;)

+ 1 - 1
thirdparty/jolt_physics/Jolt/Physics/SoftBody/SoftBodyMotionProperties.h

@@ -125,7 +125,7 @@ public:
 	/// This function allows you to update the soft body immediately without going through the PhysicsSystem.
 	/// This is useful if the soft body is teleported and needs to 'settle' or it can be used if a the soft body
 	/// is not added to the PhysicsSystem and needs to be updated manually. One reason for not adding it to the
-	/// PhyicsSystem is that you might want to update a soft body immediately after updating an animated object
+	/// PhysicsSystem is that you might want to update a soft body immediately after updating an animated object
 	/// that has the soft body attached to it. If the soft body is added to the PhysicsSystem it will be updated
 	/// by it, so calling this function will effectively update it twice. Note that when you use this function,
 	/// only the current thread will be used, whereas if you update through the PhysicsSystem, multiple threads may

+ 1 - 1
thirdparty/jolt_physics/Jolt/Physics/SoftBody/SoftBodySharedSettings.h

@@ -204,7 +204,7 @@ public:
 		/// Return the lowest vertex index of this constraint
 		uint32			GetMinVertexIndex() const					{ return min(min(mVertex[0], mVertex[1]), min(mVertex[2], mVertex[3])); }
 
-		uint32			mVertex[4];									///< Indices of the vertices that form the tetrhedron
+		uint32			mVertex[4];									///< Indices of the vertices that form the tetrahedron
 		float			mSixRestVolume = 1.0f;						///< 6 times the rest volume of the tetrahedron (calculated by CalculateVolumeConstraintVolumes())
 		float			mCompliance = 0.0f;							///< Inverse of the stiffness of the constraint
 	};

+ 1 - 1
thirdparty/jolt_physics/Jolt/Physics/Vehicle/TrackedVehicleController.h

@@ -25,7 +25,7 @@ public:
 	virtual void				RestoreBinaryState(StreamIn &inStream) override;
 
 	float						mLongitudinalFriction = 4.0f;				///< Friction in forward direction of tire
-	float						mLateralFriction = 2.0f;					///< Friction in sideway direction of tire
+	float						mLateralFriction = 2.0f;					///< Friction in sideways direction of tire
 };
 
 /// Wheel object specifically for TrackedVehicleController

+ 55 - 0
thirdparty/jolt_physics/Jolt/Skeleton/SkeletalAnimation.cpp

@@ -7,6 +7,8 @@
 #include <Jolt/Skeleton/SkeletalAnimation.h>
 #include <Jolt/Skeleton/SkeletonPose.h>
 #include <Jolt/ObjectStream/TypeDeclarations.h>
+#include <Jolt/Core/StreamIn.h>
+#include <Jolt/Core/StreamOut.h>
 
 JPH_NAMESPACE_BEGIN
 
@@ -107,4 +109,57 @@ void SkeletalAnimation::Sample(float inTime, SkeletonPose &ioPose) const
 	}
 }
 
+void SkeletalAnimation::SaveBinaryState(StreamOut &inStream) const
+{
+	inStream.Write((uint32)mAnimatedJoints.size());
+	for (const AnimatedJoint &j : mAnimatedJoints)
+	{
+		// Write Joint name and number of keyframes
+		inStream.Write(j.mJointName);
+		inStream.Write((uint32)j.mKeyframes.size());
+		for (const Keyframe &k : j.mKeyframes)
+		{
+			inStream.Write(k.mTime);
+			inStream.Write(k.mRotation);
+			inStream.Write(k.mTranslation);
+		}
+	}
+
+	// Save additional parameters
+	inStream.Write(mIsLooping);
+}
+
+SkeletalAnimation::AnimationResult SkeletalAnimation::sRestoreFromBinaryState(StreamIn &inStream)
+{
+	AnimationResult result;
+
+	Ref<SkeletalAnimation> animation = new SkeletalAnimation;
+
+	// Restore animated joints
+	uint32 len = 0;
+	inStream.Read(len);
+	animation->mAnimatedJoints.resize(len);
+	for (AnimatedJoint &j : animation->mAnimatedJoints)
+	{
+		// Read joint name
+		inStream.Read(j.mJointName);
+
+		// Read keyframes
+		len = 0;
+		inStream.Read(len);
+		j.mKeyframes.resize(len);
+		for (Keyframe &k : j.mKeyframes)
+		{
+			inStream.Read(k.mTime);
+			inStream.Read(k.mRotation);
+			inStream.Read(k.mTranslation);
+		}
+	}
+
+	// Read additional parameters
+	inStream.Read(animation->mIsLooping);
+	result.Set(animation);
+	return result;
+}
+
 JPH_NAMESPACE_END

+ 14 - 0
thirdparty/jolt_physics/Jolt/Skeleton/SkeletalAnimation.h

@@ -5,6 +5,8 @@
 #pragma once
 
 #include <Jolt/Core/Reference.h>
+#include <Jolt/Core/Result.h>
+#include <Jolt/Core/StreamUtils.h>
 #include <Jolt/ObjectStream/SerializableObject.h>
 
 JPH_NAMESPACE_BEGIN
@@ -62,6 +64,10 @@ public:
 	/// Scale the size of all joints by inScale
 	void								ScaleJoints(float inScale);
 
+	/// If the animation is looping or not. If an animation is looping, the animation will continue playing after completion
+	void 								SetIsLooping(bool inIsLooping)						{ mIsLooping = inIsLooping; }
+	bool								IsLooping() const									{ return mIsLooping; }
+
 	/// Get the (interpolated) joint transforms at time inTime
 	void								Sample(float inTime, SkeletonPose &ioPose) const;
 
@@ -69,6 +75,14 @@ public:
 	const AnimatedJointVector &			GetAnimatedJoints() const							{ return mAnimatedJoints; }
 	AnimatedJointVector &				GetAnimatedJoints()									{ return mAnimatedJoints; }
 
+	/// Saves the state of this animation in binary form to inStream.
+	void								SaveBinaryState(StreamOut &inStream) const;
+
+	using AnimationResult = Result<Ref<SkeletalAnimation>>;
+
+	/// Restore a saved ragdoll from inStream
+	static AnimationResult				sRestoreFromBinaryState(StreamIn &inStream);
+
 private:
 	AnimatedJointVector					mAnimatedJoints;									///< List of joints and keyframes
 	bool								mIsLooping = true;									///< If this animation loops back to start