diff --git a/WickedEngine/Jolt/ConfigurationString.h b/WickedEngine/Jolt/ConfigurationString.h index 7c044f574..55e5d8c35 100644 --- a/WickedEngine/Jolt/ConfigurationString.h +++ b/WickedEngine/Jolt/ConfigurationString.h @@ -81,6 +81,12 @@ inline const char *GetConfigurationString() #endif #ifdef JPH_DEBUG "(Debug) " +#endif +#if defined(__cpp_rtti) && __cpp_rtti + "(C++ RTTI) " +#endif +#if defined(__cpp_exceptions) && __cpp_exceptions + "(C++ Exceptions) " #endif ; } diff --git a/WickedEngine/Jolt/Core/ARMNeon.h b/WickedEngine/Jolt/Core/ARMNeon.h index ee4d55278..6273945dc 100644 --- a/WickedEngine/Jolt/Core/ARMNeon.h +++ b/WickedEngine/Jolt/Core/ARMNeon.h @@ -6,13 +6,22 @@ #ifdef JPH_USE_NEON +// Constructing NEON values #ifdef JPH_COMPILER_MSVC - JPH_NAMESPACE_BEGIN - - // Constructing NEON values #define JPH_NEON_INT32x4(v1, v2, v3, v4) { int64_t(v1) + (int64_t(v2) << 32), int64_t(v3) + (int64_t(v4) << 32) } #define JPH_NEON_UINT32x4(v1, v2, v3, v4) { uint64_t(v1) + (uint64_t(v2) << 32), uint64_t(v3) + (uint64_t(v4) << 32) } #define JPH_NEON_INT8x16(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) { int64_t(v1) + (int64_t(v2) << 8) + (int64_t(v3) << 16) + (int64_t(v4) << 24) + (int64_t(v5) << 32) + (int64_t(v6) << 40) + (int64_t(v7) << 48) + (int64_t(v8) << 56), int64_t(v9) + (int64_t(v10) << 8) + (int64_t(v11) << 16) + (int64_t(v12) << 24) + (int64_t(v13) << 32) + (int64_t(v14) << 40) + (int64_t(v15) << 48) + (int64_t(v16) << 56) } + #define JPH_NEON_UINT8x16(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) { uint64_t(v1) + (uint64_t(v2) << 8) + (uint64_t(v3) << 16) + (uint64_t(v4) << 24) + (uint64_t(v5) << 32) + (uint64_t(v6) << 40) + (uint64_t(v7) << 48) + (uint64_t(v8) << 56), uint64_t(v9) + (uint64_t(v10) << 8) + (uint64_t(v11) << 16) + (uint64_t(v12) << 24) + (uint64_t(v13) << 32) + (uint64_t(v14) << 40) + (uint64_t(v15) << 48) + (uint64_t(v16) << 56) } +#else + #define JPH_NEON_INT32x4(v1, v2, v3, v4) { v1, v2, v3, v4 } + #define JPH_NEON_UINT32x4(v1, v2, v3, v4) { v1, v2, v3, v4 } + #define JPH_NEON_INT8x16(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) { v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16 } + #define JPH_NEON_UINT8x16(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) { v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16 } +#endif + +// MSVC and GCC prior to version 12 don't define __builtin_shufflevector +#if defined(JPH_COMPILER_MSVC) || (defined(JPH_COMPILER_GCC) && __GNUC__ < 12) + JPH_NAMESPACE_BEGIN // Generic shuffle vector template template @@ -30,13 +39,13 @@ template <> JPH_INLINE float32x4_t NeonShuffleFloat32x4<0, 1, 2, 2>(float32x4_t inV1, float32x4_t inV2) { - return vcombine_f32(vget_low_f32(inV1), vdup_lane_s32(vget_high_f32(inV1), 0)); + return vcombine_f32(vget_low_f32(inV1), vdup_lane_f32(vget_high_f32(inV1), 0)); } template <> JPH_INLINE float32x4_t NeonShuffleFloat32x4<0, 1, 3, 3>(float32x4_t inV1, float32x4_t inV2) { - return vcombine_f32(vget_low_f32(inV1), vdup_lane_s32(vget_high_f32(inV1), 1)); + return vcombine_f32(vget_low_f32(inV1), vdup_lane_f32(vget_high_f32(inV1), 1)); } template <> @@ -48,13 +57,13 @@ template <> JPH_INLINE float32x4_t NeonShuffleFloat32x4<1, 0, 3, 2>(float32x4_t inV1, float32x4_t inV2) { - return vcombine_f32(vrev64_f32(vget_low_f32(inV1)), vrev64_f32(vget_high_f32(inV1))); + return vcombine_f32(vrev64_f32(vget_low_f32(inV1)), vrev64_f32(vget_high_f32(inV1))); } template <> JPH_INLINE float32x4_t NeonShuffleFloat32x4<2, 2, 1, 0>(float32x4_t inV1, float32x4_t inV2) { - return vcombine_f32(vdup_lane_s32(vget_high_f32(inV1), 0), vrev64_f32(vget_low_f32(inV1))); + return vcombine_f32(vdup_lane_f32(vget_high_f32(inV1), 0), vrev64_f32(vget_low_f32(inV1))); } template <> @@ -67,22 +76,19 @@ template <> JPH_INLINE float32x4_t NeonShuffleFloat32x4<1, 2, 0, 0>(float32x4_t inV1, float32x4_t inV2) { - static int8x16_t table = JPH_NEON_INT8x16(0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x02, 0x03); - return vreinterpretq_f32_u8(vqtbl1q_u8(vreinterpretq_u8_f32(inV1), table)); + static uint8x16_t table = JPH_NEON_UINT8x16(0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x02, 0x03); + return vreinterpretq_f32_u8(vqtbl1q_u8(vreinterpretq_u8_f32(inV1), table)); } // Shuffle a vector #define JPH_NEON_SHUFFLE_F32x4(vec1, vec2, index1, index2, index3, index4) NeonShuffleFloat32x4(vec1, vec2) + #define JPH_NEON_SHUFFLE_U32x4(vec1, vec2, index1, index2, index3, index4) vreinterpretq_u32_f32((NeonShuffleFloat32x4(vreinterpretq_f32_u32(vec1), vreinterpretq_f32_u32(vec2)))) JPH_NAMESPACE_END #else - // Constructing NEON values - #define JPH_NEON_INT32x4(v1, v2, v3, v4) { v1, v2, v3, v4 } - #define JPH_NEON_UINT32x4(v1, v2, v3, v4) { v1, v2, v3, v4 } - #define JPH_NEON_INT8x16(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) { v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16 } - // Shuffle a vector #define JPH_NEON_SHUFFLE_F32x4(vec1, vec2, index1, index2, index3, index4) __builtin_shufflevector(vec1, vec2, index1, index2, index3, index4) + #define JPH_NEON_SHUFFLE_U32x4(vec1, vec2, index1, index2, index3, index4) __builtin_shufflevector(vec1, vec2, index1, index2, index3, index4) #endif #endif // JPH_USE_NEON diff --git a/WickedEngine/Jolt/Core/Array.h b/WickedEngine/Jolt/Core/Array.h index 1d167d857..ba6720e8d 100644 --- a/WickedEngine/Jolt/Core/Array.h +++ b/WickedEngine/Jolt/Core/Array.h @@ -194,8 +194,8 @@ public: clear(); reserve(size_type(inList.size())); - for (typename std::initializer_list::iterator i = inList.begin(); i != inList.end(); ++i) - ::new (&mElements[mSize++]) T(*i); + for (const T &v : inList) + ::new (&mElements[mSize++]) T(v); } /// Default constructor @@ -582,13 +582,13 @@ namespace std std::size_t ret = 0; // Hash length first - JPH::HashCombine(ret, inRHS.size()); + JPH::HashCombine(ret, inRHS.size()); // Then hash elements for (const T &t : inRHS) - JPH::HashCombine(ret, t); + JPH::HashCombine(ret, t); - return ret; + return ret; } }; } diff --git a/WickedEngine/Jolt/Core/Core.h b/WickedEngine/Jolt/Core/Core.h index f4ce872ab..5e0e26791 100644 --- a/WickedEngine/Jolt/Core/Core.h +++ b/WickedEngine/Jolt/Core/Core.h @@ -6,8 +6,8 @@ // Jolt library version #define JPH_VERSION_MAJOR 5 -#define JPH_VERSION_MINOR 0 -#define JPH_VERSION_PATCH 1 +#define JPH_VERSION_MINOR 1 +#define JPH_VERSION_PATCH 0 // Determine which features the library was compiled with #ifdef JPH_DOUBLE_PRECISION @@ -86,12 +86,12 @@ #elif defined(__FreeBSD__) #define JPH_PLATFORM_FREEBSD #elif defined(__APPLE__) - #include - #if defined(TARGET_OS_IPHONE) && !TARGET_OS_IPHONE - #define JPH_PLATFORM_MACOS - #else - #define JPH_PLATFORM_IOS - #endif + #include + #if defined(TARGET_OS_IPHONE) && !TARGET_OS_IPHONE + #define JPH_PLATFORM_MACOS + #else + #define JPH_PLATFORM_IOS + #endif #elif defined(__EMSCRIPTEN__) #define JPH_PLATFORM_WASM #endif @@ -318,6 +318,7 @@ JPH_GCC_SUPPRESS_WARNING("-Wclass-memaccess") \ JPH_GCC_SUPPRESS_WARNING("-Wpedantic") \ JPH_GCC_SUPPRESS_WARNING("-Wunused-parameter") \ + JPH_GCC_SUPPRESS_WARNING("-Wmaybe-uninitialized") \ \ JPH_MSVC_SUPPRESS_WARNING(4619) /* #pragma warning: there is no warning number 'XXXX' */ \ JPH_MSVC_SUPPRESS_WARNING(4514) /* 'X' : unreferenced inline function has been removed */ \ @@ -405,6 +406,9 @@ JPH_SUPPRESS_WARNINGS_STD_BEGIN #include #include #include +#ifdef JPH_COMPILER_MSVC + #include // for alloca +#endif #if defined(JPH_USE_SSE) #include #elif defined(JPH_USE_NEON) diff --git a/WickedEngine/Jolt/Core/FPControlWord.h b/WickedEngine/Jolt/Core/FPControlWord.h index a046bffe9..0c8b3f1ff 100644 --- a/WickedEngine/Jolt/Core/FPControlWord.h +++ b/WickedEngine/Jolt/Core/FPControlWord.h @@ -75,11 +75,11 @@ public: FPControlWord() { uint64 val; - asm volatile("mrs %0, fpcr" : "=r" (val)); + asm volatile("mrs %0, fpcr" : "=r" (val)); mPrevState = val; val &= ~Mask; val |= Value; - asm volatile("msr fpcr, %0" : /* no output */ : "r" (val)); + asm volatile("msr fpcr, %0" : /* no output */ : "r" (val)); } ~FPControlWord() diff --git a/WickedEngine/Jolt/Core/HashCombine.h b/WickedEngine/Jolt/Core/HashCombine.h index 372070be3..d3d79f6a3 100644 --- a/WickedEngine/Jolt/Core/HashCombine.h +++ b/WickedEngine/Jolt/Core/HashCombine.h @@ -46,7 +46,7 @@ template inline void HashCombineHelper(size_t &ioSeed, const T &inValue) { std::hash hasher; - ioSeed ^= hasher(inValue) + 0x9e3779b9 + (ioSeed << 6) + (ioSeed >> 2); + ioSeed ^= hasher(inValue) + 0x9e3779b9 + (ioSeed << 6) + (ioSeed >> 2); } /// Hash combiner to use a custom struct in an unordered map or set @@ -55,9 +55,9 @@ inline void HashCombineHelper(size_t &ioSeed, const T &inValue) /// /// struct SomeHashKey /// { -/// std::string key1; -/// std::string key2; -/// bool key3; +/// std::string key1; +/// std::string key2; +/// bool key3; /// }; /// /// JPH_MAKE_HASHABLE(SomeHashKey, t.key1, t.key2, t.key3) @@ -76,22 +76,22 @@ JPH_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic") #define JPH_MAKE_HASH_STRUCT(type, name, ...) \ struct [[nodiscard]] name \ { \ - std::size_t operator()(const type &t) const \ + std::size_t operator()(const type &t) const \ { \ - std::size_t ret = 0; \ - ::JPH::HashCombine(ret, __VA_ARGS__); \ - return ret; \ - } \ - }; + std::size_t ret = 0; \ + ::JPH::HashCombine(ret, __VA_ARGS__); \ + return ret; \ + } \ + }; #define JPH_MAKE_HASHABLE(type, ...) \ JPH_SUPPRESS_WARNING_PUSH \ JPH_SUPPRESS_WARNINGS \ - namespace std \ + namespace std \ { \ - template<> \ + template<> \ JPH_MAKE_HASH_STRUCT(type, hash, __VA_ARGS__) \ - } \ + } \ JPH_SUPPRESS_WARNING_POP JPH_SUPPRESS_WARNING_POP diff --git a/WickedEngine/Jolt/Core/IssueReporting.h b/WickedEngine/Jolt/Core/IssueReporting.h index 29aeb911f..efbf9a0d8 100644 --- a/WickedEngine/Jolt/Core/IssueReporting.h +++ b/WickedEngine/Jolt/Core/IssueReporting.h @@ -30,7 +30,7 @@ JPH_EXPORT extern TraceFunction Trace; #define JPH_IF_ENABLE_ASSERTS(...) __VA_ARGS__ #else - #define JPH_ASSERT(...) ((void)0) + #define JPH_ASSERT(...) ((void)0) #define JPH_IF_ENABLE_ASSERTS(...) #endif // JPH_ENABLE_ASSERTS diff --git a/WickedEngine/Jolt/Core/JobSystem.h b/WickedEngine/Jolt/Core/JobSystem.h index f12f53809..301e4ce8e 100644 --- a/WickedEngine/Jolt/Core/JobSystem.h +++ b/WickedEngine/Jolt/Core/JobSystem.h @@ -33,9 +33,9 @@ JPH_NAMESPACE_BEGIN /// barrier->AddJob(third_job); /// job_system->WaitForJobs(barrier); /// -/// // Clean up -/// job_system->DestroyBarrier(barrier); -/// delete job_system; +/// // Clean up +/// job_system->DestroyBarrier(barrier); +/// delete job_system; /// /// Jobs are guaranteed to be started in the order that their dependency counter becomes zero (in case they're scheduled on a background thread) /// or in the order they're added to the barrier (when dependency count is zero and when executing on the thread that calls WaitForJobs). diff --git a/WickedEngine/Jolt/Core/JobSystemThreadPool.cpp b/WickedEngine/Jolt/Core/JobSystemThreadPool.cpp index 8a871f5ef..04da37afe 100644 --- a/WickedEngine/Jolt/Core/JobSystemThreadPool.cpp +++ b/WickedEngine/Jolt/Core/JobSystemThreadPool.cpp @@ -46,8 +46,9 @@ JobSystemThreadPool::JobSystemThreadPool(uint inMaxJobs, uint inMaxBarriers, int Init(inMaxJobs, inMaxBarriers, inNumThreads); } -void JobSystemThreadPool::StartThreads(int inNumThreads) +void JobSystemThreadPool::StartThreads([[maybe_unused]] int inNumThreads) { +#if !defined(JPH_CPU_WASM) || defined(__EMSCRIPTEN_PTHREADS__) // If we're running without threads support we cannot create threads and we ignore the inNumThreads parameter // Auto detect number of threads if (inNumThreads < 0) inNumThreads = thread::hardware_concurrency() - 1; @@ -69,6 +70,7 @@ void JobSystemThreadPool::StartThreads(int inNumThreads) mThreads.reserve(inNumThreads); for (int i = 0; i < inNumThreads; ++i) mThreads.emplace_back([this, i] { ThreadMain(i); }); +#endif } JobSystemThreadPool::~JobSystemThreadPool() diff --git a/WickedEngine/Jolt/Core/JobSystemWithBarrier.h b/WickedEngine/Jolt/Core/JobSystemWithBarrier.h index 0428824a4..0fc663330 100644 --- a/WickedEngine/Jolt/Core/JobSystemWithBarrier.h +++ b/WickedEngine/Jolt/Core/JobSystemWithBarrier.h @@ -70,7 +70,7 @@ private: /// Jobs queue for the barrier static constexpr uint cMaxJobs = 2048; static_assert(IsPowerOf2(cMaxJobs)); // We do bit operations and require max jobs to be a power of 2 - atomic mJobs[cMaxJobs]; ///< List of jobs that are part of this barrier, nullptrs for empty slots + atomic mJobs[cMaxJobs]; ///< List of jobs that are part of this barrier, nullptrs for empty slots alignas(JPH_CACHE_LINE_SIZE) atomic mJobReadIndex { 0 }; ///< First job that could be valid (modulo cMaxJobs), can be nullptr if other thread is still working on adding the job alignas(JPH_CACHE_LINE_SIZE) atomic mJobWriteIndex { 0 }; ///< First job that can be written (modulo cMaxJobs) atomic mNumToAcquire { 0 }; ///< Number of times the semaphore has been released, the barrier should acquire the semaphore this many times (written at the same time as mJobWriteIndex so ok to put in same cache line) diff --git a/WickedEngine/Jolt/Core/LockFreeHashMap.h b/WickedEngine/Jolt/Core/LockFreeHashMap.h index c4cbfa8ec..ac1557b39 100644 --- a/WickedEngine/Jolt/Core/LockFreeHashMap.h +++ b/WickedEngine/Jolt/Core/LockFreeHashMap.h @@ -145,7 +145,7 @@ public: bool operator != (const Iterator &inRHS) const { return !(*this == inRHS); } /// Convert to key value pair - KeyValue & operator * (); + KeyValue & operator * (); /// Next item Iterator & operator ++ (); diff --git a/WickedEngine/Jolt/Core/Memory.cpp b/WickedEngine/Jolt/Core/Memory.cpp index d500fc05a..6e642c4ea 100644 --- a/WickedEngine/Jolt/Core/Memory.cpp +++ b/WickedEngine/Jolt/Core/Memory.cpp @@ -25,10 +25,10 @@ JPH_ALLOC_SCOPE void *JPH_ALLOC_FN(Allocate)(size_t inSize) return malloc(inSize); } -JPH_ALLOC_SCOPE void *JPH_ALLOC_FN(Reallocate)(void *inBlock, size_t inSize) +JPH_ALLOC_SCOPE void *JPH_ALLOC_FN(Reallocate)(void *inBlock, [[maybe_unused]] size_t inOldSize, size_t inNewSize) { - JPH_ASSERT(inSize > 0); - return realloc(inBlock, inSize); + JPH_ASSERT(inNewSize > 0); + return realloc(inBlock, inNewSize); } JPH_ALLOC_SCOPE void JPH_ALLOC_FN(Free)(void *inBlock) diff --git a/WickedEngine/Jolt/Core/Memory.h b/WickedEngine/Jolt/Core/Memory.h index cae9f09c1..d5b7c6a30 100644 --- a/WickedEngine/Jolt/Core/Memory.h +++ b/WickedEngine/Jolt/Core/Memory.h @@ -10,7 +10,7 @@ JPH_NAMESPACE_BEGIN // Normal memory allocation, must be at least 8 byte aligned on 32 bit platform and 16 byte aligned on 64 bit platform using AllocateFunction = void *(*)(size_t inSize); -using ReallocateFunction = void *(*)(void *inBlock, size_t inSize); +using ReallocateFunction = void *(*)(void *inBlock, size_t inOldSize, size_t inNewSize); using FreeFunction = void (*)(void *inBlock); // Aligned memory allocation @@ -42,7 +42,7 @@ JPH_EXPORT void RegisterDefaultAllocator(); // Directly define the allocation functions JPH_EXPORT void *Allocate(size_t inSize); -JPH_EXPORT void *Reallocate(void *inBlock, size_t inSize); +JPH_EXPORT void *Reallocate(void *inBlock, size_t inOldSize, size_t inNewSize); JPH_EXPORT void Free(void *inBlock); JPH_EXPORT void *AlignedAllocate(size_t inSize, size_t inAlignment); JPH_EXPORT void AlignedFree(void *inBlock); diff --git a/WickedEngine/Jolt/Core/Profiler.cpp b/WickedEngine/Jolt/Core/Profiler.cpp index 839939966..4b2b908c9 100644 --- a/WickedEngine/Jolt/Core/Profiler.cpp +++ b/WickedEngine/Jolt/Core/Profiler.cpp @@ -13,10 +13,15 @@ JPH_SUPPRESS_WARNINGS_STD_BEGIN #include JPH_SUPPRESS_WARNINGS_STD_END -#ifdef JPH_PROFILE_ENABLED - JPH_NAMESPACE_BEGIN +#if defined(JPH_EXTERNAL_PROFILE) && defined(JPH_SHARED_LIBRARY) + +ProfileStartMeasurementFunction ProfileStartMeasurement = [](const char *, uint32, uint8 *) { }; +ProfileEndMeasurementFunction ProfileEndMeasurement = [](uint8 *) { }; + +#elif defined(JPH_PROFILE_ENABLED) + ////////////////////////////////////////////////////////////////////////////////////////// // Profiler ////////////////////////////////////////////////////////////////////////////////////////// @@ -341,6 +346,6 @@ void Profiler::DumpChart(const char *inTag, const Threads &inThreads, const KeyT )"; } -JPH_NAMESPACE_END - #endif // JPH_PROFILE_ENABLED + +JPH_NAMESPACE_END diff --git a/WickedEngine/Jolt/Core/Profiler.h b/WickedEngine/Jolt/Core/Profiler.h index bbe641821..878865313 100644 --- a/WickedEngine/Jolt/Core/Profiler.h +++ b/WickedEngine/Jolt/Core/Profiler.h @@ -17,16 +17,31 @@ JPH_SUPPRESS_WARNINGS_STD_END JPH_NAMESPACE_BEGIN +#ifdef JPH_SHARED_LIBRARY +/// Functions called when a profiler measurement starts or stops, need to be overridden by the user. +using ProfileStartMeasurementFunction = void (*)(const char *inName, uint32 inColor, uint8 *ioUserData); +using ProfileEndMeasurementFunction = void (*)(uint8 *ioUserData); + +JPH_EXPORT extern ProfileStartMeasurementFunction ProfileStartMeasurement; +JPH_EXPORT extern ProfileEndMeasurementFunction ProfileEndMeasurement; +#endif // JPH_SHARED_LIBRARY + /// Create this class on the stack to start sampling timing information of a particular scope. /// -/// Left unimplemented intentionally. Needs to be implemented by the user of the library. +/// For statically linked builds, this is left unimplemented intentionally. Needs to be implemented by the user of the library. /// On construction a measurement should start, on destruction it should be stopped. +/// For dynamically linked builds, the user should override the ProfileStartMeasurement and ProfileEndMeasurement functions. class alignas(16) ExternalProfileMeasurement : public NonCopyable { public: /// Constructor +#ifdef JPH_SHARED_LIBRARY + JPH_INLINE ExternalProfileMeasurement(const char *inName, uint32 inColor = 0) { ProfileStartMeasurement(inName, inColor, mUserData); } + JPH_INLINE ~ExternalProfileMeasurement() { ProfileEndMeasurement(mUserData); } +#else ExternalProfileMeasurement(const char *inName, uint32 inColor = 0); ~ExternalProfileMeasurement(); +#endif private: uint8 mUserData[64]; @@ -42,6 +57,8 @@ JPH_SUPPRESS_WARNING_PUSH JPH_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic") // Dummy implementations +#define JPH_PROFILE_START(name) +#define JPH_PROFILE_END() #define JPH_PROFILE_THREAD_START(name) #define JPH_PROFILE_THREAD_END() #define JPH_PROFILE_NEXTFRAME() diff --git a/WickedEngine/Jolt/Core/RTTI.h b/WickedEngine/Jolt/Core/RTTI.h index 0de966049..4bbb35374 100644 --- a/WickedEngine/Jolt/Core/RTTI.h +++ b/WickedEngine/Jolt/Core/RTTI.h @@ -308,7 +308,7 @@ public: \ #define JPH_DECLARE_RTTI_WITH_NAMESPACE_FOR_FACTORY(linkage, name_space, class_name) \ namespace name_space { \ - class class_name; \ + class class_name; \ linkage RTTI * GetRTTIOfType(class class_name *); \ } diff --git a/WickedEngine/Jolt/Core/Reference.h b/WickedEngine/Jolt/Core/Reference.h index d6fdf1da5..57862cd08 100644 --- a/WickedEngine/Jolt/Core/Reference.h +++ b/WickedEngine/Jolt/Core/Reference.h @@ -108,7 +108,7 @@ public: inline ~Ref() { Release(); } /// Assignment operators - inline Ref & operator = (T *inRHS) { if (mPtr != inRHS) { Release(); mPtr = inRHS; AddRef(); } return *this; } + inline Ref & operator = (T *inRHS) { if (mPtr != inRHS) { Release(); mPtr = inRHS; AddRef(); } return *this; } inline Ref & operator = (const Ref &inRHS) { if (mPtr != inRHS.mPtr) { Release(); mPtr = inRHS.mPtr; AddRef(); } return *this; } inline Ref & operator = (Ref &&inRHS) noexcept { if (mPtr != inRHS.mPtr) { Release(); mPtr = inRHS.mPtr; inRHS.mPtr = nullptr; } return *this; } @@ -116,7 +116,7 @@ public: inline operator T *() const { return mPtr; } /// Access like a normal pointer - inline T * operator -> () const { return mPtr; } + inline T * operator -> () const { return mPtr; } inline T & operator * () const { return *mPtr; } /// Comparison @@ -126,7 +126,7 @@ public: inline bool operator != (const Ref &inRHS) const { return mPtr != inRHS.mPtr; } /// Get pointer - inline T * GetPtr() const { return mPtr; } + inline T * GetPtr() const { return mPtr; } /// INTERNAL HELPER FUNCTION USED BY SERIALIZATION void ** InternalGetPointer() { return reinterpret_cast(&mPtr); } @@ -160,7 +160,7 @@ public: inline ~RefConst() { Release(); } /// Assignment operators - inline RefConst & operator = (const T * inRHS) { if (mPtr != inRHS) { Release(); mPtr = inRHS; AddRef(); } return *this; } + inline RefConst & operator = (const T * inRHS) { if (mPtr != inRHS) { Release(); mPtr = inRHS; AddRef(); } return *this; } inline RefConst & operator = (const RefConst &inRHS) { if (mPtr != inRHS.mPtr) { Release(); mPtr = inRHS.mPtr; AddRef(); } return *this; } inline RefConst & operator = (RefConst &&inRHS) noexcept { if (mPtr != inRHS.mPtr) { Release(); mPtr = inRHS.mPtr; inRHS.mPtr = nullptr; } return *this; } inline RefConst & operator = (const Ref &inRHS) { if (mPtr != inRHS.mPtr) { Release(); mPtr = inRHS.mPtr; AddRef(); } return *this; } @@ -170,7 +170,7 @@ public: inline operator const T * () const { return mPtr; } /// Access like a normal pointer - inline const T * operator -> () const { return mPtr; } + inline const T * operator -> () const { return mPtr; } inline const T & operator * () const { return *mPtr; } /// Comparison @@ -182,7 +182,7 @@ public: inline bool operator != (const Ref &inRHS) const { return mPtr != inRHS.mPtr; } /// Get pointer - inline const T * GetPtr() const { return mPtr; } + inline const T * GetPtr() const { return mPtr; } /// INTERNAL HELPER FUNCTION USED BY SERIALIZATION void ** InternalGetPointer() { return const_cast(reinterpret_cast(&mPtr)); } diff --git a/WickedEngine/Jolt/Core/Result.h b/WickedEngine/Jolt/Core/Result.h index da3b98cb3..ad2eab164 100644 --- a/WickedEngine/Jolt/Core/Result.h +++ b/WickedEngine/Jolt/Core/Result.h @@ -6,9 +6,6 @@ JPH_NAMESPACE_BEGIN -// GCC doesn't properly detect that mState is used to ensure that mResult is initialized -JPH_GCC_SUPPRESS_WARNING("-Wmaybe-uninitialized") - /// Helper class that either contains a valid result or an error template class Result diff --git a/WickedEngine/Jolt/Core/STLAllocator.h b/WickedEngine/Jolt/Core/STLAllocator.h index 0e3ee459a..f9573279a 100644 --- a/WickedEngine/Jolt/Core/STLAllocator.h +++ b/WickedEngine/Jolt/Core/STLAllocator.h @@ -60,10 +60,10 @@ public: /// Reallocate memory template > - inline pointer reallocate(pointer inOldPointer, [[maybe_unused]] size_type inOldSize, size_type inNewSize) + inline pointer reallocate(pointer inOldPointer, size_type inOldSize, size_type inNewSize) { JPH_ASSERT(inNewSize > 0); // Reallocating to zero size is implementation dependent, so we don't allow it - return pointer(Reallocate(inOldPointer, inNewSize * sizeof(value_type))); + return pointer(Reallocate(inOldPointer, inOldSize * sizeof(value_type), inNewSize * sizeof(value_type))); } /// Free memory diff --git a/WickedEngine/Jolt/Core/StaticArray.h b/WickedEngine/Jolt/Core/StaticArray.h index 21a685c16..cff3824d2 100644 --- a/WickedEngine/Jolt/Core/StaticArray.h +++ b/WickedEngine/Jolt/Core/StaticArray.h @@ -26,8 +26,8 @@ public: explicit StaticArray(std::initializer_list inList) { JPH_ASSERT(inList.size() <= N); - for (typename std::initializer_list::iterator i = inList.begin(); i != inList.end(); ++i) - ::new (reinterpret_cast(&mElements[mSize++])) T(*i); + for (const T &v : inList) + ::new (reinterpret_cast(&mElements[mSize++])) T(v); } /// Copy constructor @@ -311,13 +311,13 @@ namespace std std::size_t ret = 0; // Hash length first - JPH::HashCombine(ret, inRHS.size()); + JPH::HashCombine(ret, inRHS.size()); // Then hash elements for (const T &t : inRHS) - JPH::HashCombine(ret, t); + JPH::HashCombine(ret, t); - return ret; + return ret; } }; } diff --git a/WickedEngine/Jolt/Core/StreamIn.h b/WickedEngine/Jolt/Core/StreamIn.h index d5f9f3673..4de299e6d 100644 --- a/WickedEngine/Jolt/Core/StreamIn.h +++ b/WickedEngine/Jolt/Core/StreamIn.h @@ -35,7 +35,7 @@ public: template , bool> = true> void Read(Array &outT) { - typename Array::size_type len = outT.size(); // Initialize to previous array size, this is used for validation in the StateRecorder class + uint32 len = uint32(outT.size()); // Initialize to previous array size, this is used for validation in the StateRecorder class Read(len); if (!IsEOF() && !IsFailed()) { @@ -60,7 +60,7 @@ public: template void Read(std::basic_string &outString) { - typename std::basic_string::size_type len = 0; + uint32 len = 0; Read(len); if (!IsEOF() && !IsFailed()) { @@ -75,7 +75,7 @@ public: template void Read(Array &outT, const F &inReadElement) { - typename Array::size_type len = outT.size(); // Initialize to previous array size, this is used for validation in the StateRecorder class + uint32 len = uint32(outT.size()); // Initialize to previous array size, this is used for validation in the StateRecorder class Read(len); if (!IsEOF() && !IsFailed()) { diff --git a/WickedEngine/Jolt/Core/StreamOut.h b/WickedEngine/Jolt/Core/StreamOut.h index d21bf3213..566f8ec8d 100644 --- a/WickedEngine/Jolt/Core/StreamOut.h +++ b/WickedEngine/Jolt/Core/StreamOut.h @@ -32,7 +32,7 @@ public: template , bool> = true> void Write(const Array &inT) { - typename Array::size_type len = inT.size(); + uint32 len = uint32(inT.size()); Write(len); if (!IsFailed()) { @@ -54,7 +54,7 @@ public: template void Write(const std::basic_string &inString) { - typename std::basic_string::size_type len = inString.size(); + uint32 len = uint32(inString.size()); Write(len); if (!IsFailed()) WriteBytes(inString.data(), len * sizeof(Type)); @@ -64,7 +64,7 @@ public: template void Write(const Array &inT, const F &inWriteElement) { - typename Array::size_type len = inT.size(); + uint32 len = uint32(inT.size()); Write(len); if (!IsFailed()) for (typename Array::size_type i = 0; i < len; ++i) diff --git a/WickedEngine/Jolt/Core/StreamUtils.h b/WickedEngine/Jolt/Core/StreamUtils.h index e374c5210..1feb232f3 100644 --- a/WickedEngine/Jolt/Core/StreamUtils.h +++ b/WickedEngine/Jolt/Core/StreamUtils.h @@ -126,7 +126,8 @@ Result> RestoreObjectReference(StreamIn &inStream, IDToObjectMap template void SaveObjectArray(StreamOut &inStream, const ArrayType &inArray, ObjectToIDMap *ioObjectToIDMap) { - inStream.Write(size_t(inArray.size())); + uint32 len = uint32(inArray.size()); + inStream.Write(len); for (const ValueType *value: inArray) SaveObjectReference(inStream, value, ioObjectToIDMap); } @@ -137,7 +138,7 @@ Result RestoreObjectArray(StreamIn &inStream, IDToObjectMap result; - size_t len; + uint32 len; inStream.Read(len); if (inStream.IsEOF() || inStream.IsFailed()) { diff --git a/WickedEngine/Jolt/Core/StringTools.h b/WickedEngine/Jolt/Core/StringTools.h index d3def9356..d7dc8b614 100644 --- a/WickedEngine/Jolt/Core/StringTools.h +++ b/WickedEngine/Jolt/Core/StringTools.h @@ -15,9 +15,9 @@ template String ConvertToString(const T &inValue) { using OStringStream = std::basic_ostringstream, STLAllocator>; - OStringStream oss; - oss << inValue; - return oss.str(); + OStringStream oss; + oss << inValue; + return oss.str(); } /// Calculate the FNV-1a hash of inString. diff --git a/WickedEngine/Jolt/Core/TempAllocator.h b/WickedEngine/Jolt/Core/TempAllocator.h index af0cf3137..99586bde6 100644 --- a/WickedEngine/Jolt/Core/TempAllocator.h +++ b/WickedEngine/Jolt/Core/TempAllocator.h @@ -86,16 +86,40 @@ public: } } - // Check if no allocations have been made + /// Check if no allocations have been made bool IsEmpty() const { return mTop == 0; } + /// Get the total size of the fixed buffer + uint GetSize() const + { + return mSize; + } + + /// Get current usage in bytes of the buffer + uint GetUsage() const + { + return mTop; + } + + /// Check if an allocation of inSize can be made in this fixed buffer allocator + bool CanAllocate(uint inSize) const + { + return mTop + AlignUp(inSize, JPH_RVECTOR_ALIGNMENT) <= mSize; + } + + /// Check if memory block at inAddress is owned by this allocator + bool OwnsMemory(const void *inAddress) const + { + return inAddress >= mBase && inAddress < mBase + mSize; + } + private: uint8 * mBase; ///< Base address of the memory block uint mSize; ///< Size of the memory block - uint mTop = 0; ///< Current top of the stack + uint mTop = 0; ///< End of currently allocated area }; /// Implementation of the TempAllocator that just falls back to malloc/free @@ -119,4 +143,46 @@ public: } }; +/// Implementation of the TempAllocator that tries to allocate from a large preallocated block, but falls back to malloc when it is exhausted +class JPH_EXPORT TempAllocatorImplWithMallocFallback final : public TempAllocator +{ +public: + JPH_OVERRIDE_NEW_DELETE + + /// Constructs the allocator with an initial fixed block if inSize + explicit TempAllocatorImplWithMallocFallback(uint inSize) : + mAllocator(inSize) + { + } + + // See: TempAllocator + virtual void * Allocate(uint inSize) override + { + if (mAllocator.CanAllocate(inSize)) + return mAllocator.Allocate(inSize); + else + return mFallbackAllocator.Allocate(inSize); + } + + // See: TempAllocator + virtual void Free(void *inAddress, uint inSize) override + { + if (inAddress == nullptr) + { + JPH_ASSERT(inSize == 0); + } + else + { + if (mAllocator.OwnsMemory(inAddress)) + mAllocator.Free(inAddress, inSize); + else + mFallbackAllocator.Free(inAddress, inSize); + } + } + +private: + TempAllocatorImpl mAllocator; + TempAllocatorMalloc mFallbackAllocator; +}; + JPH_NAMESPACE_END diff --git a/WickedEngine/Jolt/Geometry/ConvexHullBuilder.h b/WickedEngine/Jolt/Geometry/ConvexHullBuilder.h index 7a6aea8ca..db1ef358d 100644 --- a/WickedEngine/Jolt/Geometry/ConvexHullBuilder.h +++ b/WickedEngine/Jolt/Geometry/ConvexHullBuilder.h @@ -255,7 +255,7 @@ private: #endif const Positions & mPositions; ///< List of positions (some of them are part of the hull) - Faces mFaces; ///< List of faces that are part of the hull (if !mRemoved) + Faces mFaces; ///< List of faces that are part of the hull (if !mRemoved) struct Coplanar { diff --git a/WickedEngine/Jolt/Geometry/EPAConvexHullBuilder.h b/WickedEngine/Jolt/Geometry/EPAConvexHullBuilder.h index 45571cc97..8caabc4b1 100644 --- a/WickedEngine/Jolt/Geometry/EPAConvexHullBuilder.h +++ b/WickedEngine/Jolt/Geometry/EPAConvexHullBuilder.h @@ -692,9 +692,9 @@ public: #endif private: - TriangleFactory mFactory; ///< Factory to create new triangles and remove old ones + TriangleFactory mFactory; ///< Factory to create new triangles and remove old ones const Points & mPositions; ///< List of positions (some of them are part of the hull) - TriangleQueue mTriangleQueue; ///< List of triangles that are part of the hull that still need to be checked (if !mRemoved) + TriangleQueue mTriangleQueue; ///< List of triangles that are part of the hull that still need to be checked (if !mRemoved) #if defined(JPH_EPA_CONVEX_BUILDER_VALIDATE) || defined(JPH_EPA_CONVEX_BUILDER_DRAW) Triangles mTriangles; ///< The list of all triangles in this hull (for debug purposes) diff --git a/WickedEngine/Jolt/Geometry/GJKClosestPoint.h b/WickedEngine/Jolt/Geometry/GJKClosestPoint.h index d4bfbf40c..e5f49b65a 100644 --- a/WickedEngine/Jolt/Geometry/GJKClosestPoint.h +++ b/WickedEngine/Jolt/Geometry/GJKClosestPoint.h @@ -73,7 +73,7 @@ private: } #ifdef JPH_GJK_DEBUG - Trace("GetClosest: set = 0b%s, v = [%s], |v| = %g", NibbleToBinary(set), ConvertToString(v).c_str(), (double)v.Length()); + Trace("GetClosest: set = 0b%s, v = [%s], |v| = %g", NibbleToBinary(set), ConvertToString(v).c_str(), (double)v.Length()); #endif float v_len_sq = v.LengthSq(); @@ -115,10 +115,6 @@ private: mNumPoints = num_points; } - // GCC 11.3 thinks the assignments to mP, mQ and mY below may use uninitialized variables - JPH_SUPPRESS_WARNING_PUSH - JPH_GCC_SUPPRESS_WARNING("-Wmaybe-uninitialized") - // Remove points that are not in the set, only updates mP void UpdatePointSetP(uint32 inSet) { @@ -161,8 +157,6 @@ private: mNumPoints = num_points; } - JPH_SUPPRESS_WARNING_POP - // Calculate closest points on A and B void CalculatePointAAndB(Vec3 &outPointA, Vec3 &outPointB) const { diff --git a/WickedEngine/Jolt/Geometry/Sphere.h b/WickedEngine/Jolt/Geometry/Sphere.h index c9aa0b3e2..05f7dd14f 100644 --- a/WickedEngine/Jolt/Geometry/Sphere.h +++ b/WickedEngine/Jolt/Geometry/Sphere.h @@ -26,7 +26,7 @@ public: } // Properties - inline Vec3 GetCenter() const { return Vec3::sLoadFloat3Unsafe(mCenter); } + inline Vec3 GetCenter() const { return Vec3::sLoadFloat3Unsafe(mCenter); } inline float GetRadius() const { return mRadius; } /// Test if two spheres overlap diff --git a/WickedEngine/Jolt/Jolt.cmake b/WickedEngine/Jolt/Jolt.cmake index b0336a191..78a4149a7 100644 --- a/WickedEngine/Jolt/Jolt.cmake +++ b/WickedEngine/Jolt/Jolt.cmake @@ -499,7 +499,14 @@ endif() target_include_directories(Jolt PUBLIC $ $) -target_precompile_headers(Jolt PRIVATE ${JOLT_PHYSICS_ROOT}/Jolt.h) + +# Code coverage doesn't work when using precompiled headers +target_precompile_headers(Jolt PRIVATE "$<$>:${JOLT_PHYSICS_ROOT}/Jolt.h>") + +if (NOT CPP_EXCEPTIONS_ENABLED) + # Disable use of exceptions in MSVC's STL + target_compile_definitions(Jolt PUBLIC $<$:_HAS_EXCEPTIONS=0>) +endif() # Set the debug/non-debug build flags target_compile_definitions(Jolt PUBLIC "$<$:_DEBUG>") @@ -619,12 +626,19 @@ else() # XCode builds for multiple architectures, we can't set global flags elseif (CROSS_COMPILE_ARM OR CMAKE_OSX_ARCHITECTURES MATCHES "arm64" OR "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "aarch64") # ARM64 uses no special commandline flags + elseif (EMSCRIPTEN) + if (USE_WASM_SIMD) + # Jolt currently doesn't implement the WASM specific SIMD intrinsics so uses the SSE 4.2 intrinsics + # See: https://emscripten.org/docs/porting/simd.html#webassembly-simd-intrinsics + # Note that this does not require the browser to actually support SSE 4.2 it merely means that it can translate those instructions to WASM SIMD instructions + target_compile_options(Jolt PUBLIC -msimd128 -msse4.2) + endif() elseif ("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64" OR "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "AMD64" OR "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86" OR "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "i386") # x86 and x86_64 - # On 32-bit builds we need to default to using SSE instructions, the x87 FPU instructions have higher intermediate precision + # On 32-bit builds we need to default to using SSE instructions, the x87 FPU instructions have higher intermediate precision # which will cause problems in the collision detection code (the effect is similar to leaving FMA on, search for # JPH_PRECISE_MATH_ON for the locations where this is a problem). - + if (USE_AVX512) target_compile_options(Jolt PUBLIC -mavx512f -mavx512vl -mavx512dq -mavx2 -mbmi -mpopcnt -mlzcnt -mf16c) elseif (USE_AVX2) @@ -658,3 +672,14 @@ else() EMIT_X86_INSTRUCTION_SET_DEFINITIONS() endif() endif() + +# On Unix flavors we need the pthread library +if (NOT ("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows") AND NOT EMSCRIPTEN) + target_compile_options(Jolt PUBLIC -pthread) +endif() + +if (EMSCRIPTEN) + # We need more than the default 64KB stack and 16MB memory + # Also disable warning: running limited binaryen optimizations because DWARF info requested (or indirectly required) + target_link_options(Jolt PUBLIC -sSTACK_SIZE=1048576 -sINITIAL_MEMORY=134217728 -Wno-limited-postlink-optimizations) +endif() diff --git a/WickedEngine/Jolt/Math/DVec3.h b/WickedEngine/Jolt/Math/DVec3.h index 58e0a06f3..68946d4b5 100644 --- a/WickedEngine/Jolt/Math/DVec3.h +++ b/WickedEngine/Jolt/Math/DVec3.h @@ -73,7 +73,7 @@ public: /// Prepare to convert to float vector 3 rounding towards zero (returns DVec3 that can be converted to a Vec3 to get the rounding) JPH_INLINE DVec3 PrepareRoundToZero() const; - /// Prepare to convert to float vector 3 rounding towards positive/negative inf (returns DVec3 that can be converted to a Vec3 to get the rounding) + /// Prepare to convert to float vector 3 rounding towards positive/negative inf (returns DVec3 that can be converted to a Vec3 to get the rounding) JPH_INLINE DVec3 PrepareRoundToInf() const; /// Convert to float vector 3 rounding down diff --git a/WickedEngine/Jolt/Math/DVec3.inl b/WickedEngine/Jolt/Math/DVec3.inl index 5b7603e69..64ed35a41 100644 --- a/WickedEngine/Jolt/Math/DVec3.inl +++ b/WickedEngine/Jolt/Math/DVec3.inl @@ -44,7 +44,7 @@ DVec3::DVec3(double inX, double inY, double inZ) mValue.mLow = _mm_set_pd(inY, inX); mValue.mHigh = _mm_set1_pd(inZ); #elif defined(JPH_USE_NEON) - mValue.val[0] = vcombine_f64(vcreate_f64(*reinterpret_cast(&inX)), vcreate_f64(*reinterpret_cast(&inY))); + mValue.val[0] = vcombine_f64(vcreate_f64(BitCast(inX)), vcreate_f64(BitCast(inY))); mValue.val[1] = vdupq_n_f64(inZ); #else mF64[0] = inX; @@ -232,7 +232,7 @@ DVec3 DVec3::sEquals(DVec3Arg inV1, DVec3Arg inV2) #elif defined(JPH_USE_SSE) return DVec3({ _mm_cmpeq_pd(inV1.mValue.mLow, inV2.mValue.mLow), _mm_cmpeq_pd(inV1.mValue.mHigh, inV2.mValue.mHigh) }); #elif defined(JPH_USE_NEON) - return DVec3({ vreinterpretq_u64_f64(vceqq_f64(inV1.mValue.val[0], inV2.mValue.val[0])), vreinterpretq_u64_f64(vceqq_f64(inV1.mValue.val[1], inV2.mValue.val[1])) }); + return DVec3({ vreinterpretq_f64_u64(vceqq_f64(inV1.mValue.val[0], inV2.mValue.val[0])), vreinterpretq_f64_u64(vceqq_f64(inV1.mValue.val[1], inV2.mValue.val[1])) }); #else return DVec3(inV1.mF64[0] == inV2.mF64[0]? cTrue : cFalse, inV1.mF64[1] == inV2.mF64[1]? cTrue : cFalse, @@ -247,7 +247,7 @@ DVec3 DVec3::sLess(DVec3Arg inV1, DVec3Arg inV2) #elif defined(JPH_USE_SSE) return DVec3({ _mm_cmplt_pd(inV1.mValue.mLow, inV2.mValue.mLow), _mm_cmplt_pd(inV1.mValue.mHigh, inV2.mValue.mHigh) }); #elif defined(JPH_USE_NEON) - return DVec3({ vreinterpretq_u64_f64(vcltq_f64(inV1.mValue.val[0], inV2.mValue.val[0])), vreinterpretq_u64_f64(vcltq_f64(inV1.mValue.val[1], inV2.mValue.val[1])) }); + return DVec3({ vreinterpretq_f64_u64(vcltq_f64(inV1.mValue.val[0], inV2.mValue.val[0])), vreinterpretq_f64_u64(vcltq_f64(inV1.mValue.val[1], inV2.mValue.val[1])) }); #else return DVec3(inV1.mF64[0] < inV2.mF64[0]? cTrue : cFalse, inV1.mF64[1] < inV2.mF64[1]? cTrue : cFalse, @@ -262,7 +262,7 @@ DVec3 DVec3::sLessOrEqual(DVec3Arg inV1, DVec3Arg inV2) #elif defined(JPH_USE_SSE) return DVec3({ _mm_cmple_pd(inV1.mValue.mLow, inV2.mValue.mLow), _mm_cmple_pd(inV1.mValue.mHigh, inV2.mValue.mHigh) }); #elif defined(JPH_USE_NEON) - return DVec3({ vreinterpretq_u64_f64(vcleq_f64(inV1.mValue.val[0], inV2.mValue.val[0])), vreinterpretq_u64_f64(vcleq_f64(inV1.mValue.val[1], inV2.mValue.val[1])) }); + return DVec3({ vreinterpretq_f64_u64(vcleq_f64(inV1.mValue.val[0], inV2.mValue.val[0])), vreinterpretq_f64_u64(vcleq_f64(inV1.mValue.val[1], inV2.mValue.val[1])) }); #else return DVec3(inV1.mF64[0] <= inV2.mF64[0]? cTrue : cFalse, inV1.mF64[1] <= inV2.mF64[1]? cTrue : cFalse, @@ -277,7 +277,7 @@ DVec3 DVec3::sGreater(DVec3Arg inV1, DVec3Arg inV2) #elif defined(JPH_USE_SSE) return DVec3({ _mm_cmpgt_pd(inV1.mValue.mLow, inV2.mValue.mLow), _mm_cmpgt_pd(inV1.mValue.mHigh, inV2.mValue.mHigh) }); #elif defined(JPH_USE_NEON) - return DVec3({ vreinterpretq_u64_f64(vcgtq_f64(inV1.mValue.val[0], inV2.mValue.val[0])), vreinterpretq_u64_f64(vcgtq_f64(inV1.mValue.val[1], inV2.mValue.val[1])) }); + return DVec3({ vreinterpretq_f64_u64(vcgtq_f64(inV1.mValue.val[0], inV2.mValue.val[0])), vreinterpretq_f64_u64(vcgtq_f64(inV1.mValue.val[1], inV2.mValue.val[1])) }); #else return DVec3(inV1.mF64[0] > inV2.mF64[0]? cTrue : cFalse, inV1.mF64[1] > inV2.mF64[1]? cTrue : cFalse, @@ -292,7 +292,7 @@ DVec3 DVec3::sGreaterOrEqual(DVec3Arg inV1, DVec3Arg inV2) #elif defined(JPH_USE_SSE) return DVec3({ _mm_cmpge_pd(inV1.mValue.mLow, inV2.mValue.mLow), _mm_cmpge_pd(inV1.mValue.mHigh, inV2.mValue.mHigh) }); #elif defined(JPH_USE_NEON) - return DVec3({ vreinterpretq_u64_f64(vcgeq_f64(inV1.mValue.val[0], inV2.mValue.val[0])), vreinterpretq_u64_f64(vcgeq_f64(inV1.mValue.val[1], inV2.mValue.val[1])) }); + return DVec3({ vreinterpretq_f64_u64(vcgeq_f64(inV1.mValue.val[0], inV2.mValue.val[0])), vreinterpretq_f64_u64(vcgeq_f64(inV1.mValue.val[1], inV2.mValue.val[1])) }); #else return DVec3(inV1.mF64[0] >= inV2.mF64[0]? cTrue : cFalse, inV1.mF64[1] >= inV2.mF64[1]? cTrue : cFalse, @@ -323,7 +323,8 @@ DVec3 DVec3::sSelect(DVec3Arg inV1, DVec3Arg inV2, DVec3Arg inControl) Type v = { _mm_blendv_pd(inV1.mValue.mLow, inV2.mValue.mLow, inControl.mValue.mLow), _mm_blendv_pd(inV1.mValue.mHigh, inV2.mValue.mHigh, inControl.mValue.mHigh) }; return sFixW(v); #elif defined(JPH_USE_NEON) - Type v = { vbslq_f64(vshrq_n_s64(inControl.mValue.val[0], 63), inV2.mValue.val[0], inV1.mValue.val[0]), vbslq_f64(vshrq_n_s64(inControl.mValue.val[1], 63), inV2.mValue.val[1], inV1.mValue.val[1]) }; + Type v = { vbslq_f64(vreinterpretq_u64_s64(vshrq_n_s64(vreinterpretq_s64_f64(inControl.mValue.val[0]), 63)), inV2.mValue.val[0], inV1.mValue.val[0]), + vbslq_f64(vreinterpretq_u64_s64(vshrq_n_s64(vreinterpretq_s64_f64(inControl.mValue.val[1]), 63)), inV2.mValue.val[1], inV1.mValue.val[1]) }; return sFixW(v); #else DVec3 result; @@ -343,7 +344,8 @@ DVec3 DVec3::sOr(DVec3Arg inV1, DVec3Arg inV2) #elif defined(JPH_USE_SSE) return DVec3({ _mm_or_pd(inV1.mValue.mLow, inV2.mValue.mLow), _mm_or_pd(inV1.mValue.mHigh, inV2.mValue.mHigh) }); #elif defined(JPH_USE_NEON) - return DVec3({ vorrq_s64(inV1.mValue.val[0], inV2.mValue.val[0]), vorrq_s64(inV1.mValue.val[1], inV2.mValue.val[1]) }); + return DVec3({ vreinterpretq_f64_u64(vorrq_u64(vreinterpretq_u64_f64(inV1.mValue.val[0]), vreinterpretq_u64_f64(inV2.mValue.val[0]))), + vreinterpretq_f64_u64(vorrq_u64(vreinterpretq_u64_f64(inV1.mValue.val[1]), vreinterpretq_u64_f64(inV2.mValue.val[1]))) }); #else return DVec3(BitCast(BitCast(inV1.mF64[0]) | BitCast(inV2.mF64[0])), BitCast(BitCast(inV1.mF64[1]) | BitCast(inV2.mF64[1])), @@ -358,7 +360,8 @@ DVec3 DVec3::sXor(DVec3Arg inV1, DVec3Arg inV2) #elif defined(JPH_USE_SSE) return DVec3({ _mm_xor_pd(inV1.mValue.mLow, inV2.mValue.mLow), _mm_xor_pd(inV1.mValue.mHigh, inV2.mValue.mHigh) }); #elif defined(JPH_USE_NEON) - return DVec3({ veorq_s64(inV1.mValue.val[0], inV2.mValue.val[0]), veorq_s64(inV1.mValue.val[1], inV2.mValue.val[1]) }); + return DVec3({ vreinterpretq_f64_u64(veorq_u64(vreinterpretq_u64_f64(inV1.mValue.val[0]), vreinterpretq_u64_f64(inV2.mValue.val[0]))), + vreinterpretq_f64_u64(veorq_u64(vreinterpretq_u64_f64(inV1.mValue.val[1]), vreinterpretq_u64_f64(inV2.mValue.val[1]))) }); #else return DVec3(BitCast(BitCast(inV1.mF64[0]) ^ BitCast(inV2.mF64[0])), BitCast(BitCast(inV1.mF64[1]) ^ BitCast(inV2.mF64[1])), @@ -373,7 +376,8 @@ DVec3 DVec3::sAnd(DVec3Arg inV1, DVec3Arg inV2) #elif defined(JPH_USE_SSE) return DVec3({ _mm_and_pd(inV1.mValue.mLow, inV2.mValue.mLow), _mm_and_pd(inV1.mValue.mHigh, inV2.mValue.mHigh) }); #elif defined(JPH_USE_NEON) - return DVec3({ vandq_s64(inV1.mValue.val[0], inV2.mValue.val[0]), vandq_s64(inV1.mValue.val[1], inV2.mValue.val[1]) }); + return DVec3({ vreinterpretq_f64_u64(vandq_u64(vreinterpretq_u64_f64(inV1.mValue.val[0]), vreinterpretq_u64_f64(inV2.mValue.val[0]))), + vreinterpretq_f64_u64(vandq_u64(vreinterpretq_u64_f64(inV1.mValue.val[1]), vreinterpretq_u64_f64(inV2.mValue.val[1]))) }); #else return DVec3(BitCast(BitCast(inV1.mF64[0]) & BitCast(inV2.mF64[0])), BitCast(BitCast(inV1.mF64[1]) & BitCast(inV2.mF64[1])), @@ -730,11 +734,11 @@ DVec3 DVec3::Cross(DVec3Arg inV2) const { #if defined(JPH_USE_AVX2) __m256d t1 = _mm256_permute4x64_pd(inV2.mValue, _MM_SHUFFLE(0, 0, 2, 1)); // Assure Z and W are the same - t1 = _mm256_mul_pd(t1, mValue); - __m256d t2 = _mm256_permute4x64_pd(mValue, _MM_SHUFFLE(0, 0, 2, 1)); // Assure Z and W are the same - t2 = _mm256_mul_pd(t2, inV2.mValue); - __m256d t3 = _mm256_sub_pd(t1, t2); - return _mm256_permute4x64_pd(t3, _MM_SHUFFLE(0, 0, 2, 1)); // Assure Z and W are the same + t1 = _mm256_mul_pd(t1, mValue); + __m256d t2 = _mm256_permute4x64_pd(mValue, _MM_SHUFFLE(0, 0, 2, 1)); // Assure Z and W are the same + t2 = _mm256_mul_pd(t2, inV2.mValue); + __m256d t3 = _mm256_sub_pd(t1, t2); + return _mm256_permute4x64_pd(t3, _MM_SHUFFLE(0, 0, 2, 1)); // Assure Z and W are the same #else return DVec3(mF64[1] * inV2.mF64[2] - mF64[2] * inV2.mF64[1], mF64[2] * inV2.mF64[0] - mF64[0] * inV2.mF64[2], @@ -746,10 +750,10 @@ double DVec3::Dot(DVec3Arg inV2) const { #if defined(JPH_USE_AVX) __m256d mul = _mm256_mul_pd(mValue, inV2.mValue); - __m128d xy = _mm256_castpd256_pd128(mul); + __m128d xy = _mm256_castpd256_pd128(mul); __m128d yx = _mm_shuffle_pd(xy, xy, 1); __m128d sum = _mm_add_pd(xy, yx); - __m128d zw = _mm256_extractf128_pd(mul, 1); + __m128d zw = _mm256_extractf128_pd(mul, 1); sum = _mm_add_pd(sum, zw); return _mm_cvtsd_f64(sum); #elif defined(JPH_USE_SSE) @@ -760,9 +764,9 @@ double DVec3::Dot(DVec3Arg inV2) const sum = _mm_add_pd(sum, z); return _mm_cvtsd_f64(sum); #elif defined(JPH_USE_NEON) - float64x2_t mul_low = vmulq_f64(mValue.val[0], inV2.mValue.val[0]); - float64x2_t mul_high = vmulq_f64(mValue.val[1], inV2.mValue.val[1]); - return vaddvq_f64(mul_low) + vgetq_lane_f64(mul_high, 0); + float64x2_t mul_low = vmulq_f64(mValue.val[0], inV2.mValue.val[0]); + float64x2_t mul_high = vmulq_f64(mValue.val[1], inV2.mValue.val[1]); + return vaddvq_f64(mul_low) + vgetq_lane_f64(mul_high, 0); #else double dot = 0.0; for (int i = 0; i < 3; i++) @@ -830,9 +834,10 @@ DVec3 DVec3::GetSign() const __m128d one = _mm_set1_pd(1.0); return DVec3({ _mm_or_pd(_mm_and_pd(mValue.mLow, minus_one), one), _mm_or_pd(_mm_and_pd(mValue.mHigh, minus_one), one) }); #elif defined(JPH_USE_NEON) - float64x2_t minus_one = vdupq_n_f64(-1.0f); - float64x2_t one = vdupq_n_f64(1.0f); - return DVec3({ vorrq_s64(vandq_s64(mValue.val[0], minus_one), one), vorrq_s64(vandq_s64(mValue.val[1], minus_one), one) }); + uint64x2_t minus_one = vreinterpretq_u64_f64(vdupq_n_f64(-1.0f)); + uint64x2_t one = vreinterpretq_u64_f64(vdupq_n_f64(1.0f)); + return DVec3({ vreinterpretq_f64_u64(vorrq_u64(vandq_u64(vreinterpretq_u64_f64(mValue.val[0]), minus_one), one)), + vreinterpretq_f64_u64(vorrq_u64(vandq_u64(vreinterpretq_u64_f64(mValue.val[1]), minus_one), one)) }); #else return DVec3(std::signbit(mF64[0])? -1.0 : 1.0, std::signbit(mF64[1])? -1.0 : 1.0, @@ -851,8 +856,9 @@ DVec3 DVec3::PrepareRoundToZero() const __m128d mask = _mm_castsi128_pd(_mm_set1_epi64x(int64_t(~cDoubleToFloatMantissaLoss))); return DVec3({ _mm_and_pd(mValue.mLow, mask), _mm_and_pd(mValue.mHigh, mask) }); #elif defined(JPH_USE_NEON) - float64x2_t mask = vreinterpretq_f64_u64(vdupq_n_u64(~cDoubleToFloatMantissaLoss)); - return DVec3({ vandq_s64(mValue.val[0], mask), vandq_s64(mValue.val[1], mask) }); + uint64x2_t mask = vdupq_n_u64(~cDoubleToFloatMantissaLoss); + return DVec3({ vreinterpretq_f64_u64(vandq_u64(vreinterpretq_u64_f64(mValue.val[0]), mask)), + vreinterpretq_f64_u64(vandq_u64(vreinterpretq_u64_f64(mValue.val[1]), mask)) }); #else double x = BitCast(BitCast(mF64[0]) & ~cDoubleToFloatMantissaLoss); double y = BitCast(BitCast(mF64[1]) & ~cDoubleToFloatMantissaLoss); @@ -889,15 +895,15 @@ DVec3 DVec3::PrepareRoundToInf() const __m128d value_or_mantissa_loss_high = _mm_or_pd(mValue.mHigh, _mm_castsi128_pd(mantissa_loss)); return DVec3({ _mm_blendv_pd(value_or_mantissa_loss_low, mValue.mLow, is_zero_low), _mm_blendv_pd(value_or_mantissa_loss_high, mValue.mHigh, is_zero_high) }); #elif defined(JPH_USE_NEON) - float64x2_t mantissa_loss = vreinterpretq_f64_u64(vdupq_n_u64(cDoubleToFloatMantissaLoss)); + uint64x2_t mantissa_loss = vdupq_n_u64(cDoubleToFloatMantissaLoss); float64x2_t zero = vdupq_n_f64(0.0); - float64x2_t value_and_mantissa_loss_low = vandq_s64(mValue.val[0], mantissa_loss); - float64x2_t is_zero_low = vceqq_f64(value_and_mantissa_loss_low, zero); - float64x2_t value_or_mantissa_loss_low = vorrq_s64(mValue.val[0], mantissa_loss); - float64x2_t value_and_mantissa_loss_high = vandq_s64(mValue.val[1], mantissa_loss); + float64x2_t value_and_mantissa_loss_low = vreinterpretq_f64_u64(vandq_u64(vreinterpretq_u64_f64(mValue.val[0]), mantissa_loss)); + uint64x2_t is_zero_low = vceqq_f64(value_and_mantissa_loss_low, zero); + float64x2_t value_or_mantissa_loss_low = vreinterpretq_f64_u64(vorrq_u64(vreinterpretq_u64_f64(mValue.val[0]), mantissa_loss)); + float64x2_t value_and_mantissa_loss_high = vreinterpretq_f64_u64(vandq_u64(vreinterpretq_u64_f64(mValue.val[1]), mantissa_loss)); float64x2_t value_low = vbslq_f64(is_zero_low, mValue.val[0], value_or_mantissa_loss_low); - float64x2_t is_zero_high = vceqq_f64(value_and_mantissa_loss_high, zero); - float64x2_t value_or_mantissa_loss_high = vorrq_s64(mValue.val[1], mantissa_loss); + uint64x2_t is_zero_high = vceqq_f64(value_and_mantissa_loss_high, zero); + float64x2_t value_or_mantissa_loss_high = vreinterpretq_f64_u64(vorrq_u64(vreinterpretq_u64_f64(mValue.val[1]), mantissa_loss)); float64x2_t value_high = vbslq_f64(is_zero_high, mValue.val[1], value_or_mantissa_loss_high); return DVec3({ value_low, value_high }); #else diff --git a/WickedEngine/Jolt/Math/EigenValueSymmetric.h b/WickedEngine/Jolt/Math/EigenValueSymmetric.h index 43436ee96..920ddb9c9 100644 --- a/WickedEngine/Jolt/Math/EigenValueSymmetric.h +++ b/WickedEngine/Jolt/Math/EigenValueSymmetric.h @@ -4,7 +4,7 @@ #pragma once -#include +#include JPH_NAMESPACE_BEGIN @@ -28,9 +28,9 @@ JPH_NAMESPACE_BEGIN template bool EigenValueSymmetric(const Matrix &inMatrix, Matrix &outEigVec, Vector &outEigVal) { - // This algorithm works with very small numbers and can trigger invalid float exceptions when not flushing denormals - FPFlushDenormals flush_denormals; - (void)flush_denormals; + // This algorithm can generate infinite values, see comment below + FPExceptionDisableInvalid disable_invalid; + (void)disable_invalid; // Maximum number of sweeps to make const int cMaxSweeps = 50; @@ -70,9 +70,10 @@ bool EigenValueSymmetric(const Matrix &inMatrix, Matrix &outEigVec, Vector &outE for (uint ip = 0; ip < n - 1; ++ip) for (uint iq = ip + 1; iq < n; ++iq) sm += abs(a(ip, iq)); + float avg_sm = sm / Square(n); // Normal return, convergence to machine underflow - if (sm == 0.0f) + if (avg_sm < FLT_MIN) // Original code: sm == 0.0f, when the average is denormal, we also consider it machine underflow { // Sanity checks #ifdef JPH_ENABLE_ASSERTS @@ -93,68 +94,69 @@ 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 - float tresh = sweep < 4? 0.2f * sm / Square(n) : 0.0f; + // 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 for (uint ip = 0; ip < n - 1; ++ip) for (uint iq = ip + 1; iq < n; ++iq) { - float g = 100.0f * abs(a(ip, iq)); + float &a_pq = a(ip, iq); + float &eigval_p = outEigVal[ip]; + float &eigval_q = outEigVal[iq]; + + float abs_a_pq = abs(a_pq); + float g = 100.0f * abs_a_pq; // After four sweeps, skip the rotation if the off-diagonal element is small if (sweep > 4 - && abs(outEigVal[ip]) + g == abs(outEigVal[ip]) - && abs(outEigVal[iq]) + g == abs(outEigVal[iq])) + && abs(eigval_p) + g == abs(eigval_p) + && abs(eigval_q) + g == abs(eigval_q)) { - a(ip, iq) = 0.0f; + a_pq = 0.0f; } - else if (abs(a(ip, iq)) > tresh) + else if (abs_a_pq > tresh) { - float h = outEigVal[iq] - outEigVal[ip]; + float h = eigval_q - eigval_p; + float abs_h = abs(h); float t; - if (abs(h) + g == abs(h)) + if (abs_h + g == abs_h) { - t = a(ip, iq) / h; + t = a_pq / h; } else { - float theta = 0.5f * h / a(ip, iq); // Warning: Can become inf if a(ip, iq) too small - t = 1.0f / (abs(theta) + sqrt(1.0f + theta * theta)); // Warning: Squaring large value can make it inf + float theta = 0.5f * h / a_pq; // Warning: Can become infinite if a(ip, iq) is very small which may trigger an invalid float exception + t = 1.0f / (abs(theta) + sqrt(1.0f + theta * theta)); // If theta becomes inf, t will be 0 so the infinite is not a problem for the algorithm if (theta < 0.0f) t = -t; } float c = 1.0f / sqrt(1.0f + t * t); float s = t * c; float tau = s / (1.0f + c); - h = t * a(ip, iq); + h = t * a_pq; - a(ip, iq) = 0.0f; + a_pq = 0.0f; - // !Modification from Numerical Recipes! - // h can become infinite due to numerical overflow, this only happens when a(ip, iq) is very small - // so we can safely set a(ip, iq) to zero and skip the rotation, see lines marked with 'Warning' above. - if (!isnan(h)) - { - z[ip] -= h; - z[iq] += h; + z[ip] -= h; + z[iq] += h; - outEigVal[ip] -= h; - outEigVal[iq] += h; + eigval_p -= h; + eigval_q += h; - #define JPH_EVS_ROTATE(a, i, j, k, l) \ - g = a(i, j), \ - h = a(k, l), \ - a(i, j) = g - s * (h + g * tau), \ - a(k, l) = h + s * (g - h * tau) + #define JPH_EVS_ROTATE(a, i, j, k, l) \ + g = a(i, j), \ + h = a(k, l), \ + a(i, j) = g - s * (h + g * tau), \ + a(k, l) = h + s * (g - h * tau) - uint j; - for (j = 0; j < ip; ++j) JPH_EVS_ROTATE(a, j, ip, j, iq); - for (j = ip + 1; j < iq; ++j) JPH_EVS_ROTATE(a, ip, j, j, iq); - for (j = iq + 1; j < n; ++j) JPH_EVS_ROTATE(a, ip, j, iq, j); - for (j = 0; j < n; ++j) JPH_EVS_ROTATE(outEigVec, j, ip, j, iq); + uint j; + for (j = 0; j < ip; ++j) JPH_EVS_ROTATE(a, j, ip, j, iq); + for (j = ip + 1; j < iq; ++j) JPH_EVS_ROTATE(a, ip, j, j, iq); + for (j = iq + 1; j < n; ++j) JPH_EVS_ROTATE(a, ip, j, iq, j); + for (j = 0; j < n; ++j) JPH_EVS_ROTATE(outEigVec, j, ip, j, iq); - #undef JPH_EVS_ROTATE - } + #undef JPH_EVS_ROTATE } } diff --git a/WickedEngine/Jolt/Math/HalfFloat.h b/WickedEngine/Jolt/Math/HalfFloat.h index d28071e30..5b36cb095 100644 --- a/WickedEngine/Jolt/Math/HalfFloat.h +++ b/WickedEngine/Jolt/Math/HalfFloat.h @@ -193,7 +193,7 @@ JPH_INLINE Vec4 ToFloat(UVec4Arg inValue) #if defined(JPH_USE_F16C) return _mm_cvtph_ps(inValue.mValue); #elif defined(JPH_USE_NEON) - return vcvt_f32_f16(vreinterpret_f16_f32(vget_low_f32(inValue.mValue))); + return vcvt_f32_f16(vreinterpret_f16_u32(vget_low_u32(inValue.mValue))); #else return ToFloatFallback(inValue); #endif diff --git a/WickedEngine/Jolt/Math/Math.h b/WickedEngine/Jolt/Math/Math.h index ffb72f7c0..729d5403e 100644 --- a/WickedEngine/Jolt/Math/Math.h +++ b/WickedEngine/Jolt/Math/Math.h @@ -116,7 +116,9 @@ inline uint CountTrailingZeros(uint32 inValue) _BitScanForward(&result, inValue); return result; #else - return __builtin_clz(__builtin_bitreverse32(inValue)); + if (inValue == 0) + return 32; + return __builtin_ctz(inValue); #endif #elif defined(JPH_CPU_E2K) return inValue ? __builtin_ctz(inValue) : 32; diff --git a/WickedEngine/Jolt/Math/Quat.h b/WickedEngine/Jolt/Math/Quat.h index 10564cab1..6ce11c831 100644 --- a/WickedEngine/Jolt/Math/Quat.h +++ b/WickedEngine/Jolt/Math/Quat.h @@ -81,7 +81,7 @@ public: JPH_INLINE Vec3 GetXYZ() const { return Vec3(mValue); } /// Get the quaternion as a Vec4 - JPH_INLINE Vec4 GetXYZW() const { return mValue; } + JPH_INLINE Vec4 GetXYZW() const { return mValue; } /// Set individual components JPH_INLINE void SetX(float inX) { mValue.SetX(inX); } diff --git a/WickedEngine/Jolt/Math/Quat.inl b/WickedEngine/Jolt/Math/Quat.inl index 72b78341b..201481929 100644 --- a/WickedEngine/Jolt/Math/Quat.inl +++ b/WickedEngine/Jolt/Math/Quat.inl @@ -73,11 +73,11 @@ Quat Quat::operator * (QuatArg inRHS) const Quat Quat::sRotation(Vec3Arg inAxis, float inAngle) { - // returns [inAxis * sin(0.5f * inAngle), cos(0.5f * inAngle)] + // returns [inAxis * sin(0.5f * inAngle), cos(0.5f * inAngle)] JPH_ASSERT(inAxis.IsNormalized()); Vec4 s, c; Vec4::sReplicate(0.5f * inAngle).SinCos(s, c); - return Quat(Vec4::sSelect(Vec4(inAxis) * s, c, UVec4(0, 0, 0, 0xffffffffU))); + return Quat(Vec4::sSelect(Vec4(inAxis) * s, c, UVec4(0, 0, 0, 0xffffffffU))); } void Quat::GetAxisAngle(Vec3 &outAxis, float &outAngle) const @@ -237,12 +237,12 @@ Quat Quat::LERP(QuatArg inDestination, float inFraction) const Quat Quat::SLERP(QuatArg inDestination, float inFraction) const { - // Difference at which to LERP instead of SLERP + // Difference at which to LERP instead of SLERP const float delta = 0.0001f; // Calc cosine float sign_scale1 = 1.0f; - float cos_omega = Dot(inDestination); + float cos_omega = Dot(inDestination); // Adjust signs (if necessary) if (cos_omega < 0.0f) diff --git a/WickedEngine/Jolt/Math/Real.h b/WickedEngine/Jolt/Math/Real.h index 7773abf7e..ca8cf5049 100644 --- a/WickedEngine/Jolt/Math/Real.h +++ b/WickedEngine/Jolt/Math/Real.h @@ -26,7 +26,7 @@ using RMat44Arg = DMat44Arg; // Define real to float using Real = float; using Real3 = Float3; -using RVec3 = Vec3; +using RVec3 = Vec3; using RVec3Arg = Vec3Arg; using RMat44 = Mat44; using RMat44Arg = Mat44Arg; diff --git a/WickedEngine/Jolt/Math/UVec4.inl b/WickedEngine/Jolt/Math/UVec4.inl index e01d66b11..5a055e61c 100644 --- a/WickedEngine/Jolt/Math/UVec4.inl +++ b/WickedEngine/Jolt/Math/UVec4.inl @@ -36,7 +36,7 @@ UVec4 UVec4::Swizzle() const #if defined(JPH_USE_SSE) return _mm_shuffle_epi32(mValue, _MM_SHUFFLE(SwizzleW, SwizzleZ, SwizzleY, SwizzleX)); #elif defined(JPH_USE_NEON) - return JPH_NEON_SHUFFLE_F32x4(mValue, mValue, SwizzleX, SwizzleY, SwizzleZ, SwizzleW); + return JPH_NEON_SHUFFLE_U32x4(mValue, mValue, SwizzleX, SwizzleY, SwizzleZ, SwizzleW); #else return UVec4(mU32[SwizzleX], mU32[SwizzleY], mU32[SwizzleZ], mU32[SwizzleW]); #endif @@ -103,7 +103,12 @@ UVec4 UVec4::sGatherInt4(const uint32 *inBase, UVec4Arg inOffsets) #ifdef JPH_USE_AVX2 return _mm_i32gather_epi32(reinterpret_cast(inBase), inOffsets.mValue, Scale); #else - return Vec4::sGatherFloat4(reinterpret_cast(inBase), inOffsets).ReinterpretAsInt(); + const uint8 *base = reinterpret_cast(inBase); + uint32 x = *reinterpret_cast(base + inOffsets.GetX() * Scale); + uint32 y = *reinterpret_cast(base + inOffsets.GetY() * Scale); + uint32 z = *reinterpret_cast(base + inOffsets.GetZ() * Scale); + uint32 w = *reinterpret_cast(base + inOffsets.GetW() * Scale); + return UVec4(x, y, z, w); #endif } @@ -154,7 +159,7 @@ UVec4 UVec4::sSelect(UVec4Arg inV1, UVec4Arg inV2, UVec4Arg inControl) #if defined(JPH_USE_SSE4_1) return _mm_castps_si128(_mm_blendv_ps(_mm_castsi128_ps(inV1.mValue), _mm_castsi128_ps(inV2.mValue), _mm_castsi128_ps(inControl.mValue))); #elif defined(JPH_USE_NEON) - return vbslq_u32(vshrq_n_s32(inControl.mValue, 31), inV2.mValue, inV1.mValue); + return vbslq_u32(vreinterpretq_u32_s32(vshrq_n_s32(vreinterpretq_s32_u32(inControl.mValue), 31)), inV2.mValue, inV1.mValue); #else UVec4 result; for (int i = 0; i < 4; i++) @@ -323,7 +328,7 @@ Vec4 UVec4::ToFloat() const #if defined(JPH_USE_SSE) return _mm_cvtepi32_ps(mValue); #elif defined(JPH_USE_NEON) - return vcvtq_f32_s32(mValue); + return vcvtq_f32_u32(mValue); #else return Vec4((float)mU32[0], (float)mU32[1], (float)mU32[2], (float)mU32[3]); #endif @@ -334,7 +339,7 @@ Vec4 UVec4::ReinterpretAsFloat() const #if defined(JPH_USE_SSE) return Vec4(_mm_castsi128_ps(mValue)); #elif defined(JPH_USE_NEON) - return vreinterpretq_f32_s32(mValue); + return vreinterpretq_f32_u32(mValue); #else return *reinterpret_cast(this); #endif @@ -369,7 +374,7 @@ int UVec4::CountTrues() const #if defined(JPH_USE_SSE) return CountBits(_mm_movemask_ps(_mm_castsi128_ps(mValue))); #elif defined(JPH_USE_NEON) - return vaddvq_u32(vshrq_n_u32(mValue, 31)); + return vaddvq_u32(vshrq_n_u32(mValue, 31)); #else return (mU32[0] >> 31) + (mU32[1] >> 31) + (mU32[2] >> 31) + (mU32[3] >> 31); #endif @@ -380,8 +385,8 @@ int UVec4::GetTrues() const #if defined(JPH_USE_SSE) return _mm_movemask_ps(_mm_castsi128_ps(mValue)); #elif defined(JPH_USE_NEON) - int32x4_t shift = JPH_NEON_INT32x4(0, 1, 2, 3); - return vaddvq_u32(vshlq_u32(vshrq_n_u32(mValue, 31), shift)); + int32x4_t shift = JPH_NEON_INT32x4(0, 1, 2, 3); + return vaddvq_u32(vshlq_u32(vshrq_n_u32(mValue, 31), shift)); #else return (mU32[0] >> 31) | ((mU32[1] >> 31) << 1) | ((mU32[2] >> 31) << 2) | ((mU32[3] >> 31) << 3); #endif @@ -443,7 +448,7 @@ UVec4 UVec4::ArithmeticShiftRight() const #if defined(JPH_USE_SSE) return _mm_srai_epi32(mValue, Count); #elif defined(JPH_USE_NEON) - return vshrq_n_s32(mValue, Count); + return vreinterpretq_u32_s32(vshrq_n_s32(vreinterpretq_s32_u32(mValue), Count)); #else return UVec4(uint32(int32_t(mU32[0]) >> Count), uint32(int32_t(mU32[1]) >> Count), @@ -457,9 +462,9 @@ UVec4 UVec4::Expand4Uint16Lo() const #if defined(JPH_USE_SSE) return _mm_unpacklo_epi16(mValue, _mm_castps_si128(_mm_setzero_ps())); #elif defined(JPH_USE_NEON) - int16x4_t value = vget_low_s16(mValue); - int16x4_t zero = vdup_n_s16(0); - return vcombine_s16(vzip1_s16(value, zero), vzip2_s16(value, zero)); + uint16x4_t value = vget_low_u16(vreinterpretq_u16_u32(mValue)); + uint16x4_t zero = vdup_n_u16(0); + return vreinterpretq_u32_u16(vcombine_u16(vzip1_u16(value, zero), vzip2_u16(value, zero))); #else return UVec4(mU32[0] & 0xffff, (mU32[0] >> 16) & 0xffff, @@ -473,9 +478,9 @@ UVec4 UVec4::Expand4Uint16Hi() const #if defined(JPH_USE_SSE) return _mm_unpackhi_epi16(mValue, _mm_castps_si128(_mm_setzero_ps())); #elif defined(JPH_USE_NEON) - int16x4_t value = vget_high_s16(mValue); - int16x4_t zero = vdup_n_s16(0); - return vcombine_s16(vzip1_s16(value, zero), vzip2_s16(value, zero)); + uint16x4_t value = vget_high_u16(vreinterpretq_u16_u32(mValue)); + uint16x4_t zero = vdup_n_u16(0); + return vreinterpretq_u32_u16(vcombine_u16(vzip1_u16(value, zero), vzip2_u16(value, zero))); #else return UVec4(mU32[2] & 0xffff, (mU32[2] >> 16) & 0xffff, @@ -489,7 +494,7 @@ UVec4 UVec4::Expand4Byte0() const #if defined(JPH_USE_SSE4_1) return _mm_shuffle_epi8(mValue, _mm_set_epi32(int(0xffffff03), int(0xffffff02), int(0xffffff01), int(0xffffff00))); #elif defined(JPH_USE_NEON) - int8x16_t idx = JPH_NEON_INT8x16(0x00, 0x7f, 0x7f, 0x7f, 0x01, 0x7f, 0x7f, 0x7f, 0x02, 0x7f, 0x7f, 0x7f, 0x03, 0x7f, 0x7f, 0x7f); + uint8x16_t idx = JPH_NEON_UINT8x16(0x00, 0x7f, 0x7f, 0x7f, 0x01, 0x7f, 0x7f, 0x7f, 0x02, 0x7f, 0x7f, 0x7f, 0x03, 0x7f, 0x7f, 0x7f); return vreinterpretq_u32_s8(vqtbl1q_s8(vreinterpretq_s8_u32(mValue), idx)); #else UVec4 result; @@ -504,7 +509,7 @@ UVec4 UVec4::Expand4Byte4() const #if defined(JPH_USE_SSE4_1) return _mm_shuffle_epi8(mValue, _mm_set_epi32(int(0xffffff07), int(0xffffff06), int(0xffffff05), int(0xffffff04))); #elif defined(JPH_USE_NEON) - int8x16_t idx = JPH_NEON_INT8x16(0x04, 0x7f, 0x7f, 0x7f, 0x05, 0x7f, 0x7f, 0x7f, 0x06, 0x7f, 0x7f, 0x7f, 0x07, 0x7f, 0x7f, 0x7f); + uint8x16_t idx = JPH_NEON_UINT8x16(0x04, 0x7f, 0x7f, 0x7f, 0x05, 0x7f, 0x7f, 0x7f, 0x06, 0x7f, 0x7f, 0x7f, 0x07, 0x7f, 0x7f, 0x7f); return vreinterpretq_u32_s8(vqtbl1q_s8(vreinterpretq_s8_u32(mValue), idx)); #else UVec4 result; @@ -519,7 +524,7 @@ UVec4 UVec4::Expand4Byte8() const #if defined(JPH_USE_SSE4_1) return _mm_shuffle_epi8(mValue, _mm_set_epi32(int(0xffffff0b), int(0xffffff0a), int(0xffffff09), int(0xffffff08))); #elif defined(JPH_USE_NEON) - int8x16_t idx = JPH_NEON_INT8x16(0x08, 0x7f, 0x7f, 0x7f, 0x09, 0x7f, 0x7f, 0x7f, 0x0a, 0x7f, 0x7f, 0x7f, 0x0b, 0x7f, 0x7f, 0x7f); + uint8x16_t idx = JPH_NEON_UINT8x16(0x08, 0x7f, 0x7f, 0x7f, 0x09, 0x7f, 0x7f, 0x7f, 0x0a, 0x7f, 0x7f, 0x7f, 0x0b, 0x7f, 0x7f, 0x7f); return vreinterpretq_u32_s8(vqtbl1q_s8(vreinterpretq_s8_u32(mValue), idx)); #else UVec4 result; @@ -534,7 +539,7 @@ UVec4 UVec4::Expand4Byte12() const #if defined(JPH_USE_SSE4_1) return _mm_shuffle_epi8(mValue, _mm_set_epi32(int(0xffffff0f), int(0xffffff0e), int(0xffffff0d), int(0xffffff0c))); #elif defined(JPH_USE_NEON) - int8x16_t idx = JPH_NEON_INT8x16(0x0c, 0x7f, 0x7f, 0x7f, 0x0d, 0x7f, 0x7f, 0x7f, 0x0e, 0x7f, 0x7f, 0x7f, 0x0f, 0x7f, 0x7f, 0x7f); + uint8x16_t idx = JPH_NEON_UINT8x16(0x0c, 0x7f, 0x7f, 0x7f, 0x0d, 0x7f, 0x7f, 0x7f, 0x0e, 0x7f, 0x7f, 0x7f, 0x0f, 0x7f, 0x7f, 0x7f); return vreinterpretq_u32_s8(vqtbl1q_s8(vreinterpretq_s8_u32(mValue), idx)); #else UVec4 result; diff --git a/WickedEngine/Jolt/Math/Vec3.inl b/WickedEngine/Jolt/Math/Vec3.inl index 4a7953ccc..cf5e8bccc 100644 --- a/WickedEngine/Jolt/Math/Vec3.inl +++ b/WickedEngine/Jolt/Math/Vec3.inl @@ -57,9 +57,9 @@ Vec3::Vec3(const Float3 &inV) Type xy = _mm_unpacklo_ps(x, y); mValue = _mm_shuffle_ps(xy, z, _MM_SHUFFLE(0, 0, 1, 0)); // Assure Z and W are the same #elif defined(JPH_USE_NEON) - float32x2_t xy = vld1_f32(&inV.x); - float32x2_t zz = vdup_n_f32(inV.z); // Assure Z and W are the same - mValue = vcombine_f32(xy, zz); + float32x2_t xy = vld1_f32(&inV.x); + float32x2_t zz = vdup_n_f32(inV.z); // Assure Z and W are the same + mValue = vcombine_f32(xy, zz); #else mF32[0] = inV[0]; mF32[1] = inV[1]; @@ -75,9 +75,9 @@ Vec3::Vec3(float inX, float inY, float inZ) #if defined(JPH_USE_SSE) mValue = _mm_set_ps(inZ, inZ, inY, inX); #elif defined(JPH_USE_NEON) - uint32x2_t xy = vcreate_f32(static_cast(*reinterpret_cast(&inX)) | (static_cast(*reinterpret_cast(&inY)) << 32)); - uint32x2_t zz = vcreate_f32(static_cast(*reinterpret_cast(&inZ)) | (static_cast(*reinterpret_cast(&inZ)) << 32)); - mValue = vcombine_f32(xy, zz); + uint32x2_t xy = vcreate_u32(static_cast(BitCast(inX)) | (static_cast(BitCast(inY)) << 32)); + uint32x2_t zz = vreinterpret_u32_f32(vdup_n_f32(inZ)); + mValue = vreinterpretq_f32_u32(vcombine_u32(xy, zz)); #else mF32[0] = inX; mF32[1] = inY; @@ -272,7 +272,7 @@ Vec3 Vec3::sSelect(Vec3Arg inV1, Vec3Arg inV2, UVec4Arg inControl) Type v = _mm_blendv_ps(inV1.mValue, inV2.mValue, _mm_castsi128_ps(inControl.mValue)); return sFixW(v); #elif defined(JPH_USE_NEON) - Type v = vbslq_f32(vshrq_n_s32(inControl.mValue, 31), inV2.mValue, inV1.mValue); + Type v = vbslq_f32(vreinterpretq_u32_s32(vshrq_n_s32(vreinterpretq_s32_u32(inControl.mValue), 31)), inV2.mValue, inV1.mValue); return sFixW(v); #else Vec3 result; @@ -290,7 +290,7 @@ Vec3 Vec3::sOr(Vec3Arg inV1, Vec3Arg inV2) #if defined(JPH_USE_SSE) return _mm_or_ps(inV1.mValue, inV2.mValue); #elif defined(JPH_USE_NEON) - return vorrq_s32(inV1.mValue, inV2.mValue); + return vreinterpretq_f32_u32(vorrq_u32(vreinterpretq_u32_f32(inV1.mValue), vreinterpretq_u32_f32(inV2.mValue))); #else return Vec3(UVec4::sOr(inV1.ReinterpretAsInt(), inV2.ReinterpretAsInt()).ReinterpretAsFloat()); #endif @@ -301,7 +301,7 @@ Vec3 Vec3::sXor(Vec3Arg inV1, Vec3Arg inV2) #if defined(JPH_USE_SSE) return _mm_xor_ps(inV1.mValue, inV2.mValue); #elif defined(JPH_USE_NEON) - return veorq_s32(inV1.mValue, inV2.mValue); + return vreinterpretq_f32_u32(veorq_u32(vreinterpretq_u32_f32(inV1.mValue), vreinterpretq_u32_f32(inV2.mValue))); #else return Vec3(UVec4::sXor(inV1.ReinterpretAsInt(), inV2.ReinterpretAsInt()).ReinterpretAsFloat()); #endif @@ -312,7 +312,7 @@ Vec3 Vec3::sAnd(Vec3Arg inV1, Vec3Arg inV2) #if defined(JPH_USE_SSE) return _mm_and_ps(inV1.mValue, inV2.mValue); #elif defined(JPH_USE_NEON) - return vandq_s32(inV1.mValue, inV2.mValue); + return vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(inV1.mValue), vreinterpretq_u32_f32(inV2.mValue))); #else return Vec3(UVec4::sAnd(inV1.ReinterpretAsInt(), inV2.ReinterpretAsInt()).ReinterpretAsFloat()); #endif @@ -591,18 +591,18 @@ Vec3 Vec3::Cross(Vec3Arg inV2) const { #if defined(JPH_USE_SSE) Type t1 = _mm_shuffle_ps(inV2.mValue, inV2.mValue, _MM_SHUFFLE(0, 0, 2, 1)); // Assure Z and W are the same - t1 = _mm_mul_ps(t1, mValue); - Type t2 = _mm_shuffle_ps(mValue, mValue, _MM_SHUFFLE(0, 0, 2, 1)); // Assure Z and W are the same - t2 = _mm_mul_ps(t2, inV2.mValue); - Type t3 = _mm_sub_ps(t1, t2); - return _mm_shuffle_ps(t3, t3, _MM_SHUFFLE(0, 0, 2, 1)); // Assure Z and W are the same + t1 = _mm_mul_ps(t1, mValue); + Type t2 = _mm_shuffle_ps(mValue, mValue, _MM_SHUFFLE(0, 0, 2, 1)); // Assure Z and W are the same + t2 = _mm_mul_ps(t2, inV2.mValue); + Type t3 = _mm_sub_ps(t1, t2); + return _mm_shuffle_ps(t3, t3, _MM_SHUFFLE(0, 0, 2, 1)); // Assure Z and W are the same #elif defined(JPH_USE_NEON) Type t1 = JPH_NEON_SHUFFLE_F32x4(inV2.mValue, inV2.mValue, 1, 2, 0, 0); // Assure Z and W are the same - t1 = vmulq_f32(t1, mValue); - Type t2 = JPH_NEON_SHUFFLE_F32x4(mValue, mValue, 1, 2, 0, 0); // Assure Z and W are the same - t2 = vmulq_f32(t2, inV2.mValue); - Type t3 = vsubq_f32(t1, t2); - return JPH_NEON_SHUFFLE_F32x4(t3, t3, 1, 2, 0, 0); // Assure Z and W are the same + t1 = vmulq_f32(t1, mValue); + Type t2 = JPH_NEON_SHUFFLE_F32x4(mValue, mValue, 1, 2, 0, 0); // Assure Z and W are the same + t2 = vmulq_f32(t2, inV2.mValue); + Type t3 = vsubq_f32(t1, t2); + return JPH_NEON_SHUFFLE_F32x4(t3, t3, 1, 2, 0, 0); // Assure Z and W are the same #else return Vec3(mF32[1] * inV2.mF32[2] - mF32[2] * inV2.mF32[1], mF32[2] * inV2.mF32[0] - mF32[0] * inV2.mF32[2], @@ -615,9 +615,9 @@ Vec3 Vec3::DotV(Vec3Arg inV2) const #if defined(JPH_USE_SSE4_1) return _mm_dp_ps(mValue, inV2.mValue, 0x7f); #elif defined(JPH_USE_NEON) - float32x4_t mul = vmulq_f32(mValue, inV2.mValue); + float32x4_t mul = vmulq_f32(mValue, inV2.mValue); mul = vsetq_lane_f32(0, mul, 3); - return vdupq_n_f32(vaddvq_f32(mul)); + return vdupq_n_f32(vaddvq_f32(mul)); #else float dot = 0.0f; for (int i = 0; i < 3; i++) @@ -631,9 +631,9 @@ Vec4 Vec3::DotV4(Vec3Arg inV2) const #if defined(JPH_USE_SSE4_1) return _mm_dp_ps(mValue, inV2.mValue, 0x7f); #elif defined(JPH_USE_NEON) - float32x4_t mul = vmulq_f32(mValue, inV2.mValue); + float32x4_t mul = vmulq_f32(mValue, inV2.mValue); mul = vsetq_lane_f32(0, mul, 3); - return vdupq_n_f32(vaddvq_f32(mul)); + return vdupq_n_f32(vaddvq_f32(mul)); #else float dot = 0.0f; for (int i = 0; i < 3; i++) @@ -647,9 +647,9 @@ float Vec3::Dot(Vec3Arg inV2) const #if defined(JPH_USE_SSE4_1) return _mm_cvtss_f32(_mm_dp_ps(mValue, inV2.mValue, 0x7f)); #elif defined(JPH_USE_NEON) - float32x4_t mul = vmulq_f32(mValue, inV2.mValue); + float32x4_t mul = vmulq_f32(mValue, inV2.mValue); mul = vsetq_lane_f32(0, mul, 3); - return vaddvq_f32(mul); + return vaddvq_f32(mul); #else float dot = 0.0f; for (int i = 0; i < 3; i++) @@ -663,9 +663,9 @@ float Vec3::LengthSq() const #if defined(JPH_USE_SSE4_1) return _mm_cvtss_f32(_mm_dp_ps(mValue, mValue, 0x7f)); #elif defined(JPH_USE_NEON) - float32x4_t mul = vmulq_f32(mValue, mValue); + float32x4_t mul = vmulq_f32(mValue, mValue); mul = vsetq_lane_f32(0, mul, 3); - return vaddvq_f32(mul); + return vaddvq_f32(mul); #else float len_sq = 0.0f; for (int i = 0; i < 3; i++) @@ -679,10 +679,10 @@ float Vec3::Length() const #if defined(JPH_USE_SSE4_1) return _mm_cvtss_f32(_mm_sqrt_ss(_mm_dp_ps(mValue, mValue, 0x7f))); #elif defined(JPH_USE_NEON) - float32x4_t mul = vmulq_f32(mValue, mValue); + float32x4_t mul = vmulq_f32(mValue, mValue); mul = vsetq_lane_f32(0, mul, 3); - float32x2_t sum = vdup_n_f32(vaddvq_f32(mul)); - return vget_lane_f32(vsqrt_f32(sum), 0); + float32x2_t sum = vdup_n_f32(vaddvq_f32(mul)); + return vget_lane_f32(vsqrt_f32(sum), 0); #else return sqrt(LengthSq()); #endif @@ -704,10 +704,10 @@ Vec3 Vec3::Normalized() const #if defined(JPH_USE_SSE4_1) return _mm_div_ps(mValue, _mm_sqrt_ps(_mm_dp_ps(mValue, mValue, 0x7f))); #elif defined(JPH_USE_NEON) - float32x4_t mul = vmulq_f32(mValue, mValue); + float32x4_t mul = vmulq_f32(mValue, mValue); mul = vsetq_lane_f32(0, mul, 3); - float32x4_t sum = vdupq_n_f32(vaddvq_f32(mul)); - return vdivq_f32(mValue, vsqrtq_f32(sum)); + float32x4_t sum = vdupq_n_f32(vaddvq_f32(mul)); + return vdivq_f32(mValue, vsqrtq_f32(sum)); #else return *this / Length(); #endif @@ -727,12 +727,12 @@ Vec3 Vec3::NormalizedOr(Vec3Arg inZeroValue) const return _mm_blendv_ps(_mm_div_ps(mValue, _mm_sqrt_ps(len_sq)), inZeroValue.mValue, is_zero); #endif // JPH_FLOATING_POINT_EXCEPTIONS_ENABLED #elif defined(JPH_USE_NEON) - float32x4_t mul = vmulq_f32(mValue, mValue); + float32x4_t mul = vmulq_f32(mValue, mValue); mul = vsetq_lane_f32(0, mul, 3); - float32x4_t sum = vdupq_n_f32(vaddvq_f32(mul)); + float32x4_t sum = vdupq_n_f32(vaddvq_f32(mul)); float32x4_t len = vsqrtq_f32(sum); - float32x4_t is_zero = vceqq_f32(len, vdupq_n_f32(0)); - return vbslq_f32(is_zero, inZeroValue.mValue, vdivq_f32(mValue, len)); + uint32x4_t is_zero = vceqq_f32(len, vdupq_n_f32(0)); + return vbslq_f32(is_zero, inZeroValue.mValue, vdivq_f32(mValue, len)); #else float len_sq = LengthSq(); if (len_sq == 0.0f) @@ -771,9 +771,9 @@ void Vec3::StoreFloat3(Float3 *outV) const t = t.Swizzle(); _mm_store_ss(&outV->z, t.mValue); #elif defined(JPH_USE_NEON) - float32x2_t xy = vget_low_f32(mValue); - vst1_f32(&outV->x, xy); - vst1q_lane_f32(&outV->z, mValue, 2); + float32x2_t xy = vget_low_f32(mValue); + vst1_f32(&outV->x, xy); + vst1q_lane_f32(&outV->z, mValue, 2); #else outV->x = mF32[0]; outV->y = mF32[1]; @@ -842,11 +842,11 @@ Vec3 Vec3::GetSign() const #elif defined(JPH_USE_NEON) Type minus_one = vdupq_n_f32(-1.0f); Type one = vdupq_n_f32(1.0f); - return vorrq_s32(vandq_s32(mValue, minus_one), one); + return vreinterpretq_f32_u32(vorrq_u32(vandq_u32(vreinterpretq_u32_f32(mValue), vreinterpretq_u32_f32(minus_one)), vreinterpretq_u32_f32(one))); #else - return Vec3(signbit(mF32[0])? -1.0f : 1.0f, - signbit(mF32[1])? -1.0f : 1.0f, - signbit(mF32[2])? -1.0f : 1.0f); + return Vec3(std::signbit(mF32[0])? -1.0f : 1.0f, + std::signbit(mF32[1])? -1.0f : 1.0f, + std::signbit(mF32[2])? -1.0f : 1.0f); #endif } diff --git a/WickedEngine/Jolt/Math/Vec4.inl b/WickedEngine/Jolt/Math/Vec4.inl index 1090ca822..5f253329a 100644 --- a/WickedEngine/Jolt/Math/Vec4.inl +++ b/WickedEngine/Jolt/Math/Vec4.inl @@ -32,9 +32,9 @@ Vec4::Vec4(float inX, float inY, float inZ, float inW) #if defined(JPH_USE_SSE) mValue = _mm_set_ps(inW, inZ, inY, inX); #elif defined(JPH_USE_NEON) - uint32x2_t xy = vcreate_f32(static_cast(*reinterpret_cast(&inX)) | (static_cast(*reinterpret_cast(&inY)) << 32)); - uint32x2_t zw = vcreate_f32(static_cast(*reinterpret_cast(&inZ)) | (static_cast(*reinterpret_cast(&inW)) << 32)); - mValue = vcombine_f32(xy, zw); + uint32x2_t xy = vcreate_u32(static_cast(BitCast(inX)) | (static_cast(BitCast(inY)) << 32)); + uint32x2_t zw = vcreate_u32(static_cast(BitCast(inZ)) | (static_cast(BitCast(inW)) << 32)); + mValue = vreinterpretq_f32_u32(vcombine_u32(xy, zw)); #else mF32[0] = inX; mF32[1] = inY; @@ -256,7 +256,7 @@ Vec4 Vec4::sSelect(Vec4Arg inV1, Vec4Arg inV2, UVec4Arg inControl) #if defined(JPH_USE_SSE4_1) return _mm_blendv_ps(inV1.mValue, inV2.mValue, _mm_castsi128_ps(inControl.mValue)); #elif defined(JPH_USE_NEON) - return vbslq_f32(vshrq_n_s32(inControl.mValue, 31), inV2.mValue, inV1.mValue); + return vbslq_f32(vreinterpretq_u32_s32(vshrq_n_s32(vreinterpretq_s32_u32(inControl.mValue), 31)), inV2.mValue, inV1.mValue); #else Vec4 result; for (int i = 0; i < 4; i++) @@ -270,7 +270,7 @@ Vec4 Vec4::sOr(Vec4Arg inV1, Vec4Arg inV2) #if defined(JPH_USE_SSE) return _mm_or_ps(inV1.mValue, inV2.mValue); #elif defined(JPH_USE_NEON) - return vorrq_s32(inV1.mValue, inV2.mValue); + return vreinterpretq_f32_u32(vorrq_u32(vreinterpretq_u32_f32(inV1.mValue), vreinterpretq_u32_f32(inV2.mValue))); #else return UVec4::sOr(inV1.ReinterpretAsInt(), inV2.ReinterpretAsInt()).ReinterpretAsFloat(); #endif @@ -281,7 +281,7 @@ Vec4 Vec4::sXor(Vec4Arg inV1, Vec4Arg inV2) #if defined(JPH_USE_SSE) return _mm_xor_ps(inV1.mValue, inV2.mValue); #elif defined(JPH_USE_NEON) - return veorq_s32(inV1.mValue, inV2.mValue); + return vreinterpretq_f32_u32(veorq_u32(vreinterpretq_u32_f32(inV1.mValue), vreinterpretq_u32_f32(inV2.mValue))); #else return UVec4::sXor(inV1.ReinterpretAsInt(), inV2.ReinterpretAsInt()).ReinterpretAsFloat(); #endif @@ -292,7 +292,7 @@ Vec4 Vec4::sAnd(Vec4Arg inV1, Vec4Arg inV2) #if defined(JPH_USE_SSE) return _mm_and_ps(inV1.mValue, inV2.mValue); #elif defined(JPH_USE_NEON) - return vandq_s32(inV1.mValue, inV2.mValue); + return vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(inV1.mValue), vreinterpretq_u32_f32(inV2.mValue))); #else return UVec4::sAnd(inV1.ReinterpretAsInt(), inV2.ReinterpretAsInt()).ReinterpretAsFloat(); #endif @@ -619,8 +619,8 @@ Vec4 Vec4::DotV(Vec4Arg inV2) const #if defined(JPH_USE_SSE4_1) return _mm_dp_ps(mValue, inV2.mValue, 0xff); #elif defined(JPH_USE_NEON) - float32x4_t mul = vmulq_f32(mValue, inV2.mValue); - return vdupq_n_f32(vaddvq_f32(mul)); + float32x4_t mul = vmulq_f32(mValue, inV2.mValue); + return vdupq_n_f32(vaddvq_f32(mul)); #else // Brackets placed so that the order is consistent with the vectorized version return Vec4::sReplicate((mF32[0] * inV2.mF32[0] + mF32[1] * inV2.mF32[1]) + (mF32[2] * inV2.mF32[2] + mF32[3] * inV2.mF32[3])); @@ -632,8 +632,8 @@ float Vec4::Dot(Vec4Arg inV2) const #if defined(JPH_USE_SSE4_1) return _mm_cvtss_f32(_mm_dp_ps(mValue, inV2.mValue, 0xff)); #elif defined(JPH_USE_NEON) - float32x4_t mul = vmulq_f32(mValue, inV2.mValue); - return vaddvq_f32(mul); + float32x4_t mul = vmulq_f32(mValue, inV2.mValue); + return vaddvq_f32(mul); #else // Brackets placed so that the order is consistent with the vectorized version return (mF32[0] * inV2.mF32[0] + mF32[1] * inV2.mF32[1]) + (mF32[2] * inV2.mF32[2] + mF32[3] * inV2.mF32[3]); @@ -645,8 +645,8 @@ float Vec4::LengthSq() const #if defined(JPH_USE_SSE4_1) return _mm_cvtss_f32(_mm_dp_ps(mValue, mValue, 0xff)); #elif defined(JPH_USE_NEON) - float32x4_t mul = vmulq_f32(mValue, mValue); - return vaddvq_f32(mul); + float32x4_t mul = vmulq_f32(mValue, mValue); + return vaddvq_f32(mul); #else // Brackets placed so that the order is consistent with the vectorized version return (mF32[0] * mF32[0] + mF32[1] * mF32[1]) + (mF32[2] * mF32[2] + mF32[3] * mF32[3]); @@ -658,9 +658,9 @@ float Vec4::Length() const #if defined(JPH_USE_SSE4_1) return _mm_cvtss_f32(_mm_sqrt_ss(_mm_dp_ps(mValue, mValue, 0xff))); #elif defined(JPH_USE_NEON) - float32x4_t mul = vmulq_f32(mValue, mValue); - float32x2_t sum = vdup_n_f32(vaddvq_f32(mul)); - return vget_lane_f32(vsqrt_f32(sum), 0); + float32x4_t mul = vmulq_f32(mValue, mValue); + float32x2_t sum = vdup_n_f32(vaddvq_f32(mul)); + return vget_lane_f32(vsqrt_f32(sum), 0); #else // Brackets placed so that the order is consistent with the vectorized version return sqrt((mF32[0] * mF32[0] + mF32[1] * mF32[1]) + (mF32[2] * mF32[2] + mF32[3] * mF32[3])); @@ -690,12 +690,12 @@ Vec4 Vec4::GetSign() const #elif defined(JPH_USE_NEON) Type minus_one = vdupq_n_f32(-1.0f); Type one = vdupq_n_f32(1.0f); - return vorrq_s32(vandq_s32(mValue, minus_one), one); + return vreinterpretq_f32_u32(vorrq_u32(vandq_u32(vreinterpretq_u32_f32(mValue), vreinterpretq_u32_f32(minus_one)), vreinterpretq_u32_f32(one))); #else - return Vec4(signbit(mF32[0])? -1.0f : 1.0f, - signbit(mF32[1])? -1.0f : 1.0f, - signbit(mF32[2])? -1.0f : 1.0f, - signbit(mF32[3])? -1.0f : 1.0f); + return Vec4(std::signbit(mF32[0])? -1.0f : 1.0f, + std::signbit(mF32[1])? -1.0f : 1.0f, + std::signbit(mF32[2])? -1.0f : 1.0f, + std::signbit(mF32[3])? -1.0f : 1.0f); #endif } @@ -704,9 +704,9 @@ Vec4 Vec4::Normalized() const #if defined(JPH_USE_SSE4_1) return _mm_div_ps(mValue, _mm_sqrt_ps(_mm_dp_ps(mValue, mValue, 0xff))); #elif defined(JPH_USE_NEON) - float32x4_t mul = vmulq_f32(mValue, mValue); - float32x4_t sum = vdupq_n_f32(vaddvq_f32(mul)); - return vdivq_f32(mValue, vsqrtq_f32(sum)); + float32x4_t mul = vmulq_f32(mValue, mValue); + float32x4_t sum = vdupq_n_f32(vaddvq_f32(mul)); + return vdivq_f32(mValue, vsqrtq_f32(sum)); #else return *this / Length(); #endif @@ -717,7 +717,7 @@ void Vec4::StoreFloat4(Float4 *outV) const #if defined(JPH_USE_SSE) _mm_storeu_ps(&outV->x, mValue); #elif defined(JPH_USE_NEON) - vst1q_f32(&outV->x, mValue); + vst1q_f32(&outV->x, mValue); #else for (int i = 0; i < 4; ++i) (&outV->x)[i] = mF32[i]; @@ -751,10 +751,10 @@ int Vec4::GetSignBits() const #if defined(JPH_USE_SSE) return _mm_movemask_ps(mValue); #elif defined(JPH_USE_NEON) - int32x4_t shift = JPH_NEON_INT32x4(0, 1, 2, 3); - return vaddvq_u32(vshlq_u32(vshrq_n_u32(vreinterpretq_u32_f32(mValue), 31), shift)); + int32x4_t shift = JPH_NEON_INT32x4(0, 1, 2, 3); + return vaddvq_u32(vshlq_u32(vshrq_n_u32(vreinterpretq_u32_f32(mValue), 31), shift)); #else - return (signbit(mF32[0])? 1 : 0) | (signbit(mF32[1])? 2 : 0) | (signbit(mF32[2])? 4 : 0) | (signbit(mF32[3])? 8 : 0); + return (std::signbit(mF32[0])? 1 : 0) | (std::signbit(mF32[1])? 2 : 0) | (std::signbit(mF32[2])? 4 : 0) | (std::signbit(mF32[3])? 8 : 0); #endif } diff --git a/WickedEngine/Jolt/ObjectStream/ObjectStreamBinaryIn.h b/WickedEngine/Jolt/ObjectStream/ObjectStreamBinaryIn.h index 310962b40..63774110d 100644 --- a/WickedEngine/Jolt/ObjectStream/ObjectStreamBinaryIn.h +++ b/WickedEngine/Jolt/ObjectStream/ObjectStreamBinaryIn.h @@ -17,7 +17,7 @@ public: JPH_OVERRIDE_NEW_DELETE /// Constructor - explicit ObjectStreamBinaryIn(istream &inStream); + explicit ObjectStreamBinaryIn(istream &inStream); ///@name Input type specific operations virtual bool ReadDataType(EOSDataType &outType) override; diff --git a/WickedEngine/Jolt/ObjectStream/ObjectStreamBinaryOut.h b/WickedEngine/Jolt/ObjectStream/ObjectStreamBinaryOut.h index c35a4a59c..50464e28c 100644 --- a/WickedEngine/Jolt/ObjectStream/ObjectStreamBinaryOut.h +++ b/WickedEngine/Jolt/ObjectStream/ObjectStreamBinaryOut.h @@ -17,7 +17,7 @@ public: JPH_OVERRIDE_NEW_DELETE /// Constructor and destructor - explicit ObjectStreamBinaryOut(ostream &inStream); + explicit ObjectStreamBinaryOut(ostream &inStream); ///@name Output type specific operations virtual void WriteDataType(EOSDataType inType) override; diff --git a/WickedEngine/Jolt/ObjectStream/ObjectStreamIn.h b/WickedEngine/Jolt/ObjectStream/ObjectStreamIn.h index 9b99cc2bf..b59194ac0 100644 --- a/WickedEngine/Jolt/ObjectStream/ObjectStreamIn.h +++ b/WickedEngine/Jolt/ObjectStream/ObjectStreamIn.h @@ -88,7 +88,7 @@ public: protected: /// Constructor - explicit ObjectStreamIn(istream &inStream); + explicit ObjectStreamIn(istream &inStream); /// Determine the type and version of an object stream static bool GetInfo(istream &inStream, EStreamType &outType, int &outVersion, int &outRevision); @@ -112,7 +112,7 @@ private: struct ClassDescription { ClassDescription() = default; - explicit ClassDescription(const RTTI *inRTTI) : mRTTI(inRTTI) { } + explicit ClassDescription(const RTTI *inRTTI) : mRTTI(inRTTI) { } const RTTI * mRTTI = nullptr; Array mAttributes; diff --git a/WickedEngine/Jolt/ObjectStream/ObjectStreamOut.h b/WickedEngine/Jolt/ObjectStream/ObjectStreamOut.h index 2d5a476bc..cc83844f4 100644 --- a/WickedEngine/Jolt/ObjectStream/ObjectStreamOut.h +++ b/WickedEngine/Jolt/ObjectStream/ObjectStreamOut.h @@ -73,7 +73,7 @@ protected: static ObjectStreamOut * Open(EStreamType inType, ostream &inStream); /// Constructor - explicit ObjectStreamOut(ostream &inStream); + explicit ObjectStreamOut(ostream &inStream); ostream & mStream; diff --git a/WickedEngine/Jolt/ObjectStream/ObjectStreamTextIn.cpp b/WickedEngine/Jolt/ObjectStream/ObjectStreamTextIn.cpp index 4160df865..3f345c40f 100644 --- a/WickedEngine/Jolt/ObjectStream/ObjectStreamTextIn.cpp +++ b/WickedEngine/Jolt/ObjectStream/ObjectStreamTextIn.cpp @@ -30,41 +30,41 @@ bool ObjectStreamTextIn::ReadDataType(EOSDataType &outType) else if (token == "pointer") outType = EOSDataType::Pointer; else if (token == "array") - outType = EOSDataType::Array; + outType = EOSDataType::Array; else if (token == "uint8") - outType = EOSDataType::T_uint8; + outType = EOSDataType::T_uint8; else if (token == "uint16") - outType = EOSDataType::T_uint16; + outType = EOSDataType::T_uint16; else if (token == "int") - outType = EOSDataType::T_int; + outType = EOSDataType::T_int; else if (token == "uint32") - outType = EOSDataType::T_uint32; + outType = EOSDataType::T_uint32; else if (token == "uint64") - outType = EOSDataType::T_uint64; + outType = EOSDataType::T_uint64; else if (token == "float") - outType = EOSDataType::T_float; + outType = EOSDataType::T_float; else if (token == "double") - outType = EOSDataType::T_double; + outType = EOSDataType::T_double; else if (token == "bool") - outType = EOSDataType::T_bool; + outType = EOSDataType::T_bool; else if (token == "string") - outType = EOSDataType::T_String; + outType = EOSDataType::T_String; else if (token == "float3") - outType = EOSDataType::T_Float3; + outType = EOSDataType::T_Float3; else if (token == "double3") - outType = EOSDataType::T_Double3; + outType = EOSDataType::T_Double3; else if (token == "vec3") - outType = EOSDataType::T_Vec3; + outType = EOSDataType::T_Vec3; else if (token == "dvec3") - outType = EOSDataType::T_DVec3; + outType = EOSDataType::T_DVec3; else if (token == "vec4") - outType = EOSDataType::T_Vec4; + outType = EOSDataType::T_Vec4; else if (token == "quat") - outType = EOSDataType::T_Quat; + outType = EOSDataType::T_Quat; else if (token == "mat44") - outType = EOSDataType::T_Mat44; + outType = EOSDataType::T_Mat44; else if (token == "dmat44") - outType = EOSDataType::T_DMat44; + outType = EOSDataType::T_DMat44; else { Trace("ObjectStreamTextIn: Found unknown data type."); diff --git a/WickedEngine/Jolt/ObjectStream/SerializableObject.h b/WickedEngine/Jolt/ObjectStream/SerializableObject.h index 8428c5dae..86b8830c2 100644 --- a/WickedEngine/Jolt/ObjectStream/SerializableObject.h +++ b/WickedEngine/Jolt/ObjectStream/SerializableObject.h @@ -51,7 +51,7 @@ JPH_NAMESPACE_BEGIN { \ if (inPointer) \ ioStream.WritePointerData(GetRTTI(inPointer), (void *)inPointer); \ - else \ + else \ ioStream.WritePointerData(nullptr, nullptr); \ } \ void OSWriteDataType(IObjectStreamOut &ioStream, class_name *) \ diff --git a/WickedEngine/Jolt/Physics/Body/Body.h b/WickedEngine/Jolt/Physics/Body/Body.h index 509f55f66..799150532 100644 --- a/WickedEngine/Jolt/Physics/Body/Body.h +++ b/WickedEngine/Jolt/Physics/Body/Body.h @@ -36,12 +36,6 @@ class alignas(JPH_RVECTOR_ALIGNMENT) JPH_EXPORT_GCC_BUG_WORKAROUND Body : public public: JPH_OVERRIDE_NEW_DELETE - /// Default constructor - Body() = default; - - /// Destructor - ~Body() { JPH_ASSERT(mMotionProperties == nullptr); } - /// Get the id of this body inline const BodyID & GetID() const { return mID; } @@ -234,13 +228,13 @@ public: inline RVec3 GetPosition() const { JPH_ASSERT(BodyAccess::sCheckRights(BodyAccess::sPositionAccess, BodyAccess::EAccess::Read)); return mPosition - mRotation * mShape->GetCenterOfMass(); } /// World space rotation of the body - inline Quat GetRotation() const { JPH_ASSERT(BodyAccess::sCheckRights(BodyAccess::sPositionAccess, BodyAccess::EAccess::Read)); return mRotation; } + inline Quat GetRotation() const { JPH_ASSERT(BodyAccess::sCheckRights(BodyAccess::sPositionAccess, BodyAccess::EAccess::Read)); return mRotation; } /// Calculates the transform of this body inline RMat44 GetWorldTransform() const; /// Gets the world space position of this body's center of mass - inline RVec3 GetCenterOfMassPosition() const { JPH_ASSERT(BodyAccess::sCheckRights(BodyAccess::sPositionAccess, BodyAccess::EAccess::Read)); return mPosition; } + inline RVec3 GetCenterOfMassPosition() const { JPH_ASSERT(BodyAccess::sCheckRights(BodyAccess::sPositionAccess, BodyAccess::EAccess::Read)); return mPosition; } /// Calculates the transform for this body's center of mass inline RMat44 GetCenterOfMassTransform() const; @@ -287,7 +281,7 @@ public: /// Update position using an Euler step (used during position integrate & constraint solving) inline void AddPositionStep(Vec3Arg inLinearVelocityTimesDeltaTime) { JPH_ASSERT(IsRigidBody()); JPH_ASSERT(BodyAccess::sCheckRights(BodyAccess::sPositionAccess, BodyAccess::EAccess::ReadWrite)); mPosition += mMotionProperties->LockTranslation(inLinearVelocityTimesDeltaTime); JPH_ASSERT(!mPosition.IsNaN()); } - inline void SubPositionStep(Vec3Arg inLinearVelocityTimesDeltaTime) { JPH_ASSERT(IsRigidBody()); JPH_ASSERT(BodyAccess::sCheckRights(BodyAccess::sPositionAccess, BodyAccess::EAccess::ReadWrite)); mPosition -= mMotionProperties->LockTranslation(inLinearVelocityTimesDeltaTime); JPH_ASSERT(!mPosition.IsNaN()); } + inline void SubPositionStep(Vec3Arg inLinearVelocityTimesDeltaTime) { JPH_ASSERT(IsRigidBody()); JPH_ASSERT(BodyAccess::sCheckRights(BodyAccess::sPositionAccess, BodyAccess::EAccess::ReadWrite)); mPosition -= mMotionProperties->LockTranslation(inLinearVelocityTimesDeltaTime); JPH_ASSERT(!mPosition.IsNaN()); } /// Update rotation using an Euler step (using during position integrate & constraint solving) inline void AddRotationStep(Vec3Arg inAngularVelocityTimesDeltaTime); @@ -336,9 +330,15 @@ public: private: friend class BodyManager; + friend class BodyWithMotionProperties; + friend class SoftBodyWithMotionPropertiesAndShape; + + Body() = default; ///< Bodies must be created through BodyInterface::CreateBody explicit Body(bool); ///< Alternative constructor that initializes all members + ~Body() { JPH_ASSERT(mMotionProperties == nullptr); } ///< Bodies must be destroyed through BodyInterface::DestroyBody + inline void GetSleepTestPoints(RVec3 *outPoints) const; ///< Determine points to test for checking if body is sleeping: COM, COM + largest bounding box axis, COM + second largest bounding box axis enum class EFlags : uint8 diff --git a/WickedEngine/Jolt/Physics/Body/BodyFilter.h b/WickedEngine/Jolt/Physics/Body/BodyFilter.h index c876e9d09..111d51401 100644 --- a/WickedEngine/Jolt/Physics/Body/BodyFilter.h +++ b/WickedEngine/Jolt/Physics/Body/BodyFilter.h @@ -12,7 +12,7 @@ JPH_NAMESPACE_BEGIN class Body; /// Class function to filter out bodies, returns true if test should collide with body -class BodyFilter : public NonCopyable +class JPH_EXPORT BodyFilter : public NonCopyable { public: /// Destructor @@ -32,7 +32,7 @@ public: }; /// A simple body filter implementation that ignores a single, specified body -class IgnoreSingleBodyFilter : public BodyFilter +class JPH_EXPORT IgnoreSingleBodyFilter : public BodyFilter { public: /// Constructor, pass the body you want to ignore @@ -52,7 +52,7 @@ private: }; /// A simple body filter implementation that ignores multiple, specified bodies -class IgnoreMultipleBodiesFilter : public BodyFilter +class JPH_EXPORT IgnoreMultipleBodiesFilter : public BodyFilter { public: /// Remove all bodies from the filter @@ -83,9 +83,37 @@ private: Array mBodyIDs; }; +/// Ignores a single body and chains the filter to another filter +class JPH_EXPORT IgnoreSingleBodyFilterChained : public BodyFilter +{ +public: + /// Constructor + explicit IgnoreSingleBodyFilterChained(const BodyID inBodyID, const BodyFilter &inFilter) : + mBodyID(inBodyID), + mFilter(inFilter) + { + } + + /// Filter function. Returns true if we should collide with inBodyID + virtual bool ShouldCollide(const BodyID &inBodyID) const override + { + return inBodyID != mBodyID && mFilter.ShouldCollide(inBodyID); + } + + /// Filter function. Returns true if we should collide with inBody (this is called after the body is locked and makes it possible to filter based on body members) + virtual bool ShouldCollideLocked(const Body &inBody) const override + { + return mFilter.ShouldCollideLocked(inBody); + } + +private: + BodyID mBodyID; + const BodyFilter & mFilter; +}; + #ifdef JPH_DEBUG_RENDERER /// Class function to filter out bodies for debug rendering, returns true if body should be rendered -class BodyDrawFilter : public NonCopyable +class JPH_EXPORT BodyDrawFilter : public NonCopyable { public: /// Destructor diff --git a/WickedEngine/Jolt/Physics/Body/BodyInterface.h b/WickedEngine/Jolt/Physics/Body/BodyInterface.h index 2b18245c0..e29c48b03 100644 --- a/WickedEngine/Jolt/Physics/Body/BodyInterface.h +++ b/WickedEngine/Jolt/Physics/Body/BodyInterface.h @@ -83,10 +83,12 @@ public: /// @param outBodies If not null on input, this will contain a list of body pointers corresponding to inBodyIDs that can be destroyed afterwards (caller assumes ownership over these). void UnassignBodyIDs(const BodyID *inBodyIDs, int inNumber, Body **outBodies); - /// Destroy a body + /// Destroy a body. + /// Make sure that you remove the body from the physics system using BodyInterface::RemoveBody before calling this function. void DestroyBody(const BodyID &inBodyID); /// Destroy multiple bodies + /// Make sure that you remove the bodies from the physics system using BodyInterface::RemoveBody before calling this function. void DestroyBodies(const BodyID *inBodyIDs, int inNumber); /// Add body to the physics system. diff --git a/WickedEngine/Jolt/Physics/Body/BodyManager.cpp b/WickedEngine/Jolt/Physics/Body/BodyManager.cpp index c65f5b6bf..f47bbe312 100644 --- a/WickedEngine/Jolt/Physics/Body/BodyManager.cpp +++ b/WickedEngine/Jolt/Physics/Body/BodyManager.cpp @@ -188,7 +188,7 @@ Body *BodyManager::AllocateBody(const BodyCreationSettings &inBodyCreationSettin } else { - body = new Body; + body = new Body; } body->mBodyType = EBodyType::RigidBody; body->mShape = inBodyCreationSettings.GetShape(); @@ -403,7 +403,7 @@ Body *BodyManager::RemoveBodyInternal(const BodyID &inBodyID) // Validate that it can be removed JPH_ASSERT(body->GetID() == inBodyID); JPH_ASSERT(!body->IsActive()); - JPH_ASSERT(!body->IsInBroadPhase()); + JPH_ASSERT(!body->IsInBroadPhase(), "Use BodyInterface::RemoveBody to remove this body first!"); // Push the id onto the freelist mBodies[idx] = (Body *)mBodyIDFreeListStart; @@ -554,7 +554,7 @@ void BodyManager::ActivateBodies(const BodyID *inBodyIDs, int inNumber) Body &body = *mBodies[body_id.GetIndex()]; JPH_ASSERT(body.GetID() == body_id); - JPH_ASSERT(body.IsInBroadPhase()); + JPH_ASSERT(body.IsInBroadPhase(), "Use BodyInterface::AddBody to add the body first!"); if (!body.IsStatic()) { @@ -591,7 +591,7 @@ void BodyManager::DeactivateBodies(const BodyID *inBodyIDs, int inNumber) Body &body = *mBodies[body_id.GetIndex()]; JPH_ASSERT(body.GetID() == body_id); - JPH_ASSERT(body.IsInBroadPhase()); + JPH_ASSERT(body.IsInBroadPhase(), "Use BodyInterface::AddBody to add the body first!"); if (body.mMotionProperties != nullptr && body.mMotionProperties->mIndexInActiveBodies != Body::cInactiveIndex) diff --git a/WickedEngine/Jolt/Physics/Body/MotionProperties.h b/WickedEngine/Jolt/Physics/Body/MotionProperties.h index f3e6bc32e..2373fd5b5 100644 --- a/WickedEngine/Jolt/Physics/Body/MotionProperties.h +++ b/WickedEngine/Jolt/Physics/Body/MotionProperties.h @@ -102,10 +102,10 @@ public: void SetInverseMass(float inInverseMass) { mInvMass = inInverseMass; } /// Diagonal of inverse inertia matrix: D. Should only be called on a dynamic object (static or kinematic bodies have infinite mass so should be treated as D = 0) - inline Vec3 GetInverseInertiaDiagonal() const { JPH_ASSERT(mCachedMotionType == EMotionType::Dynamic); return mInvInertiaDiagonal; } + inline Vec3 GetInverseInertiaDiagonal() const { JPH_ASSERT(mCachedMotionType == EMotionType::Dynamic); return mInvInertiaDiagonal; } /// Rotation (R) that takes inverse inertia diagonal to local space: \f$I_{body}^{-1} = R \: D \: R^{-1}\f$ - inline Quat GetInertiaRotation() const { return mInertiaRotation; } + inline Quat GetInertiaRotation() const { return mInertiaRotation; } /// Set the inverse inertia tensor in local space by setting the diagonal and the rotation: \f$I_{body}^{-1} = R \: D \: R^{-1}\f$. /// Note that mass and inertia are linearly related (e.g. inertia of a sphere with mass m and radius r is \f$2/5 \: m \: r^2\f$). @@ -114,10 +114,10 @@ public: void SetInverseInertia(Vec3Arg inDiagonal, QuatArg inRot) { mInvInertiaDiagonal = inDiagonal; mInertiaRotation = inRot; } /// Get inverse inertia matrix (\f$I_{body}^{-1}\f$). Will be a matrix of zeros for a static or kinematic object. - inline Mat44 GetLocalSpaceInverseInertia() const; + inline Mat44 GetLocalSpaceInverseInertia() const; /// Same as GetLocalSpaceInverseInertia() but doesn't check if the body is dynamic - inline Mat44 GetLocalSpaceInverseInertiaUnchecked() const; + inline Mat44 GetLocalSpaceInverseInertiaUnchecked() const; /// Get inverse inertia matrix (\f$I^{-1}\f$) for a given object rotation (translation will be ignored). Zero if object is static or kinematic. inline Mat44 GetInverseInertiaForRotation(Mat44Arg inRotation) const; @@ -191,7 +191,7 @@ public: inline void AddLinearVelocityStep(Vec3Arg inLinearVelocityChange) { JPH_DET_LOG("AddLinearVelocityStep: " << inLinearVelocityChange); JPH_ASSERT(BodyAccess::sCheckRights(BodyAccess::sVelocityAccess, BodyAccess::EAccess::ReadWrite)); mLinearVelocity = LockTranslation(mLinearVelocity + inLinearVelocityChange); JPH_ASSERT(!mLinearVelocity.IsNaN()); } inline void SubLinearVelocityStep(Vec3Arg inLinearVelocityChange) { JPH_DET_LOG("SubLinearVelocityStep: " << inLinearVelocityChange); JPH_ASSERT(BodyAccess::sCheckRights(BodyAccess::sVelocityAccess, BodyAccess::EAccess::ReadWrite)); mLinearVelocity = LockTranslation(mLinearVelocity - inLinearVelocityChange); JPH_ASSERT(!mLinearVelocity.IsNaN()); } inline void AddAngularVelocityStep(Vec3Arg inAngularVelocityChange) { JPH_DET_LOG("AddAngularVelocityStep: " << inAngularVelocityChange); JPH_ASSERT(BodyAccess::sCheckRights(BodyAccess::sVelocityAccess, BodyAccess::EAccess::ReadWrite)); mAngularVelocity += inAngularVelocityChange; JPH_ASSERT(!mAngularVelocity.IsNaN()); } - inline void SubAngularVelocityStep(Vec3Arg inAngularVelocityChange) { JPH_DET_LOG("SubAngularVelocityStep: " << inAngularVelocityChange); JPH_ASSERT(BodyAccess::sCheckRights(BodyAccess::sVelocityAccess, BodyAccess::EAccess::ReadWrite)); mAngularVelocity -= inAngularVelocityChange; JPH_ASSERT(!mAngularVelocity.IsNaN()); } + inline void SubAngularVelocityStep(Vec3Arg inAngularVelocityChange) { JPH_DET_LOG("SubAngularVelocityStep: " << inAngularVelocityChange); JPH_ASSERT(BodyAccess::sCheckRights(BodyAccess::sVelocityAccess, BodyAccess::EAccess::ReadWrite)); mAngularVelocity -= inAngularVelocityChange; JPH_ASSERT(!mAngularVelocity.IsNaN()); } ///@} /// Apply the gyroscopic force (aka Dzhanibekov effect, see https://en.wikipedia.org/wiki/Tennis_racket_theorem) diff --git a/WickedEngine/Jolt/Physics/Character/Character.cpp b/WickedEngine/Jolt/Physics/Character/Character.cpp index 73914962c..14b231287 100644 --- a/WickedEngine/Jolt/Physics/Character/Character.cpp +++ b/WickedEngine/Jolt/Physics/Character/Character.cpp @@ -315,4 +315,9 @@ bool Character::SetShape(const Shape *inShape, float inMaxPenetrationDepth, bool return true; } +TransformedShape Character::GetTransformedShape(bool inLockBodies) const +{ + return sGetBodyInterface(mSystem, inLockBodies).GetTransformedShape(mBodyID); +} + JPH_NAMESPACE_END diff --git a/WickedEngine/Jolt/Physics/Character/Character.h b/WickedEngine/Jolt/Physics/Character/Character.h index b886045e4..db67f8b3b 100644 --- a/WickedEngine/Jolt/Physics/Character/Character.h +++ b/WickedEngine/Jolt/Physics/Character/Character.h @@ -6,6 +6,7 @@ #include #include +#include #include JPH_NAMESPACE_BEGIN @@ -105,6 +106,9 @@ public: /// Calculate the world transform of the character RMat44 GetWorldTransform(bool inLockBodies = true) const; + /// Get the layer of the character + ObjectLayer GetLayer() const { return mLayer; } + /// Update the layer of the character void SetLayer(ObjectLayer inLayer, bool inLockBodies = true); @@ -112,6 +116,9 @@ public: /// if the new shape collides before switching shape. Returns true if the switch succeeded. bool SetShape(const Shape *inShape, float inMaxPenetrationDepth, bool inLockBodies = true); + /// Get the transformed shape that represents the volume of the character, can be used for collision checks. + TransformedShape GetTransformedShape(bool inLockBodies = true) const; + /// @brief Get all contacts for the character at a particular location /// @param inPosition Position to test. /// @param inRotation Rotation at which to test the shape. diff --git a/WickedEngine/Jolt/Physics/Character/CharacterBase.h b/WickedEngine/Jolt/Physics/Character/CharacterBase.h index c5804af97..fc19c3d99 100644 --- a/WickedEngine/Jolt/Physics/Character/CharacterBase.h +++ b/WickedEngine/Jolt/Physics/Character/CharacterBase.h @@ -100,10 +100,10 @@ public: bool IsSupported() const { return mGroundState == EGroundState::OnGround || mGroundState == EGroundState::OnSteepGround; } /// Get the contact point with the ground - RVec3 GetGroundPosition() const { return mGroundPosition; } + RVec3 GetGroundPosition() const { return mGroundPosition; } /// Get the contact normal with the ground - Vec3 GetGroundNormal() const { return mGroundNormal; } + Vec3 GetGroundNormal() const { return mGroundNormal; } /// Velocity in world space of ground Vec3 GetGroundVelocity() const { return mGroundVelocity; } diff --git a/WickedEngine/Jolt/Physics/Character/CharacterVirtual.cpp b/WickedEngine/Jolt/Physics/Character/CharacterVirtual.cpp index dc851832b..645773464 100644 --- a/WickedEngine/Jolt/Physics/Character/CharacterVirtual.cpp +++ b/WickedEngine/Jolt/Physics/Character/CharacterVirtual.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -20,6 +21,68 @@ JPH_NAMESPACE_BEGIN +void CharacterVsCharacterCollisionSimple::Remove(const CharacterVirtual *inCharacter) +{ + Array::iterator i = std::find(mCharacters.begin(), mCharacters.end(), inCharacter); + if (i != mCharacters.end()) + mCharacters.erase(i); +} + +void CharacterVsCharacterCollisionSimple::CollideCharacter(const CharacterVirtual *inCharacter, RMat44Arg inCenterOfMassTransform, const CollideShapeSettings &inCollideShapeSettings, RVec3Arg inBaseOffset, CollideShapeCollector &ioCollector) const +{ + // Make shape 1 relative to inBaseOffset + Mat44 transform1 = inCenterOfMassTransform.PostTranslated(-inBaseOffset).ToMat44(); + + const Shape *shape = inCharacter->GetShape(); + CollideShapeSettings settings = inCollideShapeSettings; + + // Iterate over all characters + for (const CharacterVirtual *c : mCharacters) + if (c != inCharacter + && !ioCollector.ShouldEarlyOut()) + { + // Collector needs to know which character we're colliding with + ioCollector.SetUserData(reinterpret_cast(c)); + + // Make shape 2 relative to inBaseOffset + Mat44 transform2 = c->GetCenterOfMassTransform().PostTranslated(-inBaseOffset).ToMat44(); + + // We need to add the padding of character 2 so that we will detect collision with its outer shell + settings.mMaxSeparationDistance = inCollideShapeSettings.mMaxSeparationDistance + c->GetCharacterPadding(); + + // Note that this collides against the character's shape without padding, this will be corrected for in CharacterVirtual::GetContactsAtPosition + CollisionDispatch::sCollideShapeVsShape(shape, c->GetShape(), Vec3::sReplicate(1.0f), Vec3::sReplicate(1.0f), transform1, transform2, SubShapeIDCreator(), SubShapeIDCreator(), settings, ioCollector); + } + + // Reset the user data + ioCollector.SetUserData(0); +} + +void CharacterVsCharacterCollisionSimple::CastCharacter(const CharacterVirtual *inCharacter, RMat44Arg inCenterOfMassTransform, Vec3Arg inDirection, const ShapeCastSettings &inShapeCastSettings, RVec3Arg inBaseOffset, CastShapeCollector &ioCollector) const +{ + // Convert shape cast relative to inBaseOffset + Mat44 transform1 = inCenterOfMassTransform.PostTranslated(-inBaseOffset).ToMat44(); + ShapeCast shape_cast(inCharacter->GetShape(), Vec3::sReplicate(1.0f), transform1, inDirection); + + // Iterate over all characters + for (const CharacterVirtual *c : mCharacters) + if (c != inCharacter + && !ioCollector.ShouldEarlyOut()) + { + // Collector needs to know which character we're colliding with + ioCollector.SetUserData(reinterpret_cast(c)); + + // Make shape 2 relative to inBaseOffset + Mat44 transform2 = c->GetCenterOfMassTransform().PostTranslated(-inBaseOffset).ToMat44(); + + // Note that this collides against the character's shape without padding, this will be corrected for in CharacterVirtual::GetFirstContactForSweep + CollisionDispatch::sCastShapeVsShapeWorldSpace(shape_cast, inShapeCastSettings, c->GetShape(), Vec3::sReplicate(1.0f), { }, transform2, SubShapeIDCreator(), SubShapeIDCreator(), ioCollector); + } + + // Reset the user data + ioCollector.SetUserData(0); +} + CharacterVirtual::CharacterVirtual(const CharacterVirtualSettings *inSettings, RVec3Arg inPosition, QuatArg inRotation, uint64 inUserData, PhysicsSystem *inSystem) : CharacterBase(inSettings, inSystem), mBackFaceMode(inSettings->mBackFaceMode), @@ -41,6 +104,30 @@ CharacterVirtual::CharacterVirtual(const CharacterVirtualSettings *inSettings, R // Copy settings SetMaxStrength(inSettings->mMaxStrength); SetMass(inSettings->mMass); + + // Create an inner rigid body if requested + if (inSettings->mInnerBodyShape != nullptr) + { + BodyCreationSettings settings(inSettings->mInnerBodyShape, GetInnerBodyPosition(), mRotation, EMotionType::Kinematic, inSettings->mInnerBodyLayer); + settings.mAllowSleeping = false; // Disable sleeping so that we will receive sensor callbacks + settings.mUserData = inUserData; + mInnerBodyID = inSystem->GetBodyInterface().CreateAndAddBody(settings, EActivation::Activate); + } +} + +CharacterVirtual::~CharacterVirtual() +{ + if (!mInnerBodyID.IsInvalid()) + { + mSystem->GetBodyInterface().RemoveBody(mInnerBodyID); + mSystem->GetBodyInterface().DestroyBody(mInnerBodyID); + } +} + +void CharacterVirtual::UpdateInnerBodyTransform() +{ + if (!mInnerBodyID.IsInvalid()) + mSystem->GetBodyInterface().SetPositionAndRotation(mInnerBodyID, GetInnerBodyPosition(), mRotation, EActivation::DontActivate); } void CharacterVirtual::GetAdjustedBodyVelocity(const Body& inBody, Vec3 &outLinearVelocity, Vec3 &outAngularVelocity) const @@ -104,6 +191,20 @@ void CharacterVirtual::sFillContactProperties(const CharacterVirtual *inCharacte outContact.mMaterial = inCollector.GetContext()->GetMaterial(inResult.mSubShapeID2); } +void CharacterVirtual::sFillCharacterContactProperties(Contact &outContact, CharacterVirtual *inOtherCharacter, RVec3Arg inBaseOffset, const CollideShapeResult &inResult) +{ + outContact.mPosition = inBaseOffset + inResult.mContactPointOn2; + outContact.mLinearVelocity = inOtherCharacter->GetLinearVelocity(); + outContact.mSurfaceNormal = outContact.mContactNormal = -inResult.mPenetrationAxis.NormalizedOr(Vec3::sZero()); + outContact.mDistance = -inResult.mPenetrationDepth; + outContact.mCharacterB = inOtherCharacter; + outContact.mSubShapeIDB = inResult.mSubShapeID2; + outContact.mMotionTypeB = EMotionType::Kinematic; // Other character is kinematic, we can't directly move it + outContact.mIsSensorB = false; + outContact.mUserData = inOtherCharacter->GetUserData(); + outContact.mMaterial = PhysicsMaterial::sDefault; +} + void CharacterVirtual::ContactCollector::AddHit(const CollideShapeResult &inResult) { // If we exceed our contact limit, try to clean up near-duplicate contacts @@ -122,7 +223,7 @@ void CharacterVirtual::ContactCollector::AddHit(const CollideShapeResult &inResu for (int j = i - 1; j >= 0; --j) { Contact &contact_j = mContacts[j]; - if (contact_i.mBodyB == contact_j.mBodyB // Same body + if (contact_i.IsSameBody(contact_j) && contact_i.mContactNormal.Dot(contact_j.mContactNormal) > mHitReductionCosMaxAngle) // Very similar contact normals { // Remove the contact with the biggest distance @@ -160,22 +261,35 @@ void CharacterVirtual::ContactCollector::AddHit(const CollideShapeResult &inResu } } - BodyLockRead lock(mSystem->GetBodyLockInterface(), inResult.mBodyID2); - if (lock.SucceededAndIsInBroadPhase()) + if (inResult.mBodyID2.IsInvalid()) { + // Assuming this is a hit against another character + JPH_ASSERT(mOtherCharacter != nullptr); + + // Create contact with other character mContacts.emplace_back(); Contact &contact = mContacts.back(); - sFillContactProperties(mCharacter, contact, lock.GetBody(), mUp, mBaseOffset, *this, inResult); + sFillCharacterContactProperties(contact, mOtherCharacter, mBaseOffset, inResult); contact.mFraction = 0.0f; } + else + { + // Create contact with other body + BodyLockRead lock(mSystem->GetBodyLockInterface(), inResult.mBodyID2); + if (lock.SucceededAndIsInBroadPhase()) + { + mContacts.emplace_back(); + Contact &contact = mContacts.back(); + sFillContactProperties(mCharacter, contact, lock.GetBody(), mUp, mBaseOffset, *this, inResult); + contact.mFraction = 0.0f; + } + } } void CharacterVirtual::ContactCastCollector::AddHit(const ShapeCastResult &inResult) { - // Should not have gotten here without a lower fraction - JPH_ASSERT(inResult.mFraction < mContact.mFraction); - - if (inResult.mFraction > 0.0f // Ignore collisions at fraction = 0 + if (inResult.mFraction < mContact.mFraction // Since we're doing checks against the world and against characters, we may get a hit with a higher fraction than the previous hit + && inResult.mFraction > 0.0f // Ignore collisions at fraction = 0 && inResult.mPenetrationAxis.Dot(mDisplacement) > 0.0f) // Ignore penetrations that we're moving away from { // Test if this contact should be ignored @@ -185,8 +299,17 @@ void CharacterVirtual::ContactCastCollector::AddHit(const ShapeCastResult &inRes Contact contact; - // Lock body only while we fetch contact properties + if (inResult.mBodyID2.IsInvalid()) { + // Assuming this is a hit against another character + JPH_ASSERT(mOtherCharacter != nullptr); + + // Create contact with other character + sFillCharacterContactProperties(contact, mOtherCharacter, mBaseOffset, inResult); + } + else + { + // Lock body only while we fetch contact properties BodyLockRead lock(mSystem->GetBodyLockInterface(), inResult.mBodyID2); if (!lock.SucceededAndIsInBroadPhase()) return; @@ -219,15 +342,18 @@ void CharacterVirtual::CheckCollision(RVec3Arg inPosition, QuatArg inRotation, V // Settings for collide shape CollideShapeSettings settings; - settings.mActiveEdgeMode = EActiveEdgeMode::CollideOnlyWithActive; settings.mBackFaceMode = mBackFaceMode; settings.mActiveEdgeMovementDirection = inMovementDirection; settings.mMaxSeparationDistance = mCharacterPadding + inMaxSeparationDistance; + // Body filter + IgnoreSingleBodyFilterChained body_filter(mInnerBodyID, inBodyFilter); + // Collide shape if (mEnhancedInternalEdgeRemoval) { // Version that does additional work to remove internal edges + settings.mActiveEdgeMode = EActiveEdgeMode::CollideWithAll; settings.mCollectFacesMode = ECollectFacesMode::CollectFaces; // This is a copy of NarrowPhaseQuery::CollideShape with additional logic to wrap the collector in an InternalEdgeRemovingCollector and flushing that collector after every body @@ -287,11 +413,23 @@ void CharacterVirtual::CheckCollision(RVec3Arg inPosition, QuatArg inRotation, V bounds.ExpandBy(Vec3::sReplicate(settings.mMaxSeparationDistance)); // Do broadphase test - MyCollector collector(inShape, transform, settings, inBaseOffset, ioCollector, mSystem->GetBodyLockInterface(), inBodyFilter, inShapeFilter); + MyCollector collector(inShape, transform, settings, inBaseOffset, ioCollector, mSystem->GetBodyLockInterface(), body_filter, inShapeFilter); mSystem->GetBroadPhaseQuery().CollideAABox(bounds, collector, inBroadPhaseLayerFilter, inObjectLayerFilter); } else - mSystem->GetNarrowPhaseQuery().CollideShape(inShape, Vec3::sReplicate(1.0f), transform, settings, inBaseOffset, ioCollector, inBroadPhaseLayerFilter, inObjectLayerFilter, inBodyFilter, inShapeFilter); + { + // Version that uses the cached active edges + settings.mActiveEdgeMode = EActiveEdgeMode::CollideOnlyWithActive; + + mSystem->GetNarrowPhaseQuery().CollideShape(inShape, Vec3::sReplicate(1.0f), transform, settings, inBaseOffset, ioCollector, inBroadPhaseLayerFilter, inObjectLayerFilter, body_filter, inShapeFilter); + } + + // Also collide with other characters + if (mCharacterVsCharacterCollision != nullptr) + { + ioCollector.SetContext(nullptr); // We're no longer colliding with a transformed shape, reset + mCharacterVsCharacterCollision->CollideCharacter(this, transform, settings, inBaseOffset, ioCollector); + } } void CharacterVirtual::GetContactsAtPosition(RVec3Arg inPosition, Vec3Arg inMovementDirection, const Shape *inShape, TempContactList &outContacts, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) const @@ -299,9 +437,12 @@ void CharacterVirtual::GetContactsAtPosition(RVec3Arg inPosition, Vec3Arg inMove // Remove previous results outContacts.clear(); + // Body filter + IgnoreSingleBodyFilterChained body_filter(mInnerBodyID, inBodyFilter); + // Collide shape ContactCollector collector(mSystem, this, mMaxNumHits, mHitReductionCosMaxAngle, mUp, mPosition, outContacts); - CheckCollision(inPosition, mRotation, inMovementDirection, mPredictiveContactDistance, inShape, mPosition, collector, inBroadPhaseLayerFilter, inObjectLayerFilter, inBodyFilter, inShapeFilter); + CheckCollision(inPosition, mRotation, inMovementDirection, mPredictiveContactDistance, inShape, mPosition, collector, inBroadPhaseLayerFilter, inObjectLayerFilter, body_filter, inShapeFilter); // The broadphase bounding boxes will not be deterministic, which means that the order in which the contacts are received by the collector is not deterministic. // Therefore we need to sort the contacts to preserve determinism. Note that currently this will fail if we exceed mMaxNumHits hits. @@ -313,7 +454,12 @@ void CharacterVirtual::GetContactsAtPosition(RVec3Arg inPosition, Vec3Arg inMove // Reduce distance to contact by padding to ensure we stay away from the object by a little margin // (this will make collision detection cheaper - especially for sweep tests as they won't hit the surface if we're properly sliding) for (Contact &c : outContacts) + { c.mDistance -= mCharacterPadding; + + if (c.mCharacterB != nullptr) + c.mDistance -= c.mCharacterB->mCharacterPadding; + } } void CharacterVirtual::RemoveConflictingContacts(TempContactList &ioContacts, IgnoredContactList &outIgnoredContacts) const @@ -330,7 +476,7 @@ void CharacterVirtual::RemoveConflictingContacts(TempContactList &ioContacts, Ig for (size_t c2 = c1 + 1; c2 < ioContacts.size(); c2++) { Contact &contact2 = ioContacts[c2]; - if (contact1.mBodyB == contact2.mBodyB // Only same body + if (contact1.IsSameBody(contact2) && contact2.mDistance <= -cMinRequiredPenetration // Only for penetrations && contact1.mContactNormal.Dot(contact2.mContactNormal) < 0.0f) // Only opposing normals { @@ -360,7 +506,21 @@ bool CharacterVirtual::ValidateContact(const Contact &inContact) const if (mListener == nullptr) return true; - return mListener->OnContactValidate(this, inContact.mBodyB, inContact.mSubShapeIDB); + if (inContact.mCharacterB != nullptr) + return mListener->OnCharacterContactValidate(this, inContact.mCharacterB, inContact.mSubShapeIDB); + else + return mListener->OnContactValidate(this, inContact.mBodyB, inContact.mSubShapeIDB); +} + +void CharacterVirtual::ContactAdded(const Contact &inContact, CharacterContactSettings &ioSettings) const +{ + if (mListener != nullptr) + { + if (inContact.mCharacterB != nullptr) + mListener->OnCharacterContactAdded(this, inContact.mCharacterB, inContact.mSubShapeIDB, inContact.mPosition, -inContact.mContactNormal, ioSettings); + else + mListener->OnContactAdded(this, inContact.mBodyB, inContact.mSubShapeIDB, inContact.mPosition, -inContact.mContactNormal, ioSettings); + } } template @@ -410,30 +570,58 @@ bool CharacterVirtual::GetFirstContactForSweep(RVec3Arg inPosition, Vec3Arg inDi // Calculate how much extra fraction we need to add to the cast to account for the character padding float character_padding_fraction = mCharacterPadding / sqrt(displacement_len_sq); + // Body filter + IgnoreSingleBodyFilterChained body_filter(mInnerBodyID, inBodyFilter); + // Cast shape Contact contact; contact.mFraction = 1.0f + character_padding_fraction; - ContactCastCollector collector(mSystem, this, inDisplacement, mUp, inIgnoredContacts, start.GetTranslation(), contact); + RVec3 base_offset = start.GetTranslation(); + ContactCastCollector collector(mSystem, this, inDisplacement, mUp, inIgnoredContacts, base_offset, contact); collector.ResetEarlyOutFraction(contact.mFraction); RShapeCast shape_cast(mShape, Vec3::sReplicate(1.0f), start, inDisplacement); - mSystem->GetNarrowPhaseQuery().CastShape(shape_cast, settings, start.GetTranslation(), collector, inBroadPhaseLayerFilter, inObjectLayerFilter, inBodyFilter, inShapeFilter); - if (contact.mBodyB.IsInvalid()) + mSystem->GetNarrowPhaseQuery().CastShape(shape_cast, settings, base_offset, collector, inBroadPhaseLayerFilter, inObjectLayerFilter, body_filter, inShapeFilter); + + // Also collide with other characters + if (mCharacterVsCharacterCollision != nullptr) + { + collector.SetContext(nullptr); // We're no longer colliding with a transformed shape, reset + mCharacterVsCharacterCollision->CastCharacter(this, start, inDisplacement, settings, base_offset, collector); + } + + if (contact.mBodyB.IsInvalid() && contact.mCharacterB == nullptr) return false; // Store contact outContact = contact; + TransformedShape ts; + float character_padding = mCharacterPadding; + if (outContact.mCharacterB != nullptr) + { + // Create a transformed shape for the character + RMat44 com = outContact.mCharacterB->GetCenterOfMassTransform(); + ts = TransformedShape(com.GetTranslation(), com.GetQuaternion(), outContact.mCharacterB->GetShape(), BodyID(), SubShapeIDCreator()); + + // We need to take the other character's padding into account as well + character_padding += outContact.mCharacterB->mCharacterPadding; + } + else + { + // Create a transformed shape for the body + ts = mSystem->GetBodyInterface().GetTransformedShape(outContact.mBodyB); + } + // Fetch the face we're colliding with - TransformedShape ts = mSystem->GetBodyInterface().GetTransformedShape(outContact.mBodyB); Shape::SupportingFace face; - ts.GetSupportingFace(outContact.mSubShapeIDB, -outContact.mContactNormal, start.GetTranslation(), face); + ts.GetSupportingFace(outContact.mSubShapeIDB, -outContact.mContactNormal, base_offset, face); bool corrected = false; if (face.size() >= 2) { // Inflate the colliding face by the character padding PolygonConvexSupport polygon(face); - AddConvexRadius add_cvx(polygon, mCharacterPadding); + AddConvexRadius add_cvx(polygon, character_padding); // Correct fraction to hit this inflated face instead of the inner shape corrected = sCorrectFractionForCharacterPadding(mShape, start.GetRotation(), inDisplacement, add_cvx, outContact.mFraction); @@ -503,8 +691,7 @@ bool CharacterVirtual::HandleContact(Vec3Arg inVelocity, Constraint &ioConstrain // Send contact added event CharacterContactSettings settings; - if (mListener != nullptr) - mListener->OnContactAdded(this, contact.mBodyB, contact.mSubShapeIDB, contact.mPosition, -contact.mContactNormal, settings); + ContactAdded(contact, settings); contact.mCanPushCharacter = settings.mCanPushCharacter; // We don't have any further interaction with sensors beyond an OnContactAdded notification @@ -776,7 +963,12 @@ void CharacterVirtual::SolveConstraints(Vec3Arg inVelocity, float inDeltaTime, f // Allow application to modify calculated velocity if (mListener != nullptr) - mListener->OnContactSolve(this, constraint->mContact->mBodyB, constraint->mContact->mSubShapeIDB, constraint->mContact->mPosition, constraint->mContact->mContactNormal, constraint->mContact->mLinearVelocity, constraint->mContact->mMaterial, velocity, new_velocity); + { + if (constraint->mContact->mCharacterB != nullptr) + mListener->OnCharacterContactSolve(this, constraint->mContact->mCharacterB, constraint->mContact->mSubShapeIDB, constraint->mContact->mPosition, constraint->mContact->mContactNormal, constraint->mContact->mLinearVelocity, constraint->mContact->mMaterial, velocity, new_velocity); + else + mListener->OnContactSolve(this, constraint->mContact->mBodyB, constraint->mContact->mSubShapeIDB, constraint->mContact->mPosition, constraint->mContact->mContactNormal, constraint->mContact->mLinearVelocity, constraint->mContact->mMaterial, velocity, new_velocity); + } #ifdef JPH_DEBUG_RENDERER if (inDrawConstraints) @@ -1088,6 +1280,14 @@ void CharacterVirtual::MoveShape(RVec3 &ioPosition, Vec3Arg inVelocity, float in } } +void CharacterVirtual::SetUserData(uint64 inUserData) +{ + mUserData = inUserData; + + if (!mInnerBodyID.IsInvalid()) + mSystem->GetBodyInterface().SetUserData(mInnerBodyID, inUserData); +} + Vec3 CharacterVirtual::CancelVelocityTowardsSteepSlopes(Vec3Arg inDesiredVelocity) const { // If we're not pushing against a steep slope, return the desired velocity @@ -1134,6 +1334,9 @@ void CharacterVirtual::Update(float inDeltaTime, Vec3Arg inGravity, const BroadP // Determine the object that we're standing on UpdateSupportingContact(false, inAllocator); + // Ensure that the rigid body ends up at the new position + UpdateInnerBodyTransform(); + // If we're on the ground if (!mGroundBodyID.IsInvalid() && mMass > 0.0f) { @@ -1178,6 +1381,10 @@ void CharacterVirtual::MoveToContact(RVec3Arg inPosition, const Contact &inConta // Set the new position SetPosition(inPosition); + // Trigger contact added callback + CharacterContactSettings dummy; + ContactAdded(inContact, dummy); + // Determine the contacts TempContactList contacts(inAllocator); contacts.reserve(mMaxNumHits + 1); // +1 because we can add one extra below @@ -1202,6 +1409,9 @@ void CharacterVirtual::MoveToContact(RVec3Arg inPosition, const Contact &inConta StoreActiveContacts(contacts, inAllocator); JPH_ASSERT(mGroundState != EGroundState::InAir); + + // Ensure that the rigid body ends up at the new position + UpdateInnerBodyTransform(); } bool CharacterVirtual::SetShape(const Shape *inShape, float inMaxPenetrationDepth, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter, TempAllocator &inAllocator) @@ -1238,6 +1448,11 @@ bool CharacterVirtual::SetShape(const Shape *inShape, float inMaxPenetrationDept return mShape == inShape; } +void CharacterVirtual::SetInnerBodyShape(const Shape *inShape) +{ + mSystem->GetBodyInterface().SetShape(mInnerBodyID, inShape, false, EActivation::DontActivate); +} + bool CharacterVirtual::CanWalkStairs(Vec3Arg inLinearVelocity) const { // We can only walk stairs if we're supported diff --git a/WickedEngine/Jolt/Physics/Character/CharacterVirtual.h b/WickedEngine/Jolt/Physics/Character/CharacterVirtual.h index 8df82f1a9..65b8f89df 100644 --- a/WickedEngine/Jolt/Physics/Character/CharacterVirtual.h +++ b/WickedEngine/Jolt/Physics/Character/CharacterVirtual.h @@ -9,11 +9,13 @@ #include #include #include +#include #include JPH_NAMESPACE_BEGIN class CharacterVirtual; +class CollideShapeSettings; /// Contains the configuration of a character class JPH_EXPORT CharacterVirtualSettings : public CharacterBaseSettings @@ -41,14 +43,28 @@ public: uint mMaxNumHits = 256; ///< Max num hits to collect in order to avoid excess of contact points collection float mHitReductionCosMaxAngle = 0.999f; ///< Cos(angle) where angle is the maximum angle between two hits contact normals that are allowed to be merged during hit reduction. Default is around 2.5 degrees. Set to -1 to turn off. float mPenetrationRecoverySpeed = 1.0f; ///< This value governs how fast a penetration will be resolved, 0 = nothing is resolved, 1 = everything in one update + + /// This character can optionally have an inner rigid body. This rigid body can be used to give the character presence in the world. When set it means that: + /// - Regular collision checks (e.g. NarrowPhaseQuery::CastRay) will collide with the rigid body (they cannot collide with CharacterVirtual since it is not added to the broad phase) + /// - Regular contact callbacks will be called through the ContactListener (next to the ones that will be passed to the CharacterContactListener) + /// - Fast moving objects of motion quality LinearCast will not be able to pass through the CharacterVirtual in 1 time step + RefConst mInnerBodyShape; + + /// Layer that the inner rigid body will be added to + ObjectLayer mInnerBodyLayer = 0; }; /// This class contains settings that allow you to override the behavior of a character's collision response class CharacterContactSettings { public: - bool mCanPushCharacter = true; ///< True when the object can push the virtual character - bool mCanReceiveImpulses = true; ///< True when the virtual character can apply impulses (push) the body + /// True when the object can push the virtual character. + bool mCanPushCharacter = true; + + /// True when the virtual character can apply impulses (push) the body. + /// Note that this only works against rigid bodies. Other CharacterVirtual objects can only be moved in their own update, + /// so you must ensure that in their OnCharacterContactAdded mCanPushCharacter is true. + bool mCanReceiveImpulses = true; }; /// This class receives callbacks when a virtual character hits something. @@ -65,6 +81,9 @@ public: /// Checks if a character can collide with specified body. Return true if the contact is valid. virtual bool OnContactValidate(const CharacterVirtual *inCharacter, const BodyID &inBodyID2, const SubShapeID &inSubShapeID2) { return true; } + /// Same as OnContactValidate but when colliding with a CharacterVirtual + virtual bool OnCharacterContactValidate(const CharacterVirtual *inCharacter, const CharacterVirtual *inOtherCharacter, const SubShapeID &inSubShapeID2) { return true; } + /// Called whenever the character collides with a body. /// @param inCharacter Character that is being solved /// @param inBodyID2 Body ID of body that is being hit @@ -74,6 +93,9 @@ public: /// @param ioSettings Settings returned by the contact callback to indicate how the character should behave virtual void OnContactAdded(const CharacterVirtual *inCharacter, const BodyID &inBodyID2, const SubShapeID &inSubShapeID2, RVec3Arg inContactPosition, Vec3Arg inContactNormal, CharacterContactSettings &ioSettings) { /* Default do nothing */ } + /// Same as OnContactAdded but when colliding with a CharacterVirtual + virtual void OnCharacterContactAdded(const CharacterVirtual *inCharacter, const CharacterVirtual *inOtherCharacter, const SubShapeID &inSubShapeID2, RVec3Arg inContactPosition, Vec3Arg inContactNormal, CharacterContactSettings &ioSettings) { /* Default do nothing */ } + /// Called whenever a contact is being used by the solver. Allows the listener to override the resulting character velocity (e.g. by preventing sliding along certain surfaces). /// @param inCharacter Character that is being solved /// @param inBodyID2 Body ID of body that is being hit @@ -85,6 +107,53 @@ public: /// @param inCharacterVelocity World space velocity of the character prior to hitting this contact /// @param ioNewCharacterVelocity Contains the calculated world space velocity of the character after hitting this contact, this velocity slides along the surface of the contact. Can be modified by the listener to provide an alternative velocity. virtual void OnContactSolve(const CharacterVirtual *inCharacter, const BodyID &inBodyID2, const SubShapeID &inSubShapeID2, RVec3Arg inContactPosition, Vec3Arg inContactNormal, Vec3Arg inContactVelocity, const PhysicsMaterial *inContactMaterial, Vec3Arg inCharacterVelocity, Vec3 &ioNewCharacterVelocity) { /* Default do nothing */ } + + /// Same as OnContactSolve but when colliding with a CharacterVirtual + virtual void OnCharacterContactSolve(const CharacterVirtual *inCharacter, const CharacterVirtual *inOtherCharacter, const SubShapeID &inSubShapeID2, RVec3Arg inContactPosition, Vec3Arg inContactNormal, Vec3Arg inContactVelocity, const PhysicsMaterial *inContactMaterial, Vec3Arg inCharacterVelocity, Vec3 &ioNewCharacterVelocity) { /* Default do nothing */ } +}; + +/// Interface class that allows a CharacterVirtual to check collision with other CharacterVirtual instances. +/// Since CharacterVirtual instances are not registered anywhere, it is up to the application to test collision against relevant characters. +/// The characters could be stored in a tree structure to make this more efficient. +class JPH_EXPORT CharacterVsCharacterCollision : public NonCopyable +{ +public: + virtual ~CharacterVsCharacterCollision() = default; + + /// Collide a character against other CharacterVirtuals. + /// @param inCharacter The character to collide. + /// @param inCenterOfMassTransform Center of mass transform for this character. + /// @param inCollideShapeSettings Settings for the collision check. + /// @param inBaseOffset All hit results will be returned relative to this offset, can be zero to get results in world position, but when you're testing far from the origin you get better precision by picking a position that's closer e.g. GetPosition() since floats are most accurate near the origin + /// @param ioCollector Collision collector that receives the collision results. + virtual void CollideCharacter(const CharacterVirtual *inCharacter, RMat44Arg inCenterOfMassTransform, const CollideShapeSettings &inCollideShapeSettings, RVec3Arg inBaseOffset, CollideShapeCollector &ioCollector) const = 0; + + /// Cast a character against other CharacterVirtuals. + /// @param inCharacter The character to cast. + /// @param inCenterOfMassTransform Center of mass transform for this character. + /// @param inDirection Direction and length to cast in. + /// @param inShapeCastSettings Settings for the shape cast. + /// @param inBaseOffset All hit results will be returned relative to this offset, can be zero to get results in world position, but when you're testing far from the origin you get better precision by picking a position that's closer e.g. GetPosition() since floats are most accurate near the origin + /// @param ioCollector Collision collector that receives the collision results. + virtual void CastCharacter(const CharacterVirtual *inCharacter, RMat44Arg inCenterOfMassTransform, Vec3Arg inDirection, const ShapeCastSettings &inShapeCastSettings, RVec3Arg inBaseOffset, CastShapeCollector &ioCollector) const = 0; +}; + +/// Simple collision checker that loops over all registered characters. +/// Note that this is not thread safe, so make sure that only one CharacterVirtual is checking collision at a time. +class JPH_EXPORT CharacterVsCharacterCollisionSimple : public CharacterVsCharacterCollision +{ +public: + /// Add a character to the list of characters to check collision against. + void Add(CharacterVirtual *inCharacter) { mCharacters.push_back(inCharacter); } + + /// Remove a character from the list of characters to check collision against. + void Remove(const CharacterVirtual *inCharacter); + + // See: CharacterVsCharacterCollision + virtual void CollideCharacter(const CharacterVirtual *inCharacter, RMat44Arg inCenterOfMassTransform, const CollideShapeSettings &inCollideShapeSettings, RVec3Arg inBaseOffset, CollideShapeCollector &ioCollector) const override; + virtual void CastCharacter(const CharacterVirtual *inCharacter, RMat44Arg inCenterOfMassTransform, Vec3Arg inDirection, const ShapeCastSettings &inShapeCastSettings, RVec3Arg inBaseOffset, CastShapeCollector &ioCollector) const override; + + Array mCharacters; ///< The list of characters to check collision against }; /// Runtime character object. @@ -102,18 +171,24 @@ public: /// @param inPosition Initial position for the character /// @param inRotation Initial rotation for the character (usually only around the up-axis) /// @param inUserData Application specific value - /// @param inSystem Physics system that this character will be added to later + /// @param inSystem Physics system that this character will be added to CharacterVirtual(const CharacterVirtualSettings *inSettings, RVec3Arg inPosition, QuatArg inRotation, uint64 inUserData, PhysicsSystem *inSystem); /// Constructor without user data CharacterVirtual(const CharacterVirtualSettings *inSettings, RVec3Arg inPosition, QuatArg inRotation, PhysicsSystem *inSystem) : CharacterVirtual(inSettings, inPosition, inRotation, 0, inSystem) { } + /// Destructor + virtual ~CharacterVirtual() override; + /// Set the contact listener void SetListener(CharacterContactListener *inListener) { mListener = inListener; } /// Get the current contact listener CharacterContactListener * GetListener() const { return mListener; } + /// Set the character vs character collision interface + void SetCharacterVsCharacterCollision(CharacterVsCharacterCollision *inCharacterVsCharacterCollision) { mCharacterVsCharacterCollision = inCharacterVsCharacterCollision; } + /// Get the linear velocity of the character (m / s) Vec3 GetLinearVelocity() const { return mLinearVelocity; } @@ -124,13 +199,16 @@ public: RVec3 GetPosition() const { return mPosition; } /// Set the position of the character - void SetPosition(RVec3Arg inPosition) { mPosition = inPosition; } + void SetPosition(RVec3Arg inPosition) { mPosition = inPosition; UpdateInnerBodyTransform(); } /// Get the rotation of the character Quat GetRotation() const { return mRotation; } /// Set the rotation of the character - void SetRotation(QuatArg inRotation) { mRotation = inRotation; } + void SetRotation(QuatArg inRotation) { mRotation = inRotation; UpdateInnerBodyTransform(); } + + // Get the center of mass position of the shape + inline RVec3 GetCenterOfMassPosition() const { return mPosition + (mRotation * (mShapeOffset + mShape->GetCenterOfMass()) + mCharacterPadding * mUp); } /// Calculate the world transform of the character RMat44 GetWorldTransform() const { return RMat44::sRotationTranslation(mRotation, mPosition); } @@ -173,11 +251,14 @@ public: /// An extra offset applied to the shape in local space. This allows applying an extra offset to the shape in local space. Note that setting it on the fly can cause the shape to teleport into collision. Vec3 GetShapeOffset() const { return mShapeOffset; } - void SetShapeOffset(Vec3Arg inShapeOffset) { mShapeOffset = inShapeOffset; } + void SetShapeOffset(Vec3Arg inShapeOffset) { mShapeOffset = inShapeOffset; UpdateInnerBodyTransform(); } /// Access to the user data, can be used for anything by the application uint64 GetUserData() const { return mUserData; } - void SetUserData(uint64 inUserData) { mUserData = inUserData; } + void SetUserData(uint64 inUserData); + + /// Optional inner rigid body that proxies the character in the world. Can be used to update body properties. + BodyID GetInnerBodyID() const { return mInnerBodyID; } /// This function can be called prior to calling Update() to convert a desired velocity into a velocity that won't make the character move further onto steep slopes. /// This velocity can then be set on the character using SetLinearVelocity() @@ -271,7 +352,14 @@ public: /// @return Returns true if the switch succeeded. bool SetShape(const Shape *inShape, float inMaxPenetrationDepth, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter, TempAllocator &inAllocator); - /// @brief Get all contacts for the character at a particular location + /// Updates the shape of the inner rigid body. Should be called after a successful call to SetShape. + void SetInnerBodyShape(const Shape *inShape); + + /// Get the transformed shape that represents the volume of the character, can be used for collision checks. + TransformedShape GetTransformedShape() const { return TransformedShape(GetCenterOfMassPosition(), mRotation, mShape, mInnerBodyID); } + + /// @brief Get all contacts for the character at a particular location. + /// When colliding with another character virtual, this pointer will be provided through CollideShapeCollector::SetUserContext before adding a hit. /// @param inPosition Position to test, note that this position will be corrected for the character padding. /// @param inRotation Rotation at which to test the shape. /// @param inMovementDirection A hint in which direction the character is moving, will be used to calculate a proper normal. @@ -302,13 +390,17 @@ public: void SaveState(StateRecorder &inStream) const; void RestoreState(StateRecorder &inStream); + // Checks if two contacts refer to the same body (or virtual character) + inline bool IsSameBody(const Contact &inOther) const { return mBodyB == inOther.mBodyB && mCharacterB == inOther.mCharacterB; } + RVec3 mPosition; ///< Position where the character makes contact Vec3 mLinearVelocity; ///< Velocity of the contact point Vec3 mContactNormal; ///< Contact normal, pointing towards the character Vec3 mSurfaceNormal; ///< Surface normal of the contact float mDistance; ///< Distance to the contact <= 0 means that it is an actual contact, > 0 means predictive float mFraction; ///< Fraction along the path where this contact takes place - BodyID mBodyB; ///< ID of body we're colliding with + BodyID mBodyB; ///< ID of body we're colliding with (if not invalid) + CharacterVirtual * mCharacterB = nullptr; ///< Character we're colliding with (if not null) SubShapeID mSubShapeIDB; ///< Sub shape ID of body we're colliding with EMotionType mMotionTypeB; ///< Motion type of B, used to determine the priority of the contact bool mIsSensorB; ///< If B is a sensor @@ -325,6 +417,24 @@ public: /// Access to the internal list of contacts that the character has found. const ContactList & GetActiveContacts() const { return mActiveContacts; } + /// Check if the character is currently in contact with or has collided with another body in the last time step + bool HasCollidedWith(const BodyID &inBody) const + { + for (const CharacterVirtual::Contact &c : mActiveContacts) + if (c.mHadCollision && c.mBodyB == inBody) + return true; + return false; + } + + /// Check if the character is currently in contact with or has collided with another character in the last time step + bool HasCollidedWith(const CharacterVirtual *inCharacter) const + { + for (const CharacterVirtual::Contact &c : mActiveContacts) + if (c.mHadCollision && c.mCharacterB == inCharacter) + return true; + return false; + } + private: // Sorting predicate for making contact order deterministic struct ContactOrderingPredicate @@ -369,12 +479,15 @@ private: public: ContactCollector(PhysicsSystem *inSystem, const CharacterVirtual *inCharacter, uint inMaxHits, float inHitReductionCosMaxAngle, Vec3Arg inUp, RVec3Arg inBaseOffset, TempContactList &outContacts) : mBaseOffset(inBaseOffset), mUp(inUp), mSystem(inSystem), mCharacter(inCharacter), mContacts(outContacts), mMaxHits(inMaxHits), mHitReductionCosMaxAngle(inHitReductionCosMaxAngle) { } + virtual void SetUserData(uint64 inUserData) override { mOtherCharacter = reinterpret_cast(inUserData); } + virtual void AddHit(const CollideShapeResult &inResult) override; RVec3 mBaseOffset; Vec3 mUp; PhysicsSystem * mSystem; const CharacterVirtual * mCharacter; + CharacterVirtual * mOtherCharacter = nullptr; TempContactList & mContacts; uint mMaxHits; float mHitReductionCosMaxAngle; @@ -387,6 +500,8 @@ private: public: ContactCastCollector(PhysicsSystem *inSystem, const CharacterVirtual *inCharacter, Vec3Arg inDisplacement, Vec3Arg inUp, const IgnoredContactList &inIgnoredContacts, RVec3Arg inBaseOffset, Contact &outContact) : mBaseOffset(inBaseOffset), mDisplacement(inDisplacement), mUp(inUp), mSystem(inSystem), mCharacter(inCharacter), mIgnoredContacts(inIgnoredContacts), mContact(outContact) { } + virtual void SetUserData(uint64 inUserData) override { mOtherCharacter = reinterpret_cast(inUserData); } + virtual void AddHit(const ShapeCastResult &inResult) override; RVec3 mBaseOffset; @@ -394,6 +509,7 @@ private: Vec3 mUp; PhysicsSystem * mSystem; const CharacterVirtual * mCharacter; + CharacterVirtual * mOtherCharacter = nullptr; const IgnoredContactList & mIgnoredContacts; Contact & mContact; }; @@ -401,6 +517,7 @@ private: // Helper function to convert a Jolt collision result into a contact template inline static void sFillContactProperties(const CharacterVirtual *inCharacter, Contact &outContact, const Body &inBody, Vec3Arg inUp, RVec3Arg inBaseOffset, const taCollector &inCollector, const CollideShapeResult &inResult); + inline static void sFillCharacterContactProperties(Contact &outContact, CharacterVirtual *inOtherCharacter, RVec3Arg inBaseOffset, const CollideShapeResult &inResult); // Move the shape from ioPosition and try to displace it by inVelocity * inDeltaTime, this will try to slide the shape along the world geometry void MoveShape(RVec3 &ioPosition, Vec3Arg inVelocity, float inDeltaTime, ContactList *outActiveContacts, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter, TempAllocator &inAllocator @@ -412,6 +529,9 @@ private: // Ask the callback if inContact is a valid contact point bool ValidateContact(const Contact &inContact) const; + // Trigger the contact callback for inContact and get the contact settings + void ContactAdded(const Contact &inContact, CharacterContactSettings &ioSettings) const; + // Tests the shape for collision around inPosition void GetContactsAtPosition(RVec3Arg inPosition, Vec3Arg inMovementDirection, const Shape *inShape, TempContactList &outContacts, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) const; @@ -457,9 +577,21 @@ private: return RMat44::sRotationTranslation(inRotation, inPosition).PreTranslated(mShapeOffset + inShape->GetCenterOfMass()).PostTranslated(mCharacterPadding * mUp); } + // This function returns the position of the inner rigid body + inline RVec3 GetInnerBodyPosition() const + { + return mPosition + (mRotation * mShapeOffset + mCharacterPadding * mUp); + } + + // Move the inner rigid body to the current position + void UpdateInnerBodyTransform(); + // Our main listener for contacts CharacterContactListener * mListener = nullptr; + // Interface to detect collision between characters + CharacterVsCharacterCollision * mCharacterVsCharacterCollision = nullptr; + // Movement settings EBackFaceMode mBackFaceMode; // When colliding with back faces, the character will not be able to move through back facing triangles. Use this if you have triangles that need to collide on both sides. float mPredictiveContactDistance; // How far to scan outside of the shape for predictive contacts. A value of 0 will most likely cause the character to get stuck as it cannot properly calculate a sliding direction anymore. A value that's too high will cause ghost collisions. @@ -502,6 +634,9 @@ private: // User data, can be used for anything by the application uint64 mUserData = 0; + + // The inner rigid body that proxies the character in the world + BodyID mInnerBodyID; }; JPH_NAMESPACE_END diff --git a/WickedEngine/Jolt/Physics/Collision/BroadPhase/BroadPhaseLayer.h b/WickedEngine/Jolt/Physics/Collision/BroadPhase/BroadPhaseLayer.h index bd22cc3a5..bc591e733 100644 --- a/WickedEngine/Jolt/Physics/Collision/BroadPhase/BroadPhaseLayer.h +++ b/WickedEngine/Jolt/Physics/Collision/BroadPhase/BroadPhaseLayer.h @@ -19,7 +19,7 @@ class BroadPhaseLayer public: using Type = uint8; - JPH_INLINE BroadPhaseLayer() = default; + JPH_INLINE BroadPhaseLayer() = default; JPH_INLINE explicit constexpr BroadPhaseLayer(Type inValue) : mValue(inValue) { } JPH_INLINE constexpr BroadPhaseLayer(const BroadPhaseLayer &) = default; JPH_INLINE BroadPhaseLayer & operator = (const BroadPhaseLayer &) = default; @@ -57,7 +57,7 @@ private: static constexpr BroadPhaseLayer cBroadPhaseLayerInvalid(0xff); /// Interface that the application should implement to allow mapping object layers to broadphase layers -class BroadPhaseLayerInterface : public NonCopyable +class JPH_EXPORT BroadPhaseLayerInterface : public NonCopyable { public: /// Destructor @@ -76,7 +76,7 @@ public: }; /// Class to test if an object can collide with a broadphase layer. Used while finding collision pairs. -class ObjectVsBroadPhaseLayerFilter : public NonCopyable +class JPH_EXPORT ObjectVsBroadPhaseLayerFilter : public NonCopyable { public: /// Destructor @@ -90,7 +90,7 @@ public: }; /// Filter class for broadphase layers -class BroadPhaseLayerFilter : public NonCopyable +class JPH_EXPORT BroadPhaseLayerFilter : public NonCopyable { public: /// Destructor @@ -104,7 +104,7 @@ public: }; /// Default filter class that uses the pair filter in combination with a specified layer to filter layers -class DefaultBroadPhaseLayerFilter : public BroadPhaseLayerFilter +class JPH_EXPORT DefaultBroadPhaseLayerFilter : public BroadPhaseLayerFilter { public: /// Constructor @@ -126,7 +126,7 @@ private: }; /// Allows objects from a specific broad phase layer only -class SpecifiedBroadPhaseLayerFilter : public BroadPhaseLayerFilter +class JPH_EXPORT SpecifiedBroadPhaseLayerFilter : public BroadPhaseLayerFilter { public: /// Constructor diff --git a/WickedEngine/Jolt/Physics/Collision/BroadPhase/QuadTree.h b/WickedEngine/Jolt/Physics/Collision/BroadPhase/QuadTree.h index 94d36bc3b..4ce09cc5f 100644 --- a/WickedEngine/Jolt/Physics/Collision/BroadPhase/QuadTree.h +++ b/WickedEngine/Jolt/Physics/Collision/BroadPhase/QuadTree.h @@ -33,11 +33,11 @@ private: JPH_OVERRIDE_NEW_DELETE /// Default constructor does not initialize - inline NodeID() = default; + inline NodeID() = default; /// Construct a node ID static inline NodeID sInvalid() { return NodeID(cInvalidNodeIndex); } - static inline NodeID sFromBodyID(BodyID inID) { NodeID node_id(inID.GetIndexAndSequenceNumber()); JPH_ASSERT(node_id.IsBody()); return node_id; } + static inline NodeID sFromBodyID(BodyID inID) { NodeID node_id(inID.GetIndexAndSequenceNumber()); JPH_ASSERT(node_id.IsBody()); return node_id; } static inline NodeID sFromNodeIndex(uint32 inIdx) { NodeID node_id(inIdx | cIsNode); JPH_ASSERT(node_id.IsNode()); return node_id; } /// Check what type of ID it is diff --git a/WickedEngine/Jolt/Physics/Collision/CollisionCollector.h b/WickedEngine/Jolt/Physics/Collision/CollisionCollector.h index 274e8f032..ec6085027 100644 --- a/WickedEngine/Jolt/Physics/Collision/CollisionCollector.h +++ b/WickedEngine/Jolt/Physics/Collision/CollisionCollector.h @@ -70,6 +70,9 @@ public: void SetContext(const TransformedShape *inContext) { mContext = inContext; } const TransformedShape *GetContext() const { return mContext; } + /// This function can be used to set some user data on the collision collector + virtual void SetUserData(uint64 inUserData) { /* Does nothing by default */ } + /// This function will be called for every hit found, it's up to the application to decide how to store the hit virtual void AddHit(const ResultType &inResult) = 0; diff --git a/WickedEngine/Jolt/Physics/Collision/ObjectLayer.h b/WickedEngine/Jolt/Physics/Collision/ObjectLayer.h index f684e09e6..bfb9e6c9a 100644 --- a/WickedEngine/Jolt/Physics/Collision/ObjectLayer.h +++ b/WickedEngine/Jolt/Physics/Collision/ObjectLayer.h @@ -24,7 +24,7 @@ JPH_NAMESPACE_BEGIN static constexpr ObjectLayer cObjectLayerInvalid = ObjectLayer(~ObjectLayer(0U)); /// Filter class for object layers -class ObjectLayerFilter : public NonCopyable +class JPH_EXPORT ObjectLayerFilter : public NonCopyable { public: /// Destructor @@ -46,7 +46,7 @@ public: }; /// Filter class to test if two objects can collide based on their object layer. Used while finding collision pairs. -class ObjectLayerPairFilter : public NonCopyable +class JPH_EXPORT ObjectLayerPairFilter : public NonCopyable { public: /// Destructor @@ -60,7 +60,7 @@ public: }; /// Default filter class that uses the pair filter in combination with a specified layer to filter layers -class DefaultObjectLayerFilter : public ObjectLayerFilter +class JPH_EXPORT DefaultObjectLayerFilter : public ObjectLayerFilter { public: /// Constructor @@ -89,7 +89,7 @@ private: }; /// Allows objects from a specific layer only -class SpecifiedObjectLayerFilter : public ObjectLayerFilter +class JPH_EXPORT SpecifiedObjectLayerFilter : public ObjectLayerFilter { public: /// Constructor diff --git a/WickedEngine/Jolt/Physics/Collision/Shape/BoxShape.h b/WickedEngine/Jolt/Physics/Collision/Shape/BoxShape.h index dc53772d9..36d33db66 100644 --- a/WickedEngine/Jolt/Physics/Collision/Shape/BoxShape.h +++ b/WickedEngine/Jolt/Physics/Collision/Shape/BoxShape.h @@ -44,7 +44,7 @@ public: BoxShape(Vec3Arg inHalfExtent, float inConvexRadius = cDefaultConvexRadius, const PhysicsMaterial *inMaterial = nullptr) : ConvexShape(EShapeSubType::Box, inMaterial), mHalfExtent(inHalfExtent), mConvexRadius(inConvexRadius) { JPH_ASSERT(inConvexRadius >= 0.0f); JPH_ASSERT(inHalfExtent.ReduceMin() >= inConvexRadius); } /// Get half extent of box - Vec3 GetHalfExtent() const { return mHalfExtent; } + Vec3 GetHalfExtent() const { return mHalfExtent; } // See Shape::GetLocalBounds virtual AABox GetLocalBounds() const override { return AABox(-mHalfExtent, mHalfExtent); } diff --git a/WickedEngine/Jolt/Physics/Collision/Shape/CapsuleShape.cpp b/WickedEngine/Jolt/Physics/Collision/Shape/CapsuleShape.cpp index 1032505f2..d00552c45 100644 --- a/WickedEngine/Jolt/Physics/Collision/Shape/CapsuleShape.cpp +++ b/WickedEngine/Jolt/Physics/Collision/Shape/CapsuleShape.cpp @@ -380,15 +380,6 @@ void CapsuleShape::CollideSoftBodyVertices(Mat44Arg inCenterOfMassTransform, Vec } } -void CapsuleShape::TransformShape(Mat44Arg inCenterOfMassTransform, TransformedShapeCollector &ioCollector) const -{ - Vec3 scale; - Mat44 transform = inCenterOfMassTransform.Decompose(scale); - TransformedShape ts(RVec3(transform.GetTranslation()), transform.GetQuaternion(), this, BodyID(), SubShapeIDCreator()); - ts.SetShapeScale(ScaleHelpers::MakeUniformScale(scale.Abs())); - ioCollector.AddHit(ts); -} - void CapsuleShape::GetTrianglesStart(GetTrianglesContext &ioContext, const AABox &inBox, Vec3Arg inPositionCOM, QuatArg inRotation, Vec3Arg inScale) const { JPH_ASSERT(IsValidScale(inScale)); @@ -436,6 +427,13 @@ bool CapsuleShape::IsValidScale(Vec3Arg inScale) const return ConvexShape::IsValidScale(inScale) && ScaleHelpers::IsUniformScale(inScale.Abs()); } +Vec3 CapsuleShape::MakeScaleValid(Vec3Arg inScale) const +{ + Vec3 scale = ScaleHelpers::MakeNonZeroScale(inScale); + + return scale.GetSign() * ScaleHelpers::MakeUniformScale(scale.Abs()); +} + void CapsuleShape::sRegister() { ShapeFunctions &f = ShapeFunctions::sGet(EShapeSubType::Capsule); diff --git a/WickedEngine/Jolt/Physics/Collision/Shape/CapsuleShape.h b/WickedEngine/Jolt/Physics/Collision/Shape/CapsuleShape.h index 73281d0fe..a187553a8 100644 --- a/WickedEngine/Jolt/Physics/Collision/Shape/CapsuleShape.h +++ b/WickedEngine/Jolt/Physics/Collision/Shape/CapsuleShape.h @@ -88,9 +88,6 @@ public: // See: Shape::CollideSoftBodyVertices virtual void CollideSoftBodyVertices(Mat44Arg inCenterOfMassTransform, Vec3Arg inScale, SoftBodyVertex *ioVertices, uint inNumVertices, float inDeltaTime, Vec3Arg inDisplacementDueToGravity, int inCollidingShapeIndex) const override; - // See Shape::TransformShape - virtual void TransformShape(Mat44Arg inCenterOfMassTransform, TransformedShapeCollector &ioCollector) const override; - // See Shape::GetTrianglesStart virtual void GetTrianglesStart(GetTrianglesContext &ioContext, const AABox &inBox, Vec3Arg inPositionCOM, QuatArg inRotation, Vec3Arg inScale) const override; @@ -109,6 +106,9 @@ public: // See Shape::IsValidScale virtual bool IsValidScale(Vec3Arg inScale) const override; + // See Shape::MakeScaleValid + virtual Vec3 MakeScaleValid(Vec3Arg inScale) const override; + // Register shape functions with the registry static void sRegister(); diff --git a/WickedEngine/Jolt/Physics/Collision/Shape/CompoundShape.cpp b/WickedEngine/Jolt/Physics/Collision/Shape/CompoundShape.cpp index 20a61f28a..8d484bd91 100644 --- a/WickedEngine/Jolt/Physics/Collision/Shape/CompoundShape.cpp +++ b/WickedEngine/Jolt/Physics/Collision/Shape/CompoundShape.cpp @@ -388,6 +388,20 @@ bool CompoundShape::IsValidScale(Vec3Arg inScale) const return true; } +Vec3 CompoundShape::MakeScaleValid(Vec3Arg inScale) const +{ + Vec3 scale = ScaleHelpers::MakeNonZeroScale(inScale); + if (CompoundShape::IsValidScale(scale)) + return scale; + + Vec3 abs_uniform_scale = ScaleHelpers::MakeUniformScale(scale.Abs()); + Vec3 uniform_scale = scale.GetSign() * abs_uniform_scale; + if (CompoundShape::IsValidScale(uniform_scale)) + return uniform_scale; + + return Sign(scale.GetX()) * abs_uniform_scale; +} + void CompoundShape::sRegister() { for (EShapeSubType s1 : sCompoundSubShapeTypes) diff --git a/WickedEngine/Jolt/Physics/Collision/Shape/CompoundShape.h b/WickedEngine/Jolt/Physics/Collision/Shape/CompoundShape.h index 7694bf4e0..cc0468ad6 100644 --- a/WickedEngine/Jolt/Physics/Collision/Shape/CompoundShape.h +++ b/WickedEngine/Jolt/Physics/Collision/Shape/CompoundShape.h @@ -298,6 +298,9 @@ public: // See Shape::IsValidScale virtual bool IsValidScale(Vec3Arg inScale) const override; + // See Shape::MakeScaleValid + virtual Vec3 MakeScaleValid(Vec3Arg inScale) const override; + // Register shape functions with the registry static void sRegister(); diff --git a/WickedEngine/Jolt/Physics/Collision/Shape/CompoundShapeVisitors.h b/WickedEngine/Jolt/Physics/Collision/Shape/CompoundShapeVisitors.h index ecccb658a..1b1e3867b 100644 --- a/WickedEngine/Jolt/Physics/Collision/Shape/CompoundShapeVisitors.h +++ b/WickedEngine/Jolt/Physics/Collision/Shape/CompoundShapeVisitors.h @@ -19,7 +19,7 @@ JPH_NAMESPACE_BEGIN struct CompoundShape::CastRayVisitor { - JPH_INLINE CastRayVisitor(const RayCast &inRay, const CompoundShape *inShape, const SubShapeIDCreator &inSubShapeIDCreator, RayCastResult &ioHit) : + JPH_INLINE CastRayVisitor(const RayCast &inRay, const CompoundShape *inShape, const SubShapeIDCreator &inSubShapeIDCreator, RayCastResult &ioHit) : mRay(inRay), mHit(ioHit), mSubShapeIDCreator(inSubShapeIDCreator), @@ -64,7 +64,7 @@ struct CompoundShape::CastRayVisitor struct CompoundShape::CastRayVisitorCollector { - JPH_INLINE CastRayVisitorCollector(const RayCast &inRay, const RayCastSettings &inRayCastSettings, const CompoundShape *inShape, const SubShapeIDCreator &inSubShapeIDCreator, CastRayCollector &ioCollector, const ShapeFilter &inShapeFilter) : + JPH_INLINE CastRayVisitorCollector(const RayCast &inRay, const RayCastSettings &inRayCastSettings, const CompoundShape *inShape, const SubShapeIDCreator &inSubShapeIDCreator, CastRayCollector &ioCollector, const ShapeFilter &inShapeFilter) : mRay(inRay), mCollector(ioCollector), mSubShapeIDCreator(inSubShapeIDCreator), @@ -225,7 +225,7 @@ struct CompoundShape::CastShapeVisitor struct CompoundShape::CollectTransformedShapesVisitor { - JPH_INLINE CollectTransformedShapesVisitor(const AABox &inBox, const CompoundShape *inShape, Vec3Arg inPositionCOM, QuatArg inRotation, Vec3Arg inScale, const SubShapeIDCreator &inSubShapeIDCreator, TransformedShapeCollector &ioCollector, const ShapeFilter &inShapeFilter) : + JPH_INLINE CollectTransformedShapesVisitor(const AABox &inBox, const CompoundShape *inShape, Vec3Arg inPositionCOM, QuatArg inRotation, Vec3Arg inScale, const SubShapeIDCreator &inSubShapeIDCreator, TransformedShapeCollector &ioCollector, const ShapeFilter &inShapeFilter) : mBox(inBox), mLocalBox(Mat44::sInverseRotationTranslation(inRotation, inPositionCOM), inBox), mPositionCOM(inPositionCOM), @@ -271,8 +271,8 @@ struct CompoundShape::CollectTransformedShapesVisitor inSubShape.mShape->CollectTransformedShapes(mBox, position, rotation, inSubShape.TransformScale(mScale), sub_shape_id, mCollector, mShapeFilter); } - AABox mBox; - OrientedBox mLocalBox; + AABox mBox; + OrientedBox mLocalBox; Vec3 mPositionCOM; Quat mRotation; Vec3 mScale; diff --git a/WickedEngine/Jolt/Physics/Collision/Shape/CylinderShape.cpp b/WickedEngine/Jolt/Physics/Collision/Shape/CylinderShape.cpp index b08231cbb..d19d19f17 100644 --- a/WickedEngine/Jolt/Physics/Collision/Shape/CylinderShape.cpp +++ b/WickedEngine/Jolt/Physics/Collision/Shape/CylinderShape.cpp @@ -360,17 +360,6 @@ void CylinderShape::CollideSoftBodyVertices(Mat44Arg inCenterOfMassTransform, Ve } } -void CylinderShape::TransformShape(Mat44Arg inCenterOfMassTransform, TransformedShapeCollector &ioCollector) const -{ - Vec3 scale; - Mat44 transform = inCenterOfMassTransform.Decompose(scale); - TransformedShape ts(RVec3(transform.GetTranslation()), transform.GetQuaternion(), this, BodyID(), SubShapeIDCreator()); - Vec3 abs_scale = scale.Abs(); - float xz = 0.5f * (abs_scale.GetX() + abs_scale.GetZ()); - ts.SetShapeScale(Vec3(xz, abs_scale.GetY(), xz)); - ioCollector.AddHit(ts); -} - void CylinderShape::GetTrianglesStart(GetTrianglesContext &ioContext, const AABox &inBox, Vec3Arg inPositionCOM, QuatArg inRotation, Vec3Arg inScale) const { Mat44 unit_cylinder_transform(Vec4(mRadius, 0, 0, 0), Vec4(0, mHalfHeight, 0, 0), Vec4(0, 0, mRadius, 0), Vec4(0, 0, 0, 1)); @@ -407,6 +396,15 @@ bool CylinderShape::IsValidScale(Vec3Arg inScale) const return ConvexShape::IsValidScale(inScale) && abs_scale.Swizzle().IsClose(abs_scale, ScaleHelpers::cScaleToleranceSq); } +Vec3 CylinderShape::MakeScaleValid(Vec3Arg inScale) const +{ + Vec3 scale = ScaleHelpers::MakeNonZeroScale(inScale); + + // Average X and Z + Vec3 abs_scale = scale.Abs(); + return 0.5f * scale.GetSign() * (abs_scale + abs_scale.Swizzle()); +} + void CylinderShape::sRegister() { ShapeFunctions &f = ShapeFunctions::sGet(EShapeSubType::Cylinder); diff --git a/WickedEngine/Jolt/Physics/Collision/Shape/CylinderShape.h b/WickedEngine/Jolt/Physics/Collision/Shape/CylinderShape.h index 52108b13e..def0f9c50 100644 --- a/WickedEngine/Jolt/Physics/Collision/Shape/CylinderShape.h +++ b/WickedEngine/Jolt/Physics/Collision/Shape/CylinderShape.h @@ -83,9 +83,6 @@ public: // See: Shape::CollideSoftBodyVertices virtual void CollideSoftBodyVertices(Mat44Arg inCenterOfMassTransform, Vec3Arg inScale, SoftBodyVertex *ioVertices, uint inNumVertices, float inDeltaTime, Vec3Arg inDisplacementDueToGravity, int inCollidingShapeIndex) const override; - // See Shape::TransformShape - virtual void TransformShape(Mat44Arg inCenterOfMassTransform, TransformedShapeCollector &ioCollector) const override; - // See Shape::GetTrianglesStart virtual void GetTrianglesStart(GetTrianglesContext &ioContext, const AABox &inBox, Vec3Arg inPositionCOM, QuatArg inRotation, Vec3Arg inScale) const override; @@ -107,6 +104,9 @@ public: // See Shape::IsValidScale virtual bool IsValidScale(Vec3Arg inScale) const override; + // See Shape::MakeScaleValid + virtual Vec3 MakeScaleValid(Vec3Arg inScale) const override; + // Register shape functions with the registry static void sRegister(); diff --git a/WickedEngine/Jolt/Physics/Collision/Shape/DecoratedShape.h b/WickedEngine/Jolt/Physics/Collision/Shape/DecoratedShape.h index 5c97dcebc..e4f98a2ed 100644 --- a/WickedEngine/Jolt/Physics/Collision/Shape/DecoratedShape.h +++ b/WickedEngine/Jolt/Physics/Collision/Shape/DecoratedShape.h @@ -63,6 +63,12 @@ public: // See Shape::GetStatsRecursive virtual Stats GetStatsRecursive(VisitedShapes &ioVisitedShapes) const override; + // See Shape::IsValidScale + virtual bool IsValidScale(Vec3Arg inScale) const override { return mInnerShape->IsValidScale(inScale); } + + // See Shape::MakeScaleValid + virtual Vec3 MakeScaleValid(Vec3Arg inScale) const override { return mInnerShape->MakeScaleValid(inScale); } + protected: RefConst mInnerShape; }; diff --git a/WickedEngine/Jolt/Physics/Collision/Shape/MeshShape.cpp b/WickedEngine/Jolt/Physics/Collision/Shape/MeshShape.cpp index cf5e86403..d0ac1fb75 100644 --- a/WickedEngine/Jolt/Physics/Collision/Shape/MeshShape.cpp +++ b/WickedEngine/Jolt/Physics/Collision/Shape/MeshShape.cpp @@ -392,7 +392,7 @@ Vec3 MeshShape::GetSurfaceNormal(const SubShapeID &inSubShapeID, Vec3Arg inLocal const TriangleCodec::DecodingContext triangle_ctx(sGetTriangleHeader(mTree)); triangle_ctx.GetTriangle(block_start, triangle_idx, v1, v2, v3); - // Calculate normal + // Calculate normal return (v3 - v2).Cross(v1 - v2).Normalized(); } @@ -588,7 +588,7 @@ void MeshShape::Draw(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransfor { struct Visitor { - JPH_INLINE Visitor(DebugRenderer *inRenderer, RMat44Arg inTransform) : + JPH_INLINE Visitor(DebugRenderer *inRenderer, RMat44Arg inTransform) : mRenderer(inRenderer), mTransform(inTransform) { @@ -938,7 +938,7 @@ void MeshShape::sCastSphereVsMesh(const ShapeCast &inShapeCast, const ShapeCastS struct MeshShape::MSGetTrianglesContext { - JPH_INLINE MSGetTrianglesContext(const MeshShape *inShape, const AABox &inBox, Vec3Arg inPositionCOM, QuatArg inRotation, Vec3Arg inScale) : + JPH_INLINE MSGetTrianglesContext(const MeshShape *inShape, const AABox &inBox, Vec3Arg inPositionCOM, QuatArg inRotation, Vec3Arg inScale) : mDecodeCtx(sGetNodeHeader(inShape->mTree)), mShape(inShape), mLocalBox(Mat44::sInverseRotationTranslation(inRotation, inPositionCOM), inBox), diff --git a/WickedEngine/Jolt/Physics/Collision/Shape/MutableCompoundShape.cpp b/WickedEngine/Jolt/Physics/Collision/Shape/MutableCompoundShape.cpp index 755773de7..fdedc9a31 100644 --- a/WickedEngine/Jolt/Physics/Collision/Shape/MutableCompoundShape.cpp +++ b/WickedEngine/Jolt/Physics/Collision/Shape/MutableCompoundShape.cpp @@ -87,6 +87,21 @@ void MutableCompoundShape::AdjustCenterOfMass() for (CompoundShape::SubShape &sub_shape : mSubShapes) sub_shape.SetPositionCOM(sub_shape.GetPositionCOM() - center_of_mass); + // Update bounding boxes + for (Bounds &bounds : mSubShapeBounds) + { + Vec4 xxxx = center_of_mass.SplatX(); + Vec4 yyyy = center_of_mass.SplatY(); + Vec4 zzzz = center_of_mass.SplatZ(); + bounds.mMinX -= xxxx; + bounds.mMinY -= yyyy; + bounds.mMinZ -= zzzz; + bounds.mMaxX -= xxxx; + bounds.mMaxY -= yyyy; + bounds.mMaxZ -= zzzz; + } + mLocalBounds.Translate(-center_of_mass); + // And adjust the center of mass for this shape in the opposite direction mCenterOfMass += center_of_mass; } @@ -162,7 +177,7 @@ void MutableCompoundShape::CalculateSubShapeBounds(uint inStartIdx, uint inNumbe { const SubShape &sub_shape = mSubShapes[sub_shape_idx]; - // Tranform the shape's bounds into our local space + // Transform the shape's bounds into our local space Mat44 transform = Mat44::sRotationTranslation(sub_shape.GetRotation(), sub_shape.GetPositionCOM()); // Get the bounding box @@ -174,7 +189,7 @@ void MutableCompoundShape::CalculateSubShapeBounds(uint inStartIdx, uint inNumbe bounds_max.SetColumn3(col, sub_shape_bounds.mMax); } - // Transpose to go to strucucture of arrays format + // Transpose to go to structure of arrays format Mat44 bounds_min_t = bounds_min.Transposed(); Mat44 bounds_max_t = bounds_max.Transposed(); diff --git a/WickedEngine/Jolt/Physics/Collision/Shape/OffsetCenterOfMassShape.h b/WickedEngine/Jolt/Physics/Collision/Shape/OffsetCenterOfMassShape.h index 3e828181c..1774c5504 100644 --- a/WickedEngine/Jolt/Physics/Collision/Shape/OffsetCenterOfMassShape.h +++ b/WickedEngine/Jolt/Physics/Collision/Shape/OffsetCenterOfMassShape.h @@ -120,9 +120,6 @@ public: // See Shape::GetVolume virtual float GetVolume() const override { return mInnerShape->GetVolume(); } - // See Shape::IsValidScale - virtual bool IsValidScale(Vec3Arg inScale) const override { return mInnerShape->IsValidScale(inScale); } - // Register shape functions with the registry static void sRegister(); diff --git a/WickedEngine/Jolt/Physics/Collision/Shape/RotatedTranslatedShape.cpp b/WickedEngine/Jolt/Physics/Collision/Shape/RotatedTranslatedShape.cpp index 7d6e06a01..d031b4166 100644 --- a/WickedEngine/Jolt/Physics/Collision/Shape/RotatedTranslatedShape.cpp +++ b/WickedEngine/Jolt/Physics/Collision/Shape/RotatedTranslatedShape.cpp @@ -282,7 +282,7 @@ void RotatedTranslatedShape::RestoreBinaryState(StreamIn &inStream) bool RotatedTranslatedShape::IsValidScale(Vec3Arg inScale) const { - if (!DecoratedShape::IsValidScale(inScale)) + if (!Shape::IsValidScale(inScale)) return false; if (mIsRotationIdentity || ScaleHelpers::IsUniformScale(inScale)) @@ -294,6 +294,24 @@ bool RotatedTranslatedShape::IsValidScale(Vec3Arg inScale) const return mInnerShape->IsValidScale(ScaleHelpers::RotateScale(mRotation, inScale)); } +Vec3 RotatedTranslatedShape::MakeScaleValid(Vec3Arg inScale) const +{ + Vec3 scale = ScaleHelpers::MakeNonZeroScale(inScale); + + if (mIsRotationIdentity || ScaleHelpers::IsUniformScale(scale)) + return mInnerShape->MakeScaleValid(scale); + + if (ScaleHelpers::CanScaleBeRotated(mRotation, scale)) + return ScaleHelpers::RotateScale(mRotation.Conjugated(), mInnerShape->MakeScaleValid(ScaleHelpers::RotateScale(mRotation, scale))); + + Vec3 abs_uniform_scale = ScaleHelpers::MakeUniformScale(scale.Abs()); + Vec3 uniform_scale = scale.GetSign() * abs_uniform_scale; + if (ScaleHelpers::CanScaleBeRotated(mRotation, uniform_scale)) + return uniform_scale; + + return Sign(scale.GetX()) * abs_uniform_scale; +} + void RotatedTranslatedShape::sRegister() { ShapeFunctions &f = ShapeFunctions::sGet(EShapeSubType::RotatedTranslated); diff --git a/WickedEngine/Jolt/Physics/Collision/Shape/RotatedTranslatedShape.h b/WickedEngine/Jolt/Physics/Collision/Shape/RotatedTranslatedShape.h index c37dbca82..a27851b0f 100644 --- a/WickedEngine/Jolt/Physics/Collision/Shape/RotatedTranslatedShape.h +++ b/WickedEngine/Jolt/Physics/Collision/Shape/RotatedTranslatedShape.h @@ -124,6 +124,9 @@ public: // See Shape::IsValidScale virtual bool IsValidScale(Vec3Arg inScale) const override; + // See Shape::MakeScaleValid + virtual Vec3 MakeScaleValid(Vec3Arg inScale) const override; + // Register shape functions with the registry static void sRegister(); diff --git a/WickedEngine/Jolt/Physics/Collision/Shape/ScaleHelpers.h b/WickedEngine/Jolt/Physics/Collision/Shape/ScaleHelpers.h index ba20c2519..5ce2f8752 100644 --- a/WickedEngine/Jolt/Physics/Collision/Shape/ScaleHelpers.h +++ b/WickedEngine/Jolt/Physics/Collision/Shape/ScaleHelpers.h @@ -11,6 +11,9 @@ JPH_NAMESPACE_BEGIN /// Helper functions to get properties of a scaling vector namespace ScaleHelpers { + /// Minimum valid scale value. This is used to prevent division by zero when scaling a shape with a zero scale. + static constexpr float cMinScale = 1.0e-6f; + /// The tolerance used to check if components of the scale vector are the same static constexpr float cScaleToleranceSq = 1.0e-8f; @@ -26,6 +29,12 @@ namespace ScaleHelpers /// Test if a scale flips an object inside out (which requires flipping all normals and polygon windings) inline bool IsInsideOut(Vec3Arg inScale) { return (CountBits(Vec3::sLess(inScale, Vec3::sZero()).GetTrues() & 0x7) & 1) != 0; } + /// Test if any of the components of the scale have a value below cMinScale + inline bool IsZeroScale(Vec3Arg inScale) { return Vec3::sLess(inScale.Abs(), Vec3::sReplicate(cMinScale)).TestAnyXYZTrue(); } + + /// Ensure that the scale for each component is at least cMinScale + inline Vec3 MakeNonZeroScale(Vec3Arg inScale) { return inScale.GetSign() * Vec3::sMax(inScale.Abs(), Vec3::sReplicate(cMinScale)); } + /// Get the average scale if inScale, used to make the scale uniform when a shape doesn't support non-uniform scale inline Vec3 MakeUniformScale(Vec3Arg inScale) { return Vec3::sReplicate((inScale.GetX() + inScale.GetY() + inScale.GetZ()) / 3.0f); } diff --git a/WickedEngine/Jolt/Physics/Collision/Shape/ScaledShape.cpp b/WickedEngine/Jolt/Physics/Collision/Shape/ScaledShape.cpp index 10b1c83f3..9393f4cb0 100644 --- a/WickedEngine/Jolt/Physics/Collision/Shape/ScaledShape.cpp +++ b/WickedEngine/Jolt/Physics/Collision/Shape/ScaledShape.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -36,6 +37,12 @@ ScaledShape::ScaledShape(const ScaledShapeSettings &inSettings, ShapeResult &out if (outResult.HasError()) return; + if (ScaleHelpers::IsZeroScale(inSettings.mScale)) + { + outResult.SetError("Can't use zero scale!"); + return; + } + outResult.Set(this); } @@ -175,6 +182,11 @@ bool ScaledShape::IsValidScale(Vec3Arg inScale) const return mInnerShape->IsValidScale(inScale * mScale); } +Vec3 ScaledShape::MakeScaleValid(Vec3Arg inScale) const +{ + return mInnerShape->MakeScaleValid(mScale * inScale) / mScale; +} + void ScaledShape::sCollideScaledVsShape(const Shape *inShape1, const Shape *inShape2, Vec3Arg inScale1, Vec3Arg inScale2, Mat44Arg inCenterOfMassTransform1, Mat44Arg inCenterOfMassTransform2, const SubShapeIDCreator &inSubShapeIDCreator1, const SubShapeIDCreator &inSubShapeIDCreator2, const CollideShapeSettings &inCollideShapeSettings, CollideShapeCollector &ioCollector, const ShapeFilter &inShapeFilter) { JPH_ASSERT(inShape1->GetSubType() == EShapeSubType::Scaled); diff --git a/WickedEngine/Jolt/Physics/Collision/Shape/ScaledShape.h b/WickedEngine/Jolt/Physics/Collision/Shape/ScaledShape.h index ea9b34351..9b0fc5d9c 100644 --- a/WickedEngine/Jolt/Physics/Collision/Shape/ScaledShape.h +++ b/WickedEngine/Jolt/Physics/Collision/Shape/ScaledShape.h @@ -5,6 +5,7 @@ #pragma once #include +#include JPH_NAMESPACE_BEGIN @@ -42,10 +43,10 @@ public: ScaledShape(const ScaledShapeSettings &inSettings, ShapeResult &outResult); /// Constructor that decorates another shape with a scale - ScaledShape(const Shape *inShape, Vec3Arg inScale) : DecoratedShape(EShapeSubType::Scaled, inShape), mScale(inScale) { } + ScaledShape(const Shape *inShape, Vec3Arg inScale) : DecoratedShape(EShapeSubType::Scaled, inShape), mScale(inScale) { JPH_ASSERT(!ScaleHelpers::IsZeroScale(mScale)); } /// Get the scale - Vec3 GetScale() const { return mScale; } + Vec3 GetScale() const { return mScale; } // See Shape::GetCenterOfMass virtual Vec3 GetCenterOfMass() const override { return mScale * mInnerShape->GetCenterOfMass(); } @@ -120,6 +121,9 @@ public: // See Shape::IsValidScale virtual bool IsValidScale(Vec3Arg inScale) const override; + // See Shape::MakeScaleValid + virtual Vec3 MakeScaleValid(Vec3Arg inScale) const override; + // Register shape functions with the registry static void sRegister(); diff --git a/WickedEngine/Jolt/Physics/Collision/Shape/Shape.cpp b/WickedEngine/Jolt/Physics/Collision/Shape/Shape.cpp index 8412156f7..9c05cbbe8 100644 --- a/WickedEngine/Jolt/Physics/Collision/Shape/Shape.cpp +++ b/WickedEngine/Jolt/Physics/Collision/Shape/Shape.cpp @@ -59,7 +59,7 @@ void Shape::TransformShape(Mat44Arg inCenterOfMassTransform, TransformedShapeCol Vec3 scale; Mat44 transform = inCenterOfMassTransform.Decompose(scale); TransformedShape ts(RVec3(transform.GetTranslation()), transform.GetQuaternion(), this, BodyID(), SubShapeIDCreator()); - ts.SetShapeScale(scale); + ts.SetShapeScale(MakeScaleValid(scale)); ioCollector.AddHit(ts); } @@ -117,7 +117,7 @@ void Shape::SaveWithChildren(StreamOut &inStream, ShapeToIDMap &ioShapeMap, Mate // Write the ID's of all sub shapes ShapeList sub_shapes; SaveSubShapeState(sub_shapes); - inStream.Write(sub_shapes.size()); + inStream.Write(uint32(sub_shapes.size())); for (const Shape *shape : sub_shapes) { if (shape == nullptr) @@ -173,7 +173,7 @@ Shape::ShapeResult Shape::sRestoreWithChildren(StreamIn &inStream, IDToShapeMap ioShapeMap.push_back(result.Get()); // Read the sub shapes - size_t len; + uint32 len; inStream.Read(len); if (inStream.IsEOF() || inStream.IsFailed()) { @@ -215,6 +215,16 @@ Shape::Stats Shape::GetStatsRecursive(VisitedShapes &ioVisitedShapes) const return stats; } +bool Shape::IsValidScale(Vec3Arg inScale) const +{ + return !ScaleHelpers::IsZeroScale(inScale); +} + +Vec3 Shape::MakeScaleValid(Vec3Arg inScale) const +{ + return ScaleHelpers::MakeNonZeroScale(inScale); +} + Shape::ShapeResult Shape::ScaleShape(Vec3Arg inScale) const { const Vec3 unit_scale = Vec3::sReplicate(1.0f); diff --git a/WickedEngine/Jolt/Physics/Collision/Shape/Shape.h b/WickedEngine/Jolt/Physics/Collision/Shape/Shape.h index a61314483..a7dceacd3 100644 --- a/WickedEngine/Jolt/Physics/Collision/Shape/Shape.h +++ b/WickedEngine/Jolt/Physics/Collision/Shape/Shape.h @@ -170,7 +170,7 @@ public: static inline ShapeFunctions & sGet(EShapeSubType inSubType) { return sRegistry[int(inSubType)]; } private: - static ShapeFunctions sRegistry[NumSubShapeTypes]; + static ShapeFunctions sRegistry[NumSubShapeTypes]; }; /// Base class for all shapes (collision volume of a body). Defines a virtual interface for collision detection. @@ -424,7 +424,14 @@ public: /// * CylinderShape: Scale must be uniform in XZ plane, Y can scale independently (signs of scale are ignored). /// * RotatedTranslatedShape: Scale must not cause shear in the child shape. /// * CompoundShape: Scale must not cause shear in any of the child shapes. - virtual bool IsValidScale(Vec3Arg inScale) const { return !inScale.IsNearZero(); } + virtual bool IsValidScale(Vec3Arg inScale) const; + + /// This function will make sure that if you wrap this shape in a ScaledShape that the scale is valid. + /// Note that this involves discarding components of the scale that are invalid, so the resulting scaled shape may be different than the requested scale. + /// Compare the return value of this function with the scale you passed in to detect major inconsistencies and possibly warn the user. + /// @param inScale Local space scale for this shape. + /// @return Scale that can be used to wrap this shape in a ScaledShape. IsValidScale will return true for this scale. + virtual Vec3 MakeScaleValid(Vec3Arg inScale) const; #ifdef JPH_DEBUG_RENDERER /// Debug helper which draws the intersection between water and the shapes, the center of buoyancy and the submerged volume diff --git a/WickedEngine/Jolt/Physics/Collision/Shape/SphereShape.cpp b/WickedEngine/Jolt/Physics/Collision/Shape/SphereShape.cpp index 28577f7ec..6856d58e2 100644 --- a/WickedEngine/Jolt/Physics/Collision/Shape/SphereShape.cpp +++ b/WickedEngine/Jolt/Physics/Collision/Shape/SphereShape.cpp @@ -303,15 +303,6 @@ void SphereShape::CollideSoftBodyVertices(Mat44Arg inCenterOfMassTransform, Vec3 } } -void SphereShape::TransformShape(Mat44Arg inCenterOfMassTransform, TransformedShapeCollector &ioCollector) const -{ - Vec3 scale; - Mat44 transform = inCenterOfMassTransform.Decompose(scale); - TransformedShape ts(RVec3(transform.GetTranslation()), transform.GetQuaternion(), this, BodyID(), SubShapeIDCreator()); - ts.SetShapeScale(ScaleHelpers::MakeUniformScale(scale.Abs())); - ioCollector.AddHit(ts); -} - void SphereShape::GetTrianglesStart(GetTrianglesContext &ioContext, const AABox &inBox, Vec3Arg inPositionCOM, QuatArg inRotation, Vec3Arg inScale) const { float scaled_radius = GetScaledRadius(inScale); @@ -342,6 +333,13 @@ bool SphereShape::IsValidScale(Vec3Arg inScale) const return ConvexShape::IsValidScale(inScale) && ScaleHelpers::IsUniformScale(inScale.Abs()); } +Vec3 SphereShape::MakeScaleValid(Vec3Arg inScale) const +{ + Vec3 scale = ScaleHelpers::MakeNonZeroScale(inScale); + + return scale.GetSign() * ScaleHelpers::MakeUniformScale(scale.Abs()); +} + void SphereShape::sRegister() { ShapeFunctions &f = ShapeFunctions::sGet(EShapeSubType::Sphere); diff --git a/WickedEngine/Jolt/Physics/Collision/Shape/SphereShape.h b/WickedEngine/Jolt/Physics/Collision/Shape/SphereShape.h index 9d976948a..c84df100c 100644 --- a/WickedEngine/Jolt/Physics/Collision/Shape/SphereShape.h +++ b/WickedEngine/Jolt/Physics/Collision/Shape/SphereShape.h @@ -83,9 +83,6 @@ public: // See: Shape::CollideSoftBodyVertices virtual void CollideSoftBodyVertices(Mat44Arg inCenterOfMassTransform, Vec3Arg inScale, SoftBodyVertex *ioVertices, uint inNumVertices, float inDeltaTime, Vec3Arg inDisplacementDueToGravity, int inCollidingShapeIndex) const override; - // See Shape::TransformShape - virtual void TransformShape(Mat44Arg inCenterOfMassTransform, TransformedShapeCollector &ioCollector) const override; - // See Shape::GetTrianglesStart virtual void GetTrianglesStart(GetTrianglesContext &ioContext, const AABox &inBox, Vec3Arg inPositionCOM, QuatArg inRotation, Vec3Arg inScale) const override; @@ -104,6 +101,9 @@ public: // See Shape::IsValidScale virtual bool IsValidScale(Vec3Arg inScale) const override; + // See Shape::MakeScaleValid + virtual Vec3 MakeScaleValid(Vec3Arg inScale) const override; + // Register shape functions with the registry static void sRegister(); @@ -116,8 +116,8 @@ private: inline float GetScaledRadius(Vec3Arg inScale) const; // Classes for GetSupportFunction - class SphereNoConvex; - class SphereWithConvex; + class SphereNoConvex; + class SphereWithConvex; float mRadius = 0.0f; }; diff --git a/WickedEngine/Jolt/Physics/Collision/Shape/TaperedCapsuleShape.cpp b/WickedEngine/Jolt/Physics/Collision/Shape/TaperedCapsuleShape.cpp index 983864185..e540fdad0 100644 --- a/WickedEngine/Jolt/Physics/Collision/Shape/TaperedCapsuleShape.cpp +++ b/WickedEngine/Jolt/Physics/Collision/Shape/TaperedCapsuleShape.cpp @@ -406,15 +406,6 @@ AABox TaperedCapsuleShape::GetInertiaApproximation() const return AABox(Vec3(-avg_radius, mBottomCenter - mBottomRadius, -avg_radius), Vec3(avg_radius, mTopCenter + mTopRadius, avg_radius)); } -void TaperedCapsuleShape::TransformShape(Mat44Arg inCenterOfMassTransform, TransformedShapeCollector &ioCollector) const -{ - Vec3 scale; - Mat44 transform = inCenterOfMassTransform.Decompose(scale); - TransformedShape ts(RVec3(transform.GetTranslation()), transform.GetQuaternion(), this, BodyID(), SubShapeIDCreator()); - ts.SetShapeScale(scale.GetSign() * ScaleHelpers::MakeUniformScale(scale.Abs())); - ioCollector.AddHit(ts); -} - void TaperedCapsuleShape::SaveBinaryState(StreamOut &inStream) const { ConvexShape::SaveBinaryState(inStream); @@ -448,6 +439,13 @@ bool TaperedCapsuleShape::IsValidScale(Vec3Arg inScale) const return ConvexShape::IsValidScale(inScale) && ScaleHelpers::IsUniformScale(inScale.Abs()); } +Vec3 TaperedCapsuleShape::MakeScaleValid(Vec3Arg inScale) const +{ + Vec3 scale = ScaleHelpers::MakeNonZeroScale(inScale); + + return scale.GetSign() * ScaleHelpers::MakeUniformScale(scale.Abs()); +} + void TaperedCapsuleShape::sRegister() { ShapeFunctions &f = ShapeFunctions::sGet(EShapeSubType::TaperedCapsule); diff --git a/WickedEngine/Jolt/Physics/Collision/Shape/TaperedCapsuleShape.h b/WickedEngine/Jolt/Physics/Collision/Shape/TaperedCapsuleShape.h index 6dad3c2e9..76e35784c 100644 --- a/WickedEngine/Jolt/Physics/Collision/Shape/TaperedCapsuleShape.h +++ b/WickedEngine/Jolt/Physics/Collision/Shape/TaperedCapsuleShape.h @@ -79,9 +79,6 @@ public: virtual void Draw(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, Vec3Arg inScale, ColorArg inColor, bool inUseMaterialColors, bool inDrawWireframe) const override; #endif // JPH_DEBUG_RENDERER - // See Shape::TransformShape - virtual void TransformShape(Mat44Arg inCenterOfMassTransform, TransformedShapeCollector &ioCollector) const override; - // See Shape virtual void SaveBinaryState(StreamOut &inStream) const override; @@ -94,6 +91,9 @@ public: // See Shape::IsValidScale virtual bool IsValidScale(Vec3Arg inScale) const override; + // See Shape::MakeScaleValid + virtual Vec3 MakeScaleValid(Vec3Arg inScale) const override; + // Register shape functions with the registry static void sRegister(); diff --git a/WickedEngine/Jolt/Physics/Collision/Shape/TriangleShape.cpp b/WickedEngine/Jolt/Physics/Collision/Shape/TriangleShape.cpp index b70179647..599bf9f3a 100644 --- a/WickedEngine/Jolt/Physics/Collision/Shape/TriangleShape.cpp +++ b/WickedEngine/Jolt/Physics/Collision/Shape/TriangleShape.cpp @@ -313,15 +313,6 @@ void TriangleShape::sCastSphereVsTriangle(const ShapeCast &inShapeCast, const Sh caster.Cast(shape->mV1, shape->mV2, shape->mV3, 0b111, inSubShapeIDCreator2.GetID()); } -void TriangleShape::TransformShape(Mat44Arg inCenterOfMassTransform, TransformedShapeCollector &ioCollector) const -{ - Vec3 scale; - Mat44 transform = inCenterOfMassTransform.Decompose(scale); - TransformedShape ts(RVec3(transform.GetTranslation()), transform.GetQuaternion(), this, BodyID(), SubShapeIDCreator()); - ts.SetShapeScale(mConvexRadius == 0.0f? scale : scale.GetSign() * ScaleHelpers::MakeUniformScale(scale.Abs())); - ioCollector.AddHit(ts); -} - class TriangleShape::TSGetTrianglesContext { public: @@ -393,6 +384,16 @@ bool TriangleShape::IsValidScale(Vec3Arg inScale) const return ConvexShape::IsValidScale(inScale) && (mConvexRadius == 0.0f || ScaleHelpers::IsUniformScale(inScale.Abs())); } +Vec3 TriangleShape::MakeScaleValid(Vec3Arg inScale) const +{ + Vec3 scale = ScaleHelpers::MakeNonZeroScale(inScale); + + if (mConvexRadius == 0.0f) + return scale; + + return scale.GetSign() * ScaleHelpers::MakeUniformScale(scale.Abs()); +} + void TriangleShape::sRegister() { ShapeFunctions &f = ShapeFunctions::sGet(EShapeSubType::Triangle); diff --git a/WickedEngine/Jolt/Physics/Collision/Shape/TriangleShape.h b/WickedEngine/Jolt/Physics/Collision/Shape/TriangleShape.h index 990e6e051..458f703f2 100644 --- a/WickedEngine/Jolt/Physics/Collision/Shape/TriangleShape.h +++ b/WickedEngine/Jolt/Physics/Collision/Shape/TriangleShape.h @@ -87,9 +87,6 @@ public: // See: Shape::CollideSoftBodyVertices virtual void CollideSoftBodyVertices(Mat44Arg inCenterOfMassTransform, Vec3Arg inScale, SoftBodyVertex *ioVertices, uint inNumVertices, float inDeltaTime, Vec3Arg inDisplacementDueToGravity, int inCollidingShapeIndex) const override; - // See Shape::TransformShape - virtual void TransformShape(Mat44Arg inCenterOfMassTransform, TransformedShapeCollector &ioCollector) const override; - // See Shape::GetTrianglesStart virtual void GetTrianglesStart(GetTrianglesContext &ioContext, const AABox &inBox, Vec3Arg inPositionCOM, QuatArg inRotation, Vec3Arg inScale) const override; @@ -108,6 +105,9 @@ public: // See Shape::IsValidScale virtual bool IsValidScale(Vec3Arg inScale) const override; + // See Shape::MakeScaleValid + virtual Vec3 MakeScaleValid(Vec3Arg inScale) const override; + // Register shape functions with the registry static void sRegister(); @@ -126,7 +126,7 @@ private: class TSGetTrianglesContext; // Classes for GetSupportFunction - class TriangleNoConvex; + class TriangleNoConvex; class TriangleWithConvex; Vec3 mV1; diff --git a/WickedEngine/Jolt/Physics/Constraints/ConeConstraint.h b/WickedEngine/Jolt/Physics/Constraints/ConeConstraint.h index 630d089dd..b338a4ba3 100644 --- a/WickedEngine/Jolt/Physics/Constraints/ConeConstraint.h +++ b/WickedEngine/Jolt/Physics/Constraints/ConeConstraint.h @@ -99,7 +99,7 @@ public: float GetCosHalfConeAngle() const { return mCosHalfConeAngle; } ///@name Get Lagrange multiplier from last physics update (the linear/angular impulse applied to satisfy the constraint) - inline Vec3 GetTotalLambdaPosition() const { return mPointConstraintPart.GetTotalLambda(); } + inline Vec3 GetTotalLambdaPosition() const { return mPointConstraintPart.GetTotalLambda(); } inline float GetTotalLambdaRotation() const { return mAngleConstraintPart.GetTotalLambda(); } private: diff --git a/WickedEngine/Jolt/Physics/Constraints/ConstraintPart/PointConstraintPart.h b/WickedEngine/Jolt/Physics/Constraints/ConstraintPart/PointConstraintPart.h index 62f663f9e..f9e86b86b 100644 --- a/WickedEngine/Jolt/Physics/Constraints/ConstraintPart/PointConstraintPart.h +++ b/WickedEngine/Jolt/Physics/Constraints/ConstraintPart/PointConstraintPart.h @@ -210,7 +210,7 @@ public: } /// Return lagrange multiplier - Vec3 GetTotalLambda() const + Vec3 GetTotalLambda() const { return mTotalLambda; } diff --git a/WickedEngine/Jolt/Physics/Constraints/ConstraintPart/RotationEulerConstraintPart.h b/WickedEngine/Jolt/Physics/Constraints/ConstraintPart/RotationEulerConstraintPart.h index 34319e980..ec84776a4 100644 --- a/WickedEngine/Jolt/Physics/Constraints/ConstraintPart/RotationEulerConstraintPart.h +++ b/WickedEngine/Jolt/Physics/Constraints/ConstraintPart/RotationEulerConstraintPart.h @@ -243,7 +243,7 @@ public: } /// Return lagrange multiplier - Vec3 GetTotalLambda() const + Vec3 GetTotalLambda() const { return mTotalLambda; } diff --git a/WickedEngine/Jolt/Physics/Constraints/ConstraintPart/RotationQuatConstraintPart.h b/WickedEngine/Jolt/Physics/Constraints/ConstraintPart/RotationQuatConstraintPart.h index e7fb9672d..a4675a51b 100644 --- a/WickedEngine/Jolt/Physics/Constraints/ConstraintPart/RotationQuatConstraintPart.h +++ b/WickedEngine/Jolt/Physics/Constraints/ConstraintPart/RotationQuatConstraintPart.h @@ -218,7 +218,7 @@ public: } /// Return lagrange multiplier - Vec3 GetTotalLambda() const + Vec3 GetTotalLambda() const { return mTotalLambda; } diff --git a/WickedEngine/Jolt/Physics/Constraints/ContactConstraintManager.cpp b/WickedEngine/Jolt/Physics/Constraints/ContactConstraintManager.cpp index f3f968883..e7e1a2a2c 100644 --- a/WickedEngine/Jolt/Physics/Constraints/ContactConstraintManager.cpp +++ b/WickedEngine/Jolt/Physics/Constraints/ContactConstraintManager.cpp @@ -408,7 +408,7 @@ void ContactConstraintManager::ManifoldCache::SaveState(StateRecorder &inStream, } // Write body pairs - size_t num_body_pairs = selected_bp.size(); + uint32 num_body_pairs = uint32(selected_bp.size()); inStream.Write(num_body_pairs); for (const BPKeyValue *bp_kv : selected_bp) { @@ -424,7 +424,7 @@ void ContactConstraintManager::ManifoldCache::SaveState(StateRecorder &inStream, GetAllManifoldsSorted(bp, all_m); // Write num manifolds - size_t num_manifolds = all_m.size(); + uint32 num_manifolds = uint32(all_m.size()); inStream.Write(num_manifolds); // Write all manifolds @@ -464,7 +464,7 @@ void ContactConstraintManager::ManifoldCache::SaveState(StateRecorder &inStream, } // Write all CCD manifold keys - size_t num_manifolds = selected_m.size(); + uint32 num_manifolds = uint32(selected_m.size()); inStream.Write(num_manifolds); for (const MKeyValue *m_kv : selected_m) inStream.Write(m_kv->GetKey()); @@ -485,13 +485,13 @@ bool ContactConstraintManager::ManifoldCache::RestoreState(const ManifoldCache & inReadCache.GetAllBodyPairsSorted(all_bp); // Read amount of body pairs - size_t num_body_pairs; + uint32 num_body_pairs; if (inStream.IsValidating()) - num_body_pairs = all_bp.size(); + num_body_pairs = uint32(all_bp.size()); inStream.Read(num_body_pairs); // Read entire cache - for (size_t i = 0; i < num_body_pairs; ++i) + for (uint32 i = 0; i < num_body_pairs; ++i) { // Read key BodyPair body_pair_key; @@ -521,13 +521,13 @@ bool ContactConstraintManager::ManifoldCache::RestoreState(const ManifoldCache & inReadCache.GetAllManifoldsSorted(all_bp[i]->GetValue(), all_m); // Read amount of manifolds - size_t num_manifolds; + uint32 num_manifolds; if (inStream.IsValidating()) - num_manifolds = all_m.size(); + num_manifolds = uint32(all_m.size()); inStream.Read(num_manifolds); uint32 handle = ManifoldMap::cInvalidHandle; - for (size_t j = 0; j < num_manifolds; ++j) + for (uint32 j = 0; j < num_manifolds; ++j) { // Read key SubShapeIDPair sub_shape_key; @@ -573,12 +573,12 @@ bool ContactConstraintManager::ManifoldCache::RestoreState(const ManifoldCache & inReadCache.GetAllCCDManifoldsSorted(all_m); // Read amount of CCD manifolds - size_t num_manifolds; + uint32 num_manifolds; if (inStream.IsValidating()) - num_manifolds = all_m.size(); + num_manifolds = uint32(all_m.size()); inStream.Read(num_manifolds); - for (size_t j = 0; j < num_manifolds; ++j) + for (uint32 j = 0; j < num_manifolds; ++j) { // Read key SubShapeIDPair sub_shape_key; diff --git a/WickedEngine/Jolt/Physics/Constraints/DistanceConstraint.h b/WickedEngine/Jolt/Physics/Constraints/DistanceConstraint.h index fc9d35267..c4aa54e6e 100644 --- a/WickedEngine/Jolt/Physics/Constraints/DistanceConstraint.h +++ b/WickedEngine/Jolt/Physics/Constraints/DistanceConstraint.h @@ -83,7 +83,7 @@ public: void SetLimitsSpringSettings(const SpringSettings &inLimitsSpringSettings) { mLimitsSpringSettings = inLimitsSpringSettings; } ///@name Get Lagrange multiplier from last physics update (the linear impulse applied to satisfy the constraint) - inline float GetTotalLambdaPosition() const { return mAxisConstraint.GetTotalLambda(); } + inline float GetTotalLambdaPosition() const { return mAxisConstraint.GetTotalLambda(); } private: // Internal helper function to calculate the values below diff --git a/WickedEngine/Jolt/Physics/Constraints/HingeConstraint.h b/WickedEngine/Jolt/Physics/Constraints/HingeConstraint.h index edf48d0e0..bb1fe83ac 100644 --- a/WickedEngine/Jolt/Physics/Constraints/HingeConstraint.h +++ b/WickedEngine/Jolt/Physics/Constraints/HingeConstraint.h @@ -28,7 +28,11 @@ public: EConstraintSpace mSpace = EConstraintSpace::WorldSpace; /// Body 1 constraint reference frame (space determined by mSpace). - /// Hinge axis is the axis where rotation is allowed, normal axis defines the 0 angle of the hinge. + /// Hinge axis is the axis where rotation is allowed. + /// When the normal axis of both bodies align in world space, the hinge angle is defined to be 0. + /// mHingeAxis1 and mNormalAxis1 should be perpendicular. mHingeAxis2 and mNormalAxis2 should also be perpendicular. + /// If you configure the joint in world space and create both bodies with a relative rotation you want to be defined as zero, + /// you can simply set mHingeAxis1 = mHingeAxis2 and mNormalAxis1 = mNormalAxis2. RVec3 mPoint1 = RVec3::sZero(); Vec3 mHingeAxis1 = Vec3::sAxisY(); Vec3 mNormalAxis1 = Vec3::sAxisX(); @@ -38,7 +42,7 @@ public: Vec3 mHingeAxis2 = Vec3::sAxisY(); Vec3 mNormalAxis2 = Vec3::sAxisX(); - /// Bodies are assumed to be placed so that the hinge angle = 0, movement will be limited between [mLimitsMin, mLimitsMax] where mLimitsMin e [-pi, 0] and mLimitsMax e [0, pi]. + /// Rotation around the hinge axis will be limited between [mLimitsMin, mLimitsMax] where mLimitsMin e [-pi, 0] and mLimitsMax e [0, pi]. /// Both angles are in radians. float mLimitsMin = -JPH_PI; float mLimitsMax = JPH_PI; @@ -86,6 +90,20 @@ public: virtual Mat44 GetConstraintToBody1Matrix() const override; virtual Mat44 GetConstraintToBody2Matrix() const override; + /// Get the attachment point for body 1 relative to body 1 COM (transform by Body::GetCenterOfMassTransform to take to world space) + inline Vec3 GetLocalSpacePoint1() const { return mLocalSpacePosition1; } + + /// Get the attachment point for body 2 relative to body 2 COM (transform by Body::GetCenterOfMassTransform to take to world space) + inline Vec3 GetLocalSpacePoint2() const { return mLocalSpacePosition2; } + + // Local space hinge directions (transform direction by Body::GetCenterOfMassTransform to take to world space) + Vec3 GetLocalSpaceHingeAxis1() const { return mLocalSpaceHingeAxis1; } + Vec3 GetLocalSpaceHingeAxis2() const { return mLocalSpaceHingeAxis2; } + + // Local space normal directions (transform direction by Body::GetCenterOfMassTransform to take to world space) + Vec3 GetLocalSpaceNormalAxis1() const { return mLocalSpaceNormalAxis1; } + Vec3 GetLocalSpaceNormalAxis2() const { return mLocalSpaceNormalAxis2; } + /// Get the current rotation angle from the rest position float GetCurrentAngle() const; @@ -117,7 +135,7 @@ public: void SetLimitsSpringSettings(const SpringSettings &inLimitsSpringSettings) { mLimitsSpringSettings = inLimitsSpringSettings; } ///@name Get Lagrange multiplier from last physics update (the linear/angular impulse applied to satisfy the constraint) - inline Vec3 GetTotalLambdaPosition() const { return mPointConstraintPart.GetTotalLambda(); } + inline Vec3 GetTotalLambdaPosition() const { return mPointConstraintPart.GetTotalLambda(); } inline Vector<2> GetTotalLambdaRotation() const { return mRotationConstraintPart.GetTotalLambda(); } inline float GetTotalLambdaRotationLimits() const { return mRotationLimitsConstraintPart.GetTotalLambda(); } inline float GetTotalLambdaMotor() const { return mMotorConstraintPart.GetTotalLambda(); } diff --git a/WickedEngine/Jolt/Physics/Constraints/PathConstraintPathHermite.cpp b/WickedEngine/Jolt/Physics/Constraints/PathConstraintPathHermite.cpp index 55c1f33ad..132d3b25f 100644 --- a/WickedEngine/Jolt/Physics/Constraints/PathConstraintPathHermite.cpp +++ b/WickedEngine/Jolt/Physics/Constraints/PathConstraintPathHermite.cpp @@ -139,7 +139,7 @@ static inline float sCalculateClosestPointThroughNewtonRaphson(Vec3Arg inP1, Vec float d2dt_h01 = -d2dt_h00; float d2dt_h11 = 6.0f * t - 2.0f; Vec3 ddt_tangent = d2dt_h00 * inP1 + d2dt_h10 * inM1 + d2dt_h01 * inP2 + d2dt_h11 * inM2; - float d2dt = tangent.Dot(tangent) + position.Dot(ddt_tangent); // Leaving out factor 2, because we left it out above too + float d2dt = tangent.Dot(tangent) + position.Dot(ddt_tangent); // Leaving out factor 2, because we left it out above too // If d2dt is zero, the curve is flat and there are multiple t's for which we are closest to the origin, stop now if (d2dt == 0.0f) diff --git a/WickedEngine/Jolt/Physics/Constraints/PointConstraint.h b/WickedEngine/Jolt/Physics/Constraints/PointConstraint.h index f88756931..215d6b069 100644 --- a/WickedEngine/Jolt/Physics/Constraints/PointConstraint.h +++ b/WickedEngine/Jolt/Physics/Constraints/PointConstraint.h @@ -66,10 +66,10 @@ public: /// Update the attachment point for body 2 void SetPoint2(EConstraintSpace inSpace, RVec3Arg inPoint2); - /// Get the attachment point for body 1 relative to body 1 COM + /// Get the attachment point for body 1 relative to body 1 COM (transform by Body::GetCenterOfMassTransform to take to world space) inline Vec3 GetLocalSpacePoint1() const { return mLocalSpacePosition1; } - /// Get the attachment point for body 2 relative to body 2 COM + /// Get the attachment point for body 2 relative to body 2 COM (transform by Body::GetCenterOfMassTransform to take to world space) inline Vec3 GetLocalSpacePoint2() const { return mLocalSpacePosition2; } // See: TwoBodyConstraint @@ -77,7 +77,7 @@ public: virtual Mat44 GetConstraintToBody2Matrix() const override { return Mat44::sTranslation(mLocalSpacePosition2); } // Note: Incorrect rotation as we don't track the original rotation difference, should not matter though as the constraint is not limiting rotation. ///@name Get Lagrange multiplier from last physics update (the linear impulse applied to satisfy the constraint) - inline Vec3 GetTotalLambdaPosition() const { return mPointConstraintPart.GetTotalLambda(); } + inline Vec3 GetTotalLambdaPosition() const { return mPointConstraintPart.GetTotalLambda(); } private: // Internal helper function to calculate the values below diff --git a/WickedEngine/Jolt/Physics/Constraints/PulleyConstraint.h b/WickedEngine/Jolt/Physics/Constraints/PulleyConstraint.h index 5f2523dae..8b2df68db 100644 --- a/WickedEngine/Jolt/Physics/Constraints/PulleyConstraint.h +++ b/WickedEngine/Jolt/Physics/Constraints/PulleyConstraint.h @@ -92,7 +92,7 @@ public: float GetCurrentLength() const { return Vec3(mWorldSpacePosition1 - mFixedPosition1).Length() + mRatio * Vec3(mWorldSpacePosition2 - mFixedPosition2).Length(); } ///@name Get Lagrange multiplier from last physics update (the linear impulse applied to satisfy the constraint) - inline float GetTotalLambdaPosition() const { return mIndependentAxisConstraintPart.GetTotalLambda(); } + inline float GetTotalLambdaPosition() const { return mIndependentAxisConstraintPart.GetTotalLambda(); } private: // Calculates world positions and normals and returns current length diff --git a/WickedEngine/Jolt/Physics/Constraints/SixDOFConstraint.h b/WickedEngine/Jolt/Physics/Constraints/SixDOFConstraint.h index 1bc03eced..493a3b8e8 100644 --- a/WickedEngine/Jolt/Physics/Constraints/SixDOFConstraint.h +++ b/WickedEngine/Jolt/Physics/Constraints/SixDOFConstraint.h @@ -173,15 +173,15 @@ public: EMotorState GetMotorState(EAxis inAxis) const { return mMotorState[inAxis]; } /// Set the target velocity in body 1 constraint space - Vec3 GetTargetVelocityCS() const { return mTargetVelocity; } + Vec3 GetTargetVelocityCS() const { return mTargetVelocity; } void SetTargetVelocityCS(Vec3Arg inVelocity) { mTargetVelocity = inVelocity; } /// Set the target angular velocity in body 2 constraint space (!) void SetTargetAngularVelocityCS(Vec3Arg inAngularVelocity) { mTargetAngularVelocity = inAngularVelocity; } - Vec3 GetTargetAngularVelocityCS() const { return mTargetAngularVelocity; } + Vec3 GetTargetAngularVelocityCS() const { return mTargetAngularVelocity; } /// Set the target position in body 1 constraint space - Vec3 GetTargetPositionCS() const { return mTargetPosition; } + Vec3 GetTargetPositionCS() const { return mTargetPosition; } void SetTargetPositionCS(Vec3Arg inPosition) { mTargetPosition = inPosition; } /// Set the target orientation in body 1 constraint space @@ -193,7 +193,7 @@ public: void SetTargetOrientationBS(QuatArg inOrientation) { SetTargetOrientationCS(mConstraintToBody1.Conjugated() * inOrientation * mConstraintToBody2); } ///@name Get Lagrange multiplier from last physics update (the linear/angular impulse applied to satisfy the constraint) - inline Vec3 GetTotalLambdaPosition() const { return IsTranslationFullyConstrained()? mPointConstraintPart.GetTotalLambda() : Vec3(mTranslationConstraintPart[0].GetTotalLambda(), mTranslationConstraintPart[1].GetTotalLambda(), mTranslationConstraintPart[2].GetTotalLambda()); } + inline Vec3 GetTotalLambdaPosition() const { return IsTranslationFullyConstrained()? mPointConstraintPart.GetTotalLambda() : Vec3(mTranslationConstraintPart[0].GetTotalLambda(), mTranslationConstraintPart[1].GetTotalLambda(), mTranslationConstraintPart[2].GetTotalLambda()); } inline Vec3 GetTotalLambdaRotation() const { return IsRotationFullyConstrained()? mRotationConstraintPart.GetTotalLambda() : Vec3(mSwingTwistConstraintPart.GetTotalTwistLambda(), mSwingTwistConstraintPart.GetTotalSwingYLambda(), mSwingTwistConstraintPart.GetTotalSwingZLambda()); } inline Vec3 GetTotalLambdaMotorTranslation() const { return Vec3(mMotorTranslationConstraintPart[0].GetTotalLambda(), mMotorTranslationConstraintPart[1].GetTotalLambda(), mMotorTranslationConstraintPart[2].GetTotalLambda()); } inline Vec3 GetTotalLambdaMotorRotation() const { return Vec3(mMotorRotationConstraintPart[0].GetTotalLambda(), mMotorRotationConstraintPart[1].GetTotalLambda(), mMotorRotationConstraintPart[2].GetTotalLambda()); } diff --git a/WickedEngine/Jolt/Physics/Constraints/SliderConstraint.h b/WickedEngine/Jolt/Physics/Constraints/SliderConstraint.h index 2838517f2..76925125f 100644 --- a/WickedEngine/Jolt/Physics/Constraints/SliderConstraint.h +++ b/WickedEngine/Jolt/Physics/Constraints/SliderConstraint.h @@ -123,7 +123,7 @@ public: void SetLimitsSpringSettings(const SpringSettings &inLimitsSpringSettings) { mLimitsSpringSettings = inLimitsSpringSettings; } ///@name Get Lagrange multiplier from last physics update (the linear/angular impulse applied to satisfy the constraint) - inline Vector<2> GetTotalLambdaPosition() const { return mPositionConstraintPart.GetTotalLambda(); } + inline Vector<2> GetTotalLambdaPosition() const { return mPositionConstraintPart.GetTotalLambda(); } inline float GetTotalLambdaPositionLimits() const { return mPositionLimitsConstraintPart.GetTotalLambda(); } inline Vec3 GetTotalLambdaRotation() const { return mRotationConstraintPart.GetTotalLambda(); } inline float GetTotalLambdaMotor() const { return mMotorConstraintPart.GetTotalLambda(); } diff --git a/WickedEngine/Jolt/Physics/Constraints/SpringSettings.h b/WickedEngine/Jolt/Physics/Constraints/SpringSettings.h index b2f6b7e24..5f6e4a117 100644 --- a/WickedEngine/Jolt/Physics/Constraints/SpringSettings.h +++ b/WickedEngine/Jolt/Physics/Constraints/SpringSettings.h @@ -41,7 +41,7 @@ public: /// Selects the way in which the spring is defined /// If the mode is StiffnessAndDamping then mFrequency becomes the stiffness (k) and mDamping becomes the damping ratio (c) in the spring equation F = -k * x - c * v. Otherwise the properties are as documented. - ESpringMode mMode = ESpringMode::FrequencyAndDamping; + ESpringMode mMode = ESpringMode::FrequencyAndDamping; union { diff --git a/WickedEngine/Jolt/Physics/Constraints/SwingTwistConstraint.h b/WickedEngine/Jolt/Physics/Constraints/SwingTwistConstraint.h index d915c0015..0480197ef 100644 --- a/WickedEngine/Jolt/Physics/Constraints/SwingTwistConstraint.h +++ b/WickedEngine/Jolt/Physics/Constraints/SwingTwistConstraint.h @@ -96,10 +96,10 @@ public: virtual Mat44 GetConstraintToBody2Matrix() const override { return Mat44::sRotationTranslation(mConstraintToBody2, mLocalSpacePosition2); } ///@name Constraint reference frame - inline Vec3 GetLocalSpacePosition1() const { return mLocalSpacePosition1; } - inline Vec3 GetLocalSpacePosition2() const { return mLocalSpacePosition2; } - inline Quat GetConstraintToBody1() const { return mConstraintToBody1; } - inline Quat GetConstraintToBody2() const { return mConstraintToBody2; } + inline Vec3 GetLocalSpacePosition1() const { return mLocalSpacePosition1; } + inline Vec3 GetLocalSpacePosition2() const { return mLocalSpacePosition2; } + inline Quat GetConstraintToBody1() const { return mConstraintToBody1; } + inline Quat GetConstraintToBody2() const { return mConstraintToBody2; } ///@name Constraint limits inline float GetNormalHalfConeAngle() const { return mNormalHalfConeAngle; } @@ -131,11 +131,11 @@ public: /// Set the target angular velocity of body 2 in constraint space of body 2 void SetTargetAngularVelocityCS(Vec3Arg inAngularVelocity) { mTargetAngularVelocity = inAngularVelocity; } - Vec3 GetTargetAngularVelocityCS() const { return mTargetAngularVelocity; } + Vec3 GetTargetAngularVelocityCS() const { return mTargetAngularVelocity; } /// Set the target orientation in constraint space (drives constraint to: GetRotationInConstraintSpace() == inOrientation) void SetTargetOrientationCS(QuatArg inOrientation); - Quat GetTargetOrientationCS() const { return mTargetOrientation; } + Quat GetTargetOrientationCS() const { return mTargetOrientation; } /// Set the target orientation in body space (R2 = R1 * inOrientation, where R1 and R2 are the world space rotations for body 1 and 2). /// Solve: R2 * ConstraintToBody2 = R1 * ConstraintToBody1 * q (see SwingTwistConstraint::GetSwingTwist) and R2 = R1 * inOrientation for q. @@ -146,7 +146,7 @@ public: Quat GetRotationInConstraintSpace() const; ///@name Get Lagrange multiplier from last physics update (the linear/angular impulse applied to satisfy the constraint) - inline Vec3 GetTotalLambdaPosition() const { return mPointConstraintPart.GetTotalLambda(); } + inline Vec3 GetTotalLambdaPosition() const { return mPointConstraintPart.GetTotalLambda(); } inline float GetTotalLambdaTwist() const { return mSwingTwistConstraintPart.GetTotalTwistLambda(); } inline float GetTotalLambdaSwingY() const { return mSwingTwistConstraintPart.GetTotalSwingYLambda(); } inline float GetTotalLambdaSwingZ() const { return mSwingTwistConstraintPart.GetTotalSwingZLambda(); } diff --git a/WickedEngine/Jolt/Physics/LargeIslandSplitter.h b/WickedEngine/Jolt/Physics/LargeIslandSplitter.h index 8e61d0930..36f0d6140 100644 --- a/WickedEngine/Jolt/Physics/LargeIslandSplitter.h +++ b/WickedEngine/Jolt/Physics/LargeIslandSplitter.h @@ -43,7 +43,7 @@ public: struct Split { inline uint GetNumContacts() const { return mContactBufferEnd - mContactBufferBegin; } - inline uint GetNumConstraints() const { return mConstraintBufferEnd - mConstraintBufferBegin; } + inline uint GetNumConstraints() const { return mConstraintBufferEnd - mConstraintBufferBegin; } inline uint GetNumItems() const { return GetNumContacts() + GetNumConstraints(); } uint32 mContactBufferBegin; ///< Begin of the contact buffer (offset relative to mContactAndConstraintIndices) diff --git a/WickedEngine/Jolt/Physics/PhysicsLock.h b/WickedEngine/Jolt/Physics/PhysicsLock.h index 62cf72e99..638ced40b 100644 --- a/WickedEngine/Jolt/Physics/PhysicsLock.h +++ b/WickedEngine/Jolt/Physics/PhysicsLock.h @@ -83,7 +83,7 @@ private: struct LockData { uint32 mLockedMutexes = 0; - PhysicsLockContext mContext = nullptr; + PhysicsLockContext mContext = nullptr; }; static thread_local LockData sLocks[4]; @@ -133,7 +133,7 @@ public: private: LockType & mLock; #ifdef JPH_ENABLE_ASSERTS - PhysicsLockContext mContext; + PhysicsLockContext mContext; EPhysicsLockTypes mType; #endif // JPH_ENABLE_ASSERTS }; @@ -161,7 +161,7 @@ public: private: LockType & mLock; #ifdef JPH_ENABLE_ASSERTS - PhysicsLockContext mContext; + PhysicsLockContext mContext; EPhysicsLockTypes mType; #endif // JPH_ENABLE_ASSERTS }; diff --git a/WickedEngine/Jolt/Physics/PhysicsSystem.cpp b/WickedEngine/Jolt/Physics/PhysicsSystem.cpp index 2aad1c0b6..ede9cfd9f 100644 --- a/WickedEngine/Jolt/Physics/PhysicsSystem.cpp +++ b/WickedEngine/Jolt/Physics/PhysicsSystem.cpp @@ -76,6 +76,8 @@ PhysicsSystem::~PhysicsSystem() void PhysicsSystem::Init(uint inMaxBodies, uint inNumBodyMutexes, uint inMaxBodyPairs, uint inMaxContactConstraints, const BroadPhaseLayerInterface &inBroadPhaseLayerInterface, const ObjectVsBroadPhaseLayerFilter &inObjectVsBroadPhaseLayerFilter, const ObjectLayerPairFilter &inObjectLayerPairFilter) { + JPH_ASSERT(inMaxBodies <= BodyID::cMaxBodyIndex, "Cannot support this many bodies"); + mObjectVsBroadPhaseLayerFilter = &inObjectVsBroadPhaseLayerFilter; mObjectLayerPairFilter = &inObjectLayerPairFilter; @@ -999,10 +1001,13 @@ void PhysicsSystem::ProcessBodyPair(ContactAllocator &ioContactAllocator, const if (body_pair_handle == nullptr) return; // Out of cache space + // If we want enhanced active edge detection for this body pair + bool enhanced_active_edges = body1->GetEnhancedInternalEdgeRemovalWithBody(*body2); + // Create the query settings CollideShapeSettings settings; settings.mCollectFacesMode = ECollectFacesMode::CollectFaces; - settings.mActiveEdgeMode = mPhysicsSettings.mCheckActiveEdges? EActiveEdgeMode::CollideOnlyWithActive : EActiveEdgeMode::CollideWithAll; + settings.mActiveEdgeMode = mPhysicsSettings.mCheckActiveEdges && !enhanced_active_edges? EActiveEdgeMode::CollideOnlyWithActive : EActiveEdgeMode::CollideWithAll; settings.mMaxSeparationDistance = body1->IsSensor() || body2->IsSensor()? 0.0f : mPhysicsSettings.mSpeculativeContactDistance; settings.mActiveEdgeMovementDirection = body1->GetLinearVelocity() - body2->GetLinearVelocity(); @@ -1126,7 +1131,7 @@ void PhysicsSystem::ProcessBodyPair(ContactAllocator &ioContactAllocator, const // Perform collision detection between the two shapes SubShapeIDCreator part1, part2; - auto f = body1->GetEnhancedInternalEdgeRemovalWithBody(*body2)? InternalEdgeRemovingCollector::sCollideShapeVsShape : CollisionDispatch::sCollideShapeVsShape; + auto f = enhanced_active_edges? InternalEdgeRemovingCollector::sCollideShapeVsShape : CollisionDispatch::sCollideShapeVsShape; f(body1->GetShape(), body2->GetShape(), Vec3::sReplicate(1.0f), Vec3::sReplicate(1.0f), transform1, transform2, part1, part2, settings, collector, { }); // Add the contacts @@ -1227,7 +1232,7 @@ void PhysicsSystem::ProcessBodyPair(ContactAllocator &ioContactAllocator, const // Perform collision detection between the two shapes SubShapeIDCreator part1, part2; - auto f = body1->GetEnhancedInternalEdgeRemovalWithBody(*body2)? InternalEdgeRemovingCollector::sCollideShapeVsShape : CollisionDispatch::sCollideShapeVsShape; + auto f = enhanced_active_edges? InternalEdgeRemovingCollector::sCollideShapeVsShape : CollisionDispatch::sCollideShapeVsShape; f(body1->GetShape(), body2->GetShape(), Vec3::sReplicate(1.0f), Vec3::sReplicate(1.0f), transform1, transform2, part1, part2, settings, collector, { }); constraint_created = collector.mConstraintCreated; diff --git a/WickedEngine/Jolt/Physics/PhysicsSystem.h b/WickedEngine/Jolt/Physics/PhysicsSystem.h index 3234e5b53..d46dbc4ec 100644 --- a/WickedEngine/Jolt/Physics/PhysicsSystem.h +++ b/WickedEngine/Jolt/Physics/PhysicsSystem.h @@ -72,16 +72,16 @@ public: /// Access to the body interface. This interface allows to to create / remove bodies and to change their properties. const BodyInterface & GetBodyInterface() const { return mBodyInterfaceLocking; } - BodyInterface & GetBodyInterface() { return mBodyInterfaceLocking; } + BodyInterface & GetBodyInterface() { return mBodyInterfaceLocking; } const BodyInterface & GetBodyInterfaceNoLock() const { return mBodyInterfaceNoLock; } ///< Version that does not lock the bodies, use with great care! - BodyInterface & GetBodyInterfaceNoLock() { return mBodyInterfaceNoLock; } ///< Version that does not lock the bodies, use with great care! + BodyInterface & GetBodyInterfaceNoLock() { return mBodyInterfaceNoLock; } ///< Version that does not lock the bodies, use with great care! /// Access to the broadphase interface that allows coarse collision queries const BroadPhaseQuery & GetBroadPhaseQuery() const { return *mBroadPhase; } /// Interface that allows fine collision queries against first the broad phase and then the narrow phase. const NarrowPhaseQuery & GetNarrowPhaseQuery() const { return mNarrowPhaseQueryLocking; } - const NarrowPhaseQuery & GetNarrowPhaseQueryNoLock() const { return mNarrowPhaseQueryNoLock; } ///< Version that does not lock the bodies, use with great care! + const NarrowPhaseQuery & GetNarrowPhaseQueryNoLock() const { return mNarrowPhaseQueryNoLock; } ///< Version that does not lock the bodies, use with great care! /// Add constraint to the world void AddConstraint(Constraint *inConstraint) { mConstraintManager.Add(&inConstraint, 1); } @@ -144,7 +144,7 @@ public: /// Set gravity value void SetGravity(Vec3Arg inGravity) { mGravity = inGravity; } - Vec3 GetGravity() const { return mGravity; } + Vec3 GetGravity() const { return mGravity; } /// Returns a locking interface that won't actually lock the body. Use with great care! inline const BodyLockInterfaceNoLock & GetBodyLockInterfaceNoLock() const { return mBodyLockInterfaceNoLock; } @@ -288,7 +288,7 @@ private: /// The soft body contact listener SoftBodyContactListener * mSoftBodyContactListener = nullptr; - /// Simulation settings + /// Simulation settings PhysicsSettings mPhysicsSettings; /// The contact manager resolves all contacts during a simulation step diff --git a/WickedEngine/Jolt/Physics/Ragdoll/Ragdoll.h b/WickedEngine/Jolt/Physics/Ragdoll/Ragdoll.h index c31586f25..fe9debfd4 100644 --- a/WickedEngine/Jolt/Physics/Ragdoll/Ragdoll.h +++ b/WickedEngine/Jolt/Physics/Ragdoll/Ragdoll.h @@ -215,7 +215,7 @@ public: const TwoBodyConstraint * GetConstraint(int inConstraintIndex) const { return mConstraints[inConstraintIndex]; } /// Get world space bounding box for all bodies of the ragdoll - AABox GetWorldSpaceBounds(bool inLockBodies = true) const; + AABox GetWorldSpaceBounds(bool inLockBodies = true) const; /// Get the settings object that created this ragdoll const RagdollSettings * GetRagdollSettings() const { return mRagdollSettings; } diff --git a/WickedEngine/Jolt/Physics/SoftBody/SoftBodyMotionProperties.h b/WickedEngine/Jolt/Physics/SoftBody/SoftBodyMotionProperties.h index 5d07c3795..ded13445c 100644 --- a/WickedEngine/Jolt/Physics/SoftBody/SoftBodyMotionProperties.h +++ b/WickedEngine/Jolt/Physics/SoftBody/SoftBodyMotionProperties.h @@ -180,7 +180,7 @@ private: float mFriction; ///< Combined friction of the two bodies float mRestitution; ///< Combined restitution of the two bodies float mSoftBodyInvMassScale; ///< Scale factor for the inverse mass of the soft body vertices - bool mUpdateVelocities; ///< If the linear/angular velocity changed and the body needs to be updated + bool mUpdateVelocities; ///< If the linear/angular velocity changed and the body needs to be updated Mat44 mInvInertia; ///< Inverse inertia in local space to the soft body Vec3 mLinearVelocity; ///< Linear velocity of the body in local space to the soft body Vec3 mAngularVelocity; ///< Angular velocity of the body in local space to the soft body diff --git a/WickedEngine/Jolt/Physics/SoftBody/SoftBodySharedSettings.cpp b/WickedEngine/Jolt/Physics/SoftBody/SoftBodySharedSettings.cpp index 9c85a5698..413415f9f 100644 --- a/WickedEngine/Jolt/Physics/SoftBody/SoftBodySharedSettings.cpp +++ b/WickedEngine/Jolt/Physics/SoftBody/SoftBodySharedSettings.cpp @@ -200,7 +200,7 @@ void SoftBodySharedSettings::CreateConstraints(const VertexAttributes *inVertexA temp_edge.mVertex[1] = inVtx2; temp_edge.mCompliance = 0.5f * (inCompliance1 + inCompliance2); temp_edge.mRestLength = (Vec3(mVertices[inVtx2].mPosition) - Vec3(mVertices[inVtx1].mPosition)).Length(); - //JPH_ASSERT(temp_edge.mRestLength > 0.0f); + JPH_ASSERT(temp_edge.mRestLength > 0.0f); mEdgeConstraints.push_back(temp_edge); } }; diff --git a/WickedEngine/Jolt/Physics/SoftBody/SoftBodyVertex.h b/WickedEngine/Jolt/Physics/SoftBody/SoftBodyVertex.h index 34e7bb32f..68438ef4b 100644 --- a/WickedEngine/Jolt/Physics/SoftBody/SoftBodyVertex.h +++ b/WickedEngine/Jolt/Physics/SoftBody/SoftBodyVertex.h @@ -16,8 +16,8 @@ class SoftBodyVertex { public: Vec3 mPreviousPosition; ///< Position at the previous time step - Vec3 mPosition; ///< Position, relative to the center of mass of the soft body - Vec3 mVelocity; ///< Velocity, relative to the center of mass of the soft body + Vec3 mPosition; ///< Position, relative to the center of mass of the soft body + Vec3 mVelocity; ///< Velocity, relative to the center of mass of the soft body Plane mCollisionPlane; ///< Nearest collision plane, relative to the center of mass of the soft body int mCollidingShapeIndex; ///< Index in the colliding shapes list of the body we may collide with bool mHasContact; ///< True if the vertex has collided with anything in the last update diff --git a/WickedEngine/Jolt/Renderer/DebugRenderer.cpp b/WickedEngine/Jolt/Renderer/DebugRenderer.cpp index 44025aaff..e0a000de2 100644 --- a/WickedEngine/Jolt/Renderer/DebugRenderer.cpp +++ b/WickedEngine/Jolt/Renderer/DebugRenderer.cpp @@ -340,7 +340,7 @@ void DebugRenderer::Create8thSphereRecursive(Array &ioIndices, Array