aboutsummaryrefslogtreecommitdiff
path: root/PhysX_3.4/Source/SimulationController/src/cloth
diff options
context:
space:
mode:
authorgit perforce import user <a@b>2016-10-25 12:29:14 -0600
committerSheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees>2016-10-25 18:56:37 -0500
commit3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch)
treefa6485c169e50d7415a651bf838f5bcd0fd3bfbd /PhysX_3.4/Source/SimulationController/src/cloth
downloadphysx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz
physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip
Initial commit:
PhysX 3.4.0 Update @ 21294896 APEX 1.4.0 Update @ 21275617 [CL 21300167]
Diffstat (limited to 'PhysX_3.4/Source/SimulationController/src/cloth')
-rw-r--r--PhysX_3.4/Source/SimulationController/src/cloth/ScClothCore.cpp1160
-rw-r--r--PhysX_3.4/Source/SimulationController/src/cloth/ScClothFabricCore.cpp432
-rw-r--r--PhysX_3.4/Source/SimulationController/src/cloth/ScClothShape.cpp125
-rw-r--r--PhysX_3.4/Source/SimulationController/src/cloth/ScClothShape.h78
-rw-r--r--PhysX_3.4/Source/SimulationController/src/cloth/ScClothSim.cpp894
-rw-r--r--PhysX_3.4/Source/SimulationController/src/cloth/ScClothSim.h123
6 files changed, 2812 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/SimulationController/src/cloth/ScClothCore.cpp b/PhysX_3.4/Source/SimulationController/src/cloth/ScClothCore.cpp
new file mode 100644
index 00000000..8cfa74d5
--- /dev/null
+++ b/PhysX_3.4/Source/SimulationController/src/cloth/ScClothCore.cpp
@@ -0,0 +1,1160 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#include "ScClothCore.h"
+#if PX_USE_CLOTH_API
+
+using namespace physx;
+using namespace cloth;
+
+#include "PxClothParticleData.h"
+#include "PxClothTypes.h"
+
+#include "ScClothFabricCore.h"
+#include "ScClothSim.h"
+#include "ScPhysics.h"
+#include "ScScene.h"
+
+#include "Types.h"
+#include "Range.h"
+#include "Factory.h"
+#include "Cloth.h"
+#include "Fabric.h"
+#include "PsHash.h"
+
+namespace
+{
+ template <typename D, typename S>
+ PX_FORCE_INLINE cloth::Range<D> createRange(S begin, PxU32 size)
+ {
+ D* start = reinterpret_cast<D*>(begin);
+ D* end = start + size;
+
+ return cloth::Range<D>(start, end);
+ }
+}
+
+bool Sc::DefaultClothInterCollisionFilter(void* cloth0, void* cloth1)
+{
+ PX_ASSERT(cloth0);
+ PX_ASSERT(cloth1);
+
+ Sc::ClothCore* scCloth0 = static_cast<Sc::ClothCore*>(cloth0);
+ Sc::ClothCore* scCloth1 = static_cast<Sc::ClothCore*>(cloth1);
+
+ const Sc::Scene& scene = scCloth0->getSim()->getScene();
+ PX_ASSERT(&scCloth1->getSim()->getScene() == &scene);
+
+ PxSimulationFilterShader shader = scene.getFilterShaderFast();
+
+ PxPairFlags pairFlags;
+ PxFilterFlags filterFlags = shader(
+ PxFilterObjectType::eCLOTH, scCloth0->getSimulationFilterData(),
+ PxFilterObjectType::eCLOTH, scCloth1->getSimulationFilterData(),
+ pairFlags,
+ scene.getFilterShaderDataFast(),
+ scene.getFilterShaderDataSizeFast());
+
+ if (filterFlags&PxFilterFlag::eCALLBACK)
+ {
+ // create unique pair id from cloth core ptrs
+ const PxU32 pairId = shdfnd::hash(shdfnd::Pair<Sc::ClothCore*, Sc::ClothCore*>(scCloth0, scCloth1));
+
+ filterFlags = scene.getFilterCallbackFast()->pairFound(pairId,
+ PxFilterObjectType::eCLOTH, scCloth0->getSimulationFilterData(), scCloth0->getPxCloth(), NULL,
+ PxFilterObjectType::eCLOTH, scCloth1->getSimulationFilterData(), scCloth1->getPxCloth(), NULL, pairFlags);
+ }
+
+ if (filterFlags&PxFilterFlag::eKILL || filterFlags&PxFilterFlag::eSUPPRESS)
+ return false;
+
+ return true;
+}
+
+
+Sc::ClothCore::ClothCore(const PxTransform& globalPose, Sc::ClothFabricCore& fabric, const PxClothParticle* particles, PxClothFlags flags) :
+ ActorCore(PxActorType::eCLOTH, PxActorFlag::eVISUALIZATION, PX_DEFAULT_CLIENT, 0, 0),
+ mExternalAcceleration(0.0f),
+ mFabric(&fabric),
+ mBulkData(NULL),
+ mClothFlags(flags),
+ mContactOffset(0.0f),
+ mRestOffset(0.0f),
+ mNumUserSpheres(0),
+ mNumUserCapsules(0),
+ mNumUserPlanes(0),
+ mNumUserConvexes(0),
+ mNumUserTriangles(0)
+{
+ initLowLevel(globalPose, particles);
+}
+
+
+Sc::ClothCore::~ClothCore()
+{
+ PX_ASSERT(getSim() == NULL);
+
+ if (mPhaseConfigs)
+ PX_FREE(mPhaseConfigs);
+
+ cloth::Fabric* fabric = &mLowLevelCloth->getFabric();
+
+ PX_DELETE(mLowLevelCloth);
+
+ // If a cloth fabric gets deleted while the simulation is running, the fabric has to be delayed destroyed but
+ // ScClothFabric is then gone already. So we delete here in this case. It would work automatically if the fabric
+ // deleted itself on refCount 0 but doing it the way below keeps the LL interface independent.
+ if (fabric->getRefCount() == 0)
+ PX_DELETE(fabric);
+}
+
+void Sc::ClothCore::initLowLevel(const PxTransform& globalPose, const PxClothParticle* particles)
+{
+ PX_ASSERT(mFabric);
+
+ PxU32 nbPhases = mFabric->getNbPhases();
+ mPhaseConfigs = reinterpret_cast<cloth::PhaseConfig*>(PX_ALLOC(nbPhases * sizeof(cloth::PhaseConfig), "cloth::PhaseConfig"));
+
+ if (mPhaseConfigs)
+ {
+ for(PxU16 i=0; i < nbPhases; i++)
+ {
+ cloth::PhaseConfig config(i);
+ PX_PLACEMENT_NEW(mPhaseConfigs + i, cloth::PhaseConfig)(config);
+ }
+
+ // Create the low level object
+ cloth::Range<const PxVec4> particlesRange = createRange<const PxVec4>(particles, mFabric->getNbParticles());
+
+ //!!!CL todo: error processing if creation fails
+ mLowLevelCloth = Sc::Physics::getInstance().getLowLevelClothFactory().createCloth(particlesRange, mFabric->getLowLevelFabric());
+
+ if (mLowLevelCloth)
+ {
+ setGlobalPose(globalPose);
+
+ cloth::Range<const cloth::PhaseConfig> phaseConfigRange = createRange<const cloth::PhaseConfig>(mPhaseConfigs, nbPhases);
+ mLowLevelCloth->setPhaseConfig(phaseConfigRange);
+
+ mLowLevelCloth->enableContinuousCollision(mClothFlags & PxClothFlag::eSWEPT_CONTACT);
+
+ mLowLevelCloth->setUserData(this);
+
+ wakeUp(Physics::sWakeCounterOnCreation);
+ }
+ }
+}
+
+// PX_SERIALIZATION
+
+void Sc::ClothCore::updateBulkData(ClothBulkData& bulkData)
+{
+ cloth::MappedRange<const PxVec4> particles = cloth::readCurrentParticles(*mLowLevelCloth);
+ bulkData.mParticles.resize(getNbParticles(), PxClothParticle(PxVec3(0.0f), 0.0f));
+ PxMemCopy(bulkData.mParticles.begin(), particles.begin(), particles.size() * sizeof(PxVec4));
+
+ if (getNbVirtualParticles())
+ {
+ // could avoid a lot of the construction overhead inside
+ // resize() if Array supported insertRange() instead
+ bulkData.mVpData.resize(getNbVirtualParticles()*4);
+ bulkData.mVpWeightData.resize(getNbVirtualParticleWeights(), PxVec3(0.0f));
+
+ getVirtualParticles(bulkData.mVpData.begin());
+ getVirtualParticleWeights(bulkData.mVpWeightData.begin());
+ }
+
+ if (getNbCollisionSpheres() || getNbCollisionConvexes() || getNbCollisionTriangles())
+ {
+ bulkData.mCollisionSpheres.resize(getNbCollisionSpheres());
+ bulkData.mCollisionPairs.resize(getNbCollisionCapsules()*2);
+ bulkData.mCollisionPlanes.resize(getNbCollisionPlanes());
+ bulkData.mConvexMasks.resize(getNbCollisionConvexes());
+ bulkData.mCollisionTriangles.resize(getNbCollisionTriangles());
+
+ getCollisionData(bulkData.mCollisionSpheres.begin(), bulkData.mCollisionPairs.begin(),
+ bulkData.mCollisionPlanes.begin(), bulkData.mConvexMasks.begin(), bulkData.mCollisionTriangles.begin());
+ }
+
+ if (mLowLevelCloth->getNumMotionConstraints())
+ {
+ bulkData.mConstraints.resize(mLowLevelCloth->getNumMotionConstraints(), PxClothParticleMotionConstraint(PxVec3(0.0f), 0.0f));
+ getMotionConstraints(bulkData.mConstraints.begin());
+ }
+
+ if (mLowLevelCloth->getNumSeparationConstraints())
+ {
+ bulkData.mSeparationConstraints.resize(mLowLevelCloth->getNumSeparationConstraints(), PxClothParticleSeparationConstraint(PxVec3(0.0f), 0.0f));
+ getSeparationConstraints(bulkData.mSeparationConstraints.begin());
+ }
+
+ if (mLowLevelCloth->getNumParticleAccelerations())
+ {
+ bulkData.mParticleAccelerations.resize(mLowLevelCloth->getNumParticleAccelerations());
+ getParticleAccelerations(bulkData.mParticleAccelerations.begin());
+ }
+
+ if(mLowLevelCloth->getNumSelfCollisionIndices())
+ {
+ bulkData.mSelfCollisionIndices.resize(mLowLevelCloth->getNumSelfCollisionIndices());
+ getSelfCollisionIndices(bulkData.mSelfCollisionIndices.begin());
+ }
+
+ if (mLowLevelCloth->getNumRestPositions())
+ {
+ bulkData.mRestPositions.resize(mLowLevelCloth->getNumRestPositions(), PxVec4(0.0f));
+ getRestPositions(bulkData.mRestPositions.begin());
+ }
+
+ bulkData.mTetherConstraintScale = mLowLevelCloth->getTetherConstraintScale();
+ bulkData.mTetherConstraintStiffness = mLowLevelCloth->getTetherConstraintStiffness();
+ bulkData.mMotionConstraintScale = mLowLevelCloth->getMotionConstraintScale();
+ bulkData.mMotionConstraintBias = mLowLevelCloth->getMotionConstraintBias();
+ bulkData.mMotionConstraintStiffness = mLowLevelCloth->getMotionConstraintStiffness();
+ bulkData.mAcceleration = getExternalAcceleration();
+ bulkData.mDamping = mLowLevelCloth->getDamping();
+ bulkData.mFriction = mLowLevelCloth->getFriction();
+ bulkData.mCollisionMassScale = mLowLevelCloth->getCollisionMassScale();
+ bulkData.mLinearDrag = mLowLevelCloth->getLinearDrag();
+ bulkData.mAngularDrag = mLowLevelCloth->getAngularDrag();
+ bulkData.mLinearInertia = mLowLevelCloth->getLinearInertia();
+ bulkData.mAngularInertia = mLowLevelCloth->getAngularInertia();
+ bulkData.mCentrifugalInertia = mLowLevelCloth->getCentrifugalInertia();
+ bulkData.mSolverFrequency = mLowLevelCloth->getSolverFrequency();
+ bulkData.mStiffnessFrequency = mLowLevelCloth->getStiffnessFrequency();
+ bulkData.mSelfCollisionDistance = mLowLevelCloth->getSelfCollisionDistance();
+ bulkData.mSelfCollisionStiffness = mLowLevelCloth->getSelfCollisionStiffness();
+ bulkData.mGlobalPose = getGlobalPose();
+ bulkData.mSleepThreshold = mLowLevelCloth->getSleepThreshold();
+ bulkData.mWakeCounter = getWakeCounter();
+ bulkData.mWindVelocity = getWindVelocity();
+ bulkData.mDragCoefficient = getDragCoefficient();
+ bulkData.mLiftCoefficient = getLiftCoefficient();
+}
+
+void Sc::ClothCore::resolveReferences(Sc::ClothFabricCore& fabric)
+{
+ PX_ASSERT(mBulkData);
+
+ mFabric = &fabric;
+
+ // at this point we have all our bulk data and a reference
+ // to the Sc::ClothFabricCore object so we can go ahead
+ // and create the low level cloth object
+
+ initLowLevel(mBulkData->mGlobalPose, mBulkData->mParticles.begin());
+
+ mLowLevelCloth->setSpheres(createRange<PxVec4>(mBulkData->mCollisionSpheres.begin(), mBulkData->mCollisionSpheres.size()), 0, 0);
+ mLowLevelCloth->setCapsules(createRange<PxU32>(mBulkData->mCollisionPairs.begin(), mBulkData->mCollisionPairs.size()/2), 0, 0);
+ mLowLevelCloth->setPlanes(createRange<PxVec4>(mBulkData->mCollisionPlanes.begin(), mBulkData->mCollisionPlanes.size()), 0, 0);
+ mLowLevelCloth->setConvexes(createRange<PxU32>(mBulkData->mConvexMasks.begin(), mBulkData->mConvexMasks.size()), 0, 0);
+ mLowLevelCloth->setTriangles(createRange<PxVec3>(mBulkData->mCollisionTriangles.begin(), mBulkData->mCollisionTriangles.size()*3), 0, 0);
+
+ // update virtual particles
+ if (mBulkData->mVpData.size())
+ setVirtualParticles(mBulkData->mVpData.size()/4, mBulkData->mVpData.begin(),
+ mBulkData->mVpWeightData.size(), mBulkData->mVpWeightData.begin());
+
+ // update motion constraints
+ if (mBulkData->mConstraints.size())
+ setMotionConstraints(mBulkData->mConstraints.begin());
+
+ // update separation constraints
+ if (mBulkData->mSeparationConstraints.size())
+ setSeparationConstraints(mBulkData->mSeparationConstraints.begin());
+
+ // update particle accelerations
+ if (mBulkData->mParticleAccelerations.size())
+ setParticleAccelerations(mBulkData->mParticleAccelerations.begin());
+
+ if (mBulkData->mSelfCollisionIndices.size())
+ {
+ setSelfCollisionIndices(mBulkData->mSelfCollisionIndices.begin(),
+ mBulkData->mSelfCollisionIndices.size());
+ }
+
+ // update rest positions
+ if (mBulkData->mRestPositions.size())
+ setRestPositions(mBulkData->mRestPositions.begin());
+
+ mLowLevelCloth->setTetherConstraintScale(mBulkData->mTetherConstraintScale);
+ mLowLevelCloth->setTetherConstraintStiffness(mBulkData->mTetherConstraintStiffness);
+ mLowLevelCloth->setMotionConstraintScaleBias(mBulkData->mMotionConstraintScale, mBulkData->mMotionConstraintBias);
+ mLowLevelCloth->setMotionConstraintStiffness(mBulkData->mMotionConstraintStiffness);
+ setExternalAcceleration(mBulkData->mAcceleration);
+ mLowLevelCloth->setDamping(mBulkData->mDamping);
+ mLowLevelCloth->setFriction(mBulkData->mFriction);
+ mLowLevelCloth->setCollisionMassScale(mBulkData->mCollisionMassScale);
+ mLowLevelCloth->setLinearDrag(mBulkData->mLinearDrag);
+ mLowLevelCloth->setAngularDrag(mBulkData->mAngularDrag);
+ mLowLevelCloth->setLinearInertia(mBulkData->mLinearInertia);
+ mLowLevelCloth->setAngularInertia(mBulkData->mAngularInertia);
+ mLowLevelCloth->setCentrifugalInertia(mBulkData->mCentrifugalInertia);
+ mLowLevelCloth->setSolverFrequency(mBulkData->mSolverFrequency);
+ mLowLevelCloth->setStiffnessFrequency(mBulkData->mStiffnessFrequency);
+ mLowLevelCloth->setSelfCollisionDistance(mBulkData->mSelfCollisionDistance);
+ mLowLevelCloth->setSelfCollisionStiffness(mBulkData->mSelfCollisionStiffness);
+
+ mLowLevelCloth->setSleepThreshold(mBulkData->mSleepThreshold);
+ setWakeCounter(mBulkData->mWakeCounter);
+
+ mLowLevelCloth->setWindVelocity(mBulkData->mWindVelocity);
+ mLowLevelCloth->setDragCoefficient(mBulkData->mDragCoefficient);
+ mLowLevelCloth->setLiftCoefficient(mBulkData->mLiftCoefficient);
+
+ mBulkData = NULL;
+}
+
+void Sc::ClothBulkData::exportExtraData(PxSerializationContext& context)
+{
+ Cm::exportArray(mParticles, context);
+ Cm::exportArray(mVpData, context);
+ Cm::exportArray(mVpWeightData, context);
+ Cm::exportArray(mCollisionSpheres, context);
+ Cm::exportArray(mCollisionPairs, context);
+ Cm::exportArray(mCollisionPlanes, context);
+ Cm::exportArray(mConvexMasks, context);
+ Cm::exportArray(mCollisionTriangles, context);
+ Cm::exportArray(mConstraints, context);
+ Cm::exportArray(mSeparationConstraints, context);
+ Cm::exportArray(mParticleAccelerations, context);
+ Cm::exportArray(mRestPositions, context);
+}
+
+void Sc::ClothBulkData::importExtraData(PxDeserializationContext& context)
+{
+ Cm::importArray(mParticles, context);
+ Cm::importArray(mVpData, context);
+ Cm::importArray(mVpWeightData, context);
+ Cm::importArray(mCollisionSpheres, context);
+ Cm::importArray(mCollisionPairs, context);
+ Cm::importArray(mCollisionPlanes, context);
+ Cm::importArray(mConvexMasks, context);
+ Cm::importArray(mCollisionTriangles, context);
+ Cm::importArray(mConstraints, context);
+ Cm::importArray(mSeparationConstraints, context);
+ Cm::importArray(mParticleAccelerations, context);
+ Cm::importArray(mRestPositions, context);
+}
+
+void Sc::ClothCore::exportExtraData(PxSerializationContext& stream)
+{
+ PX_ALLOCA(buf, ClothBulkData, 1);
+ Cm::markSerializedMem(buf, sizeof(ClothBulkData));
+ ClothBulkData* bulkData = PX_PLACEMENT_NEW(buf, ClothBulkData);
+ updateBulkData(*bulkData);
+ stream.writeData(bulkData, sizeof(ClothBulkData));
+ bulkData->exportExtraData(stream);
+ bulkData->~ClothBulkData();
+}
+
+
+void Sc::ClothCore::importExtraData(PxDeserializationContext& context)
+{
+ mBulkData = context.readExtraData<ClothBulkData>();
+ mBulkData->importExtraData(context);
+}
+
+//~PX_SERIALIZATION
+
+
+void Sc::ClothCore::setParticles(const PxClothParticle* currentParticles, const PxClothParticle* previousParticles)
+{
+ if (currentParticles)
+ {
+ cloth::MappedRange<PxVec4> particlesRange = mLowLevelCloth->getCurrentParticles();
+ if(reinterpret_cast<const PxClothParticle*>(particlesRange.begin()) != currentParticles)
+ PxMemCopy(particlesRange.begin(), currentParticles, particlesRange.size() * sizeof(PxVec4));
+ }
+
+ if (previousParticles)
+ {
+ cloth::MappedRange<PxVec4> particlesRange = mLowLevelCloth->getPreviousParticles();
+ if(reinterpret_cast<const PxClothParticle*>(particlesRange.begin()) != previousParticles)
+ PxMemCopy(particlesRange.begin(), previousParticles, particlesRange.size() * sizeof(PxVec4));
+ }
+}
+
+PxU32 Sc::ClothCore::getNbParticles() const
+{
+ return mLowLevelCloth->getNumParticles();
+}
+
+void Sc::ClothCore::setMotionConstraints(const PxClothParticleMotionConstraint* motionConstraints)
+{
+ if(motionConstraints)
+ {
+ cloth::Range<PxVec4> motionConstraintsRange = mLowLevelCloth->getMotionConstraints();
+ PxMemCopy(motionConstraintsRange.begin(), motionConstraints,
+ PxU32(motionConstraintsRange.size() * sizeof(PxClothParticleMotionConstraint)));
+ } else {
+ mLowLevelCloth->clearMotionConstraints();
+ }
+}
+
+bool Sc::ClothCore::getMotionConstraints(PxClothParticleMotionConstraint* motionConstraintsBuffer) const
+{
+ PxU32 nbConstraints = mLowLevelCloth->getNumMotionConstraints();
+
+ if (nbConstraints)
+ {
+ PxVec4* constrData = reinterpret_cast<PxVec4*>(motionConstraintsBuffer);
+ cloth::Range<PxVec4> constrRange = createRange<PxVec4>(constrData, nbConstraints);
+
+ mLowLevelCloth->getFactory().extractMotionConstraints(*mLowLevelCloth, constrRange);
+
+ return true;
+ }
+ else
+ return false;
+}
+
+PxU32 Sc::ClothCore::getNbMotionConstraints() const
+{
+ return mLowLevelCloth->getNumMotionConstraints();
+}
+
+void Sc::ClothCore::setMotionConstraintConfig(const PxClothMotionConstraintConfig& config)
+{
+ mLowLevelCloth->setMotionConstraintScaleBias(config.scale, config.bias);
+ mLowLevelCloth->setMotionConstraintStiffness(config.stiffness);
+}
+
+
+PxClothMotionConstraintConfig Sc::ClothCore::getMotionConstraintConfig() const
+{
+ PxClothMotionConstraintConfig result;
+ result.scale = mLowLevelCloth->getMotionConstraintScale();
+ result.bias = mLowLevelCloth->getMotionConstraintBias();
+ result.stiffness = mLowLevelCloth->getMotionConstraintStiffness();
+ return result;
+}
+
+void Sc::ClothCore::setSeparationConstraints(const PxClothParticleSeparationConstraint* separationConstraints)
+{
+ if (separationConstraints)
+ {
+ cloth::Range<PxVec4> separationConstraintsRange = mLowLevelCloth->getSeparationConstraints();
+ PxMemCopy(separationConstraintsRange.begin(), separationConstraints,
+ PxU32(separationConstraintsRange.size() * sizeof(PxClothParticleSeparationConstraint)));
+ } else {
+ mLowLevelCloth->clearSeparationConstraints();
+ }
+}
+
+bool Sc::ClothCore::getSeparationConstraints(PxClothParticleSeparationConstraint* separationConstraintsBuffer) const
+{
+ PxU32 nbConstraints = mLowLevelCloth->getNumSeparationConstraints();
+
+ if (nbConstraints)
+ {
+ PxVec4* constrData = reinterpret_cast<PxVec4*>(separationConstraintsBuffer);
+ cloth::Range<PxVec4> constrRange = createRange<PxVec4>(constrData, nbConstraints);
+
+ mLowLevelCloth->getFactory().extractSeparationConstraints(*mLowLevelCloth, constrRange);
+
+ return true;
+ }
+ else
+ return false;
+}
+
+PxU32 Sc::ClothCore::getNbSeparationConstraints() const
+{
+ return mLowLevelCloth->getNumSeparationConstraints();
+}
+
+void Sc::ClothCore::clearInterpolation()
+{
+ return mLowLevelCloth->clearInterpolation();
+}
+
+void Sc::ClothCore::setParticleAccelerations(const PxVec4* particleAccelerations)
+{
+ if(particleAccelerations)
+ {
+ cloth::Range<PxVec4> accelerationsRange = mLowLevelCloth->getParticleAccelerations();
+ PxMemCopy(accelerationsRange.begin(),
+ particleAccelerations, accelerationsRange.size() * sizeof(PxVec4));
+ } else {
+ mLowLevelCloth->clearParticleAccelerations();
+ }
+}
+
+bool Sc::ClothCore::getParticleAccelerations(PxVec4* particleAccelerationBuffer) const
+{
+ PxU32 nbAccelerations = mLowLevelCloth->getNumParticleAccelerations();
+
+ if (nbAccelerations)
+ {
+ PxVec4* accelData = reinterpret_cast<PxVec4*>(particleAccelerationBuffer);
+ cloth::Range<PxVec4> accelRange = createRange<PxVec4>(accelData, nbAccelerations);
+
+ mLowLevelCloth->getFactory().extractParticleAccelerations(*mLowLevelCloth, accelRange);
+
+ return true;
+ }
+ else
+ return false;
+}
+
+PxU32 Sc::ClothCore::getNbParticleAccelerations() const
+{
+ return mLowLevelCloth->getNumParticleAccelerations();
+}
+
+
+void Sc::ClothCore::addCollisionSphere(const PxClothCollisionSphere& sphere)
+{
+ const PxVec4* data = reinterpret_cast<const PxVec4*>(&sphere);
+ mLowLevelCloth->setSpheres(createRange<const PxVec4>(data, 1), mNumUserSpheres, mNumUserSpheres);
+ ++mNumUserSpheres;
+}
+void Sc::ClothCore::removeCollisionSphere(PxU32 index)
+{
+ PxU32 numCapsules = mLowLevelCloth->getNumCapsules();
+ mLowLevelCloth->setSpheres(cloth::Range<const PxVec4>(), index, index+1);
+ mNumUserCapsules -= numCapsules - mLowLevelCloth->getNumCapsules();
+ --mNumUserSpheres;
+}
+void Sc::ClothCore::setCollisionSpheres(const PxClothCollisionSphere* spheresBuffer, PxU32 count)
+{
+ const PxVec4* data = reinterpret_cast<const PxVec4*>(spheresBuffer);
+ PxU32 numCapsules = mLowLevelCloth->getNumCapsules();
+ mLowLevelCloth->setSpheres(createRange<const PxVec4>(data, count), 0, mNumUserSpheres);
+ mNumUserCapsules -= numCapsules - mLowLevelCloth->getNumCapsules();
+ mNumUserSpheres = count;
+}
+PxU32 Sc::ClothCore::getNbCollisionSpheres() const
+{
+ return mLowLevelCloth->getNumSpheres();
+}
+
+void Sc::ClothCore::getCollisionData(PxClothCollisionSphere* spheresBuffer, PxU32* capsulesBuffer,
+ PxClothCollisionPlane* planesBuffer, PxU32* convexesBuffer, PxClothCollisionTriangle* trianglesBuffer) const
+{
+ PxVec4* sphereData = reinterpret_cast<PxVec4*>(spheresBuffer);
+ cloth::Range<PxVec4> sphereRange = createRange<PxVec4>(sphereData, sphereData ? mLowLevelCloth->getNumSpheres() : 0);
+ uint32_t* capsuleData = reinterpret_cast<uint32_t*>(capsulesBuffer);
+ cloth::Range<uint32_t> capsuleRange = createRange<uint32_t>(capsuleData, capsuleData ? 2*mLowLevelCloth->getNumCapsules() : 0);
+ PxVec4* planeData = reinterpret_cast<PxVec4*>(planesBuffer);
+ cloth::Range<PxVec4> planeRange = createRange<PxVec4>(planeData, planeData ? mLowLevelCloth->getNumPlanes() : 0);
+ uint32_t* convexData = reinterpret_cast<uint32_t*>(convexesBuffer);
+ cloth::Range<uint32_t> convexRange = createRange<uint32_t>(convexData, convexData ? mLowLevelCloth->getNumConvexes() : 0);
+ PxVec3* triangleData = reinterpret_cast<PxVec3*>(trianglesBuffer);
+ cloth::Range<PxVec3> triangleRange = createRange<PxVec3>(triangleData, triangleData ? mLowLevelCloth->getNumTriangles() * 3 : 0);
+
+ mLowLevelCloth->getFactory().extractCollisionData(*mLowLevelCloth, sphereRange, capsuleRange, planeRange, convexRange, triangleRange);
+}
+
+void Sc::ClothCore::addCollisionCapsule(PxU32 first, PxU32 second)
+{
+ PxU32 indices[2] = { first, second };
+ mLowLevelCloth->setCapsules(createRange<const PxU32>(indices, 2), mNumUserCapsules, mNumUserCapsules);
+ ++mNumUserCapsules;
+}
+void Sc::ClothCore::removeCollisionCapsule(PxU32 index)
+{
+ mLowLevelCloth->setCapsules(cloth::Range<const PxU32>(), index, index+1);
+ --mNumUserCapsules;
+}
+PxU32 Sc::ClothCore::getNbCollisionCapsules() const
+{
+ return mLowLevelCloth->getNumCapsules();
+}
+
+void Sc::ClothCore::addCollisionTriangle(const PxClothCollisionTriangle& triangle)
+{
+ mLowLevelCloth->setTriangles(createRange<const PxVec3>(&triangle, 3), mNumUserTriangles, mNumUserTriangles);
+ ++mNumUserTriangles;
+}
+void Sc::ClothCore::removeCollisionTriangle(PxU32 index)
+{
+ mLowLevelCloth->setTriangles(cloth::Range<const PxVec3>(), index, index+1);
+ --mNumUserTriangles;
+}
+void Sc::ClothCore::setCollisionTriangles(const PxClothCollisionTriangle* trianglesBuffer, PxU32 count)
+{
+ mLowLevelCloth->setTriangles(createRange<const PxVec3>(trianglesBuffer, count*3), 0, mNumUserTriangles);
+ mNumUserTriangles = count;
+}
+PxU32 Sc::ClothCore::getNbCollisionTriangles() const
+{
+ return mLowLevelCloth->getNumTriangles();
+}
+
+void Sc::ClothCore::addCollisionPlane(const PxClothCollisionPlane& plane)
+{
+ mLowLevelCloth->setPlanes(createRange<const PxVec4>(&plane, 1), mNumUserPlanes, mNumUserPlanes);
+ ++mNumUserPlanes;
+}
+void Sc::ClothCore::removeCollisionPlane(PxU32 index)
+{
+ PxU32 numConvexes = mLowLevelCloth->getNumConvexes();
+ mLowLevelCloth->setPlanes(cloth::Range<const PxVec4>(), index, index+1);
+ mNumUserConvexes -= numConvexes - mLowLevelCloth->getNumConvexes();
+ --mNumUserPlanes;
+}
+void Sc::ClothCore::setCollisionPlanes(const PxClothCollisionPlane* planesBuffer, PxU32 count)
+{
+ PxU32 numConvexes = mLowLevelCloth->getNumConvexes();
+ mLowLevelCloth->setPlanes(createRange<const PxVec4>(planesBuffer, count), 0, mNumUserPlanes);
+ mNumUserConvexes -= numConvexes - mLowLevelCloth->getNumConvexes();
+ mNumUserPlanes = count;
+}
+PxU32 Sc::ClothCore::getNbCollisionPlanes() const
+{
+ return mLowLevelCloth->getNumPlanes();
+}
+
+void Sc::ClothCore::addCollisionConvex(PxU32 mask)
+{
+ mLowLevelCloth->setConvexes(createRange<const PxU32>(&mask, 1), mNumUserConvexes, mNumUserConvexes);
+ ++mNumUserConvexes;
+}
+void Sc::ClothCore::removeCollisionConvex(PxU32 index)
+{
+ mLowLevelCloth->setConvexes(cloth::Range<const PxU32>(), index, index+1);
+ --mNumUserConvexes;
+}
+PxU32 Sc::ClothCore::getNbCollisionConvexes() const
+{
+ return mLowLevelCloth->getNumConvexes();
+}
+
+void Sc::ClothCore::setVirtualParticles(PxU32 numParticles, const PxU32* indices, PxU32 numWeights, const PxVec3* weights)
+{
+ cloth::Range<const PxU32[4]> vertexAndWeightIndicesRange = createRange<const PxU32[4]>(indices, numParticles);
+ cloth::Range<const PxVec3> weightTableRange = createRange<const PxVec3>(weights, numWeights);
+
+ mLowLevelCloth->setVirtualParticles(vertexAndWeightIndicesRange, weightTableRange);
+}
+
+
+PxU32 Sc::ClothCore::getNbVirtualParticles() const
+{
+ return mLowLevelCloth->getNumVirtualParticles();
+}
+
+
+void Sc::ClothCore::getVirtualParticles(PxU32* indicesBuffer) const
+{
+ PxU32 numVParticles = PxU32(mLowLevelCloth->getNumVirtualParticles());
+ PxU32 (*data)[4] = reinterpret_cast<PxU32(*)[4]>(indicesBuffer);
+ cloth::Range<PxU32[4]> vParticleRange(data, data + numVParticles);
+ cloth::Range<PxVec3> weightTableRange;
+
+ mLowLevelCloth->getFactory().extractVirtualParticles(*mLowLevelCloth, vParticleRange, weightTableRange);
+}
+
+
+PxU32 Sc::ClothCore::getNbVirtualParticleWeights() const
+{
+ return mLowLevelCloth->getNumVirtualParticleWeights();
+}
+
+
+void Sc::ClothCore::getVirtualParticleWeights(PxVec3* weightsBuffer) const
+{
+ PxU32 numWeights = PxU32(mLowLevelCloth->getNumVirtualParticleWeights());
+ cloth::Range<PxU32[4]> indicesRange;
+ cloth::Range<PxVec3> weightsRange(weightsBuffer, weightsBuffer + numWeights);
+
+ mLowLevelCloth->getFactory().extractVirtualParticles(*mLowLevelCloth, indicesRange, weightsRange);
+}
+
+
+PxTransform Sc::ClothCore::getGlobalPose() const
+{
+ PxTransform pose(mLowLevelCloth->getTranslation(), mLowLevelCloth->getRotation());
+ return pose;
+}
+
+
+void Sc::ClothCore::setGlobalPose(const PxTransform& pose)
+{
+ mLowLevelCloth->setTranslation(pose.p);
+ mLowLevelCloth->setRotation(pose.q);
+ mLowLevelCloth->clearInertia();
+}
+
+PxVec3 Sc::ClothCore::getLinearInertiaScale() const
+{
+ return mLowLevelCloth->getLinearInertia();
+}
+
+void Sc::ClothCore::setLinearInertiaScale(PxVec3 scale)
+{
+ mLowLevelCloth->setLinearInertia(scale);
+}
+
+PxVec3 Sc::ClothCore::getAngularInertiaScale() const
+{
+ return mLowLevelCloth->getAngularInertia();
+}
+
+void Sc::ClothCore::setAngularInertiaScale(PxVec3 scale)
+{
+ mLowLevelCloth->setAngularInertia(scale);
+}
+
+PxVec3 Sc::ClothCore::getCentrifugalInertiaScale() const
+{
+ return mLowLevelCloth->getCentrifugalInertia();
+}
+
+void Sc::ClothCore::setCentrifugalInertiaScale(PxVec3 scale)
+{
+ mLowLevelCloth->setCentrifugalInertia(scale);
+}
+
+void Sc::ClothCore::setTargetPose(const PxTransform& pose)
+{
+ //!!!CL todo: behavior for free-standing cloth?
+ mLowLevelCloth->setTranslation(pose.p);
+ mLowLevelCloth->setRotation(pose.q);
+}
+
+
+void Sc::ClothCore::setExternalAcceleration(PxVec3 acceleration)
+{
+ mExternalAcceleration = acceleration;
+}
+
+
+PxVec3 Sc::ClothCore::getExternalAcceleration() const
+{
+ return mExternalAcceleration;
+}
+
+
+void Sc::ClothCore::setDampingCoefficient(PxVec3 dampingCoefficient)
+{
+ mLowLevelCloth->setDamping(dampingCoefficient);
+}
+
+
+PxVec3 Sc::ClothCore::getDampingCoefficient() const
+{
+ return mLowLevelCloth->getDamping();
+}
+
+void Sc::ClothCore::setFrictionCoefficient(PxReal frictionCoefficient)
+{
+ mLowLevelCloth->setFriction(frictionCoefficient);
+}
+
+
+PxReal Sc::ClothCore::getFrictionCoefficient() const
+{
+ return mLowLevelCloth->getFriction();
+}
+
+void Sc::ClothCore::setLinearDragCoefficient(PxVec3 dragCoefficient)
+{
+ mLowLevelCloth->setLinearDrag(dragCoefficient);
+}
+
+PxVec3 Sc::ClothCore::getLinearDragCoefficient() const
+{
+ return mLowLevelCloth->getLinearDrag();
+}
+void Sc::ClothCore::setAngularDragCoefficient(PxVec3 dragCoefficient)
+{
+ mLowLevelCloth->setAngularDrag(dragCoefficient);
+}
+
+PxVec3 Sc::ClothCore::getAngularDragCoefficient() const
+{
+ return mLowLevelCloth->getAngularDrag();
+}
+
+void Sc::ClothCore::setCollisionMassScale(PxReal scalingCoefficient)
+{
+ mLowLevelCloth->setCollisionMassScale(scalingCoefficient);
+}
+PxReal Sc::ClothCore::getCollisionMassScale() const
+{
+ return mLowLevelCloth->getCollisionMassScale();
+}
+
+void Sc::ClothCore::setSelfCollisionDistance(PxReal distance)
+{
+ mLowLevelCloth->setSelfCollisionDistance(distance);
+}
+PxReal Sc::ClothCore::getSelfCollisionDistance() const
+{
+ return mLowLevelCloth->getSelfCollisionDistance();
+}
+void Sc::ClothCore::setSelfCollisionStiffness(PxReal stiffness)
+{
+ mLowLevelCloth->setSelfCollisionStiffness(stiffness);
+}
+PxReal Sc::ClothCore::getSelfCollisionStiffness() const
+{
+ return mLowLevelCloth->getSelfCollisionStiffness();
+}
+
+void Sc::ClothCore::setSelfCollisionIndices(const PxU32* indices, PxU32 nbIndices)
+{
+ mLowLevelCloth->setSelfCollisionIndices(
+ cloth::Range<const PxU32>(indices, indices + nbIndices));
+}
+
+bool Sc::ClothCore::getSelfCollisionIndices(PxU32* indices) const
+{
+ PxU32 nbIndices = mLowLevelCloth->getNumSelfCollisionIndices();
+ mLowLevelCloth->getFactory().extractSelfCollisionIndices(
+ *mLowLevelCloth, cloth::Range<PxU32>(indices, indices + nbIndices));
+ return !!nbIndices;
+}
+
+PxU32 Sc::ClothCore::getNbSelfCollisionIndices() const
+{
+ return mLowLevelCloth->getNumSelfCollisionIndices();
+}
+
+void Sc::ClothCore::setRestPositions(const PxVec4* restPositions)
+{
+ PxU32 size = restPositions ? mLowLevelCloth->getNumParticles() : 0;
+ mLowLevelCloth->setRestPositions(cloth::Range<const PxVec4>(restPositions, restPositions + size));
+}
+
+bool Sc::ClothCore::getRestPositions(PxVec4* restPositions) const
+{
+ PxU32 size = mLowLevelCloth->getNumRestPositions();
+ mLowLevelCloth->getFactory().extractRestPositions(*mLowLevelCloth,
+ cloth::Range<PxVec4>(restPositions, restPositions + size));
+ return true;
+}
+
+PxU32 Sc::ClothCore::getNbRestPositions() const
+{
+ return mLowLevelCloth->getNumRestPositions();
+}
+
+void Sc::ClothCore::setSolverFrequency(PxReal solverFreq)
+{
+ mLowLevelCloth->setSolverFrequency(solverFreq);
+}
+
+PxReal Sc::ClothCore::getSolverFrequency() const
+{
+ return mLowLevelCloth->getSolverFrequency();
+}
+
+void Sc::ClothCore::setStiffnessFrequency(PxReal frequency)
+{
+ mLowLevelCloth->setStiffnessFrequency(frequency);
+}
+
+
+PxReal Sc::ClothCore::getStiffnessFrequency() const
+{
+ return mLowLevelCloth->getStiffnessFrequency();
+}
+
+void physx::Sc::ClothCore::setStretchConfig(PxClothFabricPhaseType::Enum type, const PxClothStretchConfig& config)
+{
+ cloth::PhaseConfig pc;
+ pc.mStiffness = config.stiffness;
+ pc.mStiffnessMultiplier = config.stiffnessMultiplier;
+ pc.mStretchLimit = config.stretchLimit;
+ pc.mCompressionLimit = config.compressionLimit;
+
+ PxU32 nbPhases = mFabric->getNbPhases();
+ for(PxU32 i=0; i < nbPhases; i++)
+ {
+ // update phase config copies (but preserve existing phase index)
+ if (mFabric->getPhaseType(i) == type)
+ {
+ mPhaseConfigs[i].mStiffness = config.stiffness;
+ mPhaseConfigs[i].mStiffnessMultiplier = config.stiffnessMultiplier;
+ mPhaseConfigs[i].mCompressionLimit = config.compressionLimit;
+ mPhaseConfigs[i].mStretchLimit = config.stretchLimit;
+ }
+ }
+
+ // set to low level
+ cloth::Range<const cloth::PhaseConfig> phaseConfigRange = createRange<const cloth::PhaseConfig>(mPhaseConfigs, nbPhases);
+ mLowLevelCloth->setPhaseConfig(phaseConfigRange);
+}
+
+void Sc::ClothCore::setTetherConfig(const PxClothTetherConfig& config)
+{
+ mLowLevelCloth->setTetherConstraintScale(config.stretchLimit);
+ mLowLevelCloth->setTetherConstraintStiffness(config.stiffness);
+}
+
+PxClothStretchConfig Sc::ClothCore::getStretchConfig(PxClothFabricPhaseType::Enum type) const
+{
+ cloth::PhaseConfig pc;
+ PxU32 nbPhases = mFabric->getNbPhases();
+ for(PxU32 i=0; i < nbPhases; i++)
+ {
+ if (mFabric->getPhaseType(i) == type)
+ {
+ pc = mPhaseConfigs[i];
+ break;
+ }
+ }
+
+ return PxClothStretchConfig(pc.mStiffness, pc.mStiffnessMultiplier, pc.mCompressionLimit, pc.mStretchLimit);
+}
+
+PxClothTetherConfig Sc::ClothCore::getTetherConfig() const
+{
+ return PxClothTetherConfig(
+ mLowLevelCloth->getTetherConstraintStiffness(),
+ mLowLevelCloth->getTetherConstraintScale());
+}
+
+
+void Sc::ClothCore::setClothFlags(PxClothFlags flags)
+{
+ PxClothFlags diff = mClothFlags ^ flags;
+ mClothFlags = flags;
+
+ if((diff & ~flags) & PxClothFlag::eSCENE_COLLISION)
+ getSim()->clearCollisionShapes();
+
+ if(diff & PxClothFlag::eSWEPT_CONTACT)
+ mLowLevelCloth->enableContinuousCollision(flags.isSet(PxClothFlag::eSWEPT_CONTACT));
+
+ if((diff & PxClothFlag::eCUDA) && getSim())
+ getSim()->reinsert();
+}
+
+
+PxClothFlags Sc::ClothCore::getClothFlags() const
+{
+ return mClothFlags;
+}
+
+void Sc::ClothCore::setWindVelocity(PxVec3 value)
+{
+ mLowLevelCloth->setWindVelocity(value);
+}
+PxVec3 Sc::ClothCore::getWindVelocity() const
+{
+ return mLowLevelCloth->getWindVelocity();
+}
+void Sc::ClothCore::setDragCoefficient(PxReal value)
+{
+ mLowLevelCloth->setDragCoefficient(value);
+}
+PxReal Sc::ClothCore::getDragCoefficient() const
+{
+ return mLowLevelCloth->getDragCoefficient();
+}
+void Sc::ClothCore::setLiftCoefficient(PxReal value)
+{
+ mLowLevelCloth->setLiftCoefficient(value);
+}
+PxReal Sc::ClothCore::getLiftCoefficient() const
+{
+ return mLowLevelCloth->getLiftCoefficient();
+}
+
+bool Sc::ClothCore::isSleeping() const
+{
+ return mLowLevelCloth->isAsleep();
+}
+
+
+PxReal Sc::ClothCore::getSleepLinearVelocity() const
+{
+ return mLowLevelCloth->getSleepThreshold();
+}
+
+
+void Sc::ClothCore::setSleepLinearVelocity(PxReal threshold)
+{
+ mLowLevelCloth->setSleepThreshold(threshold); // does wake the cloth up automatically
+}
+
+
+void Sc::ClothCore::setWakeCounter(PxReal wakeCounterValue)
+{
+ if(wakeCounterValue > PX_MAX_U32 / 1000)
+ return mLowLevelCloth->setSleepTestInterval(PX_MAX_U32);
+
+ PxU32 intervalsToSleep = PxU32(wakeCounterValue * 1000);
+
+ // test at least 5 times until sleep, or 5 times per second
+ PxU32 testInterval = PxMax(1u, PxMin(intervalsToSleep / 5, 200u));
+ PxU32 afterCount = intervalsToSleep / testInterval;
+
+ bool wasSleeping = mLowLevelCloth->isAsleep();
+
+ // does wake the cloth up automatically
+ mLowLevelCloth->setSleepTestInterval(testInterval);
+ mLowLevelCloth->setSleepAfterCount(afterCount);
+
+ // setWakeCounter(0) should not change the sleep state, put back to sleep
+ if (wasSleeping && wakeCounterValue == 0.0f)
+ mLowLevelCloth->putToSleep();
+}
+
+PxReal Sc::ClothCore::getWakeCounter() const
+{
+ PxU32 testInterval = mLowLevelCloth->getSleepTestInterval();
+ if(testInterval == PX_MAX_U32)
+ return PX_MAX_REAL;
+
+ PxU32 afterCount = mLowLevelCloth->getSleepAfterCount();
+ PxU32 passCount = mLowLevelCloth->getSleepPassCount();
+
+ if (passCount >= afterCount)
+ return 0.0f;
+
+ return (afterCount - passCount) * testInterval / 1000.0f;
+}
+
+void Sc::ClothCore::wakeUp(PxReal wakeCounter)
+{
+ setWakeCounter(wakeCounter);
+}
+
+
+void Sc::ClothCore::putToSleep()
+{
+ mLowLevelCloth->putToSleep();
+}
+
+
+void Sc::ClothCore::getParticleData(PxClothParticleData& data)
+{
+ if(data.getDataAccessFlags() & PxDataAccessFlag::eDEVICE)
+ {
+ cloth::GpuParticles particles = mLowLevelCloth->getGpuParticles();
+ data.particles = reinterpret_cast<PxClothParticle*>(particles.mCurrent);
+ data.previousParticles = reinterpret_cast<PxClothParticle*>(particles.mPrevious);
+ }
+ else
+ {
+ mLowLevelCloth->lockParticles();
+ // When eWRITABLE flag is set, write happens during PxClothParticleData::unlock()
+ data.particles = reinterpret_cast<PxClothParticle*>(const_cast<PxVec4*>(
+ cloth::readCurrentParticles(*mLowLevelCloth).begin()));
+ data.previousParticles = reinterpret_cast<PxClothParticle*>(const_cast<PxVec4*>(
+ cloth::readPreviousParticles(*mLowLevelCloth).begin()));
+ }
+}
+
+void Sc::ClothCore::unlockParticleData()
+{
+ mLowLevelCloth->unlockParticles();
+}
+
+
+PxReal Sc::ClothCore::getPreviousTimeStep() const
+{
+ return mLowLevelCloth->getPreviousIterationDt();
+}
+
+
+PxBounds3 Sc::ClothCore::getWorldBounds() const
+{
+ const PxVec3& center = reinterpret_cast<const PxVec3&>(mLowLevelCloth->getBoundingBoxCenter());
+ const PxVec3& extent = reinterpret_cast<const PxVec3&>(mLowLevelCloth->getBoundingBoxScale());
+
+ PxBounds3 localBounds = PxBounds3::centerExtents(center, extent);
+
+ PX_ASSERT(!localBounds.isEmpty());
+ return PxBounds3::transformFast(getGlobalPose(), localBounds);
+}
+
+void Sc::ClothCore::setSimulationFilterData(const PxFilterData& data)
+{
+ mFilterData = data;
+}
+
+PxFilterData Sc::ClothCore::getSimulationFilterData() const
+{
+ return mFilterData;
+}
+
+void Sc::ClothCore::setContactOffset(PxReal offset)
+{
+ mContactOffset = offset;
+}
+
+PxReal Sc::ClothCore::getContactOffset() const
+{
+ return mContactOffset;
+}
+
+void Sc::ClothCore::setRestOffset(PxReal offset)
+{
+ mRestOffset = offset;
+}
+
+PxReal Sc::ClothCore::getRestOffset() const
+{
+ return mRestOffset;
+}
+
+Sc::ClothSim* Sc::ClothCore::getSim() const
+{
+ return static_cast<ClothSim*>(Sc::ActorCore::getSim());
+}
+
+PxCloth* Sc::ClothCore::getPxCloth()
+{
+ return gOffsetTable.convertScCloth2Px(this);
+}
+
+void Sc::ClothCore::onOriginShift(const PxVec3& shift)
+{
+ mLowLevelCloth->teleport(-shift);
+}
+
+void Sc::ClothCore::switchCloth(cloth::Cloth* cl)
+{
+ cloth::Fabric* fabric = &mLowLevelCloth->getFabric();
+ cloth::Factory::Platform platform = mLowLevelCloth->getFactory().getPlatform();
+
+ PX_DELETE(mLowLevelCloth);
+ mLowLevelCloth = cl;
+
+ // delete fabric if referenced by no lowlevel Cloth or ClothFabricCore.
+ if (0 == fabric->getRefCount())
+ {
+ if(platform != cloth::Factory::CPU)
+ mFabric->setLowLevelGpuFabric(NULL);
+ PX_DELETE(fabric);
+ }
+
+ if(cl->getFactory().getPlatform() != cloth::Factory::CPU)
+ mFabric->setLowLevelGpuFabric(&cl->getFabric());
+}
+
+#endif // PX_USE_CLOTH_API
diff --git a/PhysX_3.4/Source/SimulationController/src/cloth/ScClothFabricCore.cpp b/PhysX_3.4/Source/SimulationController/src/cloth/ScClothFabricCore.cpp
new file mode 100644
index 00000000..a195b337
--- /dev/null
+++ b/PhysX_3.4/Source/SimulationController/src/cloth/ScClothFabricCore.cpp
@@ -0,0 +1,432 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#include "ScClothFabricCore.h"
+#if PX_USE_CLOTH_API
+
+using namespace physx;
+using namespace cloth;
+
+#include "foundation/PxAssert.h"
+#include "ScPhysics.h"
+#include "Range.h"
+#include "Factory.h"
+#include "Fabric.h"
+#include "GuSerialize.h"
+#include "CmPhysXCommon.h"
+#include "CmUtils.h"
+#include "PsAlloca.h"
+#include "PsFoundation.h"
+
+Sc::ClothFabricCore::ClothFabricCore(const PxEMPTY)
+ : mLowLevelGpuFabric(NULL), mPhaseTypes(PxEmpty)
+{
+}
+
+Sc::ClothFabricCore::ClothFabricCore() :
+ mLowLevelFabric(NULL), mLowLevelGpuFabric(NULL)
+{
+}
+
+
+Sc::ClothFabricCore::~ClothFabricCore()
+{
+ if(mLowLevelFabric)
+ {
+ mLowLevelFabric->decRefCount();
+ if (0 == mLowLevelFabric->getRefCount())
+ PX_DELETE(mLowLevelFabric);
+ }
+}
+
+
+// PX_SERIALIZATION
+void Sc::ClothFabricBulkData::exportExtraData(PxSerializationContext& context)
+{
+ Cm::exportArray(mPhases, context);
+ Cm::exportArray(mSets, context);
+ Cm::exportArray(mRestvalues, context);
+ Cm::exportArray(mIndices, context);
+ Cm::exportArray(mTetherAnchors, context);
+ Cm::exportArray(mTetherLengths, context);
+ Cm::exportArray(mTriangles, context);
+}
+
+void Sc::ClothFabricBulkData::importExtraData(PxDeserializationContext& context)
+{
+ Cm::importArray(mPhases, context);
+ Cm::importArray(mSets, context);
+ Cm::importArray(mRestvalues, context);
+ Cm::importArray(mIndices, context);
+ Cm::importArray(mTetherAnchors, context);
+ Cm::importArray(mTetherLengths, context);
+ Cm::importArray(mTriangles, context);
+}
+
+void Sc::ClothFabricCore::exportExtraData(PxSerializationContext& stream)
+{
+ Cm::exportArray(mPhaseTypes, stream);
+
+ if(!mLowLevelFabric)
+ return;
+
+ PX_ALLOCA(buf, ClothFabricBulkData, 1);
+ Cm::markSerializedMem(buf, sizeof(ClothFabricBulkData));
+ ClothFabricBulkData* bulkData = PX_PLACEMENT_NEW(buf, ClothFabricBulkData);
+
+ cloth::Factory& factory = Sc::Physics::getInstance().getLowLevelClothFactory();
+
+ bulkData->mNbParticles = mLowLevelFabric->getNumParticles();
+ bulkData->mPhases.resize(mLowLevelFabric->getNumPhases());
+ bulkData->mSets.resize(mLowLevelFabric->getNumSets());
+ bulkData->mRestvalues.resize(mLowLevelFabric->getNumRestvalues());
+ bulkData->mIndices.resize(mLowLevelFabric->getNumIndices());
+ bulkData->mTetherAnchors.reserve(mLowLevelFabric->getNumTethers());
+ bulkData->mTetherLengths.reserve(mLowLevelFabric->getNumTethers());
+ bulkData->mTriangles.resize(mLowLevelFabric->getNumTriangles() * 3);
+
+ factory.extractFabricData(*mLowLevelFabric,
+ cloth::Range<uint32_t>(bulkData->mPhases.begin(), bulkData->mPhases.end()),
+ Range<uint32_t>(bulkData->mSets.begin(), bulkData->mSets.end()),
+ Range<float>(bulkData->mRestvalues.begin(), bulkData->mRestvalues.end()),
+ Range<uint32_t>(bulkData->mIndices.begin(), bulkData->mIndices.end()),
+ Range<uint32_t>(bulkData->mTetherAnchors.begin(), bulkData->mTetherAnchors.end()),
+ Range<float>(bulkData->mTetherLengths.begin(), bulkData->mTetherLengths.end()),
+ Range<uint32_t>(bulkData->mTriangles.begin(), bulkData->mTriangles.end()));
+
+ stream.writeData(bulkData, sizeof(ClothFabricBulkData));
+ bulkData->exportExtraData(stream);
+ bulkData->~ClothFabricBulkData();
+}
+
+
+void Sc::ClothFabricCore::importExtraData(PxDeserializationContext& context)
+{
+ Cm::importArray(mPhaseTypes, context);
+
+ if(mLowLevelFabric)
+ {
+ ClothFabricBulkData* bulkData = context.readExtraData<ClothFabricBulkData>();
+ bulkData->importExtraData(context);
+
+ cloth::Factory& factory = Sc::Physics::getInstance().getLowLevelClothFactory();
+
+ mLowLevelFabric = factory.createFabric(bulkData->mNbParticles,
+ cloth::Range<const uint32_t>(bulkData->mPhases.begin(), bulkData->mPhases.end()),
+ cloth::Range<const uint32_t>(bulkData->mSets.begin(), bulkData->mSets.end()),
+ Range<const float>(bulkData->mRestvalues.begin(), bulkData->mRestvalues.end()),
+ Range<const uint32_t>(bulkData->mIndices.begin(), bulkData->mIndices.end()),
+ Range<const uint32_t>(bulkData->mTetherAnchors.begin(), bulkData->mTetherAnchors.end()),
+ Range<const float>(bulkData->mTetherLengths.begin(), bulkData->mTetherLengths.end()),
+ Range<const uint32_t>(bulkData->mTriangles.begin(), bulkData->mTriangles.end()));
+
+ mLowLevelFabric->incRefCount(); // account for the user reference
+ }
+}
+//~PX_SERIALIZATION
+
+/**
+ Load cloth fabric data from the given stream.
+
+ @param[in] stream input stream to load fabric data from
+ @return true if loading was successful
+
+ @sa For cooker implementation, see ClothFabricBuilder.cpp in PhysXCooking/src
+ */
+bool Sc::ClothFabricCore::load(PxInputStream& stream)
+{
+ // Import header
+ PxU32 version;
+
+ stream.read(&version, sizeof(PxU32));
+
+ // check if incompatible version is used. Version number changed
+ // from PX_PHYSICS_VERSION to ordinal number in 3.3.2.
+ // see ExtClothFabricCooker.cpp (PxFabricCookerImpl::save)
+ if (version != 0x030300 && version != 0x030301 && version != 1)
+ {
+ Ps::getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __LINE__,
+ "Loading cloth fabric failed: mismatching version of cloth fabric stream.");
+ return false;
+ }
+
+ PxClothFabricDesc desc;
+
+ stream.read(&desc.nbParticles, sizeof(PxU32));
+ stream.read(&desc.nbPhases, sizeof(PxU32));
+ stream.read(&desc.nbSets, sizeof(PxU32));
+ stream.read(&desc.nbTethers, sizeof(PxU32));
+
+ Ps::Array<PxClothFabricPhase> phases(desc.nbPhases);
+ PX_ASSERT(sizeof(PxClothFabricPhaseType::Enum) == sizeof(PxU32));
+ stream.read(phases.begin(), desc.nbPhases * sizeof(PxClothFabricPhase));
+ desc.phases = phases.begin();
+
+ Ps::Array<PxU32> sets(desc.nbSets);
+ stream.read(sets.begin(), desc.nbSets * sizeof(PxU32));
+ desc.sets = sets.begin();
+
+ PxU32 nbRestvalues = sets.back();
+ Ps::Array<PxReal> restvalues(nbRestvalues);
+ stream.read(restvalues.begin(), nbRestvalues * sizeof(PxReal));
+ desc.restvalues = restvalues.begin();
+
+ PxU32 nbParticleIndices = nbRestvalues * 2;
+ Ps::Array<PxU32> indices(nbParticleIndices);
+ stream.read(indices.begin(), nbParticleIndices * sizeof(PxU32));
+ desc.indices = indices.begin();
+
+ Ps::Array<PxU32> tetherAnchors(desc.nbTethers);
+ stream.read(tetherAnchors.begin(), desc.nbTethers * sizeof(PxU32));
+ desc.tetherAnchors = tetherAnchors.begin();
+
+ Ps::Array<PxReal> tetherLengths(desc.nbTethers);
+ stream.read(tetherLengths.begin(), desc.nbTethers * sizeof(PxReal));
+ desc.tetherLengths = tetherLengths.begin();
+
+ return load(desc);
+}
+
+bool Sc::ClothFabricCore::load(const PxClothFabricDesc& desc)
+{
+ PX_ASSERT( desc.isValid() );
+
+ // allocate array
+ //!!!CL could be optimized by creating a single buffer that can hold all data. Would have to sacrifice the PxArrays but they don't
+ // seem very useful in this case anyway because it is mostly const data.
+
+ mPhaseTypes.resize(desc.nbPhases);
+ Ps::Array<PxU32> llphases(desc.nbPhases);
+ Ps::Array<PxU32> offsets(desc.nbPhases);
+
+ for(PxU32 i=0; i<desc.nbPhases; ++i)
+ {
+ if (desc.phases[i].phaseType == PxClothFabricPhaseType::eINVALID ||
+ desc.phases[i].phaseType >= PxClothFabricPhaseType::eCOUNT)
+ {
+ Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__,
+ "createClothFabric() failed, invalid phase type specified");
+
+ return false;
+ }
+
+ mPhaseTypes[i] = desc.phases[i].phaseType;
+ llphases[i] = desc.phases[i].setIndex;
+ }
+
+ cloth::Factory& factory = Sc::Physics::getInstance().getLowLevelClothFactory();
+
+ PxU32 nbConstraints = desc.sets[desc.nbSets-1];
+
+ mLowLevelFabric = factory.createFabric(desc.nbParticles,
+ cloth::Range<const uint32_t>(llphases.begin(), llphases.end()),
+ cloth::Range<const uint32_t>(desc.sets, desc.sets + desc.nbSets),
+ cloth::Range<const float>(desc.restvalues, desc.restvalues + nbConstraints),
+ cloth::Range<const uint32_t>(desc.indices, desc.indices + 2*nbConstraints),
+ cloth::Range<const uint32_t>(desc.tetherAnchors, desc.tetherAnchors + desc.nbTethers),
+ cloth::Range<const float>(desc.tetherLengths, desc.tetherLengths + desc.nbTethers),
+ cloth::Range<const uint32_t>(desc.triangles, desc.triangles + 3 * desc.nbTriangles));
+
+ mLowLevelFabric->incRefCount(); // account for the user reference
+
+ return true;
+}
+
+/**
+ returns number of particles
+ */
+PxU32 Sc::ClothFabricCore::getNbParticles() const
+{
+ return mLowLevelFabric->getNumParticles();
+}
+
+PxU32 Sc::ClothFabricCore::getNbPhases() const
+{
+ return mLowLevelFabric->getNumPhases();
+}
+
+/**
+ This function returns number of sets
+ @return number of phases
+ */
+PxU32 Sc::ClothFabricCore::getNbSets() const
+{
+ return mLowLevelFabric->getNumSets();
+}
+
+/**
+ get total number of particle (vertex) indices in the fabric array.
+ */
+PxU32 Sc::ClothFabricCore::getNbParticleIndices() const
+{
+ return mLowLevelFabric->getNumIndices();
+}
+
+/**
+ get total number of rest length array
+ */
+PxU32 Sc::ClothFabricCore::getNbRestvalues() const
+{
+ return mLowLevelFabric->getNumRestvalues();
+}
+
+PxU32 Sc::ClothFabricCore::getNbTethers() const
+{
+ return mLowLevelFabric->getNumTethers();
+}
+
+PxU32 Sc::ClothFabricCore::getPhases(PxClothFabricPhase* userPhaseBuffer, PxU32 bufferSize) const
+{
+ // calculate buffer size
+ PxU32 nbPhases = getNbPhases();
+ if (bufferSize < nbPhases)
+ return 0;
+
+ shdfnd::Array<PxU32> phases(nbPhases);
+
+ cloth::Factory& factory = Sc::Physics::getInstance().getLowLevelClothFactory();
+
+ factory.extractFabricData(*mLowLevelFabric,
+ cloth::Range<uint32_t>(phases.begin(), phases.end()),
+ Range<uint32_t>(), Range<float>(), Range<uint32_t>(),
+ Range<uint32_t>(), Range<float>(), Range<uint32_t>());
+
+ for(PxU32 i=0; i<nbPhases; ++i)
+ {
+ userPhaseBuffer[i].setIndex = phases[i];
+ userPhaseBuffer[i].phaseType = mPhaseTypes[i];
+ }
+
+ return nbPhases;
+}
+
+PxU32 Sc::ClothFabricCore::getRestvalues(PxReal* userRestvalueBuffer, PxU32 bufferSize) const
+{
+ // calculate buffer size
+ PxU32 nbRestvalues = getNbRestvalues();
+ if (bufferSize < nbRestvalues)
+ return 0;
+
+ cloth::Factory& factory = Sc::Physics::getInstance().getLowLevelClothFactory();
+
+ factory.extractFabricData(*mLowLevelFabric,
+ cloth::Range<uint32_t>(), cloth::Range<uint32_t>(),
+ Range<float>(userRestvalueBuffer, userRestvalueBuffer + nbRestvalues),
+ Range<uint32_t>(), Range<uint32_t>(), Range<float>(), Range<uint32_t>());
+
+ return nbRestvalues;
+}
+
+PxU32 Sc::ClothFabricCore::getSets(PxU32* userSetBuffer, PxU32 bufferSize) const
+{
+ // calculate buffer size
+ const PxU32 nbSets = getNbSets();
+ if (bufferSize < nbSets)
+ return 0;
+
+ cloth::Factory& factory = Sc::Physics::getInstance().getLowLevelClothFactory();
+
+ factory.extractFabricData(*mLowLevelFabric,
+ cloth::Range<uint32_t>(), Range<uint32_t>(userSetBuffer, userSetBuffer + nbSets),
+ Range<float>(), Range<uint32_t>(), Range<uint32_t>(), Range<float>(), Range<uint32_t>());
+
+ return nbSets;
+}
+
+PxU32 Sc::ClothFabricCore::getParticleIndices(PxU32* userParticleIndexBuffer, PxU32 bufferSize) const
+{
+ // calculate buffer size
+ const PxU32 nbParticleIndices = getNbParticleIndices();
+ if (bufferSize < nbParticleIndices)
+ return 0;
+
+ cloth::Factory& factory = Sc::Physics::getInstance().getLowLevelClothFactory();
+
+ factory.extractFabricData(*mLowLevelFabric,
+ cloth::Range<uint32_t>(), cloth::Range<uint32_t>(), Range<float>(),
+ Range<uint32_t>(userParticleIndexBuffer, userParticleIndexBuffer + nbParticleIndices),
+ Range<uint32_t>(), Range<float>(), Range<uint32_t>());
+
+ return nbParticleIndices;
+}
+
+PxU32 Sc::ClothFabricCore::getTetherAnchors(PxU32* userAnchorBuffer, PxU32 bufferSize) const
+{
+ // calculate buffer size
+ const PxU32 nbTethers = getNbTethers();
+ if (bufferSize < nbTethers)
+ return 0;
+
+ cloth::Factory& factory = Sc::Physics::getInstance().getLowLevelClothFactory();
+
+ factory.extractFabricData(*mLowLevelFabric,
+ cloth::Range<uint32_t>(), cloth::Range<uint32_t>(),
+ Range<float>(), Range<uint32_t>(),
+ Range<uint32_t>(userAnchorBuffer, userAnchorBuffer + nbTethers), Range<float>(), Range<uint32_t>());
+
+ return nbTethers;
+}
+
+PxU32 Sc::ClothFabricCore::getTetherLengths(PxReal* userLengthBuffer, PxU32 bufferSize) const
+{
+ // calculate buffer size
+ const PxU32 nbTethers = getNbTethers();
+ if (bufferSize < nbTethers)
+ return 0;
+
+ cloth::Factory& factory = Sc::Physics::getInstance().getLowLevelClothFactory();
+
+ factory.extractFabricData(*mLowLevelFabric,
+ cloth::Range<uint32_t>(), cloth::Range<uint32_t>(),
+ Range<float>(), Range<uint32_t>(), Range<uint32_t>(),
+ Range<float>(userLengthBuffer, userLengthBuffer + nbTethers), Range<uint32_t>());
+
+ return nbTethers;
+}
+
+/**
+ scale the rest length of constraints by given value.
+
+ @param[in] scale The scale factor (each rest length is multiplied by this value)
+ */
+void Sc::ClothFabricCore::scaleRestlengths(PxReal scale)
+{
+ mLowLevelFabric->scaleRestvalues(scale);
+ mLowLevelFabric->scaleTetherLengths(scale);
+
+ if(mLowLevelGpuFabric)
+ {
+ mLowLevelGpuFabric->scaleRestvalues(scale);
+ mLowLevelGpuFabric->scaleTetherLengths(scale);
+ }
+}
+
+
+#endif // PX_USE_CLOTH_API
diff --git a/PhysX_3.4/Source/SimulationController/src/cloth/ScClothShape.cpp b/PhysX_3.4/Source/SimulationController/src/cloth/ScClothShape.cpp
new file mode 100644
index 00000000..1d89d13f
--- /dev/null
+++ b/PhysX_3.4/Source/SimulationController/src/cloth/ScClothShape.cpp
@@ -0,0 +1,125 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#include "ScClothShape.h"
+#if PX_USE_CLOTH_API
+
+#include "ScNPhaseCore.h"
+#include "ScScene.h"
+
+#include "ScClothSim.h"
+#include "PxsContext.h"
+#include "BpSimpleAABBManager.h"
+#include "ScSqBoundsManager.h"
+
+using namespace physx;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+Sc::ClothShape::ClothShape(ClothSim& cloth) :
+ ElementSim(cloth, ElementType::eCLOTH),
+ mClothCore(cloth.getCore()),
+ mHasCollision(mClothCore.getClothFlags() & PxClothFlag::eSCENE_COLLISION)
+{
+ if (mHasCollision)
+ createLowLevelVolume();
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+Sc::ClothShape::~ClothShape()
+{
+ if (isInBroadPhase())
+ destroyLowLevelVolume();
+
+ PX_ASSERT(!isInBroadPhase());
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void Sc::ClothShape::getFilterInfo(PxFilterObjectAttributes& filterAttr, PxFilterData& filterData) const
+{
+ filterAttr = 0;
+ ElementSim::setFilterObjectAttributeType(filterAttr, PxFilterObjectType::eCLOTH);
+ filterData = mClothCore.getSimulationFilterData();
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void Sc::ClothShape::updateBoundsInAABBMgr()
+{
+ if(~mClothCore.getClothFlags() & PxClothFlag::eSCENE_COLLISION)
+ {
+ if(mHasCollision)
+ {
+ destroyLowLevelVolume();
+ mHasCollision = false;
+ }
+ return;
+ }
+
+ if(!mHasCollision)
+ {
+ createLowLevelVolume();
+ mHasCollision = true;
+ }
+
+ Scene& scene = getScene();
+
+ PxBounds3 worldBounds = mClothCore.getWorldBounds();
+ worldBounds.fattenSafe(mClothCore.getContactOffset()); // fatten for fast moving colliders
+ scene.getBoundsArray().setBounds(worldBounds, getElementID());
+ scene.getAABBManager()->getChangedAABBMgActorHandleMap().growAndSet(getElementID());
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void Sc::ClothShape::createLowLevelVolume()
+{
+ PX_ASSERT(getWorldBounds().isFinite());
+ getScene().getBoundsArray().setBounds(getWorldBounds(), getElementID());
+ addToAABBMgr(0, Bp::FilterGroup::eCLOTH_NO_PARTICLE_INTERACTION, false);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void Sc::ClothShape::destroyLowLevelVolume()
+{
+ if (!isInBroadPhase())
+ return;
+
+ Sc::Scene& scene = getScene();
+ PxsContactManagerOutputIterator outputs = scene.getLowLevelContext()->getNphaseImplementationContext()->getContactManagerOutputs();
+ scene.getNPhaseCore()->onVolumeRemoved(this, 0, outputs, scene.getPublicFlags() & PxSceneFlag::eADAPTIVE_FORCE);
+ removeFromAABBMgr();
+}
+
+
+#endif // PX_USE_CLOTH_API
diff --git a/PhysX_3.4/Source/SimulationController/src/cloth/ScClothShape.h b/PhysX_3.4/Source/SimulationController/src/cloth/ScClothShape.h
new file mode 100644
index 00000000..fc3e3735
--- /dev/null
+++ b/PhysX_3.4/Source/SimulationController/src/cloth/ScClothShape.h
@@ -0,0 +1,78 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 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 PX_PHYSICS_CLOTHSHAPE
+#define PX_PHYSICS_CLOTHSHAPE
+
+#include "CmPhysXCommon.h"
+#include "PxPhysXConfig.h"
+#if PX_USE_CLOTH_API
+
+#include "ScElementSim.h"
+#include "ScClothCore.h"
+
+namespace physx
+{
+namespace Sc
+{
+ /**
+ A collision detection primitive for cloth.
+ */
+ class ClothShape : public ElementSim
+ {
+ ClothShape &operator=(const ClothShape &);
+ public:
+ ClothShape(ClothSim& cloth);
+ ~ClothShape();
+
+ // ElementSim implementation
+ virtual void getFilterInfo(PxFilterObjectAttributes& filterAttr, PxFilterData& filterData) const;
+ // ~ElementSim
+
+ public:
+ PX_INLINE PxBounds3 getWorldBounds() const { return mClothCore.getWorldBounds(); }
+ PX_INLINE ClothSim& getClothSim() const { return *mClothCore.getSim(); }
+
+ void updateBoundsInAABBMgr();
+
+ void createLowLevelVolume();
+ void destroyLowLevelVolume();
+ private:
+ ClothCore& mClothCore;
+ bool mHasCollision;
+ };
+
+} // namespace Sc
+
+}
+
+#endif // PX_USE_CLOTH_API
+
+#endif
diff --git a/PhysX_3.4/Source/SimulationController/src/cloth/ScClothSim.cpp b/PhysX_3.4/Source/SimulationController/src/cloth/ScClothSim.cpp
new file mode 100644
index 00000000..0306f2cc
--- /dev/null
+++ b/PhysX_3.4/Source/SimulationController/src/cloth/ScClothSim.cpp
@@ -0,0 +1,894 @@
+// 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-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#include "ScClothSim.h"
+#if PX_USE_CLOTH_API
+
+#include "PxClothParticleData.h"
+#include "PxConvexMesh.h"
+#include "PxTriangleMesh.h"
+#include "PxHeightField.h"
+#include "PxHeightFieldSample.h"
+
+#include "ScPhysics.h"
+#include "ScScene.h"
+#include "ScClothCore.h"
+#include "ScShapeSim.h"
+
+#include "CmScaling.h"
+
+#include "Types.h"
+#include "Range.h"
+#include "Factory.h"
+#include "Cloth.h"
+
+#include "GuIntersectionTriangleBox.h"
+#include "ScNPhaseCore.h"
+#include "PsFoundation.h"
+
+using namespace physx;
+
+namespace
+{
+ template <typename D, typename S>
+ PX_FORCE_INLINE cloth::Range<D> createRange(S begin, PxU32 size)
+ {
+ D* start = reinterpret_cast<D*>(begin);
+ D* end = start + size;
+
+ return cloth::Range<D>(start, end);
+ }
+}
+
+Sc::ClothSim::ClothSim(Scene& scene, ClothCore& core) :
+ ActorSim(scene, core),
+ mClothShape(*this),
+ mNumSpheres(0),
+ mNumCapsules(0),
+ mNumPlanes(0),
+ mNumBoxes(0),
+ mNumConvexes(0),
+ mNumMeshes(0),
+ mNumHeightfields(0),
+ mNumConvexPlanes(0)
+{
+ startStep(); // sync lowlevel gravity to prevent waking up on simulate()
+}
+
+
+Sc::ClothSim::~ClothSim()
+{
+ getCore().setSim(NULL);
+}
+
+
+Sc::ClothCore& Sc::ClothSim::getCore() const
+{
+ return static_cast<ClothCore&>(getActorCore());
+}
+
+void Sc::ClothSim::updateBounds()
+{
+ mClothShape.updateBoundsInAABBMgr();
+}
+
+void Sc::ClothSim::startStep()
+{
+ updateRigidBodyPositions();
+
+ // update total external acceleration in LL
+ PxVec3 externalAcceleration = getCore().getExternalAcceleration();
+ if ((getActorCore().getActorFlags() & PxActorFlag::eDISABLE_GRAVITY) == false)
+ externalAcceleration += getScene().getGravity();
+ getCore().getLowLevelCloth()->setGravity(externalAcceleration);
+}
+
+
+void Sc::ClothSim::reinsert()
+{
+ Sc::Scene& scene = getScene();
+ Sc::ClothCore& core = getCore();
+
+ scene.removeCloth(core);
+ scene.addCloth(core);
+}
+
+bool Sc::ClothSim::addCollisionShape(const ShapeSim* shape)
+{
+ switch (shape->getGeometryType())
+ {
+ case PxGeometryType::eSPHERE:
+ return addCollisionSphere(shape);
+ case PxGeometryType::ePLANE:
+ return addCollisionPlane(shape);
+ case PxGeometryType::eCAPSULE:
+ return addCollisionCapsule(shape);
+ case PxGeometryType::eBOX:
+ return addCollisionBox(shape);
+ case PxGeometryType::eCONVEXMESH:
+ return addCollisionConvex(shape);
+ case PxGeometryType::eTRIANGLEMESH:
+ return addCollisionMesh(shape);
+ case PxGeometryType::eHEIGHTFIELD:
+ return addCollisionHeightfield(shape);
+ case PxGeometryType::eGEOMETRY_COUNT:
+ case PxGeometryType::eINVALID:
+ break;
+ }
+ return false;
+}
+
+void Sc::ClothSim::removeCollisionShape(const ShapeSim* shape)
+{
+ switch (shape->getGeometryType())
+ {
+ case PxGeometryType::eSPHERE:
+ removeCollisionSphere(shape);
+ break;
+ case PxGeometryType::ePLANE:
+ removeCollisionPlane(shape);
+ break;
+ case PxGeometryType::eCAPSULE:
+ removeCollisionCapsule(shape);
+ break;
+ case PxGeometryType::eBOX:
+ removeCollisionBox(shape);
+ break;
+ case PxGeometryType::eCONVEXMESH:
+ removeCollisionConvex(shape);
+ break;
+ case PxGeometryType::eTRIANGLEMESH:
+ removeCollisionMesh(shape);
+ break;
+ case PxGeometryType::eHEIGHTFIELD:
+ removeCollisionHeightfield(shape);
+ break;
+ case PxGeometryType::eGEOMETRY_COUNT:
+ case PxGeometryType::eINVALID:
+ break;
+ }
+}
+
+bool Sc::ClothSim::addCollisionSphere(const ShapeSim* shape)
+{
+ PxU32 startIndex = 0;
+
+#if PX_DEBUG
+ const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex;
+ for (PxU32 index = 0; index<mNumSpheres; ++index)
+ PX_ASSERT(shapeIt[index] != shape);
+#endif
+
+ ClothCore& core = getCore();
+
+ PxU32 sphereIndex = core.mNumUserSpheres + mNumSpheres;
+ if(sphereIndex >= 32)
+ {
+ Ps::getFoundation().error(PX_WARN, "Dropping collision sphere due to 32 sphere limit");
+ return false;
+ }
+
+ // current position here is before simulation
+ const PxSphereGeometry& geometry = static_cast<const PxSphereGeometry&>(shape->getCore().getGeometry());
+
+ PX_ALIGN(16, PxTransform globalPose);
+ shape->getAbsPoseAligned(&globalPose);
+
+ PxTransform trafo = core.getGlobalPose().transformInv(globalPose);
+ PxVec3 center = trafo.p;
+ PxVec4 sphere(center, geometry.radius);
+
+ core.getLowLevelCloth()->setSpheres(createRange<const PxVec4>(&sphere, 1), sphereIndex, sphereIndex);
+
+ insertShapeSim(startIndex + mNumSpheres++, shape);
+ return true;
+}
+
+void Sc::ClothSim::removeCollisionSphere(const ShapeSim* shape)
+{
+ ClothCore& core = getCore();
+
+ PxU32 startIndex = 0;
+ const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex;
+ for (PxU32 index = 0; index<mNumSpheres; ++index)
+ {
+ if (shapeIt[index] == shape)
+ {
+ mShapeSims.remove(startIndex + index);
+ --mNumSpheres;
+ PxU32 sphereIndex = core.mNumUserSpheres + index;
+ core.getLowLevelCloth()->setSpheres(cloth::Range<const PxVec4>(), sphereIndex, sphereIndex+1);
+ break;
+ }
+ }
+}
+
+bool Sc::ClothSim::addCollisionCapsule( const ShapeSim* shape )
+{
+ PxU32 startIndex = mNumSpheres;
+
+#if PX_DEBUG
+ const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex;
+ for (PxU32 index = 0; index<mNumCapsules; ++index)
+ PX_ASSERT(shapeIt[index] != shape);
+#endif
+
+ ClothCore& core = getCore();
+
+ PxU32 capsuleIndex = core.mNumUserCapsules + mNumCapsules;
+ if(capsuleIndex >= 32)
+ {
+ Ps::getFoundation().error(PX_WARN, "Dropping collision capsule due to 32 capsule limit");
+ return false;
+ }
+
+ PxU32 sphereIndex = core.mNumUserSpheres + mNumSpheres + 2*mNumCapsules;
+ if(sphereIndex >= 32)
+ {
+ Ps::getFoundation().error(PX_WARN, "Dropping collision capsule due to 32 sphere limit");
+ return false;
+ }
+
+ // current position here is before simulation
+ const PxCapsuleGeometry& geometry = static_cast<const PxCapsuleGeometry&>(shape->getCore().getGeometry());
+
+ PX_ALIGN(16, PxTransform globalPose);
+ shape->getAbsPoseAligned(&globalPose);
+
+ PxTransform trafo = core.getGlobalPose().transformInv(globalPose);
+ PxVec3 center = trafo.p;
+ PxVec3 direction = trafo.q.rotate(PxVec3(geometry.halfHeight, 0, 0));
+ PxReal radius = geometry.radius;
+ PxVec4 spheres[2] = { PxVec4(center-direction, radius), PxVec4(center+direction, radius) } ;
+
+ core.getLowLevelCloth()->setSpheres(createRange<const PxVec4>(&spheres, 2), sphereIndex, sphereIndex);
+ PxU32 indices[2] = { sphereIndex, sphereIndex+1 };
+ core.getLowLevelCloth()->setCapsules(createRange<PxU32>(indices, 2), capsuleIndex, capsuleIndex);
+
+ insertShapeSim(startIndex + mNumCapsules++, shape);
+ return true;
+}
+
+void Sc::ClothSim::removeCollisionCapsule( const ShapeSim* shape )
+{
+ ClothCore& core = getCore();
+
+ PxU32 startIndex = mNumSpheres;
+ const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex;
+ for (PxU32 index = 0; index<mNumCapsules; ++index)
+ {
+ if (shapeIt[index] == shape)
+ {
+ mShapeSims.remove(startIndex + index);
+ --mNumCapsules;
+ PxU32 sphereIndex = core.mNumUserSpheres + mNumSpheres + 2*index;
+ core.getLowLevelCloth()->setSpheres(cloth::Range<const PxVec4>(), sphereIndex, sphereIndex+2);
+ // capsule is being removed automatically
+ break;
+ }
+ }
+}
+
+bool Sc::ClothSim::addCollisionPlane( const ShapeSim* shape )
+{
+ PxU32 startIndex = mNumSpheres + mNumCapsules;
+
+#if PX_DEBUG
+ const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex;
+ for (PxU32 index = 0; index<mNumPlanes; ++index)
+ PX_ASSERT(shapeIt[index] != shape);
+#endif
+
+ ClothCore& core = getCore();
+
+ PxU32 planeIndex = core.mNumUserPlanes + mNumPlanes;
+ if(planeIndex >= 32)
+ {
+ Ps::getFoundation().error(PX_WARN, "Dropping collision plane due to 32 plane limit");
+ return false;
+ }
+
+ // current position here is before simulation
+ PX_ALIGN(16, PxTransform globalPose);
+ shape->getAbsPoseAligned(&globalPose);
+
+ PxTransform trafo = core.getGlobalPose().transformInv(globalPose);
+ PxPlane plane = PxPlaneEquationFromTransform(trafo);
+
+ const PxVec4* data = reinterpret_cast<const PxVec4*>(&plane);
+ core.getLowLevelCloth()->setPlanes(createRange<const PxVec4>(data, 1), planeIndex, planeIndex);
+ PxU32 convexIndex = core.mNumUserConvexes + mNumPlanes;
+ PxU32 convexMask = PxU32(0x1 << planeIndex);
+ core.getLowLevelCloth()->setConvexes(createRange<const PxU32>(&convexMask, 1), convexIndex, convexIndex);
+
+ insertShapeSim(startIndex + mNumPlanes++, shape);
+ return true;
+}
+
+void Sc::ClothSim::removeCollisionPlane( const ShapeSim* shape )
+{
+ ClothCore& core = getCore();
+
+ PxU32 startIndex = mNumSpheres + mNumCapsules;
+ const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex;
+ for (PxU32 index = 0; index<mNumPlanes; ++index)
+ {
+ if (shapeIt[index] == shape)
+ {
+ mShapeSims.remove(startIndex + index);
+ --mNumPlanes;
+ PxU32 planeIndex = core.mNumUserPlanes + index;
+ core.getLowLevelCloth()->setPlanes(cloth::Range<const PxVec4>(), planeIndex, planeIndex+1);
+ // convex is being removed automatically
+ break;
+ }
+ }
+}
+
+bool Sc::ClothSim::addCollisionBox( const ShapeSim* shape )
+{
+ PxU32 startIndex = mNumSpheres + mNumCapsules + mNumPlanes;
+
+#if PX_DEBUG
+ const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex;
+ for (PxU32 index = 0; index<mNumBoxes; ++index)
+ PX_ASSERT(shapeIt[index] != shape);
+#endif
+
+ ClothCore& core = getCore();
+
+ PxU32 planeIndex = core.mNumUserPlanes + mNumPlanes + 6*mNumBoxes;
+ if(planeIndex+6 > 32)
+ {
+ Ps::getFoundation().error(PX_WARN, "Dropping collision box due to 32 plane limit");
+ return false;
+ }
+
+ // current position here is before simulation
+ const PxBoxGeometry& geometry = static_cast<const PxBoxGeometry&>(shape->getCore().getGeometry());
+ PX_ALIGN(16, PxTransform globalPose);
+ shape->getAbsPoseAligned(&globalPose);
+ PxTransform trafo = core.getGlobalPose().transformInv(globalPose);
+ PxVec3 halfExtents = geometry.halfExtents;
+ PxPlane planes[6] = {
+ trafo.transform(PxPlane(PxVec3( 1.f, 0, 0), -halfExtents.x)),
+ trafo.transform(PxPlane(PxVec3(-1.f, 0, 0), -halfExtents.x)),
+ trafo.transform(PxPlane(PxVec3( 0, 1.f, 0), -halfExtents.y)),
+ trafo.transform(PxPlane(PxVec3( 0, -1.f, 0), -halfExtents.y)),
+ trafo.transform(PxPlane(PxVec3( 0, 0, 1.f), -halfExtents.z)),
+ trafo.transform(PxPlane(PxVec3( 0, 0, -1.f), -halfExtents.z)),
+ };
+
+ core.getLowLevelCloth()->setPlanes(createRange<const PxVec4>(&planes, 6), planeIndex, planeIndex);
+ PxU32 convexIndex = core.mNumUserConvexes + mNumPlanes + mNumBoxes;
+ PxU32 convexMask = PxU32(0x3f << planeIndex);
+ core.getLowLevelCloth()->setConvexes(createRange<const PxU32>(&convexMask, 1), convexIndex, convexIndex);
+
+ insertShapeSim(startIndex + mNumBoxes++, shape);
+ return true;
+}
+
+void Sc::ClothSim::removeCollisionBox( const ShapeSim* shape )
+{
+ ClothCore& core = getCore();
+
+ PxU32 startIndex = mNumSpheres + mNumCapsules + mNumPlanes;
+ const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex;
+ for (PxU32 index = 0; index<mNumBoxes; ++index)
+ {
+ if (shapeIt[index] == shape)
+ {
+ mShapeSims.remove(startIndex + index);
+ --mNumBoxes;
+ PxU32 planeIndex = core.mNumUserPlanes + mNumPlanes + 6*index;
+ core.getLowLevelCloth()->setPlanes(cloth::Range<const PxVec4>(), planeIndex, planeIndex+6);
+ // convex is being removed automatically
+ break;
+ }
+ }
+}
+
+bool Sc::ClothSim::addCollisionConvex( const ShapeSim* shape )
+{
+ PxU32 startIndex = mNumSpheres + mNumCapsules + mNumPlanes + mNumBoxes;
+
+#if PX_DEBUG
+ const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex;
+ for (PxU32 index = 0; index<mNumConvexes; ++index)
+ PX_ASSERT(shapeIt[index] != shape);
+#endif
+
+ ClothCore& core = getCore();
+
+ const PxConvexMeshGeometry& geometry = static_cast<const PxConvexMeshGeometry&>(shape->getCore().getGeometry());
+ PxU32 numPlanes = geometry.convexMesh->getNbPolygons();
+
+ PxU32 planeIndex = core.mNumUserPlanes + mNumPlanes + 6*mNumBoxes + mNumConvexPlanes;
+ if(planeIndex+numPlanes > 32)
+ {
+ Ps::getFoundation().error(PX_WARN, "Dropping collision convex due to 32 plane limit");
+ return false;
+ }
+
+ // current position here is before simulation
+ PX_ALIGN(16, PxTransform globalPose);
+ shape->getAbsPoseAligned(&globalPose);
+ Cm::Matrix34 trafo = core.getGlobalPose().transformInv(globalPose) * geometry.scale;
+ Ps::Array<PxPlane> planes;
+ planes.reserve(numPlanes);
+
+ for(PxU32 i=0; i<numPlanes; ++i)
+ {
+ PxHullPolygon polygon;
+ geometry.convexMesh->getPolygonData(i, polygon);
+ PxVec3 normal = trafo.rotate(reinterpret_cast<const PxVec3&>(polygon.mPlane));
+ planes.pushBack(PxPlane(normal, polygon.mPlane[3] - trafo.p.dot(normal)));
+ }
+
+ core.getLowLevelCloth()->setPlanes(createRange<const PxVec4>(planes.begin(), numPlanes), planeIndex, planeIndex);
+ PxU32 convexIndex = core.mNumUserConvexes + mNumPlanes + mNumBoxes + mNumConvexes;
+ PxU32 convexMask = PxU32(((1 << numPlanes) - 1) << planeIndex);
+ core.getLowLevelCloth()->setConvexes(createRange<const PxU32>(&convexMask, 1), convexIndex, convexIndex);
+
+ mNumConvexPlanes += numPlanes;
+ insertShapeSim(startIndex + mNumConvexes++, shape);
+ return true;
+}
+
+void Sc::ClothSim::removeCollisionConvex( const ShapeSim* shape )
+{
+ ClothCore& core = getCore();
+
+ PxU32 startIndex = mNumSpheres + mNumCapsules + mNumPlanes + mNumBoxes;
+ const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex;
+ PxU32 planeIndex = core.mNumUserPlanes + mNumPlanes + 6*mNumBoxes;
+ for (PxU32 index = 0; index<mNumConvexes; ++index)
+ {
+ const PxConvexMeshGeometry& geometry = static_cast<const PxConvexMeshGeometry&>(shapeIt[index]->getCore().getGeometry());
+ PxU32 numPlanes = geometry.convexMesh->getNbPolygons();
+ if (shapeIt[index] == shape)
+ {
+ mShapeSims.remove(startIndex + index);
+ --mNumConvexes;
+ core.getLowLevelCloth()->setPlanes(cloth::Range<const PxVec4>(), planeIndex, planeIndex+numPlanes);
+ mNumConvexPlanes -= numPlanes;
+ // convex is being removed automatically
+ break;
+ }
+ planeIndex += numPlanes;
+ }
+}
+
+namespace
+{
+ template <typename IndexT>
+ void gatherMeshVertices(const PxTriangleMesh& mesh, Ps::Array<PxVec3>& vertices, bool flipNormal)
+ {
+ PxU32 numTriangles = mesh.getNbTriangles();
+ const IndexT* indices = reinterpret_cast<const IndexT*>(mesh.getTriangles());
+ const PxVec3* meshVertices = mesh.getVertices();
+ for(PxU32 i=0; i<numTriangles; ++i)
+ {
+ const PxI32 winding = flipNormal ? 1 : 0;
+ vertices.pushBack(meshVertices[indices[i*3+0]]);
+ vertices.pushBack(meshVertices[indices[i*3+1 + winding]]);
+ vertices.pushBack(meshVertices[indices[i*3+2 - winding]]);
+ }
+ }
+
+ void offsetTriangles(PxVec3* it, PxVec3* end, PxReal offset)
+ {
+ for(; it < end; it += 3)
+ {
+ PxVec3 v0 = it[0];
+ PxVec3 v1 = it[1];
+ PxVec3 v2 = it[2];
+
+ PxVec3 n = (v1-v0).cross(v2-v0).getNormalized() * offset;
+
+ it[0] = v0 + n;
+ it[1] = v1 + n;
+ it[2] = v2 + n;
+ }
+ }
+
+ void transform(const Cm::Matrix34& trafo, PxVec3* first, PxVec3* last)
+ {
+ for(; first < last; ++first)
+ *first = trafo.transform(*first);
+ }
+}
+
+bool Sc::ClothSim::addCollisionMesh( const ShapeSim* shape )
+{
+ PxU32 startIndex = mNumSpheres + mNumCapsules + mNumPlanes + mNumBoxes + mNumConvexes;
+
+#if PX_DEBUG
+ const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex;
+ for (PxU32 index = 0; index<mNumMeshes; ++index)
+ PX_ASSERT(shapeIt[index] != shape);
+#endif
+
+ ClothCore& core = getCore();
+
+ // current position here is before simulation
+ const PxTriangleMeshGeometry& geometry = static_cast<const PxTriangleMeshGeometry&>(shape->getCore().getGeometry());
+ PX_ALIGN(16, PxTransform globalPose);
+ shape->getAbsPoseAligned(&globalPose);
+ Cm::Matrix34 trafo = core.getGlobalPose().transformInv(globalPose) * geometry.scale;
+ insertShapeSim(startIndex + mNumMeshes++, shape);
+ mStartShapeTrafos.pushBack(trafo);
+ return true;
+}
+
+void Sc::ClothSim::removeCollisionMesh( const ShapeSim* shape )
+{
+ PxU32 startIndex = mNumSpheres + mNumCapsules + mNumPlanes + mNumBoxes + mNumConvexes;
+ const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex;
+ for (PxU32 index = 0; index<mNumMeshes; ++index)
+ {
+ if (shapeIt[index] == shape)
+ {
+ mShapeSims.remove(startIndex + index);
+ mStartShapeTrafos.remove(index);
+ --mNumMeshes;
+ break;
+ }
+ }
+}
+
+namespace
+{
+ void gatherHeightfieldSamples(const PxHeightField& hf, Ps::Array<PxVec3>& vertices, Ps::Array<PxHeightFieldSample>& samples)
+ {
+ const PxU32 numCols = hf.getNbColumns();
+ const PxU32 numRows = hf.getNbRows();
+ const PxU32 numVertices = numRows * numCols;
+
+ samples.resize(numVertices);
+ hf.saveCells(samples.begin(), numVertices * sizeof(PxHeightFieldSample));
+
+ vertices.reserve(numVertices);
+ for(PxU32 i = 0; i < numRows; ++i)
+ {
+ for(PxU32 j = 0; j < numCols; ++j)
+ {
+ vertices.pushBack(PxVec3(PxReal(i), PxReal(samples[j + (i*numCols)].height), PxReal(j)));
+ }
+ }
+ }
+
+ void tessellateHeightfield(const PxHeightField& hf, const PxVec3* vertices,
+ const PxHeightFieldSample* samples, Ps::Array<PxVec3>& triangles)
+ {
+ const PxU32 numCols = hf.getNbColumns();
+ const PxU32 numRows = hf.getNbRows();
+ const PxU32 numTriangles = (numRows-1) * (numCols-1) * 2;
+
+ triangles.reserve(triangles.size() + numTriangles*3);
+ for(PxU32 i = 0; i < (numCols - 1); ++i)
+ {
+ for(PxU32 j = 0; j < (numRows - 1); ++j)
+ {
+ PxU8 tessFlag = samples[i+j*numCols].tessFlag();
+
+ // i2--i3
+ // | |
+ // i0--i1
+ PxU32 i0 = i * numRows + j;
+ PxU32 i1 = i * numRows + j + 1;
+ PxU32 i2 = (i+1) * numRows + j;
+ PxU32 i3 = (i+1) * numRows + j+1;
+
+ // this is really a corner vertex index, not triangle index
+ PxU32 mat0 = hf.getTriangleMaterialIndex((j*numCols+i)*2);
+ if(mat0 != PxHeightFieldMaterial::eHOLE)
+ {
+ triangles.pushBack(vertices[i2]);
+ triangles.pushBack(vertices[i0]);
+ triangles.pushBack(vertices[tessFlag ? i3 : i1]);
+ }
+
+ PxU32 mat1 = hf.getTriangleMaterialIndex((j*numCols+i)*2+1);
+ if(mat1 != PxHeightFieldMaterial::eHOLE)
+ {
+ triangles.pushBack(vertices[i1]);
+ triangles.pushBack(vertices[i3]);
+ triangles.pushBack(vertices[tessFlag ? i0 : i2]);
+ }
+
+ // we don't handle holes yet (number of triangles < expected)
+ PX_ASSERT(mat0 != PxHeightFieldMaterial::eHOLE);
+ PX_ASSERT(mat1 != PxHeightFieldMaterial::eHOLE);
+ }
+ }
+ }
+}
+
+
+bool Sc::ClothSim::addCollisionHeightfield( const ShapeSim* shape )
+{
+ PxU32 startIndex = mNumSpheres + mNumCapsules + mNumPlanes + mNumBoxes + mNumConvexes + mNumMeshes;
+
+#if PX_DEBUG
+ const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex;
+ for (PxU32 index = 0; index<mNumHeightfields; ++index)
+ PX_ASSERT(shapeIt[index] != shape);
+#endif
+
+ ClothCore& core = getCore();
+
+ // current position here is before simulation
+ const PxHeightFieldGeometry& geometry = static_cast<const PxHeightFieldGeometry&>(shape->getCore().getGeometry());
+ PX_ALIGN(16, PxTransform globalPose);
+ shape->getAbsPoseAligned(&globalPose);
+ Cm::Matrix34 trafo(core.getGlobalPose().transformInv(globalPose));
+
+ trafo.m.column0 *= geometry.rowScale;
+ trafo.m.column1 *= geometry.heightScale;
+ trafo.m.column2 *= geometry.columnScale;
+
+ insertShapeSim(startIndex + mNumHeightfields++, shape);
+ mStartShapeTrafos.pushBack(trafo);
+ return true;
+}
+
+void Sc::ClothSim::removeCollisionHeightfield( const ShapeSim* shape )
+{
+ PxU32 startIndex = mNumSpheres + mNumCapsules + mNumPlanes + mNumBoxes + mNumConvexes + mNumMeshes;
+ const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex;
+ for (PxU32 index = 0; index<mNumHeightfields; ++index)
+ {
+ if (shapeIt[index] == shape)
+ {
+ mShapeSims.remove(startIndex + index);
+ mStartShapeTrafos.remove(mNumMeshes + index);
+ --mNumHeightfields;
+ break;
+ }
+ }
+}
+
+void Sc::ClothSim::updateRigidBodyPositions()
+{
+ ClothCore& core = getCore();
+
+ if(!(core.getClothFlags() & PxClothFlag::eSCENE_COLLISION))
+ {
+ PX_ASSERT(0 == mNumSpheres + mNumCapsules + mNumPlanes +
+ mNumBoxes + mNumConvexes + mNumMeshes + mNumHeightfields);
+ return;
+ }
+
+ PxReal restOffset = core.getRestOffset();
+
+ const ShapeSim* const* shapeIt = mShapeSims.begin();
+
+ Ps::Array<PxVec4> spheres;
+ for (PxU32 i=0; i<mNumSpheres; ++i, ++shapeIt)
+ {
+ // current position here is after simulation
+ const ShapeSim* shape = *shapeIt;
+ const PxSphereGeometry& geometry = static_cast<const PxSphereGeometry&>(shape->getCore().getGeometry());
+ PX_ALIGN(16, PxTransform globalPose);
+ shape->getAbsPoseAligned(&globalPose);
+ PxVec3 p = core.getGlobalPose().transformInv(globalPose.p);
+ spheres.pushBack(PxVec4(p, geometry.radius + restOffset));
+ }
+
+ for (PxU32 i=0; i<mNumCapsules; ++i, ++shapeIt)
+ {
+ const ShapeSim* shape = *shapeIt;
+ const PxCapsuleGeometry& geometry = static_cast<const PxCapsuleGeometry&>(shape->getCore().getGeometry());
+ PX_ALIGN(16, PxTransform globalPose);
+ shape->getAbsPoseAligned(&globalPose);
+ PxTransform trafo = core.getGlobalPose().transformInv(globalPose);
+ PxVec3 center = trafo.p;
+ PxVec3 direction = trafo.q.rotate(PxVec3(geometry.halfHeight, 0, 0));
+ PxReal radius = geometry.radius + restOffset;
+ spheres.pushBack(PxVec4(center-direction, radius));
+ spheres.pushBack(PxVec4(center+direction, radius));
+ }
+
+ PxU32 sphereIndex = core.mNumUserSpheres, numSpheres = spheres.size();
+ core.getLowLevelCloth()->setSpheres(createRange<const PxVec4>(spheres.begin(), numSpheres), sphereIndex, sphereIndex+numSpheres);
+
+ Ps::Array<PxPlane> planes;
+ for (PxU32 i = 0; i<mNumPlanes; ++i, ++shapeIt)
+ {
+ const ShapeSim* shape = *shapeIt;
+ PX_ALIGN(16, PxTransform globalPose);
+ shape->getAbsPoseAligned(&globalPose);
+ PxTransform trafo = core.getGlobalPose().transformInv(globalPose);
+ PxPlane plane = PxPlaneEquationFromTransform(trafo);
+ plane.d -= restOffset;
+ planes.pushBack(plane);
+ }
+
+ for (PxU32 i = 0; i<mNumBoxes; ++i, ++shapeIt)
+ {
+ const ShapeSim* shape = *shapeIt;
+ const PxBoxGeometry& geometry = static_cast<const PxBoxGeometry&>(shape->getCore().getGeometry());
+ PX_ALIGN(16, PxTransform globalPose);
+ shape->getAbsPoseAligned(&globalPose);
+ PxTransform trafo = core.getGlobalPose().transformInv(globalPose);
+ PxVec3 halfExtents = geometry.halfExtents + PxVec3(restOffset);
+ planes.pushBack(trafo.transform(PxPlane(PxVec3( 1.f, 0, 0), -halfExtents.x)));
+ planes.pushBack(trafo.transform(PxPlane(PxVec3(-1.f, 0, 0), -halfExtents.x)));
+ planes.pushBack(trafo.transform(PxPlane(PxVec3( 0, 1.f, 0), -halfExtents.y)));
+ planes.pushBack(trafo.transform(PxPlane(PxVec3( 0, -1.f, 0), -halfExtents.y)));
+ planes.pushBack(trafo.transform(PxPlane(PxVec3( 0, 0, 1.f), -halfExtents.z)));
+ planes.pushBack(trafo.transform(PxPlane(PxVec3( 0, 0, -1.f), -halfExtents.z)));
+ }
+
+ for (PxU32 j= 0; j<mNumConvexes; ++j, ++shapeIt)
+ {
+ const ShapeSim* shape = *shapeIt;
+ const PxConvexMeshGeometry& geometry = static_cast<const PxConvexMeshGeometry&>(shape->getCore().getGeometry());
+ PX_ALIGN(16, PxTransform globalPose);
+ shape->getAbsPoseAligned(&globalPose);
+ Cm::Matrix34 trafo = core.getGlobalPose().transformInv(globalPose) * geometry.scale;
+ PxU32 numPlanes = geometry.convexMesh->getNbPolygons();
+ for(PxU32 i=0; i<numPlanes; ++i)
+ {
+ PxHullPolygon polygon;
+ geometry.convexMesh->getPolygonData(i, polygon);
+ PxVec3 normal = trafo.rotate(reinterpret_cast<const PxVec3&>(polygon.mPlane));
+ planes.pushBack(PxPlane(normal, polygon.mPlane[3] - trafo.p.dot(normal) - restOffset));
+ }
+ }
+
+ PxU32 planeIndex = core.mNumUserPlanes, numPlanes = planes.size();
+ core.getLowLevelCloth()->setPlanes(createRange<const PxVec4>(planes.begin(), numPlanes), planeIndex, planeIndex+numPlanes);
+
+ Ps::Array<PxVec3> curTriangles, prevTriangles;
+ for (PxU32 i = 0; i<mNumMeshes; ++i, ++shapeIt)
+ {
+ const ShapeSim* shape = *shapeIt;
+ const PxTriangleMeshGeometry& geometry = static_cast<const PxTriangleMeshGeometry&>(shape->getCore().getGeometry());
+ PxTransform clothPose = core.getGlobalPose();
+ PX_ALIGN(16, PxTransform meshPose);
+ shape->getAbsPoseAligned(&meshPose);
+ Cm::Matrix34 trafo = clothPose.transformInv(meshPose) * geometry.scale;
+
+ PxU32 start = curTriangles.size();
+ if(geometry.triangleMesh->getTriangleMeshFlags() & PxTriangleMeshFlag::e16_BIT_INDICES)
+ gatherMeshVertices<PxU16>(*geometry.triangleMesh, curTriangles, geometry.scale.hasNegativeDeterminant());
+ else
+ gatherMeshVertices<PxU32>(*geometry.triangleMesh, curTriangles, geometry.scale.hasNegativeDeterminant());
+
+ Cm::Matrix34 startTrafo = mStartShapeTrafos[i];
+ mStartShapeTrafos[i] = trafo;
+ for(PxU32 j=start, n=curTriangles.size(); j<n; ++j)
+ prevTriangles.pushBack(startTrafo.transform(curTriangles[j]));
+
+ transform(trafo, curTriangles.begin() + start, curTriangles.end());
+ }
+
+ Ps::Array<PxVec3> vertices;
+ Ps::Array<PxHeightFieldSample> samples;
+ for (PxU32 i = 0; i<mNumHeightfields; ++i, ++shapeIt)
+ {
+ const ShapeSim* shape = *shapeIt;
+ const PxHeightFieldGeometry& geometry = static_cast<const PxHeightFieldGeometry&>(shape->getCore().getGeometry());
+ PxTransform clothPose = core.getGlobalPose();
+ PX_ALIGN(16, PxTransform heightfieldPose);
+ shape->getAbsPoseAligned(&heightfieldPose);
+ Cm::Matrix34 trafo = Cm::Matrix34(clothPose.transformInv(heightfieldPose));
+
+ trafo.m.column0 *= geometry.rowScale;
+ trafo.m.column1 *= geometry.heightScale;
+ trafo.m.column2 *= geometry.columnScale;
+
+ gatherHeightfieldSamples(*geometry.heightField, vertices, samples);
+
+ PxU32 start = curTriangles.size();
+ tessellateHeightfield(*geometry.heightField, vertices.begin(), samples.begin(), curTriangles);
+
+ Cm::Matrix34 startTrafo = mStartShapeTrafos[mNumMeshes + i];
+ mStartShapeTrafos[mNumMeshes + i] = trafo;
+ for(PxU32 j=start, n=curTriangles.size(); j<n; ++j)
+ prevTriangles.pushBack(startTrafo.transform(curTriangles[j]));
+
+ transform(trafo, curTriangles.begin() + start, curTriangles.end());
+
+ vertices.resize(0);
+ samples.resize(0);
+ }
+
+ // cull triangles that don't intersect the cloth bounding box
+ PxVec3 bboxCenter = core.getLowLevelCloth()->getBoundingBoxCenter();
+ PxVec3 bboxScale = core.getLowLevelCloth()->getBoundingBoxScale() + PxVec3(core.getContactOffset());
+ PxU32 trianglesSize = curTriangles.size(), numVertices = 0;
+ for(PxU32 i=0; i<trianglesSize; i+=3)
+ {
+ // PT: TODO: change the code so that we can safely call the (faster) intersectTriangleBox() function
+ if (Gu::intersectTriangleBox_ReferenceCode(bboxCenter, bboxScale, curTriangles[i], curTriangles[i+1], curTriangles[i+2]) ||
+ Gu::intersectTriangleBox_ReferenceCode(bboxCenter, bboxScale, prevTriangles[i], prevTriangles[i+1], prevTriangles[i+2]))
+ {
+ curTriangles[numVertices+0] = curTriangles[i+0];
+ curTriangles[numVertices+1] = curTriangles[i+1];
+ curTriangles[numVertices+2] = curTriangles[i+2];
+
+ prevTriangles[numVertices+0] = prevTriangles[i+0];
+ prevTriangles[numVertices+1] = prevTriangles[i+1];
+ prevTriangles[numVertices+2] = prevTriangles[i+2];
+
+ numVertices += 3;
+ }
+ }
+
+ cloth::Range<PxVec3> prevRange(prevTriangles.begin(), prevTriangles.begin() + numVertices);
+ cloth::Range<PxVec3> curRange(curTriangles.begin(), curTriangles.begin() + numVertices);
+
+ offsetTriangles(prevRange.begin(), prevRange.end(), restOffset);
+ offsetTriangles(curRange.begin(), curRange.end(), restOffset);
+
+ core.getLowLevelCloth()->setTriangles(prevRange, curRange, core.mNumUserTriangles);
+
+ PX_ASSERT(shapeIt == mShapeSims.end());
+}
+
+void Sc::ClothSim::clearCollisionShapes()
+{
+ ClothCore& core = getCore();
+ cloth::Cloth* lowLevelCloth = core.getLowLevelCloth();
+
+ lowLevelCloth->setSpheres(cloth::Range<const PxVec4>(), core.mNumUserSpheres, lowLevelCloth->getNumSpheres());
+ lowLevelCloth->setPlanes(cloth::Range<const PxVec4>(), core.mNumUserPlanes, lowLevelCloth->getNumPlanes());
+ lowLevelCloth->setTriangles(cloth::Range<const PxVec3>(), core.mNumUserTriangles, lowLevelCloth->getNumTriangles());
+
+ mNumSpheres = 0;
+ mNumCapsules = 0;
+ mNumPlanes = 0;
+ mNumBoxes = 0;
+ mNumConvexes = 0;
+ mNumMeshes = 0;
+ mNumHeightfields = 0;
+ mNumConvexPlanes = 0;
+
+ NPhaseCore* narrowPhase = getScene().getNPhaseCore();
+ for(PxU32 i=0, n=mShapeSims.size(); i<n; ++i)
+ narrowPhase->removeClothOverlap(this, mShapeSims[i]);
+
+ mShapeSims.resize(0);
+}
+
+void physx::Sc::ClothSim::insertShapeSim( PxU32 index, const ShapeSim* shapeSim)
+{
+ mShapeSims.pushBack(0);
+
+ for(PxU32 i = mShapeSims.size(); --i > index; )
+ mShapeSims[i] = mShapeSims[i-1];
+
+ mShapeSims[index] = shapeSim;
+}
+
+#endif // PX_USE_CLOTH_API
diff --git a/PhysX_3.4/Source/SimulationController/src/cloth/ScClothSim.h b/PhysX_3.4/Source/SimulationController/src/cloth/ScClothSim.h
new file mode 100644
index 00000000..aa4cae21
--- /dev/null
+++ b/PhysX_3.4/Source/SimulationController/src/cloth/ScClothSim.h
@@ -0,0 +1,123 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 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 PX_PHYSICS_SCP_CLOTH_SIM
+#define PX_PHYSICS_SCP_CLOTH_SIM
+
+#include "CmPhysXCommon.h"
+#include "PxPhysXConfig.h"
+#if PX_USE_CLOTH_API
+
+#include "CmMatrix34.h"
+#include "ScClothShape.h"
+
+namespace physx
+{
+
+#if PX_SUPPORT_GPU_PHYSX
+ struct PxClothCollisionSphere;
+#endif
+
+namespace Sc
+{
+ class ClothCore;
+ class ShapeSim;
+
+ class ClothSim : public ActorSim
+ {
+ public:
+
+ ClothSim(Scene&, ClothCore&);
+ ~ClothSim();
+
+ //---------------------------------------------------------------------------------
+ // Actor implementation
+ //---------------------------------------------------------------------------------
+ public:
+ ClothCore& getCore() const;
+
+ void updateBounds();
+ void startStep();
+ void reinsert();
+
+ bool addCollisionShape(const ShapeSim* shape);
+ void removeCollisionShape(const ShapeSim* shape);
+
+ bool addCollisionSphere(const ShapeSim* shape);
+ void removeCollisionSphere(const ShapeSim* shape);
+
+ bool addCollisionCapsule(const ShapeSim* shape);
+ void removeCollisionCapsule(const ShapeSim* shape);
+
+ bool addCollisionPlane(const ShapeSim* shape);
+ void removeCollisionPlane(const ShapeSim* shape);
+
+ bool addCollisionBox(const ShapeSim* shape);
+ void removeCollisionBox(const ShapeSim* shape);
+
+ bool addCollisionConvex(const ShapeSim* shape);
+ void removeCollisionConvex(const ShapeSim* shape);
+
+ bool addCollisionMesh(const ShapeSim* shape);
+ void removeCollisionMesh(const ShapeSim* shape);
+
+ bool addCollisionHeightfield(const ShapeSim* shape);
+ void removeCollisionHeightfield(const ShapeSim* shape);
+
+ void updateRigidBodyPositions();
+ void clearCollisionShapes();
+
+ private:
+ void insertShapeSim(PxU32, const ShapeSim*);
+ ClothSim &operator=(const ClothSim &);
+
+ private:
+ ClothShape mClothShape;
+
+ PxU32 mNumSpheres;
+ PxU32 mNumCapsules;
+ PxU32 mNumPlanes;
+ PxU32 mNumBoxes;
+ PxU32 mNumConvexes;
+ PxU32 mNumMeshes;
+ PxU32 mNumHeightfields;
+ PxU32 mNumConvexPlanes;
+
+ shdfnd::Array<const ShapeSim*> mShapeSims;
+ shdfnd::Array<Cm::Matrix34> mStartShapeTrafos;
+
+ };
+
+} // namespace Sc
+}
+
+#endif // PX_PHYSICS_SCP_CLOTH_SIM
+
+#endif