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

Fixes #100557.
This commit is contained in:
Rémi Verschelde 2024-12-21 15:13:15 +01:00
parent a7a2a12bfd
commit 4727f0707b
No known key found for this signature in database
GPG key ID: C3336907360768E1
49 changed files with 350 additions and 166 deletions

View file

@ -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):

View file

@ -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:

View file

@ -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]);

View file

@ -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);

View file

@ -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 "

View file

@ -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++;
}

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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;
}

View file

@ -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,6 +204,22 @@ JPH_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic")
} \
};
#define JPH_MAKE_STD_HASH(type) \
JPH_SUPPRESS_WARNING_PUSH \
JPH_SUPPRESS_WARNINGS \
namespace std \
{ \
template<> \
struct [[nodiscard]] hash<type> \
{ \
size_t operator()(const type &t) const \
{ \
return size_t(::JPH::Hash<type>{ }(t)); \
} \
}; \
} \
JPH_SUPPRESS_WARNING_POP
#define JPH_MAKE_HASHABLE(type, ...) \
JPH_SUPPRESS_WARNING_PUSH \
JPH_SUPPRESS_WARNINGS \
@ -196,17 +228,7 @@ JPH_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic")
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 \
{ \
return std::size_t(::JPH::Hash<type>{ }(t));\
} \
}; \
} \
JPH_SUPPRESS_WARNING_POP
JPH_SUPPRESS_WARNING_POP \
JPH_MAKE_STD_HASH(type)
JPH_SUPPRESS_WARNING_POP
JPH_NAMESPACE_END

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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;
}
}

View file

@ -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

View file

@ -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);
}

View file

@ -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 (;;)
{

View file

@ -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)

View file

@ -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;

View file

@ -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);

View file

@ -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)
{

View file

@ -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

View file

@ -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
}

View file

@ -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,

View file

@ -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;

View file

@ -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)

View file

@ -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

View file

@ -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)
{

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -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)

View file

@ -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));

View file

@ -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

View file

@ -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)

View file

@ -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);
}

View file

@ -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.

View file

@ -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

View file

@ -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

View file

@ -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;)

View file

@ -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

View file

@ -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
};

View file

@ -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

View file

@ -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

View file

@ -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