// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // * Neither the name of NVIDIA CORPORATION nor the names of its // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Copyright (c) 2018 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 "Cloth.h" #include "Fabric.h" #include "Allocator.h" #include "PsMathUtils.h" namespace nvidia { namespace cloth { // SwCloth or CuCloth aggregate implementing the Cloth interface // Member specializations are implemented in Sw/CuCloth.cpp template class ClothImpl : public UserAllocated, 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); 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 getCurrentParticles(); virtual MappedRange getCurrentParticles() const; virtual MappedRange getPreviousParticles(); virtual MappedRange getPreviousParticles() const; virtual GpuParticles getGpuParticles(); virtual void setTranslation(const PxVec3& trans); virtual void setRotation(const PxQuat& rot); virtual const PxVec3& getTranslation() const; virtual const PxQuat& getRotation() const; virtual void clearInertia(); virtual void teleport(const PxVec3& delta); virtual float getPreviousIterationDt() const; virtual void setGravity(const PxVec3& gravity); virtual PxVec3 getGravity() const; virtual void setDamping(const PxVec3& damping); virtual PxVec3 getDamping() const; virtual void setLinearDrag(const PxVec3& drag); virtual PxVec3 getLinearDrag() const; virtual void setAngularDrag(const PxVec3& drag); virtual PxVec3 getAngularDrag() const; virtual void setLinearInertia(const PxVec3& inertia); virtual PxVec3 getLinearInertia() const; virtual void setAngularInertia(const PxVec3& inertia); virtual PxVec3 getAngularInertia() const; virtual void setCentrifugalInertia(const PxVec3& inertia); virtual 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 configs); virtual void setSpheres(Range, uint32_t first, uint32_t last); virtual uint32_t getNumSpheres() const; virtual void setCapsules(Range, uint32_t first, uint32_t last); virtual uint32_t getNumCapsules() const; virtual void setPlanes(Range, uint32_t first, uint32_t last); virtual uint32_t getNumPlanes() const; virtual void setConvexes(Range, uint32_t first, uint32_t last); virtual uint32_t getNumConvexes() const; virtual void setTriangles(Range, uint32_t first, uint32_t last); virtual void setTriangles(Range, Range, 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, Range); 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 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 getSeparationConstraints(); virtual void clearSeparationConstraints(); virtual uint32_t getNumSeparationConstraints() const; virtual void clearInterpolation(); virtual Range getParticleAccelerations(); virtual void clearParticleAccelerations(); virtual uint32_t getNumParticleAccelerations() const; virtual void setSelfCollisionDistance(float); virtual float getSelfCollisionDistance() const; virtual void setSelfCollisionStiffness(float); virtual float getSelfCollisionStiffness() const; virtual void setSelfCollisionIndices(Range); virtual uint32_t getNumSelfCollisionIndices() const; virtual void setRestPositions(Range); virtual uint32_t getNumRestPositions() const; virtual const PxVec3& getBoundingBoxCenter() const; virtual const 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 setHalfPrecisionOption(bool isAllowed); virtual bool getHalfPrecisionOption() const; #if APEX_UE4 virtual void simulate(float dt); #endif virtual void setUserData(void*); virtual void* getUserData() const; // helper function template MappedRange getMappedParticles(U* data) const; ClothType mCloth; }; class SwCloth; typedef ClothImpl SwClothImpl; class CuCloth; typedef ClothImpl CuClothImpl; class DxCloth; typedef ClothImpl DxClothImpl; template ClothImpl::ClothImpl(Factory& factory, Fabric& fabric, Range particles) : mCloth(static_cast(factory), static_cast(fabric), particles) { // fabric and cloth need to be created by the same factory PX_ASSERT(&fabric.getFactory() == &factory); } template ClothImpl::ClothImpl(Factory& factory, const ClothImpl& impl) : mCloth(static_cast(factory), impl.mCloth) { } template inline Fabric& ClothImpl::getFabric() const { return mCloth.mFabric; } template inline Factory& ClothImpl::getFactory() const { return mCloth.mFactory; } template inline void ClothImpl::setTranslation(const PxVec3& trans) { PxVec3 t = reinterpret_cast(trans); if(t == mCloth.mTargetMotion.p) return; mCloth.mTargetMotion.p = t; mCloth.wakeUp(); } template inline void ClothImpl::setRotation(const PxQuat& q) { if((q - mCloth.mTargetMotion.q).magnitudeSquared() == 0.0f) return; mCloth.mTargetMotion.q = q; mCloth.wakeUp(); } template inline const PxVec3& ClothImpl::getTranslation() const { return mCloth.mTargetMotion.p; } template inline const PxQuat& ClothImpl::getRotation() const { return mCloth.mTargetMotion.q; } template inline void ClothImpl::clearInertia() { mCloth.mCurrentMotion = mCloth.mTargetMotion; mCloth.mLinearVelocity = PxVec3(0.0f); mCloth.mAngularVelocity = PxVec3(0.0f); mCloth.wakeUp(); } // Fixed 4505:local function has been removed template inline void ClothImpl::teleport(const PxVec3& delta) { mCloth.mCurrentMotion.p += delta; mCloth.mTargetMotion.p += delta; } template inline float ClothImpl::getPreviousIterationDt() const { return mCloth.mPrevIterDt; } template inline void ClothImpl::setGravity(const PxVec3& gravity) { PxVec3 value = gravity; if(value == mCloth.mGravity) return; mCloth.mGravity = value; mCloth.wakeUp(); } template inline PxVec3 ClothImpl::getGravity() const { return mCloth.mGravity; } inline float safeLog2(float x) { return x ? physx::shdfnd::log2(x) : -FLT_MAX_EXP; } inline PxVec3 safeLog2(const PxVec3& v) { return 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 PxVec3 safeExp2(const PxVec3& v) { return PxVec3(safeExp2(v.x), safeExp2(v.y), safeExp2(v.z)); } template inline void ClothImpl::setDamping(const PxVec3& damping) { PxVec3 value = safeLog2(PxVec3(1.f) - damping); if(value == mCloth.mLogDamping) return; mCloth.mLogDamping = value; mCloth.wakeUp(); } template inline PxVec3 ClothImpl::getDamping() const { return PxVec3(1.f) - safeExp2(mCloth.mLogDamping); } template inline void ClothImpl::setLinearDrag(const PxVec3& drag) { PxVec3 value = safeLog2(PxVec3(1.f) - drag); if(value == mCloth.mLinearLogDrag) return; mCloth.mLinearLogDrag = value; mCloth.wakeUp(); } template inline PxVec3 ClothImpl::getLinearDrag() const { return PxVec3(1.f) - safeExp2(mCloth.mLinearLogDrag); } template inline void ClothImpl::setAngularDrag(const PxVec3& drag) { PxVec3 value = safeLog2(PxVec3(1.f) - drag); if(value == mCloth.mAngularLogDrag) return; mCloth.mAngularLogDrag = value; mCloth.wakeUp(); } template inline PxVec3 ClothImpl::getAngularDrag() const { return PxVec3(1.f) - safeExp2(mCloth.mAngularLogDrag); } template inline void ClothImpl::setLinearInertia(const PxVec3& inertia) { PxVec3 value = inertia; if(value == mCloth.mLinearInertia) return; mCloth.mLinearInertia = value; mCloth.wakeUp(); } template inline PxVec3 ClothImpl::getLinearInertia() const { return mCloth.mLinearInertia; } template inline void ClothImpl::setAngularInertia(const PxVec3& inertia) { PxVec3 value = inertia; if(value == mCloth.mAngularInertia) return; mCloth.mAngularInertia = value; mCloth.wakeUp(); } template inline PxVec3 ClothImpl::getAngularInertia() const { return mCloth.mAngularInertia; } template inline void ClothImpl::setCentrifugalInertia(const PxVec3& inertia) { PxVec3 value = inertia; if(value == mCloth.mCentrifugalInertia) return; mCloth.mCentrifugalInertia = value; mCloth.wakeUp(); } template inline PxVec3 ClothImpl::getCentrifugalInertia() const { return mCloth.mCentrifugalInertia; } template inline void ClothImpl::setSolverFrequency(float frequency) { if(frequency == mCloth.mSolverFrequency) return; mCloth.mSolverFrequency = frequency; mCloth.mClothCostDirty = true; mCloth.mIterDtAvg.reset(); mCloth.wakeUp(); } template inline float ClothImpl::getSolverFrequency() const { return mCloth.mSolverFrequency; } template inline void ClothImpl::setStiffnessFrequency(float frequency) { if(frequency == mCloth.mStiffnessFrequency) return; mCloth.mStiffnessFrequency = frequency; mCloth.wakeUp(); } template inline float ClothImpl::getStiffnessFrequency() const { return mCloth.mStiffnessFrequency; } template inline void ClothImpl::setAcceleationFilterWidth(uint32_t n) { mCloth.mIterDtAvg.resize(n); } template inline uint32_t ClothImpl::getAccelerationFilterWidth() const { return mCloth.mIterDtAvg.size(); } // move a subarray template 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 inline void ClothImpl::setSpheres(Range 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; PX_ASSERT(newSize <= 32); PX_ASSERT(first <= oldSize); PX_ASSERT(last <= oldSize); #if PX_DEBUG for(const PxVec4* it = spheres.begin(); it < spheres.end(); ++it) PX_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(PxMax(oldSize, newSize) > PxMin(mCloth.mStartCollisionSpheres.capacity(), mCloth.mTargetCollisionSpheres.capacity())) { ContextLockType contextLock(mCloth.mFactory); mCloth.mStartCollisionSpheres.reserve(newSize); mCloth.mTargetCollisionSpheres.reserve(PxMax(oldSize, newSize)); } typename T::MappedVec4fVectorType start = mCloth.mStartCollisionSpheres; typename T::MappedVec4fVectorType target = mCloth.mTargetCollisionSpheres; // 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(PxMax(oldSize, newSize), PxVec4(0.0f)); target.resize(PxMax(oldSize, newSize), 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::Type::Iterator cIt, cEnd = indices.end(); for(cIt = indices.begin(); cIt != cEnd;) { bool removed = false; removed |= updateIndex(cIt->first, last + PxMin(0, delta), int32_t(delta)); removed |= updateIndex(cIt->second, last + PxMin(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 inline uint32_t ClothImpl::getNumSpheres() const { return uint32_t(mCloth.mStartCollisionSpheres.size()); } // Fixed 4505:local function has been removed template inline void ClothImpl::setCapsules(Range capsules, uint32_t first, uint32_t last) { uint32_t oldSize = mCloth.mCapsuleIndices.size(); uint32_t newSize = uint32_t(capsules.size() / 2) + oldSize - last + first; PX_ASSERT(newSize <= 32); PX_ASSERT(first <= oldSize); PX_ASSERT(last <= oldSize); const IndexPair* srcIndices = reinterpret_cast(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(PxMax(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 inline uint32_t ClothImpl::getNumCapsules() const { return uint32_t(mCloth.mCapsuleIndices.size()); } template inline void ClothImpl::setPlanes(Range 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; PX_ASSERT(newSize <= 32); PX_ASSERT(first <= oldSize); PX_ASSERT(last <= oldSize); if(!oldSize && !newSize) return; if(!oldSize) { ContextLockType contextLock(mCloth.mFactory); mCloth.mStartCollisionPlanes.assign(planes.begin(), planes.end()); mCloth.notifyChanged(); } else { if(PxMax(oldSize, newSize) > PxMin(mCloth.mStartCollisionPlanes.capacity(), mCloth.mTargetCollisionPlanes.capacity())) { ContextLockType contextLock(mCloth.mFactory); mCloth.mStartCollisionPlanes.reserve(newSize); mCloth.mTargetCollisionPlanes.reserve(PxMax(oldSize, newSize)); } // fill target from start for(uint32_t i = mCloth.mTargetCollisionPlanes.size(); i < oldSize; ++i) mCloth.mTargetCollisionPlanes.pushBack(mCloth.mStartCollisionPlanes[i]); // resize to larger of oldSize and newSize mCloth.mStartCollisionPlanes.resize(PxMax(oldSize, newSize), PxZero); mCloth.mTargetCollisionPlanes.resize(PxMax(oldSize, newSize), PxZero); if(int32_t delta = int32_t(newSize - oldSize)) { // move past-range elements to new place move(mCloth.mStartCollisionPlanes.begin(), last, oldSize, last + delta); move(mCloth.mTargetCollisionPlanes.begin(), last, oldSize, last + delta); // fill new elements from planes for(uint32_t i = last; i < last + delta; ++i) mCloth.mStartCollisionPlanes[i] = planes[i - first]; // adjust convex indices uint32_t mask = (uint32_t(1) << (last + PxMin(delta, 0))) - 1; Vector::Type::Iterator cIt, cEnd = mCloth.mConvexMasks.end(); for(cIt = mCloth.mConvexMasks.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 { mCloth.mConvexMasks.replaceWithLast(cIt); cEnd = mCloth.mConvexMasks.end(); } } mCloth.mStartCollisionPlanes.resize(newSize); mCloth.mTargetCollisionPlanes.resize(newSize); mCloth.notifyChanged(); } // fill target elements with planes for(uint32_t i = 0; i < planes.size(); ++i) mCloth.mTargetCollisionPlanes[first + i] = planes[i]; } mCloth.wakeUp(); } template inline uint32_t ClothImpl::getNumPlanes() const { return uint32_t(mCloth.mStartCollisionPlanes.size()); } template inline void ClothImpl::setConvexes(Range convexes, uint32_t first, uint32_t last) { uint32_t oldSize = mCloth.mConvexMasks.size(); uint32_t newSize = uint32_t(convexes.size()) + oldSize - last + first; PX_ASSERT(newSize <= 32); PX_ASSERT(first <= oldSize); PX_ASSERT(last <= oldSize); if(mCloth.mConvexMasks.capacity() < newSize) { ContextLockType contextLock(mCloth.mFactory); mCloth.mConvexMasks.reserve(newSize); } // resize to larger of oldSize and newSize mCloth.mConvexMasks.resize(PxMax(oldSize, newSize)); if(uint32_t delta = newSize - oldSize) { // move past-range elements to new place move(mCloth.mConvexMasks.begin(), last, oldSize, last + delta); // fill new elements from capsules for(uint32_t i = last; i < last + delta; ++i) mCloth.mConvexMasks[i] = convexes[i - first]; mCloth.mConvexMasks.resize(newSize); mCloth.notifyChanged(); } mCloth.wakeUp(); } template inline uint32_t ClothImpl::getNumConvexes() const { return uint32_t(mCloth.mConvexMasks.size()); } template inline void ClothImpl::setTriangles(Range triangles, uint32_t first, uint32_t last) { // convert from triangle to vertex count first *= 3; last *= 3; triangles = mCloth.clampTriangleCount(triangles, last - first); PX_ASSERT(0 == triangles.size() % 3); uint32_t oldSize = uint32_t(mCloth.mStartCollisionTriangles.size()); uint32_t newSize = uint32_t(triangles.size()) + oldSize - last + first; PX_ASSERT(first <= oldSize); PX_ASSERT(last <= oldSize); if(!oldSize && !newSize) return; if(!oldSize) { ContextLockType contextLock(mCloth.mFactory); mCloth.mStartCollisionTriangles.assign(triangles.begin(), triangles.end()); mCloth.notifyChanged(); } else { if(PxMax(oldSize, newSize) > PxMin(mCloth.mStartCollisionTriangles.capacity(), mCloth.mTargetCollisionTriangles.capacity())) { ContextLockType contextLock(mCloth.mFactory); mCloth.mStartCollisionTriangles.reserve(newSize); mCloth.mTargetCollisionTriangles.reserve(PxMax(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(PxMax(oldSize, newSize)); mCloth.mTargetCollisionTriangles.resize(PxMax(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]; } mCloth.wakeUp(); } template inline void ClothImpl::setTriangles(Range startTriangles, Range targetTriangles, uint32_t first) { PX_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; PX_ASSERT(first <= oldSize); PX_ASSERT(last == oldSize); // this path only supports replacing the tail if(!oldSize && !newSize) return; if(newSize > PxMin(mCloth.mStartCollisionTriangles.capacity(), mCloth.mTargetCollisionTriangles.capacity())) { ContextLockType contextLock(mCloth.mFactory); mCloth.mStartCollisionTriangles.reserve(newSize); mCloth.mTargetCollisionTriangles.reserve(newSize); } uint32_t retainSize = oldSize - last + first; mCloth.mStartCollisionTriangles.resize(retainSize); mCloth.mTargetCollisionTriangles.resize(retainSize); 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 inline uint32_t ClothImpl::getNumTriangles() const { return uint32_t(mCloth.mStartCollisionTriangles.size()) / 3; } template inline bool ClothImpl::isContinuousCollisionEnabled() const { return mCloth.mEnableContinuousCollision; } template inline void ClothImpl::enableContinuousCollision(bool enable) { if(enable == mCloth.mEnableContinuousCollision) return; mCloth.mEnableContinuousCollision = enable; mCloth.notifyChanged(); mCloth.wakeUp(); } template inline float ClothImpl::getCollisionMassScale() const { return mCloth.mCollisionMassScale; } template inline void ClothImpl::setCollisionMassScale(float scale) { if(scale == mCloth.mCollisionMassScale) return; mCloth.mCollisionMassScale = scale; mCloth.notifyChanged(); mCloth.wakeUp(); } template inline void ClothImpl::setFriction(float friction) { mCloth.mFriction = friction; mCloth.wakeUp(); } template inline float ClothImpl::getFriction() const { return mCloth.mFriction; } template inline uint32_t ClothImpl::getNumVirtualParticleWeights() const { return uint32_t(mCloth.mVirtualParticleWeights.size()); } template inline void ClothImpl::setTetherConstraintScale(float scale) { if(scale == mCloth.mTetherConstraintScale) return; mCloth.mTetherConstraintScale = scale; mCloth.notifyChanged(); mCloth.wakeUp(); } template inline float ClothImpl::getTetherConstraintScale() const { return mCloth.mTetherConstraintScale; } template inline void ClothImpl::setTetherConstraintStiffness(float stiffness) { float value = safeLog2(1 - stiffness); if(value == mCloth.mTetherConstraintLogStiffness) return; mCloth.mTetherConstraintLogStiffness = value; mCloth.notifyChanged(); mCloth.wakeUp(); } template inline float ClothImpl::getTetherConstraintStiffness() const { return 1 - safeExp2(mCloth.mTetherConstraintLogStiffness); } template inline Range ClothImpl::getMotionConstraints() { mCloth.wakeUp(); return mCloth.push(mCloth.mMotionConstraints); } template inline void ClothImpl::clearMotionConstraints() { mCloth.clear(mCloth.mMotionConstraints); mCloth.wakeUp(); } template inline uint32_t ClothImpl::getNumMotionConstraints() const { return uint32_t(mCloth.mMotionConstraints.mStart.size()); } template inline void ClothImpl::setMotionConstraintScaleBias(float scale, float bias) { if(scale == mCloth.mMotionConstraintScale && bias == mCloth.mMotionConstraintBias) return; mCloth.mMotionConstraintScale = scale; mCloth.mMotionConstraintBias = bias; mCloth.notifyChanged(); mCloth.wakeUp(); } template inline float ClothImpl::getMotionConstraintScale() const { return mCloth.mMotionConstraintScale; } template inline float ClothImpl::getMotionConstraintBias() const { return mCloth.mMotionConstraintBias; } template inline void ClothImpl::setMotionConstraintStiffness(float stiffness) { float value = safeLog2(1 - stiffness); if(value == mCloth.mMotionConstraintLogStiffness) return; mCloth.mMotionConstraintLogStiffness = value; mCloth.notifyChanged(); mCloth.wakeUp(); } template inline float ClothImpl::getMotionConstraintStiffness() const { return 1 - safeExp2(mCloth.mMotionConstraintLogStiffness); } template inline Range ClothImpl::getSeparationConstraints() { mCloth.wakeUp(); return mCloth.push(mCloth.mSeparationConstraints); } template inline void ClothImpl::clearSeparationConstraints() { mCloth.clear(mCloth.mSeparationConstraints); mCloth.wakeUp(); } template inline void ClothImpl::clearInterpolation() { if(!mCloth.mTargetCollisionSpheres.empty()) { nvidia::swap(mCloth.mStartCollisionSpheres, mCloth.mTargetCollisionSpheres); mCloth.mTargetCollisionSpheres.resize(0); } mCloth.mMotionConstraints.pop(); mCloth.mSeparationConstraints.pop(); mCloth.wakeUp(); } template inline uint32_t ClothImpl::getNumSeparationConstraints() const { return uint32_t(mCloth.mSeparationConstraints.mStart.size()); } template inline uint32_t ClothImpl::getNumParticleAccelerations() const { return uint32_t(mCloth.mParticleAccelerations.size()); } template inline uint32_t ClothImpl::getNumSelfCollisionIndices() const { return uint32_t(mCloth.mSelfCollisionIndices.size()); } // Fixed 4505:local function has been removed template inline void ClothImpl::setRestPositions(Range restPositions) { PX_ASSERT(restPositions.empty() || restPositions.size() == getNumParticles()); ContextLockType contextLock(mCloth.mFactory); mCloth.mRestPositions.assign(restPositions.begin(), restPositions.end()); mCloth.wakeUp(); } template inline uint32_t ClothImpl::getNumRestPositions() const { return uint32_t(mCloth.mRestPositions.size()); } template inline void ClothImpl::setSelfCollisionDistance(float distance) { if(distance == mCloth.mSelfCollisionDistance) return; mCloth.mSelfCollisionDistance = distance; mCloth.notifyChanged(); mCloth.wakeUp(); } template inline float ClothImpl::getSelfCollisionDistance() const { return mCloth.mSelfCollisionDistance; } template inline void ClothImpl::setSelfCollisionStiffness(float stiffness) { float value = safeLog2(1 - stiffness); if(value == mCloth.mSelfCollisionLogStiffness) return; mCloth.mSelfCollisionLogStiffness = value; mCloth.notifyChanged(); mCloth.wakeUp(); } template inline float ClothImpl::getSelfCollisionStiffness() const { return 1 - safeExp2(mCloth.mSelfCollisionLogStiffness); } template inline const PxVec3& ClothImpl::getBoundingBoxCenter() const { return mCloth.mParticleBoundsCenter; } template inline const PxVec3& ClothImpl::getBoundingBoxScale() const { return mCloth.mParticleBoundsHalfExtent; } template inline void ClothImpl::setSleepThreshold(float threshold) { if(threshold == mCloth.mSleepThreshold) return; mCloth.mSleepThreshold = threshold; mCloth.notifyChanged(); mCloth.wakeUp(); } template inline float ClothImpl::getSleepThreshold() const { return mCloth.mSleepThreshold; } template inline void ClothImpl::setSleepTestInterval(uint32_t interval) { if(interval == mCloth.mSleepTestInterval) return; mCloth.mSleepTestInterval = interval; mCloth.notifyChanged(); mCloth.wakeUp(); } template inline uint32_t ClothImpl::getSleepTestInterval() const { return mCloth.mSleepTestInterval; } template inline void ClothImpl::setSleepAfterCount(uint32_t afterCount) { if(afterCount == mCloth.mSleepAfterCount) return; mCloth.mSleepAfterCount = afterCount; mCloth.notifyChanged(); mCloth.wakeUp(); } template inline uint32_t ClothImpl::getSleepAfterCount() const { return mCloth.mSleepAfterCount; } template inline uint32_t ClothImpl::getSleepPassCount() const { return mCloth.mSleepPassCounter; } template inline bool ClothImpl::isAsleep() const { return mCloth.isSleeping(); } template inline void ClothImpl::putToSleep() { mCloth.mSleepPassCounter = mCloth.mSleepAfterCount; } template inline void ClothImpl::wakeUp() { mCloth.wakeUp(); } template inline void ClothImpl::setHalfPrecisionOption(bool isAllowed) { mCloth.mIsAllowedHalfPrecisionSolver = isAllowed; } template inline bool ClothImpl::getHalfPrecisionOption() const { return mCloth.mIsAllowedHalfPrecisionSolver; } template inline void ClothImpl::setUserData(void* data) { mCloth.mUserData = data; } template inline void* ClothImpl::getUserData() const { return mCloth.mUserData; } template template inline MappedRange ClothImpl::getMappedParticles(U* data) const { return MappedRange(data, data + getNumParticles(), *this, &Cloth::lockParticles, &Cloth::unlockParticles); } } // namespace cloth } // namespace nvidia