diff options
| author | mtamis <[email protected]> | 2017-02-15 16:06:25 +0100 |
|---|---|---|
| committer | mtamis <[email protected]> | 2017-02-15 16:06:25 +0100 |
| commit | 85305930aeeb1d513e23522bd91f29ba81aa6d14 (patch) | |
| tree | 45f1bb20a45a300d1fef107e436cac95602a0e57 /NvCloth/src/ClothImpl.h | |
| download | nvcloth-85305930aeeb1d513e23522bd91f29ba81aa6d14.tar.xz nvcloth-85305930aeeb1d513e23522bd91f29ba81aa6d14.zip | |
NvCloth library v1.0.0
Diffstat (limited to 'NvCloth/src/ClothImpl.h')
| -rw-r--r-- | NvCloth/src/ClothImpl.h | 1393 |
1 files changed, 1393 insertions, 0 deletions
diff --git a/NvCloth/src/ClothImpl.h b/NvCloth/src/ClothImpl.h new file mode 100644 index 0000000..85d201a --- /dev/null +++ b/NvCloth/src/ClothImpl.h @@ -0,0 +1,1393 @@ +// 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-2017 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/Cloth.h" +#include "NvCloth/Fabric.h" +#include <foundation/PxVec4.h> +#include <foundation/PxVec3.h> +#include <PsMathUtils.h> +#include <cmath> + +namespace nv +{ +namespace cloth +{ + +// SwCloth or CuCloth aggregate implementing the Cloth interface +// Member specializations are implemented in Sw/CuCloth.cpp +template <typename T> +class ClothImpl : public Cloth +{ + ClothImpl(const ClothImpl&); + + public: + ClothImpl& operator = (const ClothImpl&); + + typedef T ClothType; + typedef typename ClothType::FactoryType FactoryType; + typedef typename ClothType::FabricType FabricType; + typedef typename ClothType::ContextLockType ContextLockType; + + ClothImpl(Factory&, Fabric&, Range<const physx::PxVec4>); + ClothImpl(Factory&, const ClothImpl&); + + virtual Cloth* clone(Factory& factory) const; + + virtual Fabric& getFabric() const; + virtual Factory& getFactory() const; + + virtual uint32_t getNumParticles() const; + virtual void lockParticles() const; + virtual void unlockParticles() const; + virtual MappedRange<physx::PxVec4> getCurrentParticles(); + virtual MappedRange<const physx::PxVec4> getCurrentParticles() const; + virtual MappedRange<physx::PxVec4> getPreviousParticles(); + virtual MappedRange<const physx::PxVec4> getPreviousParticles() const; + virtual GpuParticles getGpuParticles(); + + virtual void setTranslation(const physx::PxVec3& trans); + virtual void setRotation(const physx::PxQuat& rot); + + virtual const physx::PxVec3& getTranslation() const; + virtual const physx::PxQuat& getRotation() const; + + virtual void clearInertia(); + + virtual void teleport(const physx::PxVec3& delta); + + virtual float getPreviousIterationDt() const; + virtual void setGravity(const physx::PxVec3& gravity); + virtual physx::PxVec3 getGravity() const; + virtual void setDamping(const physx::PxVec3& damping); + virtual physx::PxVec3 getDamping() const; + virtual void setLinearDrag(const physx::PxVec3& drag); + virtual physx::PxVec3 getLinearDrag() const; + virtual void setAngularDrag(const physx::PxVec3& drag); + virtual physx::PxVec3 getAngularDrag() const; + virtual void setLinearInertia(const physx::PxVec3& inertia); + virtual physx::PxVec3 getLinearInertia() const; + virtual void setAngularInertia(const physx::PxVec3& inertia); + virtual physx::PxVec3 getAngularInertia() const; + virtual void setCentrifugalInertia(const physx::PxVec3& inertia); + virtual physx::PxVec3 getCentrifugalInertia() const; + + virtual void setSolverFrequency(float frequency); + virtual float getSolverFrequency() const; + + virtual void setStiffnessFrequency(float frequency); + virtual float getStiffnessFrequency() const; + + virtual void setAcceleationFilterWidth(uint32_t); + virtual uint32_t getAccelerationFilterWidth() const; + + virtual void setPhaseConfig(Range<const PhaseConfig> configs); + + virtual void setSpheres(Range<const physx::PxVec4>, uint32_t first, uint32_t last); + virtual uint32_t getNumSpheres() const; + + virtual void setCapsules(Range<const uint32_t>, uint32_t first, uint32_t last); + virtual uint32_t getNumCapsules() const; + + virtual void setPlanes(Range<const physx::PxVec4>, uint32_t first, uint32_t last); + virtual uint32_t getNumPlanes() const; + + virtual void setConvexes(Range<const uint32_t>, uint32_t first, uint32_t last); + virtual uint32_t getNumConvexes() const; + + virtual void setTriangles(Range<const physx::PxVec3>, uint32_t first, uint32_t last); + virtual void setTriangles(Range<const physx::PxVec3>, Range<const physx::PxVec3>, uint32_t first); + virtual uint32_t getNumTriangles() const; + + virtual bool isContinuousCollisionEnabled() const; + virtual void enableContinuousCollision(bool); + + virtual float getCollisionMassScale() const; + virtual void setCollisionMassScale(float); + virtual void setFriction(float friction); + virtual float getFriction() const; + + virtual void setVirtualParticles(Range<const uint32_t[4]>, Range<const physx::PxVec3>); + virtual uint32_t getNumVirtualParticles() const; + virtual uint32_t getNumVirtualParticleWeights() const; + + virtual void setTetherConstraintScale(float scale); + virtual float getTetherConstraintScale() const; + virtual void setTetherConstraintStiffness(float stiffness); + virtual float getTetherConstraintStiffness() const; + + virtual Range<physx::PxVec4> getMotionConstraints(); + virtual void clearMotionConstraints(); + virtual uint32_t getNumMotionConstraints() const; + virtual void setMotionConstraintScaleBias(float scale, float bias); + virtual float getMotionConstraintScale() const; + virtual float getMotionConstraintBias() const; + virtual void setMotionConstraintStiffness(float stiffness); + virtual float getMotionConstraintStiffness() const; + + virtual Range<physx::PxVec4> getSeparationConstraints(); + virtual void clearSeparationConstraints(); + virtual uint32_t getNumSeparationConstraints() const; + + virtual void clearInterpolation(); + + virtual Range<physx::PxVec4> getParticleAccelerations(); + virtual void clearParticleAccelerations(); + virtual uint32_t getNumParticleAccelerations() const; + + virtual void setWindVelocity(physx::PxVec3); + virtual physx::PxVec3 getWindVelocity() const; + virtual void setDragCoefficient(float); + virtual float getDragCoefficient() const; + virtual void setLiftCoefficient(float); + virtual float getLiftCoefficient() const; + + virtual void setSelfCollisionDistance(float); + virtual float getSelfCollisionDistance() const; + virtual void setSelfCollisionStiffness(float); + virtual float getSelfCollisionStiffness() const; + + virtual void setSelfCollisionIndices(Range<const uint32_t>); + virtual uint32_t getNumSelfCollisionIndices() const; + + virtual void setRestPositions(Range<const physx::PxVec4>); + virtual uint32_t getNumRestPositions() const; + + virtual const physx::PxVec3& getBoundingBoxCenter() const; + virtual const physx::PxVec3& getBoundingBoxScale() const; + + virtual void setSleepThreshold(float); + virtual float getSleepThreshold() const; + virtual void setSleepTestInterval(uint32_t); + virtual uint32_t getSleepTestInterval() const; + virtual void setSleepAfterCount(uint32_t); + virtual uint32_t getSleepAfterCount() const; + virtual uint32_t getSleepPassCount() const; + virtual bool isAsleep() const; + virtual void putToSleep(); + virtual void wakeUp(); + + virtual void setUserData(void*); + virtual void* getUserData() const; + + // helper function + template <typename U> + MappedRange<U> getMappedParticles(U* data) const; + + ClothType mCloth; +}; + +class SwCloth; +typedef ClothImpl<SwCloth> SwClothImpl; + +class CuCloth; +typedef ClothImpl<CuCloth> CuClothImpl; + +class DxCloth; +typedef ClothImpl<DxCloth> DxClothImpl; + +template <typename T> +ClothImpl<T>::ClothImpl(Factory& factory, Fabric& fabric, Range<const physx::PxVec4> particles) +: mCloth(static_cast<FactoryType&>(factory), static_cast<FabricType&>(fabric), particles) +{ + // fabric and cloth need to be created by the same factory + NV_CLOTH_ASSERT(&fabric.getFactory() == &factory); +} + +template <typename T> +ClothImpl<T>::ClothImpl(Factory& factory, const ClothImpl& impl) +: mCloth(static_cast<FactoryType&>(factory), impl.mCloth) +{ +} + +template <typename T> +inline Fabric& ClothImpl<T>::getFabric() const +{ + return mCloth.mFabric; +} + +template <typename T> +inline Factory& ClothImpl<T>::getFactory() const +{ + return mCloth.mFactory; +} + +template <typename T> +inline void ClothImpl<T>::setTranslation(const physx::PxVec3& trans) +{ + physx::PxVec3 t = reinterpret_cast<const physx::PxVec3&>(trans); + if (t == mCloth.mTargetMotion.p) + return; + + mCloth.mTargetMotion.p = t; + mCloth.wakeUp(); +} + +template <typename T> +inline void ClothImpl<T>::setRotation(const physx::PxQuat& q) +{ + if ((q - mCloth.mTargetMotion.q).magnitudeSquared() == 0.0f) + return; + + mCloth.mTargetMotion.q = q; + mCloth.wakeUp(); +} + +template <typename T> +inline const physx::PxVec3& ClothImpl<T>::getTranslation() const +{ + return mCloth.mTargetMotion.p; +} + +template <typename T> +inline const physx::PxQuat& ClothImpl<T>::getRotation() const +{ + return mCloth.mTargetMotion.q; +} + +template <typename T> +inline void ClothImpl<T>::clearInertia() +{ + mCloth.mCurrentMotion = mCloth.mTargetMotion; + mCloth.mLinearVelocity = physx::PxVec3(0.0); + mCloth.mAngularVelocity = physx::PxVec3(0.0); + + mCloth.wakeUp(); +} + +// Fixed 4505:local function has been removed +template <typename T> +inline void ClothImpl<T>::teleport(const physx::PxVec3& delta) +{ + mCloth.mCurrentMotion.p += delta; + mCloth.mTargetMotion.p += delta; +} + +template <typename T> +inline float ClothImpl<T>::getPreviousIterationDt() const +{ + return mCloth.mPrevIterDt; +} + +template <typename T> +inline void ClothImpl<T>::setGravity(const physx::PxVec3& gravity) +{ + physx::PxVec3 value = gravity; + if (value == mCloth.mGravity) + return; + + mCloth.mGravity = value; + mCloth.wakeUp(); +} + +template <typename T> +inline physx::PxVec3 ClothImpl<T>::getGravity() const +{ + return mCloth.mGravity; +} + +inline float safeLog2(float x) +{ + return x ? physx::shdfnd::log2(x) : -FLT_MAX_EXP; +} + +inline physx::PxVec3 safeLog2(const physx::PxVec3& v) +{ + return physx::PxVec3( safeLog2(v.x), safeLog2(v.y), safeLog2(v.z) ); +} + +inline float safeExp2(float x) +{ + if (x <= -FLT_MAX_EXP) + return 0.0f; + else + return physx::shdfnd::exp2(x); +} + +inline physx::PxVec3 safeExp2(const physx::PxVec3& v) +{ + return physx::PxVec3( safeExp2(v.x), safeExp2(v.y), safeExp2(v.z) ); +} + +template <typename T> +inline void ClothImpl<T>::setDamping(const physx::PxVec3& damping) +{ + physx::PxVec3 value = safeLog2(physx::PxVec3(1.f) - damping); + if (value == mCloth.mLogDamping) + return; + + mCloth.mLogDamping = value; + mCloth.wakeUp(); +} + +template <typename T> +inline physx::PxVec3 ClothImpl<T>::getDamping() const +{ + return physx::PxVec3(1.f) - safeExp2(mCloth.mLogDamping); +} + +template <typename T> +inline void ClothImpl<T>::setLinearDrag(const physx::PxVec3& drag) +{ + physx::PxVec3 value = safeLog2(physx::PxVec3(1.f) - drag); + if (value == mCloth.mLinearLogDrag) + return; + + mCloth.mLinearLogDrag = value; + mCloth.wakeUp(); +} + +template <typename T> +inline physx::PxVec3 ClothImpl<T>::getLinearDrag() const +{ + return physx::PxVec3(1.f) - safeExp2(mCloth.mLinearLogDrag); +} + +template <typename T> +inline void ClothImpl<T>::setAngularDrag(const physx::PxVec3& drag) +{ + physx::PxVec3 value = safeLog2(physx::PxVec3(1.f) - drag); + if (value == mCloth.mAngularLogDrag) + return; + + mCloth.mAngularLogDrag = value; + mCloth.wakeUp(); +} + +template <typename T> +inline physx::PxVec3 ClothImpl<T>::getAngularDrag() const +{ + return physx::PxVec3(1.f) - safeExp2(mCloth.mAngularLogDrag); +} + +template <typename T> +inline void ClothImpl<T>::setLinearInertia(const physx::PxVec3& inertia) +{ + physx::PxVec3 value = inertia; + if (value == mCloth.mLinearInertia) + return; + + mCloth.mLinearInertia = value; + mCloth.wakeUp(); +} + +template <typename T> +inline physx::PxVec3 ClothImpl<T>::getLinearInertia() const +{ + return mCloth.mLinearInertia; +} + +template <typename T> +inline void ClothImpl<T>::setAngularInertia(const physx::PxVec3& inertia) +{ + physx::PxVec3 value = inertia; + if (value == mCloth.mAngularInertia) + return; + + mCloth.mAngularInertia = value; + mCloth.wakeUp(); +} + +template <typename T> +inline physx::PxVec3 ClothImpl<T>::getAngularInertia() const +{ + return mCloth.mAngularInertia; +} + +template <typename T> +inline void ClothImpl<T>::setCentrifugalInertia(const physx::PxVec3& inertia) +{ + physx::PxVec3 value = inertia; + if (value == mCloth.mCentrifugalInertia) + return; + + mCloth.mCentrifugalInertia = value; + mCloth.wakeUp(); +} + +template <typename T> +inline physx::PxVec3 ClothImpl<T>::getCentrifugalInertia() const +{ + return mCloth.mCentrifugalInertia; +} + +template <typename T> +inline void ClothImpl<T>::setSolverFrequency(float frequency) +{ + if (frequency == mCloth.mSolverFrequency) + return; + + mCloth.mSolverFrequency = frequency; + mCloth.mClothCostDirty = true; + mCloth.mIterDtAvg.reset(); + mCloth.wakeUp(); +} + +template <typename T> +inline float ClothImpl<T>::getSolverFrequency() const +{ + return mCloth.mSolverFrequency; +} + +template <typename T> +inline void ClothImpl<T>::setStiffnessFrequency(float frequency) +{ + if (frequency == mCloth.mStiffnessFrequency) + return; + + mCloth.mStiffnessFrequency = frequency; + mCloth.wakeUp(); +} + +template <typename T> +inline float ClothImpl<T>::getStiffnessFrequency() const +{ + return mCloth.mStiffnessFrequency; +} + +template <typename T> +inline void ClothImpl<T>::setAcceleationFilterWidth(uint32_t n) +{ + mCloth.mIterDtAvg.resize(n); +} + +template <typename T> +inline uint32_t ClothImpl<T>::getAccelerationFilterWidth() const +{ + return mCloth.mIterDtAvg.size(); +} + +// move a subarray +template <typename Iter> +void move(Iter it, uint32_t first, uint32_t last, uint32_t result) +{ + if (result > first) + { + result += last - first; + while (first < last) + it[--result] = it[--last]; + } + else + { + while (first < last) + it[result++] = it[first++]; + } +} + +// update capsule index +inline bool updateIndex(uint32_t& index, uint32_t first, int32_t delta) +{ + return index >= first && int32_t(index += delta) < int32_t(first); +} + +template <typename T> +inline void ClothImpl<T>::setSpheres(Range<const physx::PxVec4> spheres, uint32_t first, uint32_t last) +{ + uint32_t oldSize = uint32_t(mCloth.mStartCollisionSpheres.size()); + uint32_t newSize = uint32_t(spheres.size()) + oldSize - last + first; + + NV_CLOTH_ASSERT(newSize <= 32); + NV_CLOTH_ASSERT(first <= oldSize); + NV_CLOTH_ASSERT(last <= oldSize); + +#if PX_DEBUG + for (const physx::PxVec4* it = spheres.begin(); it < spheres.end(); ++it) + NV_CLOTH_ASSERT(it->w >= 0.0f); +#endif + + if (!oldSize && !newSize) + return; + + if (!oldSize) + { + ContextLockType contextLock(mCloth.mFactory); + mCloth.mStartCollisionSpheres.assign(spheres.begin(), spheres.end()); + mCloth.notifyChanged(); + } + else + { + if (std::max(oldSize, newSize) > + std::min(mCloth.mStartCollisionSpheres.capacity(), mCloth.mTargetCollisionSpheres.capacity())) + { + ContextLockType contextLock(mCloth.mFactory); + mCloth.mStartCollisionSpheres.reserve(newSize); + mCloth.mTargetCollisionSpheres.reserve(std::max(oldSize, newSize)); + } + + typename T::MappedVec4fVectorType start = mCloth.mStartCollisionSpheres; + typename T::MappedVec4fVectorType target = mCloth.mTargetCollisionSpheres; + + // fill target from start + for (uint32_t i = uint32_t(target.size()); i < oldSize; ++i) + target.pushBack(start[i]); + + // resize to larger of oldSize and newSize + start.resize(std::max(oldSize, newSize), physx::PxVec4(0.0f)); + target.resize(std::max(oldSize, newSize), physx::PxVec4(0.0f)); + + if (int32_t delta = int32_t(newSize - oldSize)) + { + // move past-range elements to new place + move(start.begin(), last, oldSize, last + delta); + move(target.begin(), last, oldSize, last + delta); + + // fill new elements from spheres + for (uint32_t i = last; i < last + delta; ++i) + start[i] = spheres[i - first]; + + // adjust capsule indices + typename T::MappedIndexVectorType indices = mCloth.mCapsuleIndices; + Vector<IndexPair>::Type::Iterator cIt, cEnd = indices.end(); + for (cIt = indices.begin(); cIt != cEnd;) + { + bool removed = false; + removed |= updateIndex(cIt->first, last + std::min(0, delta), int32_t(delta)); + removed |= updateIndex(cIt->second, last + std::min(0, delta), int32_t(delta)); + if (!removed) + ++cIt; + else + { + indices.replaceWithLast(cIt); + cEnd = indices.end(); + } + } + + start.resize(newSize); + target.resize(newSize); + + mCloth.notifyChanged(); + } + + // fill target elements with spheres + for (uint32_t i = 0; i < spheres.size(); ++i) + target[first + i] = spheres[i]; + } + + mCloth.wakeUp(); +} + +template <typename T> +inline uint32_t ClothImpl<T>::getNumSpheres() const +{ + return uint32_t(mCloth.mStartCollisionSpheres.size()); +} + +// Fixed 4505:local function has been removed +template <typename T> +inline void ClothImpl<T>::setCapsules(Range<const uint32_t> capsules, uint32_t first, uint32_t last) +{ + uint32_t oldSize = uint32_t(mCloth.mCapsuleIndices.size()); + uint32_t newSize = uint32_t(capsules.size() / 2) + oldSize - last + first; + + NV_CLOTH_ASSERT(newSize <= 32); + NV_CLOTH_ASSERT(first <= oldSize); + NV_CLOTH_ASSERT(last <= oldSize); + + const IndexPair* srcIndices = reinterpret_cast<const IndexPair*>(capsules.begin()); + + if (mCloth.mCapsuleIndices.capacity() < newSize) + { + ContextLockType contextLock(mCloth.mFactory); + mCloth.mCapsuleIndices.reserve(newSize); + } + + // resize to larger of oldSize and newSize + mCloth.mCapsuleIndices.resize(std::max(oldSize, newSize)); + + typename T::MappedIndexVectorType dstIndices = mCloth.mCapsuleIndices; + + if (uint32_t delta = newSize - oldSize) + { + // move past-range elements to new place + move(dstIndices.begin(), last, oldSize, last + delta); + + // fill new elements from capsules + for (uint32_t i = last; i < last + delta; ++i) + dstIndices[i] = srcIndices[i - first]; + + dstIndices.resize(newSize); + mCloth.notifyChanged(); + } + + // fill existing elements from capsules + for (uint32_t i = first; i < last; ++i) + dstIndices[i] = srcIndices[i - first]; + + mCloth.wakeUp(); +} + +template <typename T> +inline uint32_t ClothImpl<T>::getNumCapsules() const +{ + return uint32_t(mCloth.mCapsuleIndices.size()); +} + +template <typename T> +inline void ClothImpl<T>::setPlanes(Range<const physx::PxVec4> planes, uint32_t first, uint32_t last) +{ + uint32_t oldSize = uint32_t(mCloth.mStartCollisionPlanes.size()); + uint32_t newSize = uint32_t(planes.size()) + oldSize - last + first; + + NV_CLOTH_ASSERT(newSize <= 32); + NV_CLOTH_ASSERT(first <= oldSize); + NV_CLOTH_ASSERT(last <= oldSize); +#if PX_DEBUG || PX_CHECKED + int logCount = 0; + for (int i = 0; i<static_cast<int>(planes.size()); i++) + { + if (fabsf(planes[i].getXYZ().magnitudeSquared() - 1.0f) > 0.01f) + { + if (logCount == 0) + NV_CLOTH_LOG_INVALID_PARAMETER("The plane normals passed to Cloth::setPlanes are not normalized. First error encounterd at plane %d (%f, %f, %f, %f)", + i, static_cast<double>(planes[i].x), static_cast<double>(planes[i].y), static_cast<double>(planes[i].z), static_cast<double>(planes[i].w)); + logCount++; + } + } + if (logCount>1) + { + NV_CLOTH_LOG_INVALID_PARAMETER("This error was encountered %d more times.", logCount-1); + } +#endif + + if (!oldSize && !newSize) + return; + + if (!oldSize) + { + ContextLockType contextLock(mCloth.mFactory); + mCloth.mStartCollisionPlanes.assign(planes.begin(), planes.end()); + mCloth.notifyChanged(); + } + else + { + if (std::max(oldSize, newSize) > + std::min(mCloth.mStartCollisionPlanes.capacity(), mCloth.mTargetCollisionPlanes.capacity())) + { + ContextLockType contextLock(mCloth.mFactory); + mCloth.mStartCollisionPlanes.reserve(newSize); + mCloth.mTargetCollisionPlanes.reserve(std::max(oldSize, newSize)); + } + + typename T::MappedVec4fVectorType start = mCloth.mStartCollisionPlanes; + typename T::MappedVec4fVectorType target = mCloth.mTargetCollisionPlanes; + + // fill target from start + for (uint32_t i = target.size(); i < oldSize; ++i) + target.pushBack(start[i]); + + // resize to larger of oldSize and newSize + start.resize(std::max(oldSize, newSize), physx::PxVec4(0.0f)); + target.resize(std::max(oldSize, newSize), physx::PxVec4(0.0f)); + + if (int32_t delta = int32_t(newSize - oldSize)) + { + // move past-range elements to new place + move(start.begin(), last, oldSize, last + delta); + move(target.begin(), last, oldSize, last + delta); + + // fill new elements from planes + for (uint32_t i = last; i < last + delta; ++i) + start[i] = planes[i - first]; + + // adjust convex indices + uint32_t mask = (uint32_t(1) << (last + std::min(delta, 0))) - 1; + typename T::MappedMaskVectorType masks = mCloth.mConvexMasks; + Vector<uint32_t>::Type::Iterator cIt, cEnd = masks.end(); + for (cIt = masks.begin(); cIt != cEnd;) + { + uint32_t convex = (*cIt & mask); + if (delta < 0) + convex |= *cIt >> -delta & ~mask; + else + convex |= (*cIt & ~mask) << delta; + if (convex) + *cIt++ = convex; + else + { + masks.replaceWithLast(cIt); + cEnd = masks.end(); + } + } + + start.resize(newSize); + target.resize(newSize); + + mCloth.notifyChanged(); + } + + // fill target elements with planes + for (uint32_t i = 0; i < planes.size(); ++i) + target[first + i] = planes[i]; + } + + mCloth.wakeUp(); +} + +template <typename T> +inline uint32_t ClothImpl<T>::getNumPlanes() const +{ + return uint32_t(mCloth.mStartCollisionPlanes.size()); +} + +template <typename T> +inline void ClothImpl<T>::setConvexes(Range<const uint32_t> convexMasks, uint32_t first, uint32_t last) +{ + uint32_t oldSize = uint32_t(mCloth.mConvexMasks.size()); + uint32_t newSize = uint32_t(convexMasks.size()) + oldSize - last + first; + + NV_CLOTH_ASSERT(newSize <= 32); + NV_CLOTH_ASSERT(first <= oldSize); + NV_CLOTH_ASSERT(last <= oldSize); +#if PX_DEBUG || PX_CHECKED + for (int i = 0; i<static_cast<int>(convexMasks.size()); i++) + { + if (convexMasks[i] == 0) + { + NV_CLOTH_LOG_INVALID_PARAMETER("Cloth::setConvexes expects bit masks of the form (1<<planeIndex1)|(1<<planeIndex2). 0 is not a valid mask/plane index. Error found in location %d", i); + continue; + } + } +#endif + + if (mCloth.mConvexMasks.capacity() < newSize) + { + ContextLockType contextLock(mCloth.mFactory); + mCloth.mConvexMasks.reserve(newSize); + } + + // resize to larger of oldSize and newSize + mCloth.mConvexMasks.resize(std::max(oldSize, newSize)); + + if (uint32_t delta = newSize - oldSize) + { + typename T::MappedMaskVectorType masks = mCloth.mConvexMasks; + + // move past-range elements to new place + move(masks.begin(), last, oldSize, last + delta); + + // fill new elements from capsules + for (uint32_t i = last; i < last + delta; ++i) + masks[i] = convexMasks[i - first]; + + masks.resize(newSize); + mCloth.notifyChanged(); + } + + mCloth.wakeUp(); +} + +template <typename T> +inline uint32_t ClothImpl<T>::getNumConvexes() const +{ + return uint32_t(mCloth.mConvexMasks.size()); +} + +template <typename T> +inline void ClothImpl<T>::setTriangles(Range<const physx::PxVec3> triangles, uint32_t first, uint32_t last) +{ + // convert from triangle to vertex count + first *= 3; + last *= 3; + + triangles = mCloth.clampTriangleCount(triangles, last - first); + NV_CLOTH_ASSERT(0 == triangles.size() % 3); + + uint32_t oldSize = uint32_t(mCloth.mStartCollisionTriangles.size()); + uint32_t newSize = uint32_t(triangles.size()) + oldSize - last + first; + + NV_CLOTH_ASSERT(first <= oldSize); + NV_CLOTH_ASSERT(last <= oldSize); + + if (!oldSize && !newSize) + return; + + if (!oldSize) + { + ContextLockType contextLock(mCloth.mFactory); + mCloth.mStartCollisionTriangles.assign(triangles.begin(), triangles.end()); + mCloth.notifyChanged(); + } + else + { + if (std::max(oldSize, newSize) > + std::min(mCloth.mStartCollisionTriangles.capacity(), mCloth.mTargetCollisionTriangles.capacity())) + { + ContextLockType contextLock(mCloth.mFactory); + mCloth.mStartCollisionTriangles.reserve(newSize); + mCloth.mTargetCollisionTriangles.reserve(std::max(oldSize, newSize)); + } + + typename T::MappedVec3fVectorType start = mCloth.mStartCollisionTriangles; + typename T::MappedVec3fVectorType target = mCloth.mTargetCollisionTriangles; + + // fill target from start + for (uint32_t i = target.size(); i < oldSize; ++i) + target.pushBack(start[i]); + + // resize to larger of oldSize and newSize + start.resize(std::max(oldSize, newSize), physx::PxVec3(0.0f)); + target.resize(std::max(oldSize, newSize), physx::PxVec3(0.0f)); + + if (int32_t delta = int32_t(newSize - oldSize)) + { + // move past-range elements to new place + move(start.begin(), last, oldSize, last + delta); + move(target.begin(), last, oldSize, last + delta); + + // fill new elements from planes + for (uint32_t i = last; i < last + delta; ++i) + start[i] = triangles[i - first]; + + start.resize(newSize); + target.resize(newSize); + + mCloth.notifyChanged(); + } + ////////////////////// + + // if (std::max(oldSize, newSize) > + // std::min(mCloth.mStartCollisionTriangles.capacity(), mCloth.mTargetCollisionTriangles.capacity())) + // { + // ContextLockType contextLock(mCloth.mFactory); + // mCloth.mStartCollisionTriangles.reserve(newSize); + // mCloth.mTargetCollisionTriangles.reserve(std::max(oldSize, newSize)); + // } + // + // // fill target from start + // for (uint32_t i = mCloth.mTargetCollisionTriangles.size(); i < oldSize; ++i) + // mCloth.mTargetCollisionTriangles.pushBack(mCloth.mStartCollisionTriangles[i]); + // + // // resize to larger of oldSize and newSize + // mCloth.mStartCollisionTriangles.resize(std::max(oldSize, newSize)); + // mCloth.mTargetCollisionTriangles.resize(std::max(oldSize, newSize)); + // + // if (uint32_t delta = newSize - oldSize) + // { + // // move past-range elements to new place + // move(mCloth.mStartCollisionTriangles.begin(), last, oldSize, last + delta); + // move(mCloth.mTargetCollisionTriangles.begin(), last, oldSize, last + delta); + // + // // fill new elements from triangles + // for (uint32_t i = last; i < last + delta; ++i) + // mCloth.mStartCollisionTriangles[i] = triangles[i - first]; + // + // mCloth.mStartCollisionTriangles.resize(newSize); + // mCloth.mTargetCollisionTriangles.resize(newSize); + // + // mCloth.notifyChanged(); + // } + + // fill target elements with triangles + // for (uint32_t i = 0; i < triangles.size(); ++i) + // mCloth.mTargetCollisionTriangles[first + i] = triangles[i]; + + // fill target elements with planes + for (uint32_t i = 0; i < triangles.size(); ++i) + target[first + i] = triangles[i]; + } + + mCloth.wakeUp(); +} + +template <typename T> +inline void ClothImpl<T>::setTriangles(Range<const physx::PxVec3> startTriangles, Range<const physx::PxVec3> targetTriangles, + uint32_t first) +{ + NV_CLOTH_ASSERT(startTriangles.size() == targetTriangles.size()); + + // convert from triangle to vertex count + first *= 3; + + uint32_t last = uint32_t(mCloth.mStartCollisionTriangles.size()); + + startTriangles = mCloth.clampTriangleCount(startTriangles, last - first); + targetTriangles = mCloth.clampTriangleCount(targetTriangles, last - first); + + uint32_t oldSize = uint32_t(mCloth.mStartCollisionTriangles.size()); + uint32_t newSize = uint32_t(startTriangles.size()) + oldSize - last + first; + + NV_CLOTH_ASSERT(first <= oldSize); + NV_CLOTH_ASSERT(last == oldSize); // this path only supports replacing the tail + + if (!oldSize && !newSize) + return; + + if (newSize > std::min(mCloth.mStartCollisionTriangles.capacity(), mCloth.mTargetCollisionTriangles.capacity())) + { + ContextLockType contextLock(mCloth.mFactory); + // mCloth.mStartCollisionTriangles.reserve(newSize); + // mCloth.mTargetCollisionTriangles.reserve(newSize); + + + mCloth.mStartCollisionTriangles.assign(startTriangles.begin(), startTriangles.end()); + mCloth.mTargetCollisionTriangles.assign(targetTriangles.begin(), targetTriangles.end()); + mCloth.notifyChanged(); + } + else + { + uint32_t retainSize = oldSize - last + first; + mCloth.mStartCollisionTriangles.resize(retainSize); + mCloth.mTargetCollisionTriangles.resize(retainSize); + + mCloth.mStartCollisionTriangles.assign(startTriangles.begin(), startTriangles.end()); + mCloth.mTargetCollisionTriangles.assign(targetTriangles.begin(), targetTriangles.end()); + + // for (uint32_t i = 0, n = startTriangles.size(); i < n; ++i) + // { + // mCloth.mStartCollisionTriangles.pushBack(startTriangles[i]); + // mCloth.mTargetCollisionTriangles.pushBack(targetTriangles[i]); + // } + + if (newSize - oldSize) + mCloth.notifyChanged(); + } + + mCloth.wakeUp(); +} + +template <typename T> +inline uint32_t ClothImpl<T>::getNumTriangles() const +{ + return uint32_t(mCloth.mStartCollisionTriangles.size()) / 3; +} + +template <typename T> +inline bool ClothImpl<T>::isContinuousCollisionEnabled() const +{ + return mCloth.mEnableContinuousCollision; +} + +template <typename T> +inline void ClothImpl<T>::enableContinuousCollision(bool enable) +{ + if (enable == mCloth.mEnableContinuousCollision) + return; + + mCloth.mEnableContinuousCollision = enable; + mCloth.notifyChanged(); + mCloth.wakeUp(); +} + +template <typename T> +inline float ClothImpl<T>::getCollisionMassScale() const +{ + return mCloth.mCollisionMassScale; +} + +template <typename T> +inline void ClothImpl<T>::setCollisionMassScale(float scale) +{ + if (scale == mCloth.mCollisionMassScale) + return; + + mCloth.mCollisionMassScale = scale; + mCloth.notifyChanged(); + mCloth.wakeUp(); +} + +template <typename T> +inline void ClothImpl<T>::setFriction(float friction) +{ + mCloth.mFriction = friction; + mCloth.wakeUp(); +} + +template <typename T> +inline float ClothImpl<T>::getFriction() const +{ + return mCloth.mFriction; +} + +template <typename T> +inline uint32_t ClothImpl<T>::getNumVirtualParticleWeights() const +{ + return uint32_t(mCloth.mVirtualParticleWeights.size()); +} + +template <typename T> +inline void ClothImpl<T>::setTetherConstraintScale(float scale) +{ + if (scale == mCloth.mTetherConstraintScale) + return; + + mCloth.mTetherConstraintScale = scale; + mCloth.notifyChanged(); + mCloth.wakeUp(); +} + +template <typename T> +inline float ClothImpl<T>::getTetherConstraintScale() const +{ + return mCloth.mTetherConstraintScale; +} + +template <typename T> +inline void ClothImpl<T>::setTetherConstraintStiffness(float stiffness) +{ + float value = safeLog2(1 - stiffness); + if (value == mCloth.mTetherConstraintLogStiffness) + return; + + mCloth.mTetherConstraintLogStiffness = value; + mCloth.notifyChanged(); + mCloth.wakeUp(); +} + +template <typename T> +inline float ClothImpl<T>::getTetherConstraintStiffness() const +{ + return 1.f - safeExp2(mCloth.mTetherConstraintLogStiffness); +} + +template <typename T> +inline Range<physx::PxVec4> ClothImpl<T>::getMotionConstraints() +{ + mCloth.wakeUp(); + return mCloth.push(mCloth.mMotionConstraints); +} + +template <typename T> +inline void ClothImpl<T>::clearMotionConstraints() +{ + mCloth.clear(mCloth.mMotionConstraints); + mCloth.wakeUp(); +} + +template <typename T> +inline uint32_t ClothImpl<T>::getNumMotionConstraints() const +{ + return uint32_t(mCloth.mMotionConstraints.mStart.size()); +} + +template <typename T> +inline void ClothImpl<T>::setMotionConstraintScaleBias(float scale, float bias) +{ + if (scale == mCloth.mMotionConstraintScale && bias == mCloth.mMotionConstraintBias) + return; + + mCloth.mMotionConstraintScale = scale; + mCloth.mMotionConstraintBias = bias; + mCloth.notifyChanged(); + mCloth.wakeUp(); +} + +template <typename T> +inline float ClothImpl<T>::getMotionConstraintScale() const +{ + return mCloth.mMotionConstraintScale; +} + +template <typename T> +inline float ClothImpl<T>::getMotionConstraintBias() const +{ + return mCloth.mMotionConstraintBias; +} + +template <typename T> +inline void ClothImpl<T>::setMotionConstraintStiffness(float stiffness) +{ + float value = safeLog2(1 - stiffness); + if (value == mCloth.mMotionConstraintLogStiffness) + return; + + mCloth.mMotionConstraintLogStiffness = value; + mCloth.notifyChanged(); + mCloth.wakeUp(); +} + +template <typename T> +inline float ClothImpl<T>::getMotionConstraintStiffness() const +{ + return 1.f - safeExp2(mCloth.mMotionConstraintLogStiffness); +} + +template <typename T> +inline Range<physx::PxVec4> ClothImpl<T>::getSeparationConstraints() +{ + mCloth.wakeUp(); + return mCloth.push(mCloth.mSeparationConstraints); +} + +template <typename T> +inline void ClothImpl<T>::clearSeparationConstraints() +{ + mCloth.clear(mCloth.mSeparationConstraints); + mCloth.wakeUp(); +} + +template <typename T> +inline void ClothImpl<T>::clearInterpolation() +{ + if (!mCloth.mTargetCollisionSpheres.empty()) + { + ContextLockType contextLock(mCloth.mFactory); + physx::shdfnd::swap(mCloth.mStartCollisionSpheres, mCloth.mTargetCollisionSpheres); + mCloth.mTargetCollisionSpheres.resize(0); + } + mCloth.mMotionConstraints.pop(); + mCloth.mSeparationConstraints.pop(); + mCloth.wakeUp(); +} + +template <typename T> +inline uint32_t ClothImpl<T>::getNumSeparationConstraints() const +{ + return uint32_t(mCloth.mSeparationConstraints.mStart.size()); +} + +template <typename T> +inline uint32_t ClothImpl<T>::getNumParticleAccelerations() const +{ + return uint32_t(mCloth.mParticleAccelerations.size()); +} + +template <typename T> +inline void ClothImpl<T>::setWindVelocity(physx::PxVec3 wind) +{ + if (wind == mCloth.mWind) + return; + + mCloth.mWind = wind; + mCloth.notifyChanged(); + mCloth.wakeUp(); +} + +template <typename T> +inline physx::PxVec3 ClothImpl<T>::getWindVelocity() const +{ + return mCloth.mWind; +} + +template <typename T> +inline void ClothImpl<T>::setDragCoefficient(float coefficient) +{ + NV_CLOTH_ASSERT(coefficient < 1.f); + + float value = safeLog2(1.f - coefficient); + if (value == mCloth.mDragLogCoefficient) + return; + + mCloth.mDragLogCoefficient = value; + mCloth.notifyChanged(); + mCloth.wakeUp(); +} + +template <typename T> +inline float ClothImpl<T>::getDragCoefficient() const +{ + return 1.f - safeExp2(mCloth.mDragLogCoefficient); +} + +template <typename T> +inline void ClothImpl<T>::setLiftCoefficient(float coefficient) +{ + NV_CLOTH_ASSERT(coefficient < 1.f); + + float value = safeLog2(1.f - coefficient); + if (value == mCloth.mLiftLogCoefficient) + return; + + mCloth.mLiftLogCoefficient = value; + mCloth.notifyChanged(); + mCloth.wakeUp(); +} + +template <typename T> +inline float ClothImpl<T>::getLiftCoefficient() const +{ + return 1.f - safeExp2(mCloth.mLiftLogCoefficient); +} + +template <typename T> +inline uint32_t ClothImpl<T>::getNumSelfCollisionIndices() const +{ + return uint32_t(mCloth.mSelfCollisionIndices.size()); +} + +// Fixed 4505:local function has been removed +template <typename T> +inline void ClothImpl<T>::setRestPositions(Range<const physx::PxVec4> restPositions) +{ + NV_CLOTH_ASSERT(restPositions.empty() || restPositions.size() == getNumParticles()); + ContextLockType contextLock(mCloth.mFactory); + mCloth.mRestPositions.assign(restPositions.begin(), restPositions.end()); + mCloth.wakeUp(); +} + +template <typename T> +inline uint32_t ClothImpl<T>::getNumRestPositions() const +{ + return uint32_t(mCloth.mRestPositions.size()); +} + +template <typename T> +inline void ClothImpl<T>::setSelfCollisionDistance(float distance) +{ + if (distance == mCloth.mSelfCollisionDistance) + return; + + mCloth.mSelfCollisionDistance = distance; + mCloth.notifyChanged(); + mCloth.wakeUp(); +} + +template <typename T> +inline float ClothImpl<T>::getSelfCollisionDistance() const +{ + return mCloth.mSelfCollisionDistance; +} + +template <typename T> +inline void ClothImpl<T>::setSelfCollisionStiffness(float stiffness) +{ + float value = safeLog2(1 - stiffness); + if (value == mCloth.mSelfCollisionLogStiffness) + return; + + mCloth.mSelfCollisionLogStiffness = value; + mCloth.notifyChanged(); + mCloth.wakeUp(); +} + +template <typename T> +inline float ClothImpl<T>::getSelfCollisionStiffness() const +{ + return 1.f - safeExp2(mCloth.mSelfCollisionLogStiffness); +} + +template <typename T> +inline const physx::PxVec3& ClothImpl<T>::getBoundingBoxCenter() const +{ + return mCloth.mParticleBoundsCenter; +} + +template <typename T> +inline const physx::PxVec3& ClothImpl<T>::getBoundingBoxScale() const +{ + return mCloth.mParticleBoundsHalfExtent; +} + +template <typename T> +inline void ClothImpl<T>::setSleepThreshold(float threshold) +{ + if (threshold == mCloth.mSleepThreshold) + return; + + mCloth.mSleepThreshold = threshold; + mCloth.notifyChanged(); + mCloth.wakeUp(); +} + +template <typename T> +inline float ClothImpl<T>::getSleepThreshold() const +{ + return mCloth.mSleepThreshold; +} + +template <typename T> +inline void ClothImpl<T>::setSleepTestInterval(uint32_t interval) +{ + if (interval == mCloth.mSleepTestInterval) + return; + + mCloth.mSleepTestInterval = interval; + mCloth.notifyChanged(); + mCloth.wakeUp(); +} + +template <typename T> +inline uint32_t ClothImpl<T>::getSleepTestInterval() const +{ + return mCloth.mSleepTestInterval; +} + +template <typename T> +inline void ClothImpl<T>::setSleepAfterCount(uint32_t afterCount) +{ + if (afterCount == mCloth.mSleepAfterCount) + return; + + mCloth.mSleepAfterCount = afterCount; + mCloth.notifyChanged(); + mCloth.wakeUp(); +} + +template <typename T> +inline uint32_t ClothImpl<T>::getSleepAfterCount() const +{ + return mCloth.mSleepAfterCount; +} + +template <typename T> +inline uint32_t ClothImpl<T>::getSleepPassCount() const +{ + return mCloth.mSleepPassCounter; +} + +template <typename T> +inline bool ClothImpl<T>::isAsleep() const +{ + return mCloth.isSleeping(); +} + +template <typename T> +inline void ClothImpl<T>::putToSleep() +{ + mCloth.mSleepPassCounter = mCloth.mSleepAfterCount; +} + +template <typename T> +inline void ClothImpl<T>::wakeUp() +{ + mCloth.wakeUp(); +} + +template <typename T> +inline void ClothImpl<T>::setUserData(void* data) +{ + mCloth.mUserData = data; +} + +template <typename T> +inline void* ClothImpl<T>::getUserData() const +{ + return mCloth.mUserData; +} + +template <typename T> +template <typename U> +inline MappedRange<U> ClothImpl<T>::getMappedParticles(U* data) const +{ + return MappedRange<U>(data, data + getNumParticles(), *this, &Cloth::lockParticles, &Cloth::unlockParticles); +} + + +} // namespace cloth +} // namespace nv |