diff --git a/Source/Platforms/Android/Binaries/ThirdParty/ARM64/libNvCloth.a b/Source/Platforms/Android/Binaries/ThirdParty/ARM64/libNvCloth.a new file mode 100644 index 000000000..7b77e9bc2 --- /dev/null +++ b/Source/Platforms/Android/Binaries/ThirdParty/ARM64/libNvCloth.a @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dc4f2a3a7fc559e0891d47190110d8e0de5d5d96655374fee3f909bc71764a1d +size 3656516 diff --git a/Source/Platforms/Windows/Binaries/ThirdParty/x64/NvCloth_x64.lib b/Source/Platforms/Windows/Binaries/ThirdParty/x64/NvCloth_x64.lib new file mode 100644 index 000000000..d5ddd1770 --- /dev/null +++ b/Source/Platforms/Windows/Binaries/ThirdParty/x64/NvCloth_x64.lib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e92cff7b740448dcb882892a8ff1e7c360cccad07c8333af9c7232e9266482ba +size 2425458 diff --git a/Source/Platforms/Windows/Binaries/ThirdParty/x64/NvCloth_x64.pdb b/Source/Platforms/Windows/Binaries/ThirdParty/x64/NvCloth_x64.pdb new file mode 100644 index 000000000..e3ec6d317 --- /dev/null +++ b/Source/Platforms/Windows/Binaries/ThirdParty/x64/NvCloth_x64.pdb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f322c45592d9b58fe8ec9d75c2c9fbb523e752be768fcbc9f867ab9eb12f527f +size 520192 diff --git a/Source/ThirdParty/NvCloth/Allocator.h b/Source/ThirdParty/NvCloth/Allocator.h new file mode 100644 index 000000000..15c1cc2df --- /dev/null +++ b/Source/ThirdParty/NvCloth/Allocator.h @@ -0,0 +1,168 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + + +/** \file Allocator.h + This file together with Callbacks.h define most memory management interfaces for internal use. +*/ + +/** \cond HIDDEN_SYMBOLS */ +#pragma once + +#include "NvCloth/ps/PsArray.h" +#include "NvCloth/ps/PsHashMap.h" +#include "NvCloth/Callbacks.h" +#include "NvCloth/ps/PsAlignedMalloc.h" + +namespace nv +{ +namespace cloth +{ + +void* allocate(size_t); +void deallocate(void*); + + +/* templated typedefs for convenience */ + +template +struct Vector +{ + typedef ps::Array Type; +}; + +template +struct AlignedVector +{ + typedef ps::Array > Type; +}; + +template > +struct HashMap +{ + typedef ps::HashMap Type; +}; + +struct NvClothOverload{}; +#define NV_CLOTH_NEW(T) new (__FILE__, __LINE__, nv::cloth::NvClothOverload()) T +#define NV_CLOTH_ALLOC(n, name) GetNvClothAllocator()->allocate(n, name, __FILE__, __LINE__) +#define NV_CLOTH_FREE(x) GetNvClothAllocator()->deallocate(x) +#define NV_CLOTH_DELETE(x) delete x + +} // namespace cloth +} // namespace nv + +//new/delete operators need to be declared in global scope +template +PX_INLINE void* operator new(size_t size, const char* fileName, + typename nv::cloth::ps::EnableIfPod::Type line, nv::cloth::NvClothOverload overload) +{ + PX_UNUSED(overload); + return GetNvClothAllocator()->allocate(size, "", fileName, line); +} + +template +PX_INLINE void* operator new [](size_t size, const char* fileName, + typename nv::cloth::ps::EnableIfPod::Type line, nv::cloth::NvClothOverload overload) +{ + PX_UNUSED(overload); + return GetNvClothAllocator()->allocate(size, "", fileName, line); +} + +// If construction after placement new throws, this placement delete is being called. +template +PX_INLINE void operator delete(void* ptr, const char* fileName, + typename nv::cloth::ps::EnableIfPod::Type line, nv::cloth::NvClothOverload overload) +{ + PX_UNUSED(fileName); + PX_UNUSED(line); + PX_UNUSED(overload); + + return GetNvClothAllocator()->deallocate(ptr); +} + +// If construction after placement new throws, this placement delete is being called. +template +PX_INLINE void operator delete [](void* ptr, const char* fileName, + typename nv::cloth::ps::EnableIfPod::Type line, nv::cloth::NvClothOverload overload) +{ + PX_UNUSED(fileName); + PX_UNUSED(line); + PX_UNUSED(overload); + + return GetNvClothAllocator()->deallocate(ptr); +} + +namespace nv +{ +namespace cloth +{ + +class UserAllocated +{ + public: + PX_INLINE void* operator new(size_t size, const char* fileName, int line, NvClothOverload overload) + { + PX_UNUSED(overload); + return GetNvClothAllocator()->allocate(size, "", fileName, line); + } + PX_INLINE void* operator new [](size_t size, const char* fileName, int line, NvClothOverload overload) + { + PX_UNUSED(overload); + return GetNvClothAllocator()->allocate(size, "", fileName, line); + } + + // placement delete + PX_INLINE void operator delete(void* ptr, const char* fileName, int line, NvClothOverload overload) + { + PX_UNUSED(fileName); + PX_UNUSED(line); + PX_UNUSED(overload); + GetNvClothAllocator()->deallocate(ptr); + } + PX_INLINE void operator delete [](void* ptr, const char* fileName, int line, NvClothOverload overload) + { + PX_UNUSED(fileName); + PX_UNUSED(line); + PX_UNUSED(overload); + GetNvClothAllocator()->deallocate(ptr); + } + PX_INLINE void operator delete(void* ptr) + { + return GetNvClothAllocator()->deallocate(ptr); + } + PX_INLINE void operator delete [](void* ptr) + { + return GetNvClothAllocator()->deallocate(ptr); + } +}; + +} // namespace cloth +} // namespace nv +/** \endcond */ diff --git a/Source/ThirdParty/NvCloth/Callbacks.h b/Source/ThirdParty/NvCloth/Callbacks.h new file mode 100644 index 000000000..5a44fa581 --- /dev/null +++ b/Source/ThirdParty/NvCloth/Callbacks.h @@ -0,0 +1,192 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +/** \file Callbacks.h + \brief All functions to initialize and use user provided callbacks are declared in this header. + Initialize the callbacks with InitializeNvCloth(...) before using any other NvCloth API. + The other functions defined in this header are used to access the functionality provided by the callbacks, and are mostly for internal use. + */ + +#pragma once +#include +#include +#include +#ifndef NV_CLOTH_IMPORT +#define NV_CLOTH_IMPORT PX_DLL_IMPORT +#endif + +#define NV_CLOTH_DLL_ID 0x2 + +#define NV_CLOTH_LINKAGE PX_C_EXPORT NV_CLOTH_IMPORT +#define NV_CLOTH_CALL_CONV PX_CALL_CONV +#define NV_CLOTH_API(ret_type) NV_CLOTH_LINKAGE ret_type NV_CLOTH_CALL_CONV + + + +/** \brief NVidia namespace */ +namespace nv +{ +/** \brief nvcloth namespace */ +namespace cloth +{ + class PxAllocatorCallback; + class PxErrorCallback; + class PxProfilerCallback; + class PxAssertHandler; + +/** \brief Initialize the library by passing in callback functions. + This needs to be called before using any other part of the library. + @param allocatorCallback Callback interface for memory allocations. Needs to return 16 byte aligned memory. + @param errorCallback Callback interface for debug/warning/error messages. + @param assertHandler Callback interface for asserts. + @param profilerCallback Optional callback interface for performance information. + @param autoDllIDCheck Leave as default parameter. This is used to check header and dll version compatibility. + */ +NV_CLOTH_API(void) + InitializeNvCloth(physx::PxAllocatorCallback* allocatorCallback, physx::PxErrorCallback* errorCallback, + nv::cloth::PxAssertHandler* assertHandler, physx::PxProfilerCallback* profilerCallback, + int autoDllIDCheck = NV_CLOTH_DLL_ID); +} +} + +//Allocator +NV_CLOTH_API(physx::PxAllocatorCallback*) GetNvClothAllocator(); //Only use internally + +namespace nv +{ +namespace cloth +{ + +/* Base class to handle assert failures */ +class PxAssertHandler +{ +public: + virtual ~PxAssertHandler() + { + } + virtual void operator()(const char* exp, const char* file, int line, bool& ignore) = 0; +}; + + +//Logging +void LogErrorFn (const char* fileName, int lineNumber, const char* msg, ...); +void LogInvalidParameterFn (const char* fileName, int lineNumber, const char* msg, ...); +void LogWarningFn(const char* fileName, int lineNumber, const char* msg, ...); +void LogInfoFn (const char* fileName, int lineNumber, const char* msg, ...); +///arguments: NV_CLOTH_LOG_ERROR("format %s %s\n","additional","arguments"); +#define NV_CLOTH_LOG_ERROR(...) nv::cloth::LogErrorFn(__FILE__,__LINE__,__VA_ARGS__) +#define NV_CLOTH_LOG_INVALID_PARAMETER(...) nv::cloth::LogInvalidParameterFn(__FILE__,__LINE__,__VA_ARGS__) +#define NV_CLOTH_LOG_WARNING(...) nv::cloth::LogWarningFn(__FILE__,__LINE__,__VA_ARGS__) +#define NV_CLOTH_LOG_INFO(...) nv::cloth::LogInfoFn(__FILE__,__LINE__,__VA_ARGS__) + +//ASSERT +NV_CLOTH_API(nv::cloth::PxAssertHandler*) GetNvClothAssertHandler(); //This function needs to be exposed to properly inline asserts outside this dll +#if !PX_ENABLE_ASSERTS +#if PX_VC +#define NV_CLOTH_ASSERT(exp) __noop +#define NV_CLOTH_ASSERT_WITH_MESSAGE(message, exp) __noop +#else +#define NV_CLOTH_ASSERT(exp) ((void)0) +#define NV_CLOTH_ASSERT_WITH_MESSAGE(message, exp) ((void)0) +#endif +#else +#if PX_VC +#define PX_CODE_ANALYSIS_ASSUME(exp) \ + __analysis_assume(!!(exp)) // This macro will be used to get rid of analysis warning messages if a NV_CLOTH_ASSERT is used + // to "guard" illegal mem access, for example. +#else +#define PX_CODE_ANALYSIS_ASSUME(exp) +#endif +#define NV_CLOTH_ASSERT(exp) \ + { \ + static bool _ignore = false; \ + ((void)((!!(exp)) || (!_ignore && ((*nv::cloth::GetNvClothAssertHandler())(#exp, __FILE__, __LINE__, _ignore), false)))); \ + PX_CODE_ANALYSIS_ASSUME(exp); \ + } +#define NV_CLOTH_ASSERT_WITH_MESSAGE(message, exp) \ + { \ + static bool _ignore = false; \ + ((void)((!!(exp)) || (!_ignore && ((*nv::cloth::GetNvClothAssertHandler())(message, __FILE__, __LINE__, _ignore), false)))); \ + PX_CODE_ANALYSIS_ASSUME(exp); \ + } +#endif + +//Profiler +physx::PxProfilerCallback* GetNvClothProfiler(); //Only use internally +#if PX_DEBUG || PX_CHECKED || PX_PROFILE +class NvClothProfileScoped +{ + public: + PX_FORCE_INLINE NvClothProfileScoped(const char* eventName, bool detached, uint64_t contextId, + const char* fileName, int lineno, physx::PxProfilerCallback* callback) + : mCallback(callback) + { + PX_UNUSED(fileName); + PX_UNUSED(lineno); + mProfilerData = NULL; //nullptr doesn't work here on mac + if (mCallback) + { + mEventName = eventName; + mDetached = detached; + mContextId = contextId; + mProfilerData = mCallback->zoneStart(mEventName, mDetached, mContextId); + } + } + ~NvClothProfileScoped(void) + { + if (mCallback) + { + mCallback->zoneEnd(mProfilerData, mEventName, mDetached, mContextId); + } + } + physx::PxProfilerCallback* mCallback; + const char* mEventName; + bool mDetached; + uint64_t mContextId; + void* mProfilerData; +}; + +#define NV_CLOTH_PROFILE_ZONE(x, y) \ + nv::cloth::NvClothProfileScoped PX_CONCAT(_scoped, __LINE__)(x, false, y, __FILE__, __LINE__, nv::cloth::GetNvClothProfiler()) +#define NV_CLOTH_PROFILE_START_CROSSTHREAD(x, y) \ + (GetNvClothProfiler()!=nullptr? \ + GetNvClothProfiler()->zoneStart(x, true, y):nullptr) +#define NV_CLOTH_PROFILE_STOP_CROSSTHREAD(profilerData, x, y) \ + if (GetNvClothProfiler()) \ + GetNvClothProfiler()->zoneEnd(profilerData, x, true, y) +#else + +#define NV_CLOTH_PROFILE_ZONE(x, y) +#define NV_CLOTH_PROFILE_START_CROSSTHREAD(x, y) nullptr +#define NV_CLOTH_PROFILE_STOP_CROSSTHREAD(profilerData, x, y) + +#endif + +} +} diff --git a/Source/ThirdParty/NvCloth/Cloth.h b/Source/ThirdParty/NvCloth/Cloth.h new file mode 100644 index 000000000..af913dda8 --- /dev/null +++ b/Source/ThirdParty/NvCloth/Cloth.h @@ -0,0 +1,477 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +#pragma once + +#include "NvCloth/Range.h" +#include "NvCloth/PhaseConfig.h" +#include +#include "NvCloth/Allocator.h" + +struct ID3D11Buffer; + +namespace nv +{ +namespace cloth +{ + +class Factory; +class Fabric; +class Cloth; + +#ifdef _MSC_VER +#pragma warning(disable : 4371) // layout of class may have changed from a previous version of the compiler due to + // better packing of member +#endif + +template +struct MappedRange : public Range +{ + MappedRange(T* first, T* last, const Cloth& cloth, void (Cloth::*lock)() const, void (Cloth::*unlock)() const) + : Range(first, last), mCloth(cloth), mLock(lock), mUnlock(unlock) + { + } + + MappedRange(const MappedRange& other) + : Range(other), mCloth(other.mCloth), mLock(other.mLock), mUnlock(other.mUnlock) + { + (mCloth.*mLock)(); + } + + ~MappedRange() + { + (mCloth.*mUnlock)(); + } + + private: + MappedRange& operator = (const MappedRange&); + + const Cloth& mCloth; + void (Cloth::*mLock)() const; + void (Cloth::*mUnlock)() const; +}; + +struct GpuParticles +{ + physx::PxVec4* mCurrent; + physx::PxVec4* mPrevious; + ID3D11Buffer* mBuffer; +}; + +// abstract cloth instance +class Cloth : public UserAllocated +{ + protected: + Cloth() {} + Cloth(const Cloth&); + Cloth& operator = (const Cloth&); + + public: + virtual ~Cloth() {} + + /** \brief Creates a duplicate of this Cloth instance. + Same as: + \code + getFactory().clone(*this); + \endcode + */ + virtual Cloth* clone(Factory& factory) const = 0; + + /** \brief Returns the fabric used to create this Cloth.*/ + virtual Fabric& getFabric() const = 0; + /** \brief Returns the Factory used to create this Cloth.*/ + virtual Factory& getFactory() const = 0; + + /* particle properties */ + /// Returns the number of particles simulated by this fabric. + virtual uint32_t getNumParticles() const = 0; + /** \brief Used internally to synchronize CPU and GPU particle memory.*/ + virtual void lockParticles() const = 0; //Might be better if it was called map/unmapParticles + /** \brief Used internally to synchronize CPU and GPU particle memory.*/ + virtual void unlockParticles() const = 0; + + /** \brief Returns the simulation particles of the current frame. + Each PxVec4 element contains the particle position in the XYZ components and the inverse mass in the W component. + The returned memory may be overwritten (to change attachment point locations for animation for example). + Setting the inverse mass to 0 locks the particle in place. + */ + virtual MappedRange getCurrentParticles() = 0; + + /** \brief Returns the simulation particles of the current frame, read only. + Similar to the non-const version of this function. + This version is preferred as it doesn't wake up the cloth to account for the possibility that particles were changed. + */ + virtual MappedRange getCurrentParticles() const = 0; + + /** \brief Returns the simulation particles of the previous frame. + Similar to getCurrentParticles(). + */ + virtual MappedRange getPreviousParticles() = 0; + + /** \brief Returns the simulation particles of the previous frame. + Similar to getCurrentParticles() const. + */ + virtual MappedRange getPreviousParticles() const = 0; + + /** \brief Returns platform dependent pointers to the current GPU particle memory.*/ + virtual GpuParticles getGpuParticles() = 0; + + + /** \brief Set the translation of the local space simulation after next call to simulate(). + This applies a force to make the cloth behave as if it was moved through space. + This does not move the particles as they are in local space. + Use the graphics transformation matrices to render the cloth in the proper location. + The applied force is proportional to the value set with Cloth::setLinearInertia(). + */ + virtual void setTranslation(const physx::PxVec3& trans) = 0; + + /** \brief Set the rotation of the local space simulation after next call to simulate(). + Similar to Cloth::setTranslation(). + The applied force is proportional to the value set with Cloth::setAngularInertia() and Cloth::setCentrifugalInertia(). + */ + virtual void setRotation(const physx::PxQuat& rot) = 0; + + /** \brief Returns the current translation value that was set using setTranslation().*/ + virtual const physx::PxVec3& getTranslation() const = 0; + /** \brief Returns the current rotation value that was set using setRotation().*/ + virtual const physx::PxQuat& getRotation() const = 0; + + /** \brief Set inertia derived from setTranslation() and setRotation() to zero (once).*/ + virtual void clearInertia() = 0; + + /** \brief Adjust the position of the cloth without affecting the dynamics (to call after a world origin shift, for example). */ + virtual void teleport(const physx::PxVec3& delta) = 0; + + /** \brief Adjust the position and rotation of the cloth without affecting the dynamics (to call after a world origin shift, for example). + The velocity will be set to zero this frame, unless setTranslation/setRotation is called with a different value after this function is called. + The correct order to use this is: + \code + cloth->teleportToLocation(pos, rot); + pos += velocity * dt; + rot += 0.5 * angularVelocity * rot * dt; + cloth->setTranslation(pos); + cloth->setRotation(rot); + \endcode + */ + virtual void teleportToLocation(const physx::PxVec3& translation, const physx::PxQuat& rotation) = 0; + + /** \brief Don't recalculate the velocity based on the values provided by setTranslation and setRotation for one frame (so it acts as if the velocity was the same as last frame). + This is useful when the cloth is moving while teleported, but the integration of the cloth position for that frame is already included in the teleport. + Example: + \code + pos += velocity * dt; + rot += 0.5 * angularVelocity * rot * dt; + cloth->teleportToLocation(pos, rot); + cloth->ignoreVelocityDiscontinuity(); + \endcode + */ + virtual void ignoreVelocityDiscontinuity() = 0; + + + /* solver parameters */ + + /** \brief Returns the delta time used for previous iteration.*/ + virtual float getPreviousIterationDt() const = 0; + + /** \brief Sets gravity in global coordinates.*/ + virtual void setGravity(const physx::PxVec3&) = 0; + /// Returns gravity set with setGravity(). + virtual physx::PxVec3 getGravity() const = 0; + + /** \brief Sets damping of local particle velocity (1/stiffnessFrequency). + 0 (default): velocity is unaffected, 1: velocity is zeroed + */ + virtual void setDamping(const physx::PxVec3&) = 0; + /// Returns value set with setDamping(). + virtual physx::PxVec3 getDamping() const = 0; + + // portion of local frame velocity applied to particles + // 0 (default): particles are unaffected + // same as damping: damp global particle velocity + virtual void setLinearDrag(const physx::PxVec3&) = 0; + virtual physx::PxVec3 getLinearDrag() const = 0; + virtual void setAngularDrag(const physx::PxVec3&) = 0; + virtual physx::PxVec3 getAngularDrag() const = 0; + + /** \brief Set the portion of local frame linear acceleration applied to particles. + 0: particles are unaffected, 1 (default): physically correct. + */ + virtual void setLinearInertia(const physx::PxVec3&) = 0; + /// Returns value set with getLinearInertia(). + virtual physx::PxVec3 getLinearInertia() const = 0; + /** \brief Similar to setLinearInertia(), but for angular inertia.*/ + virtual void setAngularInertia(const physx::PxVec3&) = 0; + /// Returns value set with setAngularInertia(). + virtual physx::PxVec3 getAngularInertia() const = 0; + /** \brief Similar to setLinearInertia(), but for centrifugal inertia.*/ + virtual void setCentrifugalInertia(const physx::PxVec3&) = 0; + ///Returns value set with setCentrifugalInertia(). + virtual physx::PxVec3 getCentrifugalInertia() const = 0; + + /** \brief Set target solver iterations per second. + At least 1 iteration per frame will be solved regardless of the value set. + */ + virtual void setSolverFrequency(float) = 0; + /// Returns gravity set with getSolverFrequency().*/ + virtual float getSolverFrequency() const = 0; + + // damp, drag, stiffness exponent per second + virtual void setStiffnessFrequency(float) = 0; + virtual float getStiffnessFrequency() const = 0; + + // filter width for averaging dt^2 factor of gravity and + // external acceleration, in numbers of iterations (default=30). + virtual void setAcceleationFilterWidth(uint32_t) = 0; + virtual uint32_t getAccelerationFilterWidth() const = 0; + + // setup edge constraint solver iteration + virtual void setPhaseConfig(Range configs) = 0; + + /* collision parameters */ + + /** \brief Set spheres for collision detection. + Elements of spheres contain PxVec4(x,y,z,r) where [x,y,z] is the center and r the radius of the sphere. + The values currently in range[first, last[ will be replaced with the content of spheres. + \code + cloth->setSpheres(Range(), 0, cloth->getNumSpheres()); //Removes all spheres + \endcode + */ + virtual void setSpheres(Range spheres, uint32_t first, uint32_t last) = 0; + virtual void setSpheres(Range startSpheres, Range targetSpheres) = 0; + /// Returns the number of spheres currently set. + virtual uint32_t getNumSpheres() const = 0; + + + /** \brief Set indices for capsule collision detection. + The indices define the spheres that form the end points between the capsule. + Every two elements in capsules define one capsule. + The values currently in range[first, last[ will be replaced with the content of capsules. + Note that first and last are indices to whole capsules consisting of 2 indices each. So if + you want to update the first two capsules (without changing the total number of capsules) + you would use the following code: + \code + uint32_t capsules[4] = { 0,1, 1,2 }; //Define indices for 2 capsules + //updates the indices of the first 2 capsules in cloth + cloth->setCapsules(Range(capsules, capsules + 4), 0, 2); + \endcode + */ + virtual void setCapsules(Range capsules, uint32_t first, uint32_t last) = 0; + /// Returns the number of capsules (which is half the number of capsule indices). + virtual uint32_t getNumCapsules() const = 0; + + /** \brief Sets plane values to be used with convex collision detection. + The planes are specified in the form ax + by + cz + d = 0, where elements in planes contain PxVec4(x,y,z,d). + [x,y,z] is required to be normalized. + The values currently in range [first, last[ will be replaced with the content of planes. + Use setConvexes to enable planes for collision detection. + */ + virtual void setPlanes(Range planes, uint32_t first, uint32_t last) = 0; + virtual void setPlanes(Range startPlanes, Range targetPlanes) = 0; + /// Returns the number of planes currently set. + virtual uint32_t getNumPlanes() const = 0; + + /** \brief Enable planes for collision. + convexMasks must contain masks of the form (1< convexMasks, uint32_t first, uint32_t last) = 0; + /// Returns the number of convexMasks currently set. + virtual uint32_t getNumConvexes() const = 0; + + /** \brief Set triangles for collision. + Each triangle in the list is defined by of 3 vertices. + The values currently in range [first, last[ will be replaced with the content of triangles. + */ + virtual void setTriangles(Range triangles, uint32_t first, uint32_t last) = 0; + virtual void setTriangles(Range startTriangles, Range targetTriangles, uint32_t first) = 0; + /// Returns the number of triangles currently set. + virtual uint32_t getNumTriangles() const = 0; + + /// Returns true if we use ccd + virtual bool isContinuousCollisionEnabled() const = 0; + /// Set if we use ccd or not (disabled by default) + virtual void enableContinuousCollision(bool) = 0; + + // controls how quickly mass is increased during collisions + virtual float getCollisionMassScale() const = 0; + virtual void setCollisionMassScale(float) = 0; + + /** \brief Set the cloth collision shape friction coefficient.*/ + virtual void setFriction(float) = 0; + ///Returns value set with setFriction(). + virtual float getFriction() const = 0; + + // set virtual particles for collision handling. + // each indices element consists of 3 particle + // indices and an index into the lerp weights array. + virtual void setVirtualParticles(Range indices, Range weights) = 0; + virtual uint32_t getNumVirtualParticles() const = 0; + virtual uint32_t getNumVirtualParticleWeights() const = 0; + + /* tether constraint parameters */ + + /** \brief Set Tether constraint scale. + 1.0 is the original scale of the Fabric. + 0.0 disables tether constraints in the Solver. + */ + virtual void setTetherConstraintScale(float scale) = 0; + ///Returns value set with setTetherConstraintScale(). + virtual float getTetherConstraintScale() const = 0; + /** \brief Set Tether constraint stiffness.. + 1.0 is the default. + <1.0 makes the constraints behave springy. + */ + virtual void setTetherConstraintStiffness(float stiffness) = 0; + ///Returns value set with setTetherConstraintStiffness(). + virtual float getTetherConstraintStiffness() const = 0; + + /* motion constraint parameters */ + + /** \brief Returns reference to motion constraints (position, radius) + The entire range must be written after calling this function. + */ + virtual Range getMotionConstraints() = 0; + /** \brief Removes all motion constraints. + */ + virtual void clearMotionConstraints() = 0; + virtual uint32_t getNumMotionConstraints() const = 0; + virtual void setMotionConstraintScaleBias(float scale, float bias) = 0; + virtual float getMotionConstraintScale() const = 0; + virtual float getMotionConstraintBias() const = 0; + virtual void setMotionConstraintStiffness(float stiffness) = 0; + virtual float getMotionConstraintStiffness() const = 0; + + /* separation constraint parameters */ + + // return reference to separation constraints (position, radius) + // The entire range must be written after calling this function. + virtual Range getSeparationConstraints() = 0; + virtual void clearSeparationConstraints() = 0; + virtual uint32_t getNumSeparationConstraints() const = 0; + + /* clear interpolation */ + + // assign current to previous positions for + // collision spheres, motion, and separation constraints + virtual void clearInterpolation() = 0; + + /* particle acceleration parameters */ + + // return reference to particle accelerations (in local coordinates) + // The entire range must be written after calling this function. + virtual Range getParticleAccelerations() = 0; + virtual void clearParticleAccelerations() = 0; + virtual uint32_t getNumParticleAccelerations() const = 0; + + /* wind */ + + /** /brief Set wind in global coordinates. Acts on the fabric's triangles. */ + virtual void setWindVelocity(physx::PxVec3) = 0; + ///Returns value set with setWindVelocity(). + virtual physx::PxVec3 getWindVelocity() const = 0; + /** /brief Sets the air drag coefficient. */ + virtual void setDragCoefficient(float) = 0; + ///Returns value set with setDragCoefficient(). + virtual float getDragCoefficient() const = 0; + /** /brief Sets the air lift coefficient. */ + virtual void setLiftCoefficient(float) = 0; + ///Returns value set with setLiftCoefficient(). + virtual float getLiftCoefficient() const = 0; + /** /brief Sets the fluid density used for air drag/lift calculations. */ + virtual void setFluidDensity(float) = 0; + ///Returns value set with setFluidDensity(). + virtual float getFluidDensity() const = 0; + + /* self collision */ + + /** /brief Set the distance particles need to be separated from each other withing the cloth. */ + virtual void setSelfCollisionDistance(float distance) = 0; + ///Returns value set with setSelfCollisionDistance(). + virtual float getSelfCollisionDistance() const = 0; + /** /brief Set the constraint stiffness for the self collision constraints. */ + virtual void setSelfCollisionStiffness(float stiffness) = 0; + ///Returns value set with setSelfCollisionStiffness(). + virtual float getSelfCollisionStiffness() const = 0; + + /** \brief Set self collision indices. + Each index in the range indicates that the particle at that index should be used for self collision. + If set to an empty range (default) all particles will be used. + */ + virtual void setSelfCollisionIndices(Range) = 0; + ///Returns the number of self collision indices set. + virtual uint32_t getNumSelfCollisionIndices() const = 0; + + /* rest positions */ + + // set rest particle positions used during self-collision + virtual void setRestPositions(Range) = 0; + virtual uint32_t getNumRestPositions() const = 0; + + /* bounding box */ + + /** \brief Returns current particle position bounds center in local space */ + virtual const physx::PxVec3& getBoundingBoxCenter() const = 0; + /** \brief Returns current particle position bounds size in local space */ + virtual const physx::PxVec3& getBoundingBoxScale() const = 0; + + /* sleeping (disabled by default) */ + + // max particle velocity (per axis) to pass sleep test + virtual void setSleepThreshold(float) = 0; + virtual float getSleepThreshold() const = 0; + // test sleep condition every nth millisecond + virtual void setSleepTestInterval(uint32_t) = 0; + virtual uint32_t getSleepTestInterval() const = 0; + // put cloth to sleep when n consecutive sleep tests pass + virtual void setSleepAfterCount(uint32_t) = 0; + virtual uint32_t getSleepAfterCount() const = 0; + virtual uint32_t getSleepPassCount() const = 0; + virtual bool isAsleep() const = 0; + virtual void putToSleep() = 0; + virtual void wakeUp() = 0; + + /** \brief Set user data. Not used internally. */ + virtual void setUserData(void*) = 0; + // Returns value set by setUserData(). + virtual void* getUserData() const = 0; +}; + +// wrappers to prevent non-const overload from marking particles dirty +inline MappedRange readCurrentParticles(const Cloth& cloth) +{ + return cloth.getCurrentParticles(); +} +inline MappedRange readPreviousParticles(const Cloth& cloth) +{ + return cloth.getPreviousParticles(); +} + +} // namespace cloth +} // namespace nv diff --git a/Source/ThirdParty/NvCloth/DxContextManagerCallback.h b/Source/ThirdParty/NvCloth/DxContextManagerCallback.h new file mode 100644 index 000000000..dee89c9fd --- /dev/null +++ b/Source/ThirdParty/NvCloth/DxContextManagerCallback.h @@ -0,0 +1,84 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +#pragma once + +struct ID3D11Device; +struct ID3D11DeviceContext; + +namespace nv +{ +namespace cloth +{ + +/** Callback interface to manage the DirectX context/device used for compute + * + */ +class DxContextManagerCallback +{ +public: + virtual ~DxContextManagerCallback() {} + /** + * \brief Acquire the D3D context for the current thread + * + * Acquisitions are allowed to be recursive within a single thread. + * You can acquire the context multiple times so long as you release + * it the same count. + */ + virtual void acquireContext() = 0; + + /** + * \brief Release the D3D context from the current thread + */ + virtual void releaseContext() = 0; + + /** + * \brief Return the D3D device to use for compute work + */ + virtual ID3D11Device* getDevice() const = 0; + + /** + * \brief Return the D3D context to use for compute work + */ + virtual ID3D11DeviceContext* getContext() const = 0; + + /** + * \brief Return if exposed buffers (only cloth particles at the moment) + * are created with D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX. + * + * The user is responsible to query and acquire the mutex of all + * corresponding buffers. + * todo: We should acquire the mutex locally if we continue to + * allow resource sharing across devices. + */ + virtual bool synchronizeResources() const = 0; +}; + +} +} \ No newline at end of file diff --git a/Source/ThirdParty/NvCloth/Fabric.h b/Source/ThirdParty/NvCloth/Fabric.h new file mode 100644 index 000000000..693a76ce7 --- /dev/null +++ b/Source/ThirdParty/NvCloth/Fabric.h @@ -0,0 +1,130 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +#pragma once + +#include "NvCloth/Callbacks.h" +#include "NvCloth/Allocator.h" +#include "NvCloth/ps/PsAtomic.h" + +namespace nv +{ +namespace cloth +{ + +class Factory; + +// abstract cloth constraints and triangle indices +class Fabric : public UserAllocated +{ +protected: + Fabric(const Fabric&); + Fabric& operator = (const Fabric&); + +protected: + Fabric() : mRefCount(1) + { + } + + virtual ~Fabric() + { + NV_CLOTH_ASSERT(0 == mRefCount); + } + +public: + /** \brief Returns the Factory used to create this Fabric.*/ + virtual Factory& getFactory() const = 0; + + /** \brief Returns the number of constraint solve phases stored. + Phases are groups of constraints that make up the general structure of the fabric. + Cloth instances can have different configuration settings per phase (see Cloth::setPhaseConfig()). + Phases are usually split by type (horizontal, vertical, bending, shearing), depending on the cooker used. + */ + virtual uint32_t getNumPhases() const = 0; + + /** \brief Returns the number of rest lengths stored. + Each constraint uses the rest value to determine if the two connected particles need to be pulled together or pushed apart. + */ + virtual uint32_t getNumRestvalues() const = 0; + + /** \brief Returns the number of constraint stiffness values stored. + It is optional for a Fabric to have per constraint stiffness values provided. + This function will return 0 if no values are stored. + Stiffness per constraint values stored here can be used if more fine grain control is required (as opposed to the values stored in the cloth's phase configuration). + The Cloth 's phase configuration stiffness values will be ignored if stiffness per constraint values are used. + */ + virtual uint32_t getNumStiffnessValues() const = 0; + + + /** \brief Returns the number of sets stored. + Sets connect a phase to a range of indices. + */ + virtual uint32_t getNumSets() const = 0; + + /** \brief Returns the number of indices stored. + Each constraint has a pair of indices that indicate which particles it connects. + */ + virtual uint32_t getNumIndices() const = 0; + /// Returns the number of particles. + virtual uint32_t getNumParticles() const = 0; + /// Returns the number of Tethers stored. + virtual uint32_t getNumTethers() const = 0; + /// Returns the number of triangles that make up the cloth mesh. + virtual uint32_t getNumTriangles() const = 0; + + /** Scales all constraint rest lengths.*/ + virtual void scaleRestvalues(float) = 0; + /** Scales all tether lengths.*/ + virtual void scaleTetherLengths(float) = 0; + + void incRefCount() + { + ps::atomicIncrement(&mRefCount); + NV_CLOTH_ASSERT(mRefCount > 0); + } + + /// Returns true if the object is destroyed + bool decRefCount() + { + NV_CLOTH_ASSERT(mRefCount > 0); + int result = ps::atomicDecrement(&mRefCount); + if (result == 0) + { + delete this; + return true; + } + return false; + } + + protected: + int32_t mRefCount; +}; + +} // namespace cloth +} // namespace nv diff --git a/Source/ThirdParty/NvCloth/Factory.h b/Source/ThirdParty/NvCloth/Factory.h new file mode 100644 index 000000000..46a7adfe5 --- /dev/null +++ b/Source/ThirdParty/NvCloth/Factory.h @@ -0,0 +1,194 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +#pragma once + +#include "NvCloth/Range.h" +#include +#include +#include "NvCloth/Allocator.h" + +typedef struct CUctx_st* CUcontext; + +namespace nv +{ +namespace cloth +{ +class DxContextManagerCallback; +class Factory; +} +} +NV_CLOTH_API(nv::cloth::Factory*) NvClothCreateFactoryCPU(); +NV_CLOTH_API(nv::cloth::Factory*) NvClothCreateFactoryCUDA(CUcontext); +NV_CLOTH_API(nv::cloth::Factory*) NvClothCreateFactoryDX11(nv::cloth::DxContextManagerCallback*); +NV_CLOTH_API(void) NvClothDestroyFactory(nv::cloth::Factory*); + +///Returns true if this dll was compiled with cuda support +NV_CLOTH_API(bool) NvClothCompiledWithCudaSupport(); +///Returns true if this dll was compiled with DX support +NV_CLOTH_API(bool) NvClothCompiledWithDxSupport(); + +namespace nv +{ +namespace cloth +{ + +class Fabric; +class Cloth; +class Solver; + +enum struct Platform +{ + CPU, + CUDA, + DX11 +}; + +/// abstract factory to create context-specific simulation components +/// such as cloth, solver, collision, etc. +class Factory : public UserAllocated +{ + protected: + Factory() {} + Factory(const Factory&); + Factory& operator = (const Factory&); + virtual ~Factory() {} + + friend NV_CLOTH_IMPORT void NV_CLOTH_CALL_CONV ::NvClothDestroyFactory(nv::cloth::Factory*); + + public: + virtual Platform getPlatform() const = 0; + + /** + \brief Create fabric data used to setup cloth object. + Look at the cooking extension for helper functions to create fabrics from meshes. + The returned fabric will have a refcount of 1. + @param numParticles number of particles, must be larger than any particle index + @param phaseIndices map from phase to set index + @param sets inclusive prefix sum of restvalue count per set + @param restvalues array of constraint rest values + @param indices array of particle index pair per constraint + */ + virtual Fabric* createFabric(uint32_t numParticles, Range phaseIndices, Range sets, + Range restvalues, Range stiffnessValues, Range indices, + Range anchors, Range tetherLengths, + Range triangles) = 0; + + /** + \brief Create cloth object. + @param particles initial particle positions. + @param fabric edge distance constraint structure + */ + virtual Cloth* createCloth(Range particles, Fabric& fabric) = 0; + + /** + \brief Create cloth solver object. + */ + virtual Solver* createSolver() = 0; + + /** + \brief Create a copy of a cloth instance + @param cloth the instance to be cloned, need not match the factory type + */ + virtual Cloth* clone(const Cloth& cloth) = 0; + + /** + \brief Extract original data from a fabric object. + Use the getNum* methods on Cloth to get the memory requirements before calling this function. + @param fabric to extract from, must match factory type + @param phaseIndices pre-allocated memory range to write phase => set indices + @param sets pre-allocated memory range to write sets + @param restvalues pre-allocated memory range to write restvalues + @param indices pre-allocated memory range to write indices + */ + virtual void extractFabricData(const Fabric& fabric, Range phaseIndices, Range sets, + Range restvalues, Range stiffnessValues, Range indices, Range anchors, + Range tetherLengths, Range triangles) const = 0; + + /** + \brief Extract current collision spheres and capsules from a cloth object. + Use the getNum* methods on Cloth to get the memory requirements before calling this function. + @param cloth the instance to extract from, must match factory type + @param spheres pre-allocated memory range to write spheres + @param capsules pre-allocated memory range to write capsules + @param planes pre-allocated memory range to write planes + @param convexes pre-allocated memory range to write convexes + @param triangles pre-allocated memory range to write triangles + */ + virtual void extractCollisionData(const Cloth& cloth, Range spheres, Range capsules, + Range planes, Range convexes, Range triangles) const = 0; + + /** + Extract current motion constraints from a cloth object + Use the getNum* methods on Cloth to get the memory requirements before calling this function. + @param cloth the instance to extract from, must match factory type + @param destConstraints pre-allocated memory range to write constraints + */ + virtual void extractMotionConstraints(const Cloth& cloth, Range destConstraints) const = 0; + + /** + Extract current separation constraints from a cloth object + @param cloth the instance to extract from, must match factory type + @param destConstraints pre-allocated memory range to write constraints + */ + virtual void extractSeparationConstraints(const Cloth& cloth, Range destConstraints) const = 0; + + /** + Extract current particle accelerations from a cloth object + @param cloth the instance to extract from, must match factory type + @param destAccelerations pre-allocated memory range to write accelerations + */ + virtual void extractParticleAccelerations(const Cloth& cloth, Range destAccelerations) const = 0; + + /** + Extract virtual particles from a cloth object + @param cloth the instance to extract from, must match factory type + @param destIndices pre-allocated memory range to write indices + @param destWeights pre-allocated memory range to write weights + */ + virtual void extractVirtualParticles(const Cloth& cloth, Range destIndices, + Range destWeights) const = 0; + + /** + Extract self collision indices from cloth object. + @param cloth the instance to extract from, must match factory type + @param destIndices pre-allocated memory range to write indices + */ + virtual void extractSelfCollisionIndices(const Cloth& cloth, Range destIndices) const = 0; + + /** + Extract particle rest positions from cloth object. + @param cloth the instance to extract from, must match factory type + @param destRestPositions pre-allocated memory range to write rest positions + */ + virtual void extractRestPositions(const Cloth& cloth, Range destRestPositions) const = 0; +}; + +} // namespace cloth +} // namespace nv diff --git a/Source/ThirdParty/NvCloth/License.txt b/Source/ThirdParty/NvCloth/License.txt new file mode 100644 index 000000000..174b4d88d --- /dev/null +++ b/Source/ThirdParty/NvCloth/License.txt @@ -0,0 +1,69 @@ +Nvidia Source Code License (1-Way Commercial) + +1. Definitions + +"Licensor" means any person or entity that distributes its Work. "Software" +means the original work of authorship made available under this License. "Work" +means the Software and any additions to or derivative works of the Software that +are made available under this License. The terms "reproduce," "reproduction," +"derivative works," and "distribution" have the meaning as provided under U.S. +copyright law; provided, however, that for the purposes of this License, +derivative works shall not include works that remain separable from, or merely +link (or bind by name) to the interfaces of, the Work. Works, including the +Software, are "made available" under this License by including in or with the +Work either (a) a copyright notice referencing the applicability of this License +to the Work, or (b) a copy of this License. + +2. License Grants + +2.1 Copyright Grant. Subject to the terms and conditions of this License, each +Licensor grants to you a perpetual, worldwide, non-exclusive, royalty-free, +copyright license to reproduce, prepare derivative works of, publicly display, +publicly perform, sublicense and distribute its Work and any resulting +derivative works in any form. + +3. Limitations + +3.1 Redistribution. You may reproduce or distribute the Work only if (a) you do +so under this License, (b) you include a complete copy of this License with your +distribution, and (c) you retain without modification any copyright, patent, +trademark, or attribution notices that are present in the Work. + +3.2 Derivative Works. You may specify that additional or different terms apply +to the use, reproduction, and distribution of your derivative works of the Work +("Your Terms") only if you identify the specific derivative works that are +subject to Your Terms. Notwithstanding Your Terms, this License (including the +redistribution requirements in Section 3.1) will continue to apply to the Work +itself. + +3.3 Patent Claims. If you bring or threaten to bring a patent claim against any +Licensor (including any claim, cross-claim or counterclaim in a lawsuit) to +enforce any patents that you allege are infringed by any Work, then your rights +under this License from such Licensor (including the grant in Section 2.1) will +terminate immediately. + +3.4 Trademarks. This License does not grant any rights to use any Licensor's or +its affiliates' names, logos, or trademarks, except as necessary to reproduce +the notices described in this License. + +3.5 Termination. If you violate any term of this License, then your rights under +this License (including the grant in Section 2.1) will terminate +immediately. + +4. Disclaimer of Warranty. + +THE WORK IS PROVIDED "AS IS" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +EITHER EXPRESS OR IMPLIED, INCLUDING WARRANTIES OR CONDITIONS OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE OR NON-INFRINGEMENT. +YOU BEAR THE RISK OF UNDERTAKING ANY ACTIVITIES UNDER THIS LICENSE. + +5. Limitation of Liability. + +EXCEPT AS PROHIBITED BY APPLICABLE LAW, IN NO EVENT AND UNDER NO LEGAL THEORY, +WHETHER IN TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE SHALL ANY +LICENSOR BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY DIRECT, INDIRECT, SPECIAL, +INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATED TO THIS LICENSE, +THE USE OR INABILITY TO USE THE WORK (INCLUDING BUT NOT LIMITED TO LOSS OF +GOODWILL, BUSINESS INTERRUPTION, LOST PROFITS OR DATA, COMPUTER FAILURE OR +MALFUNCTION, OR ANY OTHER COMMERCIAL DAMAGES OR LOSSES), EVEN IF THE LICENSOR +HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. diff --git a/Source/ThirdParty/NvCloth/NvCloth.Build.cs b/Source/ThirdParty/NvCloth/NvCloth.Build.cs new file mode 100644 index 000000000..ea2bc02c8 --- /dev/null +++ b/Source/ThirdParty/NvCloth/NvCloth.Build.cs @@ -0,0 +1,48 @@ +// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. + +using System.IO; +using Flax.Build; +using Flax.Build.NativeCpp; + +/// +/// https://github.com/NVIDIAGameWorks/NvCloth +/// +public class NvCloth : DepsModule +{ + /// + public override void Init() + { + base.Init(); + + LicenseType = LicenseTypes.Custom; + LicenseFilePath = "License.txt"; + + // Merge third-party modules into engine binary + BinaryModuleName = "FlaxEngine"; + } + + /// + public override void Setup(BuildOptions options) + { + base.Setup(options); + + options.PublicDefinitions.Add("WITH_CLOTH"); + options.PublicDefinitions.Add("NV_CLOTH_IMPORT="); + + var libName = "NvCloth_x64"; + switch (options.Platform.Target) + { + case TargetPlatform.PS4: + case TargetPlatform.PS5: + case TargetPlatform.Android: + libName = "NvCloth"; + break; + case TargetPlatform.Switch: + libName = "NvCloth"; + options.PublicIncludePaths.Add(Path.Combine(Globals.EngineRoot, "Source/Platforms/Switch/Binaries/Data/PhysX/physx/include")); + options.PublicIncludePaths.Add(Path.Combine(Globals.EngineRoot, "Source/Platforms/Switch/Binaries/Data/PhysX/physx/include/foundation")); + break; + } + AddLib(options, options.DepsFolder, libName); + } +} diff --git a/Source/ThirdParty/NvCloth/NvClothExt/ClothFabricCooker.h b/Source/ThirdParty/NvCloth/NvClothExt/ClothFabricCooker.h new file mode 100644 index 000000000..329c455e2 --- /dev/null +++ b/Source/ThirdParty/NvCloth/NvClothExt/ClothFabricCooker.h @@ -0,0 +1,225 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + + +#ifndef NV_CLOTH_EXTENSIONS_CLOTH_FABRIC_COOKER_H +#define NV_CLOTH_EXTENSIONS_CLOTH_FABRIC_COOKER_H + +/** \addtogroup extensions + @{ +*/ + +#include "ClothMeshDesc.h" +#include "NvCloth/Fabric.h" +#include "NvCloth/Factory.h" + +namespace nv +{ +namespace cloth +{ + +struct CookedData +{ + uint32_t mNumParticles; + Range mPhaseIndices; + Range mPhaseTypes; + Range mSets; + Range mRestvalues; + Range mStiffnessValues; + Range mIndices; + Range mAnchors; + Range mTetherLengths; + Range mTriangles; +}; + +/** +\brief Describe type of phase in cloth fabric. +\see Fabric for an explanation of concepts on phase and set. +*/ +struct ClothFabricPhaseType +{ + enum Enum + { + eINVALID, //!< invalid type + eVERTICAL, //!< resists stretching or compression, usually along the gravity + eHORIZONTAL, //!< resists stretching or compression, perpendicular to the gravity + eBENDING, //!< resists out-of-plane bending in angle-based formulation + eSHEARING, //!< resists in-plane shearing along (typically) diagonal edges, + eCOUNT // internal use only + }; +}; + +/** +\brief References a set of constraints that can be solved in parallel. +\see Fabric for an explanation of the concepts on phase and set. +*/ +struct ClothFabricPhase +{ + ClothFabricPhase(ClothFabricPhaseType::Enum type = + ClothFabricPhaseType::eINVALID, physx::PxU32 index = 0); + + /** + \brief Type of constraints to solve. + */ + ClothFabricPhaseType::Enum phaseType; + + /** + \brief Index of the set that contains the particle indices. + */ + physx::PxU32 setIndex; +}; + +PX_INLINE ClothFabricPhase::ClothFabricPhase( + ClothFabricPhaseType::Enum type, physx::PxU32 index) + : phaseType(type) + , setIndex(index) +{} + +/** +\brief References all the data required to create a fabric. +\see ClothFabricCooker.getDescriptor() +*/ +class ClothFabricDesc +{ +public: + /** \brief The number of particles needed when creating a PxCloth instance from the fabric. */ + physx::PxU32 nbParticles; + + /** \brief The number of solver phases. */ + physx::PxU32 nbPhases; + /** \brief Array defining which constraints to solve each phase. See #Fabric.getPhases(). */ + const ClothFabricPhase* phases; + + /** \brief The number of sets in the fabric. */ + physx::PxU32 nbSets; + /** \brief Array with an index per set which points one entry beyond the last constraint of the set. See #Fabric.getSets(). */ + const physx::PxU32* sets; + + /** \brief Array of particle indices which specifies the pair of constrained vertices. See #Fabric.getParticleIndices(). */ + const physx::PxU32* indices; + /** \brief Array of rest values for each constraint. See #Fabric.getRestvalues(). */ + const physx::PxReal* restvalues; + + /** \brief Size of tetherAnchors and tetherLengths arrays, needs to be multiple of nbParticles. */ + physx::PxU32 nbTethers; + /** \brief Array of particle indices specifying the tether anchors. See #Fabric.getTetherAnchors(). */ + const physx::PxU32* tetherAnchors; + /** \brief Array of rest distance between tethered particle pairs. See #Fabric.getTetherLengths(). */ + const physx::PxReal* tetherLengths; + + physx::PxU32 nbTriangles; + const physx::PxU32* triangles; + + /** + \brief constructor sets to default. + */ + PX_INLINE ClothFabricDesc(); + + /** + \brief (re)sets the structure to the default. + */ + PX_INLINE void setToDefault(); + + /** + \brief Returns true if the descriptor is valid. + \return True if the current settings are valid + */ + PX_INLINE bool isValid() const; +}; + +PX_INLINE ClothFabricDesc::ClothFabricDesc() +{ + setToDefault(); +} + +PX_INLINE void ClothFabricDesc::setToDefault() +{ + memset(this, 0, sizeof(ClothFabricDesc)); +} + +PX_INLINE bool ClothFabricDesc::isValid() const +{ + return nbParticles && nbPhases && phases && restvalues && nbSets + && sets && indices && (!nbTethers || (tetherAnchors && tetherLengths)) + && (!nbTriangles || triangles); +} + +///Use NvClothCreateFabricCooker() to create an implemented instance +class NV_CLOTH_IMPORT ClothFabricCooker : public UserAllocated +{ +public: + virtual ~ClothFabricCooker(){} + + /** + \brief Cooks a triangle mesh to a ClothFabricDesc. + \param desc The cloth mesh descriptor on which the generation of the cooked mesh depends. + \param gravity A normalized vector which specifies the direction of gravity. + This information allows the cooker to generate a fabric with higher quality simulation behavior. + The gravity vector should point in the direction gravity will be pulling towards in the most common situation/at rest. + e.g. For flags it might be beneficial to set the gravity horizontal if they are cooked in landscape orientation, as a flag will hang in portrait orientation at rest. + \param useGeodesicTether A flag to indicate whether to compute geodesic distance for tether constraints. + \note The geodesic option for tether only works for manifold input. For non-manifold input, a simple Euclidean distance will be used. + For more detailed cooker status for such cases, try running ClothGeodesicTetherCooker directly. + */ + virtual bool cook(const ClothMeshDesc& desc, physx::PxVec3 gravity, bool useGeodesicTether = true) = 0; + + /** \brief Returns fabric cooked data for creating fabrics. */ + virtual CookedData getCookedData() const = 0; + + /** \brief Returns the fabric descriptor to create the fabric. */ + virtual ClothFabricDesc getDescriptor() const = 0; + + /** \brief Saves the fabric data to a platform and version dependent stream. */ + virtual void save(physx::PxOutputStream& stream, bool platformMismatch) const = 0; +}; + +/** @} */ + +} // namespace cloth +} // namespace nv + + +NV_CLOTH_API(nv::cloth::ClothFabricCooker*) NvClothCreateFabricCooker(); + +/** +\brief Cooks a triangle mesh to a Fabric. + +\param factory The factory for which the cloth is cooked. +\param desc The cloth mesh descriptor on which the generation of the cooked mesh depends. +\param gravity A normalized vector which specifies the direction of gravity. +This information allows the cooker to generate a fabric with higher quality simulation behavior. +\param phaseTypes Optional array where phase type information can be writen to. +\param useGeodesicTether A flag to indicate whether to compute geodesic distance for tether constraints. +\return The created cloth fabric, or NULL if creation failed. +*/ +NV_CLOTH_API(nv::cloth::Fabric*) NvClothCookFabricFromMesh(nv::cloth::Factory* factory, + const nv::cloth::ClothMeshDesc& desc, const float gravity[3], + nv::cloth::Vector::Type* phaseTypes = nullptr, bool useGeodesicTether = true); + +#endif // NV_CLOTH_EXTENSIONS_CLOTH_FABRIC_COOKER_H diff --git a/Source/ThirdParty/NvCloth/NvClothExt/ClothMeshDesc.h b/Source/ThirdParty/NvCloth/NvClothExt/ClothMeshDesc.h new file mode 100644 index 000000000..9ec187c9c --- /dev/null +++ b/Source/ThirdParty/NvCloth/NvClothExt/ClothMeshDesc.h @@ -0,0 +1,211 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + + +#ifndef NV_CLOTH_EXTENSIONS_CLOTHMESHDESC +#define NV_CLOTH_EXTENSIONS_CLOTHMESHDESC +/** \addtogroup extensions +@{ +*/ + +#include "foundation/PxVec3.h" + +namespace nv +{ +namespace cloth +{ + +struct StridedData +{ + /** + \brief The offset in bytes between consecutive samples in the data. + + Default: 0 + */ + physx::PxU32 stride; + const void* data; + + StridedData() : stride( 0 ), data( NULL ) {} + + template + PX_INLINE const TDataType& at( physx::PxU32 idx ) const + { + physx::PxU32 theStride( stride ); + if ( theStride == 0 ) + theStride = sizeof( TDataType ); + physx::PxU32 offset( theStride * idx ); + return *(reinterpret_cast( reinterpret_cast< const physx::PxU8* >( data ) + offset )); + } +}; + +struct BoundedData : public StridedData +{ + physx::PxU32 count; + BoundedData() : count( 0 ) {} +}; + +/** +\brief Enum with flag values to be used in ClothMeshDesc. +*/ +struct MeshFlag +{ + enum Enum + { + e16_BIT_INDICES = (1<<1) //!< Denotes the use of 16-bit vertex indices + }; +}; + +/** +\brief Descriptor class for a cloth mesh. +*/ +class ClothMeshDesc +{ +public: + + /** + \brief Pointer to first vertex point. + */ + BoundedData points; + + /** + \brief Pointer to first stiffness value in stiffnes per vertex array. empty if unused. + */ + BoundedData pointsStiffness; + + /** + \brief Determines whether particle is simulated or static. + A positive value denotes that the particle is being simulated, zero denotes a static particle. + This data is used to generate tether and zero stretch constraints. + If invMasses.data is null, all particles are assumed to be simulated + and no tether and zero stretch constraints are being generated. + */ + BoundedData invMasses; + + /** + \brief Pointer to the first triangle. + + These are triplets of 0 based indices: + vert0 vert1 vert2 + vert0 vert1 vert2 + vert0 vert1 vert2 + ... + + where vert* is either a 32 or 16 bit unsigned integer. There are a total of 3*count indices. + The stride determines the byte offset to the next index triple. + + This is declared as a void pointer because it is actually either an physx::PxU16 or a physx::PxU32 pointer. + */ + BoundedData triangles; + + /** + \brief Pointer to the first quad. + + These are quadruples of 0 based indices: + vert0 vert1 vert2 vert3 + vert0 vert1 vert2 vert3 + vert0 vert1 vert2 vert3 + ... + + where vert* is either a 32 or 16 bit unsigned integer. There are a total of 4*count indices. + The stride determines the byte offset to the next index quadruple. + + This is declared as a void pointer because it is actually either an physx::PxU16 or a physx::PxU32 pointer. + */ + BoundedData quads; + + /** + \brief Flags bits, combined from values of the enum ::MeshFlag + */ + unsigned int flags; + + /** + \brief constructor sets to default. + */ + PX_INLINE ClothMeshDesc(); + /** + \brief (re)sets the structure to the default. + */ + PX_INLINE void setToDefault(); + /** + \brief Returns true if the descriptor is valid. + \return True if the current settings are valid + */ + PX_INLINE bool isValid() const; +}; + +PX_INLINE ClothMeshDesc::ClothMeshDesc() +{ + flags = 0; +} + +PX_INLINE void ClothMeshDesc::setToDefault() +{ + *this = ClothMeshDesc(); +} + +PX_INLINE bool ClothMeshDesc::isValid() const +{ + if (points.count < 3) // at least 1 triangle + return false; + if ((pointsStiffness.count != points.count) && pointsStiffness.count != 0) + return false; // either all or none of the points can have stiffness information + if (points.count > 0xffff && flags & MeshFlag::e16_BIT_INDICES) + return false; + if (!points.data) + return false; + if (points.stride < sizeof(physx::PxVec3)) // should be at least one point + return false; + + if (invMasses.data && invMasses.stride < sizeof(float)) + return false; + if (invMasses.data && invMasses.count != points.count) + return false; + + if (!triangles.count && !quads.count) // no support for non-indexed mesh + return false; + if (triangles.count && !triangles.data) + return false; + if (quads.count && !quads.data) + return false; + + physx::PxU32 indexSize = (flags & MeshFlag::e16_BIT_INDICES) ? sizeof(physx::PxU16) : sizeof(physx::PxU32); + if (triangles.count && triangles.stride < indexSize*3) + return false; + if (quads.count && quads.stride < indexSize*4) + return false; + + return true; +} + +} // namespace cloth +} // namespace nv + + +/** @} */ +#endif diff --git a/Source/ThirdParty/NvCloth/NvClothExt/ClothMeshQuadifier.h b/Source/ThirdParty/NvCloth/NvClothExt/ClothMeshQuadifier.h new file mode 100644 index 000000000..731d361d8 --- /dev/null +++ b/Source/ThirdParty/NvCloth/NvClothExt/ClothMeshQuadifier.h @@ -0,0 +1,78 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + + +#ifndef NV_CLOTH_EXTENSIONS_CLOTH_EDGE_QUADIFIER_H +#define NV_CLOTH_EXTENSIONS_CLOTH_EDGE_QUADIFIER_H + +/** \addtogroup extensions +@{ +*/ + +#include "ClothMeshDesc.h" +#include "NvCloth/Callbacks.h" +#include "NvCloth/Allocator.h" + +namespace nv +{ +namespace cloth +{ + +class ClothMeshQuadifier : public UserAllocated +{ +public: + virtual ~ClothMeshQuadifier(){} + + /** + \brief Convert triangles of ClothMeshDesc to quads. + \details In NvCloth, quad dominant mesh representations are preferable to pre-triangulated versions. + In cases where the mesh has been already triangulated, this class provides a meachanism to + convert (quadify) some triangles back to quad representations. + \see ClothFabricCooker + \param desc The cloth mesh descriptor prepared for cooking + */ + virtual bool quadify(const ClothMeshDesc& desc) = 0; + + /** + \brief Returns a mesh descriptor with some triangle pairs converted to quads. + \note The returned descriptor is valid only within the lifespan of ClothMeshQuadifier class. + */ + + virtual ClothMeshDesc getDescriptor() const = 0; + +}; + +} // namespace cloth +} // namespace nv + +NV_CLOTH_API(nv::cloth::ClothMeshQuadifier*) NvClothCreateMeshQuadifier(); + +/** @} */ + +#endif // NV_CLOTH_EXTENSIONS_CLOTH_EDGE_QUADIFIER_H diff --git a/Source/ThirdParty/NvCloth/NvClothExt/ClothTetherCooker.h b/Source/ThirdParty/NvCloth/NvClothExt/ClothTetherCooker.h new file mode 100644 index 000000000..ce20f6c25 --- /dev/null +++ b/Source/ThirdParty/NvCloth/NvClothExt/ClothTetherCooker.h @@ -0,0 +1,94 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + + +#ifndef NV_CLOTH_EXTENSIONS_CLOTH_TETHER_COOKER_H +#define NV_CLOTH_EXTENSIONS_CLOTH_TETHER_COOKER_H + +/** \addtogroup extensions +@{ +*/ + +#include "ClothMeshDesc.h" +#include "NvCloth/Allocator.h" + +namespace nv +{ +namespace cloth +{ + +class ClothTetherCooker : public UserAllocated +{ +public: + virtual ~ClothTetherCooker(){} + + /** + \brief Compute tether data from ClothMeshDesc with simple distance measure. + \details The tether constraint in NvCloth requires rest distance and anchor index to be precomputed during cooking time. + This cooker computes a simple Euclidean distance to closest anchor point. + The Euclidean distance measure works reasonably for flat cloth and flags and computation time is very fast. + With this cooker, there is only one tether anchor point per particle. + \see ClothTetherGeodesicCooker for more accurate distance estimation. + \param desc The cloth mesh descriptor prepared for cooking + */ + virtual bool cook(const ClothMeshDesc &desc) = 0; + + /** + \brief Returns cooker status + \details This function returns cooker status after cooker computation is done. + A non-zero return value indicates a failure. + */ + virtual uint32_t getCookerStatus() const = 0; //From APEX + + /** + \brief Returns number of tether anchors per particle + \note Returned number indicates the maximum anchors. + If some particles are assigned fewer anchors, the anchor indices will be physx::PxU32(-1) + \note If there is no attached point in the input mesh descriptor, this will return 0 and no tether data will be generated. + */ + virtual physx::PxU32 getNbTethersPerParticle() const = 0; + + /** + \brief Returns computed tether data. + \details This function returns anchor indices for each particle as well as desired distance between the tether anchor and the particle. + The user buffers should be at least as large as number of particles. + */ + virtual void getTetherData(physx::PxU32* userTetherAnchors, physx::PxReal* userTetherLengths) const = 0; + +}; + +} // namespace cloth +} // namespace nv + +NV_CLOTH_API(nv::cloth::ClothTetherCooker*) NvClothCreateSimpleTetherCooker(); +NV_CLOTH_API(nv::cloth::ClothTetherCooker*) NvClothCreateGeodesicTetherCooker(); + +/** @} */ + +#endif // NV_CLOTH_EXTENSIONS_CLOTH_TETHER_COOKER_H diff --git a/Source/ThirdParty/NvCloth/PhaseConfig.h b/Source/ThirdParty/NvCloth/PhaseConfig.h new file mode 100644 index 000000000..29fb73573 --- /dev/null +++ b/Source/ThirdParty/NvCloth/PhaseConfig.h @@ -0,0 +1,62 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +#pragma once + +#include + +namespace nv +{ +namespace cloth +{ + +struct PhaseConfig +{ + PhaseConfig(uint16_t index = uint16_t(-1)) + : mStiffness(1.0f) + , mStiffnessMultiplier(1.0f) + , mCompressionLimit(1.0f) + , mStretchLimit(1.0f) + , mPhaseIndex(index) + , mPadding(0xffff) + { + } + + //These 4 floats need to be in order as they are loaded in to simd vectors in the solver + float mStiffness; // target convergence rate per iteration (1/solverFrequency) + float mStiffnessMultiplier; + float mCompressionLimit; + float mStretchLimit; + + uint16_t mPhaseIndex; + uint16_t mPadding; +}; + +} // namespace cloth +} // namespace nv diff --git a/Source/ThirdParty/NvCloth/Range.h b/Source/ThirdParty/NvCloth/Range.h new file mode 100644 index 000000000..a1e41d425 --- /dev/null +++ b/Source/ThirdParty/NvCloth/Range.h @@ -0,0 +1,155 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +#pragma once + +#include "NvCloth/Callbacks.h" + +namespace nv +{ +namespace cloth +{ + +template +struct Range +{ + /** \brief Construct an empty range. + */ + Range(); + + /** \brief Construct a range (array like container) using existing memory. + Range doesn't take ownership of this memory. + Interface works similar to std::vector. + @param begin start of the memory + @param end end of the memory range, point to one element past the last valid element. + */ + Range(T* begin, T* end); + + template + Range(const Range& other); + + uint32_t size() const; + bool empty() const; + + void popFront(); + void popBack(); + + T* begin() const; + T* end() const; + + T& front() const; + T& back() const; + + T& operator[](uint32_t i) const; + + private: + T* mBegin; + T* mEnd; // past last element (like std::vector::end()) +}; + +template +Range::Range() +: mBegin(0), mEnd(0) +{ +} + +template +Range::Range(T* begin, T* end) +: mBegin(begin), mEnd(end) +{ +} + +template +template +Range::Range(const Range& other) +: mBegin(other.begin()), mEnd(other.end()) +{ +} + +template +uint32_t Range::size() const +{ + return uint32_t(mEnd - mBegin); +} + +template +bool Range::empty() const +{ + return mBegin >= mEnd; +} + +template +void Range::popFront() +{ + NV_CLOTH_ASSERT(mBegin < mEnd); + ++mBegin; +} + +template +void Range::popBack() +{ + NV_CLOTH_ASSERT(mBegin < mEnd); + --mEnd; +} + +template +T* Range::begin() const +{ + return mBegin; +} + +template +T* Range::end() const +{ + return mEnd; +} + +template +T& Range::front() const +{ + NV_CLOTH_ASSERT(mBegin < mEnd); + return *mBegin; +} + +template +T& Range::back() const +{ + NV_CLOTH_ASSERT(mBegin < mEnd); + return mEnd[-1]; +} + +template +T& Range::operator[](uint32_t i) const +{ + NV_CLOTH_ASSERT(mBegin + i < mEnd); + return mBegin[i]; +} + +} // namespace cloth +} // namespace nv diff --git a/Source/ThirdParty/NvCloth/Solver.h b/Source/ThirdParty/NvCloth/Solver.h new file mode 100644 index 000000000..0d2bbb816 --- /dev/null +++ b/Source/ThirdParty/NvCloth/Solver.h @@ -0,0 +1,111 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +#pragma once + +#include "NvCloth/Allocator.h" +#include "NvCloth/Range.h" +#include "NvCloth/ps/PsArray.h" + +namespace nv +{ +namespace cloth +{ + +class Cloth; + +// called during inter-collision, user0 and user1 are the user data from each cloth +typedef bool (*InterCollisionFilter)(void* user0, void* user1); + +/// base class for solvers +class Solver : public UserAllocated +{ + protected: + Solver() {} + Solver(const Solver&); + Solver& operator = (const Solver&); + + public: + virtual ~Solver() {} + + /// Adds cloth object. + virtual void addCloth(Cloth* cloth) = 0; + + /// Adds an array of cloth objects. + virtual void addCloths(Range cloths) = 0; + + /// Removes cloth object. + virtual void removeCloth(Cloth* cloth) = 0; + + /// Returns the numer of cloths added to the solver. + virtual int getNumCloths() const = 0; + + /// Returns the pointer to the first cloth added to the solver + virtual Cloth * const * getClothList() const = 0; + + // functions executing the simulation work. + /** \brief Begins a simulation frame. + Returns false if there is nothing to simulate. + Use simulateChunk() after calling this function to do the computation. + @param dt The delta time for this frame. + */ + virtual bool beginSimulation(float dt) = 0; + + /** \brief Do the computationally heavy part of the simulation. + Call this function getSimulationChunkCount() times to do the entire simulation. + This function can be called from multiple threads in parallel. + All Chunks need to be simulated before ending the frame. + */ + virtual void simulateChunk(int idx) = 0; + + /** \brief Finishes up the simulation. + This function can be expensive if inter-collision is enabled. + */ + virtual void endSimulation() = 0; + + /** \brief Returns the number of chunks that need to be simulated this frame. + */ + virtual int getSimulationChunkCount() const = 0; + + /// inter-collision parameters + /// Note that using intercollision with more than 32 cloths added to the solver will cause undefined behavior + virtual void setInterCollisionDistance(float distance) = 0; + virtual float getInterCollisionDistance() const = 0; + virtual void setInterCollisionStiffness(float stiffness) = 0; + virtual float getInterCollisionStiffness() const = 0; + virtual void setInterCollisionNbIterations(uint32_t nbIterations) = 0; + virtual uint32_t getInterCollisionNbIterations() const = 0; + virtual void setInterCollisionFilter(InterCollisionFilter filter) = 0; + + /// Returns true if an unrecoverable error has occurred. + virtual bool hasError() const = 0; +}; + +} // namespace cloth +} // namespace nv diff --git a/Source/ThirdParty/NvCloth/ps/Ps.h b/Source/ThirdParty/NvCloth/ps/Ps.h new file mode 100644 index 000000000..1c1843fe0 --- /dev/null +++ b/Source/ThirdParty/NvCloth/ps/Ps.h @@ -0,0 +1,75 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +#ifndef PSFOUNDATION_PS_H +#define PSFOUNDATION_PS_H + +/*! \file top level include file for shared foundation */ + +#include "foundation/Px.h" + +/** +Platform specific defines +*/ +#if PX_WINDOWS_FAMILY || PX_XBOXONE +#pragma intrinsic(memcmp) +#pragma intrinsic(memcpy) +#pragma intrinsic(memset) +#pragma intrinsic(abs) +#pragma intrinsic(labs) +#endif + +// An expression that should expand to nothing in non PX_CHECKED builds. +// We currently use this only for tagging the purpose of containers for memory use tracking. +#if PX_CHECKED +#define PX_DEBUG_EXP(x) (x) +#else +#define PX_DEBUG_EXP(x) +#endif + +#define PX_SIGN_BITMASK 0x80000000 + +/** \brief NVidia namespace */ +namespace nv +{ +/** \brief nvcloth namespace */ +namespace cloth +{ +namespace ps +{ +// Int-as-bool type - has some uses for efficiency and with SIMD +typedef int IntBool; +static const IntBool IntFalse = 0; +static const IntBool IntTrue = 1; + +} +} +} + +#endif // #ifndef PSFOUNDATION_PS_H diff --git a/Source/ThirdParty/NvCloth/ps/PsAlignedMalloc.h b/Source/ThirdParty/NvCloth/ps/PsAlignedMalloc.h new file mode 100644 index 000000000..5591acbcd --- /dev/null +++ b/Source/ThirdParty/NvCloth/ps/PsAlignedMalloc.h @@ -0,0 +1,93 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +#ifndef PSFOUNDATION_PSALIGNEDMALLOC_H +#define PSFOUNDATION_PSALIGNEDMALLOC_H + +#include "PsUserAllocated.h" + +/*! +Allocate aligned memory. +Alignment must be a power of 2! +-- should be templated by a base allocator +*/ + +/** \brief NVidia namespace */ +namespace nv +{ +/** \brief nvcloth namespace */ +namespace cloth +{ +namespace ps +{ +/** +Allocator, which is used to access the global PxAllocatorCallback instance +(used for dynamic data types template instantiation), which can align memory +*/ + +// SCS: AlignedMalloc with 3 params not found, seems not used on PC either +// disabled for now to avoid GCC error + +template +class AlignedAllocator : public BaseAllocator +{ + public: + AlignedAllocator(const BaseAllocator& base = BaseAllocator()) : BaseAllocator(base) + { + } + + void* allocate(size_t size, const char* file, int line) + { + size_t pad = N - 1 + sizeof(size_t); // store offset for delete. + uint8_t* base = reinterpret_cast(BaseAllocator::allocate(size + pad, file, line)); + if(!base) + return NULL; + + uint8_t* ptr = reinterpret_cast(size_t(base + pad) & ~(size_t(N) - 1)); // aligned pointer, ensuring N + // is a size_t + // wide mask + reinterpret_cast(ptr)[-1] = size_t(ptr - base); // store offset + + return ptr; + } + void deallocate(void* ptr) + { + if(ptr == NULL) + return; + + uint8_t* base = reinterpret_cast(ptr) - reinterpret_cast(ptr)[-1]; + BaseAllocator::deallocate(base); + } +}; + +} // namespace ps +} // namespace cloth +} // namespace nv + +#endif // #ifndef PSFOUNDATION_PSALIGNEDMALLOC_H diff --git a/Source/ThirdParty/NvCloth/ps/PsAllocator.h b/Source/ThirdParty/NvCloth/ps/PsAllocator.h new file mode 100644 index 000000000..4d2f53852 --- /dev/null +++ b/Source/ThirdParty/NvCloth/ps/PsAllocator.h @@ -0,0 +1,351 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +#ifndef PSFOUNDATION_PSALLOCATOR_H +#define PSFOUNDATION_PSALLOCATOR_H + +#include "foundation/PxAllocatorCallback.h" +//#include "foundation/PxFoundation.h" +#include "Ps.h" +#include "../Callbacks.h" + +#if(PX_WINDOWS_FAMILY || PX_XBOXONE) +#include + #if PX_VC >= 16 + #include + #else + #include + #endif +#endif +#if(PX_APPLE_FAMILY) +#include +#endif + +#include + +// Allocation macros going through user allocator +#define PX_ALLOC(n, name) nv::cloth::NonTrackingAllocator().allocate(n, __FILE__, __LINE__) +#define PX_ALLOC_TEMP(n, name) PX_ALLOC(n, name) +#define PX_FREE(x) nv::cloth::NonTrackingAllocator().deallocate(x) +#define PX_FREE_AND_RESET(x) \ + { \ + PX_FREE(x); \ + x = 0; \ + } + +// The following macros support plain-old-types and classes derived from UserAllocated. +#define PX_NEW(T) new (nv::cloth::ReflectionAllocator(), __FILE__, __LINE__) T +#define PX_NEW_TEMP(T) PX_NEW(T) +#define PX_DELETE(x) delete x +#define PX_DELETE_AND_RESET(x) \ + { \ + PX_DELETE(x); \ + x = 0; \ + } +#define PX_DELETE_POD(x) \ + { \ + PX_FREE(x); \ + x = 0; \ + } +#define PX_DELETE_ARRAY(x) \ + { \ + PX_DELETE([] x); \ + x = 0; \ + } + +// aligned allocation +#define PX_ALIGNED16_ALLOC(n) nv::cloth::AlignedAllocator<16>().allocate(n, __FILE__, __LINE__) +#define PX_ALIGNED16_FREE(x) nv::cloth::AlignedAllocator<16>().deallocate(x) + +//! placement new macro to make it easy to spot bad use of 'new' +#define PX_PLACEMENT_NEW(p, T) new (p) T + +#if PX_DEBUG || PX_CHECKED +#define PX_USE_NAMED_ALLOCATOR 1 +#else +#define PX_USE_NAMED_ALLOCATOR 0 +#endif + +// Don't use inline for alloca !!! +#if PX_WINDOWS_FAMILY +#include +#define PxAlloca(x) _alloca(x) +#elif PX_LINUX || PX_ANDROID +#include +#define PxAlloca(x) alloca(x) +#elif PX_APPLE_FAMILY +#include +#define PxAlloca(x) alloca(x) +#elif PX_PS4 || PX_PS5 +#include +#define PxAlloca(x) alloca(x) +#elif PX_XBOXONE +#include +#define PxAlloca(x) alloca(x) +#elif PX_SWITCH +#include +#define PxAlloca(x) alloca(x) +#endif + +#define PxAllocaAligned(x, alignment) ((size_t(PxAlloca(x + alignment)) + (alignment - 1)) & ~size_t(alignment - 1)) + +/** \brief NVidia namespace */ +namespace nv +{ +/** \brief nvcloth namespace */ +namespace cloth +{ +namespace ps +{ +//NV_CLOTH_IMPORT PxAllocatorCallback& getAllocator(); + +/** +Allocator used to access the global PxAllocatorCallback instance without providing additional information. +*/ + +class NV_CLOTH_IMPORT Allocator +{ + public: + Allocator(const char* = 0) + { + } + void* allocate(size_t size, const char* file, int line); + void deallocate(void* ptr); +}; + +/* + * Bootstrap allocator using malloc/free. + * Don't use unless your objects get allocated before foundation is initialized. + */ +class RawAllocator +{ + public: + RawAllocator(const char* = 0) + { + } + void* allocate(size_t size, const char*, int) + { + // malloc returns valid pointer for size==0, no need to check + return ::malloc(size); + } + void deallocate(void* ptr) + { + // free(0) is guaranteed to have no side effect, no need to check + ::free(ptr); + } +}; + +/* + * Allocator that simply calls straight back to the application without tracking. + * This is used by the heap (Foundation::mNamedAllocMap) that tracks allocations + * because it needs to be able to grow as a result of an allocation. + * Making the hash table re-entrant to deal with this may not make sense. + */ +class NonTrackingAllocator +{ + public: + PX_FORCE_INLINE NonTrackingAllocator(const char* = 0) + { + } + PX_FORCE_INLINE void* allocate(size_t size, const char* file, int line) + { + return !size ? 0 : GetNvClothAllocator()->allocate(size, "NonTrackedAlloc", file, line); + } + PX_FORCE_INLINE void deallocate(void* ptr) + { + if(ptr) + GetNvClothAllocator()->deallocate(ptr); + } +}; + +/* +\brief Virtual allocator callback used to provide run-time defined allocators to foundation types like Array or Bitmap. + This is used by VirtualAllocator +*/ +class VirtualAllocatorCallback +{ + public: + VirtualAllocatorCallback() + { + } + virtual ~VirtualAllocatorCallback() + { + } + virtual void* allocate(const size_t size, const char* file, const int line) = 0; + virtual void deallocate(void* ptr) = 0; +}; + +/* +\brief Virtual allocator to be used by foundation types to provide run-time defined allocators. +Due to the fact that Array extends its allocator, rather than contains a reference/pointer to it, the VirtualAllocator +must +be a concrete type containing a pointer to a virtual callback. The callback may not be available at instantiation time, +therefore +methods are provided to set the callback later. +*/ +class VirtualAllocator +{ + public: + VirtualAllocator(VirtualAllocatorCallback* callback = NULL) : mCallback(callback) + { + } + + void* allocate(const size_t size, const char* file, const int line) + { + NV_CLOTH_ASSERT(mCallback); + if(size) + return mCallback->allocate(size, file, line); + return NULL; + } + void deallocate(void* ptr) + { + NV_CLOTH_ASSERT(mCallback); + if(ptr) + mCallback->deallocate(ptr); + } + + void setCallback(VirtualAllocatorCallback* callback) + { + mCallback = callback; + } + VirtualAllocatorCallback* getCallback() + { + return mCallback; + } + + private: + VirtualAllocatorCallback* mCallback; + VirtualAllocator& operator=(const VirtualAllocator&); +}; + +/** +Allocator used to access the global PxAllocatorCallback instance using a static name derived from T. +*/ + +template +class ReflectionAllocator +{ + static const char* getName() + { + if(true) + return ""; +#if PX_GCC_FAMILY + return __PRETTY_FUNCTION__; +#else + // name() calls malloc(), raw_name() wouldn't + return typeid(T).name(); +#endif + } + + public: + ReflectionAllocator(const physx::PxEMPTY) + { + } + ReflectionAllocator(const char* = 0) + { + } + inline ReflectionAllocator(const ReflectionAllocator&) + { + } + void* allocate(size_t size, const char* filename, int line) + { + return size ? GetNvClothAllocator()->allocate(size, getName(), filename, line) : 0; + } + void deallocate(void* ptr) + { + if(ptr) + GetNvClothAllocator()->deallocate(ptr); + } +}; + +template +struct AllocatorTraits +{ + typedef ReflectionAllocator Type; +}; + +// if you get a build error here, you are trying to PX_NEW a class +// that is neither plain-old-type nor derived from UserAllocated +template +union EnableIfPod +{ + int i; + T t; + typedef X Type; +}; + +} // namespace ps +} // namespace cloth +} // namespace nv + +// Global placement new for ReflectionAllocator templated by +// plain-old-type. Allows using PX_NEW for pointers and built-in-types. +// +// ATTENTION: You need to use PX_DELETE_POD or PX_FREE to deallocate +// memory, not PX_DELETE. PX_DELETE_POD redirects to PX_FREE. +// +// Rationale: PX_DELETE uses global operator delete(void*), which we dont' want to overload. +// Any other definition of PX_DELETE couldn't support array syntax 'PX_DELETE([]a);'. +// PX_DELETE_POD was preferred over PX_DELETE_ARRAY because it is used +// less often and applies to both single instances and arrays. +template +PX_INLINE void* operator new(size_t size, nv::cloth::ps::ReflectionAllocator alloc, const char* fileName, + typename nv::cloth::ps::EnableIfPod::Type line) +{ + return alloc.allocate(size, fileName, line); +} + +template +PX_INLINE void* operator new [](size_t size, nv::cloth::ps::ReflectionAllocator alloc, const char* fileName, + typename nv::cloth::ps::EnableIfPod::Type line) +{ return alloc.allocate(size, fileName, line); } + +// If construction after placement new throws, this placement delete is being called. +template +PX_INLINE void operator delete(void* ptr, nv::cloth::ps::ReflectionAllocator alloc, const char* fileName, + typename nv::cloth::ps::EnableIfPod::Type line) +{ + PX_UNUSED(fileName); + PX_UNUSED(line); + + alloc.deallocate(ptr); +} + +// If construction after placement new throws, this placement delete is being called. +template +PX_INLINE void operator delete [](void* ptr, nv::cloth::ps::ReflectionAllocator alloc, const char* fileName, + typename nv::cloth::ps::EnableIfPod::Type line) +{ + PX_UNUSED(fileName); + PX_UNUSED(line); + + alloc.deallocate(ptr); +} + +#endif // #ifndef PSFOUNDATION_PSALLOCATOR_H diff --git a/Source/ThirdParty/NvCloth/ps/PsArray.h b/Source/ThirdParty/NvCloth/ps/PsArray.h new file mode 100644 index 000000000..a4d296b7b --- /dev/null +++ b/Source/ThirdParty/NvCloth/ps/PsArray.h @@ -0,0 +1,726 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +#ifndef PSFOUNDATION_PSARRAY_H +#define PSFOUNDATION_PSARRAY_H + +#include "../Callbacks.h" +#include "foundation/PxIntrinsics.h" +#include "PsBasicTemplates.h" +#include "NvCloth/ps/PsAllocator.h" + +/** \brief NVidia namespace */ +namespace nv +{ +/** \brief nvcloth namespace */ +namespace cloth +{ +namespace ps +{ +template +void exportArray(Serializer& stream, const void* data, uint32_t size, uint32_t sizeOfElement, uint32_t capacity); +char* importArray(char* address, void** data, uint32_t size, uint32_t sizeOfElement, uint32_t capacity); + +/*! +An array is a sequential container. + +Implementation note +* entries between 0 and size are valid objects +* we use inheritance to build this because the array is included inline in a lot + of objects and we want the allocator to take no space if it's not stateful, which + aggregation doesn't allow. Also, we want the metadata at the front for the inline + case where the allocator contains some inline storage space +*/ +template ::Type> +class Array : protected Alloc +{ + public: + typedef T* Iterator; + typedef const T* ConstIterator; + + explicit Array(const physx::PxEMPTY v) : Alloc(v) + { + if(mData) + mCapacity |= PX_SIGN_BITMASK; + } + + /*! + Default array constructor. Initialize an empty array + */ + PX_INLINE explicit Array(const Alloc& alloc = Alloc()) : Alloc(alloc), mData(0), mSize(0), mCapacity(0) + { + } + + /*! + Initialize array with given capacity + */ + PX_INLINE explicit Array(uint32_t size, const T& a = T(), const Alloc& alloc = Alloc()) + : Alloc(alloc), mData(0), mSize(0), mCapacity(0) + { + resize(size, a); + } + + /*! + Copy-constructor. Copy all entries from other array + */ + template + PX_INLINE explicit Array(const Array& other, const Alloc& alloc = Alloc()) + : Alloc(alloc) + { + copy(other); + } + + // This is necessary else the basic default copy constructor is used in the case of both arrays being of the same + // template instance + // The C++ standard clearly states that a template constructor is never a copy constructor [2]. In other words, + // the presence of a template constructor does not suppress the implicit declaration of the copy constructor. + // Also never make a copy constructor explicit, or copy-initialization* will no longer work. This is because + // 'binding an rvalue to a const reference requires an accessible copy constructor' (http://gcc.gnu.org/bugs/) + // *http://stackoverflow.com/questions/1051379/is-there-a-difference-in-c-between-copy-initialization-and-assignment-initializ + PX_INLINE Array(const Array& other, const Alloc& alloc = Alloc()) : Alloc(alloc) + { + copy(other); + } + + /*! + Initialize array with given length + */ + PX_INLINE explicit Array(const T* first, const T* last, const Alloc& alloc = Alloc()) + : Alloc(alloc), mSize(last < first ? 0 : uint32_t(last - first)), mCapacity(mSize) + { + mData = allocate(mSize); + copy(mData, mData + mSize, first); + } + + /*! + Destructor + */ + PX_INLINE ~Array() + { + destroy(mData, mData + mSize); + + if(capacity() && !isInUserMemory()) + deallocate(mData); + } + + /*! + Assignment operator. Copy content (deep-copy) + */ + template + PX_INLINE Array& operator=(const Array& rhs) + { + if(&rhs == this) + return *this; + + clear(); + reserve(rhs.mSize); + copy(mData, mData + rhs.mSize, rhs.mData); + + mSize = rhs.mSize; + return *this; + } + + PX_INLINE Array& operator=(const Array& t) // Needs to be declared, see comment at copy-constructor + { + return operator=(t); + } + + /*! + Array indexing operator. + \param i + The index of the element that will be returned. + \return + The element i in the array. + */ + PX_FORCE_INLINE const T& operator[](uint32_t i) const + { + NV_CLOTH_ASSERT(i < mSize); + return mData[i]; + } + + /*! + Array indexing operator. + \param i + The index of the element that will be returned. + \return + The element i in the array. + */ + PX_FORCE_INLINE T& operator[](uint32_t i) + { + NV_CLOTH_ASSERT(i < mSize); + return mData[i]; + } + + /*! + Returns a pointer to the initial element of the array. + \return + a pointer to the initial element of the array. + */ + PX_FORCE_INLINE ConstIterator begin() const + { + return mData; + } + + PX_FORCE_INLINE Iterator begin() + { + return mData; + } + + /*! + Returns an iterator beyond the last element of the array. Do not dereference. + \return + a pointer to the element beyond the last element of the array. + */ + + PX_FORCE_INLINE ConstIterator end() const + { + return mData + mSize; + } + + PX_FORCE_INLINE Iterator end() + { + return mData + mSize; + } + + /*! + Returns a reference to the first element of the array. Undefined if the array is empty. + \return a reference to the first element of the array + */ + + PX_FORCE_INLINE const T& front() const + { + NV_CLOTH_ASSERT(mSize); + return mData[0]; + } + + PX_FORCE_INLINE T& front() + { + NV_CLOTH_ASSERT(mSize); + return mData[0]; + } + + /*! + Returns a reference to the last element of the array. Undefined if the array is empty + \return a reference to the last element of the array + */ + + PX_FORCE_INLINE const T& back() const + { + NV_CLOTH_ASSERT(mSize); + return mData[mSize - 1]; + } + + PX_FORCE_INLINE T& back() + { + NV_CLOTH_ASSERT(mSize); + return mData[mSize - 1]; + } + + /*! + Returns the number of entries in the array. This can, and probably will, + differ from the array capacity. + \return + The number of of entries in the array. + */ + PX_FORCE_INLINE uint32_t size() const + { + return mSize; + } + + /*! + Clears the array. + */ + PX_INLINE void clear() + { + destroy(mData, mData + mSize); + mSize = 0; + } + + /*! + Returns whether the array is empty (i.e. whether its size is 0). + \return + true if the array is empty + */ + PX_FORCE_INLINE bool empty() const + { + return mSize == 0; + } + + /*! + Finds the first occurrence of an element in the array. + \param a + The element to find. + */ + + PX_INLINE Iterator find(const T& a) + { + uint32_t index; + for(index = 0; index < mSize && mData[index] != a; index++) + ; + return mData + index; + } + + PX_INLINE ConstIterator find(const T& a) const + { + uint32_t index; + for(index = 0; index < mSize && mData[index] != a; index++) + ; + return mData + index; + } + + ///////////////////////////////////////////////////////////////////////// + /*! + Adds one element to the end of the array. Operation is O(1). + \param a + The element that will be added to this array. + */ + ///////////////////////////////////////////////////////////////////////// + + PX_FORCE_INLINE T& pushBack(const T& a) + { + if(capacity() <= mSize) + return growAndPushBack(a); + + PX_PLACEMENT_NEW(reinterpret_cast(mData + mSize), T)(a); + + return mData[mSize++]; + } + + ///////////////////////////////////////////////////////////////////////// + /*! + Returns the element at the end of the array. Only legal if the array is non-empty. + */ + ///////////////////////////////////////////////////////////////////////// + PX_INLINE T popBack() + { + NV_CLOTH_ASSERT(mSize); + T t = mData[mSize - 1]; + + mData[--mSize].~T(); + + return t; + } + + ///////////////////////////////////////////////////////////////////////// + /*! + Construct one element at the end of the array. Operation is O(1). + */ + ///////////////////////////////////////////////////////////////////////// + PX_INLINE T& insert() + { + if(capacity() <= mSize) + grow(capacityIncrement()); + + T* ptr = mData + mSize++; + new (ptr) T; // not 'T()' because PODs should not get default-initialized. + return *ptr; + } + + ///////////////////////////////////////////////////////////////////////// + /*! + Subtracts the element on position i from the array and replace it with + the last element. + Operation is O(1) + \param i + The position of the element that will be subtracted from this array. + */ + ///////////////////////////////////////////////////////////////////////// + PX_INLINE void replaceWithLast(uint32_t i) + { + NV_CLOTH_ASSERT(i < mSize); + mData[i] = mData[--mSize]; + + mData[mSize].~T(); + } + + PX_INLINE void replaceWithLast(Iterator i) + { + replaceWithLast(static_cast(i - mData)); + } + + ///////////////////////////////////////////////////////////////////////// + /*! + Replaces the first occurrence of the element a with the last element + Operation is O(n) + \param a + The position of the element that will be subtracted from this array. + \return true if the element has been removed. + */ + ///////////////////////////////////////////////////////////////////////// + + PX_INLINE bool findAndReplaceWithLast(const T& a) + { + uint32_t index = 0; + while(index < mSize && mData[index] != a) + ++index; + if(index == mSize) + return false; + replaceWithLast(index); + return true; + } + + ///////////////////////////////////////////////////////////////////////// + /*! + Subtracts the element on position i from the array. Shift the entire + array one step. + Operation is O(n) + \param i + The position of the element that will be subtracted from this array. + */ + ///////////////////////////////////////////////////////////////////////// + PX_INLINE void remove(uint32_t i) + { + NV_CLOTH_ASSERT(i < mSize); + + T* it = mData + i; + it->~T(); + while (++i < mSize) + { + new (it) T(mData[i]); + ++it; + it->~T(); + } + --mSize; + } + + ///////////////////////////////////////////////////////////////////////// + /*! + Removes a range from the array. Shifts the array so order is maintained. + Operation is O(n) + \param begin + The starting position of the element that will be subtracted from this array. + \param count + The number of elments that will be subtracted from this array. + */ + ///////////////////////////////////////////////////////////////////////// + PX_INLINE void removeRange(uint32_t begin, uint32_t count) + { + NV_CLOTH_ASSERT(begin < mSize); + NV_CLOTH_ASSERT((begin + count) <= mSize); + + for(uint32_t i = 0; i < count; i++) + mData[begin + i].~T(); // call the destructor on the ones being removed first. + + T* dest = &mData[begin]; // location we are copying the tail end objects to + T* src = &mData[begin + count]; // start of tail objects + uint32_t move_count = mSize - (begin + count); // compute remainder that needs to be copied down + + for(uint32_t i = 0; i < move_count; i++) + { + new (dest) T(*src); // copy the old one to the new location + src->~T(); // call the destructor on the old location + dest++; + src++; + } + mSize -= count; + } + + ////////////////////////////////////////////////////////////////////////// + /*! + Resize array + */ + ////////////////////////////////////////////////////////////////////////// + PX_NOINLINE void resize(const uint32_t size, const T& a = T()); + + PX_NOINLINE void resizeUninitialized(const uint32_t size); + + ////////////////////////////////////////////////////////////////////////// + /*! + Resize array such that only as much memory is allocated to hold the + existing elements + */ + ////////////////////////////////////////////////////////////////////////// + PX_INLINE void shrink() + { + recreate(mSize); + } + + ////////////////////////////////////////////////////////////////////////// + /*! + Deletes all array elements and frees memory. + */ + ////////////////////////////////////////////////////////////////////////// + PX_INLINE void reset() + { + resize(0); + shrink(); + } + + ////////////////////////////////////////////////////////////////////////// + /*! + Ensure that the array has at least size capacity. + */ + ////////////////////////////////////////////////////////////////////////// + PX_INLINE void reserve(const uint32_t capacity) + { + if(capacity > this->capacity()) + grow(capacity); + } + + ////////////////////////////////////////////////////////////////////////// + /*! + Query the capacity(allocated mem) for the array. + */ + ////////////////////////////////////////////////////////////////////////// + PX_FORCE_INLINE uint32_t capacity() const + { + return mCapacity & ~PX_SIGN_BITMASK; + } + + ////////////////////////////////////////////////////////////////////////// + /*! + Unsafe function to force the size of the array + */ + ////////////////////////////////////////////////////////////////////////// + PX_FORCE_INLINE void forceSize_Unsafe(uint32_t size) + { + NV_CLOTH_ASSERT(size <= mCapacity); + mSize = size; + } + + ////////////////////////////////////////////////////////////////////////// + /*! + Swap contents of an array without allocating temporary storage + */ + ////////////////////////////////////////////////////////////////////////// + PX_INLINE void swap(Array& other) + { + ps::swap(mData, other.mData); + ps::swap(mSize, other.mSize); + ps::swap(mCapacity, other.mCapacity); + } + + ////////////////////////////////////////////////////////////////////////// + /*! + Assign a range of values to this vector (resizes to length of range) + */ + ////////////////////////////////////////////////////////////////////////// + PX_INLINE void assign(const T* first, const T* last) + { + resizeUninitialized(uint32_t(last - first)); + copy(begin(), end(), first); + } + + // We need one bit to mark arrays that have been deserialized from a user-provided memory block. + // For alignment & memory saving purpose we store that bit in the rarely used capacity member. + PX_FORCE_INLINE uint32_t isInUserMemory() const + { + return mCapacity & PX_SIGN_BITMASK; + } + + /// return reference to allocator + PX_INLINE Alloc& getAllocator() + { + return *this; + } + + protected: + // constructor for where we don't own the memory + Array(T* memory, uint32_t size, uint32_t capacity, const Alloc& alloc = Alloc()) + : Alloc(alloc), mData(memory), mSize(size), mCapacity(capacity | PX_SIGN_BITMASK) + { + } + + template + PX_NOINLINE void copy(const Array& other); + + PX_INLINE T* allocate(uint32_t size) + { + if(size > 0) + { + T* p = reinterpret_cast(Alloc::allocate(sizeof(T) * size, __FILE__, __LINE__)); +/** +Mark a specified amount of memory with 0xcd pattern. This is used to check that the meta data +definition for serialized classes is complete in checked builds. +*/ +#if PX_CHECKED + if(p) + { + for(uint32_t i = 0; i < (sizeof(T) * size); ++i) + reinterpret_cast(p)[i] = 0xcd; + } +#endif + return p; + } + return 0; + } + + PX_INLINE void deallocate(void* mem) + { + Alloc::deallocate(mem); + } + + static PX_INLINE void create(T* first, T* last, const T& a) + { + for(; first < last; ++first) + ::new (first) T(a); + } + + static PX_INLINE void copy(T* first, T* last, const T* src) + { + if(last <= first) + return; + + for(; first < last; ++first, ++src) + ::new (first) T(*src); + } + + static PX_INLINE void destroy(T* first, T* last) + { + for(; first < last; ++first) + first->~T(); + } + + /*! + Called when pushBack() needs to grow the array. + \param a The element that will be added to this array. + */ + PX_NOINLINE T& growAndPushBack(const T& a); + + /*! + Resizes the available memory for the array. + + \param capacity + The number of entries that the set should be able to hold. + */ + PX_INLINE void grow(uint32_t capacity) + { + NV_CLOTH_ASSERT(this->capacity() < capacity); + recreate(capacity); + } + + /*! + Creates a new memory block, copies all entries to the new block and destroys old entries. + + \param capacity + The number of entries that the set should be able to hold. + */ + PX_NOINLINE void recreate(uint32_t capacity); + + // The idea here is to prevent accidental bugs with pushBack or insert. Unfortunately + // it interacts badly with InlineArrays with smaller inline allocations. + // TODO(dsequeira): policy template arg, this is exactly what they're for. + PX_INLINE uint32_t capacityIncrement() const + { + const uint32_t capacity = this->capacity(); + return capacity == 0 ? 1 : capacity * 2; + } + + T* mData; + uint32_t mSize; + uint32_t mCapacity; +}; + +template +PX_NOINLINE void Array::resize(const uint32_t size, const T& a) +{ + reserve(size); + create(mData + mSize, mData + size, a); + destroy(mData + size, mData + mSize); + mSize = size; +} + +template +template +PX_NOINLINE void Array::copy(const Array& other) +{ + if(!other.empty()) + { + mData = allocate(mSize = mCapacity = other.size()); + copy(mData, mData + mSize, other.begin()); + } + else + { + mData = NULL; + mSize = 0; + mCapacity = 0; + } + + // mData = allocate(other.mSize); + // mSize = other.mSize; + // mCapacity = other.mSize; + // copy(mData, mData + mSize, other.mData); +} + +template +PX_NOINLINE void Array::resizeUninitialized(const uint32_t size) +{ + reserve(size); + mSize = size; +} + +template +PX_NOINLINE T& Array::growAndPushBack(const T& a) +{ + uint32_t capacity = capacityIncrement(); + + T* newData = allocate(capacity); + NV_CLOTH_ASSERT((!capacity) || (newData && (newData != mData))); + copy(newData, newData + mSize, mData); + + // inserting element before destroying old array + // avoids referencing destroyed object when duplicating array element. + PX_PLACEMENT_NEW(reinterpret_cast(newData + mSize), T)(a); + + destroy(mData, mData + mSize); + if(!isInUserMemory()) + deallocate(mData); + + mData = newData; + mCapacity = capacity; + + return mData[mSize++]; +} + +template +PX_NOINLINE void Array::recreate(uint32_t capacity) +{ + T* newData = allocate(capacity); + NV_CLOTH_ASSERT((!capacity) || (newData && (newData != mData))); + + copy(newData, newData + mSize, mData); + destroy(mData, mData + mSize); + if(!isInUserMemory()) + deallocate(mData); + + mData = newData; + mCapacity = capacity; +} + +template +PX_INLINE void swap(Array& x, Array& y) +{ + x.swap(y); +} + +} // namespace ps +} // namespace cloth +} // namespace nv + +#endif // #ifndef PSFOUNDATION_PSARRAY_H diff --git a/Source/ThirdParty/NvCloth/ps/PsAtomic.h b/Source/ThirdParty/NvCloth/ps/PsAtomic.h new file mode 100644 index 000000000..65f12ef7a --- /dev/null +++ b/Source/ThirdParty/NvCloth/ps/PsAtomic.h @@ -0,0 +1,69 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +#ifndef PSFOUNDATION_PSATOMIC_H +#define PSFOUNDATION_PSATOMIC_H + +#include "NvCloth/ps/Ps.h" +#include "NvCloth/Callbacks.h" + +/** \brief NVidia namespace */ +namespace nv +{ +/** \brief nvcloth namespace */ +namespace cloth +{ +namespace ps +{ +/* set *dest equal to val. Return the old value of *dest */ +NV_CLOTH_IMPORT int32_t atomicExchange(volatile int32_t* dest, int32_t val); + +/* if *dest == comp, replace with exch. Return original value of *dest */ +NV_CLOTH_IMPORT int32_t atomicCompareExchange(volatile int32_t* dest, int32_t exch, int32_t comp); + +/* if *dest == comp, replace with exch. Return original value of *dest */ +NV_CLOTH_IMPORT void* atomicCompareExchangePointer(volatile void** dest, void* exch, void* comp); + +/* increment the specified location. Return the incremented value */ +NV_CLOTH_IMPORT int32_t atomicIncrement(volatile int32_t* val); + +/* decrement the specified location. Return the decremented value */ +NV_CLOTH_IMPORT int32_t atomicDecrement(volatile int32_t* val); + +/* add delta to *val. Return the new value */ +NV_CLOTH_IMPORT int32_t atomicAdd(volatile int32_t* val, int32_t delta); + +/* compute the maximum of dest and val. Return the new value */ +NV_CLOTH_IMPORT int32_t atomicMax(volatile int32_t* val, int32_t val2); + +} // namespace ps +} // namespace cloth +} // namespace nv + +#endif // #ifndef PSFOUNDATION_PSATOMIC_H diff --git a/Source/ThirdParty/NvCloth/ps/PsBasicTemplates.h b/Source/ThirdParty/NvCloth/ps/PsBasicTemplates.h new file mode 100644 index 000000000..c8ef56c70 --- /dev/null +++ b/Source/ThirdParty/NvCloth/ps/PsBasicTemplates.h @@ -0,0 +1,151 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +#ifndef PSFOUNDATION_PSBASICTEMPLATES_H +#define PSFOUNDATION_PSBASICTEMPLATES_H + +#include "Ps.h" + +/** \brief NVidia namespace */ +namespace nv +{ +/** \brief nvcloth namespace */ +namespace cloth +{ +namespace ps +{ +template +struct Equal +{ + bool operator()(const A& a, const A& b) const + { + return a == b; + } +}; + +template +struct Less +{ + bool operator()(const A& a, const A& b) const + { + return a < b; + } +}; + +template +struct Greater +{ + bool operator()(const A& a, const A& b) const + { + return a > b; + } +}; + +template +class Pair +{ + public: + F first; + S second; + Pair() : first(F()), second(S()) + { + } + Pair(const F& f, const S& s) : first(f), second(s) + { + } + Pair(const Pair& p) : first(p.first), second(p.second) + { + } + // CN - fix for /.../PsBasicTemplates.h(61) : warning C4512: 'nv::cloth::Pair' : assignment operator could + // not be generated + Pair& operator=(const Pair& p) + { + first = p.first; + second = p.second; + return *this; + } + bool operator==(const Pair& p) const + { + return first == p.first && second == p.second; + } + bool operator<(const Pair& p) const + { + if(first < p.first) + return true; + else + return !(p.first < first) && (second < p.second); + } +}; + +template +struct LogTwo +{ + static const unsigned int value = LogTwo<(A >> 1)>::value + 1; +}; +template <> +struct LogTwo<1> +{ + static const unsigned int value = 0; +}; + +template +struct UnConst +{ + typedef T Type; +}; +template +struct UnConst +{ + typedef T Type; +}; + +template +T pointerOffset(void* p, ptrdiff_t offset) +{ + return reinterpret_cast(reinterpret_cast(p) + offset); +} +template +T pointerOffset(const void* p, ptrdiff_t offset) +{ + return reinterpret_cast(reinterpret_cast(p) + offset); +} + +template +PX_CUDA_CALLABLE PX_INLINE void swap(T& x, T& y) +{ + const T tmp = x; + x = y; + y = tmp; +} + +} // namespace ps +} // namespace cloth +} // namespace nv + +#endif // #ifndef PSFOUNDATION_PSBASICTEMPLATES_H diff --git a/Source/ThirdParty/NvCloth/ps/PsBitUtils.h b/Source/ThirdParty/NvCloth/ps/PsBitUtils.h new file mode 100644 index 000000000..f25e32ce1 --- /dev/null +++ b/Source/ThirdParty/NvCloth/ps/PsBitUtils.h @@ -0,0 +1,114 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +#ifndef PSFOUNDATION_PSBITUTILS_H +#define PSFOUNDATION_PSBITUTILS_H + +#include "foundation/PxIntrinsics.h" +#include "../Callbacks.h" +#include "PsIntrinsics.h" +#include "Ps.h" + +/** \brief NVidia namespace */ +namespace nv +{ +/** \brief nvcloth namespace */ +namespace cloth +{ +namespace ps +{ +PX_INLINE uint32_t bitCount(uint32_t v) +{ + // from http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel + uint32_t const w = v - ((v >> 1) & 0x55555555); + uint32_t const x = (w & 0x33333333) + ((w >> 2) & 0x33333333); + return (((x + (x >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; +} + +PX_INLINE bool isPowerOfTwo(uint32_t x) +{ + return x != 0 && (x & (x - 1)) == 0; +} + +// "Next Largest Power of 2 +// Given a binary integer value x, the next largest power of 2 can be computed by a SWAR algorithm +// that recursively "folds" the upper bits into the lower bits. This process yields a bit vector with +// the same most significant 1 as x, but all 1's below it. Adding 1 to that value yields the next +// largest power of 2. For a 32-bit value:" +PX_INLINE uint32_t nextPowerOfTwo(uint32_t x) +{ + x |= (x >> 1); + x |= (x >> 2); + x |= (x >> 4); + x |= (x >> 8); + x |= (x >> 16); + return x + 1; +} + +/*! +Return the index of the highest set bit. Not valid for zero arg. +*/ + +PX_INLINE uint32_t lowestSetBit(uint32_t x) +{ + NV_CLOTH_ASSERT(x); + return PxLowestSetBitUnsafe(x); +} + +/*! +Return the index of the highest set bit. Not valid for zero arg. +*/ + +PX_INLINE uint32_t highestSetBit(uint32_t x) +{ + NV_CLOTH_ASSERT(x); + return PxHighestSetBitUnsafe(x); +} + +// Helper function to approximate log2 of an integer value +// assumes that the input is actually power of two. +// todo: replace 2 usages with 'highestSetBit' +PX_INLINE uint32_t ilog2(uint32_t num) +{ + for(uint32_t i = 0; i < 32; i++) + { + num >>= 1; + if(num == 0) + return i; + } + + NV_CLOTH_ASSERT(0); + return uint32_t(-1); +} + +} // namespace ps +} // namespace cloth +} // namespace nv + +#endif // #ifndef PSFOUNDATION_PSBITUTILS_H diff --git a/Source/ThirdParty/NvCloth/ps/PsHash.h b/Source/ThirdParty/NvCloth/ps/PsHash.h new file mode 100644 index 000000000..92c323df1 --- /dev/null +++ b/Source/ThirdParty/NvCloth/ps/PsHash.h @@ -0,0 +1,167 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +#ifndef PSFOUNDATION_PSHASH_H +#define PSFOUNDATION_PSHASH_H + +#include "Ps.h" +#include "PsBasicTemplates.h" + +#if PX_VC +#pragma warning(push) +#pragma warning(disable : 4302) +#endif + +#if PX_LINUX +#include "foundation/PxSimpleTypes.h" +#endif + +/*! +Central definition of hash functions +*/ + +/** \brief NVidia namespace */ +namespace nv +{ +/** \brief nvcloth namespace */ +namespace cloth +{ +namespace ps +{ +// Hash functions + +// Thomas Wang's 32 bit mix +// http://www.cris.com/~Ttwang/tech/inthash.htm +PX_FORCE_INLINE uint32_t hash(const uint32_t key) +{ + uint32_t k = key; + k += ~(k << 15); + k ^= (k >> 10); + k += (k << 3); + k ^= (k >> 6); + k += ~(k << 11); + k ^= (k >> 16); + return uint32_t(k); +} + +PX_FORCE_INLINE uint32_t hash(const int32_t key) +{ + return hash(uint32_t(key)); +} + +// Thomas Wang's 64 bit mix +// http://www.cris.com/~Ttwang/tech/inthash.htm +PX_FORCE_INLINE uint32_t hash(const uint64_t key) +{ + uint64_t k = key; + k += ~(k << 32); + k ^= (k >> 22); + k += ~(k << 13); + k ^= (k >> 8); + k += (k << 3); + k ^= (k >> 15); + k += ~(k << 27); + k ^= (k >> 31); + return uint32_t(UINT32_MAX & k); +} + +#if PX_APPLE_FAMILY +// hash for size_t, to make gcc happy +PX_INLINE uint32_t hash(const size_t key) +{ +#if PX_P64_FAMILY + return hash(uint64_t(key)); +#else + return hash(uint32_t(key)); +#endif +} +#endif + +// Hash function for pointers +PX_INLINE uint32_t hash(const void* ptr) +{ +#if PX_P64_FAMILY + return hash(uint64_t(ptr)); +#else + return hash(uint32_t(UINT32_MAX & size_t(ptr))); +#endif +} + +// Hash function for pairs +template +PX_INLINE uint32_t hash(const Pair& p) +{ + uint32_t seed = 0x876543; + uint32_t m = 1000007; + return hash(p.second) ^ (m * (hash(p.first) ^ (m * seed))); +} + +// hash object for hash map template parameter +template +struct Hash +{ + uint32_t operator()(const Key& k) const + { + return hash(k); + } + bool equal(const Key& k0, const Key& k1) const + { + return k0 == k1; + } +}; + +// specialization for strings +template <> +struct Hash +{ + public: + uint32_t operator()(const char* _string) const + { + // "DJB" string hash + const uint8_t* string = reinterpret_cast(_string); + uint32_t h = 5381; + for(const uint8_t* ptr = string; *ptr; ptr++) + h = ((h << 5) + h) ^ uint32_t(*ptr); + return h; + } + bool equal(const char* string0, const char* string1) const + { + return !strcmp(string0, string1); + } +}; + +} // namespace ps +} // namespace cloth +} // namespace nv + +#if PX_VC +#pragma warning(pop) +#endif + +#endif // #ifndef PSFOUNDATION_PSHASH_H diff --git a/Source/ThirdParty/NvCloth/ps/PsHashInternals.h b/Source/ThirdParty/NvCloth/ps/PsHashInternals.h new file mode 100644 index 000000000..7e823e8d6 --- /dev/null +++ b/Source/ThirdParty/NvCloth/ps/PsHashInternals.h @@ -0,0 +1,800 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +#ifndef PSFOUNDATION_PSHASHINTERNALS_H +#define PSFOUNDATION_PSHASHINTERNALS_H + +#include "PsBasicTemplates.h" +#include "PsArray.h" +#include "PsBitUtils.h" +#include "PsHash.h" +#include "foundation/PxIntrinsics.h" + +#if PX_VC +#pragma warning(push) +#pragma warning(disable : 4127) // conditional expression is constant +#endif +/** \brief NVidia namespace */ +namespace nv +{ +/** \brief nvcloth namespace */ +namespace cloth +{ +namespace ps +{ +namespace internal +{ +template +class HashBase : private Allocator +{ + void init(uint32_t initialTableSize, float loadFactor) + { + mBuffer = NULL; + mEntries = NULL; + mEntriesNext = NULL; + mHash = NULL; + mEntriesCapacity = 0; + mHashSize = 0; + mLoadFactor = loadFactor; + mFreeList = uint32_t(EOL); + mTimestamp = 0; + mEntriesCount = 0; + + if(initialTableSize) + reserveInternal(initialTableSize); + } + + public: + typedef Entry EntryType; + + HashBase(uint32_t initialTableSize = 64, float loadFactor = 0.75f) : Allocator(PX_DEBUG_EXP("hashBase")) + { + init(initialTableSize, loadFactor); + } + + HashBase(uint32_t initialTableSize, float loadFactor, const Allocator& alloc) : Allocator(alloc) + { + init(initialTableSize, loadFactor); + } + + HashBase(const Allocator& alloc) : Allocator(alloc) + { + init(64, 0.75f); + } + + ~HashBase() + { + destroy(); // No need to clear() + + if(mBuffer) + Allocator::deallocate(mBuffer); + } + + static const uint32_t EOL = 0xffffffff; + + PX_INLINE Entry* create(const Key& k, bool& exists) + { + uint32_t h = 0; + if(mHashSize) + { + h = hash(k); + uint32_t index = mHash[h]; + while(index != EOL && !HashFn().equal(GetKey()(mEntries[index]), k)) + index = mEntriesNext[index]; + exists = index != EOL; + if(exists) + return mEntries + index; + } + else + exists = false; + + if(freeListEmpty()) + { + grow(); + h = hash(k); + } + + uint32_t entryIndex = freeListGetNext(); + + mEntriesNext[entryIndex] = mHash[h]; + mHash[h] = entryIndex; + + mEntriesCount++; + mTimestamp++; + + return mEntries + entryIndex; + } + + PX_INLINE const Entry* find(const Key& k) const + { + if(!mEntriesCount) + return NULL; + + const uint32_t h = hash(k); + uint32_t index = mHash[h]; + while(index != EOL && !HashFn().equal(GetKey()(mEntries[index]), k)) + index = mEntriesNext[index]; + return index != EOL ? mEntries + index : NULL; + } + + PX_INLINE bool erase(const Key& k, Entry& e) + { + if(!mEntriesCount) + return false; + + const uint32_t h = hash(k); + uint32_t* ptr = mHash + h; + while(*ptr != EOL && !HashFn().equal(GetKey()(mEntries[*ptr]), k)) + ptr = mEntriesNext + *ptr; + + if(*ptr == EOL) + return false; + + PX_PLACEMENT_NEW(&e, Entry)(mEntries[*ptr]); + + return eraseInternal(ptr); + } + + PX_INLINE bool erase(const Key& k) + { + if(!mEntriesCount) + return false; + + const uint32_t h = hash(k); + uint32_t* ptr = mHash + h; + while(*ptr != EOL && !HashFn().equal(GetKey()(mEntries[*ptr]), k)) + ptr = mEntriesNext + *ptr; + + if(*ptr == EOL) + return false; + + return eraseInternal(ptr); + } + + PX_INLINE uint32_t size() const + { + return mEntriesCount; + } + + PX_INLINE uint32_t capacity() const + { + return mHashSize; + } + + void clear() + { + if(!mHashSize || mEntriesCount == 0) + return; + + destroy(); + + physx::intrinsics::memSet(mHash, EOL, mHashSize * sizeof(uint32_t)); + + const uint32_t sizeMinus1 = mEntriesCapacity - 1; + for(uint32_t i = 0; i < sizeMinus1; i++) + { + PxPrefetchLine(mEntriesNext + i, 128); + mEntriesNext[i] = i + 1; + } + mEntriesNext[mEntriesCapacity - 1] = uint32_t(EOL); + mFreeList = 0; + mEntriesCount = 0; + } + + void reserve(uint32_t size) + { + if(size > mHashSize) + reserveInternal(size); + } + + PX_INLINE const Entry* getEntries() const + { + return mEntries; + } + + PX_INLINE Entry* insertUnique(const Key& k) + { + NV_CLOTH_ASSERT(find(k) == NULL); + uint32_t h = hash(k); + + uint32_t entryIndex = freeListGetNext(); + + mEntriesNext[entryIndex] = mHash[h]; + mHash[h] = entryIndex; + + mEntriesCount++; + mTimestamp++; + + return mEntries + entryIndex; + } + + private: + void destroy() + { + for(uint32_t i = 0; i < mHashSize; i++) + { + for(uint32_t j = mHash[i]; j != EOL; j = mEntriesNext[j]) + mEntries[j].~Entry(); + } + } + + template + PX_NOINLINE void copy(const HashBase& other); + + // free list management - if we're coalescing, then we use mFreeList to hold + // the top of the free list and it should always be equal to size(). Otherwise, + // we build a free list in the next() pointers. + + PX_INLINE void freeListAdd(uint32_t index) + { + if(compacting) + { + mFreeList--; + NV_CLOTH_ASSERT(mFreeList == mEntriesCount); + } + else + { + mEntriesNext[index] = mFreeList; + mFreeList = index; + } + } + + PX_INLINE void freeListAdd(uint32_t start, uint32_t end) + { + if(!compacting) + { + for(uint32_t i = start; i < end - 1; i++) // add the new entries to the free list + mEntriesNext[i] = i + 1; + + // link in old free list + mEntriesNext[end - 1] = mFreeList; + NV_CLOTH_ASSERT(mFreeList != end - 1); + mFreeList = start; + } + else if(mFreeList == EOL) // don't reset the free ptr for the compacting hash unless it's empty + mFreeList = start; + } + + PX_INLINE uint32_t freeListGetNext() + { + NV_CLOTH_ASSERT(!freeListEmpty()); + if(compacting) + { + NV_CLOTH_ASSERT(mFreeList == mEntriesCount); + return mFreeList++; + } + else + { + uint32_t entryIndex = mFreeList; + mFreeList = mEntriesNext[mFreeList]; + return entryIndex; + } + } + + PX_INLINE bool freeListEmpty() const + { + if(compacting) + return mEntriesCount == mEntriesCapacity; + else + return mFreeList == EOL; + } + + PX_INLINE void replaceWithLast(uint32_t index) + { + PX_PLACEMENT_NEW(mEntries + index, Entry)(mEntries[mEntriesCount]); + mEntries[mEntriesCount].~Entry(); + mEntriesNext[index] = mEntriesNext[mEntriesCount]; + + uint32_t h = hash(GetKey()(mEntries[index])); + uint32_t* ptr; + for(ptr = mHash + h; *ptr != mEntriesCount; ptr = mEntriesNext + *ptr) + NV_CLOTH_ASSERT(*ptr != EOL); + *ptr = index; + } + + PX_INLINE uint32_t hash(const Key& k, uint32_t hashSize) const + { + return HashFn()(k) & (hashSize - 1); + } + + PX_INLINE uint32_t hash(const Key& k) const + { + return hash(k, mHashSize); + } + + PX_INLINE bool eraseInternal(uint32_t* ptr) + { + const uint32_t index = *ptr; + + *ptr = mEntriesNext[index]; + + mEntries[index].~Entry(); + + mEntriesCount--; + mTimestamp++; + + if (compacting && index != mEntriesCount) + replaceWithLast(index); + + freeListAdd(index); + return true; + } + + void reserveInternal(uint32_t size) + { + if(!isPowerOfTwo(size)) + size = nextPowerOfTwo(size); + + NV_CLOTH_ASSERT(!(size & (size - 1))); + + // decide whether iteration can be done on the entries directly + bool resizeCompact = compacting || freeListEmpty(); + + // define new table sizes + uint32_t oldEntriesCapacity = mEntriesCapacity; + uint32_t newEntriesCapacity = uint32_t(float(size) * mLoadFactor); + uint32_t newHashSize = size; + + // allocate new common buffer and setup pointers to new tables + uint8_t* newBuffer; + uint32_t* newHash; + uint32_t* newEntriesNext; + Entry* newEntries; + { + uint32_t newHashByteOffset = 0; + uint32_t newEntriesNextBytesOffset = newHashByteOffset + newHashSize * sizeof(uint32_t); + uint32_t newEntriesByteOffset = newEntriesNextBytesOffset + newEntriesCapacity * sizeof(uint32_t); + newEntriesByteOffset += (16 - (newEntriesByteOffset & 15)) & 15; + uint32_t newBufferByteSize = newEntriesByteOffset + newEntriesCapacity * sizeof(Entry); + + newBuffer = reinterpret_cast(Allocator::allocate(newBufferByteSize, __FILE__, __LINE__)); + NV_CLOTH_ASSERT(newBuffer); + + newHash = reinterpret_cast(newBuffer + newHashByteOffset); + newEntriesNext = reinterpret_cast(newBuffer + newEntriesNextBytesOffset); + newEntries = reinterpret_cast(newBuffer + newEntriesByteOffset); + } + + // initialize new hash table + physx::intrinsics::memSet(newHash, uint32_t(EOL), newHashSize * sizeof(uint32_t)); + + // iterate over old entries, re-hash and create new entries + if(resizeCompact) + { + // check that old free list is empty - we don't need to copy the next entries + NV_CLOTH_ASSERT(compacting || mFreeList == EOL); + + for(uint32_t index = 0; index < mEntriesCount; ++index) + { + uint32_t h = hash(GetKey()(mEntries[index]), newHashSize); + newEntriesNext[index] = newHash[h]; + newHash[h] = index; + + PX_PLACEMENT_NEW(newEntries + index, Entry)(mEntries[index]); + mEntries[index].~Entry(); + } + } + else + { + // copy old free list, only required for non compact resizing + physx::intrinsics::memCopy(newEntriesNext, mEntriesNext, mEntriesCapacity * sizeof(uint32_t)); + + for(uint32_t bucket = 0; bucket < mHashSize; bucket++) + { + uint32_t index = mHash[bucket]; + while(index != EOL) + { + uint32_t h = hash(GetKey()(mEntries[index]), newHashSize); + newEntriesNext[index] = newHash[h]; + NV_CLOTH_ASSERT(index != newHash[h]); + + newHash[h] = index; + + PX_PLACEMENT_NEW(newEntries + index, Entry)(mEntries[index]); + mEntries[index].~Entry(); + + index = mEntriesNext[index]; + } + } + } + + // swap buffer and pointers + Allocator::deallocate(mBuffer); + mBuffer = newBuffer; + mHash = newHash; + mHashSize = newHashSize; + mEntriesNext = newEntriesNext; + mEntries = newEntries; + mEntriesCapacity = newEntriesCapacity; + + freeListAdd(oldEntriesCapacity, newEntriesCapacity); + } + + void grow() + { + NV_CLOTH_ASSERT((mFreeList == EOL) || (compacting && (mEntriesCount == mEntriesCapacity))); + + uint32_t size = mHashSize == 0 ? 16 : mHashSize * 2; + reserve(size); + } + + uint8_t* mBuffer; + Entry* mEntries; + uint32_t* mEntriesNext; // same size as mEntries + uint32_t* mHash; + uint32_t mEntriesCapacity; + uint32_t mHashSize; + float mLoadFactor; + uint32_t mFreeList; + uint32_t mTimestamp; + uint32_t mEntriesCount; // number of entries + + public: + class Iter + { + public: + PX_INLINE Iter(HashBase& b) : mBucket(0), mEntry(uint32_t(b.EOL)), mTimestamp(b.mTimestamp), mBase(b) + { + if(mBase.mEntriesCapacity > 0) + { + mEntry = mBase.mHash[0]; + skip(); + } + } + + PX_INLINE void check() const + { + NV_CLOTH_ASSERT(mTimestamp == mBase.mTimestamp); + } + PX_INLINE const Entry& operator*() const + { + check(); + return mBase.mEntries[mEntry]; + } + PX_INLINE Entry& operator*() + { + check(); + return mBase.mEntries[mEntry]; + } + PX_INLINE const Entry* operator->() const + { + check(); + return mBase.mEntries + mEntry; + } + PX_INLINE Entry* operator->() + { + check(); + return mBase.mEntries + mEntry; + } + PX_INLINE Iter operator++() + { + check(); + advance(); + return *this; + } + PX_INLINE Iter operator++(int) + { + check(); + Iter i = *this; + advance(); + return i; + } + PX_INLINE bool done() const + { + check(); + return mEntry == mBase.EOL; + } + + private: + PX_INLINE void advance() + { + mEntry = mBase.mEntriesNext[mEntry]; + skip(); + } + PX_INLINE void skip() + { + while(mEntry == mBase.EOL) + { + if(++mBucket == mBase.mHashSize) + break; + mEntry = mBase.mHash[mBucket]; + } + } + + Iter& operator=(const Iter&); + + uint32_t mBucket; + uint32_t mEntry; + uint32_t mTimestamp; + HashBase& mBase; + }; + + /*! + Iterate over entries in a hash base and allow entry erase while iterating + */ + class EraseIterator + { + public: + PX_INLINE EraseIterator(HashBase& b): mBase(b) + { + reset(); + } + + PX_INLINE Entry* eraseCurrentGetNext(bool eraseCurrent) + { + if(eraseCurrent && mCurrentEntryIndexPtr) + { + mBase.eraseInternal(mCurrentEntryIndexPtr); + // if next was valid return the same ptr, if next was EOL search new hash entry + if(*mCurrentEntryIndexPtr != mBase.EOL) + return mBase.mEntries + *mCurrentEntryIndexPtr; + else + return traverseHashEntries(); + } + + // traverse mHash to find next entry + if(mCurrentEntryIndexPtr == NULL) + return traverseHashEntries(); + + const uint32_t index = *mCurrentEntryIndexPtr; + if(mBase.mEntriesNext[index] == mBase.EOL) + { + return traverseHashEntries(); + } + else + { + mCurrentEntryIndexPtr = mBase.mEntriesNext + index; + return mBase.mEntries + *mCurrentEntryIndexPtr; + } + } + + PX_INLINE void reset() + { + mCurrentHashIndex = 0; + mCurrentEntryIndexPtr = NULL; + } + + private: + PX_INLINE Entry* traverseHashEntries() + { + mCurrentEntryIndexPtr = NULL; + while (mCurrentEntryIndexPtr == NULL && mCurrentHashIndex < mBase.mHashSize) + { + if (mBase.mHash[mCurrentHashIndex] != mBase.EOL) + { + mCurrentEntryIndexPtr = mBase.mHash + mCurrentHashIndex; + mCurrentHashIndex++; + return mBase.mEntries + *mCurrentEntryIndexPtr; + } + else + { + mCurrentHashIndex++; + } + } + return NULL; + } + + EraseIterator& operator=(const EraseIterator&); + private: + uint32_t* mCurrentEntryIndexPtr; + uint32_t mCurrentHashIndex; + HashBase& mBase; + }; +}; + +template +template +PX_NOINLINE void +HashBase::copy(const HashBase& other) +{ + reserve(other.mEntriesCount); + + for(uint32_t i = 0; i < other.mEntriesCount; i++) + { + for(uint32_t j = other.mHash[i]; j != EOL; j = other.mEntriesNext[j]) + { + const Entry& otherEntry = other.mEntries[j]; + + bool exists; + Entry* newEntry = create(GK()(otherEntry), exists); + NV_CLOTH_ASSERT(!exists); + + PX_PLACEMENT_NEW(newEntry, Entry)(otherEntry); + } + } +} + +template ::Type, bool Coalesced = false> +class HashSetBase +{ + PX_NOCOPY(HashSetBase) + public: + struct GetKey + { + PX_INLINE const Key& operator()(const Key& e) + { + return e; + } + }; + + typedef HashBase BaseMap; + typedef typename BaseMap::Iter Iterator; + + HashSetBase(uint32_t initialTableSize, float loadFactor, const Allocator& alloc) + : mBase(initialTableSize, loadFactor, alloc) + { + } + + HashSetBase(const Allocator& alloc) : mBase(64, 0.75f, alloc) + { + } + + HashSetBase(uint32_t initialTableSize = 64, float loadFactor = 0.75f) : mBase(initialTableSize, loadFactor) + { + } + + bool insert(const Key& k) + { + bool exists; + Key* e = mBase.create(k, exists); + if(!exists) + PX_PLACEMENT_NEW(e, Key)(k); + return !exists; + } + + PX_INLINE bool contains(const Key& k) const + { + return mBase.find(k) != 0; + } + PX_INLINE bool erase(const Key& k) + { + return mBase.erase(k); + } + PX_INLINE uint32_t size() const + { + return mBase.size(); + } + PX_INLINE uint32_t capacity() const + { + return mBase.capacity(); + } + PX_INLINE void reserve(uint32_t size) + { + mBase.reserve(size); + } + PX_INLINE void clear() + { + mBase.clear(); + } + + protected: + BaseMap mBase; +}; + +template >::Type> +class HashMapBase +{ + PX_NOCOPY(HashMapBase) + public: + typedef Pair Entry; + + struct GetKey + { + PX_INLINE const Key& operator()(const Entry& e) + { + return e.first; + } + }; + + typedef HashBase BaseMap; + typedef typename BaseMap::Iter Iterator; + typedef typename BaseMap::EraseIterator EraseIterator; + + HashMapBase(uint32_t initialTableSize, float loadFactor, const Allocator& alloc) + : mBase(initialTableSize, loadFactor, alloc) + { + } + + HashMapBase(const Allocator& alloc) : mBase(64, 0.75f, alloc) + { + } + + HashMapBase(uint32_t initialTableSize = 64, float loadFactor = 0.75f) : mBase(initialTableSize, loadFactor) + { + } + + bool insert(const Key /*&*/ k, const Value /*&*/ v) + { + bool exists; + Entry* e = mBase.create(k, exists); + if(!exists) + PX_PLACEMENT_NEW(e, Entry)(k, v); + return !exists; + } + + Value& operator[](const Key& k) + { + bool exists; + Entry* e = mBase.create(k, exists); + if(!exists) + PX_PLACEMENT_NEW(e, Entry)(k, Value()); + + return e->second; + } + + PX_INLINE const Entry* find(const Key& k) const + { + return mBase.find(k); + } + PX_INLINE bool erase(const Key& k) + { + return mBase.erase(k); + } + PX_INLINE bool erase(const Key& k, Entry& e) + { + return mBase.erase(k, e); + } + PX_INLINE uint32_t size() const + { + return mBase.size(); + } + PX_INLINE uint32_t capacity() const + { + return mBase.capacity(); + } + PX_INLINE Iterator getIterator() + { + return Iterator(mBase); + } + PX_INLINE EraseIterator getEraseIterator() + { + return EraseIterator(mBase); + } + PX_INLINE void reserve(uint32_t size) + { + mBase.reserve(size); + } + PX_INLINE void clear() + { + mBase.clear(); + } + + protected: + BaseMap mBase; +}; +} + +} // namespace ps +} // namespace cloth +} // namespace nv + +#if PX_VC +#pragma warning(pop) +#endif +#endif // #ifndef PSFOUNDATION_PSHASHINTERNALS_H diff --git a/Source/ThirdParty/NvCloth/ps/PsHashMap.h b/Source/ThirdParty/NvCloth/ps/PsHashMap.h new file mode 100644 index 000000000..229b35aaa --- /dev/null +++ b/Source/ThirdParty/NvCloth/ps/PsHashMap.h @@ -0,0 +1,123 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +#ifndef PSFOUNDATION_PSHASHMAP_H +#define PSFOUNDATION_PSHASHMAP_H + +#include "PsHashInternals.h" + +// TODO: make this doxy-format +// +// This header defines two hash maps. Hash maps +// * support custom initial table sizes (rounded up internally to power-of-2) +// * support custom static allocator objects +// * auto-resize, based on a load factor (i.e. a 64-entry .75 load factor hash will resize +// when the 49th element is inserted) +// * are based on open hashing +// * have O(1) contains, erase +// +// Maps have STL-like copying semantics, and properly initialize and destruct copies of objects +// +// There are two forms of map: coalesced and uncoalesced. Coalesced maps keep the entries in the +// initial segment of an array, so are fast to iterate over; however deletion is approximately +// twice as expensive. +// +// HashMap: +// bool insert(const Key& k, const Value& v) O(1) amortized (exponential resize policy) +// Value & operator[](const Key& k) O(1) for existing objects, else O(1) amortized +// const Entry * find(const Key& k); O(1) +// bool erase(const T& k); O(1) +// uint32_t size(); constant +// void reserve(uint32_t size); O(MAX(currentOccupancy,size)) +// void clear(); O(currentOccupancy) (with zero constant for objects +// without +// destructors) +// Iterator getIterator(); +// +// operator[] creates an entry if one does not exist, initializing with the default constructor. +// CoalescedHashMap does not support getIterator, but instead supports +// const Key *getEntries(); +// +// Use of iterators: +// +// for(HashMap::Iterator iter = test.getIterator(); !iter.done(); ++iter) +// myFunction(iter->first, iter->second); + +/** \brief NVidia namespace */ +namespace nv +{ +/** \brief nvcloth namespace */ +namespace cloth +{ +namespace ps +{ +template , class Allocator = NonTrackingAllocator> +class HashMap : public internal::HashMapBase +{ + public: + typedef internal::HashMapBase HashMapBase; + typedef typename HashMapBase::Iterator Iterator; + + HashMap(uint32_t initialTableSize = 64, float loadFactor = 0.75f) : HashMapBase(initialTableSize, loadFactor) + { + } + HashMap(uint32_t initialTableSize, float loadFactor, const Allocator& alloc) + : HashMapBase(initialTableSize, loadFactor, alloc) + { + } + HashMap(const Allocator& alloc) : HashMapBase(64, 0.75f, alloc) + { + } + Iterator getIterator() + { + return Iterator(HashMapBase::mBase); + } +}; + +template , class Allocator = NonTrackingAllocator> +class CoalescedHashMap : public internal::HashMapBase +{ + public: + typedef internal::HashMapBase HashMapBase; + + CoalescedHashMap(uint32_t initialTableSize = 64, float loadFactor = 0.75f) + : HashMapBase(initialTableSize, loadFactor) + { + } + const Pair* getEntries() const + { + return HashMapBase::mBase.getEntries(); + } +}; + +} // namespace ps +} // namespace cloth +} // namespace nv + +#endif // #ifndef PSFOUNDATION_PSHASHMAP_H diff --git a/Source/ThirdParty/NvCloth/ps/PsIntrinsics.h b/Source/ThirdParty/NvCloth/ps/PsIntrinsics.h new file mode 100644 index 000000000..5f5d35d16 --- /dev/null +++ b/Source/ThirdParty/NvCloth/ps/PsIntrinsics.h @@ -0,0 +1,47 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +#ifndef PSFOUNDATION_PSINTRINSICS_H +#define PSFOUNDATION_PSINTRINSICS_H + +#include "foundation/PxPreprocessor.h" + +#if PX_WINDOWS_FAMILY +#include "windows/PsWindowsIntrinsics.h" +#elif(PX_LINUX || PX_ANDROID || PX_APPLE_FAMILY || PX_PS4 || PX_PS5) +#include "unix/PsUnixIntrinsics.h" +#elif PX_XBOXONE +#include "XboxOne/PsXboxOneIntrinsics.h" +#elif PX_SWITCH +#include "switch/PsSwitchIntrinsics.h" +#else +#error "Platform not supported!" +#endif + +#endif // #ifndef PSFOUNDATION_PSINTRINSICS_H diff --git a/Source/ThirdParty/NvCloth/ps/PsMathUtils.h b/Source/ThirdParty/NvCloth/ps/PsMathUtils.h new file mode 100644 index 000000000..b2c4602c0 --- /dev/null +++ b/Source/ThirdParty/NvCloth/ps/PsMathUtils.h @@ -0,0 +1,699 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +#ifndef PSFOUNDATION_PSMATHUTILS_H +#define PSFOUNDATION_PSMATHUTILS_H + +#include "foundation/PxPreprocessor.h" +#include "foundation/PxTransform.h" +#include "foundation/PxMat33.h" +#include "NvCloth/ps/Ps.h" +#include "NvCloth/ps/PsIntrinsics.h" +#include "NvCloth/Callbacks.h" + +// General guideline is: if it's an abstract math function, it belongs here. +// If it's a math function where the inputs have specific semantics (e.g. +// separateSwingTwist) it doesn't. + +/** \brief NVidia namespace */ +namespace nv +{ +/** \brief nvcloth namespace */ +namespace cloth +{ +namespace ps +{ +/** +\brief sign returns the sign of its argument. The sign of zero is undefined. +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxF32 sign(const physx::PxF32 a) +{ + return physx::intrinsics::sign(a); +} + +/** +\brief sign returns the sign of its argument. The sign of zero is undefined. +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxF64 sign(const physx::PxF64 a) +{ + return (a >= 0.0) ? 1.0 : -1.0; +} + +/** +\brief sign returns the sign of its argument. The sign of zero is undefined. +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxI32 sign(const physx::PxI32 a) +{ + return (a >= 0) ? 1 : -1; +} + +/** +\brief Returns true if the two numbers are within eps of each other. +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE bool equals(const physx::PxF32 a, const physx::PxF32 b, const physx::PxF32 eps) +{ + return (physx::PxAbs(a - b) < eps); +} + +/** +\brief Returns true if the two numbers are within eps of each other. +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE bool equals(const physx::PxF64 a, const physx::PxF64 b, const physx::PxF64 eps) +{ + return (physx::PxAbs(a - b) < eps); +} + +/** +\brief The floor function returns a floating-point value representing the largest integer that is less than or equal to +x. +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxF32 floor(const physx::PxF32 a) +{ + return ::floorf(a); +} + +/** +\brief The floor function returns a floating-point value representing the largest integer that is less than or equal to +x. +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxF64 floor(const physx::PxF64 a) +{ + return ::floor(a); +} + +/** +\brief The ceil function returns a single value representing the smallest integer that is greater than or equal to x. +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxF32 ceil(const physx::PxF32 a) +{ + return ::ceilf(a); +} + +/** +\brief The ceil function returns a double value representing the smallest integer that is greater than or equal to x. +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxF64 ceil(const physx::PxF64 a) +{ + return ::ceil(a); +} + +/** +\brief mod returns the floating-point remainder of x / y. + +If the value of y is 0.0, mod returns a quiet NaN. +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxF32 mod(const physx::PxF32 x, const physx::PxF32 y) +{ + return physx::PxF32(::fmodf(x, y)); +} + +/** +\brief mod returns the floating-point remainder of x / y. + +If the value of y is 0.0, mod returns a quiet NaN. +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxF64 mod(const physx::PxF64 x, const physx::PxF64 y) +{ + return ::fmod(x, y); +} + +/** +\brief Square. +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxF32 sqr(const physx::PxF32 a) +{ + return a * a; +} + +/** +\brief Square. +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxF64 sqr(const physx::PxF64 a) +{ + return a * a; +} + +/** +\brief Calculates x raised to the power of y. +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxF32 pow(const physx::PxF32 x, const physx::PxF32 y) +{ + return ::powf(x, y); +} + +/** +\brief Calculates x raised to the power of y. +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxF64 pow(const physx::PxF64 x, const physx::PxF64 y) +{ + return ::pow(x, y); +} + +/** +\brief Calculates e^n +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxF32 exp(const physx::PxF32 a) +{ + return ::expf(a); +} +/** + +\brief Calculates e^n +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxF64 exp(const physx::PxF64 a) +{ + return ::exp(a); +} + +/** +\brief Calculates 2^n +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxF32 exp2(const physx::PxF32 a) +{ + return ::expf(a * 0.693147180559945309417f); +} +/** + +\brief Calculates 2^n +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxF64 exp2(const physx::PxF64 a) +{ + return ::exp(a * 0.693147180559945309417); +} + +/** +\brief Calculates logarithms. +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxF32 logE(const physx::PxF32 a) +{ + return ::logf(a); +} + +/** +\brief Calculates logarithms. +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxF64 logE(const physx::PxF64 a) +{ + return ::log(a); +} + +/** +\brief Calculates logarithms. +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxF32 log2(const physx::PxF32 a) +{ + return ::logf(a) / 0.693147180559945309417f; +} + +/** +\brief Calculates logarithms. +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxF64 log2(const physx::PxF64 a) +{ + return ::log(a) / 0.693147180559945309417; +} + +/** +\brief Calculates logarithms. +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxF32 log10(const physx::PxF32 a) +{ + return ::log10f(a); +} + +/** +\brief Calculates logarithms. +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxF64 log10(const physx::PxF64 a) +{ + return ::log10(a); +} + +/** +\brief Converts degrees to radians. +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxF32 degToRad(const physx::PxF32 a) +{ + return 0.01745329251994329547f * a; +} + +/** +\brief Converts degrees to radians. +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxF64 degToRad(const physx::PxF64 a) +{ + return 0.01745329251994329547 * a; +} + +/** +\brief Converts radians to degrees. +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxF32 radToDeg(const physx::PxF32 a) +{ + return 57.29577951308232286465f * a; +} + +/** +\brief Converts radians to degrees. +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxF64 radToDeg(const physx::PxF64 a) +{ + return 57.29577951308232286465 * a; +} + +//! \brief compute sine and cosine at the same time. There is a 'fsincos' on PC that we probably want to use here +PX_CUDA_CALLABLE PX_FORCE_INLINE void sincos(const physx::PxF32 radians, physx::PxF32& sin, physx::PxF32& cos) +{ + /* something like: + _asm fld Local + _asm fsincos + _asm fstp LocalCos + _asm fstp LocalSin + */ + sin = physx::PxSin(radians); + cos = physx::PxCos(radians); +} + +/** +\brief uniform random number in [a,b] +*/ +PX_FORCE_INLINE physx::PxI32 rand(const physx::PxI32 a, const physx::PxI32 b) +{ + return a + physx::PxI32(::rand() % (b - a + 1)); +} + +/** +\brief uniform random number in [a,b] +*/ +PX_FORCE_INLINE physx::PxF32 rand(const physx::PxF32 a, const physx::PxF32 b) +{ + return a + (b - a) * ::rand() / RAND_MAX; +} + +//! \brief return angle between two vectors in radians +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxF32 angle(const physx::PxVec3& v0, const physx::PxVec3& v1) +{ + const physx::PxF32 cos = v0.dot(v1); // |v0|*|v1|*Cos(Angle) + const physx::PxF32 sin = (v0.cross(v1)).magnitude(); // |v0|*|v1|*Sin(Angle) + return physx::PxAtan2(sin, cos); +} + +//! If possible use instead fsel on the dot product /*fsel(d.dot(p),onething,anotherthing);*/ +//! Compares orientations (more readable, user-friendly function) +PX_CUDA_CALLABLE PX_FORCE_INLINE bool sameDirection(const physx::PxVec3& d, const physx::PxVec3& p) +{ + return d.dot(p) >= 0.0f; +} + +//! Checks 2 values have different signs +PX_CUDA_CALLABLE PX_FORCE_INLINE IntBool differentSign(physx::PxReal f0, physx::PxReal f1) +{ +#if !PX_EMSCRIPTEN + union + { + physx::PxU32 u; + physx::PxReal f; + } u1, u2; + u1.f = f0; + u2.f = f1; + return IntBool((u1.u ^ u2.u) & PX_SIGN_BITMASK); +#else + // javascript floats are 64-bits... + return IntBool( (f0*f1) < 0.0f ); +#endif +} + +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxMat33 star(const physx::PxVec3& v) +{ + return physx::PxMat33(physx::PxVec3(0, v.z, -v.y), physx::PxVec3(-v.z, 0, v.x), physx::PxVec3(v.y, -v.x, 0)); +} + +PX_CUDA_CALLABLE PX_INLINE physx::PxVec3 log(const physx::PxQuat& q) +{ + const physx::PxReal s = q.getImaginaryPart().magnitude(); + if(s < 1e-12f) + return physx::PxVec3(0.0f); + // force the half-angle to have magnitude <= pi/2 + physx::PxReal halfAngle = q.w < 0 ? physx::PxAtan2(-s, -q.w) : physx::PxAtan2(s, q.w); + NV_CLOTH_ASSERT(halfAngle >= -physx::PxPi / 2 && halfAngle <= physx::PxPi / 2); + + return q.getImaginaryPart().getNormalized() * 2.f * halfAngle; +} + +PX_CUDA_CALLABLE PX_INLINE physx::PxQuat exp(const physx::PxVec3& v) +{ + const physx::PxReal m = v.magnitudeSquared(); + return m < 1e-24f ? physx::PxQuat(physx::PxIdentity) : physx::PxQuat(physx::PxSqrt(m), v * physx::PxRecipSqrt(m)); +} + +// quat to rotate v0 t0 v1 +PX_CUDA_CALLABLE PX_INLINE physx::PxQuat rotationArc(const physx::PxVec3& v0, const physx::PxVec3& v1) +{ + const physx::PxVec3 cross = v0.cross(v1); + const physx::PxReal d = v0.dot(v1); + if(d <= -0.99999f) + return (physx::PxAbs(v0.x) < 0.1f ? physx::PxQuat(0.0f, v0.z, -v0.y, 0.0f) : physx::PxQuat(v0.y, -v0.x, 0.0, 0.0)).getNormalized(); + + const physx::PxReal s = physx::PxSqrt((1 + d) * 2), r = 1 / s; + + return physx::PxQuat(cross.x * r, cross.y * r, cross.z * r, s * 0.5f).getNormalized(); +} + +/** +\brief returns largest axis +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxU32 largestAxis(const physx::PxVec3& v) +{ + physx::PxU32 m = physx::PxU32(v.y > v.x ? 1 : 0); + return v.z > v[m] ? 2 : m; +} + +/** +\brief returns indices for the largest axis and 2 other axii +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxU32 largestAxis(const physx::PxVec3& v, physx::PxU32& other1, physx::PxU32& other2) +{ + if(v.x >= physx::PxMax(v.y, v.z)) + { + other1 = 1; + other2 = 2; + return 0; + } + else if(v.y >= v.z) + { + other1 = 0; + other2 = 2; + return 1; + } + else + { + other1 = 0; + other2 = 1; + return 2; + } +} + +/** +\brief returns axis with smallest absolute value +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxU32 closestAxis(const physx::PxVec3& v) +{ + physx::PxU32 m = physx::PxU32(physx::PxAbs(v.y) > physx::PxAbs(v.x) ? 1 : 0); + return physx::PxAbs(v.z) > physx::PxAbs(v[m]) ? 2 : m; +} + +PX_CUDA_CALLABLE PX_INLINE physx::PxU32 closestAxis(const physx::PxVec3& v, physx::PxU32& j, physx::PxU32& k) +{ + // find largest 2D plane projection + const physx::PxF32 absPx = physx::PxAbs(v.x); + const physx::PxF32 absNy = physx::PxAbs(v.y); + const physx::PxF32 absNz = physx::PxAbs(v.z); + + physx::PxU32 m = 0; // x biggest axis + j = 1; + k = 2; + if(absNy > absPx && absNy > absNz) + { + // y biggest + j = 2; + k = 0; + m = 1; + } + else if(absNz > absPx) + { + // z biggest + j = 0; + k = 1; + m = 2; + } + return m; +} + +/*! +Extend an edge along its length by a factor +*/ +PX_CUDA_CALLABLE PX_FORCE_INLINE void makeFatEdge(physx::PxVec3& p0, physx::PxVec3& p1, physx::PxReal fatCoeff) +{ + physx::PxVec3 delta = p1 - p0; + + const physx::PxReal m = delta.magnitude(); + if(m > 0.0f) + { + delta *= fatCoeff / m; + p0 -= delta; + p1 += delta; + } +} + +//! Compute point as combination of barycentric coordinates +PX_CUDA_CALLABLE PX_FORCE_INLINE physx::PxVec3 +computeBarycentricPoint(const physx::PxVec3& p0, const physx::PxVec3& p1, const physx::PxVec3& p2, physx::PxReal u, physx::PxReal v) +{ + // This seems to confuse the compiler... + // return (1.0f - u - v)*p0 + u*p1 + v*p2; + const physx::PxF32 w = 1.0f - u - v; + return physx::PxVec3(w * p0.x + u * p1.x + v * p2.x, w * p0.y + u * p1.y + v * p2.y, w * p0.z + u * p1.z + v * p2.z); +} + +// generates a pair of quaternions (swing, twist) such that in = swing * twist, with +// swing.x = 0 +// twist.y = twist.z = 0, and twist is a unit quat +PX_FORCE_INLINE void separateSwingTwist(const physx::PxQuat& q, physx::PxQuat& swing, physx::PxQuat& twist) +{ + twist = q.x != 0.0f ? physx::PxQuat(q.x, 0, 0, q.w).getNormalized() : physx::PxQuat(physx::PxIdentity); + swing = q * twist.getConjugate(); +} + +// generate two tangent vectors to a given normal +PX_FORCE_INLINE void normalToTangents(const physx::PxVec3& normal, physx::PxVec3& tangent0, physx::PxVec3& tangent1) +{ + tangent0 = physx::PxAbs(normal.x) < 0.70710678f ? physx::PxVec3(0, -normal.z, normal.y) : physx::PxVec3(-normal.y, normal.x, 0); + tangent0.normalize(); + tangent1 = normal.cross(tangent0); +} + +/** +\brief computes a oriented bounding box around the scaled basis. +\param basis Input = skewed basis, Output = (normalized) orthogonal basis. +\return Bounding box extent. +*/ +NV_CLOTH_IMPORT physx::PxVec3 optimizeBoundingBox(physx::PxMat33& basis); + +NV_CLOTH_IMPORT physx::PxQuat slerp(const physx::PxReal t, const physx::PxQuat& left, const physx::PxQuat& right); + +PX_CUDA_CALLABLE PX_INLINE physx::PxVec3 ellipseClamp(const physx::PxVec3& point, const physx::PxVec3& radii) +{ + // This function need to be implemented in the header file because + // it is included in a spu shader program. + + // finds the closest point on the ellipse to a given point + + // (p.y, p.z) is the input point + // (e.y, e.z) are the radii of the ellipse + + // lagrange multiplier method with Newton/Halley hybrid root-finder. + // see http://www.geometrictools.com/Documentation/DistancePointToEllipse2.pdf + // for proof of Newton step robustness and initial estimate. + // Halley converges much faster but sometimes overshoots - when that happens we take + // a newton step instead + + // converges in 1-2 iterations where D&C works well, and it's good with 4 iterations + // with any ellipse that isn't completely crazy + + const physx::PxU32 MAX_ITERATIONS = 20; + const physx::PxReal convergenceThreshold = 1e-4f; + + // iteration requires first quadrant but we recover generality later + + physx::PxVec3 q(0, physx::PxAbs(point.y), physx::PxAbs(point.z)); + const physx::PxReal tinyEps = 1e-6f; // very close to minor axis is numerically problematic but trivial + if(radii.y >= radii.z) + { + if(q.z < tinyEps) + return physx::PxVec3(0, point.y > 0 ? radii.y : -radii.y, 0); + } + else + { + if(q.y < tinyEps) + return physx::PxVec3(0, 0, point.z > 0 ? radii.z : -radii.z); + } + + physx::PxVec3 denom, e2 = radii.multiply(radii), eq = radii.multiply(q); + + // we can use any initial guess which is > maximum(-e.y^2,-e.z^2) and for which f(t) is > 0. + // this guess works well near the axes, but is weak along the diagonals. + + physx::PxReal t = physx::PxMax(eq.y - e2.y, eq.z - e2.z); + + for(physx::PxU32 i = 0; i < MAX_ITERATIONS; i++) + { + denom = physx::PxVec3(0, 1 / (t + e2.y), 1 / (t + e2.z)); + physx::PxVec3 denom2 = eq.multiply(denom); + + physx::PxVec3 fv = denom2.multiply(denom2); + physx::PxReal f = fv.y + fv.z - 1; + + // although in exact arithmetic we are guaranteed f>0, we can get here + // on the first iteration via catastrophic cancellation if the point is + // very close to the origin. In that case we just behave as if f=0 + + if(f < convergenceThreshold) + return e2.multiply(point).multiply(denom); + + physx::PxReal df = fv.dot(denom) * -2.0f; + t = t - f / df; + } + + // we didn't converge, so clamp what we have + physx::PxVec3 r = e2.multiply(point).multiply(denom); + return r * physx::PxRecipSqrt(sqr(r.y / radii.y) + sqr(r.z / radii.z)); +} + +PX_CUDA_CALLABLE PX_INLINE physx::PxReal tanHalf(physx::PxReal sin, physx::PxReal cos) +{ + return sin / (1 + cos); +} + +PX_INLINE physx::PxQuat quatFromTanQVector(const physx::PxVec3& v) +{ + physx::PxReal v2 = v.dot(v); + if(v2 < 1e-12f) + return physx::PxQuat(physx::PxIdentity); + physx::PxReal d = 1 / (1 + v2); + return physx::PxQuat(v.x * 2, v.y * 2, v.z * 2, 1 - v2) * d; +} + +PX_FORCE_INLINE physx::PxVec3 cross100(const physx::PxVec3& b) +{ + return physx::PxVec3(0.0f, -b.z, b.y); +} +PX_FORCE_INLINE physx::PxVec3 cross010(const physx::PxVec3& b) +{ + return physx::PxVec3(b.z, 0.0f, -b.x); +} +PX_FORCE_INLINE physx::PxVec3 cross001(const physx::PxVec3& b) +{ + return physx::PxVec3(-b.y, b.x, 0.0f); +} + +PX_INLINE void decomposeVector(physx::PxVec3& normalCompo, physx::PxVec3& tangentCompo, const physx::PxVec3& outwardDir, + const physx::PxVec3& outwardNormal) +{ + normalCompo = outwardNormal * (outwardDir.dot(outwardNormal)); + tangentCompo = outwardDir - normalCompo; +} + +//! \brief Return (i+1)%3 +// Avoid variable shift for XBox: +// PX_INLINE physx::PxU32 Ps::getNextIndex3(physx::PxU32 i) { return (1<> 1)) & 3; +} + +PX_INLINE physx::PxMat33 rotFrom2Vectors(const physx::PxVec3& from, const physx::PxVec3& to) +{ + // See bottom of http://www.euclideanspace.com/maths/algebra/matrix/orthogonal/rotation/index.htm + + // Early exit if to = from + if((from - to).magnitudeSquared() < 1e-4f) + return physx::PxMat33(physx::PxIdentity); + + // Early exit if to = -from + if((from + to).magnitudeSquared() < 1e-4f) + return physx::PxMat33::createDiagonal(physx::PxVec3(1.0f, -1.0f, -1.0f)); + + physx::PxVec3 n = from.cross(to); + + physx::PxReal C = from.dot(to), S = physx::PxSqrt(1 - C * C), CC = 1 - C; + + physx::PxReal xx = n.x * n.x, yy = n.y * n.y, zz = n.z * n.z, xy = n.x * n.y, yz = n.y * n.z, xz = n.x * n.z; + + physx::PxMat33 R; + + R(0, 0) = 1 + CC * (xx - 1); + R(0, 1) = -n.z * S + CC * xy; + R(0, 2) = n.y * S + CC * xz; + + R(1, 0) = n.z * S + CC * xy; + R(1, 1) = 1 + CC * (yy - 1); + R(1, 2) = -n.x * S + CC * yz; + + R(2, 0) = -n.y * S + CC * xz; + R(2, 1) = n.x * S + CC * yz; + R(2, 2) = 1 + CC * (zz - 1); + + return R; +} + +NV_CLOTH_IMPORT void integrateTransform(const physx::PxTransform& curTrans, const physx::PxVec3& linvel, const physx::PxVec3& angvel, + physx::PxReal timeStep, physx::PxTransform& result); + +PX_INLINE void computeBasis(const physx::PxVec3& dir, physx::PxVec3& right, physx::PxVec3& up) +{ + // Derive two remaining vectors + if(physx::PxAbs(dir.y) <= 0.9999f) + { + right = physx::PxVec3(dir.z, 0.0f, -dir.x); + right.normalize(); + + // PT: normalize not needed for 'up' because dir & right are unit vectors, + // and by construction the angle between them is 90 degrees (i.e. sin(angle)=1) + up = physx::PxVec3(dir.y * right.z, dir.z * right.x - dir.x * right.z, -dir.y * right.x); + } + else + { + right = physx::PxVec3(1.0f, 0.0f, 0.0f); + + up = physx::PxVec3(0.0f, dir.z, -dir.y); + up.normalize(); + } +} + +PX_INLINE void computeBasis(const physx::PxVec3& p0, const physx::PxVec3& p1, physx::PxVec3& dir, physx::PxVec3& right, physx::PxVec3& up) +{ + // Compute the new direction vector + dir = p1 - p0; + dir.normalize(); + + // Derive two remaining vectors + computeBasis(dir, right, up); +} + +PX_FORCE_INLINE bool isAlmostZero(const physx::PxVec3& v) +{ + if(physx::PxAbs(v.x) > 1e-6f || physx::PxAbs(v.y) > 1e-6f || physx::PxAbs(v.z) > 1e-6f) + return false; + return true; +} +} // namespace ps +} // namespace cloth +} // namespace nv + +#endif diff --git a/Source/ThirdParty/NvCloth/ps/PsUserAllocated.h b/Source/ThirdParty/NvCloth/ps/PsUserAllocated.h new file mode 100644 index 000000000..bcf3928bb --- /dev/null +++ b/Source/ThirdParty/NvCloth/ps/PsUserAllocated.h @@ -0,0 +1,97 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +#ifndef PSFOUNDATION_PSUSERALLOCATED_H +#define PSFOUNDATION_PSUSERALLOCATED_H + +#include "PsAllocator.h" + +/** \brief NVidia namespace */ +namespace nv +{ +/** \brief nvcloth namespace */ +namespace cloth +{ +namespace ps +{ +/** +Provides new and delete using a UserAllocator. +Guarantees that 'delete x;' uses the UserAllocator too. +*/ +class UserAllocated +{ + public: + // PX_SERIALIZATION + PX_INLINE void* operator new(size_t, void* address) + { + return address; + } + //~PX_SERIALIZATION + // Matching operator delete to the above operator new. Don't ask me + // how this makes any sense - Nuernberger. + PX_INLINE void operator delete(void*, void*) + { + } + + template + PX_INLINE void* operator new(size_t size, Alloc alloc, const char* fileName, int line) + { + return alloc.allocate(size, fileName, line); + } + template + PX_INLINE void* operator new [](size_t size, Alloc alloc, const char* fileName, int line) + { return alloc.allocate(size, fileName, line); } + + // placement delete + template + PX_INLINE void operator delete(void* ptr, Alloc alloc, const char* fileName, int line) + { + PX_UNUSED(fileName); + PX_UNUSED(line); + alloc.deallocate(ptr); + } + template + PX_INLINE void operator delete [](void* ptr, Alloc alloc, const char* fileName, int line) + { + PX_UNUSED(fileName); + PX_UNUSED(line); + alloc.deallocate(ptr); + } PX_INLINE void + operator delete(void* ptr) + { + NonTrackingAllocator().deallocate(ptr); + } + PX_INLINE void operator delete [](void* ptr) + { NonTrackingAllocator().deallocate(ptr); } +}; +} // namespace ps +} // namespace cloth +} // namespace nv + +#endif // #ifndef PSFOUNDATION_PSUSERALLOCATED_H diff --git a/Source/ThirdParty/NvCloth/ps/unix/PsUnixIntrinsics.h b/Source/ThirdParty/NvCloth/ps/unix/PsUnixIntrinsics.h new file mode 100644 index 000000000..2a7401764 --- /dev/null +++ b/Source/ThirdParty/NvCloth/ps/unix/PsUnixIntrinsics.h @@ -0,0 +1,138 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +#ifndef PSFOUNDATION_PSUNIXINTRINSICS_H +#define PSFOUNDATION_PSUNIXINTRINSICS_H + +#include "NvCloth/ps/Ps.h" +#include "NvCloth/Callbacks.h" +#include + +#if PX_ANDROID || (PX_LINUX && !(PX_X64 || PX_X64)) // x86[_64] Linux uses inline assembly for debug break +#include // for Ns::debugBreak() { raise(SIGTRAP); } +#endif + +#if 0 +#include +#endif + +// this file is for internal intrinsics - that is, intrinsics that are used in +// cross platform code but do not appear in the API + +#if !(PX_LINUX || PX_ANDROID || PX_PS4 || PX_PS5 || PX_APPLE_FAMILY) +#error "This file should only be included by unix builds!!" +#endif + +/** \brief NVidia namespace */ +namespace nv +{ +/** \brief nvcloth namespace */ +namespace cloth +{ +namespace ps +{ + + +PX_FORCE_INLINE void PxMemoryBarrier() +{ + __sync_synchronize(); +} + +/*! +Return the index of the highest set bit. Undefined for zero arg. +*/ +PX_INLINE uint32_t PxHighestSetBitUnsafe(uint32_t v) +{ + + return 31 - __builtin_clz(v); +} + +/*! +Return the index of the highest set bit. Undefined for zero arg. +*/ +PX_INLINE int32_t PxLowestSetBitUnsafe(uint32_t v) +{ + return __builtin_ctz(v); +} + +/*! +Returns the index of the highest set bit. Returns 32 for v=0. +*/ +PX_INLINE uint32_t PxCountLeadingZeros(uint32_t v) +{ + if(v) + return __builtin_clz(v); + else + return 32; +} + +/*! +Prefetch aligned 64B x86, 32b ARM around \c ptr+offset. +*/ +PX_FORCE_INLINE void PxPrefetchLine(const void* ptr, uint32_t offset = 0) +{ + __builtin_prefetch(reinterpret_cast(ptr) + offset, 0, 3); +} + +/*! +Prefetch \c count bytes starting at \c ptr. +*/ +#if PX_ANDROID || PX_IOS +PX_FORCE_INLINE void prefetch(const void* ptr, uint32_t count = 1) +{ + const char* cp = static_cast(ptr); + size_t p = reinterpret_cast(ptr); + uint32_t startLine = uint32_t(p >> 5), endLine = uint32_t((p + count - 1) >> 5); + uint32_t lines = endLine - startLine + 1; + do + { + PxPrefetchLine(cp); + cp += 32; + } while(--lines); +} +#else +PX_FORCE_INLINE void prefetch(const void* ptr, uint32_t count = 1) +{ + const char* cp = reinterpret_cast(ptr); + uint64_t p = size_t(ptr); + uint64_t startLine = p >> 6, endLine = (p + count - 1) >> 6; + uint64_t lines = endLine - startLine + 1; + do + { + PxPrefetchLine(cp); + cp += 64; + } while(--lines); +} +#endif + +} // namespace ps +} // namespace cloth +} // namespace nv + +#endif // #ifndef PSFOUNDATION_PSUNIXINTRINSICS_H diff --git a/Source/ThirdParty/NvCloth/ps/windows/PsWindowsIntrinsics.h b/Source/ThirdParty/NvCloth/ps/windows/PsWindowsIntrinsics.h new file mode 100644 index 000000000..5eaaac40f --- /dev/null +++ b/Source/ThirdParty/NvCloth/ps/windows/PsWindowsIntrinsics.h @@ -0,0 +1,173 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +#ifndef PSFOUNDATION_PSWINDOWSINTRINSICS_H +#define PSFOUNDATION_PSWINDOWSINTRINSICS_H + +#include "Ps.h" + +// this file is for internal intrinsics - that is, intrinsics that are used in +// cross platform code but do not appear in the API + +#if !PX_WINDOWS_FAMILY +#error "This file should only be included by Windows builds!!" +#endif + +#pragma warning(push) +//'symbol' is not defined as a preprocessor macro, replacing with '0' for 'directives' +#pragma warning(disable : 4668) +#if PX_VC == 10 +#pragma warning(disable : 4987) // nonstandard extension used: 'throw (...)' +#endif +#include +#pragma warning(pop) + +#pragma warning(push) +#pragma warning(disable : 4985) // 'symbol name': attributes not present on previous declaration +#include +#pragma warning(pop) + +#include +#include + +#pragma intrinsic(_BitScanForward) +#pragma intrinsic(_BitScanReverse) + +/** \brief NVidia namespace */ +namespace nv +{ +/** \brief nvcloth namespace */ +namespace cloth +{ +namespace ps +{ + +/* +* Implements a memory barrier +*/ +PX_FORCE_INLINE void PxMemoryBarrier() +{ + _ReadWriteBarrier(); + /* long Barrier; + __asm { + xchg Barrier, eax + }*/ +} + +/*! +Returns the index of the highest set bit. Not valid for zero arg. +*/ +PX_FORCE_INLINE uint32_t PxHighestSetBitUnsafe(uint32_t v) +{ + unsigned long retval; + _BitScanReverse(&retval, v); + return retval; +} + +/*! +Returns the index of the highest set bit. Undefined for zero arg. +*/ +PX_FORCE_INLINE uint32_t PxLowestSetBitUnsafe(uint32_t v) +{ + unsigned long retval; + _BitScanForward(&retval, v); + return retval; +} + +/*! +Returns the number of leading zeros in v. Returns 32 for v=0. +*/ +PX_FORCE_INLINE uint32_t PxCountLeadingZeros(uint32_t v) +{ + if(v) + { + unsigned long bsr = (unsigned long)-1; + _BitScanReverse(&bsr, v); + return 31 - bsr; + } + else + return 32; +} + +/*! +Prefetch aligned cache size around \c ptr+offset. +*/ +#if !PX_ARM +PX_FORCE_INLINE void PxPrefetchLine(const void* ptr, uint32_t offset = 0) +{ + // cache line on X86/X64 is 64-bytes so a 128-byte prefetch would require 2 prefetches. + // However, we can only dispatch a limited number of prefetch instructions so we opt to prefetch just 1 cache line + /*_mm_prefetch(((const char*)ptr + offset), _MM_HINT_T0);*/ + // We get slightly better performance prefetching to non-temporal addresses instead of all cache levels + _mm_prefetch(((const char*)ptr + offset), _MM_HINT_NTA); +} +#else +PX_FORCE_INLINE void PxPrefetchLine(const void* ptr, uint32_t offset = 0) +{ + // arm does have 32b cache line size + __prefetch(((const char*)ptr + offset)); +} +#endif + +/*! +Prefetch \c count bytes starting at \c ptr. +*/ +#if !PX_ARM +PX_FORCE_INLINE void PxPrefetch(const void* ptr, uint32_t count = 1) +{ + const char* cp = (char*)ptr; + uint64_t p = size_t(ptr); + uint64_t startLine = p >> 6, endLine = (p + count - 1) >> 6; + uint64_t lines = endLine - startLine + 1; + do + { + PxPrefetchLine(cp); + cp += 64; + } while(--lines); +} +#else +PX_FORCE_INLINE void PxPrefetch(const void* ptr, uint32_t count = 1) +{ + const char* cp = (char*)ptr; + uint32_t p = size_t(ptr); + uint32_t startLine = p >> 5, endLine = (p + count - 1) >> 5; + uint32_t lines = endLine - startLine + 1; + do + { + PxPrefetchLine(cp); + cp += 32; + } while(--lines); +} +#endif + +} // namespace ps +} // namespace cloth +} // namespace nv + +#endif // #ifndef PSFOUNDATION_PSWINDOWSINTRINSICS_H diff --git a/Source/Tools/Flax.Build/Deps/Dependency.cs b/Source/Tools/Flax.Build/Deps/Dependency.cs index 29b9fd58a..46422179e 100644 --- a/Source/Tools/Flax.Build/Deps/Dependency.cs +++ b/Source/Tools/Flax.Build/Deps/Dependency.cs @@ -275,18 +275,18 @@ namespace Flax.Deps cmdLine = string.Format("CMakeLists.txt -G \"Visual Studio 17 2022\" -A {0}", arch); break; } - case TargetPlatform.Linux: case TargetPlatform.PS4: + cmdLine = "CMakeLists.txt -DCMAKE_GENERATOR_PLATFORM=ORBIS -G \"Visual Studio 15 2017\""; + break; case TargetPlatform.PS5: - { + cmdLine = "CMakeLists.txt -DCMAKE_GENERATOR_PLATFORM=PROSPERO -G \"Visual Studio 16 2019\""; + break; + case TargetPlatform.Linux: cmdLine = "CMakeLists.txt"; break; - } case TargetPlatform.Switch: - { cmdLine = string.Format("-DCMAKE_TOOLCHAIN_FILE=\"{1}\\Source\\Platforms\\Switch\\Binaries\\Data\\Switch.cmake\" -G \"NMake Makefiles\" -DCMAKE_MAKE_PROGRAM=\"{0}..\\..\\VC\\bin\\nmake.exe\"", Environment.GetEnvironmentVariable("VS140COMNTOOLS"), Globals.EngineRoot); break; - } case TargetPlatform.Android: { var ndk = AndroidNdk.Instance.RootPath;