Add NvCloth dependency

This commit is contained in:
Wojtek Figat
2023-07-03 09:51:42 +02:00
parent 99ee0b1bfe
commit 8818b3b07c
34 changed files with 6135 additions and 5 deletions

168
Source/ThirdParty/NvCloth/Allocator.h vendored Normal file
View File

@@ -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 <typename T>
struct Vector
{
typedef ps::Array<T, ps::NonTrackingAllocator> Type;
};
template <typename T, size_t alignment>
struct AlignedVector
{
typedef ps::Array<T, ps::AlignedAllocator<alignment, ps::NonTrackingAllocator> > Type;
};
template <class Key, class Value, class HashFn = ps::Hash<Key> >
struct HashMap
{
typedef ps::HashMap<Key, Value, HashFn, ps::NonTrackingAllocator> 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 <typename T>
PX_INLINE void* operator new(size_t size, const char* fileName,
typename nv::cloth::ps::EnableIfPod<T, int>::Type line, nv::cloth::NvClothOverload overload)
{
PX_UNUSED(overload);
return GetNvClothAllocator()->allocate(size, "<TypeName Unknown>", fileName, line);
}
template <typename T>
PX_INLINE void* operator new [](size_t size, const char* fileName,
typename nv::cloth::ps::EnableIfPod<T, int>::Type line, nv::cloth::NvClothOverload overload)
{
PX_UNUSED(overload);
return GetNvClothAllocator()->allocate(size, "<TypeName Unknown>", fileName, line);
}
// If construction after placement new throws, this placement delete is being called.
template <typename T>
PX_INLINE void operator delete(void* ptr, const char* fileName,
typename nv::cloth::ps::EnableIfPod<T, int>::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 <typename T>
PX_INLINE void operator delete [](void* ptr, const char* fileName,
typename nv::cloth::ps::EnableIfPod<T, int>::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, "<TypeName Unknown>", fileName, line);
}
PX_INLINE void* operator new [](size_t size, const char* fileName, int line, NvClothOverload overload)
{
PX_UNUSED(overload);
return GetNvClothAllocator()->allocate(size, "<TypeName Unknown>", 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 */

192
Source/ThirdParty/NvCloth/Callbacks.h vendored Normal file
View File

@@ -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 <foundation/PxPreprocessor.h>
#include <foundation/PxProfiler.h>
#include <foundation/PxAllocatorCallback.h>
#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
}
}

477
Source/ThirdParty/NvCloth/Cloth.h vendored Normal file
View File

@@ -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 <foundation/PxVec3.h>
#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 <typename T>
struct MappedRange : public Range<T>
{
MappedRange(T* first, T* last, const Cloth& cloth, void (Cloth::*lock)() const, void (Cloth::*unlock)() const)
: Range<T>(first, last), mCloth(cloth), mLock(lock), mUnlock(unlock)
{
}
MappedRange(const MappedRange& other)
: Range<T>(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<physx::PxVec4> 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<const physx::PxVec4> getCurrentParticles() const = 0;
/** \brief Returns the simulation particles of the previous frame.
Similar to getCurrentParticles().
*/
virtual MappedRange<physx::PxVec4> getPreviousParticles() = 0;
/** \brief Returns the simulation particles of the previous frame.
Similar to getCurrentParticles() const.
*/
virtual MappedRange<const physx::PxVec4> 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<const PhaseConfig> 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<const PxVec4>(), 0, cloth->getNumSpheres()); //Removes all spheres
\endcode
*/
virtual void setSpheres(Range<const physx::PxVec4> spheres, uint32_t first, uint32_t last) = 0;
virtual void setSpheres(Range<const physx::PxVec4> startSpheres, Range<const physx::PxVec4> 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<const uint32_t>(capsules, capsules + 4), 0, 2);
\endcode
*/
virtual void setCapsules(Range<const uint32_t> 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<const physx::PxVec4> planes, uint32_t first, uint32_t last) = 0;
virtual void setPlanes(Range<const physx::PxVec4> startPlanes, Range<const physx::PxVec4> 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<<planeIndex1)|(1<<planeIndex2)|...|(1<<planeIndexN).
All planes masked in a single element of convexMasks form a single convex polyhedron.
The values currently in range [first, last[ will be replaced with the content of convexMasks.
*/
virtual void setConvexes(Range<const uint32_t> 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<const physx::PxVec3> triangles, uint32_t first, uint32_t last) = 0;
virtual void setTriangles(Range<const physx::PxVec3> startTriangles, Range<const physx::PxVec3> 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<const uint32_t[4]> indices, Range<const physx::PxVec3> 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<physx::PxVec4> 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<physx::PxVec4> 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<physx::PxVec4> 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<const uint32_t>) = 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<const physx::PxVec4>) = 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<const physx::PxVec4> readCurrentParticles(const Cloth& cloth)
{
return cloth.getCurrentParticles();
}
inline MappedRange<const physx::PxVec4> readPreviousParticles(const Cloth& cloth)
{
return cloth.getPreviousParticles();
}
} // namespace cloth
} // namespace nv

View File

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

130
Source/ThirdParty/NvCloth/Fabric.h vendored Normal file
View File

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

194
Source/ThirdParty/NvCloth/Factory.h vendored Normal file
View File

@@ -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 <foundation/PxVec4.h>
#include <foundation/PxVec3.h>
#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<const uint32_t> phaseIndices, Range<const uint32_t> sets,
Range<const float> restvalues, Range<const float> stiffnessValues, Range<const uint32_t> indices,
Range<const uint32_t> anchors, Range<const float> tetherLengths,
Range<const uint32_t> triangles) = 0;
/**
\brief Create cloth object.
@param particles initial particle positions.
@param fabric edge distance constraint structure
*/
virtual Cloth* createCloth(Range<const physx::PxVec4> 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<uint32_t> phaseIndices, Range<uint32_t> sets,
Range<float> restvalues, Range<float> stiffnessValues, Range<uint32_t> indices, Range<uint32_t> anchors,
Range<float> tetherLengths, Range<uint32_t> 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<physx::PxVec4> spheres, Range<uint32_t> capsules,
Range<physx::PxVec4> planes, Range<uint32_t> convexes, Range<physx::PxVec3> 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<physx::PxVec4> 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<physx::PxVec4> 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<physx::PxVec4> 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<uint32_t[4]> destIndices,
Range<physx::PxVec3> 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<uint32_t> 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<physx::PxVec4> destRestPositions) const = 0;
};
} // namespace cloth
} // namespace nv

69
Source/ThirdParty/NvCloth/License.txt vendored Normal file
View File

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

View File

@@ -0,0 +1,48 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
using System.IO;
using Flax.Build;
using Flax.Build.NativeCpp;
/// <summary>
/// https://github.com/NVIDIAGameWorks/NvCloth
/// </summary>
public class NvCloth : DepsModule
{
/// <inheritdoc />
public override void Init()
{
base.Init();
LicenseType = LicenseTypes.Custom;
LicenseFilePath = "License.txt";
// Merge third-party modules into engine binary
BinaryModuleName = "FlaxEngine";
}
/// <inheritdoc />
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);
}
}

View File

@@ -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<const uint32_t> mPhaseIndices;
Range<const int32_t> mPhaseTypes;
Range<const uint32_t> mSets;
Range<const float> mRestvalues;
Range<const float> mStiffnessValues;
Range<const uint32_t> mIndices;
Range<const uint32_t> mAnchors;
Range<const float> mTetherLengths;
Range<const uint32_t> 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<int32_t>::Type* phaseTypes = nullptr, bool useGeodesicTether = true);
#endif // NV_CLOTH_EXTENSIONS_CLOTH_FABRIC_COOKER_H

View File

@@ -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.
<b>Default:</b> 0
*/
physx::PxU32 stride;
const void* data;
StridedData() : stride( 0 ), data( NULL ) {}
template<typename TDataType>
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<const TDataType*>( 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

View File

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

View File

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

62
Source/ThirdParty/NvCloth/PhaseConfig.h vendored Normal file
View File

@@ -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 <foundation/Px.h>
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

155
Source/ThirdParty/NvCloth/Range.h vendored Normal file
View File

@@ -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 <class T>
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 <typename S>
Range(const Range<S>& 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 <typename T>
Range<T>::Range()
: mBegin(0), mEnd(0)
{
}
template <typename T>
Range<T>::Range(T* begin, T* end)
: mBegin(begin), mEnd(end)
{
}
template <typename T>
template <typename S>
Range<T>::Range(const Range<S>& other)
: mBegin(other.begin()), mEnd(other.end())
{
}
template <typename T>
uint32_t Range<T>::size() const
{
return uint32_t(mEnd - mBegin);
}
template <typename T>
bool Range<T>::empty() const
{
return mBegin >= mEnd;
}
template <typename T>
void Range<T>::popFront()
{
NV_CLOTH_ASSERT(mBegin < mEnd);
++mBegin;
}
template <typename T>
void Range<T>::popBack()
{
NV_CLOTH_ASSERT(mBegin < mEnd);
--mEnd;
}
template <typename T>
T* Range<T>::begin() const
{
return mBegin;
}
template <typename T>
T* Range<T>::end() const
{
return mEnd;
}
template <typename T>
T& Range<T>::front() const
{
NV_CLOTH_ASSERT(mBegin < mEnd);
return *mBegin;
}
template <typename T>
T& Range<T>::back() const
{
NV_CLOTH_ASSERT(mBegin < mEnd);
return mEnd[-1];
}
template <typename T>
T& Range<T>::operator[](uint32_t i) const
{
NV_CLOTH_ASSERT(mBegin + i < mEnd);
return mBegin[i];
}
} // namespace cloth
} // namespace nv

111
Source/ThirdParty/NvCloth/Solver.h vendored Normal file
View File

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

75
Source/ThirdParty/NvCloth/ps/Ps.h vendored Normal file
View File

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

View File

@@ -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 <uint32_t N, typename BaseAllocator = NonTrackingAllocator>
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<uint8_t*>(BaseAllocator::allocate(size + pad, file, line));
if(!base)
return NULL;
uint8_t* ptr = reinterpret_cast<uint8_t*>(size_t(base + pad) & ~(size_t(N) - 1)); // aligned pointer, ensuring N
// is a size_t
// wide mask
reinterpret_cast<size_t*>(ptr)[-1] = size_t(ptr - base); // store offset
return ptr;
}
void deallocate(void* ptr)
{
if(ptr == NULL)
return;
uint8_t* base = reinterpret_cast<uint8_t*>(ptr) - reinterpret_cast<size_t*>(ptr)[-1];
BaseAllocator::deallocate(base);
}
};
} // namespace ps
} // namespace cloth
} // namespace nv
#endif // #ifndef PSFOUNDATION_PSALIGNEDMALLOC_H

View File

@@ -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 <exception>
#if PX_VC >= 16
#include <typeinfo>
#else
#include <typeinfo.h>
#endif
#endif
#if(PX_APPLE_FAMILY)
#include <typeinfo>
#endif
#include <new>
// 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<T>(), __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 <malloc.h>
#define PxAlloca(x) _alloca(x)
#elif PX_LINUX || PX_ANDROID
#include <malloc.h>
#define PxAlloca(x) alloca(x)
#elif PX_APPLE_FAMILY
#include <alloca.h>
#define PxAlloca(x) alloca(x)
#elif PX_PS4 || PX_PS5
#include <memory.h>
#define PxAlloca(x) alloca(x)
#elif PX_XBOXONE
#include <malloc.h>
#define PxAlloca(x) alloca(x)
#elif PX_SWITCH
#include <malloc.h>
#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 <typename T>
class ReflectionAllocator
{
static const char* getName()
{
if(true)
return "<allocation names disabled>";
#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 <typename T>
struct AllocatorTraits
{
typedef ReflectionAllocator<T> 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 <typename T, typename X>
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 <typename T>
PX_INLINE void* operator new(size_t size, nv::cloth::ps::ReflectionAllocator<T> alloc, const char* fileName,
typename nv::cloth::ps::EnableIfPod<T, int>::Type line)
{
return alloc.allocate(size, fileName, line);
}
template <typename T>
PX_INLINE void* operator new [](size_t size, nv::cloth::ps::ReflectionAllocator<T> alloc, const char* fileName,
typename nv::cloth::ps::EnableIfPod<T, int>::Type line)
{ return alloc.allocate(size, fileName, line); }
// If construction after placement new throws, this placement delete is being called.
template <typename T>
PX_INLINE void operator delete(void* ptr, nv::cloth::ps::ReflectionAllocator<T> alloc, const char* fileName,
typename nv::cloth::ps::EnableIfPod<T, int>::Type line)
{
PX_UNUSED(fileName);
PX_UNUSED(line);
alloc.deallocate(ptr);
}
// If construction after placement new throws, this placement delete is being called.
template <typename T>
PX_INLINE void operator delete [](void* ptr, nv::cloth::ps::ReflectionAllocator<T> alloc, const char* fileName,
typename nv::cloth::ps::EnableIfPod<T, int>::Type line)
{
PX_UNUSED(fileName);
PX_UNUSED(line);
alloc.deallocate(ptr);
}
#endif // #ifndef PSFOUNDATION_PSALLOCATOR_H

726
Source/ThirdParty/NvCloth/ps/PsArray.h vendored Normal file
View File

@@ -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 <class Serializer>
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 <class T, class Alloc = typename AllocatorTraits<T>::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 <class A>
PX_INLINE explicit Array(const Array<T, A>& 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 <class A>
PX_INLINE Array& operator=(const Array<T, A>& 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=<Alloc>(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<void*>(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<uint32_t>(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<T, Alloc>& 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 <class A>
PX_NOINLINE void copy(const Array<T, A>& other);
PX_INLINE T* allocate(uint32_t size)
{
if(size > 0)
{
T* p = reinterpret_cast<T*>(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<uint8_t*>(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 <class T, class Alloc>
PX_NOINLINE void Array<T, Alloc>::resize(const uint32_t size, const T& a)
{
reserve(size);
create(mData + mSize, mData + size, a);
destroy(mData + size, mData + mSize);
mSize = size;
}
template <class T, class Alloc>
template <class A>
PX_NOINLINE void Array<T, Alloc>::copy(const Array<T, A>& 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 <class T, class Alloc>
PX_NOINLINE void Array<T, Alloc>::resizeUninitialized(const uint32_t size)
{
reserve(size);
mSize = size;
}
template <class T, class Alloc>
PX_NOINLINE T& Array<T, Alloc>::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<void*>(newData + mSize), T)(a);
destroy(mData, mData + mSize);
if(!isInUserMemory())
deallocate(mData);
mData = newData;
mCapacity = capacity;
return mData[mSize++];
}
template <class T, class Alloc>
PX_NOINLINE void Array<T, Alloc>::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 <class T, class Alloc>
PX_INLINE void swap(Array<T, Alloc>& x, Array<T, Alloc>& y)
{
x.swap(y);
}
} // namespace ps
} // namespace cloth
} // namespace nv
#endif // #ifndef PSFOUNDATION_PSARRAY_H

69
Source/ThirdParty/NvCloth/ps/PsAtomic.h vendored Normal file
View File

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

View File

@@ -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 <typename A>
struct Equal
{
bool operator()(const A& a, const A& b) const
{
return a == b;
}
};
template <typename A>
struct Less
{
bool operator()(const A& a, const A& b) const
{
return a < b;
}
};
template <typename A>
struct Greater
{
bool operator()(const A& a, const A& b) const
{
return a > b;
}
};
template <class F, class S>
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<F,S>' : 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 <unsigned int A>
struct LogTwo
{
static const unsigned int value = LogTwo<(A >> 1)>::value + 1;
};
template <>
struct LogTwo<1>
{
static const unsigned int value = 0;
};
template <typename T>
struct UnConst
{
typedef T Type;
};
template <typename T>
struct UnConst<const T>
{
typedef T Type;
};
template <typename T>
T pointerOffset(void* p, ptrdiff_t offset)
{
return reinterpret_cast<T>(reinterpret_cast<char*>(p) + offset);
}
template <typename T>
T pointerOffset(const void* p, ptrdiff_t offset)
{
return reinterpret_cast<T>(reinterpret_cast<const char*>(p) + offset);
}
template <class T>
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

View File

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

167
Source/ThirdParty/NvCloth/ps/PsHash.h vendored Normal file
View File

@@ -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 <typename F, typename S>
PX_INLINE uint32_t hash(const Pair<F, S>& 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 <class Key>
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<const char*>
{
public:
uint32_t operator()(const char* _string) const
{
// "DJB" string hash
const uint8_t* string = reinterpret_cast<const uint8_t*>(_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

View File

@@ -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 Entry, class Key, class HashFn, class GetKey, class Allocator, bool compacting>
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 <typename HK, typename GK, class A, bool comp>
PX_NOINLINE void copy(const HashBase<Entry, Key, HK, GK, A, comp>& 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<uint8_t*>(Allocator::allocate(newBufferByteSize, __FILE__, __LINE__));
NV_CLOTH_ASSERT(newBuffer);
newHash = reinterpret_cast<uint32_t*>(newBuffer + newHashByteOffset);
newEntriesNext = reinterpret_cast<uint32_t*>(newBuffer + newEntriesNextBytesOffset);
newEntries = reinterpret_cast<Entry*>(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 <class Entry, class Key, class HashFn, class GetKey, class Allocator, bool compacting>
template <typename HK, typename GK, class A, bool comp>
PX_NOINLINE void
HashBase<Entry, Key, HashFn, GetKey, Allocator, compacting>::copy(const HashBase<Entry, Key, HK, GK, A, comp>& 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 <class Key, class HashFn, class Allocator = typename AllocatorTraits<Key>::Type, bool Coalesced = false>
class HashSetBase
{
PX_NOCOPY(HashSetBase)
public:
struct GetKey
{
PX_INLINE const Key& operator()(const Key& e)
{
return e;
}
};
typedef HashBase<Key, Key, HashFn, GetKey, Allocator, Coalesced> 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 <class Key, class Value, class HashFn, class Allocator = typename AllocatorTraits<Pair<const Key, Value> >::Type>
class HashMapBase
{
PX_NOCOPY(HashMapBase)
public:
typedef Pair<const Key, Value> Entry;
struct GetKey
{
PX_INLINE const Key& operator()(const Entry& e)
{
return e.first;
}
};
typedef HashBase<Entry, Key, HashFn, GetKey, Allocator, true> 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

123
Source/ThirdParty/NvCloth/ps/PsHashMap.h vendored Normal file
View File

@@ -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<T>:
// 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<T> 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 Key, class Value, class HashFn = Hash<Key>, class Allocator = NonTrackingAllocator>
class HashMap : public internal::HashMapBase<Key, Value, HashFn, Allocator>
{
public:
typedef internal::HashMapBase<Key, Value, HashFn, Allocator> 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 Key, class Value, class HashFn = Hash<Key>, class Allocator = NonTrackingAllocator>
class CoalescedHashMap : public internal::HashMapBase<Key, Value, HashFn, Allocator>
{
public:
typedef internal::HashMapBase<Key, Value, HashFn, Allocator> HashMapBase;
CoalescedHashMap(uint32_t initialTableSize = 64, float loadFactor = 0.75f)
: HashMapBase(initialTableSize, loadFactor)
{
}
const Pair<const Key, Value>* getEntries() const
{
return HashMapBase::mBase.getEntries();
}
};
} // namespace ps
} // namespace cloth
} // namespace nv
#endif // #ifndef PSFOUNDATION_PSHASHMAP_H

View File

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

View File

@@ -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<<i) & 3; }
PX_INLINE physx::PxU32 getNextIndex3(physx::PxU32 i)
{
return (i + 1 + (i >> 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

View File

@@ -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 <typename Alloc>
PX_INLINE void* operator new(size_t size, Alloc alloc, const char* fileName, int line)
{
return alloc.allocate(size, fileName, line);
}
template <typename Alloc>
PX_INLINE void* operator new [](size_t size, Alloc alloc, const char* fileName, int line)
{ return alloc.allocate(size, fileName, line); }
// placement delete
template <typename Alloc>
PX_INLINE void operator delete(void* ptr, Alloc alloc, const char* fileName, int line)
{
PX_UNUSED(fileName);
PX_UNUSED(line);
alloc.deallocate(ptr);
}
template <typename Alloc>
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

View File

@@ -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 <math.h>
#if PX_ANDROID || (PX_LINUX && !(PX_X64 || PX_X64)) // x86[_64] Linux uses inline assembly for debug break
#include <signal.h> // for Ns::debugBreak() { raise(SIGTRAP); }
#endif
#if 0
#include <libkern/OSAtomic.h>
#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<const char* PX_RESTRICT>(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<const char*>(ptr);
size_t p = reinterpret_cast<size_t>(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<const 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);
}
#endif
} // namespace ps
} // namespace cloth
} // namespace nv
#endif // #ifndef PSFOUNDATION_PSUNIXINTRINSICS_H

View File

@@ -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 <intrin.h>
#pragma warning(pop)
#pragma warning(push)
#pragma warning(disable : 4985) // 'symbol name': attributes not present on previous declaration
#include <math.h>
#pragma warning(pop)
#include <float.h>
#include <mmintrin.h>
#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