diff options
| author | git perforce import user <a@b> | 2016-10-25 12:29:14 -0600 |
|---|---|---|
| committer | Sheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees> | 2016-10-25 18:56:37 -0500 |
| commit | 3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch) | |
| tree | fa6485c169e50d7415a651bf838f5bcd0fd3bfbd /PhysX_3.4/Source/SimulationController | |
| download | physx-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')
97 files changed, 31472 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/SimulationController/include/ScActorCore.h b/PhysX_3.4/Source/SimulationController/include/ScActorCore.h new file mode 100644 index 00000000..77c2e0b2 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/include/ScActorCore.h @@ -0,0 +1,137 @@ +// 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_COLLISION_ACTOR_CORE +#define PX_COLLISION_ACTOR_CORE + +#include "PsUserAllocated.h" +#include "CmPhysXCommon.h" +#include "PxMetaData.h" +#include "PxActor.h" + +namespace physx +{ + +class PxActor; + +namespace Sc +{ + + class Scene; + class ActorSim; + + class ActorCore : public Ps::UserAllocated + { + //= ATTENTION! ===================================================================================== + // Changing the data layout of this class breaks the binary serialization format. See comments for + // PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData + // function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION + // accordingly. + //================================================================================================== + public: +// PX_SERIALIZATION + ActorCore(const PxEMPTY) : mSim(NULL), mActorFlags(PxEmpty) + { + } + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + ActorCore(PxActorType::Enum actorType, PxU8 actorFlags, + PxClientID owner, PxU8 behavior, PxDominanceGroup dominanceGroup); + /*virtual*/ ~ActorCore(); + + PX_FORCE_INLINE ActorSim* getSim() const { return mSim; } + PX_FORCE_INLINE void setSim(ActorSim* sim) + { + PX_ASSERT((sim==NULL) ^ (mSim==NULL)); + mSim = sim; + } + + PX_FORCE_INLINE PxActorFlags getActorFlags() const { return mActorFlags; } + void setActorFlags(PxActorFlags af); + + PX_FORCE_INLINE PxDominanceGroup getDominanceGroup() const + { + return PxDominanceGroup(mDominanceGroup); + } + void setDominanceGroup(PxDominanceGroup g); + + PX_FORCE_INLINE void setOwnerClient(PxClientID inId) + { + const PxU32 aggid = mAggregateIDOwnerClient & 0x00ffffff; + mAggregateIDOwnerClient = (PxU32(inId)<<24) | aggid; + + } + PX_FORCE_INLINE PxClientID getOwnerClient() const + { + return mAggregateIDOwnerClient>>24; + } + + PX_FORCE_INLINE PxActorClientBehaviorFlags getClientBehaviorFlags() const { return mClientBehaviorFlags; } + PX_FORCE_INLINE void setClientBehaviorFlags(PxActorClientBehaviorFlags b) { mClientBehaviorFlags = b; } + + PX_FORCE_INLINE PxActorType::Enum getActorCoreType() const { return PxActorType::Enum(mActorType); } + + void reinsertShapes(); +// PX_AGGREGATE + PX_FORCE_INLINE void setAggregateID(PxU32 id) + { + PX_ASSERT(id==0xffffffff || id<(1<<24)); + const PxU32 ownerClient = mAggregateIDOwnerClient & 0xff000000; + mAggregateIDOwnerClient = (id & 0x00ffffff) | ownerClient; + } + PX_FORCE_INLINE PxU32 getAggregateID() const + { + const PxU32 id = mAggregateIDOwnerClient & 0x00ffffff; + return id == 0x00ffffff ? PX_INVALID_U32 : id; + } +//~PX_AGGREGATE + private: + ActorSim* mSim; // + PxU32 mAggregateIDOwnerClient; // PxClientID (8bit) | aggregate ID (24bit) + // PT: TODO: the remaining members could be packed into just a 16bit mask + PxActorFlags mActorFlags; // PxActor's flags (PxU8) => only 4 bits used + PxU8 mActorType; // Actor type (8 bits, but 3 would be enough) + PxActorClientBehaviorFlags mClientBehaviorFlags; // PxU8 => only 4 bits used + PxU8 mDominanceGroup; // Dominance group (8 bits, but 5 would be enough because "must be < 32") + }; + +#if PX_P64_FAMILY + PX_COMPILE_TIME_ASSERT(sizeof(Sc::ActorCore)==16); +#else + PX_COMPILE_TIME_ASSERT(sizeof(Sc::ActorCore)==12); +#endif + +} // namespace Sc + +} + +////////////////////////////////////////////////////////////////////////// + +#endif diff --git a/PhysX_3.4/Source/SimulationController/include/ScArticulationCore.h b/PhysX_3.4/Source/SimulationController/include/ScArticulationCore.h new file mode 100644 index 00000000..77f2285a --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/include/ScArticulationCore.h @@ -0,0 +1,170 @@ +// 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_ARTICULATION_CORE +#define PX_PHYSICS_SCP_ARTICULATION_CORE + +#include "ScActorCore.h" +#include "DyArticulation.h" + +namespace physx +{ + +class PxvArticulation; + +namespace IG +{ + class NodeIndex; +} + + +namespace Sc +{ + typedef Dy::FsData ArticulationDriveCache; + + class ArticulationSim; + class BodyCore; + + class ArticulationCore + { + //= ATTENTION! ===================================================================================== + // Changing the data layout of this class breaks the binary serialization format. See comments for + // PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData + // function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION + // accordingly. + //================================================================================================== + + //--------------------------------------------------------------------------------- + // Construction, destruction & initialization + //--------------------------------------------------------------------------------- + +// PX_SERIALIZATION + public: + ArticulationCore(const PxEMPTY) : mSim(NULL) {} + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + ArticulationCore(); + ~ArticulationCore(); + + //--------------------------------------------------------------------------------- + // External API + //--------------------------------------------------------------------------------- + PxU32 getInternalDriveIterations() const; + void setInternalDriveIterations(const PxU32 v); + + PxU32 getExternalDriveIterations() const; + void setExternalDriveIterations(const PxU32 v); + + PxU32 getMaxProjectionIterations() const; + void setMaxProjectionIterations(const PxU32 v); + + PxReal getSeparationTolerance() const; + void setSeparationTolerance(const PxReal v); + + PxReal getSleepThreshold() const; + void setSleepThreshold(const PxReal v); + + PxReal getFreezeThreshold() const; + void setFreezeThreshold(const PxReal v); + + PxReal getWakeCounter() const; + void setWakeCounter(const PxReal v); + void setWakeCounterInternal(const PxReal v); + + bool isSleeping() const; + void wakeUp(PxReal wakeCounter); + void putToSleep(); + + PxU16 getSolverIterationCounts() const; + void setSolverIterationCounts(PxU16 c); + + PxArticulation* getPxArticulation(); + const PxArticulation* getPxArticulation() const; + + + //--------------------------------------------------------------------------------- + // Drive Cache API + //--------------------------------------------------------------------------------- + ArticulationDriveCache* createDriveCache(PxReal compliance, + PxU32 driveIterations) const; + + void updateDriveCache(ArticulationDriveCache& cache, + PxReal compliance, + PxU32 driveIterations) const; + + void releaseDriveCache(ArticulationDriveCache& cache) const; + + PxU32 getCacheLinkCount(const ArticulationDriveCache& cache) const; + + void applyImpulse(BodyCore& link, + const ArticulationDriveCache& driveCache, + const PxVec3& force, + const PxVec3& torque); + + void computeImpulseResponse(BodyCore& link, + PxVec3& linearResponse, + PxVec3& angularResponse, + const ArticulationDriveCache& driveCache, + const PxVec3& force, + const PxVec3& torque) const; + + //--------------------------------------------------------------------------------- + // Internal API + //--------------------------------------------------------------------------------- + public: + PX_FORCE_INLINE void setSim(ArticulationSim* sim) + { + PX_ASSERT((sim==0) ^ (mSim == 0)); + mSim = sim; + } + PX_FORCE_INLINE ArticulationSim* getSim() const { return mSim; } + + PX_FORCE_INLINE const Dy::ArticulationCore& getCore() { return mCore; } + + static PX_FORCE_INLINE ArticulationCore& getArticulationCore(ArticulationCore& core) + { + size_t offset = PX_OFFSET_OF(ArticulationCore, mCore); + return *reinterpret_cast<ArticulationCore*>(reinterpret_cast<PxU8*>(&core) - offset); + } + + IG::NodeIndex getIslandNodeIndex() const; + + private: + ArticulationSim* mSim; + Dy::ArticulationCore mCore; + }; + + + +} // namespace Sc + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/include/ScArticulationJointCore.h b/PhysX_3.4/Source/SimulationController/include/ScArticulationJointCore.h new file mode 100644 index 00000000..7572f5b0 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/include/ScArticulationJointCore.h @@ -0,0 +1,157 @@ +// 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_ARTICULATION_JOINT_CORE +#define PX_PHYSICS_SCP_ARTICULATION_JOINT_CORE + +#include "foundation/PxTransform.h" +#include "CmPhysXCommon.h" +#include "PsUserAllocated.h" +#include "DyArticulation.h" +#include "PxMetaData.h" + +namespace physx +{ +namespace Sc +{ + + class BodyCore; + class ArticulationJointSim; + + class ArticulationJointDesc + { + public: + BodyCore* parent; + BodyCore* child; + PxTransform parentPose; + PxTransform childPose; + }; + + class ArticulationJointCore : public Ps::UserAllocated + { + //= ATTENTION! ===================================================================================== + // Changing the data layout of this class breaks the binary serialization format. See comments for + // PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData + // function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION + // accordingly. + //================================================================================================== + + //--------------------------------------------------------------------------------- + // Construction, destruction & initialization + //--------------------------------------------------------------------------------- + public: +// PX_SERIALIZATION + ArticulationJointCore(const PxEMPTY) : mSim(NULL), mCore(PxEmpty) {} + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + ArticulationJointCore(const PxTransform& parentFrame, + const PxTransform& childFrame); + + ~ArticulationJointCore(); + + //--------------------------------------------------------------------------------- + // External API + //--------------------------------------------------------------------------------- + + const PxTransform& getParentPose() const { return mCore.parentPose; } + void setParentPose(const PxTransform&); + + const PxTransform& getChildPose() const { return mCore.childPose; } + void setChildPose(const PxTransform&); + + const PxQuat& getTargetOrientation() const { return mCore.targetPosition; } + void setTargetOrientation(const PxQuat&); + + const PxVec3& getTargetVelocity() const { return mCore.targetVelocity; } + void setTargetVelocity(const PxVec3&); + + PxReal getStiffness() const { return mCore.spring; } + void setStiffness(PxReal); + + PxReal getDamping() const { return mCore.damping; } + void setDamping(PxReal); + + PxReal getInternalCompliance() const { return mCore.internalCompliance; } + void setInternalCompliance(PxReal); + + PxReal getExternalCompliance() const { return mCore.externalCompliance; } + void setExternalCompliance(PxReal); + + void getSwingLimit(PxReal& yLimit, PxReal& zLimit) const { yLimit = mCore.swingYLimit; zLimit = mCore.swingZLimit; } + void setSwingLimit(PxReal yLimit, PxReal zLimit); + + PxReal getTangentialStiffness() const { return mCore.tangentialStiffness; } + void setTangentialStiffness(PxReal); + + PxReal getTangentialDamping() const { return mCore.tangentialDamping; } + void setTangentialDamping(PxReal); + + bool getSwingLimitEnabled() const { return mCore.swingLimited; } + void setSwingLimitEnabled(bool); + + PxReal getSwingLimitContactDistance() const { return mCore.swingLimitContactDistance; } + void setSwingLimitContactDistance(PxReal); + + void getTwistLimit(PxReal& lower, PxReal& upper) const { lower = mCore.twistLimitLow; upper = mCore.twistLimitHigh; } + void setTwistLimit(PxReal lower, PxReal upper); + + bool getTwistLimitEnabled() const { return mCore.twistLimited; } + void setTwistLimitEnabled(bool); + + PxReal getTwistLimitContactDistance() const { return mCore.twistLimitContactDistance; } + void setTwistLimitContactDistance(PxReal); + + void setDriveType(PxArticulationJointDriveType::Enum type); + PxArticulationJointDriveType::Enum + getDriveType() const { return PxArticulationJointDriveType::Enum(mCore.driveType); } + + //--------------------------------------------------------------------------------- + // Low Level data access - some wouldn't be needed if the interface wasn't virtual + //--------------------------------------------------------------------------------- + + PX_FORCE_INLINE ArticulationJointSim* getSim() const { return mSim; } + PX_FORCE_INLINE void setSim(ArticulationJointSim* sim) + { + PX_ASSERT((sim==0) ^ (mSim == 0)); + mSim = sim; + } + + PX_FORCE_INLINE const Dy::ArticulationJointCore& getCore() { return mCore; } + + private: + ArticulationJointSim* mSim; + Dy::ArticulationJointCore mCore; + }; + +} // namespace Sc + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/include/ScBodyCore.h b/PhysX_3.4/Source/SimulationController/include/ScBodyCore.h new file mode 100644 index 00000000..54fa5b38 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/include/ScBodyCore.h @@ -0,0 +1,213 @@ +// 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_BODYCORE +#define PX_PHYSICS_SCP_BODYCORE + +#include "foundation/PxTransform.h" +#include "ScRigidCore.h" +#include "PxRigidDynamic.h" +#include "PxvDynamics.h" +#include "PxvConfig.h" +#include "PsPool.h" + +namespace physx +{ + +class PxRigidBodyDesc; + +namespace Sc +{ + class BodySim; + struct SimStateData; + + struct KinematicTransform + { + PxTransform targetPose; // The body will move to this pose over the superstep following this getting set. + PxU8 targetValid; // User set a kinematic target. + PxU8 pad[2]; + PxU8 type; + }; + + class BodyCore : public RigidCore + { + //= ATTENTION! ===================================================================================== + // Changing the data layout of this class breaks the binary serialization format. See comments for + // PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData + // function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION + // accordingly. + //================================================================================================== + + //--------------------------------------------------------------------------------- + // Construction, destruction & initialization + //--------------------------------------------------------------------------------- + public: +// PX_SERIALIZATION + BodyCore(const PxEMPTY) : RigidCore(PxEmpty), mCore(PxEmpty), mSimStateData(NULL) {} + static void getBinaryMetaData(PxOutputStream& stream); + void disableInternalCaching(bool disable); + size_t getSerialCore(PxsBodyCore& serialCore); +//~PX_SERIALIZATION + BodyCore(PxActorType::Enum type, const PxTransform& bodyPose); + /*virtual*/ ~BodyCore(); + + //--------------------------------------------------------------------------------- + // External API + //--------------------------------------------------------------------------------- + PX_FORCE_INLINE const PxTransform& getBody2World() const { return mCore.body2World; } + void setBody2World(const PxTransform& p); + + PX_FORCE_INLINE const PxVec3& getLinearVelocity() const { return mCore.linearVelocity; } + void setLinearVelocity(const PxVec3& v); + + PX_FORCE_INLINE const PxVec3& getAngularVelocity() const { return mCore.angularVelocity; } + void setAngularVelocity(const PxVec3& v); + + + PX_FORCE_INLINE void updateVelocities(const PxVec3& linearVelModPerStep, const PxVec3& angularVelModPerStep) + { + mCore.linearVelocity += linearVelModPerStep; + mCore.angularVelocity += angularVelModPerStep; + } + + PX_FORCE_INLINE const PxTransform& getBody2Actor() const { return mCore.getBody2Actor(); } + void setBody2Actor(const PxTransform& p); + + void addSpatialAcceleration(Ps::Pool<SimStateData>* simStateDataPool, const PxVec3* linAcc, const PxVec3* angAcc); + void clearSpatialAcceleration(bool force, bool torque); + void addSpatialVelocity(Ps::Pool<SimStateData>* simStateDataPool, const PxVec3* linVelDelta, const PxVec3* angVelDelta); + void clearSpatialVelocity(bool force, bool torque); + + PX_FORCE_INLINE PxReal getMaxPenetrationBias() const { return mCore.maxPenBias; } + PX_FORCE_INLINE void setMaxPenetrationBias(PxReal p) { mCore.maxPenBias = p; } + + PxReal getInverseMass() const; + void setInverseMass(PxReal m); + const PxVec3& getInverseInertia() const; + void setInverseInertia(const PxVec3& i); + + PxReal getLinearDamping() const; + void setLinearDamping(PxReal d); + + PxReal getAngularDamping() const; + void setAngularDamping(PxReal d); + + PX_FORCE_INLINE PxRigidBodyFlags getFlags() const { return mCore.mFlags; } + void setFlags(Ps::Pool<SimStateData>* simStateDataPool, PxRigidBodyFlags f); + + PX_FORCE_INLINE PxRigidDynamicLockFlags getRigidDynamicLockFlags() const { return mCore.lockFlags; } + + PX_FORCE_INLINE void setRigidDynamicLockFlags(PxRigidDynamicLockFlags flags) { mCore.lockFlags = flags; } + + PX_FORCE_INLINE PxReal getSleepThreshold() const { return mCore.sleepThreshold; } + void setSleepThreshold(PxReal t); + + PX_FORCE_INLINE PxReal getFreezeThreshold() const { return mCore.freezeThreshold; } + void setFreezeThreshold(PxReal t); + + PX_FORCE_INLINE PxReal getMaxContactImpulse() const { return mCore.maxContactImpulse; } + void setMaxContactImpulse(PxReal m); + + PX_FORCE_INLINE PxReal getWakeCounter() const { return mCore.wakeCounter; } + void setWakeCounter(PxReal wakeCounter, bool forceWakeUp=false); + + bool isSleeping() const; + PX_FORCE_INLINE void wakeUp(PxReal wakeCounter) { setWakeCounter(wakeCounter, true); } + void putToSleep(); + + PxReal getMaxAngVelSq() const; + void setMaxAngVelSq(PxReal v); + + + PxU32 getSolverIterationCounts() const { return mCore.solverIterationCounts; } + void setSolverIterationCounts(PxU16 c); + + bool getKinematicTarget(PxTransform& p) const; + bool getHasValidKinematicTarget() const; + void setKinematicTarget(Ps::Pool<SimStateData>* simStateDataPool, const PxTransform& p, PxReal wakeCounter); + void invalidateKinematicTarget(); + + PX_FORCE_INLINE PxReal getContactReportThreshold() const { return mCore.contactReportThreshold; } + void setContactReportThreshold(PxReal t) { mCore.contactReportThreshold = t; } + + void onOriginShift(const PxVec3& shift); + + //--------------------------------------------------------------------------------- + // Internal API + //--------------------------------------------------------------------------------- + + PX_FORCE_INLINE void setLinearVelocityInternal(const PxVec3& v) { mCore.linearVelocity = v; } + PX_FORCE_INLINE void setAngularVelocityInternal(const PxVec3& v) { mCore.angularVelocity = v; } + PX_FORCE_INLINE void setWakeCounterFromSim(PxReal c) { mCore.wakeCounter = c; } + + BodySim* getSim() const; + + PX_FORCE_INLINE PxsBodyCore& getCore() { return mCore; } + PX_FORCE_INLINE const PxsBodyCore& getCore() const { return mCore; } + + PX_FORCE_INLINE PxReal getCCDAdvanceCoefficient() const { return mCore.ccdAdvanceCoefficient; } + PX_FORCE_INLINE void setCCDAdvanceCoefficient(PxReal c) { mCore.ccdAdvanceCoefficient = c; } + + bool setupSimStateData(Ps::Pool<SimStateData>* simStateDataPool, const bool isKinematic, const bool targetValid = false); + void tearDownSimStateData(Ps::Pool<SimStateData>* simStateDataPool, const bool isKinematic); + + bool checkSimStateKinematicStatus(bool) const; + + Ps::IntBool isFrozen() const; + void setFrozen(); + void clearFrozen(); + + PX_FORCE_INLINE const SimStateData* getSimStateData(bool isKinematic) const { return (mSimStateData && (checkSimStateKinematicStatus(isKinematic)) ? mSimStateData : NULL); } + PX_FORCE_INLINE SimStateData* getSimStateData(bool isKinematic) { return (mSimStateData && (checkSimStateKinematicStatus(isKinematic)) ? mSimStateData : NULL); } + + static PX_FORCE_INLINE BodyCore& getCore(PxsBodyCore& core) + { + size_t offset = PX_OFFSET_OF_RT(BodyCore, mCore); + return *reinterpret_cast<BodyCore*>(reinterpret_cast<PxU8*>(&core) - offset); + } + + private: + void backup(SimStateData&); + void restore(); + + PX_ALIGN_PREFIX(16) PxsBodyCore mCore PX_ALIGN_SUFFIX(16); + /*PxReal mSleepThreshold; + PxReal mFreezeThreshold; + PxReal mWakeCounter;*/ + SimStateData* mSimStateData; + }; + + PxActor* getPxActorFromBodyCore(Sc::BodyCore* bodyCore, PxActorType::Enum& type); + +} // namespace Sc + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/include/ScClothCore.h b/PhysX_3.4/Source/SimulationController/include/ScClothCore.h new file mode 100644 index 00000000..b6e63639 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/include/ScClothCore.h @@ -0,0 +1,336 @@ +// 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_CORE +#define PX_PHYSICS_SCP_CLOTH_CORE + +#include "CmPhysXCommon.h" +#include "PxPhysXConfig.h" +#if PX_USE_CLOTH_API + +#include "ScActorCore.h" + +#include "foundation/PxTransform.h" +#include "PxFiltering.h" +#include "PxCloth.h" +#include "PxClothTypes.h" +#include "PxClothCollisionData.h" + +#include "PsArray.h" + +namespace physx +{ + +struct PxClothCollisionSphere; + +namespace cloth +{ + class Cloth; + struct PhaseConfig; +} + +namespace Sc +{ + class ClothFabricCore; + class ClothSim; + + bool DefaultClothInterCollisionFilter(void* cloth0, void* cloth1); + + struct ClothBulkData : public Ps::UserAllocated + { + //= ATTENTION! ===================================================================================== + // Changing the data layout of this class breaks the binary serialization format. See comments for + // PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData + // function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION + // accordingly. + //================================================================================================== + + // constructor and destructor are needed because some compilers zero the memory in the + // default constructor and that breaks the serialization related memory markers for + // implicitly padded bytes + ClothBulkData() {} + ~ClothBulkData() {} + + void exportExtraData(PxSerializationContext& stream); + void importExtraData(PxDeserializationContext& context); + static void getBinaryMetaData(PxOutputStream& stream); + + shdfnd::Array<PxClothParticle> mParticles; + shdfnd::Array<PxU32> mVpData; + shdfnd::Array<PxVec3> mVpWeightData; + shdfnd::Array<PxClothCollisionSphere> mCollisionSpheres; + shdfnd::Array<PxU32> mCollisionPairs; + shdfnd::Array<PxClothCollisionPlane> mCollisionPlanes; + shdfnd::Array<PxU32> mConvexMasks; + shdfnd::Array<PxClothCollisionTriangle> mCollisionTriangles; + shdfnd::Array<PxClothParticleMotionConstraint> mConstraints; + shdfnd::Array<PxClothParticleSeparationConstraint> mSeparationConstraints; + shdfnd::Array<PxVec4> mParticleAccelerations; + shdfnd::Array<PxU32> mSelfCollisionIndices; + shdfnd::Array<PxVec4> mRestPositions; + + // misc data + PxReal mTetherConstraintScale; + PxReal mTetherConstraintStiffness; + PxReal mMotionConstraintScale; + PxReal mMotionConstraintBias; + PxReal mMotionConstraintStiffness; + PxVec3 mAcceleration; + PxVec3 mDamping; + PxReal mFriction; + PxReal mCollisionMassScale; + PxVec3 mLinearDrag; + PxVec3 mAngularDrag; + PxVec3 mLinearInertia; + PxVec3 mAngularInertia; + PxVec3 mCentrifugalInertia; + PxReal mSolverFrequency; + PxReal mStiffnessFrequency; + PxReal mSelfCollisionDistance; + PxReal mSelfCollisionStiffness; + PxTransform mGlobalPose; + PxReal mSleepThreshold; + PxReal mWakeCounter; + PxVec3 mWindVelocity; + PxReal mDragCoefficient; + PxReal mLiftCoefficient; + }; + + + class ClothCore : public ActorCore + { + //= ATTENTION! ===================================================================================== + // Changing the data layout of this class breaks the binary serialization format. See comments for + // PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData + // function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION + // accordingly. + //================================================================================================== + public: +// PX_SERIALIZATION + ClothCore(const PxEMPTY) : ActorCore(PxEmpty), mLowLevelCloth(NULL), mFabric(NULL) {} + void exportExtraData(PxSerializationContext& stream); + void importExtraData(PxDeserializationContext& context); + void resolveReferences(Sc::ClothFabricCore& fabric); + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + ClothCore(const PxTransform& globalPose, Sc::ClothFabricCore& fabric, const PxClothParticle* particles, PxClothFlags flags); + ~ClothCore(); + + //--------------------------------------------------------------------------------- + // External API + //--------------------------------------------------------------------------------- + PX_FORCE_INLINE ClothFabricCore* getFabric() const { return mFabric; } + PX_FORCE_INLINE void resetFabric() { mFabric = NULL; } + + void setParticles(const PxClothParticle* currentParticles, const PxClothParticle* previousParticles); + PxU32 getNbParticles() const; + + void setMotionConstraints(const PxClothParticleMotionConstraint* motionConstraints); + bool getMotionConstraints(PxClothParticleMotionConstraint* motionConstraintsBuffer) const; + PxU32 getNbMotionConstraints() const; + + void setMotionConstraintConfig(const PxClothMotionConstraintConfig& config); + PxClothMotionConstraintConfig getMotionConstraintConfig() const; + + void setSeparationConstraints(const PxClothParticleSeparationConstraint* separationConstraints); + bool getSeparationConstraints(PxClothParticleSeparationConstraint* separationConstraintsBuffer) const; + PxU32 getNbSeparationConstraints() const; + + void clearInterpolation(); + + void setParticleAccelerations(const PxVec4* particleAccelerations); + bool getParticleAccelerations(PxVec4* particleAccelerationsBuffer) const; + PxU32 getNbParticleAccelerations() const; + + void addCollisionSphere(const PxClothCollisionSphere& sphere); + void removeCollisionSphere(PxU32 index); + void setCollisionSpheres(const PxClothCollisionSphere* spheresBuffer, PxU32 count); + PxU32 getNbCollisionSpheres() const; + + void getCollisionData(PxClothCollisionSphere* spheresBuffer, PxU32* capsulesBuffer, + PxClothCollisionPlane* planesBuffer, PxU32* convexesBuffer, PxClothCollisionTriangle* trianglesBuffer) const; + + void addCollisionCapsule(PxU32 first, PxU32 second); + void removeCollisionCapsule(PxU32 index); + PxU32 getNbCollisionCapsules() const; + + void addCollisionTriangle(const PxClothCollisionTriangle& triangle); + void removeCollisionTriangle(PxU32 index); + void setCollisionTriangles(const PxClothCollisionTriangle* trianglesBuffer, PxU32 count); + PxU32 getNbCollisionTriangles() const; + + void addCollisionPlane(const PxClothCollisionPlane& plane); + void removeCollisionPlane(PxU32 index); + void setCollisionPlanes(const PxClothCollisionPlane* planesBuffer, PxU32 count); + PxU32 getNbCollisionPlanes() const; + + void addCollisionConvex(PxU32 mask); + void removeCollisionConvex(PxU32 index); + PxU32 getNbCollisionConvexes() const; + + void setVirtualParticles(PxU32 numParticles, const PxU32* indices, PxU32 numWeights, const PxVec3* weights); + + PxU32 getNbVirtualParticles() const; + void getVirtualParticles(PxU32* indicesBuffer) const; + + PxU32 getNbVirtualParticleWeights() const; + void getVirtualParticleWeights(PxVec3* weightsBuffer) const; + + PxTransform getGlobalPose() const; + void setGlobalPose(const PxTransform& pose); + + void setTargetPose(const PxTransform& pose); + + PxVec3 getExternalAcceleration() const; + void setExternalAcceleration(PxVec3 acceleration); + + PxVec3 getDampingCoefficient() const; + void setDampingCoefficient(PxVec3 dampingCoefficient); + + PxReal getFrictionCoefficient() const; + void setFrictionCoefficient(PxReal frictionCoefficient); + + PxVec3 getLinearDragCoefficient() const; + void setLinearDragCoefficient(PxVec3 dragCoefficient); + PxVec3 getAngularDragCoefficient() const; + void setAngularDragCoefficient(PxVec3 dragCoefficient); + + PxReal getCollisionMassScale() const; + void setCollisionMassScale(PxReal scalingCoefficient); + + void setSelfCollisionDistance(PxReal distance); + PxReal getSelfCollisionDistance() const; + void setSelfCollisionStiffness(PxReal stiffness); + PxReal getSelfCollisionStiffness() const; + + void setSelfCollisionIndices(const PxU32* indices, PxU32 nbIndices); + bool getSelfCollisionIndices(PxU32* indices) const; + PxU32 getNbSelfCollisionIndices() const; + + void setRestPositions(const PxVec4* restPositions); + bool getRestPositions(PxVec4* restPositions) const; + PxU32 getNbRestPositions() const; + + PxReal getSolverFrequency() const; + void setSolverFrequency(PxReal); + + PxReal getStiffnessFrequency() const; + void setStiffnessFrequency(PxReal); + + PxVec3 getLinearInertiaScale() const; + void setLinearInertiaScale( PxVec3 ); + PxVec3 getAngularInertiaScale() const; + void setAngularInertiaScale( PxVec3 ); + PxVec3 getCentrifugalInertiaScale() const; + void setCentrifugalInertiaScale( PxVec3 ); + + PxClothStretchConfig getStretchConfig(PxClothFabricPhaseType::Enum type) const; + PxClothTetherConfig getTetherConfig() const; + + void setStretchConfig(PxClothFabricPhaseType::Enum type, const PxClothStretchConfig& config); + void setTetherConfig(const PxClothTetherConfig& config); + + PxClothFlags getClothFlags() const; + void setClothFlags(PxClothFlags flags); + + PxVec3 getWindVelocity() const; + void setWindVelocity(PxVec3); + PxReal getDragCoefficient() const; + void setDragCoefficient(PxReal); + PxReal getLiftCoefficient() const; + void setLiftCoefficient(PxReal); + + + bool isSleeping() const; + PxReal getSleepLinearVelocity() const; + void setSleepLinearVelocity(PxReal threshold); + void setWakeCounter(PxReal wakeCounterValue); + PxReal getWakeCounter() const; + void wakeUp(PxReal wakeCounter); + void putToSleep(); + + void getParticleData(PxClothParticleData& readData); + void unlockParticleData(); + + PxReal getPreviousTimeStep() const; + + PxBounds3 getWorldBounds() const; + + void setSimulationFilterData(const PxFilterData& data); + PxFilterData getSimulationFilterData() const; + + void setContactOffset(PxReal); + PxReal getContactOffset() const; + void setRestOffset(PxReal); + PxReal getRestOffset() const; + + public: + ClothSim* getSim() const; + + PxCloth* getPxCloth(); + + PX_FORCE_INLINE cloth::Cloth* getLowLevelCloth() { return mLowLevelCloth; } + + void onOriginShift(const PxVec3& shift); + + void switchCloth(cloth::Cloth*); + PX_FORCE_INLINE bool isGpu() const { return mClothFlags & PxClothFlag::eCUDA; } + + private: + + void updateBulkData(ClothBulkData& bulkData); + void initLowLevel(const PxTransform& globalPose, const PxClothParticle* particles); + + private: + PxVec3 mExternalAcceleration; + cloth::Cloth* mLowLevelCloth; + ClothFabricCore* mFabric; + ClothBulkData* mBulkData; + cloth::PhaseConfig* mPhaseConfigs; + PxFilterData mFilterData; + PxClothFlags mClothFlags; + PxReal mContactOffset; + PxReal mRestOffset; + + public: // + PxU32 mNumUserSpheres; + PxU32 mNumUserCapsules; + PxU32 mNumUserPlanes; + PxU32 mNumUserConvexes; + PxU32 mNumUserTriangles; + }; + +} // namespace Sc + +} + +#endif // PX_USE_CLOTH_API + +#endif diff --git a/PhysX_3.4/Source/SimulationController/include/ScClothFabricCore.h b/PhysX_3.4/Source/SimulationController/include/ScClothFabricCore.h new file mode 100644 index 00000000..5dfeb76d --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/include/ScClothFabricCore.h @@ -0,0 +1,146 @@ +// 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_FABRIC_CORE +#define PX_PHYSICS_SCP_CLOTH_FABRIC_CORE + +#include "CmPhysXCommon.h" +#include "PsUserAllocated.h" +#include "PxPhysXConfig.h" +#include "PxClothFabric.h" +#include "PsArray.h" + +namespace physx +{ + +#if PX_USE_CLOTH_API + +class PxSerializationContext; + +namespace cloth +{ + class Fabric; +} + + +namespace Sc +{ + struct ClothFabricBulkData : public Ps::UserAllocated + { + //= ATTENTION! ===================================================================================== + // Changing the data layout of this class breaks the binary serialization format. See comments for + // PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData + // function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION + // accordingly. + //================================================================================================== + + // constructor and destructor are needed because some compilers zero the memory in the + // default constructor and that breaks the serialization related memory markers for + // implicitly padded bytes + ClothFabricBulkData() {} + ~ClothFabricBulkData() {} + + void exportExtraData(PxSerializationContext& stream); + void importExtraData(PxDeserializationContext& context); + static void getBinaryMetaData(PxOutputStream& stream); + + PxU32 mNbParticles; + + shdfnd::Array<PxU32> mPhases; + shdfnd::Array<PxU32> mSets; + shdfnd::Array<float> mRestvalues; + shdfnd::Array<PxU32> mIndices; + shdfnd::Array<PxU32> mTetherAnchors; + shdfnd::Array<PxReal> mTetherLengths; + shdfnd::Array<PxU32> mTriangles; + }; + + + class ClothFabricCore : public Ps::UserAllocated + { + //= ATTENTION! ===================================================================================== + // Changing the data layout of this class breaks the binary serialization format. See comments for + // PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData + // function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION + // accordingly. + //================================================================================================== + public: +// PX_SERIALIZATION + ClothFabricCore(const PxEMPTY); + void exportExtraData(PxSerializationContext& stream); + void importExtraData(PxDeserializationContext& context); + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + ClothFabricCore(); + ~ClothFabricCore(); + + PX_FORCE_INLINE cloth::Fabric& getLowLevelFabric() const { PX_ASSERT(mLowLevelFabric); return *mLowLevelFabric; } + PX_FORCE_INLINE void setLowLevelGpuFabric(cloth::Fabric* fabric) { mLowLevelGpuFabric = fabric; } + + bool load(PxInputStream& stream); + bool load(const PxClothFabricDesc& desc); + + PxU32 getNbParticles() const; + PxU32 getNbPhases() const; + PxU32 getNbSets() const; + PxU32 getNbParticleIndices() const; + PxU32 getNbRestvalues() const; + PxU32 getNbTethers() const; + + PxU32 getPhases(PxClothFabricPhase* userPhaseIndexBuffer, PxU32 bufferSize) const; + PxU32 getRestvalues(PxReal* userRestvalueBuffer, PxU32 bufferSize) const; + + PxU32 getSets(PxU32* userPhaseBuffer, PxU32 bufferSize) const; + PxU32 getParticleIndices(PxU32* userParticleIndexBuffer, PxU32 bufferSize) const; + + PxU32 getTetherAnchors(PxU32* userAnchorBuffer, PxU32 bufferSize) const; + PxU32 getTetherLengths(PxReal* userLengthBuffer, PxU32 bufferSize) const; + + PxClothFabricPhaseType::Enum getPhaseType(PxU32 phaseIndex) const { return mPhaseTypes[phaseIndex]; } + + void scaleRestlengths(PxReal scale); + + private: + cloth::Fabric* mLowLevelFabric; + cloth::Fabric* mLowLevelGpuFabric; + + // Each phase has a type defined in PxClothFabricPhaseType::Enum. + // The size of this array is the same as number of phases (mPhases.size()) + Ps::Array<PxClothFabricPhaseType::Enum> mPhaseTypes; + }; + +} // namespace Sc + + +#endif // PX_USE_CLOTH_API + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/include/ScConstraintCore.h b/PhysX_3.4/Source/SimulationController/include/ScConstraintCore.h new file mode 100644 index 00000000..ff9791e3 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/include/ScConstraintCore.h @@ -0,0 +1,134 @@ +// 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_CONSTRAINTCORE +#define PX_PHYSICS_CONSTRAINTCORE + +#include "CmPhysXCommon.h" +#include "PxConstraintDesc.h" +#include "PsAllocator.h" +#include "PxConstraint.h" + +namespace physx +{ + +class PxConstraint; + +namespace Sc +{ + class ConstraintCore; + class ConstraintSim; + class RigidCore; + + + class ConstraintCore : public Ps::UserAllocated + { + //= ATTENTION! ===================================================================================== + // Changing the data layout of this class breaks the binary serialization format. See comments for + // PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData + // function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION + // accordingly. + //================================================================================================== + public: +// PX_SERIALIZATION + ConstraintCore(const PxEMPTY) : mConnector(NULL), mSim(NULL) {} + PX_FORCE_INLINE void setConstraintFunctions(PxConstraintConnector& n, + const PxConstraintShaderTable& shaders) + { + mConnector = &n; + mSolverPrep = shaders.solverPrep; + mProject = shaders.project; + mVisualize = shaders.visualize; + } + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + ConstraintCore(PxConstraintConnector& connector, const PxConstraintShaderTable& shaders, PxU32 dataSize); + ~ConstraintCore(); + + // The two-step protocol here allows us to unlink the constraint prior to deleting + // the actors when synchronizing the scene, then set the bodies after new actors have been inserted + + void prepareForSetBodies(); + void setBodies(RigidCore* r0v, RigidCore* r1v); + + PxConstraint* getPxConstraint(); + const PxConstraint* getPxConstraint() const; + PX_FORCE_INLINE PxConstraintConnector* getPxConnector() const { return mConnector; } + + PX_FORCE_INLINE PxConstraintFlags getFlags() const { return mFlags; } + void setFlags(PxConstraintFlags flags); + + void getForce(PxVec3& force, PxVec3& torque) const; + + bool updateConstants(void* addr); + + void setBreakForce(PxReal linear, PxReal angular); + void getBreakForce(PxReal& linear, PxReal& angular) const; + + void setMinResponseThreshold(PxReal threshold); + PxReal getMinResponseThreshold() const { return mMinResponseThreshold; } + + void breakApart(); + + PX_FORCE_INLINE PxConstraintVisualize getVisualize() const { return mVisualize; } + PX_FORCE_INLINE PxConstraintProject getProject() const { return mProject; } + PX_FORCE_INLINE PxConstraintSolverPrep getSolverPrep() const { return mSolverPrep; } + PX_FORCE_INLINE PxU32 getConstantBlockSize() const { return mDataSize; } + + PX_FORCE_INLINE void setSim(ConstraintSim* sim) + { + PX_ASSERT((sim==0) ^ (mSim == 0)); + mSim = sim; + } + PX_FORCE_INLINE ConstraintSim* getSim() const { return mSim; } + private: + PxConstraintFlags mFlags; + PxU16 mPaddingFromFlags; // PT: because flags are PxU16 + + PxVec3 mAppliedForce; + PxVec3 mAppliedTorque; + + PxConstraintConnector* mConnector; + PxConstraintProject mProject; + PxConstraintSolverPrep mSolverPrep; + PxConstraintVisualize mVisualize; + PxU32 mDataSize; + PxReal mLinearBreakForce; + PxReal mAngularBreakForce; + PxReal mMinResponseThreshold; + + ConstraintSim* mSim; + }; + +} // namespace Sc + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/include/ScIterators.h b/PhysX_3.4/Source/SimulationController/include/ScIterators.h new file mode 100644 index 00000000..89b67ebc --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/include/ScIterators.h @@ -0,0 +1,129 @@ +// 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_ITERATOR +#define PX_PHYSICS_SCP_ITERATOR + +#include "foundation/PxVec3.h" +#include "PxContact.h" + +namespace physx +{ + +class PxShape; +class PxRigidBody; +class PxsContactManagerOutputIterator; + +namespace Sq +{ + typedef size_t PrunerData; +} + +namespace Sc +{ + class ShapeSim; + class Interaction; + + + struct SqBoundsSync + { + virtual void sync(const PxU32* sqRefs, const PxU32* indices, const PxBounds3* bounds, PxU32 count) = 0; + + virtual ~SqBoundsSync() {} + }; + + struct SqRefFinder + { + virtual PxU32 find(const PxRigidBody * body, const PxShape* shape) = 0; + + virtual ~SqRefFinder() {} + }; + + + struct Contact + { + Contact() + : normal(0.0f) + , point(0.0f) + , separation(0.0f) + , normalForce(0.0f) + {} + + PxVec3 normal; + PxVec3 point; + PxShape* shape0; + PxShape* shape1; + PxReal separation; + PxReal normalForce; + PxU32 faceIndex0; // these are the external indices + PxU32 faceIndex1; + bool normalForceAvailable; + }; + + class ContactIterator + { + public: + + class Pair + { + public: + Pair() : mIter(NULL, NULL, NULL, 0, 0) {} + Pair(const void*& contactPatches, const void*& contactPoints, const PxU32 /*contactDataSize*/, const PxReal*& forces, PxU32 numContacts, PxU32 numPatches, ShapeSim& shape0, ShapeSim& shape1); + Contact* getNextContact(); + + private: + PxU32 mIndex; + PxU32 mNumContacts; + PxContactStreamIterator mIter; + const PxReal* mForces; + Contact mCurrentContact; + ShapeSim* mShape0; + ShapeSim* mShape1; + }; + + ContactIterator() {} + explicit ContactIterator(Interaction** first, Interaction** last, PxsContactManagerOutputIterator& outputs): mCurrent(first), mLast(last), mOffset(0), mOutputs(&outputs) {} + Pair* getNextPair(); + + private: + Interaction** mCurrent; + Interaction** mLast; + Pair mCurrentPair; + PxU32 mOffset; + PxsContactManagerOutputIterator* mOutputs; + + private: + }; + +} // namespace Sc + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/include/ScMaterialCore.h b/PhysX_3.4/Source/SimulationController/include/ScMaterialCore.h new file mode 100644 index 00000000..1a84d220 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/include/ScMaterialCore.h @@ -0,0 +1,74 @@ +// 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_MATERIAL_CORE +#define PX_PHYSICS_SCP_MATERIAL_CORE + +#include "foundation/PxVec3.h" +#include "PsUserAllocated.h" +#include "CmPhysXCommon.h" +#include "PxMaterial.h" +#include "PxsMaterialCore.h" + +namespace physx +{ + +class PxMaterial; + +namespace Sc +{ + +typedef PxsMaterialData MaterialData; + +class MaterialCore : public PxsMaterialCore +{ +//= ATTENTION! ===================================================================================== +// Changing the data layout of this class breaks the binary serialization format. See comments for +// PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData +// function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION +// accordingly. +//================================================================================================== +public: + MaterialCore(const MaterialData& desc); + MaterialCore(const PxEMPTY) : PxsMaterialCore(PxEmpty) {} + MaterialCore(){} + ~MaterialCore(); + static void getBinaryMetaData(PxOutputStream& stream); + + PX_FORCE_INLINE void save(MaterialData& data) const { data = *this; } + PX_FORCE_INLINE void load(const MaterialData& data) { static_cast<MaterialData&>(*this) = data; } // To make synchronization between master material and scene material table less painful + +}; + +} // namespace Sc + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/include/ScParticleSystemCore.h b/PhysX_3.4/Source/SimulationController/include/ScParticleSystemCore.h new file mode 100644 index 00000000..9c8db669 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/include/ScParticleSystemCore.h @@ -0,0 +1,205 @@ +// 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_PARTICLE_SYSTEM_CORE +#define PX_PHYSICS_SCP_PARTICLE_SYSTEM_CORE + +#include "CmPhysXCommon.h" +#include "PxPhysXConfig.h" +#if PX_USE_PARTICLE_SYSTEM_API + +#include "PsArray.h" +#include "CmBitMap.h" +#include "ScActorCore.h" +#include "PxFiltering.h" +#include "PtParticleSystemCore.h" +#include "particles/PxParticleBaseFlag.h" +#include "particles/PxParticleFluidReadData.h" + +namespace physx +{ + +class PxParticleCreationData; +class PxParticleBase; +class PxvObjectFactory; + +#if PX_SUPPORT_GPU_PHYSX +class PxParticleDeviceExclusiveAccess; +#endif + +namespace Pt +{ + class ParticleData; + class ParticleSystemState; +} + +#define MAX_PARTICLES_PER_PARTICLE_SYSTEM PT_PARTICLE_SYSTEM_PARTICLE_LIMIT +#define SPH_KERNEL_RADIUS_MULT 2.0f +#define SPH_REST_DENSITY 1000.0f + +namespace Sc +{ + + class ParticleSystemSim; + + class ParticleSystemCore : public ActorCore + { + //= ATTENTION! ===================================================================================== + // Changing the data layout of this class breaks the binary serialization format. See comments for + // PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData + // function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION + // accordingly. + //================================================================================================== + public: +// PX_SERIALIZATION + ParticleSystemCore(const PxEMPTY) : ActorCore(PxEmpty), mSimulationFilterData(PxEmpty), mLLParameter(PxEmpty) {} + void exportExtraData(PxSerializationContext& stream); + void importExtraData(PxDeserializationContext& context); + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + ParticleSystemCore(const PxActorType::Enum&, PxU32, bool); + ~ParticleSystemCore(); + + //--------------------------------------------------------------------------------- + // External API + //--------------------------------------------------------------------------------- + PxParticleBase* getPxParticleBase(); + + PxReal getStiffness() const; + void setStiffness(PxReal); + + PxReal getViscosity() const; + void setViscosity(PxReal); + + PxReal getDamping() const; + void setDamping(PxReal); + + PxReal getParticleMass() const; + void setParticleMass(PxReal); + + PxReal getRestitution() const; + void setRestitution(PxReal); + + PxReal getDynamicFriction() const; + void setDynamicFriction(PxReal); + + PxReal getStaticFriction() const; + void setStaticFriction(PxReal); + + const PxFilterData& getSimulationFilterData() const; + void setSimulationFilterData(const PxFilterData& data); + void resetFiltering(); + + PxParticleBaseFlags getFlags() const; + void setFlags(PxParticleBaseFlags); + PxU32 getInternalFlags() const; + void setInternalFlags(PxParticleBaseFlags flags); + void notifyCpuFallback(); + + PxParticleReadDataFlags getParticleReadDataFlags() const; + void setParticleReadDataFlags(PxParticleReadDataFlags); + + PxU32 getMaxParticles() const; + + PxReal getMaxMotionDistance() const; + void setMaxMotionDistance(PxReal); + PxReal getRestOffset() const; + void setRestOffset(PxReal); + PxReal getContactOffset() const; + void setContactOffset(PxReal); + PxReal getGridSize() const; + void setGridSize(PxReal); + PxReal getRestParticleDistance() const; + void setRestParticleDistance(PxReal); + + //---------------------------------------------------------------------------------------------------------------------------// + + bool createParticles(const PxParticleCreationData& creationData); + void releaseParticles(PxU32 numParticles, const PxStrideIterator<const PxU32>& indices); + void releaseParticles(); + void setPositions(PxU32 numParticles, const PxStrideIterator<const PxU32>& indexBuffer, const PxStrideIterator<const PxVec3>& positionBuffer); + void setVelocities(PxU32 numParticles, const PxStrideIterator<const PxU32>& indexBuffer, const PxStrideIterator<const PxVec3>& velocityBuffer); + void setRestOffsets(PxU32 numParticles, const PxStrideIterator<const PxU32>& indexBuffer, const PxStrideIterator<const PxF32>& restOffsetBuffer); + void addDeltaVelocities(const Cm::BitMap& bufferMap, const PxVec3* buffer, PxReal multiplier); + + void getParticleReadData(PxParticleFluidReadData& readData) const; + + PxU32 getParticleCount() const; + const Cm::BitMap& getParticleMap() const; + PxBounds3 getWorldBounds() const; + + //---------------------------------------------------------------------------------------------------------------------------// + + const PxVec3& getExternalAcceleration() const; + void setExternalAcceleration(const PxVec3&); + + const PxPlane& getProjectionPlane() const; + void setProjectionPlane(const PxPlane& plane); + +#if PX_SUPPORT_GPU_PHYSX + void enableDeviceExclusiveModeGpu(); + PxParticleDeviceExclusiveAccess* + getDeviceExclusiveAccessGpu() const; + bool isGpu() const; +#endif + + public: + // non-DDI methods: + Pt::ParticleSystemParameter& getLowLevelParameter() { return mLLParameter; } + ParticleSystemSim* getSim() const; + Pt::ParticleData* obtainStandaloneData(); + void returnStandaloneData(Pt::ParticleData* stateBuffer); + + void onOriginShift(const PxVec3& shift); + + private: + Pt::ParticleSystemState& getParticleState(); + const Pt::ParticleSystemState& getParticleState() const; + + private: + Pt::ParticleData* mStandaloneData; + PxFilterData mSimulationFilterData; // The filter data + + // External acceleration is set every frame for the LL sim object + PxVec3 mExternalAcceleration; + + // Used for two way interaction executed in HL + PxReal mParticleMass; + + // Merged particleSystem/particleFluid, API + internal parameter + Pt::ParticleSystemParameter mLLParameter; + }; + +} // namespace Sc + +} + +#endif // PX_USE_PARTICLE_SYSTEM_API +#endif // PX_PHYSICS_SCP_PARTICLE_SYSTEM_CORE diff --git a/PhysX_3.4/Source/SimulationController/include/ScPhysics.h b/PhysX_3.4/Source/SimulationController/include/ScPhysics.h new file mode 100644 index 00000000..62a41e28 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/include/ScPhysics.h @@ -0,0 +1,137 @@ +// 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_SC_PHYSICS +#define PX_PHYSICS_SC_PHYSICS + +#include "PxPhysics.h" +#include "PxScene.h" +#include "PsUserAllocated.h" +#include "CmPhysXCommon.h" +#include "PsBasicTemplates.h" +#include "PxActor.h" + +namespace physx +{ + +namespace cloth +{ +class Factory; +} + + +class PxMaterial; +class PxTolerancesScale; +struct PxvOffsetTable; + +#if PX_SUPPORT_GPU_PHYSX +class PxPhysXGpu; +#endif + +namespace Sc +{ + class Scene; + class StaticCore; + class RigidCore; + class BodyCore; + class ArticulationCore; + class ConstraintCore; + class ParticleSystemCore; + class ClothCore; + class ShapeCore; + + struct OffsetTable + { + PX_FORCE_INLINE OffsetTable() {} + + PX_FORCE_INLINE PxActor* convertScRigidStatic2PxActor(StaticCore* sc) const { return Ps::pointerOffset<PxActor*>(sc, scRigidStatic2PxActor); } + PX_FORCE_INLINE PxActor* convertScRigidDynamic2PxActor(BodyCore* sc) const { return Ps::pointerOffset<PxActor*>(sc, scRigidDynamic2PxActor); } + PX_FORCE_INLINE PxActor* convertScArticulationLink2PxActor(BodyCore* sc) const { return Ps::pointerOffset<PxActor*>(sc, scArticulationLink2PxActor); } + + PX_FORCE_INLINE PxShape* convertScShape2Px(ShapeCore* sc) const { return Ps::pointerOffset<PxShape*>(sc, scShape2Px); } + PX_FORCE_INLINE const PxShape* convertScShape2Px(const ShapeCore* sc) const { return Ps::pointerOffset<const PxShape*>(sc, scShape2Px); } + + PX_FORCE_INLINE PxArticulation* convertScArticulation2Px(ArticulationCore* sc) const { return Ps::pointerOffset<PxArticulation*>(sc, scArticulation2Px); } + PX_FORCE_INLINE const PxArticulation* convertScArticulation2Px(const ArticulationCore* sc) const { return Ps::pointerOffset<const PxArticulation*>(sc, scArticulation2Px); } + + PX_FORCE_INLINE PxConstraint* convertScConstraint2Px(ConstraintCore* sc) const { return Ps::pointerOffset<PxConstraint*>(sc, scConstraint2Px); } + PX_FORCE_INLINE const PxConstraint* convertScConstraint2Px(const ConstraintCore* sc) const { return Ps::pointerOffset<const PxConstraint*>(sc, scConstraint2Px); } + + PX_FORCE_INLINE PxParticleFluid* convertScParticleSystem2PxParticleFluid(ParticleSystemCore* sc) const { return Ps::pointerOffset<PxParticleFluid*>(sc, scParticleSystem2PxParticleFluid); } + PX_FORCE_INLINE PxParticleSystem* convertScParticleSystem2Px(ParticleSystemCore* sc) const { return Ps::pointerOffset<PxParticleSystem*>(sc, scParticleSystem2Px); } + + PX_FORCE_INLINE PxCloth* convertScCloth2Px(ClothCore* sc) const { return Ps::pointerOffset<PxCloth*>(sc, scCloth2Px); } + + ptrdiff_t scRigidStatic2PxActor; + ptrdiff_t scRigidDynamic2PxActor; + ptrdiff_t scArticulationLink2PxActor; + ptrdiff_t scShape2Px; + ptrdiff_t scArticulation2Px; + ptrdiff_t scConstraint2Px; + ptrdiff_t scParticleSystem2PxParticleFluid; + ptrdiff_t scParticleSystem2Px; + ptrdiff_t scCloth2Px; + + ptrdiff_t scCore2PxActor[PxActorType::eACTOR_COUNT]; + }; + extern OffsetTable gOffsetTable; + + class Physics : public Ps::UserAllocated + { + public: + PX_FORCE_INLINE static Physics& getInstance() { return *mInstance; } + + Physics(const PxTolerancesScale&, const PxvOffsetTable& pxvOffsetTable); + ~Physics(); // use release() instead + public: + void release(); + + PX_FORCE_INLINE const PxTolerancesScale& getTolerancesScale() const { return mScale; } + +#if PX_USE_CLOTH_API + void registerCloth(); + PX_FORCE_INLINE bool hasLowLevelClothFactory() const { return mLowLevelClothFactory != 0; } + PX_FORCE_INLINE cloth::Factory& getLowLevelClothFactory() { PX_ASSERT(mLowLevelClothFactory); return *mLowLevelClothFactory; } +#endif + + private: + PxTolerancesScale mScale; + static Physics* mInstance; + cloth::Factory* mLowLevelClothFactory; + + public: + static const PxReal sWakeCounterOnCreation; + }; + +} // namespace Sc + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/include/ScRigidCore.h b/PhysX_3.4/Source/SimulationController/include/ScRigidCore.h new file mode 100644 index 00000000..6ab9c8fe --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/include/ScRigidCore.h @@ -0,0 +1,93 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-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_RB_CORE +#define PX_PHYSICS_SCP_RB_CORE + +#include "ScActorCore.h" +#include "PxvDynamics.h" +#include "PxShape.h" + +namespace physx +{ + +namespace Sc +{ + + class RigidSim; + + struct ShapeChangeNotifyFlag + { + enum Enum + { + eGEOMETRY = 1<<0, + eMATERIAL = 1<<1, + eSHAPE2BODY = 1<<2, + eFILTERDATA = 1<<3, + eCONTACTOFFSET = 1<<4, + eRESTOFFSET = 1<<5, + eFLAGS = 1<<6, + eRESET_FILTERING = 1<<7 + + }; + }; + typedef PxFlags<ShapeChangeNotifyFlag::Enum, PxU32> ShapeChangeNotifyFlags; + PX_FLAGS_OPERATORS(ShapeChangeNotifyFlag::Enum,PxU32) + + + class ShapeCore; + + class RigidCore : public ActorCore + { + //= ATTENTION! ===================================================================================== + // Changing the data layout of this class breaks the binary serialization format. See comments for + // PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData + // function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION + // accordingly. + //================================================================================================== + public: + PxActor* getPxActor() const; + void addShapeToScene(ShapeCore& shape); + void removeShapeFromScene(ShapeCore& shape, bool wakeOnLostTouch); + void onShapeChange(ShapeCore& shape, ShapeChangeNotifyFlags notifyFlags, PxShapeFlags newShapeFlags = PxShapeFlags(), bool forceBoundsUpdate = false); + + RigidSim* getSim() const; + static void getBinaryMetaData(PxOutputStream& stream); + protected: + RigidCore(const PxEMPTY) : ActorCore(PxEmpty) {} + RigidCore(PxActorType::Enum type); + ~RigidCore(); + }; + +} // namespace Sc + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/include/ScScene.h b/PhysX_3.4/Source/SimulationController/include/ScScene.h new file mode 100644 index 00000000..4e80a610 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/include/ScScene.h @@ -0,0 +1,1043 @@ +// 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_SCENE +#define PX_PHYSICS_SCP_SCENE + +#include "foundation/PxProfiler.h" +#include "CmPhysXCommon.h" +#include "PxPhysXConfig.h" +#include "PxScene.h" +#include "PxSceneDesc.h" +#include "PxSimulationEventCallback.h" +#include "PsPool.h" +#include "PsHashSet.h" +#include "CmRenderOutput.h" +#include "CmTask.h" +#include "CmFlushPool.h" +#include "CmPreallocatingPool.h" +#include "CmBitMap.h" +#include "ScIterators.h" +#include "PxvContext.h" +#include "PxsMaterialManager.h" +#include "PxvManager.h" +#include "ScBodyCore.h" + +#define EXTRA_PROFILING 0 +#define PX_MAX_DOMINANCE_GROUP 32 + + +#if EXTRA_PROFILING +#include <cstdio> +#endif + +class OverlapFilterTask; + +namespace physx +{ +class PxSceneGpu; +struct PxTriggerPair; + +class PxsIslandManager; +class PxsSimulationController; +class PxsSimulationControllerCallback; +class PxsMemoryManager; + +#if PX_SUPPORT_GPU_PHYSX +class PxsKernelWranglerManager; +class PxsHeapMemoryAllocatorManager; +#endif + +namespace IG +{ + class SimpleIslandManager; +} + +class PxsCCDContext; + +namespace Cm +{ + class DeferredIDPool; + class IDPool; +} +#if PX_USE_CLOTH_API +namespace cloth +{ + class Solver; + class Factory; +} +#endif + +namespace Bp +{ + class SimpleAABBManager; + class BroadPhase; + class BoundsArray; +} + + +namespace Dy +{ + class Articulation; + class Context; +} + +namespace Pt +{ + class Context; +} + +namespace Sc +{ + class ActorSim; + class ElementSim; + class Interaction; + + class ShapeCore; + class RigidCore; + class StaticCore; + class ConstraintCore; + class MaterialCore; + class ArticulationCore; + class ArticulationJointCore; + class LLArticulationPool; + class ClothCore; + class BodyCore; + class ParticleSystemCore; + + class NPhaseCore; + class LowLevelThreadingThunk; + class Client; + class ConstraintInteraction; + + class BodySim; + class ShapeSim; + class RigidSim; + class StaticSim; + class ConstraintSim; + struct ConstraintGroupNode; + class ConstraintProjectionManager; + struct TriggerPairExtraData; + class ObjectIDTracker; + class ActorPairReport; + class ContactStreamManager; + class SqBoundsManager; + class ShapeInteraction; + class ElementInteractionMarker; + class ArticulationSim; + +#if PX_USE_PARTICLE_SYSTEM_API + class ParticleSystemSim; + class ParticlePacketShape; +#endif + +#if PX_USE_CLOTH_API + class ClothShape; +#endif + + class SimStats; + + struct SimStateData; + + struct BatchInsertionState + { + BodySim* bodySim; + StaticSim*staticSim; + ShapeSim* shapeSim; + ptrdiff_t staticActorOffset; + ptrdiff_t staticShapeTableOffset; + ptrdiff_t dynamicActorOffset; + ptrdiff_t dynamicShapeTableOffset; + ptrdiff_t shapeOffset; + }; + + struct BatchRemoveState + { + Ps::InlineArray<Sc::ShapeSim*, 64> bufferedShapes; + Ps::InlineArray<const Sc::ShapeCore*, 64> removedShapes; + }; + + + struct InteractionType + { + enum Enum + { + eOVERLAP = 0, // corresponds to ShapeInteraction + eTRIGGER, // corresponds to TriggerInteraction + eMARKER, // corresponds to ElementInteractionMarker + eTRACKED_IN_SCENE_COUNT, // not a real type, interactions above this limit are tracked in the scene + eCONSTRAINTSHADER, // corresponds to ConstraintInteraction +#if PX_USE_PARTICLE_SYSTEM_API + ePARTICLE_BODY, // corresponds to ParticleElementRbElementInteraction +#endif + eARTICULATION, // corresponds to ArticulationJointSim + + eINVALID + }; + }; + + + struct SceneInternalFlag + { + enum Enum + { + eSCENE_SIP_STATES_DIRTY_DOMINANCE = (1<<1), + eSCENE_SIP_STATES_DIRTY_VISUALIZATION = (1<<2), + eSCENE_DEFAULT = 0 + }; + }; + + + struct SimulationStage + { + enum Enum + { + eCOMPLETE, + eCOLLIDE, + eFETCHCOLLIDE, + eADVANCE, + eFETCHRESULT + }; + }; + + + + class Scene : public Ps::UserAllocated + { + struct SimpleBodyPair + { + BodySim* body1; + BodySim* body2; + PxU32 body1ID; + PxU32 body2ID; + }; + + PX_NOCOPY(Scene) + + //--------------------------------------------------------------------------------- + // External interface + //--------------------------------------------------------------------------------- + public: + + void release(); + + PX_FORCE_INLINE void setGravity(const PxVec3& g) { mGravity = g; mBodyGravityDirty = true; } + PX_FORCE_INLINE PxVec3 getGravity() const { return mGravity; } + PX_FORCE_INLINE void setElapsedTime(const PxReal t) { mDt = t; mOneOverDt = t > 0.0f ? 1.0f/t : 0.0f; } + + void setBounceThresholdVelocity(const PxReal t); + PxReal getBounceThresholdVelocity() const; + + PX_FORCE_INLINE void setPublicFlags(PxSceneFlags flags) { mPublicFlags = flags; } + PX_FORCE_INLINE PxSceneFlags getPublicFlags() const { return mPublicFlags; } + + void setFrictionType(PxFrictionType::Enum model); + PxFrictionType::Enum getFrictionType() const; + void setPCM(bool enabled); + void setContactCache(bool enabled); + + void addStatic(StaticCore&, void*const *shapes, PxU32 nbShapes, size_t shapePtrOffset, PxBounds3* uninflatedBounds); + void removeStatic(StaticCore&, Ps::InlineArray<const Sc::ShapeCore*,64>& removedShapes, bool wakeOnLostTouch); + + void addBody(BodyCore&, void*const *shapes, PxU32 nbShapes, size_t shapePtrOffset, PxBounds3* uninflatedBounds); + void removeBody(BodyCore&, Ps::InlineArray<const Sc::ShapeCore*,64>& removedShapes, bool wakeOnLostTouch); + + // Batch insertion API. + // the bounds generated here are the uninflated bounds for the shapes, *if* they are trigger or sim shapes. + // It's up to the caller to ensure the bounds array is big enough. + // Some care is required in handling these since sim and SQ tweak the bounds in slightly different ways. + + void startBatchInsertion(BatchInsertionState&); + void addStatic(PxActor* actor, BatchInsertionState&, PxBounds3* outBounds); + void addBody(PxActor* actor, BatchInsertionState&, PxBounds3* outBounds); + void finishBatchInsertion(BatchInsertionState&); + + // Batch remove helpers + PX_FORCE_INLINE void setBatchRemove(BatchRemoveState* bs) { mBatchRemoveState = bs; } + PX_FORCE_INLINE BatchRemoveState* getBatchRemove() const { return mBatchRemoveState; } + void prefetchForRemove(const BodyCore& ) const; + void prefetchForRemove(const StaticCore& ) const; + + void addConstraint(ConstraintCore&, RigidCore*, RigidCore*); + void removeConstraint(ConstraintCore&); + + void addArticulation(ArticulationCore&, BodyCore& root); + void removeArticulation(ArticulationCore&); + + void addArticulationJoint(ArticulationJointCore&, BodyCore& parent, BodyCore& child); + void removeArticulationJoint(ArticulationJointCore&); + +#if PX_USE_PARTICLE_SYSTEM_API + void addParticleSystem(ParticleSystemCore&); + void removeParticleSystem(ParticleSystemCore&, bool isRelease); + + PxU32 getNbParticleSystems() const; + ParticleSystemCore* const* getParticleSystems(); +#endif + bool hasParticleSystems() const; + +#if PX_USE_CLOTH_API + bool addCloth(ClothCore&); + void removeCloth(ClothCore&); +#endif + bool hasCloths() const; + + PxU32 getNbArticulations() const; + Sc::ArticulationCore* const* getArticulations(); + + PxU32 getNbConstraints() const; + Sc::ConstraintCore*const * getConstraints(); + + void initContactsIterator(ContactIterator&, PxsContactManagerOutputIterator&); + + // Simulation events + void setSimulationEventCallback(PxSimulationEventCallback* callback, PxClientID client); + PxSimulationEventCallback* getSimulationEventCallback(PxClientID client) const; + + // Contact modification + void setContactModifyCallback(PxContactModifyCallback* callback); + PxContactModifyCallback* getContactModifyCallback() const; + void setCCDContactModifyCallback(PxCCDContactModifyCallback* callback); + PxCCDContactModifyCallback* getCCDContactModifyCallback() const; + + void setCCDMaxPasses(PxU32 ccdMaxPasses); + PxU32 getCCDMaxPasses() const; + + // Broad-phase callback + void setBroadPhaseCallback(PxBroadPhaseCallback* callback, PxClientID client); + PxBroadPhaseCallback* getBroadPhaseCallback(PxClientID client) const; + + // Broad-phase management + void finishBroadPhase(const PxU32 ccdPass, PxBaseTask* continuation); + void finishBroadPhaseStage2(const PxU32 ccdPass); + void preallocateContactManagers(PxBaseTask* continuation); + + void islandInsertion(PxBaseTask* continuation); + void registerContactManagers(PxBaseTask* continuation); + void registerInteractions(PxBaseTask* continuation); + void registerSceneInteractions(PxBaseTask* continuation); + + void secondPassNarrowPhase(PxBaseTask* continuation); + + // Groups + void setDominanceGroupPair(PxDominanceGroup group1, PxDominanceGroup group2, const PxDominanceGroupPair& dominance); + PxDominanceGroupPair getDominanceGroupPair(PxDominanceGroup group1, PxDominanceGroup group2) const; + + void setSolverBatchSize(PxU32 solverBatchSize); + PxU32 getSolverBatchSize() const; + + void setVisualizationParameter(PxVisualizationParameter::Enum param, PxReal value); + PxReal getVisualizationParameter(PxVisualizationParameter::Enum param) const; + + void setVisualizationCullingBox(const PxBounds3& box); + const PxBounds3& getVisualizationCullingBox() const; + + // Run + void simulate(PxReal timeStep, PxBaseTask* continuation); + void advance(PxReal timeStep, PxBaseTask* continuation); + void collide(PxReal timeStep, PxBaseTask* continuation); + void endSimulation(); + void flush(bool sendPendingReports); + void fireBrokenConstraintCallbacks(); + void fireTriggerCallbacks(); + void fireQueuedContactCallbacks(bool asPartOfFlush); + void fireOnAdvanceCallback(); + + const Ps::Array<PxContactPairHeader>& + getQueuedContactPairHeaders(); + + bool fireOutOfBoundsCallbacks(); + void prepareOutOfBoundsCallbacks(); + void postCallbacksPreSync(); + void postReportsCleanup(); + void fireCallbacksPostSync(); + void syncSceneQueryBounds(SqBoundsSync& sync, SqRefFinder& finder); + PxU32 getErrorState(); + + PxU32 getDefaultContactReportStreamBufferSize() const; + + PxReal getFrictionOffsetThreshold() const; + + void setLimits(const PxSceneLimits& limits); + const PxSceneLimits& getLimits() const; + + void visualizeStartStep(); + void visualizeEndStep(); + Cm::RenderBuffer& getRenderBuffer(); + + void setNbContactDataBlocks(PxU32 blockCount); + PxU32 getNbContactDataBlocksUsed() const; + PxU32 getMaxNbContactDataBlocksUsed() const; + PxU32 getMaxNbConstraintDataBlocksUsed() const; + + void setScratchBlock(void* addr, PxU32 size); + +// PX_ENABLE_SIM_STATS + void getStats(PxSimulationStatistics& stats) const; + PX_FORCE_INLINE SimStats& getStatsInternal() { return *mStats; } +// PX_ENABLE_SIM_STATS + + PX_DEPRECATED void buildActiveTransforms(); + PX_DEPRECATED PxActiveTransform* getActiveTransforms(PxU32& nbTransformsOut, PxClientID client); + void buildActiveActors(); + PxActor** getActiveActors(PxU32& nbActorsOut, PxClientID client); + + void finalizeContactStreamAndCreateHeader(PxContactPairHeader& header, + const ActorPairReport& aPair, + ContactStreamManager& cs, PxU32 removedShapeTestMask); + + PxClientID createClient(); + void setClientBehaviorFlags(PxClientID client, PxClientBehaviorFlags clientBehaviorFlags); + PxClientBehaviorFlags getClientBehaviorFlags(PxClientID client) const; + +#if PX_USE_CLOTH_API + void setClothInterCollisionDistance(PxF32 distance); + PxF32 getClothInterCollisionDistance() const; + void setClothInterCollisionStiffness(PxF32 stiffness); + PxF32 getClothInterCollisionStiffness() const; + void setClothInterCollisionNbIterations(PxU32 nbIterations); + PxU32 getClothInterCollisionNbIterations() const; + void createClothSolver(); +#endif + + PxSceneGpu* getSceneGpu(bool createIfNeeded = false); + + PxTaskManager* getTaskManagerPtr() const { return mTaskManager; } + + void shiftOrigin(const PxVec3& shift); + + Ps::Pool<SimStateData>* getSimStateDataPool() { return mSimStateDataPool; } + + //--------------------------------------------------------------------------------- + // Miscellaneous + //--------------------------------------------------------------------------------- + //internal public methods: + public: + Scene(const PxSceneDesc& desc, PxU64 contextID); + ~Scene() {} //use release() plz. + + void preAllocate(PxU32 nbStatics, PxU32 nbBodies, PxU32 nbStaticShapes, PxU32 nbDynamicShapes); + + PX_FORCE_INLINE PxsContext* getLowLevelContext() { return mLLContext; } + PX_FORCE_INLINE const PxsContext* getLowLevelContext() const { return mLLContext; } + + PX_FORCE_INLINE Dy::Context* getDynamicsContext() { return mDynamicsContext; } + PX_FORCE_INLINE const Dy::Context* getDynamicsContext() const { return mDynamicsContext; } + + PX_FORCE_INLINE PxsSimulationController* getSimulationController() { return mSimulationController; } + PX_FORCE_INLINE const PxsSimulationController* getSimulationController() const { return mSimulationController; } + + PX_FORCE_INLINE Bp::SimpleAABBManager* getAABBManager() { return mAABBManager; } + PX_FORCE_INLINE const Bp::SimpleAABBManager*getAABBManager() const { return mAABBManager; } + PX_FORCE_INLINE Ps::Array<BodySim*>& getCcdBodies() { return mCcdBodies; } + +#if PX_USE_PARTICLE_SYSTEM_API + PX_FORCE_INLINE Pt::Context* getParticleContext() { return mParticleContext; } +#endif + + /*PX_FORCE_INLINE PxsIslandManager* getIslandManager() { return mIslandManager; } + PX_FORCE_INLINE const PxsIslandManager* getIslandManager() const { return mIslandManager; }*/ + + PX_FORCE_INLINE IG::SimpleIslandManager* getSimpleIslandManager() { return mSimpleIslandManager; } + PX_FORCE_INLINE const IG::SimpleIslandManager* getSimpleIslandManager() const { return mSimpleIslandManager; } + + PX_FORCE_INLINE Sc::SimulationStage::Enum getSimulationStage() const { return mSimulationStage; } + PX_FORCE_INLINE void setSimulationStage(Sc::SimulationStage::Enum stage) { mSimulationStage = stage; } + + void addShape(RigidSim&, ShapeCore&, PxBounds3* uninflatedBounds); + void removeShape(ShapeSim&, bool wakeOnLostTouch); + + void registerShapeInNphase(const ShapeCore& shapeCore); + void unregisterShapeFromNphase(const ShapeCore& shapeCore); + + void notifyNphaseOnUpdateShapeMaterial(const ShapeCore& shapeCore); + + // Get an array of the active actors. + PX_FORCE_INLINE BodyCore*const* getActiveBodiesArray() const { return mActiveBodies.begin(); } + PX_FORCE_INLINE PxU32 getNumActiveBodies() const { return mActiveBodies.size(); } + + PX_FORCE_INLINE PxU32 getNbInteractions(InteractionType::Enum type) const { return mInteractions[type].size(); } + PX_FORCE_INLINE PxU32 getNbActiveInteractions(InteractionType::Enum type) const { return mActiveInteractionCount[type]; } + // Get all interactions of a certain type + PX_FORCE_INLINE Interaction** getInteractions(InteractionType::Enum type) { return mInteractions[type].begin(); } + PX_FORCE_INLINE Interaction** getActiveInteractions(InteractionType::Enum type) { return mInteractions[type].begin(); } + + void registerInteraction(Interaction* interaction, bool active); + void unregisterInteraction(Interaction* interaction); + + void notifyInteractionActivated(Interaction* interaction); + void notifyInteractionDeactivated(Interaction* interaction); + + // for pool management of interaction arrays, a major cause of dynamic allocation + void** allocatePointerBlock(PxU32 size); + void deallocatePointerBlock(void**, PxU32 size); + + private: + // Get the number of active one-way dominator actors + PX_FORCE_INLINE PxU32 getActiveKinematicBodiesCount() const { return mActiveKinematicBodyCount; } + + // Get an iterator to the active one-way dominator actors + PX_FORCE_INLINE BodyCore*const* getActiveKinematicBodies() const { return mActiveBodies.begin(); } + + // Get the number of active non-kinematic actors + PX_FORCE_INLINE PxU32 getActiveDynamicBodiesCount() const { return mActiveBodies.size() - mActiveKinematicBodyCount; } + + // Get the active non-kinematic actors + PX_FORCE_INLINE BodyCore*const* getActiveDynamicBodies() const { return mActiveBodies.begin() + mActiveKinematicBodyCount; } + + void swapInteractionArrayIndices(PxU32 id1, PxU32 id2, InteractionType::Enum type); + + + + public: + + PX_FORCE_INLINE Cm::BitMap& getDirtyShapeSimMap() { return mDirtyShapeSimMap; } + + void addToActiveBodyList(BodySim& actor); + void removeFromActiveBodyList(BodySim& actor); + void swapInActiveBodyList(BodySim& body); // call when an active body gets switched from dynamic to kinematic or vice versa + + void addBrokenConstraint(Sc::ConstraintCore*); + void addActiveBreakableConstraint(Sc::ConstraintSim*, ConstraintInteraction*); + void removeActiveBreakableConstraint(Sc::ConstraintSim*); + //the Actor should register its top level shapes with these. + void removeBody(BodySim&); + + void raiseSceneFlag(SceneInternalFlag::Enum flag) { mInternalFlags |= flag; } + + //lists of actors woken up or put to sleep last simulate + void onBodyWakeUp(BodySim* body); + void onBodySleep(BodySim* body); + + bool isValid() const; + + void addToLostTouchList(BodySim* body1, BodySim* body2); + + void initDominanceMatrix(); + + void setCreateContactReports(bool s); + +// PX_AGGREGATE + PxU32 createAggregate(void* userData, bool selfCollisions); + void deleteAggregate(PxU32 id); +//~PX_AGGREGATE + Dy::Articulation* createLLArticulation(Sc::ArticulationSim* sim); + void destroyLLArticulation(Dy::Articulation&); + + + Ps::Pool<ConstraintInteraction>* + getConstraintInteractionPool() const { return mConstraintInteractionPool; } + public: + PxBroadPhaseType::Enum getBroadPhaseType() const; + bool getBroadPhaseCaps(PxBroadPhaseCaps& caps) const; + PxU32 getNbBroadPhaseRegions() const; + PxU32 getBroadPhaseRegions(PxBroadPhaseRegionInfo* userBuffer, PxU32 bufferSize, PxU32 startIndex) const; + PxU32 addBroadPhaseRegion(const PxBroadPhaseRegion& region, bool populateRegion); + bool removeBroadPhaseRegion(PxU32 handle); + void** getOutOfBoundsAggregates(); + PxU32 getNbOutOfBoundsAggregates(); + void clearOutOfBoundsAggregates(); + + + PX_FORCE_INLINE const PxsMaterialManager& getMaterialManager() const { return mMaterialManager; } + PX_FORCE_INLINE PxsMaterialManager& getMaterialManager() { return mMaterialManager; } + + //material management functions to be called from Scb::Scene + void registerMaterialInNP(const PxsMaterialCore& materialCore); + void updateMaterialInNP(const PxsMaterialCore& materialCore); + void unregisterMaterialInNP(const PxsMaterialCore& materialCore); + + // Collision filtering + void setFilterShaderData(const void* data, PxU32 dataSize); + PX_FORCE_INLINE const void* getFilterShaderDataFast() const { return mFilterShaderData; } + PX_FORCE_INLINE PxU32 getFilterShaderDataSizeFast() const { return mFilterShaderDataSize; } + PX_FORCE_INLINE PxSimulationFilterShader getFilterShaderFast() const { return mFilterShader; } + PX_FORCE_INLINE PxSimulationFilterCallback* getFilterCallbackFast() const { return mFilterCallback; } + + PX_FORCE_INLINE PxU32 getTimeStamp() const { return mTimeStamp; } + PX_FORCE_INLINE PxU32 getReportShapePairTimeStamp() const { return mReportShapePairTimeStamp; } + + PX_FORCE_INLINE PxReal getOneOverDt() const { return mOneOverDt; } + PX_FORCE_INLINE PxReal getDt() const { return mDt; } + + PX_FORCE_INLINE const PxVec3& getGravityFast() const { return mGravity; } + PX_FORCE_INLINE bool readFlag(SceneInternalFlag::Enum flag) const { return (mInternalFlags & flag) != 0; } + PX_FORCE_INLINE bool readPublicFlag(PxSceneFlag::Enum flag) const { return (mPublicFlags & flag); } + + PX_FORCE_INLINE NPhaseCore* getNPhaseCore() const { return mNPhaseCore; } + + void checkConstraintBreakage(); + + PX_FORCE_INLINE Ps::Array<TriggerPairExtraData>& + getTriggerBufferExtraData() { return *mTriggerBufferExtraData; } + PX_FORCE_INLINE Ps::Array<PxTriggerPair>& getTriggerBufferAPI() { return mTriggerBufferAPI; } + void reserveTriggerReportBufferSpace(const PxU32 pairCount, PxTriggerPair*& triggerPairBuffer, TriggerPairExtraData*& triggerPairExtraBuffer); + + PX_FORCE_INLINE ObjectIDTracker& getRigidIDTracker() { return *mRigidIDTracker; } + PX_FORCE_INLINE ObjectIDTracker& getShapeIDTracker() { return *mShapeIDTracker; } + + PX_FORCE_INLINE void markReleasedBodyIDForLostTouch(PxU32 id) { mLostTouchPairsDeletedBodyIDs.growAndSet(id); } + void resizeReleasedBodyIDMaps(PxU32 maxActors, PxU32 numActors); + + PX_FORCE_INLINE StaticSim& getStaticAnchor() { return *mStaticAnchor; } + + PX_FORCE_INLINE ConstraintProjectionManager& getProjectionManager() { return *mProjectionManager; } + + PX_FORCE_INLINE Bp::BoundsArray& getBoundsArray() const { return *mBoundsArray; } + PX_FORCE_INLINE void updateContactDistance(PxU32 idx, PxReal distance) { (*mContactDistance)[idx] = distance; mHasContactDistanceChanged = true; } + PX_FORCE_INLINE SqBoundsManager& getSqBoundsManager() const { return *mSqBoundsManager; } + + PX_FORCE_INLINE PxReal getVisualizationScale() const { return mVisualizationScale; } // This is actually redundant but makes checks whether debug visualization is enabled faster + + PX_FORCE_INLINE BodyCore* const* getSleepBodiesArray(PxU32& count) { count = mSleepBodies.size(); return mSleepBodies.getEntries(); } + + PX_FORCE_INLINE PxTaskManager& getTaskManager() const { PX_ASSERT(mTaskManager); return *mTaskManager; } + + Cm::FlushPool* getFlushPool(); + + PX_FORCE_INLINE bool getStabilizationEnabled() const { return mEnableStabilization; } + + PX_FORCE_INLINE void setPostSolverVelocityNeeded() { mContactReportsNeedPostSolverVelocity = true; } + + ObjectIDTracker& getConstraintIDTracker() { return *mConstraintIDTracker; } + + + void* allocateConstraintBlock(PxU32 size); + void deallocateConstraintBlock(void* addr, PxU32 size); + + PX_INLINE ObjectIDTracker& getElementIDPool() { return *mElementIDPool; } + + PX_FORCE_INLINE Cm::BitMap& getVelocityModifyMap() { return mVelocityModifyMap; } + + void stepSetupCollide();//This is very important to guarantee thread safty in the collide + PX_FORCE_INLINE void addToPosePreviewList(BodySim& b) { PX_ASSERT(!mPosePreviewBodies.contains(&b)); mPosePreviewBodies.insert(&b); } + PX_FORCE_INLINE void removeFromPosePreviewList(BodySim& b) { PX_ASSERT(mPosePreviewBodies.contains(&b)); mPosePreviewBodies.erase(&b); } +#if PX_DEBUG + PX_FORCE_INLINE bool isInPosePreviewList(BodySim& b) const { return mPosePreviewBodies.contains(&b); } +#endif + + PX_FORCE_INLINE void setSpeculativeCCDRigidBody(const PxU32 index) { mSpeculativeCCDRigidBodyBitMap.growAndSet(index); } + PX_FORCE_INLINE void resetSpeculativeCCDRigidBody(const PxU32 index) { mSpeculativeCCDRigidBodyBitMap.reset(index); } + + PX_FORCE_INLINE void setSpeculativeCCDArticulationLink(const PxU32 index) { mSpeculativeCDDArticulationBitMap.growAndSet(index); } + PX_FORCE_INLINE void resetSpeculativeCCDArticulationLink(const PxU32 index) { mSpeculativeCDDArticulationBitMap.reset(index); } + + PX_FORCE_INLINE PxU64 getContextId() const { return mContextId; } + + //internal private methods: + private: + void releaseConstraints(bool endOfScene); + PX_INLINE void clearBrokenConstraintBuffer(); + + ///////////////////////////////////////////////////////////// + + void prepareCollide(); + + void collideStep(PxBaseTask* continuation); + void advanceStep(PxBaseTask* continuation); + + // subroutines of collideStep/solveStep: + void kinematicsSetup(); + void stepSetupSolve(); + //void stepSetupSimulate(); + + void fetchPatchEvents(PxBaseTask*); + void processNarrowPhaseTouchEvents(); + void processNarrowPhaseTouchEventsStage2(PxBaseTask*); + void setEdgesConnected(PxBaseTask*); + void processNarrowPhaseLostTouchEvents(PxBaseTask*); + void processNarrowPhaseLostTouchEventsIslands(PxBaseTask*); + void processLostTouchPairs(); + void integrateKinematicPose(); + void updateKinematicCached(); + + void beforeSolver(PxBaseTask* continuation); + void checkForceThresholdContactEvents(const PxU32 ccdPass); + void processCallbacks(bool pendingReportsOnly = false); + void endStep(); + private: + PxBaseTask& scheduleCloth(PxBaseTask& continuation, bool afterBroadPhase); + void scheduleClothGpu(PxBaseTask& continuation); + PxBaseTask& scheduleParticleShapeGeneration(PxBaseTask& broadPhaseDependent, + PxBaseTask& dynamicsCpuDependent); + PxBaseTask& scheduleParticleDynamicsCpu(PxBaseTask& continuation); + PxBaseTask& scheduleParticleCollisionPrep(PxBaseTask& collisionCpuDependent, + PxBaseTask& gpuDependent); + PxBaseTask& scheduleParticleCollisionCpu(PxBaseTask& continuation); + PxBaseTask& scheduleParticleGpu(PxBaseTask& continuation); + + void prepareParticleSystems(); + void finishParticleSystems(); + + PX_FORCE_INLINE void putObjectsToSleep(PxU32 infoFlag); + PX_FORCE_INLINE void putInteractionsToSleep(PxU32 infoFlag); + PX_FORCE_INLINE void wakeObjectsUp(PxU32 infoFlag); + PX_FORCE_INLINE void wakeInteractions(PxU32 infoFlag); + + void collectPostSolverVelocitiesBeforeCCD(); + void updateFromVisualizationParameters(); + + void clearSleepWakeBodies(void); + PX_INLINE void cleanUpSleepBodies(); + PX_INLINE void cleanUpWokenBodies(); + PX_INLINE void cleanUpSleepOrWokenBodies(Ps::CoalescedHashSet<BodyCore*>& bodyList, PxU32 removeFlag, bool& validMarker); + + //internal variables: + private: + // Material manager + PX_ALIGN(16, PxsMaterialManager mMaterialManager); + + PxU64 mContextId; + + Ps::Array<BodyCore*> mActiveBodies; // Sorted: kinematic before dynamic + PxU32 mActiveKinematicBodyCount; // Number of active kinematics. This is also the index in mActiveBodies where the active dynamic bodies start. + + + Ps::Array<Interaction*> mInteractions[InteractionType::eTRACKED_IN_SCENE_COUNT]; + PxU32 mActiveInteractionCount[InteractionType::eTRACKED_IN_SCENE_COUNT]; // Interactions with id < activeInteractionCount are active + + template <typename T, PxU32 size> + struct Block + { + PxU8 mem[sizeof(T)*size]; + Block() {} // get around VS warning C4345, otherwise useless + }; + + typedef Block<void*, 8> PointerBlock8; + typedef Block<void*, 16> PointerBlock16; + typedef Block<void*, 32> PointerBlock32; + + Ps::Pool<PointerBlock8> mPointerBlock8Pool; + Ps::Pool<PointerBlock16> mPointerBlock16Pool; + Ps::Pool<PointerBlock32> mPointerBlock32Pool; + + PxsContext* mLLContext; + + Bp::SimpleAABBManager* mAABBManager; + Bp::BroadPhase* mBP; + PxsCCDContext* mCCDContext; + PxI32 mNumFastMovingShapes; + PxU32 mCCDPass; + + //PxsIslandManager* mIslandManager; + + IG::SimpleIslandManager* mSimpleIslandManager; + + Dy::Context* mDynamicsContext; + + + PxsMemoryManager* mMemoryManager; + +#if PX_SUPPORT_GPU_PHYSX + PxsKernelWranglerManager* mGpuWranglerManagers; + PxsHeapMemoryAllocatorManager* mHeapMemoryAllocationManager; +#endif + + PxsSimulationController* mSimulationController; + + PxsSimulationControllerCallback* mSimulationControllerCallback; + + PxSceneLimits mLimits; + + PxVec3 mGravity; //!< Gravity vector + PxU32 mBodyGravityDirty; // Set to true before body->updateForces() when the mGravity has changed + + Ps::Array<PxContactPairHeader> + mQueuedContactPairHeaders; + //time: + //constants set with setTiming(): + PxReal mDt; //delta time for current step. + PxReal mOneOverDt; //inverse of dt. + //stepping / counters: + PxU32 mTimeStamp; //Counts number of steps. + PxU32 mReportShapePairTimeStamp; //Timestamp for refreshing the shape pair report structure. Updated before delayed shape/actor deletion and before CCD passes. + //containers: + // Those ones contain shape ptrs from Actor, i.e. compound level, not subparts + + Ps::CoalescedHashSet<Sc::ConstraintCore*> + mConstraints; + + Sc::ConstraintProjectionManager* mProjectionManager; + Bp::BoundsArray* mBoundsArray; + Ps::Array<PxReal, Ps::VirtualAllocator>* mContactDistance; + bool mHasContactDistanceChanged; + SqBoundsManager* mSqBoundsManager; + + Ps::Array<BodySim*> mCcdBodies; + Ps::Array<BodySim*> mProjectedBodies; + Ps::Array<PxTriggerPair> mTriggerBufferAPI; + Ps::Array<TriggerPairExtraData>* + mTriggerBufferExtraData; + + PxU32 mRemovedShapeCountAtSimStart; // counter used to detect whether there have been buffered shape removals + + Ps::CoalescedHashSet<ArticulationCore*> mArticulations; + +#if PX_USE_PARTICLE_SYSTEM_API + Pt::Context* mParticleContext; + Ps::CoalescedHashSet<ParticleSystemCore*> mParticleSystems; + Ps::Array<ParticleSystemSim*> mEnabledParticleSystems; // List of enabled particle systems updated every simulation step. +#endif + +#if PX_USE_CLOTH_API + Ps::CoalescedHashSet<ClothCore*> mCloths; + + static const PxU32 mNumClothSolvers = 2; + cloth::Solver* mClothSolvers[mNumClothSolvers]; + PxBaseTask* mClothTasks[mNumClothSolvers]; // first element unused + cloth::Factory* mClothFactories[mNumClothSolvers]; // necessary because we have a context manager per scene +#endif + + Ps::Array<Sc::ConstraintCore*> mBrokenConstraints; + Ps::CoalescedHashSet<Sc::ConstraintSim*> mActiveBreakableConstraints; + + // pools for joint buffers + // Fixed joint is 92 bytes, D6 is 364 bytes right now. So these three pools cover all the internal cases + typedef Block<PxU8, 128> MemBlock128; + typedef Block<PxU8, 256> MemBlock256; + typedef Block<PxU8, 384> MemBlock384; + + Ps::Pool2<MemBlock128, 8192> mMemBlock128Pool; + Ps::Pool2<MemBlock256, 8192> mMemBlock256Pool; + Ps::Pool2<MemBlock384, 8192> mMemBlock384Pool; + + + // broad phase data: + NPhaseCore* mNPhaseCore; + + // Collision filtering + void* mFilterShaderData; + PxU32 mFilterShaderDataSize; + PxU32 mFilterShaderDataCapacity; + PxSimulationFilterShader mFilterShader; + PxSimulationFilterCallback* mFilterCallback; + + Ps::CoalescedHashSet<BodyCore*> mSleepBodies; + Ps::CoalescedHashSet<BodyCore*> mWokeBodies; + bool mWokeBodyListValid; + bool mSleepBodyListValid; + bool mEnableStabilization; + Ps::Array<Client*> mClients; //an array of transform arrays, one for each client. + SimStats* mStats; + PxU32 mInternalFlags; //!< Combination of ::SceneFlag + PxSceneFlags mPublicFlags; //copy of PxSceneDesc::flags, of type PxSceneFlag + + ObjectIDTracker* mConstraintIDTracker; + ObjectIDTracker* mShapeIDTracker; + ObjectIDTracker* mRigidIDTracker; + ObjectIDTracker* mElementIDPool; + + StaticSim* mStaticAnchor; + + Cm::PreallocatingPool<ShapeSim>* mShapeSimPool; + Cm::PreallocatingPool<StaticSim>* mStaticSimPool; + Cm::PreallocatingPool<BodySim>* mBodySimPool; + Ps::Pool<ConstraintSim>* mConstraintSimPool; + LLArticulationPool* mLLArticulationPool; + + Ps::Pool<ConstraintInteraction>* + mConstraintInteractionPool; + + Ps::Pool<SimStateData>* mSimStateDataPool; + + BatchRemoveState* mBatchRemoveState; + + Ps::Array<SimpleBodyPair> mLostTouchPairs; + Cm::BitMap mLostTouchPairsDeletedBodyIDs; // Need to know which bodies have been deleted when processing the lost touch pair list. + // Can't use the existing rigid object ID tracker class since this map needs to be cleared at + // another point in time. + + Cm::BitMap mVelocityModifyMap; + + Ps::Array<PxvContactManagerTouchEvent> mTouchFoundEvents; + Ps::Array<PxvContactManagerTouchEvent> mTouchLostEvents; + + Ps::Array<PxsContactManager*> mFoundPatchManagers; + Ps::Array<PxsContactManager*> mLostPatchManagers; + + Ps::Array<PxU32> mOutOfBoundsIDs; + + Cm::BitMap mDirtyShapeSimMap; + + PxU32 mErrorState; + + PxU32 mDominanceBitMatrix[PX_MAX_DOMINANCE_GROUP]; + + PxReal mVisualizationScale; // Redundant but makes checks whether debug visualization is enabled faster + + bool mVisualizationParameterChanged; + + // statics: + PxU32 mNbRigidStatics; + PxU32 mNbRigidDynamics; + PxU32 mNbGeometries[PxGeometryType::eGEOMETRY_COUNT]; + + PxU32 mNumDeactivatingNodes[2]; + +#if EXTRA_PROFILING + private: + FILE* mExtraProfileFile; + PxU32 mLineNum; +#endif + + + // task decomposition + void preBroadPhase(PxBaseTask* continuation); + void broadPhase(PxBaseTask* continuation); + void postBroadPhase(PxBaseTask* continuation); + void preRigidBodyNarrowPhase(PxBaseTask* continuation); + void postBroadPhaseStage2(PxBaseTask* continuation); + void postBroadPhaseStage3(PxBaseTask* continuation); + void rigidBodyNarrowPhase(PxBaseTask* continuation); + void unblockNarrowPhase(PxBaseTask* continuation); + void islandGen(PxBaseTask* continuation); + void processLostSolverPatches(PxBaseTask* continuation); + void postIslandGen(PxBaseTask* continuation); + void processTriggerInteractions(PxBaseTask* continuation); + void solver(PxBaseTask* continuation); + void updateBodiesAndShapes(PxBaseTask* continuation); + void updateSimulationController(PxBaseTask* continuation); + void updateDynamics(PxBaseTask* continuation); + void processLostContacts(PxBaseTask*); + void processLostContacts2(PxBaseTask*); + void processLostContacts3(PxBaseTask*); + void destroyManagers(PxBaseTask*); + void lostTouchReports(PxBaseTask*); + void unregisterInteractions(PxBaseTask*); + void postThirdPassIslandGen(PxBaseTask*); + void postSolver(PxBaseTask* continuation); + void constraintProjection(PxBaseTask* continuation); + void afterIntegration(PxBaseTask* continuation); // performs sleep check, for instance + void postCCDPass(PxBaseTask* continuation); + void ccdBroadPhaseAABB(PxBaseTask* continuation); + void ccdBroadPhase(PxBaseTask* continuation); + void updateCCDMultiPass(PxBaseTask* continuation); + void updateCCDSinglePass(PxBaseTask* continuation); + void updateCCDSinglePassStage2(PxBaseTask* continuation); + void updateCCDSinglePassStage3(PxBaseTask* continuation); + void finalizationPhase(PxBaseTask* continuation); + + void postNarrowPhase(PxBaseTask* continuation); + void particlePostCollPrep(PxBaseTask* continuation); + void particlePostShapeGen(PxBaseTask* continuation); + + + void clothPreprocessing(PxBaseTask* continuation); + + void addShapes(void *const* shapes, PxU32 nbShapes, size_t ptrOffset, RigidSim& sim, PxBounds3* outBounds); + void removeShapes(RigidSim& , Ps::InlineArray<Sc::ShapeSim*, 64>& , Ps::InlineArray<const Sc::ShapeCore*, 64>&, bool wakeOnLostTouch); + + + private: + + void addShapes(void *const* shapes, PxU32 nbShapes, size_t ptrOffset, RigidSim& sim, ShapeSim*& prefetchedShapeSim, PxBounds3* outBounds); + + Cm::DelegateTask<Sc::Scene, &Sc::Scene::clothPreprocessing> mClothPreprocessing; + + Cm::DelegateTask<Sc::Scene, &Sc::Scene::secondPassNarrowPhase> mSecondPassNarrowPhase; + Cm::DelegateFanoutTask<Sc::Scene, &Sc::Scene::postNarrowPhase> mPostNarrowPhase; + Cm::FanoutTask mParticlePostCollPrep; + Cm::DelegateFanoutTask<Sc::Scene, &Sc::Scene::particlePostShapeGen> mParticlePostShapeGen; + Cm::DelegateFanoutTask<Sc::Scene, &Sc::Scene::finalizationPhase> mFinalizationPhase; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::updateCCDMultiPass> mUpdateCCDMultiPass; + + //multi-pass ccd stuff + Ps::Array<Cm::DelegateTask<Sc::Scene, &Sc::Scene::updateCCDSinglePass> > mUpdateCCDSinglePass; + Ps::Array<Cm::DelegateTask<Sc::Scene, &Sc::Scene::updateCCDSinglePassStage2> > mUpdateCCDSinglePass2; + Ps::Array<Cm::DelegateTask<Sc::Scene, &Sc::Scene::updateCCDSinglePassStage3> > mUpdateCCDSinglePass3; + Ps::Array<Cm::DelegateTask<Sc::Scene, &Sc::Scene::ccdBroadPhaseAABB> > mCCDBroadPhaseAABB; + Ps::Array<Cm::DelegateTask<Sc::Scene, &Sc::Scene::ccdBroadPhase> > mCCDBroadPhase; + Ps::Array<Cm::DelegateTask<Sc::Scene, &Sc::Scene::postCCDPass> > mPostCCDPass; + PxU32 mCurrentCCDTask; + + Cm::DelegateTask<Sc::Scene, &Sc::Scene::afterIntegration> mAfterIntegration; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::constraintProjection> mConstraintProjection; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::postSolver> mPostSolver; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::solver> mSolver; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::updateBodiesAndShapes> mUpdateBodiesAndShapes; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::updateSimulationController> mUpdateSimulationController; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::updateDynamics> mUpdateDynamics; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::processLostContacts> mProcessLostContactsTask; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::processLostContacts2> mProcessLostContactsTask2; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::processLostContacts3> mProcessLostContactsTask3; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::destroyManagers> mDestroyManagersTask; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::lostTouchReports> mLostTouchReportsTask; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::unregisterInteractions> mUnregisterInteractionsTask; + Cm::DelegateTask<Sc::Scene, + &Sc::Scene::processNarrowPhaseLostTouchEventsIslands> mProcessNarrowPhaseLostTouchTasks; + Cm::DelegateTask<Sc::Scene, + &Sc::Scene::processNarrowPhaseLostTouchEvents> mProcessNPLostTouchEvents; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::postThirdPassIslandGen> mPostThirdPassIslandGenTask; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::postIslandGen> mPostIslandGen; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::islandGen> mIslandGen; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::preRigidBodyNarrowPhase> mPreRigidBodyNarrowPhase; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::setEdgesConnected> mSetEdgesConnectedTask; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::fetchPatchEvents> mFetchPatchEventsTask; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::processLostSolverPatches> mProcessLostPatchesTask; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::rigidBodyNarrowPhase> mRigidBodyNarrowPhase; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::unblockNarrowPhase> mRigidBodyNPhaseUnlock; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::postBroadPhase> mPostBroadPhase; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::postBroadPhaseStage2> mPostBroadPhase2; + Cm::DelegateFanoutTask<Sc::Scene, &Sc::Scene::postBroadPhaseStage3> mPostBroadPhase3; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::preallocateContactManagers> mPreallocateContactManagers; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::islandInsertion> mIslandInsertion; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::registerContactManagers> mRegisterContactManagers; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::registerInteractions> mRegisterInteractions; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::registerSceneInteractions> mRegisterSceneInteractions; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::broadPhase> mBroadPhase; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::advanceStep> mAdvanceStep; + Cm::DelegateTask<Sc::Scene, &Sc::Scene::collideStep> mCollideStep; + + Cm::FlushPool mTaskPool; + PxTaskManager* mTaskManager; + + bool mContactReportsNeedPostSolverVelocity; + + SimulationStage::Enum mSimulationStage; + + ConstraintGroupNode** mTmpConstraintGroupRootBuffer; // temporary list of constraint group roots, used for constraint projection + + Ps::CoalescedHashSet<const BodySim*> mPosePreviewBodies; // list of bodies that requested early report of the integrated pose (eENABLE_POSE_INTEGRATION_PREVIEW). + + Ps::Array<PxsContactManager*> mPreallocatedContactManagers; + Ps::Array<ShapeInteraction*> mPreallocatedShapeInteractions; + Ps::Array<ElementInteractionMarker*> mPreallocatedInteractionMarkers; + + Ps::Array<OverlapFilterTask*> mOverlapFilterTasks; + Ps::Array<PxFilterInfo> mFilterInfo; + Cm::BitMap mSpeculativeCCDRigidBodyBitMap; + Cm::BitMap mSpeculativeCDDArticulationBitMap; + }; + +} // namespace Sc + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/include/ScShapeCore.h b/PhysX_3.4/Source/SimulationController/include/ScShapeCore.h new file mode 100644 index 00000000..be65cd60 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/include/ScShapeCore.h @@ -0,0 +1,129 @@ +// 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_SHAPECORE +#define PX_PHYSICS_SCP_SHAPECORE + +#include "PsUserAllocated.h" +#include "GuGeometryUnion.h" +#include "PxvGeometry.h" +#include "PsUtilities.h" +#include "PxFiltering.h" +#include "PxShape.h" + +namespace physx +{ +class PxShape; + +namespace Sc +{ + class Scene; + class RigidCore; + class BodyCore; + class ShapeSim; + class MaterialCore; + + class ShapeCore : public Ps::UserAllocated + { + //= ATTENTION! ===================================================================================== + // Changing the data layout of this class breaks the binary serialization format. See comments for + // PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData + // function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION + // accordingly. + //================================================================================================== + public: +// PX_SERIALIZATION + ShapeCore(const PxEMPTY); + void exportExtraData(PxSerializationContext& stream); + void importExtraData(PxDeserializationContext& context); + void resolveReferences(PxDeserializationContext& context); + static void getBinaryMetaData(PxOutputStream& stream); + void resolveMaterialReference(PxU32 materialTableIndex, PxU16 materialIndex); +//~PX_SERIALIZATION + + ShapeCore(const PxGeometry& geometry, + PxShapeFlags shapeFlags, + const PxU16* materialIndices, + PxU16 materialCount); + + ~ShapeCore(); + + PX_FORCE_INLINE PxGeometryType::Enum getGeometryType() const { return mCore.geometry.getType(); } + PxShape* getPxShape(); + const PxShape* getPxShape() const; + + PX_FORCE_INLINE const Gu::GeometryUnion& getGeometryUnion() const { return mCore.geometry; } + PX_FORCE_INLINE const PxGeometry& getGeometry() const { return mCore.geometry.getGeometry(); } + void setGeometry(const PxGeometry& geom); + + PxU16 getNbMaterialIndices() const; + const PxU16* getMaterialIndices() const; + void setMaterialIndices(const PxU16* materialIndices, PxU16 materialIndexCount); + + PX_FORCE_INLINE const PxTransform& getShape2Actor() const { return mCore.transform; } + PX_FORCE_INLINE void setShape2Actor(const PxTransform& s2b) { mCore.transform = s2b; } + + PX_FORCE_INLINE const PxFilterData& getSimulationFilterData() const { return mSimulationFilterData; } + PX_FORCE_INLINE void setSimulationFilterData(const PxFilterData& data) { mSimulationFilterData = data; } + + // PT: this one doesn't need double buffering + PX_FORCE_INLINE const PxFilterData& getQueryFilterData() const { return mQueryFilterData; } + PX_FORCE_INLINE void setQueryFilterData(const PxFilterData& data) { mQueryFilterData = data; } + + PX_FORCE_INLINE PxReal getContactOffset() const { return mCore.contactOffset; } + PX_FORCE_INLINE void setContactOffset(PxReal offset) { mCore.contactOffset = offset; } + + PX_FORCE_INLINE PxReal getRestOffset() const { return mRestOffset; } + PX_FORCE_INLINE void setRestOffset(PxReal offset) { mRestOffset = offset; } + + PX_FORCE_INLINE PxShapeFlags getFlags() const { return PxShapeFlags(mCore.mShapeFlags); } + PX_FORCE_INLINE void setFlags(PxShapeFlags f) { mCore.mShapeFlags = f; } + + PX_FORCE_INLINE const PxsShapeCore& getCore() const { return mCore; } + + static PX_FORCE_INLINE ShapeCore& getCore(PxsShapeCore& core) + { + size_t offset = PX_OFFSET_OF(ShapeCore, mCore); + return *reinterpret_cast<ShapeCore*>(reinterpret_cast<PxU8*>(&core) - offset); + } + + protected: + PxFilterData mQueryFilterData; // Query filter data PT: TODO: consider moving this to SceneQueryShapeData + PxFilterData mSimulationFilterData; // Simulation filter data + PxsShapeCore PX_ALIGN(16, mCore); + PxReal mRestOffset; // same as the API property of the same name + }; + +} // namespace Sc + + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/include/ScStaticCore.h b/PhysX_3.4/Source/SimulationController/include/ScStaticCore.h new file mode 100644 index 00000000..b71f405f --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/include/ScStaticCore.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_SCP_STATIC_CORE +#define PX_PHYSICS_SCP_STATIC_CORE + +#include "ScRigidCore.h" +#include "PxvDynamics.h" + +namespace physx +{ +namespace Sc +{ + + class StaticSim; + + class StaticCore: public RigidCore + { + //= ATTENTION! ===================================================================================== + // Changing the data layout of this class breaks the binary serialization format. See comments for + // PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData + // function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION + // accordingly. + //================================================================================================== + public: + StaticCore(const PxTransform& actor2World): RigidCore(PxActorType::eRIGID_STATIC) + { + mCore.body2World = actor2World; + mCore.mFlags = PxRigidBodyFlags(); + } + + PX_FORCE_INLINE const PxTransform& getActor2World() const { return mCore.body2World; } + void setActor2World(const PxTransform& actor2World); + + PX_FORCE_INLINE PxsRigidCore& getCore() { return mCore; } + + StaticCore(const PxEMPTY) : RigidCore(PxEmpty), mCore(PxEmpty) {} + static void getBinaryMetaData(PxOutputStream& stream); + + StaticSim* getSim() const; + + PX_FORCE_INLINE void onOriginShift(const PxVec3& shift) { mCore.body2World.p -= shift; } + private: + PxsRigidCore mCore; + }; + +} // namespace Sc + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/ScActorCore.cpp b/PhysX_3.4/Source/SimulationController/src/ScActorCore.cpp new file mode 100644 index 00000000..9e547e40 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScActorCore.cpp @@ -0,0 +1,84 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-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 "ScActorCore.h" +#include "ScActorSim.h" +#include "ScShapeIterator.h" +#include "ScShapeCore.h" +#include "ScShapeSim.h" +#include "ScBodySim.h" + +using namespace physx; + +Sc::ActorCore::ActorCore(PxActorType::Enum actorType, PxU8 actorFlags, PxClientID owner, PxU8 behavior, PxDominanceGroup dominanceGroup) : + mSim (NULL), + mAggregateIDOwnerClient ((PxU32(owner)<<24)|0x00ffffff), + mActorFlags (actorFlags), + mActorType (PxU8(actorType)), + mClientBehaviorFlags (behavior), + mDominanceGroup (dominanceGroup) +{ + PX_ASSERT((actorType & 0xff) == actorType); +} + +Sc::ActorCore::~ActorCore() +{ +} + +void Sc::ActorCore::setActorFlags(PxActorFlags af) +{ + const PxActorFlags old = mActorFlags; + if(af!=old) + { + mActorFlags = af; + + if(mSim) + mSim->postActorFlagChange(old, af); + } +} + +void Sc::ActorCore::setDominanceGroup(PxDominanceGroup g) +{ + PX_ASSERT(g<128); + mDominanceGroup = g; + if(mSim) + mSim->postDominanceGroupChange(); +} + +void Sc::ActorCore::reinsertShapes() +{ + PX_ASSERT(mSim); + if(!mSim) + return; + + ShapeSim* sim = NULL; + for (ShapeIterator shapeIterator(*mSim); NULL != (sim = shapeIterator.getNext()); ) + sim->reinsertBroadPhase(); +} diff --git a/PhysX_3.4/Source/SimulationController/src/ScActorElementPair.h b/PhysX_3.4/Source/SimulationController/src/ScActorElementPair.h new file mode 100644 index 00000000..27c8c3ba --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScActorElementPair.h @@ -0,0 +1,117 @@ +// 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_ACTOR_ELEMENT_PAIR +#define PX_PHYSICS_SCP_ACTOR_ELEMENT_PAIR + +#include "ScActorSim.h" +#include "ScElementSim.h" + +namespace physx +{ +namespace Sc +{ + + // Class shared by all element-element pairs where one element should not be distinguished from + // its actor (for example: rb-fluid, ...) + class ActorElementPair + { + public: + PX_INLINE ActorElementPair(ActorSim& actor, ElementSim& element, PxPairFlags pairFlag); + PX_INLINE ~ActorElementPair(); + + PX_INLINE ElementSim& getElement() const { return mElement; } + PX_INLINE ActorSim& getActor() const { return mActor; } + + PX_INLINE void incRefCount() { ++mRefCount; PX_ASSERT(mRefCount>0); } + PX_INLINE PxU32 decRefCount() { PX_ASSERT(mRefCount>0); return --mRefCount; } + PX_INLINE PxU32 getRefCount() const { return mRefCount; } + + PX_INLINE PxPairFlags getPairFlags() const { return mPairFlags; } + PX_INLINE void setPairFlags(PxPairFlags pairFlags) { mPairFlags = pairFlags; } + + PX_INLINE bool isFilterPair() const { return mIsFilterPair; } + PX_INLINE void markAsFilterPair(bool filterPair) { mIsFilterPair = filterPair; } + + PX_INLINE bool isSuppressed() const { return mIsSuppressed; } + PX_INLINE void markAsSuppressed(bool suppress) { mIsSuppressed = suppress; } + + PX_INLINE bool isKilled() const { return mIsKilled; } + PX_INLINE void markAsKilled(bool killed) { mIsKilled = killed; } + + PX_INLINE bool hasBeenRefiltered(PxU32 sceneTimestamp); + + private: + ActorElementPair& operator=(const ActorElementPair&); + ActorSim& mActor; + ElementSim& mElement; + PxPairFlags mPairFlags; + PxU32 mRefilterTimestamp; + PxU16 mRefCount; + bool mIsFilterPair; + bool mIsSuppressed; + bool mIsKilled; + }; + +} // namespace Sc + + +Sc::ActorElementPair::ActorElementPair(ActorSim& actor, ElementSim& element, PxPairFlags pairFlag) : + mActor(actor), + mElement(element), + mPairFlags(pairFlag), + mRefilterTimestamp(0), + mRefCount(0), + mIsFilterPair(false), + mIsSuppressed(false), + mIsKilled(false) +{ +} + + +Sc::ActorElementPair::~ActorElementPair() +{ +} + + +PX_INLINE bool Sc::ActorElementPair::hasBeenRefiltered(PxU32 sceneTimestamp) +{ + if (mRefilterTimestamp != sceneTimestamp) + { + mRefilterTimestamp = sceneTimestamp; + return false; + } + else + return true; +} + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/ScActorInteraction.h b/PhysX_3.4/Source/SimulationController/src/ScActorInteraction.h new file mode 100644 index 00000000..cb064116 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScActorInteraction.h @@ -0,0 +1,76 @@ +// 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_COLLISION_ACTOR_INTERACTION +#define PX_COLLISION_ACTOR_INTERACTION + +#include "ScInteraction.h" +#include "ScActorSim.h" + +namespace physx +{ +namespace Sc +{ + class ActorSim; + class Scene; + + class ActorInteraction : public Interaction + { + public: + PX_INLINE ActorInteraction(ActorSim& actor0, ActorSim& actor1, InteractionType::Enum interactionType, PxU8 flags); + virtual ~ActorInteraction() {} + + PX_INLINE ActorSim& getActorSim0() const; + PX_INLINE ActorSim& getActorSim1() const; + private: + }; + +} // namespace Sc + +////////////////////////////////////////////////////////////////////////// +PX_INLINE Sc::ActorInteraction::ActorInteraction(ActorSim& actor0, ActorSim& actor1, InteractionType::Enum interactionType, PxU8 flags) : + Interaction (actor0, actor1, interactionType, flags) +{ +} + +PX_INLINE Sc::ActorSim& Sc::ActorInteraction::getActorSim0() const +{ + return static_cast<ActorSim&>(getActor0()); +} + +PX_INLINE Sc::ActorSim& Sc::ActorInteraction::getActorSim1() const +{ + return static_cast<ActorSim&>(getActor1()); +} + + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/ScActorPair.h b/PhysX_3.4/Source/SimulationController/src/ScActorPair.h new file mode 100644 index 00000000..c3ce1868 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScActorPair.h @@ -0,0 +1,251 @@ +// 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_COLLISION_ACTORPAIR +#define PX_COLLISION_ACTORPAIR + +#include "ScRigidSim.h" +#include "ScContactStream.h" +#include "ScNPhaseCore.h" + +namespace physx +{ +namespace Sc +{ + + class ActorPairContactReportData + { + public: + ActorPairContactReportData() : + mStrmResetStamp (0xffffffff), + mActorAID (0xffffffff), + mActorBID (0xffffffff), + mPxActorA (NULL), + mPxActorB (NULL), + mActorAClientID (0xff), + mActorBClientID (0xff), + mActorAClientBehavior (0), + mActorBClientBehavior (0) + {} + + ContactStreamManager mContactStreamManager; + PxU32 mStrmResetStamp; + PxU32 mActorAID; + PxU32 mActorBID; + PxActor* mPxActorA; + PxActor* mPxActorB; + PxClientID mActorAClientID; + PxClientID mActorBClientID; + PxU8 mActorAClientBehavior; + PxU8 mActorBClientBehavior; + }; + + + /** + \brief Class shared by all shape interactions for a pair of actors. + + This base class is used if no shape pair of an actor pair has contact reports requested. + */ + class ActorPair + { + public: + + enum ActorPairFlags + { + eIS_REPORT_PAIR = (1<<0), + eNEXT_FREE = (1<<1) + }; + + PX_FORCE_INLINE ActorPair() : mInternalFlags(0), mTouchCount(0), mRefCount(0) {} + PX_FORCE_INLINE ~ActorPair() {} + + PX_FORCE_INLINE Ps::IntBool isReportPair() const { return (mInternalFlags & eIS_REPORT_PAIR); } + + PX_FORCE_INLINE void incTouchCount() { mTouchCount++; PX_ASSERT(mTouchCount); } + PX_FORCE_INLINE void decTouchCount() { PX_ASSERT(mTouchCount); mTouchCount--; } + PX_FORCE_INLINE PxU32 getTouchCount() const { return mTouchCount; } + + PX_FORCE_INLINE void incRefCount() { ++mRefCount; PX_ASSERT(mRefCount>0); } + PX_FORCE_INLINE PxU32 decRefCount() { PX_ASSERT(mRefCount>0); return --mRefCount; } + PX_FORCE_INLINE PxU32 getRefCount() const { return mRefCount; } + + private: + ActorPair& operator=(const ActorPair&); + + + protected: + PxU16 mInternalFlags; + PxU16 mTouchCount; + PxU16 mRefCount; + PxU16 mPad; // instances of this class are stored in a pool which needs an item size of at least size_t + }; + + + /** + \brief Class shared by all shape interactions for a pair of actors if contact reports are requested. + + This class is used if at least one shape pair of an actor pair has contact reports requested. + + \note If a pair of actors had contact reports requested for some of the shape interactions but all of them switch to not wanting contact reports + any longer, then the ActorPairReport instance is kept being used and won't get replaced by a simpler ActorPair instance. + */ + class ActorPairReport : public ActorPair + { + public: + + enum ActorPairReportFlags + { + eIS_IN_CONTACT_REPORT_ACTOR_PAIR_SET = ActorPair::eNEXT_FREE // PT: whether the pair is already stored in the 'ContactReportActorPairSet' or not + }; + + PX_FORCE_INLINE ActorPairReport(RigidSim&, RigidSim&); + PX_FORCE_INLINE ~ActorPairReport(); + + PX_INLINE ContactStreamManager& createContactStreamManager(NPhaseCore&); + PX_FORCE_INLINE ContactStreamManager& getContactStreamManager() const { PX_ASSERT(mReportData); return mReportData->mContactStreamManager; } + PX_FORCE_INLINE RigidSim& getActorA() const { return mActorA; } + PX_FORCE_INLINE RigidSim& getActorB() const { return mActorB; } + PX_INLINE PxU32 getActorAID() const { PX_ASSERT(mReportData); return mReportData->mActorAID; } + PX_INLINE PxU32 getActorBID() const { PX_ASSERT(mReportData); return mReportData->mActorBID; } + PX_INLINE PxActor* getPxActorA() const { PX_ASSERT(mReportData); return mReportData->mPxActorA; } + PX_INLINE PxActor* getPxActorB() const { PX_ASSERT(mReportData); return mReportData->mPxActorB; } + PX_INLINE PxClientID getActorAClientID() const { PX_ASSERT(mReportData); return mReportData->mActorAClientID; } + PX_INLINE PxClientID getActorBClientID() const { PX_ASSERT(mReportData); return mReportData->mActorBClientID; } + PX_INLINE PxU8 getActorAClientBehavior() const { PX_ASSERT(mReportData); return mReportData->mActorAClientBehavior; } + PX_INLINE PxU8 getActorBClientBehavior() const { PX_ASSERT(mReportData); return mReportData->mActorBClientBehavior; } + PX_FORCE_INLINE bool streamResetNeeded(PxU32 cmpStamp) const; + PX_INLINE bool streamResetStamp(PxU32 cmpStamp); + + PX_FORCE_INLINE PxU16 isInContactReportActorPairSet() const { return PxU16(mInternalFlags & eIS_IN_CONTACT_REPORT_ACTOR_PAIR_SET); } + PX_FORCE_INLINE void setInContactReportActorPairSet() { mInternalFlags |= eIS_IN_CONTACT_REPORT_ACTOR_PAIR_SET; } + PX_FORCE_INLINE void clearInContactReportActorPairSet() { mInternalFlags &= ~eIS_IN_CONTACT_REPORT_ACTOR_PAIR_SET; } + + PX_FORCE_INLINE void createContactReportData(NPhaseCore&); + PX_FORCE_INLINE void releaseContactReportData(NPhaseCore&); + PX_FORCE_INLINE const ActorPairContactReportData* hasReportData() const { return mReportData; } + + PX_FORCE_INLINE void convert(ActorPair& aPair) { PX_ASSERT(!aPair.isReportPair()); mTouchCount = PxU16(aPair.getTouchCount()); mRefCount = PxU16(aPair.getRefCount()); } + + PX_FORCE_INLINE static ActorPairReport& cast(ActorPair& aPair) { PX_ASSERT(aPair.isReportPair()); return static_cast<ActorPairReport&>(aPair); } + + private: + ActorPairReport& operator=(const ActorPairReport&); + + RigidSim& mActorA; + RigidSim& mActorB; + + ActorPairContactReportData* mReportData; + }; + +} // namespace Sc + + +PX_FORCE_INLINE Sc::ActorPairReport::ActorPairReport(RigidSim& actor0, RigidSim& actor1) : ActorPair(), +mActorA (actor0), +mActorB (actor1), +mReportData (NULL) +{ + PX_ASSERT(mInternalFlags == 0); + mInternalFlags = ActorPair::eIS_REPORT_PAIR; +} + + +PX_FORCE_INLINE Sc::ActorPairReport::~ActorPairReport() +{ + PX_ASSERT(mReportData == NULL); +} + + +PX_FORCE_INLINE bool Sc::ActorPairReport::streamResetNeeded(PxU32 cmpStamp) const +{ + return (cmpStamp != mReportData->mStrmResetStamp); +} + + +PX_INLINE bool Sc::ActorPairReport::streamResetStamp(PxU32 cmpStamp) +{ + PX_ASSERT(mReportData); + const bool ret = streamResetNeeded(cmpStamp); + mReportData->mStrmResetStamp = cmpStamp; + return ret; +} + + +PX_INLINE Sc::ContactStreamManager& Sc::ActorPairReport::createContactStreamManager(NPhaseCore& npCore) +{ + // Lazy create report data + if(!mReportData) + createContactReportData(npCore); + + return mReportData->mContactStreamManager; +} + + +PX_FORCE_INLINE void Sc::ActorPairReport::createContactReportData(NPhaseCore& npCore) +{ + PX_ASSERT(!mReportData); + Sc::ActorPairContactReportData* reportData = npCore.createActorPairContactReportData(); + mReportData = reportData; + + if(reportData) + { + reportData->mActorAID = mActorA.getID(); + reportData->mActorBID = mActorB.getID(); + + reportData->mPxActorA = mActorA.getPxActor(); + reportData->mPxActorB = mActorB.getPxActor(); + + const ActorCore& actorCoreA = mActorA.getActorCore(); + const ActorCore& actorCoreB = mActorB.getActorCore(); + + reportData->mActorAClientID = actorCoreA.getOwnerClient(); + reportData->mActorBClientID = actorCoreB.getOwnerClient(); + + reportData->mActorAClientBehavior = actorCoreA.getClientBehaviorFlags(); + reportData->mActorBClientBehavior = actorCoreB.getClientBehaviorFlags(); + } +} + + +PX_FORCE_INLINE void Sc::ActorPairReport::releaseContactReportData(NPhaseCore& npCore) +{ + // Can't take the NPhaseCore (scene) reference from the actors since they're already gone on scene release + + if (mReportData != NULL) + { + npCore.releaseActorPairContactReportData(mReportData); + mReportData = NULL; + } +} + + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/ScActorSim.cpp b/PhysX_3.4/Source/SimulationController/src/ScActorSim.cpp new file mode 100644 index 00000000..93bf70a3 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScActorSim.cpp @@ -0,0 +1,148 @@ +// 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 "CmPhysXCommon.h" +#include "ScActorSim.h" +#include "ScActorCore.h" +#include "ScElementSim.h" +#include "ScScene.h" +#include "ScInteraction.h" + +using namespace physx; + +Sc::ActorSim::ActorSim(Scene& scene, ActorCore& core) : + mFirstElement (NULL), + mScene (scene), + mCore (core) +{ + core.setSim(this); +} + +Sc::ActorSim::~ActorSim() +{ + mInteractions.releaseMem(*this); +} + +void Sc::ActorSim::registerInteraction(Interaction* interaction) +{ + const PxU32 id = mInteractions.size(); + mInteractions.pushBack(interaction, *this); + interaction->setActorId(this, id); +} + +void Sc::ActorSim::unregisterInteraction(Interaction* interaction) +{ + const PxU32 i = interaction->getActorId(this); + PX_ASSERT(i < mInteractions.size()); + mInteractions.replaceWithLast(i); + if (i<mInteractions.size()) + mInteractions[i]->setActorId(this, i); +} + +void Sc::ActorSim::onElementAttach(ElementSim& element) +{ + element.mNextInActor = mFirstElement; + mFirstElement = &element; +} + +void Sc::ActorSim::onElementDetach(ElementSim& element) +{ + PX_ASSERT(mFirstElement); // PT: else we shouldn't be called + ElementSim* currentElem = mFirstElement; + ElementSim* previousElem = NULL; + while(currentElem) + { + if(currentElem==&element) + { + if(previousElem) + previousElem->mNextInActor = currentElem->mNextInActor; + else + mFirstElement = currentElem->mNextInActor; + return; + } + previousElem = currentElem; + currentElem = currentElem->mNextInActor; + } + PX_ASSERT(0); +} + +// PT: TODO: refactor with Sc::ParticlePacketShape::reallocInteractions +void Sc::ActorSim::reallocInteractions(Sc::Interaction**& mem, PxU32& capacity, PxU32 size, PxU32 requiredMinCapacity) +{ + Interaction** newMem; + PxU32 newCapacity; + + if(requiredMinCapacity==0) + { + newCapacity = 0; + newMem = 0; + } + else if(requiredMinCapacity<=INLINE_INTERACTION_CAPACITY) + { + newCapacity = INLINE_INTERACTION_CAPACITY; + newMem = mInlineInteractionMem; + } + else + { + newCapacity = Ps::nextPowerOfTwo(requiredMinCapacity-1); + newMem = reinterpret_cast<Interaction**>(mScene.allocatePointerBlock(newCapacity)); + } + + PX_ASSERT(newCapacity >= requiredMinCapacity && requiredMinCapacity>=size); + + if(mem) + { + PxMemCopy(newMem, mem, size*sizeof(Interaction*)); + + if(mem!=mInlineInteractionMem) + mScene.deallocatePointerBlock(reinterpret_cast<void**>(mem), capacity); + } + + capacity = newCapacity; + mem = newMem; +} + +void Sc::ActorSim::postDominanceGroupChange() +{ + //force all related interactions to refresh, so they fetch new dominance values. + setActorsInteractionsDirty(InteractionDirtyFlag::eDOMINANCE, NULL, InteractionFlag::eRB_ELEMENT); +} + +void Sc::ActorSim::setActorsInteractionsDirty(InteractionDirtyFlag::Enum flag, const ActorSim* other, PxU8 interactionFlag) +{ + PxU32 size = getActorInteractionCount(); + Interaction** interactions = getActorInteractions(); + while(size--) + { + Interaction* interaction = *interactions++; + if ((!other || other == &interaction->getActor0() || other == &interaction->getActor1()) && + (interaction->readInteractionFlag(interactionFlag))) + interaction->setDirty(flag); + } +} diff --git a/PhysX_3.4/Source/SimulationController/src/ScActorSim.h b/PhysX_3.4/Source/SimulationController/src/ScActorSim.h new file mode 100644 index 00000000..a6e478f0 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScActorSim.h @@ -0,0 +1,126 @@ +// 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_ACTOR_SIM +#define PX_PHYSICS_SCP_ACTOR_SIM + +#include "PsUserAllocated.h" +#include "CmPhysXCommon.h" +#include "CmUtils.h" +#include "PxActor.h" +#include "ScInteractionFlags.h" +#include "ScActorCore.h" + +namespace physx +{ + +class PxActor; + +namespace Sc +{ + class Interaction; + class ElementSim; + + class ActorSim : public Ps::UserAllocated + { + friend class Scene; // the scene is allowed to set the scene array index + friend class Interaction; + PX_NOCOPY(ActorSim) + + public: + enum ActivityChangeInfoFlag + { + AS_PART_OF_CREATION = (1 << 0), + AS_PART_OF_ISLAND_GEN = (1 << 1) + }; + + ActorSim(Scene&, ActorCore&); + virtual ~ActorSim(); + + // Get the scene the actor resides in + PX_FORCE_INLINE Scene& getScene() const { return mScene; } + + // Get the number of interactions connected to the actor + PX_FORCE_INLINE PxU32 getActorInteractionCount() const { return mInteractions.size(); } + + // Prepares the actor for less than n interactions + void setInteractionCountHint(PxU32 n) { mInteractions.reserve(n, *this); } + + // Get an iterator to the interactions connected to the actor + PX_FORCE_INLINE Interaction** getActorInteractions() const { return mInteractions.begin(); } + + // Get first element in the actor (linked list) + PX_FORCE_INLINE ElementSim* getElements_() { return mFirstElement; } + PX_FORCE_INLINE const ElementSim* getElements_() const { return mFirstElement; } + + // Get the type ID of the actor + PX_FORCE_INLINE PxActorType::Enum getActorType() const { return mCore.getActorCoreType(); } + + // Returns true if the actor is a dynamic rigid body (including articulation links) + PX_FORCE_INLINE bool isDynamicRigid() const { const PxActorType::Enum type = getActorType(); return type == PxActorType::eRIGID_DYNAMIC || type == PxActorType::eARTICULATION_LINK; } + + void onElementAttach(ElementSim& element); + void onElementDetach(ElementSim& element); + + virtual void postActorFlagChange(PxU32, PxU32) {} + + void postDominanceGroupChange(); + + void setActorsInteractionsDirty(InteractionDirtyFlag::Enum flag, const ActorSim* other, PxU8 interactionFlag); + + PX_FORCE_INLINE ActorCore& getActorCore() const { return mCore; } + + private: + //These are called from interaction creation/destruction + void registerInteraction(Interaction* interaction); + void unregisterInteraction(Interaction* interaction); + + void reallocInteractions(Sc::Interaction**& mem, PxU32& capacity, PxU32 size, PxU32 requiredMinCapacity); + protected: + // dsequeira: interaction arrays are a major cause of small allocations, so we don't want to delegate them to the heap allocator + // it's not clear this inline array is really needed, we should take it out and see whether the cache perf is worse + + static const PxU32 INLINE_INTERACTION_CAPACITY = 4; + Interaction* mInlineInteractionMem[INLINE_INTERACTION_CAPACITY]; + + Cm::OwnedArray<Sc::Interaction*, Sc::ActorSim, PxU32, &Sc::ActorSim::reallocInteractions> + mInteractions; + + ElementSim* mFirstElement; + + Scene& mScene; + + ActorCore& mCore; + }; + +} // namespace Sc + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/ScArticulationCore.cpp b/PhysX_3.4/Source/SimulationController/src/ScArticulationCore.cpp new file mode 100644 index 00000000..964787db --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScArticulationCore.cpp @@ -0,0 +1,248 @@ +// 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 "ScArticulationCore.h" + +#include "PsFoundation.h" +#include "ScPhysics.h" +#include "ScBodyCore.h" +#include "ScArticulationSim.h" +#include "DyArticulation.h" + +using namespace physx; + +Sc::ArticulationCore::ArticulationCore() : + mSim(NULL) +{ + const PxTolerancesScale& scale = Physics::getInstance().getTolerancesScale(); + + mCore.internalDriveIterations = 4; + mCore.externalDriveIterations = 4; + mCore.maxProjectionIterations = 4; + mCore.separationTolerance = 0.1f * scale.length; + mCore.solverIterationCounts = 1<<8 | 4; + mCore.sleepThreshold = 5e-5f * scale.speed * scale.speed; + mCore.wakeCounter = Physics::sWakeCounterOnCreation; + mCore.freezeThreshold = 5e-6f * scale.speed * scale.speed; +} + + +Sc::ArticulationCore::~ArticulationCore() +{ +} + + +//-------------------------------------------------------------- +// +// ArticulationCore interface implementation +// +//-------------------------------------------------------------- + +PxU32 Sc::ArticulationCore::getInternalDriveIterations() const +{ + return mCore.internalDriveIterations; +} + +void Sc::ArticulationCore::setInternalDriveIterations(const PxU32 v) +{ + mCore.internalDriveIterations = v; +} + +PxU32 Sc::ArticulationCore::getExternalDriveIterations() const +{ + return mCore.externalDriveIterations; +} + +void Sc::ArticulationCore::setExternalDriveIterations(const PxU32 v) +{ + mCore.externalDriveIterations = v; +} + +PxU32 Sc::ArticulationCore::getMaxProjectionIterations() const +{ + return mCore.maxProjectionIterations; +} + +void Sc::ArticulationCore::setMaxProjectionIterations(const PxU32 v) +{ + mCore.maxProjectionIterations = v; +} + +PxReal Sc::ArticulationCore::getSeparationTolerance() const +{ + return mCore.separationTolerance; +} + +void Sc::ArticulationCore::setSeparationTolerance(const PxReal v) +{ + mCore.separationTolerance = v; +} + +PxReal Sc::ArticulationCore::getWakeCounter() const +{ + return mCore.wakeCounter; +} + +void Sc::ArticulationCore::setWakeCounterInternal(const PxReal v) +{ + mCore.wakeCounter = v; +} + +void Sc::ArticulationCore::setWakeCounter(const PxReal v) +{ + mCore.wakeCounter = v; + +#ifdef _DEBUG + if(mSim) + mSim->debugCheckWakeCounterOfLinks(v); +#endif +} + +bool Sc::ArticulationCore::isSleeping() const +{ + return mSim ? mSim->isSleeping() : (mCore.wakeCounter == 0.0f); +} + +void Sc::ArticulationCore::wakeUp(PxReal wakeCounter) +{ + mCore.wakeCounter = wakeCounter; + +#ifdef _DEBUG + if(mSim) + mSim->debugCheckSleepStateOfLinks(false); +#endif +} + +void Sc::ArticulationCore::putToSleep() +{ + mCore.wakeCounter = 0.0f; + +#ifdef _DEBUG + if(mSim) + mSim->debugCheckSleepStateOfLinks(true); +#endif +} + +PxReal Sc::ArticulationCore::getSleepThreshold() const +{ + return mCore.sleepThreshold; +} + +void Sc::ArticulationCore::setSleepThreshold(const PxReal v) +{ + mCore.sleepThreshold = v; +} + +PxReal Sc::ArticulationCore::getFreezeThreshold() const +{ + return mCore.freezeThreshold; +} + +void Sc::ArticulationCore::setFreezeThreshold(const PxReal v) +{ + mCore.freezeThreshold = v; +} + +PxU16 Sc::ArticulationCore::getSolverIterationCounts() const +{ + return mCore.solverIterationCounts; +} + +void Sc::ArticulationCore::setSolverIterationCounts(const PxU16 v) +{ + mCore.solverIterationCounts = v; +} + + +PxArticulation* Sc::ArticulationCore::getPxArticulation() +{ + return gOffsetTable.convertScArticulation2Px(this); +} + + +const PxArticulation* Sc::ArticulationCore::getPxArticulation() const +{ + return gOffsetTable.convertScArticulation2Px(this); +} + + +Sc::ArticulationDriveCache* Sc::ArticulationCore::createDriveCache(PxReal compliance, + PxU32 driveIterations) const +{ + return mSim? mSim->createDriveCache(compliance, driveIterations) : NULL; +} + + +void Sc::ArticulationCore::updateDriveCache(ArticulationDriveCache& cache, + PxReal compliance, + PxU32 driveIterations) const +{ + mSim->updateDriveCache(cache, compliance, driveIterations); +} + + +void Sc::ArticulationCore::releaseDriveCache(Sc::ArticulationDriveCache& driveCache) const +{ + if(mSim) + mSim->releaseDriveCache(driveCache); +} + + +PxU32 Sc::ArticulationCore::getCacheLinkCount(const ArticulationDriveCache& cache) const +{ + return Dy::PxvArticulationDriveCache::getLinkCount(cache); +} + +void Sc::ArticulationCore::applyImpulse(Sc::BodyCore& link, + const Sc::ArticulationDriveCache& driveCache, + const PxVec3& force, + const PxVec3& torque) +{ + if(mSim) + mSim->applyImpulse(link, driveCache, force, torque); +} + +void Sc::ArticulationCore::computeImpulseResponse(Sc::BodyCore& link, + PxVec3& linearResponse, + PxVec3& angularResponse, + const Sc::ArticulationDriveCache& driveCache, + const PxVec3& force, + const PxVec3& torque) const +{ + if(mSim) + mSim->computeImpulseResponse(link, linearResponse, angularResponse, driveCache, force, torque); +} + +IG::NodeIndex Sc::ArticulationCore::getIslandNodeIndex() const +{ + if (mSim) + return mSim->getIslandNodeIndex(); + return IG::NodeIndex(IG_INVALID_NODE); +} diff --git a/PhysX_3.4/Source/SimulationController/src/ScArticulationJointCore.cpp b/PhysX_3.4/Source/SimulationController/src/ScArticulationJointCore.cpp new file mode 100644 index 00000000..87327ed6 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScArticulationJointCore.cpp @@ -0,0 +1,201 @@ +// 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 "ScArticulationJointCore.h" + +#include "ScArticulationJointSim.h" +#include "ScBodyCore.h" + +using namespace physx; + +Sc::ArticulationJointCore::ArticulationJointCore(const PxTransform& parentFrame, + const PxTransform& childFrame) : + mSim (NULL) +{ + PX_ASSERT(parentFrame.isValid()); + PX_ASSERT(childFrame.isValid()); + + mCore.parentPose = parentFrame; + mCore.childPose = childFrame; + + mCore.targetPosition = PxQuat(PxIdentity); + mCore.targetVelocity = PxVec3(0); + + mCore.driveType = PxArticulationJointDriveType::eTARGET; + + mCore.spring = 0.0f; + mCore.damping = 0.0f; + + mCore.internalCompliance = 1.0f; + mCore.externalCompliance = 1.0f; + + mCore.swingYLimit = PxPi/4; + mCore.swingZLimit = PxPi/4; + mCore.swingLimitContactDistance = 0.05f; + mCore.swingLimited = false; + mCore.tangentialStiffness = 0.0f; + mCore.tangentialDamping = 0.0f; + + mCore.twistLimitLow = -PxPi/4; + mCore.twistLimitHigh = PxPi/4; + mCore.twistLimitContactDistance = 0.05f; + mCore.twistLimited = false; + + + mCore.tanQSwingY = PxTan(mCore.swingYLimit/4); + mCore.tanQSwingZ = PxTan(mCore.swingZLimit/4); + mCore.tanQSwingPad = PxTan(mCore.swingLimitContactDistance/4); + + mCore.tanQTwistHigh = PxTan(mCore.twistLimitHigh/4); + mCore.tanQTwistLow = PxTan(mCore.twistLimitLow/4); + mCore.tanQTwistPad = PxTan(mCore.twistLimitContactDistance/4); + +} + + +Sc::ArticulationJointCore::~ArticulationJointCore() +{ + PX_ASSERT(getSim() == 0); +} + + +//-------------------------------------------------------------- +// +// ArticulationJointCore interface implementation +// +//-------------------------------------------------------------- + + +void Sc::ArticulationJointCore::setParentPose(const PxTransform& t) +{ + mCore.parentPose = t; +} + + +void Sc::ArticulationJointCore::setChildPose(const PxTransform& t) +{ + mCore.childPose = t; +} + + +void Sc::ArticulationJointCore::setTargetOrientation(const PxQuat& p) +{ + mCore.targetPosition = p; +} + + +void Sc::ArticulationJointCore::setTargetVelocity(const PxVec3& v) +{ + mCore.targetVelocity = v; +} + +void Sc::ArticulationJointCore::setDriveType(PxArticulationJointDriveType::Enum type) +{ + mCore.driveType = PxU8(type); +} + + +void Sc::ArticulationJointCore::setStiffness(PxReal s) +{ + mCore.spring = s; +} + + +void Sc::ArticulationJointCore::setDamping(PxReal d) +{ + mCore.damping = d; +} + + +void Sc::ArticulationJointCore::setInternalCompliance(PxReal r) +{ + mCore.internalCompliance = r; +} + +void Sc::ArticulationJointCore::setExternalCompliance(PxReal r) +{ + mCore.externalCompliance = r; +} + + +void Sc::ArticulationJointCore::setSwingLimit(PxReal yLimit, PxReal zLimit) +{ + mCore.swingYLimit = yLimit; + mCore.swingZLimit = zLimit; + + mCore.tanQSwingY = PxTan(yLimit/4); + mCore.tanQSwingZ = PxTan(zLimit/4); +} + + +void Sc::ArticulationJointCore::setTangentialStiffness(PxReal s) +{ + mCore.tangentialStiffness = s; +} + + +void Sc::ArticulationJointCore::setTangentialDamping(PxReal d) +{ + mCore.tangentialDamping = d; +} + + +void Sc::ArticulationJointCore::setSwingLimitEnabled(bool e) +{ + mCore.swingLimited = e; +} + +void Sc::ArticulationJointCore::setSwingLimitContactDistance(PxReal e) +{ + mCore.swingLimitContactDistance = e; + mCore.tanQSwingPad = PxTan(e/4); +} + + +void Sc::ArticulationJointCore::setTwistLimit(PxReal lower, PxReal upper) +{ + mCore.twistLimitLow = lower; + mCore.twistLimitHigh = upper; + + mCore.tanQTwistHigh = PxTan(upper/4); + mCore.tanQTwistLow = PxTan(lower/4); +} + + +void Sc::ArticulationJointCore::setTwistLimitEnabled(bool e) +{ + mCore.twistLimited = e; +} + +void Sc::ArticulationJointCore::setTwistLimitContactDistance(PxReal e) +{ + mCore.twistLimitContactDistance = e; + mCore.tanQTwistPad = PxTan(e/4); +} diff --git a/PhysX_3.4/Source/SimulationController/src/ScArticulationJointSim.cpp b/PhysX_3.4/Source/SimulationController/src/ScArticulationJointSim.cpp new file mode 100644 index 00000000..81d50565 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScArticulationJointSim.cpp @@ -0,0 +1,97 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-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 "ScArticulationJointSim.h" +#include "ScArticulationJointCore.h" +#include "ScBodySim.h" +#include "ScScene.h" +#include "PxsRigidBody.h" +#include "DyArticulation.h" +#include "ScArticulationSim.h" +#include "PxsSimpleIslandManager.h" + +using namespace physx; + +Sc::ArticulationJointSim::ArticulationJointSim(ArticulationJointCore& joint, ActorSim& parent, ActorSim& child) : + ActorInteraction (parent, child, InteractionType::eARTICULATION, 0), + mCore (joint) +{ + registerInActors(); + + BodySim& childBody = static_cast<BodySim&>(child), + & parentBody = static_cast<BodySim&>(parent); + + parentBody.getArticulation()->addBody(childBody, &parentBody, this); + + mCore.setSim(this); +} + + +Sc::ArticulationJointSim::~ArticulationJointSim() +{ + // articulation interactions do not make use of the dirty flags yet. If they did, a setClean(true) has to be introduced here. + PX_ASSERT(!readInteractionFlag(InteractionFlag::eIN_DIRTY_LIST)); + PX_ASSERT(!getDirtyFlags()); + + unregisterFromActors(); + + BodySim& child = getChild(); + child.getArticulation()->removeBody(child); + + mCore.setSim(NULL); +} + + +Sc::BodySim& Sc::ArticulationJointSim::getParent() const +{ + return static_cast<BodySim&>(getActorSim0()); +} + + +Sc::BodySim& Sc::ArticulationJointSim::getChild() const +{ + return static_cast<BodySim&>(getActorSim1()); +} + + +bool Sc::ArticulationJointSim::onActivate(void*) +{ + if(!(getParent().isActive() && getChild().isActive())) + return false; + + raiseInteractionFlag(InteractionFlag::eIS_ACTIVE); + return true; +} + +bool Sc::ArticulationJointSim::onDeactivate(PxU32) +{ + clearInteractionFlag(InteractionFlag::eIS_ACTIVE); + return true; +} diff --git a/PhysX_3.4/Source/SimulationController/src/ScArticulationJointSim.h b/PhysX_3.4/Source/SimulationController/src/ScArticulationJointSim.h new file mode 100644 index 00000000..723e1644 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScArticulationJointSim.h @@ -0,0 +1,89 @@ +// 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_ARTICULATION_JOINT_SIM +#define PX_PHYSICS_SCP_ARTICULATION_JOINT_SIM + +#include "ScActorInteraction.h" +#include "DyArticulation.h" + +namespace physx +{ +namespace Sc +{ + class ArticulationJointCore; + class BodySim; + + class ArticulationJointSim : public ActorInteraction + { + ArticulationJointSim &operator=(const ArticulationJointSim &); + + public: + + ArticulationJointSim(ArticulationJointCore& joint, ActorSim& parent, ActorSim& child); + + ~ArticulationJointSim(); + + //---------- Interaction ---------- + virtual bool onActivate(void*); + virtual bool onDeactivate(PxU32 infoFlag); + //----------------------------------- + + PX_INLINE ArticulationJointCore& getCore() const; + PX_INLINE static bool isArticulationInteraction(const Interaction& interaction); + + BodySim& getParent() const; + BodySim& getChild() const; + + //--------------------------------------------------------------------------------- + // Low Level data access + //--------------------------------------------------------------------------------- + private: + + ArticulationJointCore& mCore; + }; + +} // namespace Sc + + +PX_INLINE Sc::ArticulationJointCore& Sc::ArticulationJointSim::getCore() const +{ + return mCore; +} + + +PX_INLINE bool Sc::ArticulationJointSim::isArticulationInteraction(const Interaction& interaction) +{ + return (interaction.getType() == InteractionType::eARTICULATION); +} + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/ScArticulationSim.cpp b/PhysX_3.4/Source/SimulationController/src/ScArticulationSim.cpp new file mode 100644 index 00000000..a35f4bf2 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScArticulationSim.cpp @@ -0,0 +1,515 @@ +// 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 "ScArticulationSim.h" +#include "ScArticulationCore.h" +#include "ScArticulationJointSim.h" +#include "ScArticulationJointCore.h" +#include "ScBodySim.h" +#include "ScScene.h" + +#include "DyArticulation.h" +#include "PxsContext.h" +#include "CmSpatialVector.h" +#include "PsVecMath.h" +#include "PxsSimpleIslandManager.h" + +using namespace physx; +using namespace physx::Dy; + +Sc::ArticulationSim::ArticulationSim(ArticulationCore& core, Scene& scene, BodyCore& root) : + mLLArticulation(NULL), + mScene(scene), + mCore(core), + mLinks (PX_DEBUG_EXP("ScArticulationSim::links")), + mBodies (PX_DEBUG_EXP("ScArticulationSim::bodies")), + mJoints (PX_DEBUG_EXP("ScArticulationSim::joints")), + mInternalLoads (PX_DEBUG_EXP("ScArticulationSim::internalLoads")), + mExternalLoads (PX_DEBUG_EXP("ScArticulationSim::externalLoads")), + mPose (PX_DEBUG_EXP("ScArticulationSim::poses")), + mMotionVelocity (PX_DEBUG_EXP("ScArticulationSim::motion velocity")), + mFsDataBytes (PX_DEBUG_EXP("ScArticulationSim::fsData")), + mScratchMemory (PX_DEBUG_EXP("ScArticulationSim::scratchMemory")), + mUpdateSolverData(true) +{ + mLinks.reserve(16); + mJoints.reserve(16); + mBodies.reserve(16); + + mLLArticulation = mScene.createLLArticulation(this); + + mIslandNodeIndex = scene.getSimpleIslandManager()->addArticulation(this, mLLArticulation, false); + + if(!mLLArticulation) + { + Ps::getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __LINE__, "Articulation: could not allocate low-level resources."); + return; + } + + PX_ASSERT(root.getSim()); + + addBody(*root.getSim(), NULL, NULL); + + + + mCore.setSim(this); + + mSolverData.core = &core.getCore(); + mSolverData.internalLoads = NULL; + mSolverData.externalLoads = NULL; + mSolverData.fsData = NULL; + mSolverData.poses = NULL; + mSolverData.motionVelocity = NULL; + mSolverData.totalDataSize = 0; + mSolverData.solverDataSize = 0; + mSolverData.linkCount = 0; + mSolverData.scratchMemory = NULL; + mSolverData.scratchMemorySize = 0; +} + + +Sc::ArticulationSim::~ArticulationSim() +{ + if (!mLLArticulation) + return; + + mScene.destroyLLArticulation(*mLLArticulation); + + mScene.getSimpleIslandManager()->removeNode(mIslandNodeIndex); + + mCore.setSim(NULL); +} + +PxU32 Sc::ArticulationSim::findBodyIndex(BodySim& body) const +{ + for(PxU32 i=0; i<mBodies.size(); i++) + { + if(mBodies[i]==&body) + return i; + } + PX_ASSERT(0); + return 0x80000000; +} + +void Sc::ArticulationSim::updateCached(Cm::BitMapPinned* shapeChangedMap) +{ + for(PxU32 i=0; i<mBodies.size(); i++) + mBodies[i]->updateCached(shapeChangedMap); +} + +void Sc::ArticulationSim::updateContactDistance(PxReal* contactDistance, const PxReal dt, Bp::BoundsArray& boundsArray) +{ + for (PxU32 i = 0; i<mBodies.size(); i++) + mBodies[i]->updateContactDistance(contactDistance, dt, boundsArray); +} + +ArticulationLinkHandle Sc::ArticulationSim::getLinkHandle(BodySim &body) const +{ + return reinterpret_cast<size_t>(mLLArticulation) | findBodyIndex(body); +} + +void Sc::ArticulationSim::addBody(BodySim& body, + BodySim* parent, + ArticulationJointSim* joint) +{ + mBodies.pushBack(&body); + mJoints.pushBack(joint); + mAcceleration.pushBack(Cm::SpatialVector(PxVec3(0.f), PxVec3(0.f))); + + PxU32 index = mLinks.size(); + + PX_ASSERT((((index==0) && (joint == 0)) && (parent == 0)) || + (((index!=0) && joint) && (parent && (parent->getArticulation() == this)))); + + ArticulationLink &link = mLinks.insert(); + link.body = &body.getLowLevelBody(); + link.bodyCore = &body.getBodyCore().getCore(); + link.children = 0; + bool shouldSleep; + bool currentlyAsleep; + bool bodyReadyForSleep = body.checkSleepReadinessBesidesWakeCounter(); + PxReal wakeCounter = getCore().getWakeCounter(); + + if(parent) + { + currentlyAsleep = !mBodies[0]->isActive(); + shouldSleep = currentlyAsleep && bodyReadyForSleep; + + PxU32 parentIndex = findBodyIndex(*parent); + link.parent = parentIndex; + link.pathToRoot = mLinks[parentIndex].pathToRoot | ArticulationBitField(1)<<index; + link.inboundJoint = &joint->getCore().getCore(); + mLinks[parentIndex].children |= ArticulationBitField(1)<<index; + } + else + { + currentlyAsleep = (wakeCounter == 0.0f); + shouldSleep = currentlyAsleep && bodyReadyForSleep; + + link.parent = DY_ARTICULATION_LINK_NONE; + link.pathToRoot = 1; + link.inboundJoint = NULL; + } + + if (currentlyAsleep && (!shouldSleep)) + { + for(PxU32 i=0; i < (mBodies.size() - 1); i++) + mBodies[i]->internalWakeUpArticulationLink(wakeCounter); + } + + body.setArticulation(this, wakeCounter, shouldSleep, index); + + mUpdateSolverData = true; + +} + + +void Sc::ArticulationSim::removeBody(BodySim &body) +{ + PX_ASSERT(body.getArticulation() == this); + PxU32 index = findBodyIndex(body); + body.setArticulation(NULL, 0.0f, true, 0); + + ArticulationLink &link0 = mLinks[index]; + + PX_ASSERT(link0.children == 0); + PX_UNUSED(link0); + + // copy all the later links down by one + for(PxU32 i=index+1;i<mLinks.size();i++) + { + mLinks[i-1] = mLinks[i]; + mBodies[i-1] = mBodies[i]; + mJoints[i-1] = mJoints[i]; + //setIslandHandle(*mBodies[i-1], i-1); + } + + // adjust parent/child indices + ArticulationBitField fixedIndices = (ArticulationBitField(1)<<index)-1; + ArticulationBitField shiftIndices = ~(fixedIndices|(ArticulationBitField(1)<<index)); + + for(PxU32 i=0;i<mLinks.size();i++) + { + ArticulationLink &link = mLinks[i]; + + if(link.parent != DY_ARTICULATION_LINK_NONE && link.parent>index) + link.pathToRoot = (link.pathToRoot&fixedIndices) | (link.pathToRoot&shiftIndices)>>1; + link.children = (link.children&fixedIndices) | (link.children&shiftIndices)>>1; + } + + mLinks.popBack(); + + mUpdateSolverData = true; +} + + +void Sc::ArticulationSim::checkResize() const +{ + if(!mBodies.size()) + return; + + if(!mUpdateSolverData) + return; + + if(mLinks.size()!=mSolverData.linkCount) + { + PxU32 linkCount = mLinks.size(); + + mMotionVelocity.resize(linkCount, Cm::SpatialVector(PxVec3(0.0f), PxVec3(0.0f))); + mPose.resize(linkCount, PxTransform(PxIdentity)); + mExternalLoads.resize(linkCount, Ps::aos::M33Identity()); + mInternalLoads.resize(linkCount, Ps::aos::M33Identity()); + + PxU32 solverDataSize, totalSize, scratchSize; + Articulation::getDataSizes(linkCount, solverDataSize, totalSize, scratchSize); + + PX_ASSERT(mFsDataBytes.size()!=totalSize); + PX_ASSERT(!(totalSize&15) && !(solverDataSize&15)); + mFsDataBytes.resize(totalSize); + + mSolverData.motionVelocity = mMotionVelocity.begin(); + mSolverData.externalLoads = mExternalLoads.begin(); + mSolverData.internalLoads = mInternalLoads.begin(); + mSolverData.poses = mPose.begin(); + mSolverData.solverDataSize = Ps::to16(solverDataSize); + mSolverData.totalDataSize = Ps::to16(totalSize); + mSolverData.fsData = reinterpret_cast<FsData *>(mFsDataBytes.begin()); + mSolverData.acceleration = mAcceleration.begin(); + + mScratchMemory.resize(scratchSize); + mSolverData.scratchMemory = mScratchMemory.begin(); + mSolverData.scratchMemorySize = Ps::to16(scratchSize); + } + + + // something changed... e.g. a link deleted and one added - we need to change the warm start + + PxMemZero(mExternalLoads.begin(), sizeof(Ps::aos::Mat33V) * mExternalLoads.size()); + PxMemZero(mInternalLoads.begin(), sizeof(Ps::aos::Mat33V) * mExternalLoads.size()); + + mSolverData.links = mLinks.begin(); + mSolverData.linkCount = Ps::to8(mLinks.size()); + + mLLArticulation->setSolverDesc(mSolverData); + + mUpdateSolverData = false; +} + +PxU32 Sc::ArticulationSim::getCCDLinks(BodySim** sims) +{ + PxU32 nbCCDBodies = 0; + for (PxU32 a = 0; a < mBodies.size(); ++a) + { + if (mBodies[a]->getLowLevelBody().getCore().mFlags & PxRigidBodyFlag::eENABLE_CCD) + { + sims[nbCCDBodies++] = mBodies[a]; + } + } + return nbCCDBodies; +} + +void Sc::ArticulationSim::sleepCheck(PxReal dt) +{ + if(!mBodies.size()) + return; + +#if PX_CHECKED + { + PxReal maxTimer = 0.0f, minTimer = PX_MAX_F32; + bool allActive = true, noneActive = true; + for(PxU32 i=0;i<mLinks.size();i++) + { + PxReal timer = mBodies[i]->getBodyCore().getWakeCounter(); + maxTimer = PxMax(maxTimer, timer); + minTimer = PxMin(minTimer, timer); + bool active = mBodies[i]->isActive(); + allActive &= active; + noneActive &= !active; + } + // either all links are asleep, or no links are asleep + PX_ASSERT(maxTimer==0 || minTimer!=0); + PX_ASSERT(allActive || noneActive); + } + +#endif + + if(!mBodies[0]->isActive()) + return; + + PxReal sleepThreshold = getCore().getCore().sleepThreshold; + + PxReal maxTimer = 0.0f, minTimer = PX_MAX_F32; + + for(PxU32 i=0;i<mLinks.size();i++) + { + PxReal timer = mBodies[i]->updateWakeCounter(dt, sleepThreshold, reinterpret_cast<Cm::SpatialVector&>(mMotionVelocity[i]));//enableStabilization); + maxTimer = PxMax(maxTimer, timer); + minTimer = PxMin(minTimer, timer); + } + + mCore.setWakeCounterInternal(maxTimer); + + if(maxTimer != 0.0f) + { + if(minTimer == 0.0f) + { + // make sure nothing goes to sleep unless everything does + for(PxU32 i=0;i<mLinks.size();i++) + mBodies[i]->getBodyCore().setWakeCounterFromSim(PxMax(1e-6f, mBodies[i]->getBodyCore().getWakeCounter())); + } + return; + } + + for(PxU32 i=0;i<mLinks.size();i++) + { + mBodies[i]->notifyReadyForSleeping(); + mBodies[i]->resetSleepFilter(); + } + + mScene.getSimpleIslandManager()->deactivateNode(mIslandNodeIndex); +} + +bool Sc::ArticulationSim::isSleeping() const +{ + return (mBodies.size() > 0) ? (!mBodies[0]->isActive()) : true; +} + +void Sc::ArticulationSim::internalWakeUp(PxReal wakeCounter) +{ + if(mCore.getWakeCounter() < wakeCounter) + { + mCore.setWakeCounterInternal(wakeCounter); + for(PxU32 i=0;i<mLinks.size();i++) + mBodies[i]->internalWakeUpArticulationLink(wakeCounter); + } +} + +void Sc::ArticulationSim::setActive(const bool b, const PxU32 infoFlag) +{ + for(PxU32 i=0;i<mBodies.size();i++) + { + if (i+1 < mBodies.size()) + { + Ps::prefetchLine(mBodies[i+1],0); + Ps::prefetchLine(mBodies[i+1],128); + } + mBodies[i]->setActive(b, infoFlag); + } +} + +void Sc::ArticulationSim::updateForces(PxReal dt, bool simUsesAdaptiveForce) +{ + PxU32 count = 0; + for(PxU32 i=0;i<mBodies.size();i++) + { + if (i+1 < mBodies.size()) + { + Ps::prefetchLine(mBodies[i+1],128); + Ps::prefetchLine(mBodies[i+1],256); + } + mBodies[i]->updateForces(dt, NULL, NULL, count, &mAcceleration[i], simUsesAdaptiveForce); + } +} + +void Sc::ArticulationSim::saveLastCCDTransform() +{ + for(PxU32 i=0;i<mBodies.size();i++) + { + if (i+1 < mBodies.size()) + { + Ps::prefetchLine(mBodies[i+1],128); + Ps::prefetchLine(mBodies[i+1],256); + } + mBodies[i]->getLowLevelBody().saveLastCCDTransform(); + } +} + + +Sc::ArticulationDriveCache* Sc::ArticulationSim::createDriveCache(PxReal compliance, + PxU32 driveIterations) const +{ + checkResize(); + PxU32 solverDataSize, totalSize, scratchSize; + Articulation::getDataSizes(mLinks.size(), solverDataSize, totalSize, scratchSize); + + // In principle we should only need solverDataSize here. But right now prepareFsData generates the auxiliary data + // for use in potential debugging, which takes up extra space. + FsData* data = reinterpret_cast<FsData*>(PX_ALLOC(totalSize,"Articulation Drive Cache")); + PxvArticulationDriveCache::initialize(*data, Ps::to16(mLinks.size()), mLinks.begin(), compliance, driveIterations, mScratchMemory.begin(), mScratchMemory.size()); + return data; +} + + +void Sc::ArticulationSim::updateDriveCache(ArticulationDriveCache& cache, + PxReal compliance, + PxU32 driveIterations) const +{ + checkResize(); + PxvArticulationDriveCache::initialize(cache, Ps::to16(mLinks.size()), mLinks.begin(), compliance, driveIterations, mScratchMemory.begin(), mScratchMemory.size()); +} + + +void Sc::ArticulationSim::releaseDriveCache(Sc::ArticulationDriveCache& driveCache) const +{ + PX_FREE(&driveCache); +} + + +void Sc::ArticulationSim::applyImpulse(Sc::BodyCore& link, + const Sc::ArticulationDriveCache& driveCache, + const PxVec3& force, + const PxVec3& torque) +{ + Cm::SpatialVectorV v[DY_ARTICULATION_MAX_SIZE], z[DY_ARTICULATION_MAX_SIZE]; + PxMemZero(z, mLinks.size()*sizeof(Cm::SpatialVector)); + PxMemZero(v, mLinks.size()*sizeof(Cm::SpatialVector)); + + PxU32 bodyIndex = findBodyIndex(*link.getSim()); + z[bodyIndex].linear = Ps::aos::V3LoadU(-force); + z[bodyIndex].angular = Ps::aos::V3LoadU(-torque); + + PxvArticulationDriveCache::applyImpulses(driveCache, z, v); + for(PxU32 i=0;i<mLinks.size();i++) + { + Sc::BodyCore& body = mBodies[i]->getBodyCore(); + PxVec3 lv, av; + Ps::aos::V3StoreU(v[i].linear, lv); + Ps::aos::V3StoreU(v[i].angular, av); + + body.setLinearVelocity(body.getLinearVelocity()+lv); + body.setAngularVelocity(body.getAngularVelocity()+av); + } +} + +void Sc::ArticulationSim::computeImpulseResponse(Sc::BodyCore& link, + PxVec3& linearResponse, + PxVec3& angularResponse, + const Sc::ArticulationDriveCache& driveCache, + const PxVec3& force, + const PxVec3& torque) const +{ + Cm::SpatialVectorV v; + PxvArticulationDriveCache::getImpulseResponse(driveCache, findBodyIndex(*link.getSim()), Cm::SpatialVectorV(Ps::aos::V3LoadU(force), Ps::aos::V3LoadU(torque)), v); + Ps::aos::V3StoreU(v.linear, linearResponse); + Ps::aos::V3StoreU(v.angular, angularResponse); +} + +void Sc::ArticulationSim::debugCheckWakeCounterOfLinks(PxReal wakeCounter) const +{ + PX_UNUSED(wakeCounter); + +#ifdef _DEBUG + // make sure the links are in sync with the articulation + for(PxU32 i=0; i < mBodies.size(); i++) + { + PX_ASSERT(mBodies[i]->getBodyCore().getWakeCounter() == wakeCounter); + } +#endif +} + +void Sc::ArticulationSim::debugCheckSleepStateOfLinks(bool isSleeping) const +{ + PX_UNUSED(isSleeping); + +#ifdef _DEBUG + // make sure the links are in sync with the articulation + for(PxU32 i=0; i < mBodies.size(); i++) + { + if (isSleeping) + { + PX_ASSERT(!mBodies[i]->isActive()); + PX_ASSERT(mBodies[i]->getBodyCore().getWakeCounter() == 0.0f); + PX_ASSERT(mBodies[i]->checkSleepReadinessBesidesWakeCounter()); + } + else + PX_ASSERT(mBodies[i]->isActive()); + } +#endif +} diff --git a/PhysX_3.4/Source/SimulationController/src/ScArticulationSim.h b/PhysX_3.4/Source/SimulationController/src/ScArticulationSim.h new file mode 100644 index 00000000..a86de4f1 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScArticulationSim.h @@ -0,0 +1,181 @@ +// 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_ARTICULATION_SIM +#define PX_PHYSICS_ARTICULATION_SIM + + +#include "PsUserAllocated.h" +#include "CmPhysXCommon.h" +#include "DyArticulation.h" +#include "ScArticulationCore.h" +#include "PxsSimpleIslandManager.h" + +namespace physx +{ + +namespace Dy +{ + class Articulation; +} + +class PxsTransformCache; +class PxsSimulationController; + +namespace Cm +{ + class SpatialVector; + template <class Allocator> class BitMapBase; + typedef BitMapBase<Ps::NonTrackingAllocator> BitMap; +} + +namespace Bp +{ + class BoundsArray; +} + +namespace Sc +{ + + class BodySim; + class ArticulationJointSim; + class ArticulationCore; + class Scene; + + class ArticulationSim : public Ps::UserAllocated + { + public: + ArticulationSim(ArticulationCore& core, + Scene& scene, + BodyCore& root); + + ~ArticulationSim(); + + PX_INLINE Dy::Articulation* getLowLevelArticulation() const { return mLLArticulation; } + PX_INLINE ArticulationCore& getCore() const { return mCore; } + + void addBody(BodySim& body, + BodySim* parent, + ArticulationJointSim* joint); + void removeBody(BodySim &sim); + + Dy::ArticulationLinkHandle getLinkHandle(BodySim& body) const; + + void checkResize() const; // resize LL memory if necessary + + void debugCheckWakeCounterOfLinks(PxReal wakeCounter) const; + void debugCheckSleepStateOfLinks(bool isSleeping) const; + + bool isSleeping() const; + void internalWakeUp(PxReal wakeCounter); // called when sim sets sleep timer + void sleepCheck(PxReal dt); + PxU32 getCCDLinks(BodySim** sims); + void updateCached(Cm::BitMapPinned* shapehapeChangedMap); + void updateContactDistance(PxReal* contactDistance, const PxReal dt, Bp::BoundsArray& boundsArray); + + + // temporary, to make sure link handles are set in island detection. This should be done on insertion, + // but when links are inserted into the scene they don't know about the articulation so for the + // moment we fix it up at sim start + + void fixupHandles(); + + void setActive(const bool b, const PxU32 infoFlag=0); + + void updateForces(PxReal dt, bool simUsesAdaptiveForce); + void saveLastCCDTransform(); + + // drive cache implementation + // + ArticulationDriveCache* + createDriveCache(PxReal compliance, + PxU32 driveIterations) const; + + void updateDriveCache(ArticulationDriveCache& cache, + PxReal compliance, + PxU32 driveIterations) const; + + void releaseDriveCache(ArticulationDriveCache& cache) const; + + void applyImpulse(BodyCore& link, + const ArticulationDriveCache& driveCache, + const PxVec3& force, + const PxVec3& torque); + + void computeImpulseResponse(BodyCore& link, + PxVec3& linearResponse, + PxVec3& angularResponse, + const ArticulationDriveCache& driveCache, + const PxVec3& force, + const PxVec3& torque) const; + + PX_FORCE_INLINE IG::NodeIndex getIslandNodeIndex() const { return mIslandNodeIndex; } + + + private: + ArticulationSim& operator=(const ArticulationSim&); + PxU32 findBodyIndex(BodySim &body) const; + + + Dy::Articulation* mLLArticulation; + Scene& mScene; + ArticulationCore& mCore; + Ps::Array<Dy::ArticulationLink> mLinks; + Ps::Array<BodySim*> mBodies; + Ps::Array<ArticulationJointSim*> mJoints; + IG::NodeIndex mIslandNodeIndex; + + + // DS: looks slightly fishy, but reallocating/relocating the LL memory for the articulation + // really is supposed to leave it behaviorally equivalent, and so we can reasonably make + // all this stuff mutable and checkResize const + + mutable Dy::ArticulationSolverDesc mSolverData; + + // persistent state of the articulation for warm-starting joint load computation + mutable Ps::Array<Ps::aos::Mat33V> mInternalLoads; + mutable Ps::Array<Ps::aos::Mat33V> mExternalLoads; + + // persistent data used during the solve that can be released at frame end + + mutable Ps::Array<PxTransform> mPose; + mutable Ps::Array<Cm::SpatialVectorV> mMotionVelocity; // saved here in solver + mutable Ps::Array<char> mFsDataBytes; // drive cache creation (which is const) can force a resize + mutable Ps::Array<char> mScratchMemory; // drive cache creation (which is const) can force a resize + mutable Ps::Array<Cm::SpatialVector> mAcceleration; + + mutable bool mUpdateSolverData; + }; + +} // namespace Sc + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/ScBodyCore.cpp b/PhysX_3.4/Source/SimulationController/src/ScBodyCore.cpp new file mode 100644 index 00000000..e9f82106 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScBodyCore.cpp @@ -0,0 +1,710 @@ +// 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 "ScBodyCore.h" +#include "ScBodySim.h" +#include "ScPhysics.h" +#include "ScScene.h" +#include "PxsSimulationController.h" +#include "PsFoundation.h" + +using namespace physx; + +Sc::BodyCore::BodyCore(PxActorType::Enum type, const PxTransform& bodyPose) +: RigidCore(type) +{ + const PxTolerancesScale& scale = Physics::getInstance().getTolerancesScale(); + // sizeof(BodyCore) = 176 => 160 => 144 => 160 bytes + + mCore.wakeCounter = Sc::Physics::sWakeCounterOnCreation; + mCore.inverseInertia = PxVec3(1.f,1.f,1.f); + mCore.inverseMass = 1.0f; + mCore.body2World = bodyPose; + + PX_ASSERT(mCore.body2World.p.isFinite()); + PX_ASSERT(mCore.body2World.q.isFinite()); + + mCore.sleepThreshold = 5e-5f * scale.speed * scale.speed; + mCore.freezeThreshold = 2.5e-5f * scale.speed * scale.speed; + mSimStateData = NULL; + mCore.maxPenBias = -1e32f;//-PX_MAX_F32; + mCore.mFlags = PxRigidBodyFlags(); + mCore.linearVelocity = PxVec3(0.0f); + mCore.angularVelocity = PxVec3(0.0f); + mCore.linearDamping = 0.0f; + mCore.maxLinearVelocitySq = PX_MAX_F32; + mCore.solverIterationCounts = (1 << 8) | 4; + mCore.contactReportThreshold = PX_MAX_F32; + mCore.setBody2Actor(PxTransform(PxIdentity)); + mCore.ccdAdvanceCoefficient = 0.15f; + mCore.maxContactImpulse = 1e32f;// PX_MAX_F32; + mCore.isFastMoving = false; + mCore.lockFlags = PxRigidDynamicLockFlags(0); + + if(type == PxActorType::eRIGID_DYNAMIC) + { + mCore.angularDamping = 0.05f; + mCore.maxAngularVelocitySq = 7.0f * 7.0f; + } + else + { + mCore.angularDamping = 0.0f; + mCore.maxAngularVelocitySq = PX_MAX_F32; + } +} + +Sc::BodyCore::~BodyCore() +{ + PX_ASSERT(getSim() == 0); + PX_ASSERT(!mSimStateData); +} + +Sc::BodySim* Sc::BodyCore::getSim() const +{ + return static_cast<BodySim*>(Sc::ActorCore::getSim()); +} + +size_t Sc::BodyCore::getSerialCore(PxsBodyCore& serialCore) +{ + serialCore = mCore; + if(mSimStateData && mSimStateData->isKine()) + { + const Kinematic* kine = mSimStateData->getKinematicData(); + serialCore.inverseMass = kine->backupInvMass; + serialCore.inverseInertia = kine->backupInverseInertia; + serialCore.linearDamping = kine->backupLinearDamping; + serialCore.angularDamping = kine->backupAngularDamping; + serialCore.maxAngularVelocitySq = kine->backupMaxAngVelSq; + serialCore.maxLinearVelocitySq = kine->backupMaxLinVelSq; + } + return reinterpret_cast<size_t>(&mCore); +} + +//-------------------------------------------------------------- +// +// BodyCore interface implementation +// +//-------------------------------------------------------------- + +void Sc::BodyCore::setBody2World(const PxTransform& p) +{ + mCore.body2World = p; + PX_ASSERT(p.p.isFinite()); + PX_ASSERT(p.q.isFinite()); + + BodySim* sim = getSim(); + if (sim) + { + sim->postBody2WorldChange(); + //update bodysim + Sc::Scene& scene = sim->getScene(); + scene.getSimulationController()->addDynamic(&sim->getLowLevelBody(), sim->getNodeIndex().index()); + } +} + +void Sc::BodyCore::setLinearVelocity(const PxVec3& v) +{ + mCore.linearVelocity = v; + + BodySim* sim = getSim(); + if (sim) + { + //update bodysim + Sc::Scene& scene = sim->getScene(); + scene.getSimulationController()->addDynamic(&sim->getLowLevelBody(), sim->getNodeIndex().index()); + } +} + +void Sc::BodyCore::setAngularVelocity(const PxVec3& v) +{ + mCore.angularVelocity = v; + + BodySim* sim = getSim(); + if (sim) + { + //update bodysim + Sc::Scene& scene = sim->getScene(); + scene.getSimulationController()->addDynamic(&sim->getLowLevelBody(), sim->getNodeIndex().index()); + } +} + +void Sc::BodyCore::setBody2Actor(const PxTransform& p) +{ + PX_ASSERT(p.p.isFinite()); + PX_ASSERT(p.q.isFinite()); + + mCore.setBody2Actor(p); + + BodySim* sim = getSim(); + if (sim) + { + sim->notifyShapesOfTransformChange(); + //update bodysim + Sc::Scene& scene = sim->getScene(); + scene.getSimulationController()->addDynamic(&sim->getLowLevelBody(), sim->getNodeIndex().index()); + } +} + + +void Sc::BodyCore::addSpatialAcceleration(Ps::Pool<SimStateData>* simStateDataPool, const PxVec3* linAcc, const PxVec3* angAcc) +{ + //The dirty flag is stored separately in the BodySim so that we query the dirty flag before going to + //the expense of querying the simStateData for the velmod values. + BodySim* sim = getSim(); + if(sim) + sim->notifyAddSpatialAcceleration(); + + if(!mSimStateData || !mSimStateData->isVelMod()) + setupSimStateData(simStateDataPool, false); + + VelocityMod* velmod = mSimStateData->getVelocityModData(); + velmod->notifyAddAcceleration(); + if(linAcc) velmod->accumulateLinearVelModPerSec(*linAcc); + if(angAcc) velmod->accumulateAngularVelModPerSec(*angAcc); +} + +void Sc::BodyCore::clearSpatialAcceleration(bool force, bool torque) +{ + PX_ASSERT(force || torque); + + //The dirty flag is stored separately in the BodySim so that we query the dirty flag before going to + //the expense of querying the simStateData for the velmod values. + BodySim* sim = getSim(); + if(sim) + sim->notifyClearSpatialAcceleration(); + + if(mSimStateData) + { + PX_ASSERT(mSimStateData->isVelMod()); + VelocityMod* velmod = mSimStateData->getVelocityModData(); + velmod->notifyClearAcceleration(); + if(force) + velmod->clearLinearVelModPerSec(); + if(torque) + velmod->clearAngularVelModPerSec(); + } +} + +void Sc::BodyCore::addSpatialVelocity(Ps::Pool<SimStateData>* simStateDataPool, const PxVec3* linVelDelta, const PxVec3* angVelDelta) +{ + //The dirty flag is stored separately in the BodySim so that we query the dirty flag before going to + //the expense of querying the simStateData for the velmod values. + BodySim* sim = getSim(); + if(sim) + sim->notifyAddSpatialVelocity(); + + if(!mSimStateData || !mSimStateData->isVelMod()) + setupSimStateData(simStateDataPool, false); + + VelocityMod* velmod = mSimStateData->getVelocityModData(); + velmod->notifyAddVelocity(); + if(linVelDelta) + velmod->accumulateLinearVelModPerStep(*linVelDelta); + if(angVelDelta) + velmod->accumulateAngularVelModPerStep(*angVelDelta); +} + +void Sc::BodyCore::clearSpatialVelocity(bool force, bool torque) +{ + PX_ASSERT(force || torque); + + //The dirty flag is stored separately in the BodySim so that we query the dirty flag before going to + //the expense of querying the simStateData for the velmod values. + BodySim* sim = getSim(); + if(sim) + sim->notifyClearSpatialVelocity(); + + if(mSimStateData) + { + PX_ASSERT(mSimStateData->isVelMod()); + VelocityMod* velmod = mSimStateData->getVelocityModData(); + velmod->notifyClearVelocity(); + if(force) + velmod->clearLinearVelModPerStep(); + if(torque) + velmod->clearAngularVelModPerStep(); + } +} + +PxReal Sc::BodyCore::getInverseMass() const +{ + return mSimStateData && mSimStateData->isKine() ? mSimStateData->getKinematicData()->backupInvMass : mCore.inverseMass; +} + +void Sc::BodyCore::setInverseMass(PxReal m) +{ + if(mSimStateData && mSimStateData->isKine()) + mSimStateData->getKinematicData()->backupInvMass = m; + else + { + mCore.inverseMass = m; + BodySim* sim = getSim(); + if (sim) + { + //update bodysim + Sc::Scene& scene = sim->getScene(); + scene.getSimulationController()->addDynamic(&sim->getLowLevelBody(), sim->getNodeIndex().index()); + } + } +} + +const PxVec3& Sc::BodyCore::getInverseInertia() const +{ + return mSimStateData && mSimStateData->isKine() ? mSimStateData->getKinematicData()->backupInverseInertia : mCore.inverseInertia; +} + +void Sc::BodyCore::setInverseInertia(const PxVec3& i) +{ + if(mSimStateData && mSimStateData->isKine()) + mSimStateData->getKinematicData()->backupInverseInertia = i; + else + { + mCore.inverseInertia = i; + BodySim* sim = getSim(); + if (sim) + { + //update bodysim + Sc::Scene& scene = sim->getScene(); + scene.getSimulationController()->addDynamic(&sim->getLowLevelBody(), sim->getNodeIndex().index()); + } + } +} + +PxReal Sc::BodyCore::getLinearDamping() const +{ + return mSimStateData && mSimStateData->isKine() ? mSimStateData->getKinematicData()->backupLinearDamping : mCore.linearDamping; +} + +void Sc::BodyCore::setLinearDamping(PxReal d) +{ + if(mSimStateData && mSimStateData->isKine()) + mSimStateData->getKinematicData()->backupLinearDamping = d; + else + { + mCore.linearDamping = d; + BodySim* sim = getSim(); + if (sim) + { + //update bodysim + Sc::Scene& scene = sim->getScene(); + scene.getSimulationController()->addDynamic(&sim->getLowLevelBody(), sim->getNodeIndex().index()); + } + } +} + +PxReal Sc::BodyCore::getAngularDamping() const +{ + return mSimStateData && mSimStateData->isKine() ? mSimStateData->getKinematicData()->backupAngularDamping : mCore.angularDamping; +} + +void Sc::BodyCore::setAngularDamping(PxReal v) +{ + if(mSimStateData && mSimStateData->isKine()) + mSimStateData->getKinematicData()->backupAngularDamping = v; + else + { + mCore.angularDamping = v; + BodySim* sim = getSim(); + if (sim) + { + //update bodysim + Sc::Scene& scene = sim->getScene(); + scene.getSimulationController()->addDynamic(&sim->getLowLevelBody(), sim->getNodeIndex().index()); + } + } +} + +PxReal Sc::BodyCore::getMaxAngVelSq() const +{ + return mSimStateData && mSimStateData->isKine() ? mSimStateData->getKinematicData()->backupMaxAngVelSq : mCore.maxAngularVelocitySq; +} + +void Sc::BodyCore::setMaxAngVelSq(PxReal v) +{ + if(mSimStateData && mSimStateData->isKine()) + mSimStateData->getKinematicData()->backupMaxAngVelSq = v; + else + { + mCore.maxAngularVelocitySq = v; + BodySim* sim = getSim(); + if (sim) + { + //update bodysim + Sc::Scene& scene = sim->getScene(); + scene.getSimulationController()->addDynamic(&sim->getLowLevelBody(), sim->getNodeIndex().index()); + } + } +} + +void Sc::BodyCore::setFlags(Ps::Pool<SimStateData>* simStateDataPool, PxRigidBodyFlags f) +{ + PxRigidBodyFlags old = mCore.mFlags; + if(f != old) + { + PxU32 wasKinematic = old & PxRigidBodyFlag::eKINEMATIC; + PxU32 isKinematic = f & PxRigidBodyFlag::eKINEMATIC; + bool switchToKinematic = ((!wasKinematic) && isKinematic); + bool switchToDynamic = (wasKinematic && (!isKinematic)); + + mCore.mFlags = f; + BodySim* sim = getSim(); + if (sim) + { + PX_ASSERT(simStateDataPool); + + const PxU32 posePreviewFlag = f & PxRigidBodyFlag::eENABLE_POSE_INTEGRATION_PREVIEW; + if (PxU32(old & PxRigidBodyFlag::eENABLE_POSE_INTEGRATION_PREVIEW) != posePreviewFlag) + sim->postPosePreviewChange(posePreviewFlag); + + // for those who might wonder about the complexity here: + // our current behavior is that you are not allowed to set a kinematic target unless the object is in a scene. + // Thus, the kinematic data should only be created/destroyed when we know for sure that we are in a scene. + + if (switchToKinematic) + { + setupSimStateData(simStateDataPool, true, false); + sim->postSwitchToKinematic(); + } + else if (switchToDynamic) + { + tearDownSimStateData(simStateDataPool, true); + sim->postSwitchToDynamic(); + } + + PxU32 wasSpeculativeCCD = old & PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD; + PxU32 isSpeculativeCCD = f & PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD; + + if (wasSpeculativeCCD ^ isSpeculativeCCD) + { + if (wasSpeculativeCCD) + { + if (sim->isArticulationLink()) + sim->getScene().resetSpeculativeCCDArticulationLink(sim->getNodeIndex().index()); + else + sim->getScene().resetSpeculativeCCDRigidBody(sim->getNodeIndex().index()); + + sim->getLowLevelBody().mInternalFlags &= (~PxcRigidBody::eSPECULATIVE_CCD); + } + else + { + if (sim->isArticulationLink()) + sim->getScene().setSpeculativeCCDArticulationLink(sim->getNodeIndex().index()); + else + sim->getScene().setSpeculativeCCDRigidBody(sim->getNodeIndex().index()); + + sim->getLowLevelBody().mInternalFlags |= (PxcRigidBody::eSPECULATIVE_CCD); + } + } + } + + if (switchToKinematic) + putToSleep(); + + if(sim) + { + PxRigidBodyFlags ktFlags(PxRigidBodyFlag::eUSE_KINEMATIC_TARGET_FOR_SCENE_QUERIES | PxRigidBodyFlag::eKINEMATIC); + bool hadKt = (old & ktFlags) == ktFlags; + bool hasKt = (f & ktFlags) == ktFlags; + if(hasKt && !hadKt) + sim->destroySqBounds(); + else if(hadKt && !hasKt) + sim->createSqBounds(); + } + } +} + +void Sc::BodyCore::setMaxContactImpulse(PxReal m) +{ + mCore.maxContactImpulse = m; + BodySim* sim = getSim(); + if (sim) + { + //maxContactImpulse changed, need to trigger dma pxgbodysim data again + Sc::Scene& scene = sim->getScene(); + scene.getSimulationController()->addDynamic(&sim->getLowLevelBody(), sim->getNodeIndex().index()); + } +} + +void Sc::BodyCore::setWakeCounter(PxReal wakeCounter, bool forceWakeUp) +{ + mCore.wakeCounter = wakeCounter; + BodySim* sim = getSim(); + if(sim) + { + //wake counter change, we need to trigger dma pxgbodysim data again + Sc::Scene& scene = sim->getScene(); + scene.getSimulationController()->addDynamic(&sim->getLowLevelBody(), sim->getNodeIndex().index()); + if ((wakeCounter > 0.0f) || forceWakeUp) + sim->wakeUp(); + sim->postSetWakeCounter(wakeCounter, forceWakeUp); + } +} + +void Sc::BodyCore::setSleepThreshold(PxReal t) +{ + mCore.sleepThreshold = t; + BodySim* sim = getSim(); + if(sim) + { + //update bodysim + Sc::Scene& scene = sim->getScene(); + scene.getSimulationController()->addDynamic(&sim->getLowLevelBody(), sim->getNodeIndex().index()); + } +} + +void Sc::BodyCore::setFreezeThreshold(PxReal t) +{ + mCore.freezeThreshold = t; + BodySim* sim = getSim(); + if(sim) + { + //update bodysim + Sc::Scene& scene = sim->getScene(); + scene.getSimulationController()->addDynamic(&sim->getLowLevelBody(), sim->getNodeIndex().index()); + } +} + +bool Sc::BodyCore::isSleeping() const +{ + BodySim* sim = getSim(); + return sim ? !sim->isActive() : true; +} + +void Sc::BodyCore::putToSleep() +{ + mCore.linearVelocity = PxVec3(0.f); + mCore.angularVelocity = PxVec3(0.0f); + + //The dirty flag is stored separately in the BodySim so that we query the dirty flag before going to + //the expense of querying the simStateData for the velmod values. + BodySim* sim = getSim(); + if (sim) + { + sim->notifyClearSpatialAcceleration(); + sim->notifyClearSpatialVelocity(); + } + + //The velmod data is stored in a separate structure so we can record forces before scene insertion. + if(mSimStateData && mSimStateData->isVelMod()) + { + VelocityMod* velmod = mSimStateData->getVelocityModData(); + velmod->clear(); + } + + // important to clear all values before setting the wake counter because the values decide + // whether an object is ready to go to sleep or not. + setWakeCounter(0.0f); + + if (sim) + sim->putToSleep(); +} + +void Sc::BodyCore::setKinematicTarget(Ps::Pool<SimStateData>* simStateDataPool, const PxTransform& p, PxReal wakeCounter) +{ + PX_ASSERT(mCore.mFlags & PxRigidBodyFlag::eKINEMATIC); + PX_ASSERT(!mSimStateData || mSimStateData->isKine()); + + if(mSimStateData) + { + Kinematic* kine = mSimStateData->getKinematicData(); + kine->targetPose = p; + kine->targetValid = 1; + + Sc::BodySim* bSim = getSim(); + if (bSim) + bSim->postSetKinematicTarget(); + } + else + { + bool success = setupSimStateData(simStateDataPool, true, true); + if (success) + { + PX_ASSERT(!getSim()); // covers the following scenario: kinematic gets added to scene while sim is running and target gets set (at that point the sim object does not yet exist) + + Kinematic* kine = mSimStateData->getKinematicData(); + kine->targetPose = p; + kine->targetValid = 1; + } + else + Ps::getFoundation().error(PxErrorCode::eOUT_OF_MEMORY, __FILE__, __LINE__, "PxRigidDynamic: setting kinematic target failed, not enough memory."); + } + + wakeUp(wakeCounter); +} + +void Sc::BodyCore::disableInternalCaching(bool disable) +{ + PX_ASSERT(!mSimStateData || mSimStateData->isKine()); + + if(mSimStateData) + { + PX_ASSERT(getFlags() & PxRigidBodyFlag::eKINEMATIC); + + if(disable) + restore(); + else + backup(*mSimStateData); + } +} + +bool Sc::BodyCore::setupSimStateData(Ps::Pool<SimStateData>* simStateDataPool, const bool isKinematic, const bool targetValid) +{ + SimStateData* data = mSimStateData; + if(!data) + { + data = simStateDataPool->construct(); + if(!data) + return false; + } + + if(isKinematic) + { + PX_ASSERT(!mSimStateData || !mSimStateData->isKine()); + + new(data) SimStateData(SimStateData::eKine); + Kinematic* kine = data->getKinematicData(); + kine->targetValid = PxU8(targetValid ? 1 : 0); + backup(*data); + } + else + { + PX_ASSERT(!mSimStateData || !mSimStateData->isVelMod()); + PX_ASSERT(!targetValid); + + new(data) SimStateData(SimStateData::eVelMod); + VelocityMod* velmod = data->getVelocityModData(); + velmod->clear(); + velmod->flags = 0; + } + mSimStateData = data; + return true; +} + +bool Sc::BodyCore::checkSimStateKinematicStatus(const bool isKinematic) const +{ + PX_ASSERT(mSimStateData); + return mSimStateData->isKine() == isKinematic; +} + +void Sc::BodyCore::tearDownSimStateData(Ps::Pool<SimStateData>* simStateDataPool, const bool isKinematic) +{ + PX_ASSERT(!mSimStateData || mSimStateData->isKine() == isKinematic); + + if (mSimStateData) + { + if(isKinematic) + { + restore(); + } + simStateDataPool->destroy(mSimStateData); + mSimStateData=NULL; + } +} + +void Sc::BodyCore::backup(SimStateData& b) +{ + PX_ASSERT(b.isKine()); + + Kinematic* kine = b.getKinematicData(); + kine->backupLinearDamping = mCore.linearDamping; + kine->backupAngularDamping = mCore.angularDamping; + kine->backupInverseInertia = mCore.inverseInertia; + kine->backupInvMass = mCore.inverseMass; + kine->backupMaxAngVelSq = mCore.maxAngularVelocitySq; + kine->backupMaxLinVelSq = mCore.maxLinearVelocitySq; + + mCore.inverseMass = 0.0f; + mCore.inverseInertia = PxVec3(0.0f); + mCore.linearDamping = 0.0f; + mCore.angularDamping = 0.0f; + mCore.maxAngularVelocitySq = PX_MAX_REAL; + mCore.maxLinearVelocitySq = PX_MAX_REAL; +} + +void Sc::BodyCore::restore() +{ + PX_ASSERT(mSimStateData && mSimStateData->isKine()); + + const Kinematic* kine = mSimStateData->getKinematicData(); + mCore.inverseMass = kine->backupInvMass; + mCore.inverseInertia = kine->backupInverseInertia; + mCore.linearDamping = kine->backupLinearDamping; + mCore.angularDamping = kine->backupAngularDamping; + mCore.maxAngularVelocitySq = kine->backupMaxAngVelSq; + mCore.maxLinearVelocitySq = kine->backupMaxLinVelSq; +} + +void Sc::BodyCore::invalidateKinematicTarget() +{ + PX_ASSERT(mSimStateData && mSimStateData->isKine()); + mSimStateData->getKinematicData()->targetValid = 0; +} + +void Sc::BodyCore::onOriginShift(const PxVec3& shift) +{ + mCore.body2World.p -= shift; + if (mSimStateData && (getFlags() & PxRigidBodyFlag::eKINEMATIC) && mSimStateData->getKinematicData()->targetValid) + { + mSimStateData->getKinematicData()->targetPose.p -= shift; + } + + BodySim* b = getSim(); + if (b) + b->onOriginShift(shift); // BodySim might not exist if actor has simulation disabled (PxActorFlag::eDISABLE_SIMULATION) +} + +// PT: TODO: isn't that the same as BodyCore->getPxActor() now? +PxActor* Sc::getPxActorFromBodyCore(Sc::BodyCore* r, PxActorType::Enum& type) +{ + const PxActorType::Enum actorCoretype = r->getActorCoreType(); + type = actorCoretype; + return Ps::pointerOffset<PxActor*>(r, Sc::gOffsetTable.scCore2PxActor[actorCoretype]); +} + +Ps::IntBool Sc::BodyCore::isFrozen() const +{ + return getSim()->isFrozen(); +} + +void Sc::BodyCore::setFrozen() +{ + getSim()->setFrozen(); +} + +void Sc::BodyCore::clearFrozen() +{ + getSim()->clearFrozen(); +} + +void Sc::BodyCore::setSolverIterationCounts(PxU16 c) +{ + mCore.solverIterationCounts = c; + if (getSim()) + getSim()->getLowLevelBody().solverIterationCounts = c; +} diff --git a/PhysX_3.4/Source/SimulationController/src/ScBodyCoreKinematic.cpp b/PhysX_3.4/Source/SimulationController/src/ScBodyCoreKinematic.cpp new file mode 100644 index 00000000..7f0eb091 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScBodyCoreKinematic.cpp @@ -0,0 +1,59 @@ +// 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 "ScBodyCore.h" +#include "ScSimStateData.h" + +using namespace physx; + +bool Sc::BodyCore::getKinematicTarget(PxTransform& p) const +{ + PX_ASSERT(mCore.mFlags & PxRigidBodyFlag::eKINEMATIC); + + if (mSimStateData && mSimStateData->isKine() && mSimStateData->getKinematicData()->targetValid) + { + p = mSimStateData->getKinematicData()->targetPose; + return true; + } + else + return false; +} + +bool Sc::BodyCore::getHasValidKinematicTarget() const +{ + //The use pattern for this is that we should only look for kinematic data if we know it is kinematic. + //We might look for velmod data even if it is kinematic. + PX_ASSERT(!mSimStateData || mSimStateData->isKine()); + return + ( + mSimStateData && + mSimStateData->isKine() && + mSimStateData->getKinematicData()->targetValid + ); +} diff --git a/PhysX_3.4/Source/SimulationController/src/ScBodySim.cpp b/PhysX_3.4/Source/SimulationController/src/ScBodySim.cpp new file mode 100644 index 00000000..b133f65d --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScBodySim.cpp @@ -0,0 +1,1011 @@ +// 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 "ScBodySim.h" +#include "ScScene.h" +#include "ScConstraintSim.h" +#include "ScConstraintInteraction.h" +#include "ScArticulationSim.h" +#include "PxsContext.h" +#include "PxsRigidBody.h" +#include "ScShapeIterator.h" +#include "ScShapeSim.h" +#include "ScConstraintCore.h" +#include "ScPhysics.h" +#include "DyArticulation.h" +#include "PxsSimpleIslandManager.h" +#include "PxsSimulationController.h" + +#if PX_USE_PARTICLE_SYSTEM_API +#include "PtContext.h" +#endif + +using namespace physx; +using namespace physx::Dy; + +#define PX_FREEZE_INTERVAL 1.5f +#define PX_FREE_EXIT_THRESHOLD 4.f +#define PX_FREEZE_TOLERANCE 0.25f + +#define PX_SLEEP_DAMPING 0.5f +#define PX_FREEZE_SCALE 0.9f + +Sc::BodySim::BodySim(Scene& scene, BodyCore& core) : + RigidSim (scene, core), + mLLBody (&core.getCore()), + mNodeIndex (IG_INVALID_NODE), + mInternalFlags (0), + mVelModState (VMF_GRAVITY_DIRTY), + mActiveListIndex (SC_NOT_IN_SCENE_INDEX), + mArticulation (NULL), + mConstraintGroup (NULL) + { + + // For 32-bit, sizeof(BodyCore) = 160 bytes, sizeof(BodySim) = 192 bytes + mLLBody.sleepLinVelAcc = PxVec3(0); + mLLBody.sleepAngVelAcc = PxVec3(0); + mLLBody.freezeCount = PX_FREEZE_INTERVAL; + mLLBody.accelScale = 1.f; + mLLBody.solverIterationCounts = core.getCore().solverIterationCounts; + core.getCore().numCountedInteractions = 0; + core.getCore().numBodyInteractions = 0; + mLLBody.mInternalFlags = 0; + if (core.getActorFlags()&PxActorFlag::eDISABLE_GRAVITY) + mLLBody.mInternalFlags |= PxsRigidBody::eDISABLE_GRAVITY; + if (core.getFlags() & PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD) + mLLBody.mInternalFlags |= PxsRigidBody::eSPECULATIVE_CCD; + + //If a body pending insertion was given a force/torque then it will have + //the dirty flags stored in a separate structure. Copy them across + //so we can use them now that the BodySim is constructed. + SimStateData* simStateData = core.getSimStateData(false); + bool hasPendingForce = false; + if(simStateData) + { + VelocityMod* velmod = simStateData->getVelocityModData(); + hasPendingForce = (velmod->flags != 0) && + (!velmod->getLinearVelModPerSec().isZero() || !velmod->getAngularVelModPerSec().isZero() || + !velmod->getLinearVelModPerStep().isZero() || !velmod->getAngularVelModPerStep().isZero()); + mVelModState = velmod->flags; + velmod->flags = 0; + } + + // PT: don't read the core ptr we just wrote, use input param + // PT: at time of writing we get a big L2 here because even though bodycore has been prefetched, the wake counter is 160 bytes away + const bool isAwake = (core.getWakeCounter() > 0) || + (!core.getLinearVelocity().isZero()) || + (!core.getAngularVelocity().isZero()) || + hasPendingForce; + + const bool isKine = isKinematic(); + + IG::SimpleIslandManager* simpleIslandManager = scene.getSimpleIslandManager(); + if (!isArticulationLink()) + { + mNodeIndex = simpleIslandManager->addRigidBody(&mLLBody, isKine, isAwake); + } + else + { + if(mArticulation) + { + const ArticulationLinkHandle articLinkhandle = mArticulation->getLinkHandle(*this); + IG::NodeIndex index = mArticulation->getIslandNodeIndex(); + mNodeIndex.setIndices(index.index(), articLinkhandle & (DY_ARTICULATION_MAX_SIZE-1)); + } + } + + PX_ASSERT(mActiveListIndex == SC_NOT_IN_SCENE_INDEX); + + setActive(isAwake, ActorSim::AS_PART_OF_CREATION); + + if (isAwake) + { + scene.addToActiveBodyList(*this); + PX_ASSERT(isActive()); + } + else + { + mActiveListIndex = SC_NOT_IN_ACTIVE_LIST_INDEX; + PX_ASSERT(!isActive()); + + simpleIslandManager->deactivateNode(mNodeIndex); + } + + if (isKine) + { + initKinematicStateBase(core, true); + + const SimStateData* kd = core.getSimStateData(true); + if (!kd) + { + core.setupSimStateData(scene.getSimStateDataPool(), true, false); + notifyPutToSleep(); // sleep state of kinematics is fully controlled by the simulation controller not the island manager + } + else + { + PX_ASSERT(kd->isKine()); + PX_ASSERT(kd->getKinematicData()->targetValid); // the only reason for the kinematic data to exist at that point already is if the target has been set + PX_ASSERT(isAwake); // the expectation is that setting a target also sets the wake counter to a positive value + postSetKinematicTarget(); + } + } +} + + +Sc::BodySim::~BodySim() +{ + Sc::Scene &scene = getScene(); + const bool active = isActive(); + + getBodyCore().tearDownSimStateData(scene.getSimStateDataPool(), isKinematic() ? true : false); + + PX_ASSERT(!readInternalFlag(BF_ON_DEATHROW)); // Before 3.0 it could happen that destroy could get called twice. Assert to make sure this is fixed. + raiseInternalFlag(BF_ON_DEATHROW); + + scene.removeBody(*this); + PX_ASSERT(!getConstraintGroup()); // Removing from scene should erase constraint group node if it existed + + if(mArticulation) + mArticulation->removeBody(*this); + + //Articulations are represented by a single node, so they must only be removed by the articulation and not the links! + if(mArticulation == NULL && mNodeIndex.articulationLinkId() == 0) //If it wasn't an articulation link, then we can remove it + scene.getSimpleIslandManager()->removeNode(mNodeIndex); + +#if PX_USE_PARTICLE_SYSTEM_API + PX_ASSERT(!scene.getParticleContext() || !scene.getParticleContext()->getBodyTransformVaultFast().isInVault(mLLBody.getCore())); +#endif + + PX_ASSERT(mActiveListIndex != SC_NOT_IN_SCENE_INDEX); + + if (active) + scene.removeFromActiveBodyList(*this); + + mActiveListIndex = SC_NOT_IN_SCENE_INDEX; + + mCore.setSim(NULL); +} + + +//-------------------------------------------------------------- +// +// Actor implementation +// +//-------------------------------------------------------------- + + +void Sc::BodySim::onActivate() +{ + PX_ASSERT((!isKinematic()) || notInScene() || readInternalFlag(BF_KINEMATIC_MOVED)); // kinematics should only get activated when a target is set. + // exception: object gets newly added, then the state change will happen later + + BodyCore& core = getBodyCore(); + if (!isArticulationLink()) + { + mLLBody.mInternalFlags &= (~PxsRigidBody::eFROZEN); + // Put in list of activated bodies. The list gets cleared at the end of a sim step after the sleep callbacks have been fired. + getScene().onBodyWakeUp(this); + } + + if (core.getFlags() & PxRigidBodyFlag::eENABLE_POSE_INTEGRATION_PREVIEW) + { + PX_ASSERT(!getScene().isInPosePreviewList(*this)); + getScene().addToPosePreviewList(*this); + } + createSqBounds(); +} + +void Sc::BodySim::updateCached(Cm::BitMapPinned* shapeChangedMap) +{ + if(!(mLLBody.mInternalFlags & PxsRigidBody::eFROZEN)) + { + Sc::ShapeSim* sim; + for(Sc::ShapeIterator iterator(*this); (sim = iterator.getNext())!=NULL;) + sim->updateCached(0, shapeChangedMap); + + } +} + +void Sc::BodySim::updateCached(PxsTransformCache& transformCache, Bp::BoundsArray& boundsArray) +{ + PX_ASSERT(!(mLLBody.mInternalFlags & PxsRigidBody::eFROZEN)); // PT: should not be called otherwise + + Sc::ShapeSim* sim; + for(Sc::ShapeIterator iterator(*this); (sim = iterator.getNext())!=NULL;) + sim->updateCached(transformCache, boundsArray); +} + +void Sc::BodySim::updateContactDistance(PxReal* contactDistance, const PxReal dt, Bp::BoundsArray& boundsArray) +{ + if (getLowLevelBody().getCore().mFlags & PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD + && !(getLowLevelBody().mInternalFlags & PxcRigidBody::eFROZEN)) + { + Sc::ShapeSim* sim; + + const PxVec3 linVel = getLowLevelBody().getLinearVelocity(); + const PxVec3 aVel = getLowLevelBody().getAngularVelocity(); + const PxReal inflation = linVel.magnitude() * dt; + + for (Sc::ShapeIterator iterator(*this); (sim = iterator.getNext()) != NULL;) + sim->updateContactDistance(contactDistance, inflation, aVel, dt, boundsArray); + } +} + + +void Sc::BodySim::onDeactivate() +{ + PX_ASSERT((!isKinematic()) || notInScene() || !readInternalFlag(BF_KINEMATIC_MOVED)); // kinematics should only get deactivated when no target is set. + // exception: object gets newly added, then the state change will happen later + BodyCore& core = getBodyCore(); + if (!readInternalFlag(BF_ON_DEATHROW)) + { + // Set velocity to 0. + // Note: this is also fine if the method gets called because the user puts something to sleep (this behavior is documented in the API) + PX_ASSERT(core.getWakeCounter() == 0.0f); + const PxVec3 zero(0.f, 0.f, 0.f); + core.setLinearVelocityInternal(zero); + core.setAngularVelocityInternal(zero); + + setForcesToDefaults(!(mLLBody.mInternalFlags & PxsRigidBody::eDISABLE_GRAVITY)); + } + + if (!isArticulationLink()) // Articulations have their own sleep logic. + getScene().onBodySleep(this); + + if (core.getFlags() & PxRigidBodyFlag::eENABLE_POSE_INTEGRATION_PREVIEW) + { + PX_ASSERT(getScene().isInPosePreviewList(*this)); + getScene().removeFromPosePreviewList(*this); + } + destroySqBounds(); + +} + + +//-------------------------------------------------------------- +// +// BodyCore interface implementation +// +//-------------------------------------------------------------- + + +void Sc::BodySim::notifyAddSpatialAcceleration() +{ + //The dirty flag is stored separately in the BodySim so that we query the dirty flag before going to + //the expense of querying the simStateData for the velmod values. + raiseVelocityModFlag(VMF_ACC_DIRTY); + + getScene().getVelocityModifyMap().growAndSet(getNodeIndex().index()); +} + +void Sc::BodySim::notifyClearSpatialAcceleration() +{ + //The dirty flag is stored separately in the BodySim so that we query the dirty flag before going to + //the expense of querying the simStateData for the velmod values. + raiseVelocityModFlag(VMF_ACC_DIRTY); + getScene().getVelocityModifyMap().growAndSet(getNodeIndex().index()); +} + + +void Sc::BodySim::notifyAddSpatialVelocity() +{ + //The dirty flag is stored separately in the BodySim so that we query the dirty flag before going to + //the expense of querying the simStateData for the velmod values. + raiseVelocityModFlag(VMF_VEL_DIRTY); + getScene().getVelocityModifyMap().growAndSet(getNodeIndex().index()); +} + +void Sc::BodySim::notifyClearSpatialVelocity() +{ + //The dirty flag is stored separately in the BodySim so that we query the dirty flag before going to + //the expense of querying the simStateData for the velmod values. + raiseVelocityModFlag(VMF_VEL_DIRTY); + getScene().getVelocityModifyMap().growAndSet(getNodeIndex().index()); +} + + +void Sc::BodySim::postActorFlagChange(PxU32 oldFlags, PxU32 newFlags) +{ + // PT: don't convert to bool if not needed + const PxU32 wasWeightless = oldFlags & PxActorFlag::eDISABLE_GRAVITY; + const PxU32 isWeightless = newFlags & PxActorFlag::eDISABLE_GRAVITY; + + if (isWeightless != wasWeightless) + { + if (mVelModState == 0) raiseVelocityModFlag(VMF_GRAVITY_DIRTY); + + if (isWeightless) + mLLBody.mInternalFlags |= PxsRigidBody::eDISABLE_GRAVITY; + else + mLLBody.mInternalFlags &= (~PxsRigidBody::eDISABLE_GRAVITY); + } +} + + +void Sc::BodySim::postBody2WorldChange() +{ + mLLBody.saveLastCCDTransform(); + +#if PX_USE_PARTICLE_SYSTEM_API + if (getScene().getParticleContext()->getBodyTransformVaultFast().isInVault(*mLLBody.mCore)) + getScene().getParticleContext()->getBodyTransformVaultFast().teleportBody(*mLLBody.mCore); +#endif + + notifyShapesOfTransformChange(); +} + + +void Sc::BodySim::postSetWakeCounter(PxReal t, bool forceWakeUp) +{ + if ((t > 0.0f) || forceWakeUp) + notifyNotReadyForSleeping(); + else + { + const bool readyForSleep = checkSleepReadinessBesidesWakeCounter(); + if (readyForSleep) + notifyReadyForSleeping(); + } +} + + +void Sc::BodySim::postSetKinematicTarget() +{ + PX_ASSERT(getBodyCore().getSimStateData(true)); + PX_ASSERT(getBodyCore().getSimStateData(true)->isKine()); + PX_ASSERT(getBodyCore().getSimStateData(true)->getKinematicData()->targetValid); + + raiseInternalFlag(BF_KINEMATIC_MOVED); // Important to set this here already because trigger interactions need to have this information when being activated. +} + + +void Sc::BodySim::postSwitchToKinematic() +{ + initKinematicStateBase(getBodyCore(), false); + + // - interactions need to get refiltered to make sure that kinematic-kinematic and kinematic-static pairs get suppressed + // - unlike postSwitchToDynamic(), constraint interactions are not marked dirty here because a transition to kinematic will put the object asleep which in turn + // triggers onDeactivate() on the constraint pairs that are active. If such pairs get deactivated, they will get removed from the list of active breakable + // constraints automatically. + setActorsInteractionsDirty(InteractionDirtyFlag::eBODY_KINEMATIC, NULL, InteractionFlag::eFILTERABLE); + + getScene().getSimpleIslandManager()->setKinematic(mNodeIndex); +} + + +void Sc::BodySim::postSwitchToDynamic() +{ + mScene.getSimpleIslandManager()->setDynamic(mNodeIndex); + + setForcesToDefaults(true); + + if (getConstraintGroup()) + getConstraintGroup()->markForProjectionTreeRebuild(mScene.getProjectionManager()); + + // - interactions need to get refiltered to make sure that former kinematic-kinematic and kinematic-static pairs get enabled + // - switching from kinematic to dynamic does not change the sleep state of the body. The constraint interactions are marked dirty + // to check later whether they need to be activated plus potentially tracked for constraint break testing. This special treatment + // is necessary because constraints between two kinematic bodies are considered inactive, no matter whether one of the kinematics + // is active (has a target) or not. + setActorsInteractionsDirty(InteractionDirtyFlag::eBODY_KINEMATIC, NULL, InteractionFlag::eFILTERABLE | InteractionFlag::eCONSTRAINT); + + clearInternalFlag(BF_KINEMATIC_MOVE_FLAGS); + + if (isActive()) + mScene.swapInActiveBodyList(*this); +} + + +void Sc::BodySim::postPosePreviewChange(const PxU32 posePreviewFlag) +{ + if (isActive()) + { + if (posePreviewFlag & PxRigidBodyFlag::eENABLE_POSE_INTEGRATION_PREVIEW) + getScene().addToPosePreviewList(*this); + else + getScene().removeFromPosePreviewList(*this); + } + else + PX_ASSERT(!getScene().isInPosePreviewList(*this)); +} + + +//-------------------------------------------------------------- +// +// Sleeping +// +//-------------------------------------------------------------- + + +void Sc::BodySim::setActive(bool active, PxU32 infoFlag) +{ + PX_ASSERT(!active || isDynamicRigid()); // Currently there should be no need to activate an actor that does not take part in island generation + + const PxU32 asPartOfCreation = infoFlag & ActorSim::AS_PART_OF_CREATION; + if (asPartOfCreation || isActive() != active) + { + PX_ASSERT(!asPartOfCreation || (getActorInteractionCount() == 0)); // On creation or destruction there should be no interactions + + if (active) + { + if (!asPartOfCreation) + { + // Inactive => Active + getScene().addToActiveBodyList(*this); + } + + onActivate(); + + activateInteractions(infoFlag); + + PX_ASSERT(asPartOfCreation || isActive()); + } + else + { + if (!asPartOfCreation) + { + // Active => Inactive + getScene().removeFromActiveBodyList(*this); + } + + deactivateInteractions(infoFlag); + + onDeactivate(); + + PX_ASSERT(asPartOfCreation || (!isActive())); + } + } +} + + +void Sc::BodySim::activateInteractions(PxU32 /*infoFlag*/) +{ + const PxU32 nbInteractions = getActorInteractionCount(); + + for(PxU32 i=0; i<nbInteractions; ++i) + { + Ps::prefetchLine(mInteractions[PxMin(i+1,nbInteractions-1)]); + Interaction* interaction = mInteractions[i]; + + bool isNotIGControlled = interaction->getType() != Sc::InteractionType::eCONSTRAINTSHADER && interaction->getType() != Sc::InteractionType::eOVERLAP && + interaction->getType() != Sc::InteractionType::eMARKER; + + if (!interaction->readInteractionFlag(InteractionFlag::eIS_ACTIVE) && isNotIGControlled) + { + const bool proceed = interaction->onActivate(NULL); + if (proceed && (interaction->getType() < InteractionType::eTRACKED_IN_SCENE_COUNT)) + getScene().notifyInteractionActivated(interaction); + } + } +} + + +void Sc::BodySim::deactivateInteractions(PxU32 infoFlag) +{ + const PxU32 nbInteractions = getActorInteractionCount(); + + for(PxU32 i=0; i<nbInteractions; ++i) + { + Ps::prefetchLine(mInteractions[PxMin(i+1,nbInteractions-1)]); + Interaction* interaction = mInteractions[i]; + + bool isNotIGControlled = interaction->getType() != Sc::InteractionType::eCONSTRAINTSHADER && interaction->getType() != Sc::InteractionType::eOVERLAP && + interaction->getType() != Sc::InteractionType::eMARKER; + + if (interaction->readInteractionFlag(InteractionFlag::eIS_ACTIVE) && isNotIGControlled) + { + const bool proceed = interaction->onDeactivate(infoFlag); + if (proceed && (interaction->getType() < InteractionType::eTRACKED_IN_SCENE_COUNT)) + getScene().notifyInteractionDeactivated(interaction); + } + } +} + + +void Sc::BodySim::wakeUp() +{ + setActive(true); + notifyWakeUp(true); +} + + +void Sc::BodySim::putToSleep() +{ + PX_ASSERT(getBodyCore().getWakeCounter() == 0.0f); + PX_ASSERT(getBodyCore().getLinearVelocity().isZero()); + PX_ASSERT(getBodyCore().getAngularVelocity().isZero()); +#ifdef _DEBUG + // pending forces should have been cleared at this point + const SimStateData* sd = getBodyCore().getSimStateData(false); + if (sd) + { + const VelocityMod* vm = sd->getVelocityModData(); + PX_ASSERT(vm->linearPerSec.isZero() && vm->linearPerStep.isZero() && vm->angularPerSec.isZero() && vm->angularPerStep.isZero()); + } +#endif + + setActive(false); + notifyPutToSleep(); + + clearInternalFlag(InternalFlags(BF_KINEMATIC_SETTLING | BF_KINEMATIC_SETTLING_2)); // putToSleep is used when a kinematic gets removed from the scene while the sim is running and then gets re-inserted immediately. + // We can move this code when we look into the open task of making buffered re-insertion more consistent with the non-buffered case. +} + + +void Sc::BodySim::internalWakeUp(PxReal wakeCounterValue) +{ + if(mArticulation) + mArticulation->internalWakeUp(wakeCounterValue); + else + internalWakeUpBase(wakeCounterValue); +} + + +void Sc::BodySim::internalWakeUpArticulationLink(PxReal wakeCounterValue) +{ + PX_ASSERT(mArticulation); + internalWakeUpBase(wakeCounterValue); +} + + +void Sc::BodySim::internalWakeUpBase(PxReal wakeCounterValue) //this one can only increase the wake counter, not decrease it, so it can't be used to put things to sleep! +{ + if ((!isKinematic()) && (getBodyCore().getWakeCounter() < wakeCounterValue)) + { + PX_ASSERT(wakeCounterValue > 0.0f); + getBodyCore().setWakeCounterFromSim(wakeCounterValue); + + //we need to update the gpu body sim because we reset the wake counter for the body core + mScene.getSimulationController()->addDynamic(&mLLBody, mNodeIndex.index()); + setActive(true); + notifyWakeUp(false); + mLLBody.mInternalFlags &= (~PxsRigidBody::eFROZEN); + } +} + + +void Sc::BodySim::notifyReadyForSleeping() +{ + if(mArticulation == NULL) + getScene().getSimpleIslandManager()->deactivateNode(mNodeIndex); +} + + +void Sc::BodySim::notifyNotReadyForSleeping() +{ + getScene().getSimpleIslandManager()->activateNode(mNodeIndex); +} + + +void Sc::BodySim::notifyWakeUp(bool /*wakeUpInIslandGen*/) +{ + getScene().getSimpleIslandManager()->activateNode(mNodeIndex); +} + + +void Sc::BodySim::notifyPutToSleep() +{ + getScene().getSimpleIslandManager()->putNodeToSleep(mNodeIndex); +} + +void Sc::BodySim::resetSleepFilter() +{ + mLLBody.sleepAngVelAcc = PxVec3(0.0f); + mLLBody.sleepLinVelAcc = PxVec3(0.0f); +} + +//This function will be called by CPU sleepCheck code +PxReal Sc::BodySim::updateWakeCounter(PxReal dt, PxReal energyThreshold, const Cm::SpatialVector& motionVelocity) +{ + // update the body's sleep state and + BodyCore& core = getBodyCore(); + + const PxReal wakeCounterResetTime = ScInternalWakeCounterResetValue; + + PxReal wc = core.getWakeCounter(); + + { + + PxVec3 bcSleepLinVelAcc = mLLBody.sleepLinVelAcc; + PxVec3 bcSleepAngVelAcc = mLLBody.sleepAngVelAcc; + + if(wc < wakeCounterResetTime * 0.5f || wc < dt) + { + const PxTransform& body2World = getBody2World(); + + // calculate normalized energy: kinetic energy divided by mass + const PxVec3 t = core.getInverseInertia(); + const PxVec3 inertia(t.x > 0.f ? 1.0f/t.x : 1.f, t.y > 0.f ? 1.0f/t.y : 1.f, t.z > 0.f ? 1.0f/t.z : 1.f); + + PxVec3 sleepLinVelAcc =motionVelocity.linear; + PxVec3 sleepAngVelAcc = body2World.q.rotateInv(motionVelocity.angular); + + + bcSleepLinVelAcc += sleepLinVelAcc; + bcSleepAngVelAcc += sleepAngVelAcc; + + PxReal invMass = core.getInverseMass(); + if(invMass == 0.f) + invMass = 1.f; + + const PxReal angular = bcSleepAngVelAcc.multiply(bcSleepAngVelAcc).dot(inertia) * invMass; + const PxReal linear = bcSleepLinVelAcc.magnitudeSquared(); + PxReal normalizedEnergy = 0.5f * (angular + linear); + + // scale threshold by cluster factor (more contacts => higher sleep threshold) + const PxReal clusterFactor = PxReal(1 + getNumCountedInteractions()); + const PxReal threshold = clusterFactor*energyThreshold; + + if (normalizedEnergy >= threshold) + { + PX_ASSERT(isActive()); + resetSleepFilter(); + const float factor = threshold == 0.f ? 2.0f : PxMin(normalizedEnergy/threshold, 2.0f); + PxReal oldWc = wc; + wc = factor * 0.5f * wakeCounterResetTime + dt * (clusterFactor - 1.0f); + core.setWakeCounterFromSim(wc); + if (oldWc == 0.0f) // for the case where a sleeping body got activated by the system (not the user) AND got processed by the solver as well + notifyNotReadyForSleeping(); + + return wc; + } + } + + mLLBody.sleepLinVelAcc = bcSleepLinVelAcc; + mLLBody.sleepAngVelAcc = bcSleepAngVelAcc; + } + + wc = PxMax(wc-dt, 0.0f); + core.setWakeCounterFromSim(wc); + return wc; +} + + +//-------------------------------------------------------------- +// +// Kinematics +// +//-------------------------------------------------------------- + +PX_FORCE_INLINE void Sc::BodySim::initKinematicStateBase(BodyCore&, bool asPartOfCreation) +{ + PX_ASSERT(!readInternalFlag(BF_KINEMATIC_MOVED)); + + if (!asPartOfCreation && isActive()) + getScene().swapInActiveBodyList(*this); + + //mLLBody.setAccelerationV(Cm::SpatialVector::zero()); + + // Need to be before setting setRigidBodyFlag::KINEMATIC + + if (getConstraintGroup()) + getConstraintGroup()->markForProjectionTreeRebuild(getScene().getProjectionManager()); +} + + +void Sc::BodySim::calculateKinematicVelocity(PxReal oneOverDt) +{ + PX_ASSERT(isKinematic()); + + /*------------------------------------------------\ + | kinematic bodies are moved directly by the user and are not influenced by external forces + | we simply determine the distance moved since the last simulation frame and + | assign the appropriate delta to the velocity. This vel will be used to shove dynamic + | objects in the solver. + | We have to do this like so in a delayed way, because when the user sets the target pos the dt is not + | yet known. + \------------------------------------------------*/ + PX_ASSERT(isActive()); + + BodyCore& core = getBodyCore(); + + if (readInternalFlag(BF_KINEMATIC_MOVED)) + { + clearInternalFlag(InternalFlags(BF_KINEMATIC_SETTLING | BF_KINEMATIC_SETTLING_2)); + const SimStateData* kData = core.getSimStateData(true); + PX_ASSERT(kData); + PX_ASSERT(kData->isKine()); + PX_ASSERT(kData->getKinematicData()->targetValid); + PxVec3 linVelLL, angVelLL; + const PxTransform targetPose = kData->getKinematicData()->targetPose; + const PxTransform& currBody2World = getBody2World(); + + //the kinematic target pose is now the target of the body (CoM) and not the actor. + + PxVec3 deltaPos = targetPose.p; + deltaPos -= currBody2World.p; + linVelLL = deltaPos * oneOverDt; + + PxQuat q = targetPose.q * currBody2World.q.getConjugate(); + + if (q.w < 0) //shortest angle. + q = -q; + + PxReal angle; + PxVec3 axis; + q.toRadiansAndUnitAxis(angle, axis); + angVelLL = axis * angle * oneOverDt; + + core.setLinearVelocity(linVelLL); + core.setAngularVelocity(angVelLL); + + // Moving a kinematic should trigger a wakeUp call on a higher level. + PX_ASSERT(core.getWakeCounter()>0); + PX_ASSERT(isActive()); + + } + else + { + core.setLinearVelocity(PxVec3(0)); + core.setAngularVelocity(PxVec3(0)); + } +} + +void Sc::BodySim::updateKinematicPose() +{ + /*------------------------------------------------\ + | kinematic bodies are moved directly by the user and are not influenced by external forces + | we simply determine the distance moved since the last simulation frame and + | assign the appropriate delta to the velocity. This vel will be used to shove dynamic + | objects in the solver. + | We have to do this like so in a delayed way, because when the user sets the target pos the dt is not + | yet known. + \------------------------------------------------*/ + + PX_ASSERT(isKinematic()); + PX_ASSERT(isActive()); + + BodyCore& core = getBodyCore(); + + if (readInternalFlag(BF_KINEMATIC_MOVED)) + { + clearInternalFlag(InternalFlags(BF_KINEMATIC_SETTLING | BF_KINEMATIC_SETTLING_2)); + const SimStateData* kData = core.getSimStateData(true); + PX_ASSERT(kData); + PX_ASSERT(kData->isKine()); + PX_ASSERT(kData->getKinematicData()->targetValid); + + const PxTransform targetPose = kData->getKinematicData()->targetPose; + getBodyCore().getCore().body2World = targetPose; + } +} + + + +bool Sc::BodySim::deactivateKinematic() +{ + BodyCore& core = getBodyCore(); + if(readInternalFlag(BF_KINEMATIC_SETTLING_2)) + { + clearInternalFlag(BF_KINEMATIC_SETTLING_2); + core.setWakeCounterFromSim(0); // For sleeping objects the wake counter must be 0. This needs to hold for kinematics too. + notifyReadyForSleeping(); + notifyPutToSleep(); + setActive(false); + return true; + } + else if (readInternalFlag(BF_KINEMATIC_SETTLING)) + { + clearInternalFlag(BF_KINEMATIC_SETTLING); + raiseInternalFlag(BF_KINEMATIC_SETTLING_2); + } + else + { + clearInternalFlag(BF_KINEMATIC_MOVED); + raiseInternalFlag(BF_KINEMATIC_SETTLING); + } + return false; +} + + + +//-------------------------------------------------------------- +// +// Miscellaneous +// +//-------------------------------------------------------------- + + +void Sc::BodySim::updateForces(PxReal dt, PxsRigidBody** updatedBodySims, PxU32* updatedBodyNodeIndices, PxU32& index, Cm::SpatialVector* acceleration, bool simUsesAdaptiveForce) +{ + PxVec3 linAcc(0.0f), angAcc(0.0f); + + const bool accDirty = readVelocityModFlag(VMF_ACC_DIRTY); + const bool velDirty = readVelocityModFlag(VMF_VEL_DIRTY); + + BodyCore& bodyCore = getBodyCore(); + SimStateData* simStateData = NULL; + + //if we change the logic like this, which means we don't need to have two seperate variables in the pxgbodysim to represent linAcc and angAcc. However, this + //means angAcc will be always 0 + if( (accDirty || velDirty) && ((simStateData = bodyCore.getSimStateData(false)) != NULL) ) + { + VelocityMod* velmod = simStateData->getVelocityModData(); + + //we don't have support for articulation yet + if (updatedBodySims) + { + updatedBodySims[index] = &getLowLevelBody(); + updatedBodyNodeIndices[index++] = getNodeIndex().index(); + } + + if(velDirty) + { + getBodyCore().updateVelocities(velmod->getLinearVelModPerStep(), velmod->getAngularVelModPerStep()); + } + + if (accDirty) + { + linAcc = velmod->getLinearVelModPerSec(); + angAcc = velmod->getAngularVelModPerSec(); + + if (acceleration) + { + acceleration->linear = linAcc; + acceleration->angular = angAcc; + } + else + { + PxReal scale = dt; + if (simUsesAdaptiveForce) + { + if (getScene().getSimpleIslandManager()->getAccurateIslandSim().getIslandStaticTouchCount(mNodeIndex) != 0) + { + scale *= mLLBody.accelScale; + } + } + getBodyCore().updateVelocities(linAcc*scale, angAcc*scale); + } + } + } + + setForcesToDefaults(readVelocityModFlag(VMF_ACC_DIRTY)); +} + + + +bool Sc::BodySim::isConnectedTo(const ActorSim& other, bool& collisionDisabled) const +{ + const Sc::ActorSim* actorToMatch; + PxU32 size; + Interaction** interactions; + + if(getActorInteractionCount() <= other.getActorInteractionCount()) + { + size = getActorInteractionCount(); + interactions = getActorInteractions(); + actorToMatch = &other; + } + else + { + size = other.getActorInteractionCount(); + interactions = other.getActorInteractions(); + actorToMatch = this; + } + + while(size--) + { + Interaction* interaction = *interactions++; + if (interaction->getType() == InteractionType::eCONSTRAINTSHADER) + { + ConstraintInteraction* csi = static_cast<ConstraintInteraction*>(interaction); + if ((&csi->getActor0() == actorToMatch) || (&csi->getActor1() == actorToMatch)) + { + collisionDisabled = !((csi->getConstraint()->getCore().getFlags() & PxConstraintFlag::eCOLLISION_ENABLED)); + return true; + } + } + } + + collisionDisabled = false; + return false; +} + + +void Sc::BodySim::onConstraintDetach() +{ + PX_ASSERT(readInternalFlag(BF_HAS_CONSTRAINTS)); + + PxU32 size = getActorInteractionCount(); + Interaction** interactions = getActorInteractions(); + unregisterCountedInteraction(); + + while(size--) + { + const Interaction* interaction = *interactions++; + if(interaction->getType() == InteractionType::eCONSTRAINTSHADER) + return; + } + + clearInternalFlag(BF_HAS_CONSTRAINTS); // There are no other constraint interactions left +} + + +void Sc::BodySim::setArticulation(Sc::ArticulationSim* a, PxReal wakeCounter, bool asleep, PxU32 bodyIndex) +{ + mArticulation = a; + if(a) + { + IG::NodeIndex index = mArticulation->getIslandNodeIndex(); + mNodeIndex.setIndices(index.index(), bodyIndex); + getBodyCore().setWakeCounterFromSim(wakeCounter); + + if (!asleep) + { + setActive(true); + notifyWakeUp(false); + } + else + { + notifyReadyForSleeping(); + notifyPutToSleep(); + setActive(false); + } + } + else + { + mNodeIndex.setIndices(IG_INVALID_NODE, 1); + } +} + +void Sc::BodySim::createSqBounds() +{ + if(!isActive() || usingSqKinematicTarget()) + return; + + PX_ASSERT(!isFrozen()); + + Sc::ShapeSim* sim; + for(Sc::ShapeIterator iterator(*this); NULL != (sim = iterator.getNext());) + sim->createSqBounds(); +} + +void Sc::BodySim::destroySqBounds() +{ + Sc::ShapeSim* sim; + for(Sc::ShapeIterator iterator(*this); NULL != (sim = iterator.getNext());) + sim->destroySqBounds(); +} + +void Sc::BodySim::freezeTransforms(Cm::BitMapPinned* shapeChangedMap) +{ + Sc::ShapeSim* sim; + for(Sc::ShapeIterator iterator(*this); NULL != (sim = iterator.getNext());) + { + sim->updateCached(PxsTransformFlag::eFROZEN, shapeChangedMap); + sim->destroySqBounds(); + } +} + +void Sc::BodySim::postShapeChange(bool /*asPartOfActorTransformChange*/) +{ + // shape geometry or transform changes can cause connectivity changes and thus a second island gen pass is needed. + /*if (!asPartOfActorTransformChange) + internalNotifySecondIslandGenPassNeeded();*/ +} diff --git a/PhysX_3.4/Source/SimulationController/src/ScBodySim.h b/PhysX_3.4/Source/SimulationController/src/ScBodySim.h new file mode 100644 index 00000000..b69f5df1 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScBodySim.h @@ -0,0 +1,324 @@ +// 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_BODYSIM +#define PX_PHYSICS_SCP_BODYSIM + +#include "PsUtilities.h" +#include "PsIntrinsics.h" +#include "ScRigidSim.h" +#include "PxvDynamics.h" +#include "ScBodyCore.h" +#include "ScSimStateData.h" +#include "ScConstraintGroupNode.h" +#include "PxRigidDynamic.h" +#include "DyArticulation.h" +#include "PxsRigidBody.h" +#include "PxsSimpleIslandManager.h" + +namespace physx +{ + class PxsTransformCache; + class PxsSimulationController; +namespace Sc +{ + #define SC_NOT_IN_SCENE_INDEX 0xffffffff // the body is not in the scene yet + #define SC_NOT_IN_ACTIVE_LIST_INDEX 0xfffffffe // the body is in the scene but not in the active list + + class Scene; + class ConstraintSim; + class ArticulationSim; + + static const PxReal ScInternalWakeCounterResetValue = 20.0f*0.02f; + + class BodySim : public RigidSim + { + public: + enum InternalFlags + { + //BF_DISABLE_GRAVITY = 1 << 0, // Don't apply the scene's gravity + + BF_HAS_STATIC_TOUCH = 1 << 1, // Set when a body is part of an island with static contacts. Needed to be able to recalculate adaptive force if this changes + BF_KINEMATIC_MOVED = 1 << 2, // Set when the kinematic was moved + + BF_ON_DEATHROW = 1 << 3, // Set when the body is destroyed + + BF_IS_IN_SLEEP_LIST = 1 << 4, // Set when the body is added to the list of bodies which were put to sleep + BF_IS_IN_WAKEUP_LIST = 1 << 5, // Set when the body is added to the list of bodies which were woken up + BF_SLEEP_NOTIFY = 1 << 6, // A sleep notification should be sent for this body (and not a wakeup event, even if the body is part of the woken list as well) + BF_WAKEUP_NOTIFY = 1 << 7, // A wake up notification should be sent for this body (and not a sleep event, even if the body is part of the sleep list as well) + + BF_HAS_CONSTRAINTS = 1 << 8, // Set if the body has one or more constraints + BF_KINEMATIC_SETTLING = 1 << 9, // Set when the body was moved kinematically last frame + BF_KINEMATIC_SETTLING_2 = 1 << 10, + BF_KINEMATIC_MOVE_FLAGS = BF_KINEMATIC_MOVED | BF_KINEMATIC_SETTLING | BF_KINEMATIC_SETTLING_2 //Used to clear kinematic masks in 1 call + + // PT: WARNING: flags stored on 16-bits now. + }; + + public: + BodySim(Scene&, BodyCore&); + virtual ~BodySim(); + + void notifyAddSpatialAcceleration(); + void notifyClearSpatialAcceleration(); + void notifyAddSpatialVelocity(); + void notifyClearSpatialVelocity(); + void updateCached(Cm::BitMapPinned* shapeChangedMap); + void updateCached(PxsTransformCache& transformCache, Bp::BoundsArray& boundsArray); + void updateContactDistance(PxReal* contactDistance, const PxReal dt, Bp::BoundsArray& boundsArray); + + // hooks for actions in body core when it's attached to a sim object. Generally + // we get called after the attribute changed. + + virtual void postActorFlagChange(PxU32 oldFlags, PxU32 newFlags); + void postBody2WorldChange(); + void postSetWakeCounter(PxReal t, bool forceWakeUp); + void postSetKinematicTarget(); + void postSwitchToKinematic(); + void postSwitchToDynamic(); + void postPosePreviewChange(const PxU32 posePreviewFlag); // called when PxRigidBodyFlag::eENABLE_POSE_INTEGRATION_PREVIEW changes + + PX_FORCE_INLINE const PxTransform& getBody2World() const { return getBodyCore().getCore().body2World; } + PX_FORCE_INLINE const PxTransform& getBody2Actor() const { return getBodyCore().getCore().getBody2Actor(); } + PX_FORCE_INLINE const PxsRigidBody& getLowLevelBody() const { return mLLBody; } + PX_FORCE_INLINE PxsRigidBody& getLowLevelBody() { return mLLBody; } + void wakeUp(); // note: for user API call purposes only, i.e., use from BodyCore. For simulation internal purposes there is internalWakeUp(). + void putToSleep(); + + static PxU32 getRigidBodyOffset() { return PxU32(PX_OFFSET_OF_RT(BodySim, mLLBody));} + + //--------------------------------------------------------------------------------- + // Actor implementation + //--------------------------------------------------------------------------------- + protected: + virtual void onActivate(); + virtual void onDeactivate(); + + private: + //--------------------------------------------------------------------------------- + // Constraint projection + //--------------------------------------------------------------------------------- + public: + PX_FORCE_INLINE ConstraintGroupNode* getConstraintGroup() { return mConstraintGroup; } + PX_FORCE_INLINE void setConstraintGroup(ConstraintGroupNode* node) { mConstraintGroup = node; } + + //// A list of active projection trees in the scene might be better + //PX_FORCE_INLINE void projectPose() { PX_ASSERT(mConstraintGroup); ConstraintGroupNode::projectPose(*mConstraintGroup); } + + //--------------------------------------------------------------------------------- + // Kinematics + //--------------------------------------------------------------------------------- + public: + PX_FORCE_INLINE bool isKinematic() const { return getBodyCore().getFlags() & PxRigidBodyFlag::eKINEMATIC; } + PX_FORCE_INLINE bool isArticulationLink() const { return getActorType() == PxActorType::eARTICULATION_LINK; } + void calculateKinematicVelocity(PxReal oneOverDt); + void updateKinematicPose(); + bool deactivateKinematic(); + + private: + PX_FORCE_INLINE void initKinematicStateBase(BodyCore&, bool asPartOfCreation); + + //--------------------------------------------------------------------------------- + // Sleeping + //--------------------------------------------------------------------------------- + public: + PX_FORCE_INLINE bool isActive() const { return (mActiveListIndex < SC_NOT_IN_ACTIVE_LIST_INDEX); } + void setActive(bool active, PxU32 infoFlag=0); // see ActivityChangeInfoFlag + + void activateInteractions(PxU32 infoFlag); + void deactivateInteractions(PxU32 infoFlag); + + PX_FORCE_INLINE PxU32 getActiveListIndex() const { return mActiveListIndex; } // if the body is active, the index is smaller than SC_NOT_IN_ACTIVE_LIST_INDEX + PX_FORCE_INLINE void setActiveListIndex(PxU32 index) { mActiveListIndex = index; } + + void internalWakeUp(PxReal wakeCounterValue=ScInternalWakeCounterResetValue); + void internalWakeUpArticulationLink(PxReal wakeCounterValue); // called by ArticulationSim to wake up this link + + PxReal updateWakeCounter(PxReal dt, PxReal energyThreshold, const Cm::SpatialVector& motionVelocity); + + void resetSleepFilter(); + void notifyReadyForSleeping(); // inform the sleep island generation system that the body is ready for sleeping + void notifyNotReadyForSleeping(); // inform the sleep island generation system that the body is not ready for sleeping + PX_FORCE_INLINE bool checkSleepReadinessBesidesWakeCounter(); // for API triggered changes to test sleep readiness + + PX_FORCE_INLINE void registerCountedInteraction() { mLLBody.getCore().numCountedInteractions++; PX_ASSERT(mLLBody.getCore().numCountedInteractions); } + PX_FORCE_INLINE void unregisterCountedInteraction() { PX_ASSERT(mLLBody.getCore().numCountedInteractions); mLLBody.getCore().numCountedInteractions--;} + PX_FORCE_INLINE PxU32 getNumCountedInteractions() const { return mLLBody.getCore().numCountedInteractions; } + + PX_FORCE_INLINE Ps::IntBool isFrozen() const { return Ps::IntBool(mLLBody.mInternalFlags & PxsRigidBody::eFROZEN); } + PX_FORCE_INLINE void setFrozen() { mLLBody.mInternalFlags |= PxsRigidBody::eFROZEN; } + PX_FORCE_INLINE void clearFrozen() { mLLBody.mInternalFlags &= (~PxsRigidBody::eFROZEN); } + private: + PX_FORCE_INLINE void notifyWakeUp(bool wakeUpInIslandGen = false); // inform the sleep island generation system that the object got woken up + PX_FORCE_INLINE void notifyPutToSleep(); // inform the sleep island generation system that the object was put to sleep + PX_FORCE_INLINE void internalWakeUpBase(PxReal wakeCounterValue); + + //--------------------------------------------------------------------------------- + // External velocity changes + //--------------------------------------------------------------------------------- + public: + + void updateForces(PxReal dt, PxsRigidBody** updatedBodySims, PxU32* updatedBodyNodeIndices, + PxU32& index, Cm::SpatialVector* acceleration, bool simUsesAdaptiveForce); + private: + PX_FORCE_INLINE void raiseVelocityModFlag(VelocityModFlags f) { mVelModState |= f; } + PX_FORCE_INLINE void clearVelocityModFlag(VelocityModFlags f) { mVelModState &= ~f; } + PX_FORCE_INLINE bool readVelocityModFlag(VelocityModFlags f) { return (mVelModState & f) != 0; } + PX_FORCE_INLINE void setForcesToDefaults(bool enableGravity); + + //--------------------------------------------------------------------------------- + // Miscellaneous + //--------------------------------------------------------------------------------- + public: + PX_FORCE_INLINE PxU16 getInternalFlag() const { return mInternalFlags; } + PX_FORCE_INLINE bool readInternalFlag(InternalFlags flag) const { return (mInternalFlags & flag) != 0; } + PX_FORCE_INLINE void raiseInternalFlag(InternalFlags flag) { mInternalFlags |= flag; } + PX_FORCE_INLINE void clearInternalFlag(InternalFlags flag) { mInternalFlags &= ~flag; } + PX_FORCE_INLINE PxU32 getFlagsFast() const { return getBodyCore().getFlags(); } + + PX_FORCE_INLINE void incrementBodyConstraintCounter() { mLLBody.mCore->numBodyInteractions++; } + PX_FORCE_INLINE void decrementBodyConstraintCounter() { PX_ASSERT(mLLBody.mCore->numBodyInteractions>0); mLLBody.mCore->numBodyInteractions--; } + + PX_FORCE_INLINE BodyCore& getBodyCore() const { return static_cast<BodyCore&>(getRigidCore()); } + + PX_INLINE ArticulationSim* getArticulation() const { return mArticulation; } + void setArticulation(ArticulationSim* a, PxReal wakeCounter, bool asleep, PxU32 bodyIndex); + + PX_FORCE_INLINE IG::NodeIndex getNodeIndex() const { return mNodeIndex; } + + bool isConnectedTo(const ActorSim& other, bool& collisionDisabled) const; // Check if connected to specified object by a constraint + PX_FORCE_INLINE void onConstraintAttach() { raiseInternalFlag(BF_HAS_CONSTRAINTS); registerCountedInteraction(); } + void onConstraintDetach(); + + PX_FORCE_INLINE void onOriginShift(const PxVec3& shift) { mLLBody.mLastTransform.p -= shift; } + + PX_FORCE_INLINE bool notInScene() const { return mActiveListIndex == SC_NOT_IN_SCENE_INDEX; } + + PX_FORCE_INLINE bool usingSqKinematicTarget() const + { + PxU32 ktFlags(PxRigidBodyFlag::eUSE_KINEMATIC_TARGET_FOR_SCENE_QUERIES | PxRigidBodyFlag::eKINEMATIC); + return (getFlagsFast()&ktFlags) == ktFlags; + } + + void postShapeChange(bool asPartOfActorTransformChange); + void createSqBounds(); + void destroySqBounds(); + void freezeTransforms(Cm::BitMapPinned* shapeChangedMap); + void invalidateSqBounds(); + + private: + + //--------------------------------------------------------------------------------- + // Base body + //--------------------------------------------------------------------------------- + PxsRigidBody mLLBody; + + //--------------------------------------------------------------------------------- + // Island manager + //--------------------------------------------------------------------------------- + IG::NodeIndex mNodeIndex; + + //--------------------------------------------------------------------------------- + // External velocity changes + //--------------------------------------------------------------------------------- + // VelocityMod data allocated on the fly when the user applies velocity changes + // which need to be accumulated. + // VelMod dirty flags stored in BodySim so we can save ourselves the expense of looking at + // the separate velmod data if no forces have been set. + PxU16 mInternalFlags; + PxU8 mVelModState; + + + //--------------------------------------------------------------------------------- + // Sleeping + //--------------------------------------------------------------------------------- + PxU32 mActiveListIndex; // Used by Scene to track active bodies + + //--------------------------------------------------------------------------------- + // Articulation + //--------------------------------------------------------------------------------- + ArticulationSim* mArticulation; // NULL if not in an articulation + + //--------------------------------------------------------------------------------- + // Joints & joint groups + //--------------------------------------------------------------------------------- + + // This is a tree data structure that gives us the projection order of joints in which this body is the tree root. + // note: the link of the root body is not necces. the root link due to the re-rooting of the articulation! + ConstraintGroupNode* mConstraintGroup; + }; + +} // namespace Sc + + + +PX_FORCE_INLINE void Sc::BodySim::setForcesToDefaults(bool enableGravity) +{ + SimStateData* simStateData = getBodyCore().getSimStateData(false); + if(simStateData) + { + VelocityMod* velmod = simStateData->getVelocityModData(); + velmod->clear(); + } + + if (enableGravity) + mVelModState = VMF_GRAVITY_DIRTY; // We want to keep the gravity flag to make sure the acceleration gets changed to gravity-only + // in the next step (unless the application adds new forces of course) + else + mVelModState = 0; +} + + +PX_FORCE_INLINE bool Sc::BodySim::checkSleepReadinessBesidesWakeCounter() +{ + const BodyCore& bodyCore = getBodyCore(); + const SimStateData* simStateData = bodyCore.getSimStateData(false); + const VelocityMod* velmod = simStateData ? simStateData->getVelocityModData() : NULL; + + bool readyForSleep = bodyCore.getLinearVelocity().isZero() && bodyCore.getAngularVelocity().isZero(); + if (readVelocityModFlag(VMF_ACC_DIRTY)) + { + readyForSleep = readyForSleep && (!velmod || velmod->getLinearVelModPerSec().isZero()); + readyForSleep = readyForSleep && (!velmod || velmod->getAngularVelModPerSec().isZero()); + } + if (readVelocityModFlag(VMF_VEL_DIRTY)) + { + readyForSleep = readyForSleep && (!velmod || velmod->getLinearVelModPerStep().isZero()); + readyForSleep = readyForSleep && (!velmod || velmod->getAngularVelModPerStep().isZero()); + } + + return readyForSleep; +} + + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/ScClient.h b/PhysX_3.4/Source/SimulationController/src/ScClient.h new file mode 100644 index 00000000..e4f49772 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScClient.h @@ -0,0 +1,73 @@ +// 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_CLIENT +#define PX_PHYSICS_CLIENT + +#include "PxScene.h" +#include "CmPhysXCommon.h" +#include "PsUserAllocated.h" + +namespace physx +{ +namespace Sc +{ + + class Client : public Ps::UserAllocated + { + public: + Client() : + activeTransforms (PX_DEBUG_EXP("clientActiveTransforms")), + activeActors (PX_DEBUG_EXP("clientActiveActors")), + posePreviewBodies (PX_DEBUG_EXP("clientPosePreviewBodies")), + posePreviewBuffer (PX_DEBUG_EXP("clientPosePreviewBuffer")), + behaviorFlags (0), + simulationEventCallback (NULL), + broadPhaseCallback (NULL) + {} + + Ps::Array<PxActiveTransform> activeTransforms; + Ps::Array<PxActor*> activeActors; + Ps::Array<const PxRigidBody*> posePreviewBodies; // buffer for bodies that requested early report of the integrated pose (eENABLE_POSE_INTEGRATION_PREVIEW). + // This buffer gets exposed to users. Is officially accessible from PxSimulationEventCallback::onAdvance() + // until the next simulate()/advance(). + Ps::Array<PxTransform> posePreviewBuffer; // buffer of newly integrated poses for the bodies that requested a preview. This buffer gets exposed + // to users. + PxClientBehaviorFlags behaviorFlags;// Tracks behavior bits for clients. + // User callbacks + PxSimulationEventCallback* simulationEventCallback; + PxBroadPhaseCallback* broadPhaseCallback; + }; + +} // namespace Sc + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/ScConstraintCore.cpp b/PhysX_3.4/Source/SimulationController/src/ScConstraintCore.cpp new file mode 100644 index 00000000..06e42589 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScConstraintCore.cpp @@ -0,0 +1,149 @@ +// 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 "PsFoundation.h" + +#include "ScPhysics.h" +#include "ScBodyCore.h" +#include "ScConstraintCore.h" +#include "ScConstraintSim.h" + +using namespace physx; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +Sc::ConstraintCore::ConstraintCore(PxConstraintConnector& connector, const PxConstraintShaderTable& shaders, PxU32 dataSize) +: mFlags(PxConstraintFlag::eDRIVE_LIMITS_ARE_FORCES) +, mAppliedForce(PxVec3(0)) +, mAppliedTorque(PxVec3(0)) +, mConnector(&connector) +, mProject(shaders.project) +, mSolverPrep(shaders.solverPrep) +, mVisualize(shaders.visualize) +, mDataSize(dataSize) +, mLinearBreakForce(PX_MAX_F32) +, mAngularBreakForce(PX_MAX_F32) +, mMinResponseThreshold(0) +, mSim(NULL) +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +Sc::ConstraintCore::~ConstraintCore() +{ +} + +void Sc::ConstraintCore::setFlags(PxConstraintFlags flags) +{ + PxConstraintFlags old = mFlags; + flags = flags | (old & PxConstraintFlag::eGPU_COMPATIBLE); + if(flags != old) + { + mFlags = flags; + if(getSim()) + getSim()->postFlagChange(old, flags); + } +} + +void Sc::ConstraintCore::getForce(PxVec3& force, PxVec3& torque) const +{ + if(!mSim) + { + force = PxVec3(0,0,0); + torque = PxVec3(0,0,0); + } + else + mSim->getForce(force, torque); + +} + +void Sc::ConstraintCore::setBodies(RigidCore* r0v, RigidCore* r1v) +{ + if(mSim) + mSim->postBodiesChange(r0v, r1v); +} + +bool Sc::ConstraintCore::updateConstants(void* addr) +{ + if (getSim()) + { + getSim()->setConstantsLL(addr); + return true; + } + return false; +} + +void Sc::ConstraintCore::setBreakForce(PxReal linear, PxReal angular) +{ + mLinearBreakForce = linear; + mAngularBreakForce = angular; + + if (getSim()) + getSim()->setBreakForceLL(linear, angular); +} + +void Sc::ConstraintCore::getBreakForce(PxReal& linear, PxReal& angular) const +{ + linear = mLinearBreakForce; + angular = mAngularBreakForce; +} + +void Sc::ConstraintCore::setMinResponseThreshold(PxReal threshold) +{ + mMinResponseThreshold = threshold; + + if (getSim()) + getSim()->setMinResponseThresholdLL(threshold); +} + +PxConstraint* Sc::ConstraintCore::getPxConstraint() +{ + return gOffsetTable.convertScConstraint2Px(this); +} + +const PxConstraint* Sc::ConstraintCore::getPxConstraint() const +{ + return gOffsetTable.convertScConstraint2Px(this); +} + +void Sc::ConstraintCore::breakApart() +{ + // TODO: probably want to do something with the interaction here + // as well as remove the constraint from LL. + + mFlags |= PxConstraintFlag::eBROKEN; +} + +void Sc::ConstraintCore::prepareForSetBodies() +{ + if(mSim) + mSim->preBodiesChange(); +} diff --git a/PhysX_3.4/Source/SimulationController/src/ScConstraintGroupNode.cpp b/PhysX_3.4/Source/SimulationController/src/ScConstraintGroupNode.cpp new file mode 100644 index 00000000..5c61c239 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScConstraintGroupNode.cpp @@ -0,0 +1,138 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-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 "ScConstraintGroupNode.h" +#include "ScConstraintProjectionManager.h" +#include "PsFoundation.h" +#include "ScBodySim.h" +#include "ScConstraintSim.h" +#include "ScConstraintInteraction.h" + +using namespace physx; + +Sc::ConstraintGroupNode::ConstraintGroupNode(BodySim& b) : + body(&b), + parent(this), + tail(this), + rank(0), + next(NULL), + + projectionFirstRoot(NULL), + projectionNextRoot(NULL), + projectionParent(NULL), + projectionFirstChild(NULL), + projectionNextSibling(NULL), + projectionConstraint(NULL), + + flags(0) +{ +} + + +// +// Implementation of FIND of +// UNION-FIND algo. +// +Sc::ConstraintGroupNode& Sc::ConstraintGroupNode::getRoot() +{ + PX_ASSERT(parent); + + ConstraintGroupNode* root = parent; + + if (root->parent == root) + return *root; + else + { + PxU32 nbHops = 1; + root = root->parent; + + while(root != root->parent) + { + root = root->parent; + nbHops++; + } + + // Write root to all nodes on the path + ConstraintGroupNode* curr = this; + while(nbHops) + { + ConstraintGroupNode* n = curr->parent; + curr->parent = root; + curr = n; + nbHops--; + } + + return *root; + } +} + + +void Sc::ConstraintGroupNode::markForProjectionTreeRebuild(ConstraintProjectionManager& cpManager) +{ + ConstraintGroupNode& root = getRoot(); + if (!root.readFlag(ConstraintGroupNode::ePENDING_TREE_UPDATE)) + { + cpManager.addToPendingTreeUpdates(root); + } +} + + +void Sc::ConstraintGroupNode::initProjectionData(ConstraintGroupNode* parent_, ConstraintSim* c) +{ + projectionConstraint = c; + + //add us to parent's child list: + if (parent_) + { + projectionNextSibling = parent_->projectionFirstChild; + parent_->projectionFirstChild = this; + + projectionParent = parent_; + } +} + + +void Sc::ConstraintGroupNode::clearProjectionData() +{ + projectionFirstRoot = NULL; + projectionNextRoot = NULL; + projectionParent = NULL; + projectionFirstChild = NULL; + projectionNextSibling = NULL; + projectionConstraint = NULL; +} + + +void Sc::ConstraintGroupNode::projectPose(ConstraintGroupNode& node, Ps::Array<BodySim*>& projectedBodies) +{ + PX_ASSERT(node.hasProjectionTreeRoot()); + + Sc::ConstraintProjectionTree::projectPose(node, projectedBodies); +} diff --git a/PhysX_3.4/Source/SimulationController/src/ScConstraintGroupNode.h b/PhysX_3.4/Source/SimulationController/src/ScConstraintGroupNode.h new file mode 100644 index 00000000..ddc426fa --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScConstraintGroupNode.h @@ -0,0 +1,178 @@ +// 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_CONSTRAINT_GROUP_NODE +#define PX_PHYSICS_SCP_CONSTRAINT_GROUP_NODE + +#include "ScConstraintProjectionTree.h" +#include "PsUtilities.h" // for Ps::to8() + +namespace physx +{ +namespace Sc +{ + class ConstraintSim; + class BodySim; + class ConstraintProjectionManager; + + // A 'simulation island' of constraints. Created by a union-find algorithm every time a new constraint is added to any of the involved bodies. + struct ConstraintGroupNode : public Ps::UserAllocated + { + enum StateFlags + { + eDISCOVERED = 1 << 0, // Used during projection tree generation to mark processed nodes. + eIN_PROJECTION_PASS_LIST = 1 << 1, // Temporarily used to avoid duplicate entries in the list of nodes that should project the pose after the solver + ePENDING_TREE_UPDATE = 1 << 2, // Marks the constraint groups that need their projection trees updated. Must only be set on the root group node. + eNEXT_FREE_SHIFT = 3, + eNEXT_FREE = 1 << eNEXT_FREE_SHIFT + }; + + // these flags should give a rough hint how many projecting constraints to expect in the constraint group. This will be used for + // load balancing when running projection in parallel. The intervals were chosen somewhat arbitrarily but the general motivation was + // to cover very simple constraint setups, simple ragdolls, complex ragdolls and very complex projection setups. Note that the load + // balancing is not waterproof since at the end it is the projection shader from the external constraint implementer (for example, a joint) + // which decides based on some thresholds whether projection runs or not. + enum ProjectionCountHintFlags + { + e1_TO_4 = eNEXT_FREE, + e5_TO_16 = eNEXT_FREE << 1, + e17_TO_64 = eNEXT_FREE << 2, + e65_TO_INF = eNEXT_FREE << 3, + eCLEAR_MASK = ~(0xffffffff << eNEXT_FREE_SHIFT) + }; + + ConstraintGroupNode(BodySim& b); + ~ConstraintGroupNode() + { + PX_ASSERT(!readFlag(ePENDING_TREE_UPDATE)); + PX_ASSERT(projectionFirstRoot == NULL); + } + + PX_FORCE_INLINE void raiseFlag(StateFlags f) { flags |= f; } + PX_FORCE_INLINE void clearFlag(StateFlags f) { flags &= ~f; } + PX_FORCE_INLINE bool readFlag(StateFlags f) const { return (flags & f) != 0; } + PX_FORCE_INLINE PxU32 getProjectionCountHint() const; + PX_FORCE_INLINE void setProjectionCountHint(PxU32 constraintsToProjectCount); + + ConstraintGroupNode& getRoot(); + + PX_FORCE_INLINE void buildProjectionTrees(); //build the projection trees for a constraint group. + void markForProjectionTreeRebuild(ConstraintProjectionManager&); + PX_FORCE_INLINE void purgeProjectionTrees(); + PX_FORCE_INLINE bool hasProjectionTreeRoot() { return projectionFirstRoot != NULL; } + PX_FORCE_INLINE void setProjectionTreeRoot(ConstraintGroupNode* root) { projectionFirstRoot = root; } + + void initProjectionData(ConstraintGroupNode* parent, ConstraintSim* c); + void clearProjectionData(); + + static void projectPose(ConstraintGroupNode& root, Ps::Array<BodySim*>& projectedBodies); + + + BodySim* body; //the owner body of this node + + //tree for union/find: + ConstraintGroupNode* parent; + ConstraintGroupNode* tail; //only valid if this is root of group, points to LList tail node. + PxU32 rank; //rank counter for union/find. Initially zero. Is number of hops from root to furthest leaf in tree. This is just a hint to create more balanced trees. + + //linked list for traversal: + ConstraintGroupNode* next; //next in list, NULL at tail. + + //projection tree information + ConstraintGroupNode* projectionFirstRoot; //pointer to first projection tree root node. Only set for constraint group roots + ConstraintGroupNode* projectionNextRoot; //pointer to next projection root node. Only set for constraint group roots + //a constraint group can consist of multiple projection trees if kinematics are involved! Because a kinematic doesn't split + //the constraint group as a static anchor does. + ConstraintGroupNode* projectionParent; //node to project to + ConstraintGroupNode* projectionFirstChild; //first node which gets projected to this one + ConstraintGroupNode* projectionNextSibling; //the next sibling which gets projected to the same node as this one. NULL if projectionParent is NULL. + ConstraintSim* projectionConstraint; //the constraint to project (constraint to projection parent) + + private: + PxU8 flags; + }; + +} // namespace Sc + + +PX_FORCE_INLINE PxU32 Sc::ConstraintGroupNode::getProjectionCountHint() const +{ + // return the mean of the upper and lower bound + + if (flags & ConstraintGroupNode::e65_TO_INF) + return 128; + else if (flags & ConstraintGroupNode::e17_TO_64) + return 40; + else if (flags & ConstraintGroupNode::e5_TO_16) + return 10; + else if (flags & ConstraintGroupNode::e1_TO_4) + return 2; + + return 0; +} + + +PX_FORCE_INLINE void Sc::ConstraintGroupNode::setProjectionCountHint(PxU32 constraintsToProjectCount) +{ + PxU8 tmpFlags = flags; + tmpFlags &= PxU8(ConstraintGroupNode::eCLEAR_MASK); + + if (constraintsToProjectCount >= 65) + tmpFlags |= ConstraintGroupNode::e65_TO_INF; + else if (constraintsToProjectCount >= 17) + tmpFlags |= ConstraintGroupNode::e17_TO_64; + else if (constraintsToProjectCount >= 5) + tmpFlags |= ConstraintGroupNode::e5_TO_16; + else if (constraintsToProjectCount >= 1) + tmpFlags |= ConstraintGroupNode::e1_TO_4; + + flags = tmpFlags; +} + + +PX_FORCE_INLINE void Sc::ConstraintGroupNode::buildProjectionTrees() +{ + PX_ASSERT(this == parent); // Only call for group roots + PX_ASSERT(!hasProjectionTreeRoot()); + + ConstraintProjectionTree::buildProjectionTrees(*this); +} + + +PX_FORCE_INLINE void Sc::ConstraintGroupNode::purgeProjectionTrees() +{ + PX_ASSERT(this == parent); // Only call for group roots + PX_ASSERT(hasProjectionTreeRoot()); + ConstraintProjectionTree::purgeProjectionTrees(*this); +} + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/ScConstraintInteraction.cpp b/PhysX_3.4/Source/SimulationController/src/ScConstraintInteraction.cpp new file mode 100644 index 00000000..5dc1bd72 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScConstraintInteraction.cpp @@ -0,0 +1,178 @@ +// 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 "ScConstraintInteraction.h" +#include "ScConstraintSim.h" +#include "ScBodySim.h" +#include "ScScene.h" +#include "PxsRigidBody.h" +#include "PxsSimpleIslandManager.h" + + +using namespace physx; + + +Sc::ConstraintInteraction::ConstraintInteraction(ConstraintSim* constraint, RigidSim& r0, RigidSim& r1) : + ActorInteraction (r0, r1, InteractionType::eCONSTRAINTSHADER, InteractionFlag::eCONSTRAINT), + mConstraint (constraint) +{ + registerInActors(); + + BodySim* b0 = mConstraint->getBody(0); + BodySim* b1 = mConstraint->getBody(1); + + if (b0) + b0->onConstraintAttach(); + if (b1) + b1->onConstraintAttach(); + + IG::SimpleIslandManager* simpleIslandManager = getScene().getSimpleIslandManager(); + mEdgeIndex = simpleIslandManager->addConstraint(&mConstraint->getLowLevelConstraint(), b0 ? b0->getNodeIndex() : IG::NodeIndex(), b1 ? b1->getNodeIndex() : IG::NodeIndex(), this); + +} + + +Sc::ConstraintInteraction::~ConstraintInteraction() +{ + PX_ASSERT(!readInteractionFlag(InteractionFlag::eIN_DIRTY_LIST)); + PX_ASSERT(!getDirtyFlags()); + PX_ASSERT(!mConstraint->readFlag(ConstraintSim::eCHECK_MAX_FORCE_EXCEEDED)); +} + + +PX_FORCE_INLINE void Sc::ConstraintInteraction::removeFromActiveBreakableList(Scene& s) +{ + if (mConstraint->readFlag(ConstraintSim::eBREAKABLE | ConstraintSim::eCHECK_MAX_FORCE_EXCEEDED) == (ConstraintSim::eBREAKABLE | ConstraintSim::eCHECK_MAX_FORCE_EXCEEDED)) + s.removeActiveBreakableConstraint(mConstraint); +} + + +void Sc::ConstraintInteraction::destroy() +{ + setClean(true); // removes the pair from the dirty interaction list etc. + + Scene& scene = getScene(); + + removeFromActiveBreakableList(scene); + + if(mEdgeIndex != IG_INVALID_EDGE) + scene.getSimpleIslandManager()->removeConnection(mEdgeIndex); + mEdgeIndex = IG_INVALID_EDGE; + + unregisterFromActors(); + + BodySim* b0 = mConstraint->getBody(0); + BodySim* b1 = mConstraint->getBody(1); + + if (b0) + b0->onConstraintDetach(); // Note: Has to be done AFTER the interaction has unregistered from the actors + if (b1) + b1->onConstraintDetach(); // Note: Has to be done AFTER the interaction has unregistered from the actors + + clearInteractionFlag(InteractionFlag::eIS_ACTIVE); // ensures that broken constraints do not go into the list of active breakable constraints anymore +} + + +void Sc::ConstraintInteraction::updateState() +{ + PX_ASSERT(!mConstraint->isBroken()); + PX_ASSERT(getDirtyFlags() & InteractionDirtyFlag::eBODY_KINEMATIC); // at the moment this should be the only reason for this method being called + + // at least one of the bodies got switched from kinematic to dynamic. This will not have changed the sleep state of the interactions, so the + // constraint interactions are just marked dirty and processed as part of the dirty interaction update system. + // + // -> need to check whether to activate the constraint and whether constraint break testing + // is now necessary + // + // the transition from dynamic to kinematic will always trigger an onDeactivate() (because the body gets deactivated) + // and thus there is no need to consider that case here. + // + + onActivate(NULL); // note: this will not activate if the necessary conditions are not met, so it can be called even if the pair has been deactivated again before the + // simulation step started +} + + +bool Sc::ConstraintInteraction::onActivate(void*) +{ + PX_ASSERT(!mConstraint->isBroken()); + + BodySim* b0 = mConstraint->getBody(0); + BodySim* b1 = mConstraint->getBody(1); + + bool b0Vote = !b0 || b0->isActive(); + bool b1Vote = !b1 || b1->isActive(); + + bool b0Dynamic = b0 && (!b0->isKinematic()); + bool b1Dynamic = b1 && (!b1->isKinematic()); + + // + // note: constraints between kinematics and kinematics/statics are always inactive and must not be activated + // + if ((b0Vote || b1Vote) && (b0Dynamic || b1Dynamic)) + { + raiseInteractionFlag(InteractionFlag::eIS_ACTIVE); + + if (mConstraint->readFlag(ConstraintSim::eBREAKABLE | ConstraintSim::eCHECK_MAX_FORCE_EXCEEDED) == ConstraintSim::eBREAKABLE) + getScene().addActiveBreakableConstraint(mConstraint, this); + + return true; + } + else + return false; +} + + +bool Sc::ConstraintInteraction::onDeactivate(PxU32) +{ + const BodySim* b0 = mConstraint->getBody(0); + const BodySim* b1 = mConstraint->getBody(1); + + bool b0Dynamic = b0 && (!b0->isKinematic()); + bool b1Dynamic = b1 && (!b1->isKinematic()); + + PX_ASSERT( (!b0 && b1 && !b1->isActive()) || + (!b1 && b0 && !b0->isActive()) || + ((b0 && b1 && (!b0->isActive() || !b1->isActive()))) ); + + // + // note: constraints between kinematics and kinematics/statics should always get deactivated + // + if (((!b0 || !b0->isActive()) && (!b1 || !b1->isActive())) || (!b0Dynamic && !b1Dynamic)) + { + removeFromActiveBreakableList(getScene()); + + clearInteractionFlag(InteractionFlag::eIS_ACTIVE); + + return true; + } + else + return false; +} diff --git a/PhysX_3.4/Source/SimulationController/src/ScConstraintInteraction.h b/PhysX_3.4/Source/SimulationController/src/ScConstraintInteraction.h new file mode 100644 index 00000000..9c461c2a --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScConstraintInteraction.h @@ -0,0 +1,75 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-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_CONSTRAINTSHADERINTERACTION +#define PX_PHYSICS_SCP_CONSTRAINTSHADERINTERACTION + +#include "ScActorInteraction.h" + +namespace physx +{ +namespace Sc +{ + + class ConstraintSim; + class RigidSim; + + class ConstraintInteraction : public ActorInteraction + { + public: + ConstraintInteraction(ConstraintSim* shader, RigidSim& r0, RigidSim& r1); + ~ConstraintInteraction(); + + //---------- Interaction ---------- + virtual bool onActivate(void* data); + virtual bool onDeactivate(PxU32 infoFlag); + //----------------------------------- + + void updateState(); + void destroy(); // disables the interaction and unregisters from the system. Does NOT delete the object. This is used on destruction but also when a constraint breaks. + + PX_FORCE_INLINE ConstraintSim* getConstraint() { return mConstraint; } + + PX_FORCE_INLINE PxU32 getEdgeIndex(){ return mEdgeIndex; } + + private: + PX_FORCE_INLINE void removeFromActiveBreakableList(Scene&); + + + ConstraintSim* mConstraint; + + PxU32 mEdgeIndex; + }; + +} // namespace Sc + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/ScConstraintProjectionManager.cpp b/PhysX_3.4/Source/SimulationController/src/ScConstraintProjectionManager.cpp new file mode 100644 index 00000000..9880f622 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScConstraintProjectionManager.cpp @@ -0,0 +1,505 @@ +// 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 "PxcScratchAllocator.h" +#include "ScConstraintProjectionManager.h" +#include "ScBodySim.h" +#include "ScConstraintSim.h" +#include "ScConstraintInteraction.h" + +using namespace physx; + + +namespace physx +{ +namespace Sc +{ + +template<typename T, const PxU32 elementsPerBlock> +class ScratchAllocatorList +{ +private: + struct ElementBlock + { + PX_FORCE_INLINE ElementBlock() {} + PX_FORCE_INLINE void init(PxU32 countAtStart) { next = NULL; count = countAtStart; } + + ElementBlock* next; + PxU32 count; + T elements[elementsPerBlock]; + }; + + PX_FORCE_INLINE const ScratchAllocatorList& operator=(const ScratchAllocatorList&) {} + + +public: + class Iterator + { + friend class ScratchAllocatorList; + + public: + T const* getNext() + { + if (mCurrentBlock) + { + if (mIndex < mCurrentBlock->count) + { + return &mCurrentBlock->elements[mIndex++]; + } + else + { + if (mCurrentBlock->next) + { + PX_ASSERT(mCurrentBlock->count == elementsPerBlock); + mCurrentBlock = mCurrentBlock->next; + PX_ASSERT(mCurrentBlock->count > 0); + + mIndex = 1; + return &mCurrentBlock->elements[0]; + } + else + return NULL; + } + } + else + return NULL; + } + + private: + Iterator(const ElementBlock* startBlock) : mCurrentBlock(startBlock), mIndex(0) {} + + private: + const ElementBlock* mCurrentBlock; + PxU32 mIndex; + }; + + PX_FORCE_INLINE ScratchAllocatorList(PxcScratchAllocator& scratchAllocator) : mScratchAllocator(scratchAllocator) + { + mFirstBlock = reinterpret_cast<ElementBlock*>(scratchAllocator.alloc(sizeof(ElementBlock), true)); + if (mFirstBlock) + mFirstBlock->init(0); + + mCurrentBlock = mFirstBlock; + } + + PX_FORCE_INLINE ~ScratchAllocatorList() + { + freeMemory(); + } + + PX_FORCE_INLINE bool add(const T& element) + { + if (mCurrentBlock) + { + if (mCurrentBlock->count < elementsPerBlock) + { + mCurrentBlock->elements[mCurrentBlock->count] = element; + mCurrentBlock->count++; + return true; + } + else + { + PX_ASSERT(mCurrentBlock->next == NULL); + PX_ASSERT(mCurrentBlock->count == elementsPerBlock); + + ElementBlock* newBlock = reinterpret_cast<ElementBlock*>(mScratchAllocator.alloc(sizeof(ElementBlock), true)); + if (newBlock) + { + newBlock->init(1); + newBlock->elements[0] = element; + mCurrentBlock->next = newBlock; + mCurrentBlock = newBlock; + return true; + } + else + return false; + } + } + else + return false; + } + + PX_FORCE_INLINE Iterator getIterator() const + { + return Iterator(mFirstBlock); + } + + PX_FORCE_INLINE void freeMemory() + { + ElementBlock* block = mFirstBlock; + + while(block) + { + ElementBlock* blockToFree = block; + block = block->next; + + mScratchAllocator.free(blockToFree); + } + } + + +private: + PxcScratchAllocator& mScratchAllocator; + ElementBlock* mFirstBlock; + ElementBlock* mCurrentBlock; +}; + +} +} + + +Sc::ConstraintProjectionManager::ConstraintProjectionManager() : + mNodePool(PX_DEBUG_EXP("projectionNodePool")) +{ +} + + +void Sc::ConstraintProjectionManager::addToPendingGroupUpdates(Sc::ConstraintSim& s) +{ + PX_ASSERT(!s.readFlag(ConstraintSim::ePENDING_GROUP_UPDATE)); + bool isNew = mPendingGroupUpdates.insert(&s); + PX_UNUSED(isNew); + PX_ASSERT(isNew); + + s.setFlag(ConstraintSim::ePENDING_GROUP_UPDATE); +} + + +void Sc::ConstraintProjectionManager::removeFromPendingGroupUpdates(Sc::ConstraintSim& s) +{ + PX_ASSERT(s.readFlag(ConstraintSim::ePENDING_GROUP_UPDATE)); + bool didExist = mPendingGroupUpdates.erase(&s); + PX_UNUSED(didExist); + PX_ASSERT(didExist); + + s.clearFlag(ConstraintSim::ePENDING_GROUP_UPDATE); +} + + +void Sc::ConstraintProjectionManager::addToPendingTreeUpdates(ConstraintGroupNode& n) +{ + PX_ASSERT(&n == &n.getRoot()); + PX_ASSERT(!n.readFlag(ConstraintGroupNode::ePENDING_TREE_UPDATE)); + bool isNew = mPendingTreeUpdates.insert(&n); + PX_UNUSED(isNew); + PX_ASSERT(isNew); + + n.raiseFlag(ConstraintGroupNode::ePENDING_TREE_UPDATE); +} + + +void Sc::ConstraintProjectionManager::removeFromPendingTreeUpdates(ConstraintGroupNode& n) +{ + PX_ASSERT(&n == &n.getRoot()); + PX_ASSERT(n.readFlag(ConstraintGroupNode::ePENDING_TREE_UPDATE)); + bool didExist = mPendingTreeUpdates.erase(&n); + PX_UNUSED(didExist); + PX_ASSERT(didExist); + + n.clearFlag(ConstraintGroupNode::ePENDING_TREE_UPDATE); +} + + +PX_INLINE Sc::ConstraintGroupNode* Sc::ConstraintProjectionManager::createGroupNode(BodySim& b) +{ + ConstraintGroupNode* n = mNodePool.construct(b); + b.setConstraintGroup(n); + return n; +} + + +// +// Implementation of UNION of +// UNION-FIND algo. +// It also updates the group traversal +// linked list. +// +void Sc::ConstraintProjectionManager::groupUnion(ConstraintGroupNode& root0, ConstraintGroupNode& root1) +{ + // Should only get called for the roots + PX_ASSERT(&root0 == root0.parent); + PX_ASSERT(&root1 == root1.parent); + + if (&root0 != &root1) //different groups? If not, its already merged. + { + //UNION(this, other); //union-find algo unites groups. + ConstraintGroupNode* newRoot; + ConstraintGroupNode* otherRoot; + if (root0.rank > root1.rank) + { + //hisGroup appended to mygroup. + newRoot = &root0; + otherRoot = &root1; + } + else + { + //myGroup appended to hisGroup. + newRoot = &root1; + otherRoot = &root0; + //there is a chance that the two ranks were equal, in which case the tree depth just increased. + root1.rank++; + } + + PX_ASSERT(newRoot->parent == newRoot); + otherRoot->parent = newRoot; + + //update traversal linked list: + newRoot->tail->next = otherRoot; + newRoot->tail = otherRoot->tail; + } +} + + +// +// Add a body to a constraint projection group. +// +void Sc::ConstraintProjectionManager::addToGroup(BodySim& b, BodySim* other, ConstraintSim& c) +{ + // If both bodies of the constraint are defined, we want to fetch the reference to the group root + // from body 0 by default (allows to avoid checking both) + PX_ASSERT(&b == c.getBody(0) || (c.getBody(0) == NULL && &b == c.getBody(1))); + PX_UNUSED(c); + + ConstraintGroupNode* myRoot; + if (!b.getConstraintGroup()) + myRoot = createGroupNode(b); + else + { + myRoot = &b.getConstraintGroup()->getRoot(); + if (myRoot->hasProjectionTreeRoot()) + myRoot->purgeProjectionTrees(); // If a new constraint gets added to a constraint group, projection trees need to be recreated + } + + if (other) + { + ConstraintGroupNode* otherRoot; + if (!other->getConstraintGroup()) + otherRoot = createGroupNode(*other); + else + { + otherRoot = &other->getConstraintGroup()->getRoot(); + if (otherRoot->hasProjectionTreeRoot()) + otherRoot->purgeProjectionTrees(); // If a new constraint gets added to a constraint group, projection trees need to be recreated + } + + //merge the two groups, if disjoint. + groupUnion(*myRoot, *otherRoot); + } +} + + +// +// Add all projection constraints connected to the specified body to the pending update list but +// ignore the specified constraint. +// +void Sc::ConstraintProjectionManager::markConnectedConstraintsForUpdate(BodySim& b, ConstraintSim* c) +{ + PxU32 size = b.getActorInteractionCount(); + Interaction** interactions = b.getActorInteractions(); + while(size--) + { + Interaction* interaction = *interactions++; + if (interaction->getType() == InteractionType::eCONSTRAINTSHADER) + { + ConstraintSim* ct = static_cast<ConstraintInteraction*>(interaction)->getConstraint(); + + if ((ct != c) && ct->needsProjection() && (!ct->readFlag(ConstraintSim::ePENDING_GROUP_UPDATE))) + { + //mark constraint for pending update: + addToPendingGroupUpdates(*ct); + } + } + } +} + + +// +// Add all constraints connected to the specified body to an array but +// ignore the specified constraint. +// +PX_FORCE_INLINE static void dumpConnectedConstraints(Sc::BodySim& b, Sc::ConstraintSim* c, Sc::ScratchAllocatorList<Sc::ConstraintSim*>& constraintList) +{ + PxU32 size = b.getActorInteractionCount(); + Sc::Interaction** interactions = b.getActorInteractions(); + while(size--) + { + Sc::Interaction* interaction = *interactions++; + if (interaction->getType() == Sc::InteractionType::eCONSTRAINTSHADER) + { + Sc::ConstraintSim* ct = static_cast<Sc::ConstraintInteraction*>(interaction)->getConstraint(); + + if ((ct != c) && (!ct->readFlag(Sc::ConstraintSim::ePENDING_GROUP_UPDATE))) + { + bool success = constraintList.add(ct); + PX_UNUSED(success); + PX_ASSERT(success); + } + } + } +} + + +PX_FORCE_INLINE void Sc::ConstraintProjectionManager::processConstraintForGroupBuilding(ConstraintSim* c, ScratchAllocatorList<ConstraintSim*>& constraintList) +{ + c->clearFlag(ConstraintSim::ePENDING_GROUP_UPDATE); + + // Find all constraints connected to the two bodies of the dirty constraint. + // - Constraints to static anchors are ignored (note: kinematics can't be ignored because they might get switched to dynamics any time which + // does trigger a projection tree rebuild but not a constraint tree rebuild + // - Already processed bodies are ignored as well + BodySim* b0 = c->getBody(0); + if (b0 && !b0->getConstraintGroup()) + { + dumpConnectedConstraints(*b0, c, constraintList); + } + BodySim* b1 = c->getBody(1); + if (b1 && !b1->getConstraintGroup()) + { + dumpConnectedConstraints(*b1, c, constraintList); + } + + BodySim* b = c->getAnyBody(); + PX_ASSERT(b); + + addToGroup(*b, c->getOtherBody(b), *c); //this will eventually merge some body's constraint groups. +} + + +void Sc::ConstraintProjectionManager::processPendingUpdates(PxcScratchAllocator& scratchAllocator) +{ + // + // if there are dirty projection trees, then rebuild them + // + const PxU32 nbProjectionTreesToUpdate = mPendingTreeUpdates.size(); + if (nbProjectionTreesToUpdate) + { + ConstraintGroupNode* const* projectionTreesToUpdate = mPendingTreeUpdates.getEntries(); + for(PxU32 i=0; i < nbProjectionTreesToUpdate; i++) + { + ConstraintGroupNode* n = projectionTreesToUpdate[i]; + + PX_ASSERT(n == &n->getRoot()); // only root nodes should be in that list + PX_ASSERT(n->readFlag(ConstraintGroupNode::ePENDING_TREE_UPDATE)); + + n->clearFlag(ConstraintGroupNode::ePENDING_TREE_UPDATE); + + // note: it is valid to get here and not have a projection root. This is the case if all nodes of a constraint graph are kinematic + // at some point (hence no projection root) and later some of those get switched to dynamic. + if (n->hasProjectionTreeRoot()) + n->purgeProjectionTrees(); + n->buildProjectionTrees(); + } + + mPendingTreeUpdates.clear(); + } + + // + // if there are new/dirty constraints, update groups + // + const PxU32 nbProjectionConstraintsToUpdate = mPendingGroupUpdates.size(); + + if (nbProjectionConstraintsToUpdate) + { + ScratchAllocatorList<ConstraintSim*> nonProjectionConstraintList(scratchAllocator); + + ConstraintSim* const* projectionConstraintsToUpdate = mPendingGroupUpdates.getEntries(); + +#if PX_DEBUG + // At the beginning the list should only contain constraints with projection. + // Further below other constraints, connected to the constraints with projection, will be added too. + for(PxU32 i=0; i < nbProjectionConstraintsToUpdate; i++) + { + PX_ASSERT(projectionConstraintsToUpdate[i]->needsProjection()); + } +#endif + for(PxU32 i=0; i < nbProjectionConstraintsToUpdate; i++) + { + processConstraintForGroupBuilding(projectionConstraintsToUpdate[i], nonProjectionConstraintList); + } + + ScratchAllocatorList<ConstraintSim*>::Iterator iter = nonProjectionConstraintList.getIterator(); + ConstraintSim* const* nextConstraint = iter.getNext(); + while(nextConstraint) + { + processConstraintForGroupBuilding(*nextConstraint, nonProjectionConstraintList); + + nextConstraint = iter.getNext(); + } + + // Now find all the newly made groups and build projection trees. + // Don't need to iterate over the additionally constraints since the roots are supposed to be + // fetchable from any node. + for (PxU32 i=0; i < nbProjectionConstraintsToUpdate; i++) + { + ConstraintSim* c = projectionConstraintsToUpdate[i]; + BodySim* b = c->getAnyBody(); + PX_ASSERT(b); + PX_ASSERT(b->getConstraintGroup()); + + ConstraintGroupNode& root = b->getConstraintGroup()->getRoot(); + if (!root.hasProjectionTreeRoot()) // Build projection tree only once + root.buildProjectionTrees(); + } + + mPendingGroupUpdates.clear(); + } +} + + +// +// Called if a body or a constraint gets deleted. All projecting constraints of the +// group (except the deleted one) are moved to the dirty list and all group nodes are destroyed. +// +void Sc::ConstraintProjectionManager::invalidateGroup(ConstraintGroupNode& node, ConstraintSim* deletedConstraint) +{ + ConstraintGroupNode* n = &node.getRoot(); + + if (n->readFlag(ConstraintGroupNode::ePENDING_TREE_UPDATE)) + { + removeFromPendingTreeUpdates(*n); + } + + while (n) //go through nodes in constraint group + { + markConnectedConstraintsForUpdate(*n->body, deletedConstraint); + + //destroy the body's constraint group information + + ConstraintGroupNode* next = n->next; //save next node ptr before we destroy it! + + BodySim* b = n->body; + b->setConstraintGroup(NULL); + if (n->hasProjectionTreeRoot()) + n->purgeProjectionTrees(); + mNodePool.destroy(n); + + n = next; + } +} diff --git a/PhysX_3.4/Source/SimulationController/src/ScConstraintProjectionManager.h b/PhysX_3.4/Source/SimulationController/src/ScConstraintProjectionManager.h new file mode 100644 index 00000000..482c6a8e --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScConstraintProjectionManager.h @@ -0,0 +1,84 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-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_CONSTRAINT_PROJECTION_MANAGER +#define PX_PHYSICS_SCP_CONSTRAINT_PROJECTION_MANAGER + +#include "PsPool.h" +#include "PsHashSet.h" +#include "ScConstraintGroupNode.h" + +namespace physx +{ + class PxcScratchAllocator; + +namespace Sc +{ + class ConstraintSim; + class BodySim; + template<typename T, const PxU32 elementsPerBlock = 64> class ScratchAllocatorList; + + class ConstraintProjectionManager : public Ps::UserAllocated + { + public: + ConstraintProjectionManager(); + ~ConstraintProjectionManager() {} + + void addToPendingGroupUpdates(ConstraintSim& s); + void removeFromPendingGroupUpdates(ConstraintSim& s); + + void addToPendingTreeUpdates(ConstraintGroupNode& n); + void removeFromPendingTreeUpdates(ConstraintGroupNode& n); + + void processPendingUpdates(PxcScratchAllocator&); + void invalidateGroup(ConstraintGroupNode& node, ConstraintSim* constraintDeleted); + + private: + PX_INLINE Sc::ConstraintGroupNode* createGroupNode(BodySim& b); + + void addToGroup(BodySim& b, BodySim* other, ConstraintSim& c); + void groupUnion(ConstraintGroupNode& root0, ConstraintGroupNode& root1); + void markConnectedConstraintsForUpdate(BodySim& b, ConstraintSim* c); + PX_FORCE_INLINE void processConstraintForGroupBuilding(ConstraintSim* c, ScratchAllocatorList<ConstraintSim*>&); + + + private: + Ps::Pool<ConstraintGroupNode> mNodePool; + Ps::CoalescedHashSet<ConstraintSim*> mPendingGroupUpdates; //list of constraints for which constraint projection groups need to be generated/updated + Ps::CoalescedHashSet<ConstraintGroupNode*> mPendingTreeUpdates; //list of constraint groups that need their projection trees rebuilt. Note: non of the + //constraints in those groups are allowed to be in mPendingGroupUpdates at the same time + //because a group update will automatically trigger tree rebuilds. + }; + +} // namespace Sc + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/ScConstraintProjectionTree.cpp b/PhysX_3.4/Source/SimulationController/src/ScConstraintProjectionTree.cpp new file mode 100644 index 00000000..5cf0a13f --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScConstraintProjectionTree.cpp @@ -0,0 +1,567 @@ +// 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 "ScConstraintProjectionTree.h" +#include "ScScene.h" +#include "ScBodySim.h" +#include "ScConstraintCore.h" +#include "ScConstraintSim.h" +#include "ScConstraintInteraction.h" + +#include "PsFoundation.h" +#include "PsBasicTemplates.h" +#include "PsSort.h" +#include "PsArray.h" + +using namespace physx; + +//------------------------------------------------------------------------------------------ +// +// The projection tree related code +// +// Projection trees are built out of a constraint group/graph. The constraint group just tracks +// the constraint connectivity while the projection trees define the projection root and +// the projection order. +// A constraint group can contain multiple projection trees. +// +//------------------------------------------------------------------------------------------ + +class Sc::BodyRank +{ +public: + PX_INLINE bool operator>(const BodyRank & b) const + { + return rank > b.rank; + } + + Sc::ConstraintGroupNode* startingNode; + Sc::ConstraintSim* constraintToFixedAnchor; + PxU32 rank; + + // + // The following weights are defined to fulfill the projection priorities described further below + // + static const PxU32 sOneWayProjection = PxU32(1 << 31); + static const PxU32 sAttachedToStatic = (1 << 30); + static const PxU32 sAttachedToKinematic = (1 << 29); + static const PxU32 sAllDominantDynamic = (1 << 28); // if for a dynamic body all connections with projection, are one-way towards the body + static const PxU32 sDominantDynamic = (1 << 27); // almost the same as above but there is at least one two-way projection + static const PxU32 sAttachedToDynamic = 1; + static const PxU32 sPrimaryTreeRootMinRank = sOneWayProjection | sAllDominantDynamic; +}; + + +PX_INLINE bool isFixedBody(const Sc::BodySim* b) +{ + return (!b || (b->isKinematic())); +} + + +void Sc::ConstraintProjectionTree::getConstraintStatus(const ConstraintSim& c, const BodySim* b, BodySim*& otherBody, PxU32& projectToBody, PxU32& projectToOtherBody) +{ + PxU32 isBroken = c.isBroken() ? 0 : 0xffffffff; + PxU32 projFlags = c.getCore().getFlags() & PxConstraintFlag::ePROJECTION; + + if (b == c.getBody(0)) + { + projectToBody = isBroken & (projFlags & PxConstraintFlag::ePROJECT_TO_ACTOR0); + projectToOtherBody = isBroken & (projFlags & PxConstraintFlag::ePROJECT_TO_ACTOR1); + + otherBody = c.getBody(1); + } + else + { + projectToBody = isBroken & (projFlags & PxConstraintFlag::ePROJECT_TO_ACTOR1); + projectToOtherBody = isBroken & (projFlags & PxConstraintFlag::ePROJECT_TO_ACTOR0); + + otherBody = c.getBody(0); + } +} + + +void Sc::ConstraintProjectionTree::rankConstraint(ConstraintSim& c, BodyRank& br, PxU32& dominanceTracking, PxU32& constraintsToProjectCount) +{ + PxU32 projectToBody, projectToOtherBody; + BodySim* otherB; + getConstraintStatus(c, br.startingNode->body, otherB, projectToBody, projectToOtherBody); + + if (isFixedBody(otherB)) // joint to fixed anchor + { + PxU32 rank; + if (projectToOtherBody) + { + dominanceTracking = 0; // makes sure that the flags below will never get raised again for the body + br.rank &= ~(BodyRank::sAllDominantDynamic | BodyRank::sDominantDynamic); + rank = BodyRank::sOneWayProjection; //we should prefer picking projected constraints as the root over non-projected ones. + constraintsToProjectCount++; + } + else + rank = 0; + + if (!otherB) + rank |= BodyRank::sAttachedToStatic; + else + { + PX_ASSERT(otherB->isKinematic()); + rank |= BodyRank::sAttachedToKinematic; + } + + // the highest ranked fixed anchor constraint should get tracked + if ((!br.constraintToFixedAnchor) || (rank > br.rank)) + br.constraintToFixedAnchor = &c; + + br.rank |= rank; + } + else + { + if (projectToBody && projectToOtherBody) + { + dominanceTracking &= ~BodyRank::sAllDominantDynamic; // makes sure that from now on this will never get raised again for the body + br.rank &= ~BodyRank::sAllDominantDynamic; + constraintsToProjectCount++; + } + else if (projectToOtherBody) + { + dominanceTracking &= ~(BodyRank::sAllDominantDynamic | BodyRank::sDominantDynamic); // makes sure that from now on these will never get raised again for the body + br.rank &= ~(BodyRank::sAllDominantDynamic | BodyRank::sDominantDynamic); + constraintsToProjectCount++; + } + else if (projectToBody) + { + br.rank |= BodyRank::sOneWayProjection | (dominanceTracking & (BodyRank::sAllDominantDynamic | BodyRank::sDominantDynamic)); + constraintsToProjectCount++; + } + + br.rank += BodyRank::sAttachedToDynamic; + } +} + + +/* +the goal here is to take the constraint group whose root is passed, and create one or more projection trees. + +At the moment, the group has to be acyclic and have at most 1 constraint with the ground to be accepted +without being broken up into multiple trees. + +We 'flood fill' the constraint graph several times, starting at bodies where projection trees can be rooted. +Projection tree roots are always dynamic bodies which either need to get projected to a fixed anchor directly +or have projecting constraints between dynamics some way along the tree branches. Static and kinematic actors +are never roots and will not be explicitly part of any tree (but a tree root can project to at most one such fixed node). + +The algo looks like this: + +for all bodies +mark body as undiscovered +rank this body + +The rank of a body depends on the constraints it's connected to. It defines the projection priority which +should be (highest first): +- dynamic attached to static/world with projection +- dynamic attached to kinematic with projection +- all dominant dynamic (has projecting constraints and all of them are one-way towards this dynamic) +---- all the ones above are guaranteed tree roots +- dominant dynamic (same as above but there is at least one projecting two-way constraint as well) +- partially dominant dynamic (has at least one projecting one-way constraints towards this dynamic and at least one projecting one-way constraints towards an other body) +- dynamic attached to static/world without projection +- dynamic attached to kinematic without projection +- dynamic with or without two-way projecting constraints to other dynamics (among these, the one with the highest connectivity count wins) + +for the first three priority types sorted according to rank: +create a projection tree root and grow the tree one connectivity layer at a time + +do the same for dominant dynamic bodies that have not been visited/discovered yet + +for all remaining bodies sorted according to rank: +if the body still hasn't been visited/discovered start a projection tree there and build the whole tree in one go +before moving to the next potential root. +*/ +void Sc::ConstraintProjectionTree::buildProjectionTrees(ConstraintGroupNode& root) +{ + PX_ASSERT(&root == root.parent); + PX_ASSERT(!root.hasProjectionTreeRoot()); + + Ps::InlineArray<BodyRank, 64> bodyRankArray PX_DEBUG_EXP("bodyRankArray"); + BodyRank br; + PxU32 constraintsToProjectCount = 0; + ConstraintGroupNode* node0 = &root; + while (node0) //for all nodes in group + { + PX_ASSERT(node0->body); + if (!node0->body->isKinematic()) + { + node0->clearFlag(ConstraintGroupNode::eDISCOVERED); + + //rank + br.startingNode = node0; + br.rank = 0; + br.constraintToFixedAnchor = 0; + PxU32 dominanceTracking = BodyRank::sAllDominantDynamic | BodyRank::sDominantDynamic; + + //go through all constraints connected to body + PxU32 size = node0->body->getActorInteractionCount(); + Sc::Interaction** interactions = node0->body->getActorInteractions(); + while(size--) + { + Interaction* interaction = *interactions++; + if (interaction->getType() == InteractionType::eCONSTRAINTSHADER) + { + ConstraintSim* c = static_cast<ConstraintInteraction*>(interaction)->getConstraint(); + rankConstraint(*c, br, dominanceTracking, constraintsToProjectCount); + } + } + + PX_ASSERT(br.rank); //if it has no constraints then why is it in the constraint group? + + if (br.rank >= BodyRank::sPrimaryTreeRootMinRank) + node0->raiseFlag(ConstraintGroupNode::eDISCOVERED); // we create a tree for each node attached to a fixed anchor, or a node which is an all dominating dynamic + // -> make sure they do not include each other + + bodyRankArray.pushBack(br); + } + else + node0->raiseFlag(ConstraintGroupNode::eDISCOVERED); // a kinematic does not get projected, it might only get projected to and it is never part of a tree. + + node0 = node0->next; + } + + root.setProjectionCountHint(constraintsToProjectCount); + + if (bodyRankArray.size()) // all of the bodies might have been switched to kinematic in which case there will be no ranked body + { + //sort bodyRankArray + + Ps::sort(&bodyRankArray.front(), bodyRankArray.size(), Ps::Greater<BodyRank>()); + + ConstraintGroupNode** nodeQueue = reinterpret_cast<ConstraintGroupNode**>(PX_ALLOC_TEMP(sizeof(ConstraintGroupNode*)*bodyRankArray.size(), "ProjectionNodeQueue")); + if (nodeQueue) + { + //build the projectionTree + + ConstraintGroupNode* firstProjectionTreeRoot = NULL; + + //go through it in sorted order + + // + // bodies attached to fixed anchors with projecting constraints or all dominant rigid dynamics should get processed first. + // For each of those we create a projection tree for sure, by extending one connectivity level from the root at a time. + // This way we make sure that scenarios like a bridge that is attached to fixed anchors at both ends breaks in the middle + // and not at one of the fixed anchors. + // + // this gets repeated for dominant dynamics. The reason for this is to cover cases where a dominant dynamic is connected to + // a higher ranked node by a chain of two-way constraints. In such a case the two-way constraint should project the dominant + // dynamic towards the higher ranked node and not start a tree on its own. + // + PxU32 brIdx = 0; + PxU32 stopIdx = bodyRankArray.size(); + PxU32 skipCount = 0; + PxU32 ranksToProcess = BodyRank::sPrimaryTreeRootMinRank; + ConstraintGroupNode** nodeQueueEnd; + ConstraintGroupNode** nodeQueueCurrent; + for(PxU32 i=0; i < 2; i++) + { + nodeQueueEnd = nodeQueue; + while((brIdx < stopIdx) && (bodyRankArray[brIdx].rank >= ranksToProcess)) + { + BodyRank& bRank = bodyRankArray[brIdx]; + PX_ASSERT((brIdx == 0) || (bRank.rank <= bodyRankArray[brIdx-1].rank)); + + ConstraintGroupNode& node = *bRank.startingNode; + PX_ASSERT(node.readFlag(ConstraintGroupNode::eDISCOVERED)); + + node.initProjectionData(NULL, bRank.constraintToFixedAnchor); + + if (bRank.rank & (BodyRank::sAttachedToStatic | BodyRank::sAttachedToKinematic)) + { + // for static/kinematic attached, the current node is already a child, so we must not traverse the neighborhood yet + // but rather add the current node to the queue. + PX_ASSERT(bRank.constraintToFixedAnchor); + *nodeQueueEnd = &node; + nodeQueueEnd++; + } + else + { + PX_ASSERT(!bRank.constraintToFixedAnchor); + PxU32 addedNodeCount = projectionTreeBuildStep(node, bRank.constraintToFixedAnchor, nodeQueueEnd); + nodeQueueEnd += addedNodeCount; + } + + node.projectionNextRoot = firstProjectionTreeRoot; + firstProjectionTreeRoot = &node; + + brIdx++; + } + + // first neighbor connectivity level has been pushed to a queue for all chosen tree roots. Now extend the trees one level at a time. + nodeQueueCurrent = nodeQueue; + while(nodeQueueCurrent != nodeQueueEnd) + { + ConstraintGroupNode* node = *nodeQueueCurrent; + PX_ASSERT(node->readFlag(ConstraintGroupNode::eDISCOVERED)); + nodeQueueCurrent++; + + PxU32 addedNodeCount = projectionTreeBuildStep(*node, node->projectionConstraint, nodeQueueEnd); + nodeQueueEnd += addedNodeCount; + } + + brIdx += skipCount; + skipCount = 0; + + // find dominant dynamics that have not been discovered yet and arrange them in a consecutive block + ranksToProcess = BodyRank::sOneWayProjection | BodyRank::sDominantDynamic; + stopIdx = brIdx; + PxU32 k = brIdx; + while((k < bodyRankArray.size()) && (bodyRankArray[k].rank >= ranksToProcess)) + { + ConstraintGroupNode* node = bodyRankArray[k].startingNode; + if (!node->readFlag(ConstraintGroupNode::eDISCOVERED)) + { + node->raiseFlag(ConstraintGroupNode::eDISCOVERED); + bodyRankArray[stopIdx] = bodyRankArray[k]; + stopIdx++; + } + else + skipCount++; + + k++; + } + } + + // + // for every body that has not been discovered yet, we build a tree. Here we do not advance one connectivity level + // at a time because there should be no fight over the nodes among equal roots anymore (or rather no fight that could + // break one-way projection in an unfair way). + // + PX_ASSERT((brIdx == 0) || (brIdx == bodyRankArray.size()) || (bodyRankArray[brIdx].rank < bodyRankArray[brIdx-1].rank)); + for(PxU32 i=brIdx; i < bodyRankArray.size(); i++) + { + nodeQueueEnd = nodeQueue; + + BodyRank& bRank = bodyRankArray[i]; + PX_ASSERT((i == brIdx) || (bRank.rank <= bodyRankArray[i-1].rank)); +#ifdef _DEBUG + if (bRank.rank & (BodyRank::sAttachedToStatic | BodyRank::sAttachedToKinematic)) + { PX_ASSERT(bRank.constraintToFixedAnchor); } + else + { PX_ASSERT(!bRank.constraintToFixedAnchor); } +#endif + + ConstraintGroupNode& node = *bRank.startingNode; + if (!node.readFlag(ConstraintGroupNode::eDISCOVERED)) + { + node.raiseFlag(ConstraintGroupNode::eDISCOVERED); + + PxU32 addedNodeCount = projectionTreeBuildStep(node, bRank.constraintToFixedAnchor, nodeQueueEnd); + nodeQueueEnd += addedNodeCount; + + nodeQueueCurrent = nodeQueue; + while(nodeQueueCurrent != nodeQueueEnd) + { + ConstraintGroupNode* n = *nodeQueueCurrent; + PX_ASSERT(n->readFlag(ConstraintGroupNode::eDISCOVERED)); + PX_ASSERT(n->projectionConstraint); + nodeQueueCurrent++; + + PxU32 nodeCount = projectionTreeBuildStep(*n, n->projectionConstraint, nodeQueueEnd); + nodeQueueEnd += nodeCount; + } + + node.projectionNextRoot = firstProjectionTreeRoot; + firstProjectionTreeRoot = &node; + } + } + + root.setProjectionTreeRoot(firstProjectionTreeRoot); + + PX_FREE(nodeQueue); + } + else + Ps::getFoundation().error(PxErrorCode::eOUT_OF_MEMORY, __FILE__, __LINE__, "Allocating projection node queue failed!"); + } +} + + +PxU32 Sc::ConstraintProjectionTree::projectionTreeBuildStep(ConstraintGroupNode& node, ConstraintSim* cToParent, ConstraintGroupNode** nodeQueue) +{ + PX_ASSERT(node.readFlag(ConstraintGroupNode::eDISCOVERED)); + + PxU32 nodeQueueFillCount = 0; + + //go through all constraints attached to the body. + BodySim* body = node.body; + PxU32 size = body->getActorInteractionCount(); + Sc::Interaction** interactions = body->getActorInteractions(); + while(size--) + { + Interaction* interaction = *interactions++; + if (interaction->getType() == InteractionType::eCONSTRAINTSHADER) + { + ConstraintSim* c = static_cast<ConstraintInteraction*>(interaction)->getConstraint(); + + if (c != cToParent) //don't go back along the edge we came from (not really necessary I guess since the ConstraintGroupNode::eDISCOVERED marker should solve this) + { + PxU32 projectToBody, projectToOtherBody; + BodySim* neighbor; + getConstraintStatus(*c, body, neighbor, projectToBody, projectToOtherBody); + + if(!isFixedBody(neighbor) && (!projectToOtherBody || projectToBody)) //just ignore the eventual constraint with environment over here. Body might be attached to multiple fixed anchors. + //Also make sure to ignore one-way projection that goes the opposite way. + { + ConstraintGroupNode* neighborNode = neighbor->getConstraintGroup(); + PX_ASSERT(neighborNode); + + if (!neighborNode->readFlag(ConstraintGroupNode::eDISCOVERED)) + { + *nodeQueue = neighborNode; + + neighborNode->initProjectionData(&node, c); + neighborNode->raiseFlag(ConstraintGroupNode::eDISCOVERED); //flag body nodes that we process so we can detect loops + + nodeQueueFillCount++; + nodeQueue++; + } + } + } + } + } + + return nodeQueueFillCount; +} + + +void Sc::ConstraintProjectionTree::purgeProjectionTrees(ConstraintGroupNode& root) +{ + PX_ASSERT(&root == root.parent); + PX_ASSERT(root.hasProjectionTreeRoot()); + + // CA: New code (non recursive: recursive calls can cause stack overflow with huge trees) + ConstraintGroupNode* projRoot = root.projectionFirstRoot; + do + { + ConstraintGroupNode* currentNode = projRoot; + projRoot = projRoot->projectionNextRoot; // need to do it here because the info might get cleared below + + do + { + // Go down the tree until we find a leaf + if (currentNode->projectionFirstChild) + { + currentNode = currentNode->projectionFirstChild; + continue; + } + + // Delete current node and go to next sibling or parent + ConstraintGroupNode* nodeToDelete = currentNode; + ConstraintGroupNode* parent = currentNode->projectionParent; + currentNode = currentNode->projectionNextSibling; + + // Mark parent as leaf + if (nodeToDelete->projectionParent) + nodeToDelete->projectionParent->projectionFirstChild = NULL; + + // Clear projection info + nodeToDelete->clearProjectionData(); + + if (currentNode != NULL) + continue; + + // No more siblings jump back to parent + currentNode = parent; + + } while (currentNode != NULL); + + } while (projRoot != NULL); + + root.projectionFirstRoot = NULL; // it can happen that the constraint graph root is not part of a projection tree (if it is a kinematic, for example) but it still points to the + // first projection tree root and that needs to get cleaned up as well. + PX_ASSERT(!root.projectionNextRoot); + PX_ASSERT(!root.projectionParent); + PX_ASSERT(!root.projectionFirstChild); + PX_ASSERT(!root.projectionNextSibling); + PX_ASSERT(!root.projectionConstraint); +} + + +void Sc::ConstraintProjectionTree::projectPoseForTree(ConstraintGroupNode& node, Ps::Array<BodySim*>& projectedBodies) +{ + // create a dummy node to keep the loops compact while covering the special case of the first node + PX_ASSERT(node.body); + ConstraintGroupNode dummyNode(*node.body); + dummyNode.projectionNextSibling = &node; + ConstraintGroupNode* currentNode = &dummyNode; + + // non recursive: recursive calls can cause stack overflow with huge trees + do + { + ConstraintGroupNode* nextSiblingNode = currentNode->projectionNextSibling; + + while (nextSiblingNode) + { + currentNode = nextSiblingNode; + ConstraintGroupNode* nextChildNode = currentNode; + + do + { + currentNode = nextChildNode; + + //----------------------------------------------------------------------------- + ConstraintSim* c = currentNode->projectionConstraint; + + if (c && c->hasDynamicBody() && c->needsProjection()) + { + c->projectPose(currentNode->body, projectedBodies); + } + //----------------------------------------------------------------------------- + + nextChildNode = currentNode->projectionFirstChild; + + } while (nextChildNode); + + nextSiblingNode = currentNode->projectionNextSibling; + } + + currentNode = currentNode->projectionParent; + + } while (currentNode != NULL); +} + + +void Sc::ConstraintProjectionTree::projectPose(ConstraintGroupNode& root, Ps::Array<BodySim*>& projectedBodies) +{ + PX_ASSERT(&root == root.parent); + PX_ASSERT(root.hasProjectionTreeRoot()); + + ConstraintGroupNode* projRoot = root.projectionFirstRoot; + do + { + projectPoseForTree(*projRoot, projectedBodies); + projRoot = projRoot->projectionNextRoot; + + } while (projRoot != NULL); +} diff --git a/PhysX_3.4/Source/SimulationController/src/ScConstraintProjectionTree.h b/PhysX_3.4/Source/SimulationController/src/ScConstraintProjectionTree.h new file mode 100644 index 00000000..47265f14 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScConstraintProjectionTree.h @@ -0,0 +1,75 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-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_CONSTRAINT_PROJECTION_TREE +#define PX_PHYSICS_SCP_CONSTRAINT_PROJECTION_TREE + +#include "PsArray.h" +#include "PsUserAllocated.h" +#include "CmPhysXCommon.h" + +namespace physx +{ +namespace Sc +{ + struct ConstraintGroupNode; + class ConstraintSim; + class BodySim; + class BodyRank; + + class ConstraintProjectionTree + { + /** + This class serves both the static administration of an articulation and the actual articulation itself. + An Articulation object holds several articulation root nodes which make up a simulation island that + is further connected with lagrange joints. + */ + public: + ConstraintProjectionTree() {} + ~ConstraintProjectionTree() {} + + static void buildProjectionTrees(ConstraintGroupNode& root); + static void purgeProjectionTrees(ConstraintGroupNode& root); + + static void projectPose(ConstraintGroupNode& root, Ps::Array<BodySim*>& projectedBodies); + + private: + static PxU32 projectionTreeBuildStep(ConstraintGroupNode& node, ConstraintSim* cToParent, ConstraintGroupNode** nodeStack); + + static void getConstraintStatus(const ConstraintSim& c, const BodySim* b, BodySim*& otherBody, PxU32& projectToBody, PxU32& projectToOtherBody); + static void rankConstraint(ConstraintSim&, BodyRank&, PxU32& dominanceTracking, PxU32& constraintsToProjectCount); + static void projectPoseForTree(ConstraintGroupNode& node, Ps::Array<BodySim*>& projectedBodies); + }; + +} // namespace Sc + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/ScConstraintSim.cpp b/PhysX_3.4/Source/SimulationController/src/ScConstraintSim.cpp new file mode 100644 index 00000000..3b81ebc4 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScConstraintSim.cpp @@ -0,0 +1,511 @@ +// 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 "ScScene.h" +#include "ScConstraintProjectionManager.h" +#include "ScBodySim.h" +#include "ScStaticSim.h" +#include "PxsContext.h" +#include "ScConstraintCore.h" +#include "ScConstraintSim.h" +#include "ScConstraintInteraction.h" +#include "ScRbElementInteraction.h" +#include "CmVisualization.h" +#include "ScObjectIDTracker.h" +#include "DyContext.h" + +using namespace physx; + + +PX_FORCE_INLINE void invalidateConstraintGroupsOnAdd(Sc::ConstraintProjectionManager& cpm, Sc::BodySim* b0, Sc::BodySim* b1, Sc::ConstraintSim& constraint) +{ + // constraint groups get built by starting from dirty constraints that need projection. If a non-projecting constraint gets added + // we need to restart the whole process (we do not want to track dirty non-projecting constraints because of a scenario where + // all constraints of a group get switched to non-projecting which should kill the group and not rebuild a new one). + if (b0 && b0->getConstraintGroup()) + cpm.invalidateGroup(*b0->getConstraintGroup(), &constraint); + if (b1 && b1->getConstraintGroup()) + cpm.invalidateGroup(*b1->getConstraintGroup(), &constraint); +} + + +Sc::ConstraintSim::ConstraintSim(ConstraintCore& core, RigidCore* r0, RigidCore* r1, Scene& scene) : + mScene (scene), + mCore (core), + mInteraction(NULL), + mFlags (0) +{ + + mBodies[0] = (r0 && (r0->getActorCoreType() != PxActorType::eRIGID_STATIC)) ? static_cast<BodySim*>(r0->getSim()) : 0; + mBodies[1] = (r1 && (r1->getActorCoreType() != PxActorType::eRIGID_STATIC)) ? static_cast<BodySim*>(r1->getSim()) : 0; + + mLowLevelConstraint.index = scene.getConstraintIDTracker().createID(); + Ps::Array<Dy::ConstraintWriteback, Ps::VirtualAllocator>& writeBackPool = scene.getDynamicsContext()->getConstraintWriteBackPool(); + if (mLowLevelConstraint.index >= writeBackPool.capacity()) + { + writeBackPool.reserve(writeBackPool.capacity() * 2); + } + + writeBackPool.resize(PxMax(writeBackPool.size(), mLowLevelConstraint.index + 1)); + writeBackPool[mLowLevelConstraint.index].initialize(); + + if (!createLLConstraint()) + return; + + PxReal linBreakForce, angBreakForce; + core.getBreakForce(linBreakForce, angBreakForce); + if ((linBreakForce < PX_MAX_F32) || (angBreakForce < PX_MAX_F32)) + setFlag(eBREAKABLE); + + core.setSim(this); + + ConstraintProjectionManager& cpm = scene.getProjectionManager(); + if (!needsProjection()) + invalidateConstraintGroupsOnAdd(cpm, mBodies[0], mBodies[1], *this); + else + cpm.addToPendingGroupUpdates(*this); + + ConstraintSim* cs = this; // to make the Wii U compiler happy + mInteraction = mScene.getConstraintInteractionPool()->construct(cs, + r0 ? *r0->getSim() : scene.getStaticAnchor(), + r1 ? *r1->getSim() : scene.getStaticAnchor()); + + PX_ASSERT(!mInteraction->isRegistered()); // constraint interactions must not register in the scene, there is a list of Sc::ConstraintSim instead +} + + +Sc::ConstraintSim::~ConstraintSim() +{ + PX_ASSERT(mInteraction); // This is fine now, a body which gets removed from the scene removes all constraints automatically + PX_ASSERT(!mInteraction->isRegistered()); // constraint interactions must not register in the scene, there is a list of Sc::ConstraintSim instead + + if (readFlag(ConstraintSim::ePENDING_GROUP_UPDATE)) + mScene.getProjectionManager().removeFromPendingGroupUpdates(*this); + + if (!isBroken()) + mInteraction->destroy(); + + mScene.getConstraintIDTracker().releaseID(mLowLevelConstraint.index); + mScene.getConstraintInteractionPool()->destroy(mInteraction); + + destroyLLConstraint(); + + mCore.setSim(NULL); +} + + +bool Sc::ConstraintSim::createLLConstraint() +{ + Dy::Constraint& llc = mLowLevelConstraint; + ConstraintCore& core = getCore(); + PxU32 constantBlockSize = core.getConstantBlockSize(); + + void* constantBlock = mScene.allocateConstraintBlock(constantBlockSize); + if(!constantBlock) + { + Ps::getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __LINE__, "Constraint: could not allocate low-level resources."); + return false; + } + + //Ensure the constant block isn't just random data because some functions may attempt to use it before it is + //setup. Specifically pvd visualization of joints + //-CN + + PxMemZero( constantBlock, constantBlockSize); + + core.getBreakForce(llc.linBreakForce, llc.angBreakForce); + llc.flags = PxU32(core.getFlags()); + llc.constantBlockSize = constantBlockSize; + + llc.solverPrep = core.getSolverPrep(); + llc.project = core.getProject(); + llc.constantBlock = constantBlock; + + //llc.index = mLowLevelConstraint.index; + llc.body0 = mBodies[0] ? &mBodies[0]->getLowLevelBody() : 0; + llc.body1 = mBodies[1] ? &mBodies[1]->getLowLevelBody() : 0; + llc.bodyCore0 = mBodies[0] ? &llc.body0->getCore() : NULL; + llc.bodyCore1 = mBodies[1] ? &llc.body1->getCore() : NULL; + + llc.minResponseThreshold = core.getMinResponseThreshold(); + + return true; +} + + +void Sc::ConstraintSim::destroyLLConstraint() +{ + if(mLowLevelConstraint.constantBlock) + { + mScene.deallocateConstraintBlock(mLowLevelConstraint.constantBlock, + mLowLevelConstraint.constantBlockSize); + } +} + +void Sc::ConstraintSim::preBodiesChange() +{ + PX_ASSERT(mInteraction); + + BodySim* b = getConstraintGroupBody(); + if (b) + mScene.getProjectionManager().invalidateGroup(*b->getConstraintGroup(), this); + + if (!isBroken()) + mInteraction->destroy(); + + mScene.getConstraintInteractionPool()->destroy(mInteraction); + mInteraction = NULL; +} + +void Sc::ConstraintSim::postBodiesChange(RigidCore* r0, RigidCore* r1) +{ + PX_ASSERT(mInteraction == NULL); + + BodySim* b0 = (r0 && (r0->getActorCoreType() != PxActorType::eRIGID_STATIC)) ? static_cast<BodySim*>(r0->getSim()) : 0; + BodySim* b1 = (r1 && (r1->getActorCoreType() != PxActorType::eRIGID_STATIC)) ? static_cast<BodySim*>(r1->getSim()) : 0; + + ConstraintProjectionManager& cpm = mScene.getProjectionManager(); + PxConstraintFlags::InternalType projectionNeeded = getCore().getFlags() & PxConstraintFlag::ePROJECTION; // can not use "needsProjection()" because that takes into account whether the constraint is broken + if (!projectionNeeded) + invalidateConstraintGroupsOnAdd(cpm, b0, b1, *this); + else if (!readFlag(ConstraintSim::ePENDING_GROUP_UPDATE)) + cpm.addToPendingGroupUpdates(*this); + + Dy::Constraint& c = mLowLevelConstraint; + + c.body0 = b0 ? &b0->getLowLevelBody() : NULL; + c.body1 = b1 ? &b1->getLowLevelBody() : NULL; + + c.bodyCore0 = c.body0 ? &c.body0->getCore() : NULL; + c.bodyCore1 = c.body1 ? &c.body1->getCore() : NULL; + + mBodies[0] = b0; + mBodies[1] = b1; + + ConstraintSim* cs = this; // to make the Wii U compiler happy + mInteraction = mScene.getConstraintInteractionPool()->construct(cs, + r0 ? *r0->getSim() : mScene.getStaticAnchor(), + r1 ? *r1->getSim() : mScene.getStaticAnchor()); +} + +void Sc::ConstraintSim::checkMaxForceExceeded() +{ + PX_ASSERT(readFlag(eCHECK_MAX_FORCE_EXCEEDED)); + + Dy::ConstraintWriteback& solverOutput = mScene.getDynamicsContext()->getConstraintWriteBackPool()[mLowLevelConstraint.index]; + if (solverOutput.broken) + { + setFlag(ConstraintSim::eBROKEN); + mScene.addBrokenConstraint(&mCore); + mCore.breakApart(); + mInteraction->destroy(); + + updateRelatedSIPs(); + + PX_ASSERT(!readFlag(eCHECK_MAX_FORCE_EXCEEDED)); + } +} + +void Sc::ConstraintSim::getForce(PxVec3& lin, PxVec3& ang) +{ + const PxReal recipDt = mScene.getOneOverDt(); + Dy::ConstraintWriteback& solverOutput= mScene.getDynamicsContext()->getConstraintWriteBackPool()[mLowLevelConstraint.index]; + lin = solverOutput.linearImpulse * recipDt; + ang = solverOutput.angularImpulse * recipDt; +} + +void Sc::ConstraintSim::updateRelatedSIPs() +{ + ActorSim& a0 = mInteraction->getActor0(); + ActorSim& a1 = mInteraction->getActor1(); + ActorSim& actor = (a0.getActorInteractionCount()< a1.getActorInteractionCount()) ? a0 : a1; + + actor.setActorsInteractionsDirty(InteractionDirtyFlag::eFILTER_STATE, NULL, InteractionFlag::eRB_ELEMENT); + // because broken constraints can re-enable contact response between the two bodies +} + + +void Sc::ConstraintSim::setBreakForceLL(PxReal linear, PxReal angular) +{ + PxU8 wasBreakable = readFlag(eBREAKABLE); + PxU8 isBreakable; + if ((linear < PX_MAX_F32) || (angular < PX_MAX_F32)) + isBreakable = eBREAKABLE; + else + isBreakable = 0; + + if (isBreakable != wasBreakable) + { + if (isBreakable) + { + PX_ASSERT(!readFlag(eCHECK_MAX_FORCE_EXCEEDED)); + setFlag(eBREAKABLE); + if (mInteraction->readInteractionFlag(InteractionFlag::eIS_ACTIVE)) + mScene.addActiveBreakableConstraint(this, mInteraction); + } + else + { + if (readFlag(eCHECK_MAX_FORCE_EXCEEDED)) + mScene.removeActiveBreakableConstraint(this); + clearFlag(eBREAKABLE); + } + } + + mLowLevelConstraint.linBreakForce = linear; + mLowLevelConstraint.angBreakForce = angular; +} + + +void Sc::ConstraintSim::postFlagChange(PxConstraintFlags oldFlags, PxConstraintFlags newFlags) +{ + mLowLevelConstraint.flags = newFlags; + + // PT: don't convert to bool if not needed + const PxU32 hadProjection = (oldFlags & PxConstraintFlag::ePROJECTION); + const PxU32 needsProjection = (newFlags & PxConstraintFlag::ePROJECTION); + + if(needsProjection && !hadProjection) + { + PX_ASSERT(!readFlag(ConstraintSim::ePENDING_GROUP_UPDATE)); // Non-projecting constrainst should not be part of the update list + + Sc::BodySim* b0 = getBody(0); + Sc::BodySim* b1 = getBody(1); + if ((!b0 || b0->getConstraintGroup()) && (!b1 || b1->getConstraintGroup())) + { + // Already part of a constraint group but not as a projection constraint -> re-generate projection tree + PX_ASSERT(b0 != NULL || b1 != NULL); + if (b0) + b0->getConstraintGroup()->markForProjectionTreeRebuild(mScene.getProjectionManager()); + else + b1->getConstraintGroup()->markForProjectionTreeRebuild(mScene.getProjectionManager()); + } + else + { + // Not part of a constraint group yet + mScene.getProjectionManager().addToPendingGroupUpdates(*this); + } + } + else if(!needsProjection && hadProjection) + { + if (!readFlag(ConstraintSim::ePENDING_GROUP_UPDATE)) + { + Sc::BodySim* b = getConstraintGroupBody(); + if (b) + { + PX_ASSERT(b->getConstraintGroup()); + mScene.getProjectionManager().invalidateGroup(*b->getConstraintGroup(), NULL); + } + // This is conservative but it could be the case that this constraint with projection was the only + // one in the group and thus the whole group must be killed. If we had a counter for the number of + // projecting constraints per group, we could just update the projection tree if the counter was + // larger than 1. But switching the projection flag does not seem likely anyway. + } + else + mScene.getProjectionManager().removeFromPendingGroupUpdates(*this); // Was part of a group which got invalidated + + PX_ASSERT(!readFlag(ConstraintSim::ePENDING_GROUP_UPDATE)); // make sure the expected post-condition is met for all paths + } +} + + +Sc::RigidSim& Sc::ConstraintSim::getRigid(PxU32 i) +{ + PX_ASSERT(mInteraction); + + if (i == 0) + return static_cast<RigidSim&>(mInteraction->getActor0()); + else + return static_cast<RigidSim&>(mInteraction->getActor1()); +} + + +bool Sc::ConstraintSim::hasDynamicBody() +{ + return (mBodies[0] && (!mBodies[0]->isKinematic())) || (mBodies[1] && (!mBodies[1]->isKinematic())); +} + +bool Sc::ConstraintSim::isBroken() const +{ + return !!(mFlags & ConstraintSim::eBROKEN); +} + +static void constrainMotion(PxsRigidBody* body, PxTransform& targetPose) +{ + //Now constraint deltaPos and deltaRot + PxU32 lockFlags = body->mCore->lockFlags; + + if (lockFlags) + { + const PxTransform& currBody2World = body->mCore->body2World; + + PxVec3 deltaPos = targetPose.p - currBody2World.p; + + PxQuat deltaQ = targetPose.q * currBody2World.q.getConjugate(); + + if (deltaQ.w < 0) //shortest angle. + deltaQ = -deltaQ; + + PxReal angle; + PxVec3 axis; + deltaQ.toRadiansAndUnitAxis(angle, axis); + PxVec3 deltaRot = axis * angle; + + if (lockFlags & PxRigidDynamicLockFlag::eLOCK_LINEAR_X) + deltaPos.x = 0.f; + if (lockFlags & PxRigidDynamicLockFlag::eLOCK_LINEAR_Y) + deltaPos.y = 0.f; + if (lockFlags & PxRigidDynamicLockFlag::eLOCK_LINEAR_Z) + deltaPos.z = 0.f; + if (lockFlags & PxRigidDynamicLockFlag::eLOCK_ANGULAR_X) + deltaRot.x = 0.f; + if (lockFlags & PxRigidDynamicLockFlag::eLOCK_ANGULAR_Y) + deltaRot.y = 0.f; + if (lockFlags & PxRigidDynamicLockFlag::eLOCK_ANGULAR_Z) + deltaRot.z = 0.f; + + targetPose.p = currBody2World.p + deltaPos; + + + PxReal w2 = deltaRot.magnitudeSquared(); + if (w2 != 0.f) + { + PxReal w = PxSqrt(w2); + + const PxReal v = w * 0.5f; + PxReal s, q; + Ps::sincos(v, s, q); + s /= w; + + const PxVec3 pqr = deltaRot * s; + const PxQuat quatVel(pqr.x, pqr.y, pqr.z, 0); + PxQuat result = quatVel * currBody2World.q; + + result += currBody2World.q * q; + + targetPose.q = result.getNormalized(); + } + else + { + targetPose.q = currBody2World.q; + } + } + + + +} + +void Sc::ConstraintSim::projectPose(BodySim* childBody, Ps::Array<BodySim*>& projectedBodies) +{ +#if PX_DEBUG + // We expect bodies in low level constraints to have same order as high level counterpart + PxsRigidBody* b0 = mLowLevelConstraint.body0; + PxsRigidBody* b1 = mLowLevelConstraint.body1; + PX_ASSERT( (childBody == getBody(0) && &childBody->getLowLevelBody() == b0) || + (childBody == getBody(1) && &childBody->getLowLevelBody() == b1) ); +#endif + + Dy::Constraint& constraint = getLowLevelConstraint(); + bool projectToBody0 = childBody == getBody(1); + + PxsRigidBody* body0 = constraint.body0, + * body1 = constraint.body1; + + PxTransform body0ToWorld = body0 ? body0->getPose() : PxTransform(PxIdentity); + PxTransform body1ToWorld = body1 ? body1->getPose() : PxTransform(PxIdentity); + + (*constraint.project)(constraint.constantBlock, body0ToWorld, body1ToWorld, projectToBody0); + + if(projectToBody0) + { + PX_ASSERT(body1); + //Constrain new pose to valid world motion + constrainMotion(body1, body1ToWorld); + body1->setPose(body1ToWorld); + projectedBodies.pushBack(getBody(1)); + } + else + { + PX_ASSERT(body0); + //Constrain new pose to valid world motion + constrainMotion(body0, body0ToWorld); + body0->setPose(body0ToWorld); + projectedBodies.pushBack(getBody(0)); + } +} + + +bool Sc::ConstraintSim::needsProjection() +{ + Dy::ConstraintWriteback& solverOutput = mScene.getDynamicsContext()->getConstraintWriteBackPool()[mLowLevelConstraint.index]; + return (getCore().getFlags() & PxConstraintFlag::ePROJECTION ) && !solverOutput.broken; +} + + +PX_INLINE Sc::BodySim* Sc::ConstraintSim::getConstraintGroupBody() +{ + BodySim* b = NULL; + if (mBodies[0] && mBodies[0]->getConstraintGroup()) + b = mBodies[0]; + else if (mBodies[1] && mBodies[1]->getConstraintGroup()) + b = mBodies[1]; + + return b; +} + + +void Sc::ConstraintSim::visualize(PxRenderBuffer& output) +{ + if (!(getCore().getFlags() & PxConstraintFlag::eVISUALIZATION)) + return; + + PxsRigidBody* b0 = mLowLevelConstraint.body0; + PxsRigidBody* b1 = mLowLevelConstraint.body1; + + const PxTransform& t0 = b0 ? b0->getPose() : PxTransform(PxIdentity); + const PxTransform& t1 = b1 ? b1->getPose() : PxTransform(PxIdentity); + + PxReal frameScale = mScene.getVisualizationScale() * mScene.getVisualizationParameter(PxVisualizationParameter::eJOINT_LOCAL_FRAMES); + PxReal limitScale = mScene.getVisualizationScale() * mScene.getVisualizationParameter(PxVisualizationParameter::eJOINT_LIMITS); + + Cm::RenderOutput renderOut( static_cast<Cm::RenderBuffer &>( output ) ); + Cm::ConstraintImmediateVisualizer viz( frameScale, limitScale, renderOut ); + + mCore.getVisualize()(viz, mLowLevelConstraint.constantBlock, t0, t1, + PxConstraintVisualizationFlag::eLOCAL_FRAMES | PxConstraintVisualizationFlag::eLIMITS); +} + + +void Sc::ConstraintSim::setConstantsLL(void* addr) +{ + PxMemCopy(mLowLevelConstraint.constantBlock, addr, mLowLevelConstraint.constantBlockSize); + + getAnyBody()->getScene().getSimulationController()->updateJoint(mInteraction->getEdgeIndex(), &mLowLevelConstraint); + +} diff --git a/PhysX_3.4/Source/SimulationController/src/ScConstraintSim.h b/PhysX_3.4/Source/SimulationController/src/ScConstraintSim.h new file mode 100644 index 00000000..35dc3ca4 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScConstraintSim.h @@ -0,0 +1,156 @@ +// 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_CONSTRAINT_SIM +#define PX_PHYSICS_CONSTRAINT_SIM + +#include "PxSimulationEventCallback.h" +#include "DyConstraint.h" + +namespace physx +{ +namespace Sc +{ + + class Scene; + class ConstraintInteraction; + class ConstraintCore; + class RigidCore; + class BodySim; + class RigidSim; + + class ConstraintSim : public Ps::UserAllocated + { + public: + enum Enum + { + ePENDING_GROUP_UPDATE = (1<<0), // For constraint projection an island of the bodies connected by constraints is generated. + // Schedule generation/update of the island this constraint is a part of. + eBREAKABLE = (1<<1), // The constraint can break + eCHECK_MAX_FORCE_EXCEEDED = (1<<2), // This constraint will get tested for breakage at the end of the sim step + eBROKEN = (1<<3) + }; + + ConstraintSim(ConstraintCore& core, + RigidCore* r0, + RigidCore* r1, + Scene& scene); + + ~ConstraintSim(); + + void preBodiesChange(); + void postBodiesChange(RigidCore* r0, RigidCore* r1); + + void checkMaxForceExceeded(); + void updateRelatedSIPs(); + + void setBreakForceLL(PxReal linear, PxReal angular); + PX_INLINE void setMinResponseThresholdLL(PxReal threshold); + void setConstantsLL(void* addr); + PX_INLINE const void* getConstantsLL() const; + + void postFlagChange(PxConstraintFlags oldFlags, PxConstraintFlags newFlags); + + PX_FORCE_INLINE const Dy::Constraint& getLowLevelConstraint() const { return mLowLevelConstraint; } + PX_FORCE_INLINE Dy::Constraint& getLowLevelConstraint() { return mLowLevelConstraint; } + PX_FORCE_INLINE ConstraintCore& getCore() const { return mCore; } + PX_FORCE_INLINE BodySim* getBody(PxU32 i) const // for static actors or world attached constraints NULL is returned + { + return mBodies[i]; + } + + RigidSim& getRigid(PxU32 i); + + void getForce(PxVec3& force, PxVec3& torque); + bool isBroken() const; + + PX_FORCE_INLINE PxU8 readFlag(PxU8 flag) const { return PxU8(mFlags & flag); } + PX_FORCE_INLINE void setFlag(PxU8 flag) { mFlags |= flag; } + PX_FORCE_INLINE void clearFlag(PxU8 flag) { mFlags &= ~flag; } + + + //------------------------------------ Projection trees ----------------------------------------- + private: + PX_INLINE BodySim* getConstraintGroupBody(); + + public: + bool hasDynamicBody(); + + void projectPose(BodySim* childBody, Ps::Array<BodySim*>& projectedBodies); + PX_INLINE BodySim* getOtherBody(BodySim*); + PX_INLINE BodySim* getAnyBody(); + + bool needsProjection(); + //----------------------------------------------------------------------------------------------- + + void visualize(PxRenderBuffer &out); + private: + ConstraintSim& operator=(const ConstraintSim&); + bool createLLConstraint(); + void destroyLLConstraint(); + private: + Dy::Constraint mLowLevelConstraint; + Scene& mScene; + ConstraintCore& mCore; + ConstraintInteraction* mInteraction; + BodySim* mBodies[2]; + PxU8 mFlags; + }; +} // namespace Sc + + +PX_INLINE void Sc::ConstraintSim::setMinResponseThresholdLL(PxReal threshold) +{ + mLowLevelConstraint.minResponseThreshold = threshold; +} + +PX_INLINE const void* Sc::ConstraintSim::getConstantsLL() const +{ + return mLowLevelConstraint.constantBlock; +} + + +PX_INLINE Sc::BodySim* Sc::ConstraintSim::getOtherBody(BodySim* b) +{ + return (b == mBodies[0]) ? mBodies[1] : mBodies[0]; +} + + +PX_INLINE Sc::BodySim* Sc::ConstraintSim::getAnyBody() +{ + if (mBodies[0]) + return mBodies[0]; + else + return mBodies[1]; +} + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/ScContactReportBuffer.h b/PhysX_3.4/Source/SimulationController/src/ScContactReportBuffer.h new file mode 100644 index 00000000..3aabde1c --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScContactReportBuffer.h @@ -0,0 +1,172 @@ +// 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_CONTACTREPORTBUFFER +#define PX_PHYSICS_SCP_CONTACTREPORTBUFFER + +#include "foundation/Px.h" + +namespace physx +{ + namespace Sc + { + class ContactReportBuffer + { + public: + PX_FORCE_INLINE ContactReportBuffer(PxU32 initialSize, bool noResizeAllowed) + : mBuffer(NULL) + ,mCurrentBufferIndex(0) + ,mCurrentBufferSize(initialSize) + ,mDefaultBufferSize(initialSize) + ,mLastBufferIndex(0) + ,mAllocationLocked(noResizeAllowed) + { + mBuffer = allocateBuffer(initialSize); + PX_ASSERT(mBuffer); + } + + ~ContactReportBuffer() + { + PX_FREE(mBuffer); + } + + PX_FORCE_INLINE void reset(); + PX_FORCE_INLINE void flush(); + + PX_FORCE_INLINE PxU8* allocateNotThreadSafe(PxU32 size, PxU32& index, PxU32 alignment= 16); + PX_FORCE_INLINE PxU8* reallocateNotThreadSafe(PxU32 size, PxU32& index, PxU32 alignment= 16, PxU32 lastIndex = 0xFFFFFFFF); + PX_FORCE_INLINE PxU8* getData(const PxU32& index) const { return mBuffer+index; } + + PX_FORCE_INLINE PxU32 getDefaultBufferSize() const {return mDefaultBufferSize;} + + private: + PX_FORCE_INLINE PxU8* allocateBuffer(PxU32 size); + + private: + PxU8* mBuffer; + PxU32 mCurrentBufferIndex; + PxU32 mCurrentBufferSize; + PxU32 mDefaultBufferSize; + PxU32 mLastBufferIndex; + bool mAllocationLocked; + }; + + } // namespace Sc + + ////////////////////////////////////////////////////////////////////////// + + PX_FORCE_INLINE void Sc::ContactReportBuffer::reset() + { + mCurrentBufferIndex = 0; + mLastBufferIndex = 0xFFFFFFFF; + } + + ////////////////////////////////////////////////////////////////////////// + + void Sc::ContactReportBuffer::flush() + { + mCurrentBufferIndex = 0; + mLastBufferIndex = 0xFFFFFFFF; + + if(mCurrentBufferSize != mDefaultBufferSize) + { + PX_FREE(mBuffer); + + mBuffer = allocateBuffer(mDefaultBufferSize); + PX_ASSERT(mBuffer); + + mCurrentBufferSize = mDefaultBufferSize; + } + } + + ////////////////////////////////////////////////////////////////////////// + + PxU8* Sc::ContactReportBuffer::allocateNotThreadSafe(PxU32 size, PxU32& index ,PxU32 alignment/* =16 */) + { + PX_ASSERT(shdfnd::isPowerOfTwo(alignment)); + + // padding for alignment + PxU32 pad = ((mCurrentBufferIndex+alignment-1)&~(alignment-1)) - mCurrentBufferIndex; + + index = mCurrentBufferIndex + pad; + + if (index + size > mCurrentBufferSize) + { + if(mAllocationLocked) + return NULL; + + PxU32 oldBufferSize = mCurrentBufferSize; + while(index + size > mCurrentBufferSize) + { + mCurrentBufferSize *= 2; + } + + PxU8* tempBuffer = allocateBuffer(mCurrentBufferSize); + + PxMemCopy(tempBuffer,mBuffer,oldBufferSize); + + PX_FREE(mBuffer); + + mBuffer = tempBuffer; + } + + + PxU8* ptr = mBuffer + index; + mLastBufferIndex = index; + PX_ASSERT((reinterpret_cast<size_t>(ptr)&(alignment-1)) == 0); + mCurrentBufferIndex += size + pad; + return ptr; + } + + ////////////////////////////////////////////////////////////////////////// + + PxU8* Sc::ContactReportBuffer::reallocateNotThreadSafe(PxU32 size, PxU32& index ,PxU32 alignment/* =16 */, PxU32 lastIndex) + { + if(lastIndex != mLastBufferIndex) + { + return allocateNotThreadSafe(size,index,alignment); + } + else + { + mCurrentBufferIndex = mLastBufferIndex; + return allocateNotThreadSafe(size,index,alignment); + } + } + + ////////////////////////////////////////////////////////////////////////// + + PX_FORCE_INLINE PxU8* Sc::ContactReportBuffer::allocateBuffer(PxU32 size) + { + return (static_cast<PxU8*>(PX_ALLOC(size, "ContactReportBuffer"))); + } + +} // namespace physx + +#endif // PX_PHYSICS_SCP_CONTACTREPORTBUFFER diff --git a/PhysX_3.4/Source/SimulationController/src/ScContactStream.h b/PhysX_3.4/Source/SimulationController/src/ScContactStream.h new file mode 100644 index 00000000..163f119c --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScContactStream.h @@ -0,0 +1,422 @@ +// 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_CONTACTSTREAM +#define PX_PHYSICS_SCP_CONTACTSTREAM + +#include "foundation/Px.h" +#include "PxSimulationEventCallback.h" +#include "ScObjectIDTracker.h" +#include "ScRigidSim.h" +#include "ScStaticSim.h" +#include "ScBodySim.h" + +namespace physx +{ + class PxShape; + +namespace Sc +{ + class ActorPair; + + + // Internal counterpart of PxContactPair + struct ContactShapePair + { + public: + PxShape* shapes[2]; + const PxU8* contactPatches; + const PxU8* contactPoints; + const PxReal* contactForces; + PxU32 requiredBufferSize; + PxU8 contactCount; + PxU8 patchCount; + PxU16 constraintStreamSize; + PxU16 flags; + PxU16 events; + PxU32 shapeID[2]; + //26 (or 38 on 64bit) + }; + PX_COMPILE_TIME_ASSERT(sizeof(ContactShapePair) == sizeof(PxContactPair)); + + struct ContactStreamManagerFlag + { + enum Enum + { + /** + \brief Need to test stream for shapes that were removed from the actor/scene + + Usually this is the case when a shape gets removed from the scene, however, other operations that remove the + broadphase volume of a pair object have to be considered as well since the shape might get removed later after such an + operation. The scenarios to consider are: + + \li shape gets removed (this includes raising PxActorFlag::eDISABLE_SIMULATION) + \li shape switches to eSCENE_QUERY_SHAPE only + \li shape switches to eTRIGGER_SHAPE + \li resetFiltering() + \li actor gets removed from an aggregate + + */ + eTEST_FOR_REMOVED_SHAPES = (1<<0), + + /** + \brief Invalid stream memory not allocated + */ + eINVALID_STREAM = (1<<1), + + /** + \brief Incomplete stream will be reported + */ + eINCOMPLETE_STREAM = (1<<2), + + /** + \brief The stream contains extra data with PxContactPairVelocity items where the post solver velocity needs to get written to. + Only valid for discrete collision (in CCD the post response velocity is available immediately). + */ + eNEEDS_POST_SOLVER_VELOCITY = (1<<3), + + /** + \brief Contains pairs that lost touch + + This info is used as an optimization to only parse the stream and check for removed shapes if there is a potential for + having removed shapes in the stream that won't get detected in any other way. For example, there is the scenario where + during the simulation a pair loses AABB touch and gets deleted. At that point a lost touch event might get written to the + stream. If at fetchResults a buffered shape removal takes place, and that shape was part of the mentioned pair, there is + no way any longer to make the connection to the corresponding event stream (since the pair has been deleted during the sim). + */ + eHAS_PAIRS_THAT_LOST_TOUCH = (1<<4), + + /** + \brief Marker for the next available free flag + */ + eNEXT_FREE_FLAG = (1<<5) + }; + }; + + struct ContactStreamHeader + { + PxU16 contactPass; // marker for extra data to know when a new collison pass started (discrete collision -> CCD pass 1 -> CCD pass 2 -> ...) + PxU16 pad; // to keep the stream 4byte aligned + }; + + /** + \brief Contact report logic and data management. + + The internal contact report stream has the following format: + + ContactStreamHeader | PxContactPairIndex0 | (PxContactPairPose0, PxContactPairVelocity0) | ... | PxContactPairIndexN | (PxContactPairPoseN, PxContactPairVelocityN) | (unused memory up to maxExtraDataSize ) | + PxContactPair0 | ... | PxContactPairM | (unsued pairs up to maxPairCount) + */ + class ContactStreamManager + { + public: + PX_FORCE_INLINE ContactStreamManager() : maxPairCount(0), flags_and_maxExtraDataBlocks(0) {} + PX_FORCE_INLINE ~ContactStreamManager() {} + + PX_FORCE_INLINE void reset(); + + PX_FORCE_INLINE PxU16 getFlags() const; + PX_FORCE_INLINE void raiseFlags(PxU16 flags); + PX_FORCE_INLINE void clearFlags(PxU16 flags); + + PX_FORCE_INLINE PxU32 getMaxExtraDataSize() const; + PX_FORCE_INLINE void setMaxExtraDataSize(PxU32 size); // size in bytes (will translate into blocks internally) + + PX_FORCE_INLINE Sc::ContactShapePair* getShapePairs(PxU8* contactReportPairData) const; + + PX_FORCE_INLINE static void convertDeletedShapesInContactStream(ContactShapePair*, PxU32 pairCount, const ObjectIDTracker&); + + PX_FORCE_INLINE static PxU32 computeExtraDataBlockCount(PxU32 extraDataSize); + PX_FORCE_INLINE static PxU32 computeExtraDataBlockSize(PxU32 extraDataSize); + PX_FORCE_INLINE static PxU16 computeContactReportExtraDataSize(PxU32 extraDataFlags, bool addHeader); + PX_FORCE_INLINE static void fillInContactReportExtraData(PxContactPairVelocity*, PxU32 index, const RigidSim&, bool isCCDPass); + PX_FORCE_INLINE static void fillInContactReportExtraData(PxContactPairPose*, PxU32 index, const RigidSim&, bool isCCDPass, const bool useCurrentTransform); + PX_FORCE_INLINE void fillInContactReportExtraData(PxU8* stream, PxU32 extraDataFlags, const RigidSim&, const RigidSim&, PxU32 ccdPass, const bool useCurrentTransform, PxU32 pairIndex, PxU32 sizeOffset); + PX_FORCE_INLINE void setContactReportPostSolverVelocity(PxU8* stream, const RigidSim&, const RigidSim&); + + PxU32 bufferIndex; // marks the start of the shape pair stream of the actor pair (byte offset with respect to global contact buffer stream) + PxU16 maxPairCount; // used to reserve the same amount of memory as in the last frame (as an initial guess) + PxU16 currentPairCount; // number of shape pairs stored in the buffer + PxU16 extraDataSize; // size of the extra data section in the stream + private: + PxU16 flags_and_maxExtraDataBlocks; // used to reserve the same amount of memory as in the last frame (as an initial guess) + + public: + static const PxU32 sExtraDataBlockSizePow2 = 4; // extra data gets allocated as a multiple of 2^sExtraDataBlockSizePow2 to keep memory low of this struct. + static const PxU32 sFlagMask = (ContactStreamManagerFlag::eNEXT_FREE_FLAG - 1); + static const PxU32 sMaxExtraDataShift = 5; // shift necessary to extract the maximum number of blocks allocated for extra data + + PX_COMPILE_TIME_ASSERT(ContactStreamManagerFlag::eNEXT_FREE_FLAG == (1 << sMaxExtraDataShift)); + }; + +} // namespace Sc + + +PX_FORCE_INLINE void Sc::ContactStreamManager::reset() +{ + currentPairCount = 0; + extraDataSize = 0; + flags_and_maxExtraDataBlocks &= ~sFlagMask; +} + + +PX_FORCE_INLINE PxU16 Sc::ContactStreamManager::getFlags() const +{ + return (flags_and_maxExtraDataBlocks & sFlagMask); +} + + +PX_FORCE_INLINE void Sc::ContactStreamManager::raiseFlags(PxU16 flags) +{ + PX_ASSERT(flags < ContactStreamManagerFlag::eNEXT_FREE_FLAG); + + flags_and_maxExtraDataBlocks |= flags; +} + + +PX_FORCE_INLINE void Sc::ContactStreamManager::clearFlags(PxU16 flags) +{ + PX_ASSERT(flags < ContactStreamManagerFlag::eNEXT_FREE_FLAG); + + PxU16 tmpFlags = getFlags(); + tmpFlags &= ~flags; + flags_and_maxExtraDataBlocks &= ~sFlagMask; + raiseFlags(tmpFlags); +} + + +PX_FORCE_INLINE PxU32 Sc::ContactStreamManager::getMaxExtraDataSize() const +{ + return PxU32((flags_and_maxExtraDataBlocks >> sMaxExtraDataShift) << sExtraDataBlockSizePow2); +} + + +PX_FORCE_INLINE void Sc::ContactStreamManager::setMaxExtraDataSize(PxU32 size) +{ + PxU32 nbBlocks = computeExtraDataBlockCount(size); + flags_and_maxExtraDataBlocks = Ps::to16((flags_and_maxExtraDataBlocks & sFlagMask) | (nbBlocks << sMaxExtraDataShift)); +} + + +PX_FORCE_INLINE Sc::ContactShapePair* Sc::ContactStreamManager::getShapePairs(PxU8* contactReportPairData) const +{ + return reinterpret_cast<Sc::ContactShapePair*>(contactReportPairData + getMaxExtraDataSize()); +} + + +PX_FORCE_INLINE void Sc::ContactStreamManager::convertDeletedShapesInContactStream(ContactShapePair* shapePairs, PxU32 pairCount, const ObjectIDTracker& tracker) +{ + for(PxU32 i=0; i < pairCount; i++) + { + ContactShapePair& csp = shapePairs[i]; + + PxU32 shape0ID = csp.shapeID[0]; + PxU32 shape1ID = csp.shapeID[1]; + + PxU16 flags = csp.flags; + PX_COMPILE_TIME_ASSERT(sizeof(flags) == sizeof((reinterpret_cast<ContactShapePair*>(0))->flags)); + + if (tracker.isDeletedID(shape0ID)) + flags |= PxContactPairFlag::eREMOVED_SHAPE_0; + if (tracker.isDeletedID(shape1ID)) + flags |= PxContactPairFlag::eREMOVED_SHAPE_1; + + csp.flags = flags; + } +} + + +PX_FORCE_INLINE PxU32 Sc::ContactStreamManager::computeExtraDataBlockCount(PxU32 extraDataSize_) +{ + PxU32 nbBlocks; + if (extraDataSize_ & ((1 << sExtraDataBlockSizePow2) - 1)) // not a multiple of block size -> need one block more + nbBlocks = (extraDataSize_ >> sExtraDataBlockSizePow2) + 1; + else + nbBlocks = (extraDataSize_ >> sExtraDataBlockSizePow2); + + return nbBlocks; +} + + +PX_FORCE_INLINE PxU32 Sc::ContactStreamManager::computeExtraDataBlockSize(PxU32 extraDataSize_) +{ + return (computeExtraDataBlockCount(extraDataSize_) << sExtraDataBlockSizePow2); +} + + +PX_FORCE_INLINE PxU16 Sc::ContactStreamManager::computeContactReportExtraDataSize(PxU32 extraDataFlags, bool addHeader) +{ + PX_ASSERT(extraDataFlags); + + PxU16 extraDataSize_ = sizeof(PxContactPairIndex); + if (extraDataFlags & PxPairFlag::ePRE_SOLVER_VELOCITY) + extraDataSize_ += sizeof(PxContactPairVelocity); + if (extraDataFlags & PxPairFlag::ePOST_SOLVER_VELOCITY) + extraDataSize_ += sizeof(PxContactPairVelocity); + if (extraDataFlags & PxPairFlag::eCONTACT_EVENT_POSE) + extraDataSize_ += sizeof(PxContactPairPose); + if (addHeader) + extraDataSize_ += sizeof(ContactStreamHeader); + return extraDataSize_; +} + + +PX_FORCE_INLINE void Sc::ContactStreamManager::fillInContactReportExtraData(PxContactPairVelocity* cpVel, PxU32 index, const RigidSim& rs, bool isCCDPass) +{ + if (rs.getActorType() != PxActorType::eRIGID_STATIC) + { + const BodySim& bs = static_cast<const BodySim&>(rs); + if ((!isCCDPass) || (cpVel->type == PxContactPairExtraDataType::ePOST_SOLVER_VELOCITY)) + { + const BodyCore& bc = bs.getBodyCore(); + cpVel->linearVelocity[index] = bc.getLinearVelocity(); + cpVel->angularVelocity[index] = bc.getAngularVelocity(); + } + else + { + PX_ASSERT(cpVel->type == PxContactPairExtraDataType::ePRE_SOLVER_VELOCITY); + const Cm::SpatialVector& vel = bs.getLowLevelBody().getPreSolverVelocities(); + cpVel->linearVelocity[index] = vel.linear; + cpVel->angularVelocity[index] = vel.angular; + } + } + else + { + cpVel->linearVelocity[index] = PxVec3(0.0f); + cpVel->angularVelocity[index] = PxVec3(0.0f); + } +} + + +PX_FORCE_INLINE void Sc::ContactStreamManager::fillInContactReportExtraData(PxContactPairPose* cpPose, PxU32 index, const RigidSim& rs, bool isCCDPass, const bool useCurrentTransform) +{ + if (rs.getActorType() != PxActorType::eRIGID_STATIC) + { + const BodySim& bs = static_cast<const BodySim&>(rs); + const BodyCore& bc = bs.getBodyCore(); + + if (!isCCDPass) + { + if (useCurrentTransform) + cpPose->globalPose[index] = bc.getBody2World() * bc.getBody2Actor().getInverse(); + else + cpPose->globalPose[index] = bs.getLowLevelBody().getLastCCDTransform() * bc.getBody2Actor().getInverse(); + } + else + cpPose->globalPose[index] = bs.getLowLevelBody().getLastCCDTransform() * bc.getBody2Actor().getInverse(); + + } + else + { + const StaticSim& ss = static_cast<const StaticSim&>(rs); + const StaticCore& sc = ss.getStaticCore(); + cpPose->globalPose[index] = sc.getActor2World(); + } +} + + +PX_FORCE_INLINE void Sc::ContactStreamManager::fillInContactReportExtraData(PxU8* stream, PxU32 extraDataFlags, const RigidSim& rs0, const RigidSim& rs1, PxU32 ccdPass, const bool useCurrentTransform, + PxU32 pairIndex, PxU32 sizeOffset) +{ + ContactStreamHeader* strHeader = reinterpret_cast<ContactStreamHeader*>(stream); + strHeader->contactPass = Ps::to16(ccdPass); + + stream += sizeOffset; + PxU8* edStream = stream; + bool isCCDPass = (ccdPass != 0); + + { + PxContactPairIndex* cpIndex = reinterpret_cast<PxContactPairIndex*>(edStream); + cpIndex->type = PxContactPairExtraDataType::eCONTACT_PAIR_INDEX; + cpIndex->index = Ps::to16(pairIndex); + edStream += sizeof(PxContactPairIndex); + + PX_ASSERT(edStream <= reinterpret_cast<PxU8*>(getShapePairs(stream))); + } + + // Important: make sure this one is the first after the PxContactPairIndex item for discrete contacts as it needs to get filled in before the reports get sent + // (post solver velocity is not available when it gets created) + if (extraDataFlags & PxPairFlag::ePOST_SOLVER_VELOCITY) + { + PxContactPairVelocity* cpVel = reinterpret_cast<PxContactPairVelocity*>(edStream); + cpVel->type = PxContactPairExtraDataType::ePOST_SOLVER_VELOCITY; + edStream += sizeof(PxContactPairVelocity); + + if (!isCCDPass) + raiseFlags(ContactStreamManagerFlag::eNEEDS_POST_SOLVER_VELOCITY); // don't know the post solver velocity yet + else + { + ContactStreamManager::fillInContactReportExtraData(cpVel, 0, rs0, true); + ContactStreamManager::fillInContactReportExtraData(cpVel, 1, rs1, true); + } + + PX_ASSERT(edStream <= reinterpret_cast<PxU8*>(getShapePairs(stream))); + } + if (extraDataFlags & PxPairFlag::ePRE_SOLVER_VELOCITY) + { + PxContactPairVelocity* cpVel = reinterpret_cast<PxContactPairVelocity*>(edStream); + cpVel->type = PxContactPairExtraDataType::ePRE_SOLVER_VELOCITY; + ContactStreamManager::fillInContactReportExtraData(cpVel, 0, rs0, isCCDPass); + ContactStreamManager::fillInContactReportExtraData(cpVel, 1, rs1, isCCDPass); + edStream += sizeof(PxContactPairVelocity); + + PX_ASSERT(edStream <= reinterpret_cast<PxU8*>(getShapePairs(stream))); + } + if (extraDataFlags & PxPairFlag::eCONTACT_EVENT_POSE) + { + PxContactPairPose* cpPose = reinterpret_cast<PxContactPairPose*>(edStream); + cpPose->type = PxContactPairExtraDataType::eCONTACT_EVENT_POSE; + ContactStreamManager::fillInContactReportExtraData(cpPose, 0, rs0, isCCDPass, useCurrentTransform); + ContactStreamManager::fillInContactReportExtraData(cpPose, 1, rs1, isCCDPass, useCurrentTransform); + edStream += sizeof(PxContactPairPose); + + PX_ASSERT(edStream <= reinterpret_cast<PxU8*>(getShapePairs(stream))); + } + + extraDataSize = Ps::to16(sizeOffset + PxU32(edStream - stream)); +} + + +PX_FORCE_INLINE void Sc::ContactStreamManager::setContactReportPostSolverVelocity(PxU8* stream, const RigidSim& rs0, const RigidSim& rs1) +{ + PX_ASSERT(extraDataSize > (sizeof(ContactStreamHeader) + sizeof(PxContactPairIndex))); + PxContactPairVelocity* cpVel = reinterpret_cast<PxContactPairVelocity*>(stream + sizeof(ContactStreamHeader) + sizeof(PxContactPairIndex)); + PX_ASSERT(cpVel->type == PxContactPairExtraDataType::ePOST_SOLVER_VELOCITY); + + fillInContactReportExtraData(cpVel, 0, rs0, false); + fillInContactReportExtraData(cpVel, 1, rs1, false); + + clearFlags(ContactStreamManagerFlag::eNEEDS_POST_SOLVER_VELOCITY); +} + + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/ScElementInteractionMarker.cpp b/PhysX_3.4/Source/SimulationController/src/ScElementInteractionMarker.cpp new file mode 100644 index 00000000..2cb2a178 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScElementInteractionMarker.cpp @@ -0,0 +1,54 @@ +// 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 "ScElementInteractionMarker.h" +#include "ScNPhaseCore.h" + +using namespace physx; + +Sc::ElementInteractionMarker::~ElementInteractionMarker() +{ + if (getInteractionId() != PX_INVALID_INTERACTION_SCENE_ID) + { + getScene().unregisterInteraction(this); + getScene().getNPhaseCore()->unregisterInteraction(this); + } + unregisterFromActors(); +} + +bool Sc::ElementInteractionMarker::onActivate(void*) +{ + return false; +} + +bool Sc::ElementInteractionMarker::onDeactivate(PxU32) +{ + return true; +} diff --git a/PhysX_3.4/Source/SimulationController/src/ScElementInteractionMarker.h b/PhysX_3.4/Source/SimulationController/src/ScElementInteractionMarker.h new file mode 100644 index 00000000..01210737 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScElementInteractionMarker.h @@ -0,0 +1,70 @@ +// 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_COLLISION_ELEMENT_INTERACTION_MARKER +#define PX_COLLISION_ELEMENT_INTERACTION_MARKER + +#include "ScElementSimInteraction.h" + +namespace physx +{ +namespace Sc +{ + + class ElementInteractionMarker : public ElementSimInteraction + { + public: + PX_INLINE ElementInteractionMarker(ElementSim& element0, ElementSim& element1, bool createParallel = false); + virtual ~ElementInteractionMarker(); + + //---------- Interaction ---------- + virtual bool onActivate(void*); + virtual bool onDeactivate(PxU32 infoFlag); + //----------------------------------- + }; + +} // namespace Sc + + +PX_INLINE Sc::ElementInteractionMarker::ElementInteractionMarker(ElementSim& element0, ElementSim& element1, bool createParallel) : + ElementSimInteraction(element0, element1, InteractionType::eMARKER, InteractionFlag::eRB_ELEMENT|InteractionFlag::eFILTERABLE) +{ + if (!createParallel) + { + bool active = registerInActors(); + PX_UNUSED(active); + PX_ASSERT(!active); + getScene().registerInteraction(this, false); + } +} + +} + +#endif //PX_COLLISION_SHAPEINTERACTIONMARKER diff --git a/PhysX_3.4/Source/SimulationController/src/ScElementSim.cpp b/PhysX_3.4/Source/SimulationController/src/ScElementSim.cpp new file mode 100644 index 00000000..a12300e4 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScElementSim.cpp @@ -0,0 +1,151 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-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 "PsFoundation.h" +#include "PxsContext.h" +#include "BpSimpleAABBManager.h" +#include "ScElementSim.h" +#include "ScElementSimInteraction.h" +#include "ScSqBoundsManager.h" +#include "ScSimStats.h" + +using namespace physx; +using namespace Sc; + +static PX_FORCE_INLINE bool interactionHasElement(const Interaction* it, const ElementSim* elem) +{ + if(it->readInteractionFlag(InteractionFlag::eELEMENT_ELEMENT)) + { +#if PX_USE_PARTICLE_SYSTEM_API + PX_ASSERT( (it->getType() == InteractionType::eMARKER) || + (it->getType() == InteractionType::eOVERLAP) || + (it->getType() == InteractionType::eTRIGGER) || + (it->getType() == InteractionType::ePARTICLE_BODY) ); +#else + PX_ASSERT( (it->getType() == InteractionType::eMARKER) || + (it->getType() == InteractionType::eOVERLAP) || + (it->getType() == InteractionType::eTRIGGER) ); +#endif + const ElementSimInteraction* ei = static_cast<const ElementSimInteraction*>(it); + if((&ei->getElement0() == elem) || (&ei->getElement1() == elem)) + return true; + } + return false; +} + +Sc::ElementSimInteraction* Sc::ElementSim::ElementInteractionIterator::getNext() +{ + while(mInteractions!=mInteractionsLast) + { + Interaction* it = *mInteractions++; + if(interactionHasElement(it, mElement)) + return static_cast<ElementSimInteraction*>(it); + } + return NULL; +} + +Sc::ElementSimInteraction* Sc::ElementSim::ElementInteractionReverseIterator::getNext() +{ + while(mInteractions!=mInteractionsLast) + { + Interaction* it = *--mInteractionsLast; + if(interactionHasElement(it, mElement)) + return static_cast<ElementSimInteraction*>(it); + } + return NULL; +} + +Sc::ElementSim::ElementSim(ActorSim& actor, ElementType::Enum type) : + mNextInActor (NULL), + mActor (actor), + mType (Ps::to8(type)), + mInBroadPhase (false) +{ + initID(); + + PX_ASSERT((type & 0x03) == type); // we use 2 bits to store + + actor.onElementAttach(*this); +} + +Sc::ElementSim::~ElementSim() +{ + PX_ASSERT(!mInBroadPhase); + releaseID(); + mActor.onElementDetach(*this); +} + +void Sc::ElementSim::setElementInteractionsDirty(InteractionDirtyFlag::Enum flag, PxU8 interactionFlag) +{ + ElementSim::ElementInteractionIterator iter = getElemInteractions(); + ElementSimInteraction* interaction = iter.getNext(); + while(interaction) + { + if (interaction->readInteractionFlag(interactionFlag)) + { + static_cast<ElementSimInteraction*>(interaction)->setDirty(flag); + } + + interaction = iter.getNext(); + } +} + +// we pun these constants in order to increment the stats when adding and removing from BP +PX_COMPILE_TIME_ASSERT(PxU32(PxSimulationStatistics::eRIGID_BODY) == PxU32(Sc::ElementType::eSHAPE)); +PX_COMPILE_TIME_ASSERT(PxU32(PxSimulationStatistics::eCLOTH) == PxU32(Sc::ElementType::eCLOTH)); +PX_COMPILE_TIME_ASSERT(PxU32(PxSimulationStatistics::ePARTICLE_SYSTEM) == PxU32(Sc::ElementType::ePARTICLE_PACKET)); + +void Sc::ElementSim::addToAABBMgr(PxReal contactDistance, PxU32 group, bool isTrigger) +{ + Sc::Scene& scene = getScene(); + bool success = scene.getAABBManager()->addBounds(mElementID, contactDistance, group, this, mActor.getActorCore().getAggregateID(), isTrigger ? PxU8(Sc::ElementType::eTRIGGER) : PxU8(mType) ); + if (!success) + { + Ps::getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __LINE__, "Unable to create broadphase entity because only 32768 shapes are supported"); + return; + } + mInBroadPhase = true; +#if PX_ENABLE_SIM_STATS + scene.getStatsInternal().incBroadphaseAdds(PxSimulationStatistics::VolumeType(getElementType())); +#endif +} + +void Sc::ElementSim::removeFromAABBMgr() +{ + PX_ASSERT(mInBroadPhase); + Sc::Scene& scene = getScene(); + scene.getAABBManager()->removeBounds(mElementID); + scene.getAABBManager()->getChangedAABBMgActorHandleMap().growAndReset(mElementID); + + mInBroadPhase = false; +#if PX_ENABLE_SIM_STATS + scene.getStatsInternal().incBroadphaseRemoves(PxSimulationStatistics::VolumeType(getElementType())); +#endif +} diff --git a/PhysX_3.4/Source/SimulationController/src/ScElementSim.h b/PhysX_3.4/Source/SimulationController/src/ScElementSim.h new file mode 100644 index 00000000..5513a8fa --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScElementSim.h @@ -0,0 +1,164 @@ +// 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_ELEMENT_SIM +#define PX_PHYSICS_SCP_ELEMENT_SIM + +#include "PsUserAllocated.h" +#include "PxFiltering.h" +#include "PxvConfig.h" +#include "ScActorSim.h" +#include "ScInteraction.h" +#include "BpSimpleAABBManager.h" +#include "ScObjectIDTracker.h" + +namespace physx +{ +namespace Sc +{ + class ElementSimInteraction; + + struct ElementType + { + enum Enum + { + eSHAPE = 0, +#if PX_USE_PARTICLE_SYSTEM_API + ePARTICLE_PACKET, +#endif +#if PX_USE_CLOTH_API + eCLOTH, +#endif + eCOUNT, + eTRIGGER = eCOUNT + }; + }; + + PX_COMPILE_TIME_ASSERT(ElementType::eCOUNT <= 4); //2 bits reserved for type on win32 and win64 (8 bits on other platforms) + + /* + A ElementSim is a part of a ActorSim. It contributes to the activation framework by adding its + interactions to the actor. */ + PX_ALIGN_PREFIX(16) + class ElementSim : public Ps::UserAllocated + { + PX_NOCOPY(ElementSim) + + public: + class ElementInteractionIterator + { + public: + PX_FORCE_INLINE ElementInteractionIterator(const ElementSim& e, PxU32 nbInteractions, Interaction** interactions) : + mInteractions(interactions), mInteractionsLast(interactions + nbInteractions), mElement(&e) {} + ElementSimInteraction* getNext(); + + private: + Interaction** mInteractions; + Interaction** mInteractionsLast; + const ElementSim* mElement; + }; + + class ElementInteractionReverseIterator + { + public: + PX_FORCE_INLINE ElementInteractionReverseIterator(const ElementSim& e, PxU32 nbInteractions, Interaction** interactions) : + mInteractions(interactions), mInteractionsLast(interactions + nbInteractions), mElement(&e) {} + ElementSimInteraction* getNext(); + + private: + Interaction** mInteractions; + Interaction** mInteractionsLast; + const ElementSim* mElement; + }; + + + ElementSim(ActorSim& actor, ElementType::Enum type); + virtual ~ElementSim(); + + // Get an iterator to the interactions connected to the element + PX_FORCE_INLINE ElementInteractionIterator getElemInteractions() const { return ElementInteractionIterator(*this, mActor.getActorInteractionCount(), mActor.getActorInteractions()); } + PX_FORCE_INLINE ElementInteractionReverseIterator getElemInteractionsReverse() const { return ElementInteractionReverseIterator(*this, mActor.getActorInteractionCount(), mActor.getActorInteractions()); } + PX_FORCE_INLINE PxU32 getElemInteractionCount() const { return mActor.getActorInteractionCount(); } + + PX_FORCE_INLINE ActorSim& getActor() const { return mActor; } + + PX_FORCE_INLINE Scene& getScene() const { return mActor.getScene(); } + + PX_FORCE_INLINE ElementType::Enum getElementType() const { return ElementType::Enum(mType); } + + PX_FORCE_INLINE PxU32 getElementID() const { return mElementID; } + PX_FORCE_INLINE bool isInBroadPhase() const { return mInBroadPhase; } + + void addToAABBMgr(PxReal contactDistance, PxU32 group, bool isTrigger); + void removeFromAABBMgr(); + + //---------- Filtering ---------- + virtual void getFilterInfo(PxFilterObjectAttributes& filterAttr, PxFilterData& filterData) const = 0; + + PX_FORCE_INLINE void setFilterObjectAttributeType(PxFilterObjectAttributes& attr, PxFilterObjectType::Enum type) const; + //------------------------------- + + void setElementInteractionsDirty(InteractionDirtyFlag::Enum flag, PxU8 interactionFlag); + + PX_FORCE_INLINE void initID() + { + Scene& scene = getScene(); + mElementID = scene.getElementIDPool().createID(); + scene.getBoundsArray().initEntry(mElementID); + } + + PX_FORCE_INLINE void releaseID() + { + getScene().getElementIDPool().releaseID(mElementID); + } + + public: + ElementSim* mNextInActor; + private: + ActorSim& mActor; + + PxU32 mElementID : 29; + PxU32 mType : 2; + PxU32 mInBroadPhase : 1; + } + PX_ALIGN_SUFFIX(16); +} // namespace Sc + +// SFD: duplicated attribute generation in SqFiltering.h +PX_FORCE_INLINE void Sc::ElementSim::setFilterObjectAttributeType(PxFilterObjectAttributes& attr, PxFilterObjectType::Enum type) const +{ + PX_ASSERT((attr & (PxFilterObjectType::eMAX_TYPE_COUNT-1)) == 0); + attr |= type; +} + + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/ScElementSimInteraction.h b/PhysX_3.4/Source/SimulationController/src/ScElementSimInteraction.h new file mode 100644 index 00000000..f4769149 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScElementSimInteraction.h @@ -0,0 +1,77 @@ +// 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_ELEMENT_SIM_INTERACTION +#define PX_PHYSICS_SCP_ELEMENT_SIM_INTERACTION + +#include "ScInteraction.h" +#include "ScElementSim.h" + +namespace physx +{ +namespace Sc +{ + class ElementSim; + + class ElementSimInteraction : public Interaction + { + public: + PX_FORCE_INLINE ElementSim& getElement0() const { return mElement0; } + PX_FORCE_INLINE ElementSim& getElement1() const { return mElement1; } + + // Method to check if this interaction is the last filter relevant interaction between the two elements, + // i.e., if this interaction gets deleted, the pair is considered lost + virtual bool isLastFilterInteraction() const { return true; } + + protected: + PX_INLINE ElementSimInteraction(ElementSim& element0, ElementSim& element1, InteractionType::Enum type, PxU8 flags); + virtual ~ElementSimInteraction() {} + ElementSimInteraction& operator=(const ElementSimInteraction&); + + private: + ElementSim& mElement0; + ElementSim& mElement1; + }; + +} // namespace Sc + +////////////////////////////////////////////////////////////////////////// + +PX_INLINE Sc::ElementSimInteraction::ElementSimInteraction(ElementSim& element0, ElementSim& element1, InteractionType::Enum type, PxU8 flags) : + Interaction (element0.getActor(), element1.getActor(), type, flags), + mElement0 (element0), + mElement1 (element1) +{ +} + + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/ScInteraction.cpp b/PhysX_3.4/Source/SimulationController/src/ScInteraction.cpp new file mode 100644 index 00000000..426f8bf1 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScInteraction.cpp @@ -0,0 +1,75 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-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 "foundation/Px.h" + +#include "ScInteraction.h" +#include "ScNPhaseCore.h" + +using namespace physx; + + +Sc::Interaction::Interaction(ActorSim& actor0, ActorSim& actor1, InteractionType::Enum type, PxU8 flags) : + mActor0 (actor0), + mActor1 (actor1), + mSceneId (PX_INVALID_INTERACTION_SCENE_ID), + mActorId0 (PX_INVALID_INTERACTION_ACTOR_ID), + mActorId1 (PX_INVALID_INTERACTION_ACTOR_ID), + mInteractionType (Ps::to8(type)), + mInteractionFlags (flags), + mDirtyFlags (0) +{ + PX_ASSERT_WITH_MESSAGE(&actor0.getScene() == &actor1.getScene(),"Cannot create an interaction between actors belonging to different scenes."); + PX_ASSERT(PxU32(type)<256); // PT: type is now stored on a byte +} + + +void Sc::Interaction::addToDirtyList() +{ + getActor0().getScene().getNPhaseCore()->addToDirtyInteractionList(this); +} + + +void Sc::Interaction::removeFromDirtyList() +{ + getActor0().getScene().getNPhaseCore()->removeFromDirtyInteractionList(this); +} + +void Sc::Interaction::setClean(bool removeFromList) +{ + if (readInteractionFlag(InteractionFlag::eIN_DIRTY_LIST)) + { + if (removeFromList) // if we process all dirty interactions anyway, then we can just clear the list at the end and save the work here. + removeFromDirtyList(); + clearInteractionFlag(InteractionFlag::eIN_DIRTY_LIST); + } + + mDirtyFlags = 0; +} diff --git a/PhysX_3.4/Source/SimulationController/src/ScInteraction.h b/PhysX_3.4/Source/SimulationController/src/ScInteraction.h new file mode 100644 index 00000000..7595b668 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScInteraction.h @@ -0,0 +1,243 @@ +// 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_INTERACTION +#define PX_PHYSICS_SCP_INTERACTION + +#include "foundation/Px.h" +#include "ScInteractionFlags.h" +#include "ScScene.h" +#include "ScActorSim.h" +#include "PsUserAllocated.h" +#include "PsUtilities.h" +#include "PsFoundation.h" + +namespace physx +{ + +#define PX_INVALID_INTERACTION_ACTOR_ID 0xffffffff +#define PX_INVALID_INTERACTION_SCENE_ID 0xffffffff + +namespace Sc +{ + // Interactions are used for connecting actors into activation + // groups. An interaction always connects exactly two actors. + // An interaction is implicitly active if at least one of the two + // actors it connects is active. + + class Interaction : public Ps::UserAllocated + { + PX_NOCOPY(Interaction) + + protected: + Interaction(ActorSim& actor0, ActorSim& actor1, InteractionType::Enum interactionType, PxU8 flags); + virtual ~Interaction() { PX_ASSERT(!readInteractionFlag(InteractionFlag::eIN_DIRTY_LIST)); } + + public: + // Interactions automatically register themselves in the actors here + PX_FORCE_INLINE bool registerInActors(void* data = NULL); + + // Interactions automatically unregister themselves from the actors here + PX_FORCE_INLINE void unregisterFromActors(); + + PX_FORCE_INLINE ActorSim& getActor0() const { return mActor0; } + PX_FORCE_INLINE ActorSim& getActor1() const { return mActor1; } + + PX_FORCE_INLINE Scene& getScene() const { return mActor0.getScene(); } + + // PT: TODO: why do we have both virtual functions AND a type in there? + PX_FORCE_INLINE InteractionType::Enum getType() const { return InteractionType::Enum(mInteractionType); } + + PX_FORCE_INLINE PxU8 readInteractionFlag(PxU8 flag) const { return PxU8(mInteractionFlags & flag); } + PX_FORCE_INLINE void raiseInteractionFlag(InteractionFlag::Enum flag) { mInteractionFlags |= flag; } + PX_FORCE_INLINE void clearInteractionFlag(InteractionFlag::Enum flag) { mInteractionFlags &= ~flag; } + + PX_FORCE_INLINE bool isRegistered() const { return mSceneId != PX_INVALID_INTERACTION_SCENE_ID; } + + /** + \brief Mark the interaction as dirty. This will put the interaction into a list that is processed once per simulation step. + + @see InteractionDirtyFlag + */ + PX_FORCE_INLINE void setDirty(PxU32 dirtyFlags); + + /** + \brief Clear all flags that mark the interaction as dirty and optionally remove the interaction from the list of dirty interactions. + + @see InteractionDirtyFlag + */ + /*PX_FORCE_INLINE*/ void setClean(bool removeFromList); + + PX_FORCE_INLINE Ps::IntBool needsRefiltering() const { return (getDirtyFlags() & InteractionDirtyFlag::eFILTER_STATE); } + + PX_FORCE_INLINE Ps::IntBool isElementInteraction() const; + + // Called when an interaction is activated or created. + // Return true if activation should proceed else return false (for example: joint interaction between two kinematics should not get activated) + virtual bool onActivate(void* data) = 0; + + // Called when an interaction is deactivated. + // Return true if deactivation should proceed else return false (for example: joint interaction between two kinematics can ignore deactivation because it always is deactivated) + virtual bool onDeactivate(PxU32 infoFlag) = 0; + + PX_FORCE_INLINE void setInteractionId(PxU32 id) { mSceneId = id; } + PX_FORCE_INLINE PxU32 getInteractionId() const { return mSceneId; } + + PX_FORCE_INLINE void setActorId(ActorSim* actor, PxU32 id); + PX_FORCE_INLINE void invalidateActorId(ActorSim* actor); + PX_FORCE_INLINE PxU32 getActorId(const ActorSim* actor) const; + + + PX_FORCE_INLINE PxU8 getDirtyFlags() const { return mDirtyFlags; } + + private: + void addToDirtyList(); + void removeFromDirtyList(); + + ActorSim& mActor0; + ActorSim& mActor1; + + PxU32 mSceneId; // PT: TODO: merge this with mInteractionType + + // PT: TODO: are those IDs even worth caching? Since the number of interactions per actor is (or should be) small, + // we could just do a linear search and save memory here... + PxU32 mActorId0; // PT: id of this interaction within mActor0's mInteractions array + PxU32 mActorId1; // PT: id of this interaction within mActor1's mInteractions array + protected: + PxU8 mInteractionType; // PT: stored on a byte to save space, should be InteractionType enum + PxU8 mInteractionFlags; + PxU8 mDirtyFlags; // see DirtyFlag enum + PxU8 mPadding; + }; + +} // namespace Sc + +////////////////////////////////////////////////////////////////////////// + +PX_FORCE_INLINE bool Sc::Interaction::registerInActors(void* data) +{ + bool active = onActivate(data); + + mActor0.registerInteraction(this); + mActor1.registerInteraction(this); + + return active; +} + + +PX_FORCE_INLINE void Sc::Interaction::unregisterFromActors() +{ + mActor0.unregisterInteraction(this); + mActor1.unregisterInteraction(this); +} + +PX_FORCE_INLINE void Sc::Interaction::invalidateActorId(ActorSim* actor) +{ + if (&mActor0 == actor) + mActorId0 = PX_INVALID_INTERACTION_ACTOR_ID; + else + mActorId1 = PX_INVALID_INTERACTION_ACTOR_ID; +} + + +PX_FORCE_INLINE void Sc::Interaction::setActorId(ActorSim* actor, PxU32 id) +{ + PX_ASSERT(id != PX_INVALID_INTERACTION_ACTOR_ID); + if (&mActor0 == actor) + mActorId0 = id; + else + mActorId1 = id; +} + + +PX_FORCE_INLINE PxU32 Sc::Interaction::getActorId(const ActorSim* actor) const +{ + if (&mActor0 == actor) + return mActorId0; + else + return mActorId1; +} + + +PX_FORCE_INLINE Ps::IntBool Sc::Interaction::isElementInteraction() const +{ + Ps::IntBool res = readInteractionFlag(InteractionFlag::eELEMENT_ELEMENT); + +#if PX_USE_PARTICLE_SYSTEM_API + PX_ASSERT( (res && + ((getType() == InteractionType::eOVERLAP) || + (getType() == InteractionType::eTRIGGER) || + (getType() == InteractionType::eMARKER) || + (getType() == InteractionType::ePARTICLE_BODY))) || + (!res && + ((getType() == InteractionType::eCONSTRAINTSHADER) || + (getType() == InteractionType::eARTICULATION)))); +#else + PX_ASSERT( (res && + ((getType() == InteractionType::eOVERLAP) || + (getType() == InteractionType::eTRIGGER) || + (getType() == InteractionType::eMARKER))) || + (!res && + ((getType() == InteractionType::eCONSTRAINTSHADER) || + (getType() == InteractionType::eARTICULATION)))); +#endif + return res; +} + + +PX_FORCE_INLINE void Sc::Interaction::setDirty(PxU32 dirtyFlags) +{ + PX_ASSERT(getType() != InteractionType::eARTICULATION); + + mDirtyFlags |= Ps::to8(dirtyFlags); + if (!readInteractionFlag(InteractionFlag::eIN_DIRTY_LIST)) + { + addToDirtyList(); + raiseInteractionFlag(InteractionFlag::eIN_DIRTY_LIST); + } +} + + +//PX_FORCE_INLINE void Sc::Interaction::setClean(bool removeFromList) +//{ +// if (readInteractionFlag(InteractionFlag::eIN_DIRTY_LIST)) +// { +// if (removeFromList) // if we process all dirty interactions anyway, then we can just clear the list at the end and save the work here. +// removeFromDirtyList(); +// clearInteractionFlag(InteractionFlag::eIN_DIRTY_LIST); +// } +// +// mDirtyFlags = 0; +//} + + +} + +#endif // PX_PHYSICS_SCP_INTERACTION diff --git a/PhysX_3.4/Source/SimulationController/src/ScInteractionFlags.h b/PhysX_3.4/Source/SimulationController/src/ScInteractionFlags.h new file mode 100644 index 00000000..41fd5366 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScInteractionFlags.h @@ -0,0 +1,75 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-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_INTERACTION_FLAGS +#define PX_PHYSICS_SCP_INTERACTION_FLAGS + +#include "foundation/Px.h" + +namespace physx +{ + +namespace Sc +{ + struct InteractionFlag // PT: TODO: use PxFlags + { + enum Enum + { + eELEMENT_ELEMENT = (1 << 0), // Interactions between rigid body shapes or interactions between rigid body and particle packet shapes + eRB_ELEMENT = (1 << 1) | eELEMENT_ELEMENT, // Interactions between rigid body shapes + eCONSTRAINT = (1 << 2), + eFILTERABLE = (1 << 3), // Interactions that go through the filter code + eIN_DIRTY_LIST = (1 << 4), // The interaction is in the dirty list + eIS_FILTER_PAIR = (1 << 5), // The interaction is tracked by the filter callback mechanism + eIS_ACTIVE = (1 << 6) + }; + }; + + struct InteractionDirtyFlag + { + enum Enum + { + eFILTER_STATE = (1 << 0), // All changes filtering related + eMATERIAL = (1 << 1), + eBODY_KINEMATIC = (1 << 2) | eFILTER_STATE, // A transition between dynamic and kinematic (and vice versa) require a refiltering + eDOMINANCE = (1 << 3), + eREST_OFFSET = (1 << 4), + eVISUALIZATION = (1 << 5) + }; + }; + + +} // namespace Sc + + +} // namespace physx + + +#endif // PX_PHYSICS_SCP_INTERACTION_FLAGS diff --git a/PhysX_3.4/Source/SimulationController/src/ScIterators.cpp b/PhysX_3.4/Source/SimulationController/src/ScIterators.cpp new file mode 100644 index 00000000..464672ed --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScIterators.cpp @@ -0,0 +1,107 @@ +// 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 "ScIterators.h" +#include "ScBodySim.h" +#include "ScShapeSim.h" +#include "ScShapeInteraction.h" + +using namespace physx; + +/////////////////////////////////////////////////////////////////////////////// + +Sc::ContactIterator::Pair::Pair(const void*& contactPatches, const void*& contactPoints, PxU32 /*contactDataSize*/, const PxReal*& forces, PxU32 numContacts, PxU32 numPatches, + ShapeSim& shape0, ShapeSim& shape1) +: mIndex(0) +, mNumContacts(numContacts) +, mIter(reinterpret_cast<const PxU8*>(contactPatches), reinterpret_cast<const PxU8*>(contactPoints), reinterpret_cast<const PxU32*>(forces + numContacts), numPatches, numContacts) +, mForces(forces) +, mShape0(&shape0) +, mShape1(&shape1) +{ + mCurrentContact.shape0 = shape0.getPxShape(); + mCurrentContact.shape1 = shape1.getPxShape(); + mCurrentContact.normalForceAvailable = (forces != NULL); +} + +Sc::ContactIterator::Pair* Sc::ContactIterator::getNextPair() +{ + if(mCurrent < mLast) + { + ShapeInteraction* si = static_cast<ShapeInteraction*>(*mCurrent); + + const void* contactPatches = NULL; + const void* contactPoints = NULL; + PxU32 contactDataSize = 0; + const PxReal* forces = NULL; + PxU32 numContacts = 0; + PxU32 numPatches = 0; + + PxU32 nextOffset = si->getContactPointData(contactPatches, contactPoints, contactDataSize, numContacts, numPatches, forces, mOffset, *mOutputs); + + if (nextOffset == mOffset) + ++mCurrent; + else + mOffset = nextOffset; + + mCurrentPair = Pair(contactPatches, contactPoints, contactDataSize, forces, numContacts, numPatches, si->getShape0(), si->getShape1()); + return &mCurrentPair; + } + else + return NULL; +} + +Sc::Contact* Sc::ContactIterator::Pair::getNextContact() +{ + if(mIndex < mNumContacts) + { + if(!mIter.hasNextContact()) + { + if(!mIter.hasNextPatch()) + return NULL; + mIter.nextPatch(); + } + PX_ASSERT(mIter.hasNextContact()); + mIter.nextContact(); + + mCurrentContact.normal = mIter.getContactNormal(); + mCurrentContact.point = mIter.getContactPoint(); + mCurrentContact.separation = mIter.getSeparation(); + mCurrentContact.normalForce = mForces ? mForces[mIndex] : 0; + mCurrentContact.faceIndex0 = mIter.getFaceIndex0(); + mCurrentContact.faceIndex1 = mIter.getFaceIndex1(); + + mIndex++; + return &mCurrentContact; + } + return NULL; +} + +/////////////////////////////////////////////////////////////////////////////// diff --git a/PhysX_3.4/Source/SimulationController/src/ScMaterialCore.cpp b/PhysX_3.4/Source/SimulationController/src/ScMaterialCore.cpp new file mode 100644 index 00000000..6b7801e9 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScMaterialCore.cpp @@ -0,0 +1,42 @@ +// 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 "ScMaterialCore.h" + +using namespace physx; + +Sc::MaterialCore::MaterialCore(const MaterialData& desc) +: PxsMaterialCore(desc) +{ +} + +Sc::MaterialCore::~MaterialCore() +{ +} diff --git a/PhysX_3.4/Source/SimulationController/src/ScMetaData.cpp b/PhysX_3.4/Source/SimulationController/src/ScMetaData.cpp new file mode 100644 index 00000000..97c2ecf3 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScMetaData.cpp @@ -0,0 +1,509 @@ +// 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 "foundation/PxIO.h" +#include "ScActorCore.h" +#include "ScActorSim.h" +#include "ScBodyCore.h" +#include "ScStaticCore.h" +#include "ScConstraintCore.h" +#include "ScMaterialCore.h" +#include "ScShapeCore.h" +#include "ScArticulationCore.h" +#include "ScArticulationJointCore.h" +#include "ScClothFabricCore.h" +#include "ScClothCore.h" +#include "ScParticleSystemCore.h" +#include "PtParticleData.h" + +using namespace physx; +using namespace Ps; +using namespace Cm; +using namespace Sc; + +/////////////////////////////////////////////////////////////////////////////// + +template <typename T> class PxMetaDataArray : public physx::shdfnd::Array<T> +{ +public: + static PX_FORCE_INLINE physx::PxU32 getDataOffset() { return PX_OFFSET_OF(PxMetaDataArray<T>, mData); } + static PX_FORCE_INLINE physx::PxU32 getDataSize() { return PX_SIZE_OF(PxMetaDataArray<T>, mData); } + static PX_FORCE_INLINE physx::PxU32 getSizeOffset() { return PX_OFFSET_OF(PxMetaDataArray<T>, mSize); } + static PX_FORCE_INLINE physx::PxU32 getSizeSize() { return PX_SIZE_OF(PxMetaDataArray<T>, mSize); } + static PX_FORCE_INLINE physx::PxU32 getCapacityOffset() { return PX_OFFSET_OF(PxMetaDataArray<T>, mCapacity); } + static PX_FORCE_INLINE physx::PxU32 getCapacitySize() { return PX_SIZE_OF(PxMetaDataArray<T>, mCapacity); } +}; + +void Sc::ActorCore::getBinaryMetaData(PxOutputStream& stream) +{ + // 16 bytes + PX_DEF_BIN_METADATA_TYPEDEF(stream, PxActorFlags, PxU8) + PX_DEF_BIN_METADATA_TYPEDEF(stream, PxDominanceGroup, PxU8) + PX_DEF_BIN_METADATA_TYPEDEF(stream, PxClientID, PxU8) + + PX_DEF_BIN_METADATA_CLASS(stream, Sc::ActorCore) + + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ActorCore, ActorSim, mSim, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ActorCore, PxU32, mAggregateIDOwnerClient, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ActorCore, PxActorFlags, mActorFlags, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ActorCore, PxU8, mActorType, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ActorCore, PxU8, mClientBehaviorFlags, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ActorCore, PxU8, mDominanceGroup, 0) +} + +/////////////////////////////////////////////////////////////////////////////// + +static void getBinaryMetaData_PxsRigidCore(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_CLASS(stream, PxsRigidCore) + + PX_DEF_BIN_METADATA_ITEM(stream, PxsBodyCore, PxTransform, body2World, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxsBodyCore, PxRigidBodyFlags, mFlags, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxsBodyCore, PxU8, mIdtBody2Actor, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxsBodyCore, PxU16, solverIterationCounts, 0) +} + +namespace +{ + class ShadowPxsBodyCore : public PxsBodyCore + { + public: + static void getBinaryMetaData(PxOutputStream& stream) + { + PX_DEF_BIN_METADATA_CLASS(stream, ShadowPxsBodyCore) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, ShadowPxsBodyCore, PxsRigidCore) + + PX_DEF_BIN_METADATA_ITEM(stream, ShadowPxsBodyCore, PxTransform, body2Actor, 0) + PX_DEF_BIN_METADATA_ITEM(stream, ShadowPxsBodyCore, PxReal, ccdAdvanceCoefficient, 0) + PX_DEF_BIN_METADATA_ITEM(stream, ShadowPxsBodyCore, PxVec3, linearVelocity, 0) + PX_DEF_BIN_METADATA_ITEM(stream, ShadowPxsBodyCore, PxReal, maxPenBias, 0) + PX_DEF_BIN_METADATA_ITEM(stream, ShadowPxsBodyCore, PxVec3, angularVelocity, 0) + PX_DEF_BIN_METADATA_ITEM(stream, ShadowPxsBodyCore, PxReal, contactReportThreshold, 0) + PX_DEF_BIN_METADATA_ITEM(stream, ShadowPxsBodyCore, PxReal, maxAngularVelocitySq, 0) + PX_DEF_BIN_METADATA_ITEM(stream, ShadowPxsBodyCore, PxReal, maxLinearVelocitySq, 0) + PX_DEF_BIN_METADATA_ITEM(stream, ShadowPxsBodyCore, PxReal, linearDamping, 0) + PX_DEF_BIN_METADATA_ITEM(stream, ShadowPxsBodyCore, PxReal, angularDamping, 0) + PX_DEF_BIN_METADATA_ITEM(stream, ShadowPxsBodyCore, PxVec3, inverseInertia, 0) + PX_DEF_BIN_METADATA_ITEM(stream, ShadowPxsBodyCore, PxReal, inverseMass, 0) + PX_DEF_BIN_METADATA_ITEM(stream, ShadowPxsBodyCore, PxReal, maxContactImpulse, 0) + PX_DEF_BIN_METADATA_ITEM(stream, ShadowPxsBodyCore, PxReal, sleepThreshold, 0) + PX_DEF_BIN_METADATA_ITEM(stream, ShadowPxsBodyCore, PxReal, freezeThreshold, 0) + PX_DEF_BIN_METADATA_ITEM(stream, ShadowPxsBodyCore, PxReal, wakeCounter, 0) + PX_DEF_BIN_METADATA_ITEM(stream, ShadowPxsBodyCore, PxReal, solverWakeCounter, 0) + PX_DEF_BIN_METADATA_ITEM(stream, ShadowPxsBodyCore, PxU32, numCountedInteractions, 0) + PX_DEF_BIN_METADATA_ITEM(stream, ShadowPxsBodyCore, PxU32, numBodyInteractions, 0) + PX_DEF_BIN_METADATA_ITEM(stream, ShadowPxsBodyCore, PxU16, isFastMoving, 0) + PX_DEF_BIN_METADATA_ITEM(stream, ShadowPxsBodyCore, PxU16, lockFlags, 0) + } + }; +} + +static void getBinaryMetaData_PxsBodyCore(PxOutputStream& stream) +{ + getBinaryMetaData_PxsRigidCore(stream); + +/* PX_DEF_BIN_METADATA_CLASS(stream, PxsBodyCore) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, PxsBodyCore, PxsRigidCore) + + PX_DEF_BIN_METADATA_ITEM(stream, PxsBodyCore, PxTransform, body2Actor, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxsBodyCore, PxReal, ccdAdvanceCoefficient, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxsBodyCore, PxVec3, linearVelocity, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxsBodyCore, PxReal, maxPenBias, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxsBodyCore, PxVec3, angularVelocity, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxsBodyCore, PxReal, contactReportThreshold, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxsBodyCore, PxReal, maxAngularVelocitySq, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxsBodyCore, PxReal, maxLinearVelocitySq, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxsBodyCore, PxReal, linearDamping, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxsBodyCore, PxReal, angularDamping, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxsBodyCore, PxVec3, inverseInertia, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxsBodyCore, PxReal, inverseMass, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxsBodyCore, PxReal, maxContactImpulse, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxsBodyCore, PxReal, sleepThreshold, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxsBodyCore, PxReal, freezeThreshold, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxsBodyCore, PxReal, wakeCounter, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxsBodyCore, PxReal, solverWakeCounter, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxsBodyCore, PxU32, numCountedInteractions, 0)*/ + + ShadowPxsBodyCore::getBinaryMetaData(stream); + PX_DEF_BIN_METADATA_TYPEDEF(stream, PxsBodyCore, ShadowPxsBodyCore) +} + +/* +We need to fix the header deps by moving the API out of PhysXCore and into its own dir where other code can get to it. +[25.08.2010 18:34:57] Dilip Sequeira: In the meantime, I think it's Ok to include PxSDK.h, but you're right, we need to be very careful about include deps in that direction. +[25.08.2010 18:38:15] Dilip Sequeira: On the memory thing... PxsBodyCore has 28 bytes of padding at the end, for no reason. In addition, it has two words of padding after the velocity fields, to facilitate SIMD loads. But in fact, Vec3FromVec4 is fast enough such that unless you were using it in an inner loop (which we never are with PxsBodyCore) that padding isn't worth it. +[25.08.2010 18:38:58] Dilip Sequeira: So, we should drop the end-padding, and move the damping values to replace the velocity padding. This probably requires a bit of fixup in the places where we do SIMD writes to the velocity. +[25.08.2010 18:39:18] Dilip Sequeira: Then we're down to 92 bytes of data, and 4 bytes of padding I think. +[25.08.2010 18:50:41] Dilip Sequeira: The reason we don't want to put the sleep data there explicitly is that it isn't LL data so I'd rather not have it in an LL interface struct. +[25.08.2010 19:04:53] Gordon Yeoman nvidia: simd loads are faster when they are 16-byte aligned. I think the padding might be to ensure the second vector is also 16-byte aligned. We could drop the second 4-byte pad but dropping the 1st 4-byte pad will likely have performance implications. +[25.08.2010 19:06:22] Dilip Sequeira: We should still align the vec3s, as now - but we shouldn't use padding to do it, since there are a boatload of scalar data fields floating around in that struct too. +*/ +void Sc::BodyCore::getBinaryMetaData(PxOutputStream& stream) +{ + getBinaryMetaData_PxsBodyCore(stream); + PX_DEF_BIN_METADATA_TYPEDEF(stream, PxRigidBodyFlags, PxU8) + +// 176 => 144 bytes + PX_DEF_BIN_METADATA_CLASS(stream, Sc::BodyCore) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, Sc::BodyCore, Sc::RigidCore) + + PX_DEF_BIN_METADATA_ITEM(stream, Sc::BodyCore, PxsBodyCore, mCore, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::BodyCore, SimStateData, mSimStateData, PxMetaDataFlag::ePTR) +} + +/////////////////////////////////////////////////////////////////////////////// + +void Sc::ConstraintCore::getBinaryMetaData(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_TYPEDEF(stream, PxConstraintFlags, PxU16) + + PX_DEF_BIN_METADATA_CLASS(stream, ConstraintCore) + + PX_DEF_BIN_METADATA_ITEM(stream, ConstraintCore, PxConstraintFlags, mFlags, 0) + PX_DEF_BIN_METADATA_ITEM(stream, ConstraintCore, PxU16, mPaddingFromFlags, PxMetaDataFlag::ePADDING) + PX_DEF_BIN_METADATA_ITEM(stream, ConstraintCore, PxVec3, mAppliedForce, 0) + PX_DEF_BIN_METADATA_ITEM(stream, ConstraintCore, PxVec3, mAppliedTorque, 0) + PX_DEF_BIN_METADATA_ITEM(stream, ConstraintCore, PxConstraintConnector, mConnector, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, ConstraintCore, PxConstraintProject, mProject, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, ConstraintCore, PxConstraintSolverPrep, mSolverPrep, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, ConstraintCore, PxConstraintVisualize, mVisualize, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, ConstraintCore, PxU32, mDataSize, 0) + PX_DEF_BIN_METADATA_ITEM(stream, ConstraintCore, PxReal, mLinearBreakForce, 0) + PX_DEF_BIN_METADATA_ITEM(stream, ConstraintCore, PxReal, mAngularBreakForce, 0) + PX_DEF_BIN_METADATA_ITEM(stream, ConstraintCore, PxReal, mMinResponseThreshold, 0) + PX_DEF_BIN_METADATA_ITEM(stream, ConstraintCore, ConstraintSim, mSim, PxMetaDataFlag::ePTR) +} + +/////////////////////////////////////////////////////////////////////////////// + +void Sc::MaterialCore::getBinaryMetaData(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_TYPEDEF(stream, PxCombineMode::Enum, PxU32) + PX_DEF_BIN_METADATA_TYPEDEF(stream, PxMaterialFlags, PxU16) + + PX_DEF_BIN_METADATA_CLASS(stream, MaterialCore) + + // MaterialData + PX_DEF_BIN_METADATA_ITEM(stream, MaterialCore, PxReal, dynamicFriction, 0) + PX_DEF_BIN_METADATA_ITEM(stream, MaterialCore, PxReal, staticFriction, 0) + PX_DEF_BIN_METADATA_ITEM(stream, MaterialCore, PxReal, restitution, 0) + + PX_DEF_BIN_METADATA_ITEM(stream, MaterialCore, PxMaterialFlags, flags, 0) + PX_DEF_BIN_METADATA_ITEM(stream, MaterialCore, PxU8, fricRestCombineMode, 0) + PX_DEF_BIN_METADATA_ITEM(stream, MaterialCore, PxU8, padding, PxMetaDataFlag::ePADDING) + + // MaterialCore + PX_DEF_BIN_METADATA_ITEM(stream, MaterialCore, PxMaterial, mNxMaterial, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, MaterialCore, PxU32, mMaterialIndex, 0) +} + +/////////////////////////////////////////////////////////////////////////////// + +void Sc::RigidCore::getBinaryMetaData(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_CLASS(stream, Sc::RigidCore) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, Sc::RigidCore, Sc::ActorCore) +} + + +/////////////////////////////////////////////////////////////////////////////// + +void Sc::StaticCore::getBinaryMetaData(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_CLASS(stream, Sc::StaticCore) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, Sc::StaticCore, Sc::RigidCore) + + PX_DEF_BIN_METADATA_ITEM(stream, Sc::StaticCore, PxsRigidCore, mCore, 0) + +} + +/////////////////////////////////////////////////////////////////////////////// + +static void getBinaryMetaData_PxFilterData(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_CLASS(stream, PxFilterData) + + PX_DEF_BIN_METADATA_ITEM(stream, PxFilterData, PxU32, word0, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxFilterData, PxU32, word1, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxFilterData, PxU32, word2, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxFilterData, PxU32, word3, 0) +} + +static void getBinaryMetaData_PxsShapeCore(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_CLASS(stream, PxsShapeCore) + + PX_DEF_BIN_METADATA_ITEM(stream, PxsShapeCore, PxTransform, transform, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxsShapeCore, Gu::GeometryUnion, geometry, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxsShapeCore, PxReal, contactOffset, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxsShapeCore, PxShapeFlags, mShapeFlags, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxsShapeCore, PxU8, mOwnsMaterialIdxMemory, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxsShapeCore, PxU16, materialIndex, 0) +} + +void Sc::ShapeCore::getBinaryMetaData(PxOutputStream& stream) +{ + getBinaryMetaData_PxFilterData(stream); + getBinaryMetaData_PxsShapeCore(stream); + + PX_DEF_BIN_METADATA_TYPEDEF(stream, PxShapeFlags, PxU8) + +// 144 => 128 bytes + PX_DEF_BIN_METADATA_CLASS(stream, ShapeCore) + + PX_DEF_BIN_METADATA_ITEM(stream, ShapeCore, PxFilterData, mQueryFilterData, 0) + PX_DEF_BIN_METADATA_ITEM(stream, ShapeCore, PxFilterData, mSimulationFilterData, 0) + PX_DEF_BIN_METADATA_ITEM(stream, ShapeCore, PxsShapeCore, mCore, 0) + PX_DEF_BIN_METADATA_ITEM(stream, ShapeCore, PxReal, mRestOffset, 0) +} + +/////////////////////////////////////////////////////////////////////////////// + +static void getBinaryMetaData_ArticulationCore(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_CLASS(stream, Dy::ArticulationCore) + + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationCore, PxU32, internalDriveIterations, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationCore, PxU32, externalDriveIterations, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationCore, PxU32, maxProjectionIterations, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationCore, PxU16, solverIterationCounts, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationCore, PxReal, separationTolerance, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationCore, PxReal, sleepThreshold, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationCore, PxReal, freezeThreshold, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationCore, PxReal, wakeCounter, 0) +} + +void Sc::ArticulationCore::getBinaryMetaData(PxOutputStream& stream) +{ + getBinaryMetaData_ArticulationCore(stream); + + PX_DEF_BIN_METADATA_CLASS(stream, ArticulationCore) + + PX_DEF_BIN_METADATA_ITEM(stream, ArticulationCore, ArticulationSim, mSim, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, ArticulationCore, Dy::ArticulationCore, mCore, 0) +} + +/////////////////////////////////////////////////////////////////////////////// + +static void getBinaryMetaData_ArticulationJointCore(PxOutputStream& stream) +{ + // 172 bytes + PX_DEF_BIN_METADATA_CLASS(stream, Dy::ArticulationJointCore) + + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationJointCore, PxTransform, parentPose, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationJointCore, PxTransform, childPose, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationJointCore, PxQuat, targetPosition, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationJointCore, PxVec3, targetVelocity, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationJointCore, PxReal, spring, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationJointCore, PxReal, damping, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationJointCore, PxReal, solverSpring, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationJointCore, PxReal, solverDamping, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationJointCore, PxReal, internalCompliance, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationJointCore, PxReal, externalCompliance, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationJointCore, PxReal, swingYLimit, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationJointCore, PxReal, swingZLimit, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationJointCore, PxReal, swingLimitContactDistance, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationJointCore, bool, swingLimited, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationJointCore, PxU8, driveType, 0) +#ifdef EXPLICIT_PADDING_METADATA + PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxsArticulationJointCore, PxU8, paddingFromDriveType, PxMetaDataFlag::ePADDING) +#endif + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationJointCore, PxReal, tangentialStiffness, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationJointCore, PxReal, tangentialDamping, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationJointCore, PxReal, twistLimitHigh, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationJointCore, PxReal, twistLimitLow, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationJointCore, PxReal, twistLimitContactDistance, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationJointCore, bool, twistLimited, 0) +#ifdef EXPLICIT_PADDING_METADATA + PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, Dy::ArticulationJointCore, PxU8, paddingFromTwistLimited, PxMetaDataFlag::ePADDING) +#endif + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationJointCore, PxReal, tanQSwingY, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationJointCore, PxReal, tanQSwingZ, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationJointCore, PxReal, tanQSwingPad, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationJointCore, PxReal, tanQTwistHigh, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationJointCore, PxReal, tanQTwistLow, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dy::ArticulationJointCore, PxReal, tanQTwistPad, 0) +} + +void Sc::ArticulationJointCore::getBinaryMetaData(PxOutputStream& stream) +{ + getBinaryMetaData_ArticulationJointCore(stream); + PX_DEF_BIN_METADATA_CLASS(stream, ArticulationJointCore) + PX_DEF_BIN_METADATA_ITEM(stream, ArticulationJointCore, ArticulationJointSim, mSim, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, ArticulationJointCore, Dy::ArticulationJointCore, mCore, 0) +} + +/////////////////////////////////////////////////////////////////////////////// + +#define PX_DEF_BIN_METADATA_ARRAY(stream, Class, type, array) \ +{ PxMetaDataEntry tmp = {"void", #array".mData", PxU32(PX_OFFSET_OF(Class, array)) + PxMetaDataArray<type>::getDataOffset(), PxMetaDataArray<type>::getDataSize(), 1, 0, PxMetaDataFlag::ePTR, 0}; PX_STORE_METADATA(stream, tmp); } \ +{ PxMetaDataEntry tmp = {"PxU32", #array".mSize", PxU32(PX_OFFSET_OF(Class, array)) + PxMetaDataArray<type>::getSizeOffset(), PxMetaDataArray<type>::getSizeSize(), 1, 0, 0, 0}; PX_STORE_METADATA(stream, tmp); } \ +{ PxMetaDataEntry tmp = {"PxU32", #array".mCapacity", PxU32(PX_OFFSET_OF(Class, array)) + PxMetaDataArray<type>::getCapacityOffset(), PxMetaDataArray<type>::getCapacitySize(), 1, 0, PxMetaDataFlag::eCOUNT_MASK_MSB, 0}; PX_STORE_METADATA(stream, tmp); } \ +{ PxMetaDataEntry tmp = {#type, 0, PxU32(PX_OFFSET_OF(Class, array)) + PxMetaDataArray<type>::getSizeOffset(), PxMetaDataArray<type>::getSizeSize(), 0, 0, PxMetaDataFlag::eEXTRA_DATA, 0}; PX_STORE_METADATA(stream, tmp); } + + +#if PX_USE_CLOTH_API +void Sc::ClothFabricCore::getBinaryMetaData(PxOutputStream& stream) +{ + // register bulk data class + Sc::ClothFabricBulkData::getBinaryMetaData(stream); + PX_DEF_BIN_METADATA_CLASS(stream, Sc::ClothFabricCore) + + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothFabricCore, void, mLowLevelFabric, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothFabricCore, void, mLowLevelGpuFabric, PxMetaDataFlag::ePTR) + + PX_DEF_BIN_METADATA_ARRAY(stream, Sc::ClothFabricCore, PxU32, mPhaseTypes) + + //------ Extra-data ------ + + // use the mLowLevelFabric pointer as the control + PX_DEF_BIN_METADATA_EXTRA_ITEM(stream, Sc::ClothFabricCore, Sc::ClothFabricBulkData, mLowLevelFabric, 0) +} + +void Sc::ClothFabricBulkData::getBinaryMetaData(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_CLASS(stream, Sc::ClothFabricBulkData) + + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothFabricBulkData, PxU32, mNbParticles, 0) + PX_DEF_BIN_METADATA_ARRAY(stream, Sc::ClothFabricBulkData, PxU32, mPhases) + PX_DEF_BIN_METADATA_ARRAY(stream, Sc::ClothFabricBulkData, PxU32, mSets) + PX_DEF_BIN_METADATA_ARRAY(stream, Sc::ClothFabricBulkData, PxReal, mRestvalues) + PX_DEF_BIN_METADATA_ARRAY(stream, Sc::ClothFabricBulkData, PxU32, mIndices) + PX_DEF_BIN_METADATA_ARRAY(stream, Sc::ClothFabricBulkData, PxU32, mTetherAnchors) + PX_DEF_BIN_METADATA_ARRAY(stream, Sc::ClothFabricBulkData, PxReal, mTetherLengths) + PX_DEF_BIN_METADATA_ARRAY(stream, Sc::ClothFabricBulkData, PxU32, mTriangles) +} + +void Sc::ClothBulkData::getBinaryMetaData(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_CLASS(stream, Sc::ClothBulkData) + + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothBulkData, PxReal, mTetherConstraintScale, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothBulkData, PxReal, mTetherConstraintStiffness, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothBulkData, PxReal, mMotionConstraintScale, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothBulkData, PxReal, mMotionConstraintBias, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothBulkData, PxReal, mMotionConstraintStiffness, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothBulkData, PxVec3, mAcceleration, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothBulkData, PxVec3, mDamping, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothBulkData, PxReal, mFriction, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothBulkData, PxReal, mCollisionMassScale, 0) + + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothBulkData, PxVec3, mLinearDrag, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothBulkData, PxVec3, mAngularDrag, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothBulkData, PxVec3, mLinearInertia, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothBulkData, PxVec3, mAngularInertia, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothBulkData, PxVec3, mCentrifugalInertia, 0) + + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothBulkData, PxReal, mSolverFrequency, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothBulkData, PxReal, mStiffnessFrequency, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothBulkData, PxReal, mSelfCollisionDistance, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothBulkData, PxReal, mSelfCollisionStiffness, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothBulkData, PxTransform, mGlobalPose, 0) + + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothBulkData, PxReal, mSleepThreshold, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothBulkData, PxReal, mWakeCounter, 0) + + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothBulkData, PxVec3, mWindVelocity, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothBulkData, PxReal, mDragCoefficient, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothBulkData, PxReal, mLiftCoefficient, 0) + + PX_DEF_BIN_METADATA_ARRAY(stream, Sc::ClothBulkData, PxVec4, mParticles) + PX_DEF_BIN_METADATA_ARRAY(stream, Sc::ClothBulkData, PxU32, mVpData) + PX_DEF_BIN_METADATA_ARRAY(stream, Sc::ClothBulkData, PxVec3, mVpWeightData) + PX_DEF_BIN_METADATA_ARRAY(stream, Sc::ClothBulkData, PxVec4, mCollisionSpheres) + PX_DEF_BIN_METADATA_ARRAY(stream, Sc::ClothBulkData, PxU32, mCollisionPairs) + PX_DEF_BIN_METADATA_ARRAY(stream, Sc::ClothBulkData, PxVec4, mCollisionPlanes) + PX_DEF_BIN_METADATA_ARRAY(stream, Sc::ClothBulkData, PxU32, mConvexMasks) + PX_DEF_BIN_METADATA_ARRAY(stream, Sc::ClothBulkData, PxMat33, mCollisionTriangles) + PX_DEF_BIN_METADATA_ARRAY(stream, Sc::ClothBulkData, PxVec4, mConstraints) + PX_DEF_BIN_METADATA_ARRAY(stream, Sc::ClothBulkData, PxVec4, mSeparationConstraints) + PX_DEF_BIN_METADATA_ARRAY(stream, Sc::ClothBulkData, PxVec4, mParticleAccelerations) + PX_DEF_BIN_METADATA_ARRAY(stream, Sc::ClothBulkData, PxU32, mSelfCollisionIndices) + PX_DEF_BIN_METADATA_ARRAY(stream, Sc::ClothBulkData, PxVec4, mRestPositions) +} + +void Sc::ClothCore::getBinaryMetaData(PxOutputStream& stream) +{ + // register bulk data class + Sc::ClothBulkData::getBinaryMetaData(stream); + + PX_DEF_BIN_METADATA_CLASS(stream, Sc::ClothCore) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, Sc::ClothCore, Sc::ActorCore) + + PX_DEF_BIN_METADATA_TYPEDEF(stream, PxClothFlags, PxU16) + + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothCore, PxVec3, mExternalAcceleration, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothCore, Sc::ClothFabricCore, mFabric, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothCore, PxFilterData, mFilterData, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothCore, PxClothFlags, mClothFlags, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothCore, PxReal, mContactOffset, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothCore, PxReal, mRestOffset, 0) + + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothCore, PxU32, mNumUserSpheres, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothCore, PxU32, mNumUserCapsules, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothCore, PxU32, mNumUserPlanes, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothCore, PxU32, mNumUserConvexes, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothCore, PxU32, mNumUserTriangles, 0) + + // items not serialized (void) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothCore, void, mLowLevelCloth, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothCore, void, mBulkData, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ClothCore, void, mPhaseConfigs, PxMetaDataFlag::ePTR) + + //------ Extra-data ------ + + // use the mFabric pointer as the control because mBulkData is not + // set at export time just need any value that will evaluate to true + PX_DEF_BIN_METADATA_EXTRA_ITEM(stream, Sc::ClothCore, Sc::ClothBulkData, mFabric, 0) +} + +#endif // PX_USE_CLOTH_API + +#if PX_USE_PARTICLE_SYSTEM_API +void Sc::ParticleSystemCore::getBinaryMetaData(PxOutputStream& stream) +{ + Pt::ParticleData::getBinaryMetaData(stream); + + PX_DEF_BIN_METADATA_CLASS(stream, Sc::ParticleSystemCore) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, Sc::ParticleSystemCore, Sc::ActorCore) + + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ParticleSystemCore, Pt::ParticleData, mStandaloneData, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ParticleSystemCore, PxFilterData, mSimulationFilterData, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ParticleSystemCore, PxVec3, mExternalAcceleration, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ParticleSystemCore, PxReal, mParticleMass, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Sc::ParticleSystemCore, Pt::ParticleSystemParameter, mLLParameter, 0) + + //------ Extra-data ------ + PX_DEF_BIN_METADATA_EXTRA_ITEM(stream, Sc::ParticleSystemCore, Pt::ParticleData, mParticleMass, 16) +} +#endif // PX_USE_PARTICLE_SYSTEM_API + + + + diff --git a/PhysX_3.4/Source/SimulationController/src/ScNPhaseCore.cpp b/PhysX_3.4/Source/SimulationController/src/ScNPhaseCore.cpp new file mode 100644 index 00000000..368c9063 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScNPhaseCore.cpp @@ -0,0 +1,2505 @@ +// 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 "ScNPhaseCore.h" +#include "ScShapeInteraction.h" +#include "ScTriggerInteraction.h" +#include "ScElementInteractionMarker.h" +#include "ScConstraintInteraction.h" +#include "ScSimStats.h" +#include "ScObjectIDTracker.h" +#include "ScActorElementPair.h" +#include "ScSimStats.h" + +#if PX_USE_PARTICLE_SYSTEM_API +#include "ScParticleSystemCore.h" +#include "ScParticleBodyInteraction.h" +#include "ScParticlePacketShape.h" +#include "GuOverlapTests.h" +#include "GuBox.h" +#endif + +#if PX_USE_CLOTH_API +#include "ScClothCore.h" +#include "ScClothSim.h" +#endif // PX_USE_CLOTH_API + +#include "PsThread.h" + +#include "BpBroadPhase.h" + +using namespace physx; +using namespace Sc; +using namespace Gu; + + +namespace physx +{ +namespace Sc +{ +} +} + +struct Sc::FilterPair +{ + enum Enum + { + ELEMENT_ELEMENT = 0, + ELEMENT_ACTOR = 1, + INVALID = 2 // Make sure this is the last one + }; + + template<typename T> T*getPtr() const { return reinterpret_cast<T*>(ptrAndType&~3); } + Enum getType() const { return Enum(ptrAndType&3); } + +private: + FilterPair(void* ptr = 0, Enum type = INVALID) { uintptr_t p = reinterpret_cast<uintptr_t>(ptr); PX_ASSERT(!(p&3)); ptrAndType = p|type; } + uintptr_t ptrAndType; // packed type + friend class FilterPairManager; +}; + +class Sc::FilterPairManager : public Ps::UserAllocated +{ + PX_NOCOPY(FilterPairManager) +public: + FilterPairManager() + : mPairs(PX_DEBUG_EXP("FilterPairManager Array")) + , mFree(INVALID_FILTER_PAIR_INDEX) + , mInteractionToIndex(PX_DEBUG_EXP("FilterPairManager Hash")) + {} + + PxU32 acquireIndex() + { + PxU32 index; + if(mFree == INVALID_FILTER_PAIR_INDEX) + { + index = mPairs.size(); + mPairs.pushBack(FilterPair()); + } + else + { + index = PxU32(mFree); + mFree = mPairs[index].ptrAndType; + mPairs[index] = FilterPair(); + } + return index; + } + + void releaseIndex(PxU32 index) + { + if(mPairs[index].getType()!=FilterPair::INVALID) + mInteractionToIndex.erase(mPairs[index].getPtr<void*>()); + + mPairs[index].ptrAndType = mFree; + mFree = index; + } + + void set(PxU32 index, void* ptr, FilterPair::Enum type) + { + mPairs[index] = FilterPair(ptr, type); + mInteractionToIndex[ptr] = index; + } + + FilterPair& operator[](PxU32 index) + { + return mPairs[index]; + } + + PxU32 findIndex(void* ptr) + { + const InteractionToIndex::Entry* pair = mInteractionToIndex.find(ptr); + return pair ? pair->second : INVALID_FILTER_PAIR_INDEX; + } + +private: + typedef Ps::HashMap<void*, PxU32> InteractionToIndex; + + Ps::Array<FilterPair> mPairs; + uintptr_t mFree; + InteractionToIndex mInteractionToIndex; +}; + +/* Sc::NPhaseCore methods */ +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +Sc::NPhaseCore::NPhaseCore(Scene& scene, const PxSceneDesc& sceneDesc) : + mOwnerScene (scene), + mContactReportActorPairSet (PX_DEBUG_EXP("contactReportPairSet")), + mPersistentContactEventPairList (PX_DEBUG_EXP("persistentContactEventPairs")), + mNextFramePersistentContactEventPairIndex(0), + mForceThresholdContactEventPairList (PX_DEBUG_EXP("forceThresholdContactEventPairs")), + mContactReportBuffer (sceneDesc.contactReportStreamBufferSize, (sceneDesc.flags & PxSceneFlag::eDISABLE_CONTACT_REPORT_BUFFER_RESIZE)), + mActorPairPool (PX_DEBUG_EXP("actorPairPool")), + mActorPairReportPool (PX_DEBUG_EXP("actorPairReportPool")), + mActorElementPairPool (PX_DEBUG_EXP("actorElementPool")), + mShapeInteractionPool (Ps::AllocatorTraits<ShapeInteraction>::Type(PX_DEBUG_EXP("shapeInteractionPool")), 256), + mTriggerInteractionPool (PX_DEBUG_EXP("triggerInteractionPool")), + mActorPairContactReportDataPool (PX_DEBUG_EXP("actorPairContactReportPool")), + mInteractionMarkerPool (PX_DEBUG_EXP("interactionMarkerPool")) +#if PX_USE_PARTICLE_SYSTEM_API + ,mParticleBodyPool (PX_DEBUG_EXP("particleBodyPool")) +#endif +#if PX_USE_CLOTH_API + ,mClothPool (PX_DEBUG_EXP("clothPool")) +#endif + ,mMergeProcessedTriggerInteractions (this, "ScNPhaseCore.mergeProcessedTriggerInteractions") + ,mTmpTriggerProcessingBlock (NULL) + ,mTriggerPairsToDeactivateCount (0) +{ + mFilterPairManager = PX_NEW(FilterPairManager); +} + + +Sc::NPhaseCore::~NPhaseCore() +{ + // Clear pending actor pairs (waiting on contact report callback) + clearContactReportActorPairs(false); + PX_DELETE(mFilterPairManager); +} + +PxU32 Sc::NPhaseCore::getDefaultContactReportStreamBufferSize() const +{ + return mContactReportBuffer.getDefaultBufferSize(); +} + +// PT: function used only once, so safe to force inline +Sc::ElementSimInteraction* Sc::NPhaseCore::findInteraction(ElementSim* _element0, ElementSim* _element1) +{ + if (_element0 > _element1) + Ps::swap(_element0, _element1); + + const Ps::HashMap<ElementSimKey, ElementSimInteraction*>::Entry* pair = mElementSimMap.find(ElementSimKey(_element0, _element1)); + if (pair) + return pair->second; + return NULL; +} + +PxFilterInfo Sc::NPhaseCore::onOverlapFilter(ElementSim* volume0, ElementSim* volume1, Bp::BroadPhasePair* pair) +{ + PX_ASSERT(!findInteraction(volume0, volume1)); + + if(pair) + pair->mUserData = NULL; + + PX_ASSERT(PxMax(volume0->getElementType(), volume1->getElementType()) == ElementType::eSHAPE); + + + ShapeSim* s0 = static_cast<ShapeSim*>(volume1); + ShapeSim* s1 = static_cast<ShapeSim*>(volume0); + + // No actor internal interactions + PX_ASSERT(&s0->getActor() != &s1->getActor()); + + PxU32 isTriggerPair = 0; + const PxFilterInfo finfo = filterRbCollisionPair(*s0, *s1, INVALID_FILTER_PAIR_INDEX, isTriggerPair, false); + + return finfo; +} + +Sc::Interaction* Sc::NPhaseCore::onOverlapCreated(ElementSim* volume0, ElementSim* volume1, const PxU32 ccdPass, Bp::BroadPhasePair* pair) +{ +#if PX_USE_PARTICLE_SYSTEM_API + PX_COMPILE_TIME_ASSERT(ElementType::eSHAPE < ElementType::ePARTICLE_PACKET); +#elif PX_USE_CLOTH_API + PX_COMPILE_TIME_ASSERT(ElementType::eSHAPE < ElementType::eCLOTH); + PX_UNUSED(ccdPass); +#else + PX_UNUSED(ccdPass); +#endif + + PX_ASSERT(!findInteraction(volume0, volume1)); + + ElementSim* volumeLo = volume0; + ElementSim* volumeHi = volume1; + + // PT: we already order things here? So why do we also have a swap in contact managers? + // PT: TODO: use a map here again + if (volumeLo->getElementType() > volumeHi->getElementType()) + { + volumeLo = volume1; + volumeHi = volume0; + } + + if(pair) + pair->mUserData = NULL; + + switch (volumeHi->getElementType()) + { + +#if PX_USE_PARTICLE_SYSTEM_API + case ElementType::ePARTICLE_PACKET: + { + ParticlePacketShape* shapeHi = static_cast<ParticlePacketShape*>(volumeHi); + + if (volumeLo->getElementType() != ElementType::eSHAPE) + break; // Only interactions with rigid body shapes are supported + + ShapeSim* shapeLo = static_cast<ShapeSim*>(volumeLo); + + if (shapeLo->getActor().isDynamicRigid() + && !(shapeHi->getParticleSystem().getCore().getFlags() & PxParticleBaseFlag::eCOLLISION_WITH_DYNAMIC_ACTORS)) + return NULL; // Skip dynamic rigids if corresponding flag is set on the particle system + + { + const PxGeometryType::Enum geoType = shapeLo->getGeometryType(); + if (geoType == PxGeometryType::eTRIANGLEMESH || geoType == PxGeometryType::eHEIGHTFIELD) + { + PxBounds3 particleShapeBounds; + shapeHi->computeWorldBounds(particleShapeBounds); + bool isIntersecting = false; + switch (geoType) + { + case PxGeometryType::eTRIANGLEMESH: + { + PX_ALIGN(16, PxTransform globalPose); + shapeLo->getAbsPoseAligned(&globalPose); + + isIntersecting = Gu::checkOverlapAABB_triangleGeom(shapeLo->getCore().getGeometry(), globalPose, particleShapeBounds); + } + break; + case PxGeometryType::eHEIGHTFIELD: + { + PX_ALIGN(16, PxTransform globalPose); + shapeLo->getAbsPoseAligned(&globalPose); + + isIntersecting = Gu::checkOverlapAABB_heightFieldGeom(shapeLo->getCore().getGeometry(), globalPose, particleShapeBounds); + } + break; + case PxGeometryType::eSPHERE: + case PxGeometryType::ePLANE: + case PxGeometryType::eCAPSULE: + case PxGeometryType::eBOX: + case PxGeometryType::eCONVEXMESH: + case PxGeometryType::eGEOMETRY_COUNT: + case PxGeometryType::eINVALID: + break; + } + + if (!isIntersecting) + return NULL; + } + return createParticlePacketBodyInteraction(*shapeHi, *shapeLo, ccdPass); + } + } +#endif // PX_USE_PARTICLE_SYSTEM_API + +#if PX_USE_CLOTH_API + case ElementType::eCLOTH: + { + if (volumeLo->getElementType() != ElementType::eSHAPE) + break; // Only interactions with rigid body shapes are supported + + ClothShape* shapeHi = static_cast<ClothShape*>(volumeHi); + ClothSim& clothSim = shapeHi->getClothSim(); + ClothCore& clothCore = clothSim.getCore(); + + if(~clothCore.getClothFlags() & PxClothFlag::eSCENE_COLLISION) + return NULL; + + ShapeSim* shapeLo = static_cast<ShapeSim*>(volumeLo); + + PxFilterInfo finfo = runFilter(*shapeHi, *shapeLo, INVALID_FILTER_PAIR_INDEX, true); + if (finfo.filterFlags & (PxFilterFlag::eKILL | PxFilterFlag::eSUPPRESS)) // those are treated the same for cloth + { + PX_ASSERT(finfo.filterPairIndex == INVALID_FILTER_PAIR_INDEX); // No filter callback pair info for killed pairs + return NULL; + } + + if(clothSim.addCollisionShape(shapeLo)) + { + // only add an element when the collision shape wasn't rejected + // due to hitting the sphere/plane limit of the cloth. + ClothListElement element(&clothSim, mClothOverlaps[shapeLo].mNext); + mClothOverlaps[shapeLo].mNext = mClothPool.construct(element); + } + return NULL; + } +#endif // PX_USE_CLOTH_API + + case ElementType::eSHAPE: + { + ShapeSim* shapeHi = static_cast<ShapeSim*>(volumeHi); + ShapeSim* shapeLo = static_cast<ShapeSim*>(volumeLo); + + // No actor internal interactions + PX_ASSERT(&shapeHi->getActor() != &shapeLo->getActor()); + + Sc::ElementSimInteraction* interaction = createRbElementInteraction(*shapeHi, *shapeLo, NULL, NULL, NULL); + if(pair) + pair->mUserData = interaction; + + return interaction; + } + case ElementType::eCOUNT: + PX_ASSERT(0); + break; + } + return NULL; +} + + +static PX_FORCE_INLINE void prefetchPairElements(const Bp::AABBOverlap& pair, const ElementSim** elementBuffer) +{ + const ElementSim* e0 = reinterpret_cast<const ElementSim*>(pair.mUserData0); + const ElementSim* e1 = reinterpret_cast<const ElementSim*>(pair.mUserData1); + + Ps::prefetchLine(e0); + Ps::prefetchLine(e1); + + *elementBuffer = e0; + *(elementBuffer+1) = e1; +} + + +static PX_FORCE_INLINE void prefetchPairActors(const ElementSim& e0, const ElementSim& e1, const ActorSim** actorBuffer) +{ + const ActorSim* a0 = static_cast<const ActorSim*>(&e0.getActor()); + const ActorSim* a1 = static_cast<const ActorSim*>(&e1.getActor()); + + Ps::prefetchLine(a0); + Ps::prefetchLine(reinterpret_cast<const PxU8*>(a0) + 128); + Ps::prefetchLine(a1); + Ps::prefetchLine(reinterpret_cast<const PxU8*>(a1) + 128); + + *actorBuffer = a0; + *(actorBuffer+1) = a1; +} + + +static PX_FORCE_INLINE void prefetchPairShapesCore(const ElementSim& e0, const ElementSim& e1) +{ + if (e0.getElementType() == ElementType::eSHAPE) + { + const ShapeCore* sc = &static_cast<const ShapeSim&>(e0).getCore(); + Ps::prefetchLine(sc); + Ps::prefetchLine(reinterpret_cast<const PxU8*>(sc) + 128); + } + if (e1.getElementType() == ElementType::eSHAPE) + { + const ShapeCore* sc = &static_cast<const ShapeSim&>(e1).getCore(); + Ps::prefetchLine(sc); + Ps::prefetchLine(reinterpret_cast<const PxU8*>(sc) + 128); + } +} + + +static PX_FORCE_INLINE void prefetchPairActorsCore(const ActorSim& a0, const ActorSim& a1) +{ + ActorCore* ac0 = &a0.getActorCore(); + Ps::prefetchLine(ac0); + Ps::prefetchLine((reinterpret_cast<PxU8*>(ac0)) + 128); + ActorCore* ac1 = &a1.getActorCore(); + Ps::prefetchLine(ac1); + Ps::prefetchLine((reinterpret_cast<PxU8*>(ac1)) + 128); +} + + +static PX_FORCE_INLINE Sc::Interaction* processElementPair(Sc::NPhaseCore& nPhaseCore, const Bp::AABBOverlap& pair, const PxU32 ccdPass, Bp::BroadPhasePair* bpPairs) +{ + ElementSim* e0 = reinterpret_cast<ElementSim*>(pair.mUserData0); + ElementSim* e1 = reinterpret_cast<ElementSim*>(pair.mUserData1); + + Bp::BroadPhasePair* thisPair = NULL; + if(pair.mPairHandle != BP_INVALID_BP_HANDLE && bpPairs != NULL) + thisPair = &bpPairs[pair.mPairHandle]; + + return nPhaseCore.onOverlapCreated(e0, e1, ccdPass, thisPair); +} + + +void Sc::NPhaseCore::onOverlapCreated(const Bp::AABBOverlap* PX_RESTRICT pairs, PxU32 pairCount, const PxU32 ccdPass, Bp::BroadPhasePair* bpPairs) +{ +#if PX_USE_PARTICLE_SYSTEM_API + PX_COMPILE_TIME_ASSERT(ElementType::eSHAPE < ElementType::ePARTICLE_PACKET); +#elif PX_USE_CLOTH_API + PX_COMPILE_TIME_ASSERT(ElementType::eSHAPE < ElementType::eCLOTH); +#endif + + PxU32 pairIdx = 0; + + const PxU32 prefetchLookAhead = 4; + const ElementSim* batchedElements[prefetchLookAhead * 2]; + const ActorSim* batchedActors[prefetchLookAhead * 2]; + + PxU32 batchIterCount = pairCount / prefetchLookAhead; + + for(PxU32 i=1; i < batchIterCount; i++) + { + // prefetch elements for next batch + { + PX_ASSERT(prefetchLookAhead >= 4); + prefetchPairElements(pairs[pairIdx + prefetchLookAhead], batchedElements); + prefetchPairElements(pairs[pairIdx + prefetchLookAhead + 1], batchedElements + 2); + prefetchPairElements(pairs[pairIdx + prefetchLookAhead + 2], batchedElements + 4); + prefetchPairElements(pairs[pairIdx + prefetchLookAhead + 3], batchedElements + 6); + // unrolling by hand leads to better perf on XBox + } + + processElementPair(*this, pairs[pairIdx + 0], ccdPass, bpPairs); + + // prefetch actor sim for next batch + { + PX_ASSERT(prefetchLookAhead >= 4); + prefetchPairActors(*batchedElements[0], *batchedElements[1], batchedActors); + prefetchPairActors(*batchedElements[2], *batchedElements[3], batchedActors + 2); + prefetchPairActors(*batchedElements[4], *batchedElements[5], batchedActors + 4); + prefetchPairActors(*batchedElements[6], *batchedElements[7], batchedActors + 6); + // unrolling by hand leads to better perf on XBox + } + + processElementPair(*this, pairs[pairIdx + 1], ccdPass, bpPairs); + + // prefetch shape core for next batch + { + PX_ASSERT(prefetchLookAhead >= 4); + prefetchPairShapesCore(*batchedElements[0], *batchedElements[1]); + prefetchPairShapesCore(*batchedElements[2], *batchedElements[3]); + prefetchPairShapesCore(*batchedElements[4], *batchedElements[5]); + prefetchPairShapesCore(*batchedElements[6], *batchedElements[7]); + // unrolling by hand leads to better perf on XBox + } + + processElementPair(*this, pairs[pairIdx + 2], ccdPass, bpPairs); + + // prefetch actor core for next batch + { + PX_ASSERT(prefetchLookAhead >= 4); + prefetchPairActorsCore(*batchedActors[0], *batchedActors[1]); + prefetchPairActorsCore(*batchedActors[2], *batchedActors[3]); + prefetchPairActorsCore(*batchedActors[4], *batchedActors[5]); + prefetchPairActorsCore(*batchedActors[6], *batchedActors[7]); + // unrolling by hand leads to better perf on XBox + } + + processElementPair(*this, pairs[pairIdx + 3], ccdPass, bpPairs); + + pairIdx += prefetchLookAhead; + } + + // process remaining pairs + for(PxU32 i=pairIdx; i < pairCount; i++) + { + processElementPair(*this, pairs[i], ccdPass, bpPairs); + } +} + +void Sc::NPhaseCore::registerInteraction(ElementSimInteraction* interaction) +{ + ElementSim* sim0 = &interaction->getElement0(); + ElementSim* sim1 = &interaction->getElement1(); + + if (sim0 > sim1) + Ps::swap(sim0, sim1); + + this->mElementSimMap.insert(ElementSimKey(sim0, sim1), interaction); +} +void Sc::NPhaseCore::unregisterInteraction(ElementSimInteraction* interaction) +{ + ElementSim* sim0 = &interaction->getElement0(); + ElementSim* sim1 = &interaction->getElement1(); + if (sim0 > sim1) + Ps::swap(sim0, sim1); + + mElementSimMap.erase(ElementSimKey(sim0, sim1)); +} + +ElementSimInteraction* Sc::NPhaseCore::onOverlapRemovedStage1(ElementSim* volume0, ElementSim* volume1) +{ + ElementSimInteraction* pair = findInteraction(volume0, volume1); + return pair; +} + + +void Sc::NPhaseCore::onOverlapRemoved(ElementSim* volume0, ElementSim* volume1, const PxU32 ccdPass, void* elemSim, PxsContactManagerOutputIterator& outputs, + bool useAdaptiveForce) +{ + PX_UNUSED(elemSim); + // PT: ordering them here is again useless, as "findInteraction" will reorder according to counts... + + ElementSim* elementHi = volume1; + ElementSim* elementLo = volume0; + // No actor internal interactions + PX_ASSERT(&elementHi->getActor() != &elementLo->getActor()); + + // PT: TODO: get rid of 'findInteraction', cf US10491 + ElementSimInteraction* interaction = elemSim ? reinterpret_cast<ElementSimInteraction*>(elemSim) : findInteraction(elementHi, elementLo); + + + // MS: The check below is necessary since at the moment LowLevel broadphase still tracks + // killed pairs and hence reports lost overlaps + if (interaction) + { + PxU32 flags = PxU32(PairReleaseFlag::eWAKE_ON_LOST_TOUCH); + PX_ASSERT(interaction->isElementInteraction()); + releaseElementPair(static_cast<ElementSimInteraction*>(interaction), flags, ccdPass, true, outputs, useAdaptiveForce); + } + +#if PX_USE_CLOTH_API + // Cloth doesn't use interactions + if (elementLo->getElementType() == ElementType::eCLOTH) + Ps::swap(elementLo, elementHi); + if (elementHi->getElementType() == ElementType::eCLOTH && + elementLo->getElementType() == ElementType::eSHAPE) + { + ShapeSim* shapeLo = static_cast<ShapeSim*>(elementLo); + ClothShape* shapeHi = static_cast<ClothShape*>(elementHi); + ClothSim& clothSim = shapeHi->getClothSim(); + + clothSim.removeCollisionShape(shapeLo); + removeClothOverlap(&clothSim, shapeLo); + } +#endif // PX_USE_CLOTH_API +} + + +// MS: TODO: optimize this for the actor release case? +void Sc::NPhaseCore::onVolumeRemoved(ElementSim* volume, PxU32 flags, PxsContactManagerOutputIterator& outputs, bool useAdaptiveForce) +{ + const PxU32 ccdPass = 0; + + switch (volume->getElementType()) + { + case ElementType::eSHAPE: + { + flags |= PairReleaseFlag::eSHAPE_BP_VOLUME_REMOVED; + + // Release interactions + // IMPORTANT: Iterate from the back of the list to the front as we release interactions which + // triggers a replace with last + ElementSim::ElementInteractionReverseIterator iter = volume->getElemInteractionsReverse(); + ElementSimInteraction* interaction = iter.getNext(); + while(interaction) + { +#if PX_USE_PARTICLE_SYSTEM_API + PX_ASSERT( (interaction->getType() == InteractionType::eMARKER) || + (interaction->getType() == InteractionType::eOVERLAP) || + (interaction->getType() == InteractionType::eTRIGGER) || + (interaction->getType() == InteractionType::ePARTICLE_BODY) ); +#else + PX_ASSERT( (interaction->getType() == InteractionType::eMARKER) || + (interaction->getType() == InteractionType::eOVERLAP) || + (interaction->getType() == InteractionType::eTRIGGER) ); +#endif + + releaseElementPair(interaction, flags, ccdPass, true, outputs, useAdaptiveForce); + + interaction = iter.getNext(); + } + +#if PX_USE_CLOTH_API + ShapeSim* shape = static_cast<ShapeSim*>(volume); + if(const Ps::HashMap<const ShapeSim*, ClothListElement>::Entry* entry = mClothOverlaps.find(shape)) + { + for(ClothListElement* it = entry->second.mNext; it;) + { + it->mClothSim->removeCollisionShape(shape); + ClothListElement* next = it->mNext; + mClothPool.deallocate(it); + it = next; + } + mClothOverlaps.erase(shape); + } +#endif + + break; + } +#if PX_USE_PARTICLE_SYSTEM_API + case ElementType::ePARTICLE_PACKET: + { + flags |= PairReleaseFlag::eBP_VOLUME_REMOVED; + + // Release interactions + ParticlePacketShape* ps = static_cast<ParticlePacketShape*>(volume); + + PxU32 nbInteractions = ps->getInteractionsCount(); + ParticleElementRbElementInteraction** interactions = ps->getInteractions() + nbInteractions; + while(nbInteractions--) + { + ParticleElementRbElementInteraction* interaction = *--interactions; + PX_ASSERT((*interaction).getType() == InteractionType::ePARTICLE_BODY); + // The ccdPass parameter is needed to avoid concurrent interaction updates while the gpu particle pipeline is running. + releaseElementPair(static_cast<ElementSimInteraction*>(interaction), flags, ccdPass, true, outputs, useAdaptiveForce); + } + break; + } +#endif // PX_USE_PARTICLE_SYSTEM_API +#if PX_USE_CLOTH_API + case ElementType::eCLOTH: + { + // nothing to do + } + break; +#endif // PX_USE_CLOTH_API + case ElementType::eCOUNT: + { + PX_ASSERT(0); + break; + } + } +} + +#if PX_USE_CLOTH_API +void Sc::NPhaseCore::removeClothOverlap(ClothSim* clothSim, const ShapeSim* shapeSim) +{ + // When a new overlap was rejected due to the sphere/plane limit, + // the entry to delete does not exist. + for(ClothListElement* it = &mClothOverlaps[shapeSim]; + ClothListElement* next = it->mNext; it = next) + { + if(clothSim == next->mClothSim) + { + it->mNext = next->mNext; + mClothPool.deallocate(next); + break; + } + } +} +#endif + +Sc::ElementSimInteraction* Sc::NPhaseCore::createRbElementInteraction(const PxFilterInfo& finfo, ShapeSim& s0, ShapeSim& s1, PxsContactManager* contactManager, Sc::ShapeInteraction* shapeInteraction, + Sc::ElementInteractionMarker* interactionMarker, PxU32 isTriggerPair) +{ + ElementSimInteraction* pair = NULL; + + if ((finfo.filterFlags & PxFilterFlag::eSUPPRESS) == false) + { + if (!isTriggerPair) + { + pair = createShapeInteraction(s0, s1, finfo.pairFlags, contactManager, shapeInteraction); + } + else + { + TriggerInteraction* ti = createTriggerInteraction(s0, s1, finfo.pairFlags); + pair = ti; + } + } + else + { + pair = createElementInteractionMarker(s0, s1, interactionMarker); + } + + if (finfo.filterPairIndex != INVALID_FILTER_PAIR_INDEX) + { + // Mark the pair as a filter callback pair + pair->raiseInteractionFlag(InteractionFlag::eIS_FILTER_PAIR); + + // Filter callback pair: Set the link to the interaction + mFilterPairManager->set(finfo.filterPairIndex, pair, FilterPair::ELEMENT_ELEMENT); + } + + return pair; +} + +Sc::ElementSimInteraction* Sc::NPhaseCore::createRbElementInteraction(ShapeSim& s0, ShapeSim& s1, PxsContactManager* contactManager, Sc::ShapeInteraction* shapeInteraction, + Sc::ElementInteractionMarker* interactionMarker) +{ + PxU32 isTriggerPair = 0; + const PxFilterInfo finfo = filterRbCollisionPair(s0, s1, INVALID_FILTER_PAIR_INDEX, isTriggerPair, false); + + if (finfo.filterFlags & PxFilterFlag::eKILL) + { + PX_ASSERT(finfo.filterPairIndex == INVALID_FILTER_PAIR_INDEX); // No filter callback pair info for killed pairs + return NULL; + } + + return createRbElementInteraction(finfo, s0, s1, contactManager, shapeInteraction, interactionMarker, isTriggerPair); +} + + +#if PX_USE_PARTICLE_SYSTEM_API +// PT: function used only once, so safe to force inline +static PX_FORCE_INLINE Sc::ParticleElementRbElementInteraction* findParticlePacketBodyInteraction(ParticlePacketShape* ps, ActorSim* actor) +{ + ParticleElementRbElementInteraction** interactions = ps->getInteractions(); + PxU32 count = ps->getInteractionsCount(); + + while(count--) + { + ParticleElementRbElementInteraction*const interaction = *interactions++; + + PX_ASSERT( (interaction->getActor0().getActorType() == PxActorType::ePARTICLE_SYSTEM) || + (interaction->getActor0().getActorType() == PxActorType::ePARTICLE_FLUID) ); + + if ((&interaction->getActor1() == actor) && (&interaction->getParticleShape() == ps)) + { + PX_ASSERT(interaction->getType() == InteractionType::ePARTICLE_BODY); + return interaction; + } + } + return NULL; +} + +Sc::ElementSimInteraction* Sc::NPhaseCore::createParticlePacketBodyInteraction(ParticlePacketShape& ps, ShapeSim& s, const PxU32 ccdPass) +{ + ActorElementPair* actorElementPair = NULL; + + Sc::ActorSim& shapeActorSim = s.getActor(); + Sc::ActorSim& psActorSim = ps.getActor(); + + ParticleElementRbElementInteraction* pbi = findParticlePacketBodyInteraction(&ps, &shapeActorSim); + if(pbi) + { + // There already is an interaction between the shape and the particleSystem/... + // In that case, fetch the filter information from the existing interaction. + + actorElementPair = pbi->getActorElementPair(); + PX_ASSERT(actorElementPair); + } + else + { + PxFilterInfo finfo = runFilter(ps, s, INVALID_FILTER_PAIR_INDEX, true); + + // Note: It is valid to check here for killed pairs and not in the if-section above since in the + // case of killed pairs you won't ever get in the if-section. + if(finfo.filterFlags & PxFilterFlag::eKILL) + { + PX_ASSERT(finfo.filterPairIndex == INVALID_FILTER_PAIR_INDEX); // No filter callback pair info for killed pairs + return NULL; + } + + const bool isSuppressed = finfo.filterFlags & PxFilterFlag::eSUPPRESS; + actorElementPair = mActorElementPairPool.construct(psActorSim, s, finfo.pairFlags); + actorElementPair->markAsSuppressed(isSuppressed); + + actorElementPair->markAsFilterPair(finfo.filterPairIndex != INVALID_FILTER_PAIR_INDEX); + + if(finfo.filterPairIndex != INVALID_FILTER_PAIR_INDEX) + mFilterPairManager->set(finfo.filterPairIndex, NULL, FilterPair::ELEMENT_ACTOR); + } + + ElementSimInteraction* pair = insertParticleElementRbElementPair(ps, s, actorElementPair, ccdPass); + if(actorElementPair->isFilterPair()) + pair->raiseInteractionFlag(InteractionFlag::eIS_FILTER_PAIR); // Mark the pair as a filter callback pair + + return pair; +} +#endif + + +void Sc::NPhaseCore::managerNewTouch(Sc::ShapeInteraction& interaction, const PxU32 /*ccdPass*/, bool /*adjustCounters*/, PxsContactManagerOutputIterator& /*outputs*/) +{ + //(1) if the pair hasn't already been assigned, look it up! + + ActorPair* actorPair = interaction.getActorPair(); + + if(!actorPair) + { + ShapeSim& s0 = static_cast<ShapeSim&>(interaction.getElement0()); + ShapeSim& s1 = static_cast<ShapeSim&>(interaction.getElement1()); + actorPair = findActorPair(&s0, &s1, interaction.isReportPair()); + actorPair->incRefCount(); //It's being referenced by a new pair... + interaction.setActorPair(*actorPair); + } +} + + +Sc::ShapeInteraction* Sc::NPhaseCore::createShapeInteraction(ShapeSim& s0, ShapeSim& s1, PxPairFlags pairFlags, PxsContactManager* contactManager, Sc::ShapeInteraction* shapeInteraction) +{ + ShapeSim* _s0 = &s0; + ShapeSim* _s1 = &s1; + + /* + This tries to ensure that if one of the bodies is static or kinematic, it will be body B + There is a further optimization to force all pairs that share the same bodies to have + the same body ordering. This reduces the number of required partitions in the parallel solver. + Sorting rules are: + If bodyA is static, swap + If bodyA is rigidDynamic and bodyB is articulation, swap + If bodyA is in an earlier BP group than bodyB, swap + */ + { + // PT: 'getRbSim()' is not inlined so call it only once here. + Sc::RigidSim& rs0 = s0.getRbSim(); + Sc::RigidSim& rs1 = s1.getRbSim(); + + const PxActorType::Enum actorType0 = rs0.getActorType(); + const PxActorType::Enum actorType1 = rs1.getActorType(); + if( actorType0 == PxActorType::eRIGID_STATIC + || (actorType0 == PxActorType::eRIGID_DYNAMIC && actorType1 == PxActorType::eARTICULATION_LINK) + || ((actorType0 == PxActorType::eRIGID_DYNAMIC && actorType1 == PxActorType::eRIGID_DYNAMIC) && s0.getBodySim()->isKinematic()) + || (actorType0 == actorType1 && rs0.getBroadphaseGroupId() < rs1.getBroadphaseGroupId())) + Ps::swap(_s0, _s1); + } + + ActorPair* aPair = NULL; + ShapeInteraction* si = shapeInteraction ? shapeInteraction : mShapeInteractionPool.allocate(); + PX_PLACEMENT_NEW(si, ShapeInteraction)(*_s0, *_s1, aPair, pairFlags, contactManager); + + PX_ASSERT(si->mReportPairIndex == INVALID_REPORT_PAIR_ID); + + return si; +} + + +Sc::TriggerInteraction* Sc::NPhaseCore::createTriggerInteraction(ShapeSim& s0, ShapeSim& s1, PxPairFlags triggerFlags) +{ + ShapeSim* triggerShape; + ShapeSim* otherShape; + + if (s1.getFlags() & PxShapeFlag::eTRIGGER_SHAPE) + { + triggerShape = &s1; + otherShape = &s0; + } + else + { + triggerShape = &s0; + otherShape = &s1; + } + TriggerInteraction* pair = mTriggerInteractionPool.construct(*triggerShape, *otherShape); + pair->setTriggerFlags(triggerFlags); + return pair; +} + + +Sc::ElementInteractionMarker* Sc::NPhaseCore::createElementInteractionMarker(ElementSim& e0, ElementSim& e1, Sc::ElementInteractionMarker* interactionMarker) +{ + ElementInteractionMarker* pair = interactionMarker ? interactionMarker : mInteractionMarkerPool.allocate(); + PX_PLACEMENT_NEW(pair, ElementInteractionMarker)(e0, e1, interactionMarker != NULL); + return pair; +} + +static PX_INLINE PxFilterFlags checkFilterFlags(PxFilterFlags filterFlags) +{ + if ((filterFlags & (PxFilterFlag::eKILL | PxFilterFlag::eSUPPRESS)) == (PxFilterFlag::eKILL | PxFilterFlag::eSUPPRESS)) + { +#if PX_CHECKED + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "Filtering: eKILL and eSUPPRESS must not be set simultaneously. eSUPPRESS will be used."); +#endif + filterFlags.clear(PxFilterFlag::eKILL); + } + + return filterFlags; +} + +static PX_INLINE PxPairFlags checkRbPairFlags( const ShapeSim& s0, const ShapeSim& s1, + const Sc::BodySim* bs0, const Sc::BodySim* bs1, + PxPairFlags pairFlags, PxFilterFlags filterFlags) +{ + if(filterFlags & (PxFilterFlag::eSUPPRESS | PxFilterFlag::eKILL)) + return pairFlags; + + if (bs0 && bs0->isKinematic() && + bs1 && bs1->isKinematic() && + (pairFlags & PxPairFlag::eSOLVE_CONTACT)) + { +#if PX_CHECKED + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "Filtering: Resolving contacts between two kinematic objects is invalid. Contacts will not get resolved."); +#endif + pairFlags.clear(PxPairFlag::eSOLVE_CONTACT); + } + +#if PX_CHECKED + // we want to avoid to run contact generation for pairs that should not get resolved or have no contact/trigger reports + if (!(PxU32(pairFlags) & (PxPairFlag::eSOLVE_CONTACT | ShapeInteraction::CONTACT_REPORT_EVENTS))) + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "Filtering: Pair with no contact/trigger reports detected, nor is PxPairFlag::eSOLVE_CONTACT set. It is recommended to suppress/kill such pairs for performance reasons."); + } + else if(!(pairFlags & (PxPairFlag::eDETECT_DISCRETE_CONTACT | PxPairFlag::eDETECT_CCD_CONTACT))) + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "Filtering: Pair did not request either eDETECT_DISCRETE_CONTACT or eDETECT_CCD_CONTACT. It is recommended to suppress/kill such pairs for performance reasons."); + } +#endif + +#if PX_CHECKED + if(((s0.getFlags() & PxShapeFlag::eTRIGGER_SHAPE)!=0 || (s1.getFlags() & PxShapeFlag::eTRIGGER_SHAPE)!=0) && + (pairFlags & PxPairFlag::eTRIGGER_DEFAULT) && (pairFlags & PxPairFlag::eDETECT_CCD_CONTACT)) + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "Filtering: CCD isn't supported on Triggers yet"); + } +#else + PX_UNUSED(s0); + PX_UNUSED(s1); +#endif + + return pairFlags; +} + +static Sc::InteractionType::Enum getRbElementInteractionType(const ShapeSim* primitive0, const ShapeSim* primitive1, PxFilterFlags filterFlag) +{ + if(filterFlag & PxFilterFlag::eKILL) + return InteractionType::eINVALID; + + if(filterFlag & PxFilterFlag::eSUPPRESS) + return InteractionType::eMARKER; + + if(primitive0->getFlags() & PxShapeFlag::eTRIGGER_SHAPE + || primitive1->getFlags() & PxShapeFlag::eTRIGGER_SHAPE) + return InteractionType::eTRIGGER; + + PX_ASSERT( (primitive0->getGeometryType() != PxGeometryType::eTRIANGLEMESH) || + (primitive1->getGeometryType() != PxGeometryType::eTRIANGLEMESH)); + + return InteractionType::eOVERLAP; +} + +Sc::ElementSimInteraction* Sc::NPhaseCore::refilterInteraction(ElementSimInteraction* pair, const PxFilterInfo* filterInfo, bool removeFromDirtyList, PxsContactManagerOutputIterator& outputs, + bool useAdaptiveForce) +{ + const InteractionType::Enum oldType = pair->getType(); + + switch (oldType) + { + case InteractionType::eTRIGGER: + case InteractionType::eMARKER: + case InteractionType::eOVERLAP: + { + PX_ASSERT(pair->getElement0().getElementType() == ElementType::eSHAPE); + PX_ASSERT(pair->getElement1().getElementType() == ElementType::eSHAPE); + + ShapeSim& s0 = static_cast<ShapeSim&>(pair->getElement0()); + ShapeSim& s1 = static_cast<ShapeSim&>(pair->getElement1()); + + PxFilterInfo finfo; + if (filterInfo) + { + // The filter changes are provided by an outside source (the user filter callback) + + finfo = *filterInfo; + PX_ASSERT(finfo.filterPairIndex!=INVALID_FILTER_PAIR_INDEX); + + if ((finfo.filterFlags & PxFilterFlag::eKILL) && + ((finfo.filterFlags & PxFilterFlag::eNOTIFY) == PxFilterFlag::eNOTIFY) ) + { + callPairLost(pair->getElement0(), pair->getElement1(), finfo.filterPairIndex, false); + mFilterPairManager->releaseIndex(finfo.filterPairIndex); + finfo.filterPairIndex = INVALID_FILTER_PAIR_INDEX; + } + + Sc::BodySim* bs0 = s0.getBodySim(); + Sc::BodySim* bs1 = s1.getBodySim(); + finfo.pairFlags = checkRbPairFlags(s0, s1, bs0, bs1, finfo.pairFlags, finfo.filterFlags); + + //!!!Filter Issue: Need to check whether the requested changes don't violate hard constraints. + // - Assert that the shapes are not connected through a collision disabling joint + } + else + { + PxU32 filterPairIndex = INVALID_FILTER_PAIR_INDEX; + if (pair->readInteractionFlag(InteractionFlag::eIS_FILTER_PAIR)) + { + filterPairIndex = mFilterPairManager->findIndex(pair); + PX_ASSERT(filterPairIndex!=INVALID_FILTER_PAIR_INDEX); + + callPairLost(pair->getElement0(), pair->getElement1(), filterPairIndex, false); + } + + PxU32 isTriggerPair; + finfo = filterRbCollisionPair(s0, s1, filterPairIndex, isTriggerPair, true); + PX_UNUSED(isTriggerPair); + } + + if (pair->readInteractionFlag(InteractionFlag::eIS_FILTER_PAIR) && + ((finfo.filterFlags & PxFilterFlag::eNOTIFY) != PxFilterFlag::eNOTIFY) ) + { + // The pair was a filter callback pair but not any longer + pair->clearInteractionFlag(InteractionFlag::eIS_FILTER_PAIR); + + if (finfo.filterPairIndex!=INVALID_FILTER_PAIR_INDEX) + { + mFilterPairManager->releaseIndex(finfo.filterPairIndex); + finfo.filterPairIndex = INVALID_FILTER_PAIR_INDEX; + } + } + + const InteractionType::Enum newType = getRbElementInteractionType(&s0, &s1, finfo.filterFlags); + if (pair->getType() != newType) //Only convert interaction type if the type has changed + { + return convert(pair, newType, finfo, removeFromDirtyList, outputs, useAdaptiveForce); + } + else + { + //The pair flags might have changed, we need to forward the new ones + if (oldType == InteractionType::eOVERLAP) + { + ShapeInteraction* si = static_cast<ShapeInteraction*>(pair); + + const PxU32 newPairFlags = finfo.pairFlags; + const PxU32 oldPairFlags = si->getPairFlags(); + PX_ASSERT((newPairFlags & ShapeInteraction::PAIR_FLAGS_MASK) == newPairFlags); + PX_ASSERT((oldPairFlags & ShapeInteraction::PAIR_FLAGS_MASK) == oldPairFlags); + + if (newPairFlags != oldPairFlags) + { + if (!(oldPairFlags & ShapeInteraction::CONTACT_REPORT_EVENTS) && (newPairFlags & ShapeInteraction::CONTACT_REPORT_EVENTS) && (si->getActorPair() == NULL || !si->getActorPair()->isReportPair())) + { + // for this actor pair there was no shape pair that requested contact reports but now there is one + // -> all the existing shape pairs need to get re-adjusted to point to an ActorPairReport instance instead. + findActorPair(&s0, &s1, Ps::IntTrue); + } + + if (si->readFlag(ShapeInteraction::IN_PERSISTENT_EVENT_LIST) && (!(newPairFlags & PxPairFlag::eNOTIFY_TOUCH_PERSISTS))) + { + // the new report pair flags don't require persistent checks anymore -> remove from persistent list + // Note: The pair might get added to the force threshold list later + if (si->readFlag(ShapeInteraction::IS_IN_PERSISTENT_EVENT_LIST)) + { + removeFromPersistentContactEventPairs(si); + } + else + { + si->clearFlag(ShapeInteraction::WAS_IN_PERSISTENT_EVENT_LIST); + } + } + + if (newPairFlags & ShapeInteraction::CONTACT_FORCE_THRESHOLD_PAIRS) + { + PX_ASSERT((si->mReportPairIndex == INVALID_REPORT_PAIR_ID) || (!si->readFlag(ShapeInteraction::WAS_IN_PERSISTENT_EVENT_LIST))); + + if (si->mReportPairIndex == INVALID_REPORT_PAIR_ID && si->readInteractionFlag(InteractionFlag::eIS_ACTIVE)) + { + PX_ASSERT(!si->readFlag(ShapeInteraction::WAS_IN_PERSISTENT_EVENT_LIST)); // sanity check: an active pair should never have this flag set + + if (si->hasTouch()) + addToForceThresholdContactEventPairs(si); + } + } + else if ((oldPairFlags & ShapeInteraction::CONTACT_FORCE_THRESHOLD_PAIRS)) + { + // no force threshold events needed any longer -> clear flags + si->clearFlag(ShapeInteraction::FORCE_THRESHOLD_EXCEEDED_FLAGS); + + if (si->readFlag(ShapeInteraction::IS_IN_FORCE_THRESHOLD_EVENT_LIST)) + removeFromForceThresholdContactEventPairs(si); + } + } + si->setPairFlags(finfo.pairFlags); + } + else if (oldType == InteractionType::eTRIGGER) + static_cast<TriggerInteraction*>(pair)->setTriggerFlags(finfo.pairFlags); + + return pair; + } + } +#if (PX_USE_PARTICLE_SYSTEM_API) + case InteractionType::ePARTICLE_BODY: + { + ParticleElementRbElementInteraction* pbi = static_cast<ParticleElementRbElementInteraction*>(pair); + + ActorElementPair* aep = pbi->getActorElementPair(); + + PxFilterInfo finfo; + if (filterInfo) + { + // The filter changes are provided by an outside source (the user filter callback) + + finfo = *filterInfo; + + PX_ASSERT((finfo.filterPairIndex != INVALID_FILTER_PAIR_INDEX && aep->isFilterPair()) || + (finfo.filterPairIndex == INVALID_FILTER_PAIR_INDEX && !aep->isFilterPair()) ); + PX_ASSERT(aep->getPairFlags() == finfo.pairFlags); + PX_ASSERT(!(finfo.filterFlags & PxFilterFlag::eKILL) || + ((finfo.filterFlags & PxFilterFlag::eKILL) && aep->isKilled())); + PX_ASSERT(!(finfo.filterFlags & PxFilterFlag::eSUPPRESS) || + ((finfo.filterFlags & PxFilterFlag::eSUPPRESS) && aep->isSuppressed()) ); + // This should have been done at statusChange() level (see fireCustomFilteringCallbacks()) + + if (finfo.filterPairIndex != INVALID_FILTER_PAIR_INDEX && aep->isKilled() && pair->isLastFilterInteraction()) + { + // This is the last of (possibly) multiple element-element interactions of the same element-actor interaction + // --> Kill the filter callback pair + + callPairLost(pbi->getElement0(), pbi->getElement1(), finfo.filterPairIndex, false); + mFilterPairManager->releaseIndex(finfo.filterPairIndex); + finfo.filterPairIndex = INVALID_FILTER_PAIR_INDEX; + } + } + else + { + if (!aep->hasBeenRefiltered(mOwnerScene.getTimeStamp())) + { + // The first of (possibly) multiple element-element interactions of the same element-actor interaction + // - For filter callback pairs, call pairLost() + // - Run the filter + // - Pass new pair flags on + + PxU32 filterPairIndex = INVALID_FILTER_PAIR_INDEX; + if (pbi->readInteractionFlag(InteractionFlag::eIS_FILTER_PAIR)) + { + filterPairIndex = mFilterPairManager->findIndex(aep); + PX_ASSERT(filterPairIndex!=INVALID_FILTER_PAIR_INDEX); + + callPairLost(pbi->getElement0(), pbi->getElement1(), filterPairIndex, false); + } + + finfo = runFilter(pair->getElement0(), pair->getElement1(), filterPairIndex, true); + // Note: The filter run will remove the callback pair if the element-actor interaction should get killed + // or if the pair is no longer a filter callback pair + + aep->markAsFilterPair(finfo.filterPairIndex != INVALID_FILTER_PAIR_INDEX); + + aep->setPairFlags(finfo.pairFlags); // Pass on the pair flags (this needs only be done for the first pair) + + if (finfo.filterFlags & PxFilterFlag::eKILL) + { + aep->markAsKilled(true); // Set such that other pairs of the same element-actor interaction know that they have to give their lives for a higher goal... + } + else if (finfo.filterFlags & PxFilterFlag::eSUPPRESS) + aep->markAsSuppressed(true); + else + { + aep->markAsSuppressed(false); + } + } + } + + if (aep->isFilterPair()) + { + pair->raiseInteractionFlag(InteractionFlag::eIS_FILTER_PAIR); + } + else if (pair->readInteractionFlag(InteractionFlag::eIS_FILTER_PAIR)) + { + // The pair was a filter callback pair but not any longer + pair->clearInteractionFlag(InteractionFlag::eIS_FILTER_PAIR); + } + + if (aep->isKilled()) + { + PX_ASSERT(oldType == InteractionType::ePARTICLE_BODY); + // The ccdPass parameter is needed to avoid concurrent interaction updates while the gpu particle pipeline is running. + pool_deleteParticleElementRbElementPair(pbi, 0, 0); + return NULL; + } + + pbi->checkLowLevelActivationState(); + + return pair; + } +#endif // PX_USE_PARTICLE_SYSTEM_API + case InteractionType::eCONSTRAINTSHADER: + case InteractionType::eARTICULATION: + case InteractionType::eTRACKED_IN_SCENE_COUNT: + case InteractionType::eINVALID: + PX_ASSERT(0); + break; + } + return NULL; +} + + +PX_INLINE void Sc::NPhaseCore::callPairLost(const ElementSim& e0, const ElementSim& e1, PxU32 pairID, bool objVolumeRemoved) const +{ + PxFilterData fd0, fd1; + PxFilterObjectAttributes fa0, fa1; + + e0.getFilterInfo(fa0, fd0); + e1.getFilterInfo(fa1, fd1); + + mOwnerScene.getFilterCallbackFast()->pairLost(pairID, fa0, fd0, fa1, fd1, objVolumeRemoved); +} + + +PX_INLINE void Sc::NPhaseCore::runFilterShader(const ElementSim& e0, const ElementSim& e1, + PxFilterObjectAttributes& attr0, PxFilterData& filterData0, + PxFilterObjectAttributes& attr1, PxFilterData& filterData1, + PxFilterInfo& filterInfo) +{ + e0.getFilterInfo(attr0, filterData0); + e1.getFilterInfo(attr1, filterData1); + + filterInfo.filterFlags = mOwnerScene.getFilterShaderFast()( attr0, filterData0, + attr1, filterData1, + filterInfo.pairFlags, + mOwnerScene.getFilterShaderDataFast(), + mOwnerScene.getFilterShaderDataSizeFast() ); +} + + +static PX_FORCE_INLINE void fetchActorAndShape(const ElementSim& e, PxActor*& a, PxShape*& s) +{ + if (e.getElementType() == ElementType::eSHAPE) + { + const ShapeSim& sim = static_cast<const ShapeSim&>(e); + a = sim.getRbSim().getPxActor(); + s = sim.getPxShape(); + } +#if PX_USE_PARTICLE_SYSTEM_API + else + { + if (e.getElementType() == ElementType::ePARTICLE_PACKET) + a = (static_cast<const Sc::ParticlePacketShape&>(e)).getParticleSystem().getCore().getPxParticleBase(); + s = NULL; + } +#endif +} + + +PX_INLINE PxFilterInfo Sc::NPhaseCore::runFilter(const ElementSim& e0, const ElementSim& e1, PxU32 filterPairIndex, bool doCallbacks) +{ + PxFilterInfo filterInfo; + + PxFilterData fd0, fd1; + PxFilterObjectAttributes fa0, fa1; + + runFilterShader(e0, e1, fa0, fd0, fa1, fd1, filterInfo); + + if (filterInfo.filterFlags & PxFilterFlag::eCALLBACK) + { + if (mOwnerScene.getFilterCallbackFast()) + { + if (!doCallbacks) + { + //KS - return + return filterInfo; + } + else + { + + if (filterPairIndex == INVALID_FILTER_PAIR_INDEX) + filterPairIndex = mFilterPairManager->acquireIndex(); + // If a FilterPair is provided, then we use it, else we create a new one + // (A FilterPair is provided in the case for a pairLost()-pairFound() sequence after refiltering) + + PxActor* a0, *a1; + PxShape* s0, *s1; + fetchActorAndShape(e0, a0, s0); + fetchActorAndShape(e1, a1, s1); + + filterInfo.filterFlags = mOwnerScene.getFilterCallbackFast()->pairFound(filterPairIndex, fa0, fd0, a0, s0, fa1, fd1, a1, s1, filterInfo.pairFlags); + filterInfo.filterPairIndex = filterPairIndex; + } + } + else + { + filterInfo.filterFlags.clear(PxFilterFlag::eNOTIFY); + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "Filtering: eCALLBACK set but no filter callback defined."); + } + } + + filterInfo.filterFlags = checkFilterFlags(filterInfo.filterFlags); + + if (filterPairIndex!=INVALID_FILTER_PAIR_INDEX && ((filterInfo.filterFlags & PxFilterFlag::eKILL) || ((filterInfo.filterFlags & PxFilterFlag::eNOTIFY) != PxFilterFlag::eNOTIFY))) + { + if ((filterInfo.filterFlags & PxFilterFlag::eKILL) && ((filterInfo.filterFlags & PxFilterFlag::eNOTIFY) == PxFilterFlag::eNOTIFY)) + mOwnerScene.getFilterCallbackFast()->pairLost(filterPairIndex, fa0, fd0, fa1, fd1, false); + + if ((filterInfo.filterFlags & PxFilterFlag::eNOTIFY) != PxFilterFlag::eNOTIFY) + { + // No notification, hence we don't need to treat it as a filter callback pair anymore. + // Make sure that eCALLBACK gets removed as well + filterInfo.filterFlags.clear(PxFilterFlag::eNOTIFY); + } + + mFilterPairManager->releaseIndex(filterPairIndex); + filterInfo.filterPairIndex = INVALID_FILTER_PAIR_INDEX; + } + + // Sanity checks + PX_ASSERT( (filterInfo.filterFlags != PxFilterFlag::eKILL) || + ((filterInfo.filterFlags == PxFilterFlag::eKILL) && (filterInfo.filterPairIndex == INVALID_FILTER_PAIR_INDEX)) ); + PX_ASSERT( ((filterInfo.filterFlags & PxFilterFlag::eNOTIFY) != PxFilterFlag::eNOTIFY) || + (((filterInfo.filterFlags & PxFilterFlag::eNOTIFY) == PxFilterFlag::eNOTIFY) && filterInfo.filterPairIndex!=INVALID_FILTER_PAIR_INDEX) ); + + return filterInfo; +} + + +PX_FORCE_INLINE PxFilterInfo Sc::NPhaseCore::filterOutRbCollisionPair(PxU32 filterPairIndex, const PxFilterFlags filterFlags) +{ + if(filterPairIndex!=INVALID_FILTER_PAIR_INDEX) + mFilterPairManager->releaseIndex(filterPairIndex); + + return PxFilterInfo(filterFlags); +} + + +PxFilterInfo Sc::NPhaseCore::filterRbCollisionPairSecondStage(const ShapeSim& s0, const ShapeSim& s1, const Sc::BodySim* b0, const Sc::BodySim* b1, PxU32 filterPairIndex, + bool runCallbacks) +{ + PxFilterInfo filterInfo = runFilter(s0, s1, filterPairIndex, runCallbacks); + if (runCallbacks || (!(filterInfo.filterFlags & PxFilterFlag::eCALLBACK))) + filterInfo.pairFlags = checkRbPairFlags(s0, s1, b0, b1, filterInfo.pairFlags, filterInfo.filterFlags); + return filterInfo; +} + + +PxFilterInfo Sc::NPhaseCore::filterRbCollisionPair(const ShapeSim& s0, const ShapeSim& s1, PxU32 filterPairIndex, PxU32& isTriggerPair, bool runCallbacks) +{ + const Sc::BodySim* b0 = s0.getBodySim(); + const Sc::BodySim* b1 = s1.getBodySim(); + + // if not triggers... + PX_COMPILE_TIME_ASSERT(PxU32(PxShapeFlag::eTRIGGER_SHAPE) < (1 << ((sizeof(PxShapeFlags::InternalType) * 8) - 1))); + const PxU32 triggerMask = PxShapeFlag::eTRIGGER_SHAPE | (PxShapeFlag::eTRIGGER_SHAPE << 1); + const PxU32 triggerPair = (s0.getFlags() & PxShapeFlag::eTRIGGER_SHAPE) | ((s1.getFlags() & PxShapeFlag::eTRIGGER_SHAPE) << 1); + isTriggerPair = triggerPair; + if(!(triggerPair & triggerMask)) + { + const bool isS0Kinematic = b0 ? b0->isKinematic() : false; + const bool isS1Kinematic = b1 ? b1->isKinematic() : false; + + // ...and if at least one object is kinematic + const bool kinematicPair = isS0Kinematic | isS1Kinematic; + if(kinematicPair) + { + const PxSceneFlags sceneFlags = mOwnerScene.getPublicFlags(); + + // ...then ignore kinematic vs. static pairs + if(!(sceneFlags & PxSceneFlag::eENABLE_KINEMATIC_STATIC_PAIRS)) + { + if(!b0 || !b1) + return filterOutRbCollisionPair(filterPairIndex, PxFilterFlag::eSUPPRESS); + } + + // ...and ignore kinematic vs. kinematic pairs + if(!(sceneFlags & PxSceneFlag::eENABLE_KINEMATIC_PAIRS)) + { + if(isS0Kinematic && isS1Kinematic) + return filterOutRbCollisionPair(filterPairIndex, PxFilterFlag::eSUPPRESS); + } + } + } + else + { + const PxSceneFlags sceneFlags = mOwnerScene.getPublicFlags(); + if (!(sceneFlags & PxSceneFlag::eDEPRECATED_TRIGGER_TRIGGER_REPORTS)) + { + if ((triggerPair & triggerMask) != triggerMask) // only one shape is a trigger + { + return filterRbCollisionPairSecondStage(s0, s1, b0, b1, filterPairIndex, runCallbacks); + } + else + { + // trigger-trigger pairs are not supported + return filterOutRbCollisionPair(filterPairIndex, PxFilterFlag::eKILL); + } + } + else + { + return filterRbCollisionPairSecondStage(s0, s1, b0, b1, filterPairIndex, runCallbacks); + } + } + + // If the bodies of the shape pair are connected by a joint, we need to check whether this connection disables the collision. + // Note: As an optimization, the dynamic bodies have a flag which specifies whether they have any constraints at all. That works + // because a constraint has at least one dynamic body and an interaction is tracked by both objects. + bool collisionDisabled = false; + bool hasConstraintConnection = false; + + ActorSim& rbActor0 = s0.getActor(); + ActorSim& rbActor1 = s1.getActor(); + + if (b0 && b0->readInternalFlag(Sc::BodySim::BF_HAS_CONSTRAINTS)) + hasConstraintConnection = b0->isConnectedTo(rbActor1, collisionDisabled); + else if (b1 && b1->readInternalFlag(Sc::BodySim::BF_HAS_CONSTRAINTS)) + hasConstraintConnection = b1->isConnectedTo(rbActor0, collisionDisabled); + + if (!(hasConstraintConnection && collisionDisabled)) + { + if ((rbActor0.getActorType() != PxActorType::eARTICULATION_LINK) || (rbActor1.getActorType() != PxActorType::eARTICULATION_LINK)) + { + return filterRbCollisionPairSecondStage(s0, s1, b0, b1, filterPairIndex, runCallbacks); + } + else + { + // If the bodies are articulation links of the same articulation and one link is the parent of the other link, then disable collision + + PxU32 size = rbActor0.getActorInteractionCount(); + Interaction** interactions = rbActor0.getActorInteractions(); + while(size--) + { + const Interaction* interaction = *interactions++; + if(interaction->getType() == InteractionType::eARTICULATION) + { + if((&interaction->getActor0() == &rbActor1) || (&interaction->getActor1() == &rbActor1)) + return filterOutRbCollisionPair(filterPairIndex, PxFilterFlag::eKILL); + } + } + } + + return filterRbCollisionPairSecondStage(s0, s1, b0, b1, filterPairIndex, runCallbacks); + } + else + { + return filterOutRbCollisionPair(filterPairIndex, PxFilterFlag::eSUPPRESS); + } +} + + +Sc::ActorPair* Sc::NPhaseCore::findActorPair(ShapeSim* s0, ShapeSim* s1, Ps::IntBool isReportPair) +{ + PX_ASSERT(!(s0->getFlags() & PxShapeFlag::eTRIGGER_SHAPE) + && !(s1->getFlags() & PxShapeFlag::eTRIGGER_SHAPE)); + // This method is only for the case where a ShapeInteraction is going to be created. + // Else we might create an ActorPair that does not get referenced and causes a mem leak. + + + BodyPairKey key; + + RigidSim* aLess = &s0->getRbSim(); + RigidSim* aMore = &s1->getRbSim(); + + if(aLess > aMore) + Ps::swap(aLess, aMore); + + key.mSim0 = aLess; + key.mSim1 = aMore; + + Sc::ActorPair*& actorPair = mActorPairMap[key]; + + //PX_ASSERT(actorPair == NULL || actorPair->getRefCount() > 0); + if(actorPair == NULL) + { + if (!isReportPair) + actorPair = mActorPairPool.construct(); + else + actorPair = mActorPairReportPool.construct(s0->getRbSim(), s1->getRbSim()); + } + + + Ps::IntBool actorPairHasReports = actorPair->isReportPair(); + + if (!isReportPair || actorPairHasReports) + return actorPair; + else + { + PxU32 size = aLess->getActorInteractionCount(); + Interaction** interactions = aLess->getActorInteractions(); + + + ActorPairReport* actorPairReport = mActorPairReportPool.construct(s0->getRbSim(), s1->getRbSim()); + actorPairReport->convert(*actorPair); + + while (size--) + { + Interaction* interaction = *interactions++; + if ((&interaction->getActor0() == aMore) || (&interaction->getActor1() == aMore)) + { + PX_ASSERT(((&interaction->getActor0() == aLess) || (&interaction->getActor1() == aLess))); + + if(interaction->getType() == InteractionType::eOVERLAP) + { + ShapeInteraction* si = static_cast<ShapeInteraction*>(interaction); + if(si->getActorPair() != NULL) + si->setActorPair(*actorPairReport); + } + } + } + actorPair = actorPairReport; + } + return actorPair; +} + + +PX_FORCE_INLINE void Sc::NPhaseCore::destroyActorPairReport(ActorPairReport& aPair) +{ + PX_ASSERT(aPair.isReportPair()); + + aPair.releaseContactReportData(*this); + mActorPairReportPool.destroy(&aPair); +} + + +Sc::ElementSimInteraction* Sc::NPhaseCore::convert(ElementSimInteraction* pair, InteractionType::Enum newType, PxFilterInfo& filterInfo, bool removeFromDirtyList, + PxsContactManagerOutputIterator& outputs, bool useAdaptiveForce) +{ + PX_ASSERT(newType != pair->getType()); + + ElementSim& elementA = pair->getElement0(); + ElementSim& elementB = pair->getElement1(); + + ElementSimInteraction* result = NULL; + + // Wake up the actors of the pair + if ((pair->getActor0().getActorType() == PxActorType::eRIGID_DYNAMIC) && !(static_cast<BodySim&>(pair->getActor0()).isActive())) + static_cast<BodySim&>(pair->getActor0()).internalWakeUp(); + if ((pair->getActor1().getActorType() == PxActorType::eRIGID_DYNAMIC) && !(static_cast<BodySim&>(pair->getActor1()).isActive())) + static_cast<BodySim&>(pair->getActor1()).internalWakeUp(); + + switch (newType) + { + case InteractionType::eINVALID: + // This means the pair should get killed + break; + case InteractionType::eMARKER: + { + result = createElementInteractionMarker(elementA, elementB, NULL); + break; + } + case InteractionType::eOVERLAP: + { + PX_ASSERT(elementA.getElementType() == ElementType::eSHAPE && elementB.getElementType() == ElementType::eSHAPE); + result = createShapeInteraction(static_cast<ShapeSim&>(elementA), static_cast<ShapeSim&>(elementB), filterInfo.pairFlags, NULL, NULL); + break; + } + case InteractionType::eTRIGGER: + { + PX_ASSERT(elementA.getElementType() == ElementType::eSHAPE && elementB.getElementType() == ElementType::eSHAPE); + result = createTriggerInteraction(static_cast<ShapeSim&>(elementA), static_cast<ShapeSim&>(elementB), filterInfo.pairFlags); + break; + } + case InteractionType::eCONSTRAINTSHADER: +#if PX_USE_PARTICLE_SYSTEM_API + case InteractionType::ePARTICLE_BODY: +#endif + case InteractionType::eARTICULATION: + case InteractionType::eTRACKED_IN_SCENE_COUNT: + PX_ASSERT(0); + break; + }; + + if (filterInfo.filterPairIndex != INVALID_FILTER_PAIR_INDEX) + { + PX_ASSERT(result); + // If a filter callback pair is going to get killed, then the FilterPair struct should already have + // been deleted. + + // Mark the new interaction as a filter callback pair + result->raiseInteractionFlag(InteractionFlag::eIS_FILTER_PAIR); + + mFilterPairManager->set(filterInfo.filterPairIndex, result, FilterPair::ELEMENT_ELEMENT); + } + + if (pair->readInteractionFlag(InteractionFlag::eIS_FILTER_PAIR)) + pair->clearInteractionFlag(InteractionFlag::eIS_FILTER_PAIR); + // Since the FilterPair struct might have been re-used in the newly created interaction, we need to clear + // the filter pair marker of the old interaction to avoid that the FilterPair gets deleted by the releaseElementPair() + // call that follows. + + unregisterInteraction(pair); + + releaseElementPair(pair, PairReleaseFlag::eWAKE_ON_LOST_TOUCH | PairReleaseFlag::eBP_VOLUME_REMOVED, 0, removeFromDirtyList, outputs, useAdaptiveForce); + + return result; +} + + +namespace physx +{ +namespace Sc +{ +static bool findTriggerContacts(TriggerInteraction* tri, bool toBeDeleted, bool volumeRemoved, + PxTriggerPair& triggerPair, TriggerPairExtraData& triggerPairExtra, + SimStats::TriggerPairCountsNonVolatile& triggerPairStats) +{ + ShapeSim& s0 = tri->getTriggerShape(); + ShapeSim& s1 = tri->getOtherShape(); + + const PxPairFlags pairFlags = tri->getTriggerFlags(); + PxPairFlags pairEvent; + + bool overlap; + PxU8 testForRemovedShapes = 0; + if (toBeDeleted) + { + // The trigger interaction is to lie down in its tomb, hence we know that the overlap is gone. + // What remains is to check whether the interaction was deleted because of a shape removal in + // which case we need to later check for removed shapes. + + overlap = false; + + if (volumeRemoved) + { + // Note: only the first removed volume can be detected when the trigger interaction is deleted but at a later point the second volume might get removed too. + testForRemovedShapes = TriggerPairFlag::eTEST_FOR_REMOVED_SHAPES; + } + } + else + { +#if PX_ENABLE_SIM_STATS + PX_ASSERT(s0.getGeometryType() < PxGeometryType::eCONVEXMESH+1); // The first has to be the trigger shape + triggerPairStats[s0.getGeometryType()][s1.getGeometryType()]++; +#else + PX_UNUSED(triggerPairStats); +#endif + + ShapeSim* primitive0 = &s0; + ShapeSim* primitive1 = &s1; + + PX_ASSERT(primitive0->getFlags() & PxShapeFlag::eTRIGGER_SHAPE + || primitive1->getFlags() & PxShapeFlag::eTRIGGER_SHAPE); + + // Reorder them if needed + if(primitive0->getGeometryType() > primitive1->getGeometryType()) + Ps::swap(primitive0, primitive1); + + const Gu::GeomOverlapFunc overlapFunc = + Gu::getOverlapFuncTable()[primitive0->getGeometryType()][primitive1->getGeometryType()]; + + PX_ALIGN(16, PxTransform globalPose0); + primitive0->getAbsPoseAligned(&globalPose0); + + PX_ALIGN(16, PxTransform globalPose1); + primitive1->getAbsPoseAligned(&globalPose1); + + PX_ASSERT(overlapFunc); + overlap = overlapFunc( primitive0->getCore().getGeometry(), globalPose0, + primitive1->getCore().getGeometry(), globalPose1, + &tri->getTriggerCache()); + } + + const bool hadOverlap = tri->lastFrameHadContacts(); + if (hadOverlap) + { + if (!overlap) + pairEvent = PxPairFlag::eNOTIFY_TOUCH_LOST; + } + else + { + if (overlap) + pairEvent = PxPairFlag::eNOTIFY_TOUCH_FOUND; + } + tri->updateLastFrameHadContacts(overlap); + + const PxPairFlags triggeredFlags = pairEvent & pairFlags; + if (triggeredFlags) + { + triggerPair.triggerShape = s0.getPxShape(); + triggerPair.otherShape = s1.getPxShape(); + triggerPair.status = PxPairFlag::Enum(PxU32(pairEvent)); + triggerPair.flags = PxTriggerPairFlags(testForRemovedShapes); + + const RigidCore& rigidCore0 = s0.getRbSim().getRigidCore(); + const RigidCore& rigidCore1 = s1.getRbSim().getRigidCore(); + + triggerPair.triggerActor = static_cast<PxRigidActor*>(rigidCore0.getPxActor()); + triggerPair.otherActor = static_cast<PxRigidActor*>(rigidCore1.getPxActor()); + + triggerPairExtra = TriggerPairExtraData(s0.getID(), s1.getID(), + rigidCore0.getOwnerClient(), rigidCore1.getOwnerClient(), + rigidCore0.getClientBehaviorFlags(), rigidCore1.getClientBehaviorFlags()); + return true; + } + return false; +} + + +class TriggerContactTask : public Cm::Task +{ +private: + TriggerContactTask& operator = (const TriggerContactTask&); + +public: + TriggerContactTask( Interaction* const* triggerPairs, PxU32 triggerPairCount, Ps::Mutex& lock, + TriggerInteraction** pairsToDeactivate, volatile PxI32& pairsToDeactivateCount, + Scene& scene) + : + mTriggerPairs(triggerPairs), + mTriggerPairCount(triggerPairCount), + mLock(lock), + mPairsToDeactivate(pairsToDeactivate), + mPairsToDeactivateCount(pairsToDeactivateCount), + mScene(scene) + { + } + + virtual void runInternal() + { + SimStats::TriggerPairCountsNonVolatile triggerPairStats; +#if PX_ENABLE_SIM_STATS + PxMemZero(&triggerPairStats, sizeof(SimStats::TriggerPairCountsNonVolatile)); +#endif + PxTriggerPair triggerPair[sTriggerPairsPerTask]; + TriggerPairExtraData triggerPairExtra[sTriggerPairsPerTask]; + PxU32 triggerReportItemCount = 0; + + TriggerInteraction* deactivatePairs[sTriggerPairsPerTask]; + PxI32 deactivatePairCount = 0; + + for(PxU32 i=0; i < mTriggerPairCount; i++) + { + TriggerInteraction* tri = static_cast<TriggerInteraction*>(mTriggerPairs[i]); + + PX_ASSERT(tri->readInteractionFlag(InteractionFlag::eIS_ACTIVE)); + + if (findTriggerContacts(tri, false, false, triggerPair[triggerReportItemCount], triggerPairExtra[triggerReportItemCount], triggerPairStats)) + triggerReportItemCount++; + + if (!(tri->readFlag(TriggerInteraction::PROCESS_THIS_FRAME))) + { + // active trigger pairs for which overlap tests were not forced should remain in the active list + // to catch transitions between overlap and no overlap + continue; + } + else + { + tri->clearFlag(TriggerInteraction::PROCESS_THIS_FRAME); + + // explicitly scheduled overlap test is done (after object creation, teleport, ...). Check if trigger pair should remain active or not. + + if (!tri->onActivate(0)) + { + PX_ASSERT(tri->readInteractionFlag(InteractionFlag::eIS_ACTIVE)); + // Why is the assert enough? + // Once an explicit overlap test is scheduled, the interaction can not get deactivated anymore until it got processed. + + tri->clearInteractionFlag(InteractionFlag::eIS_ACTIVE); + deactivatePairs[deactivatePairCount] = tri; + deactivatePairCount++; + } + } + } + + if (triggerReportItemCount) + { + PxTriggerPair* triggerPairBuffer; + TriggerPairExtraData* triggerPairExtraBuffer; + + { + Ps::Mutex::ScopedLock lock(mLock); + + mScene.reserveTriggerReportBufferSpace(triggerReportItemCount, triggerPairBuffer, triggerPairExtraBuffer); + + PxMemCopy(triggerPairBuffer, triggerPair, sizeof(PxTriggerPair) * triggerReportItemCount); + PxMemCopy(triggerPairExtraBuffer, triggerPairExtra, sizeof(TriggerPairExtraData) * triggerReportItemCount); + } + } + + if (deactivatePairCount) + { + PxI32 newSize = Ps::atomicAdd(&mPairsToDeactivateCount, deactivatePairCount); + PxMemCopy(mPairsToDeactivate + newSize - deactivatePairCount, deactivatePairs, sizeof(TriggerInteraction*) * deactivatePairCount); + } + +#if PX_ENABLE_SIM_STATS + SimStats& simStats = mScene.getStatsInternal(); + for(PxU32 i=0; i < PxGeometryType::eCONVEXMESH+1; i++) + { + for(PxU32 j=0; j < PxGeometryType::eGEOMETRY_COUNT; j++) + { + if (triggerPairStats[i][j] != 0) + Ps::atomicAdd(&simStats.numTriggerPairs[i][j], triggerPairStats[i][j]); + } + } +#endif + } + + virtual const char* getName() const + { + return "ScNPhaseCore.triggerInteractionWork"; + } + + +public: + static const PxU32 sTriggerPairsPerTask = 64; + +private: + Interaction* const* mTriggerPairs; + const PxU32 mTriggerPairCount; + Ps::Mutex& mLock; + TriggerInteraction** mPairsToDeactivate; + volatile PxI32& mPairsToDeactivateCount; + Scene& mScene; +}; + +} // namespace Sc +} // namespace physx + + +void Sc::NPhaseCore::processTriggerInteractions(PxBaseTask* continuation) +{ + PX_ASSERT(!mTmpTriggerProcessingBlock); + PX_ASSERT(mTriggerPairsToDeactivateCount == 0); + + Scene& scene = mOwnerScene; + + // Triggers + Interaction** triggerInteractions = mOwnerScene.getActiveInteractions(InteractionType::eTRIGGER); + const PxU32 pairCount = mOwnerScene.getNbActiveInteractions(InteractionType::eTRIGGER); + + if (pairCount > 0) + { + const PxU32 taskCountWithoutRemainder = pairCount / TriggerContactTask::sTriggerPairsPerTask; + const PxU32 maxTaskCount = taskCountWithoutRemainder + 1; + const PxU32 pairPtrSize = pairCount * sizeof(TriggerInteraction*); + const PxU32 memBlockSize = pairPtrSize + (maxTaskCount * sizeof(TriggerContactTask)); + void* triggerProcessingBlock = scene.getLowLevelContext()->getScratchAllocator().alloc(memBlockSize, true); + if (triggerProcessingBlock) + { + const bool hasMultipleThreads = scene.getTaskManager().getCpuDispatcher()->getWorkerCount() > 1; + const bool moreThanOneBatch = pairCount > TriggerContactTask::sTriggerPairsPerTask; + const bool scheduleTasks = hasMultipleThreads && moreThanOneBatch; + // when running on a single thread, the task system seems to cause the main overhead (locking and atomic operations + // seemed less of an issue). Hence, the tasks get run directly in that case. Same if there is only one batch. + + mTmpTriggerProcessingBlock = triggerProcessingBlock; // note: gets released in the continuation task + if (scheduleTasks) + mMergeProcessedTriggerInteractions.setContinuation(continuation); + + TriggerInteraction** triggerPairsToDeactivateWriteBack = reinterpret_cast<TriggerInteraction**>(triggerProcessingBlock); + TriggerContactTask* triggerContactTaskBuffer = reinterpret_cast<TriggerContactTask*>(reinterpret_cast<PxU8*>(triggerProcessingBlock) + pairPtrSize); + + PxU32 remainder = pairCount; + while(remainder) + { + const PxU32 nb = remainder > TriggerContactTask::sTriggerPairsPerTask ? TriggerContactTask::sTriggerPairsPerTask : remainder; + remainder -= nb; + + TriggerContactTask* task = triggerContactTaskBuffer; + task = PX_PLACEMENT_NEW(task, TriggerContactTask( triggerInteractions, nb, mTriggerWriteBackLock, + triggerPairsToDeactivateWriteBack, mTriggerPairsToDeactivateCount, scene)); + if (scheduleTasks) + { + task->setContinuation(&mMergeProcessedTriggerInteractions); + task->removeReference(); + } + else + task->runInternal(); + + triggerContactTaskBuffer++; + triggerInteractions += nb; + } + + if (scheduleTasks) + mMergeProcessedTriggerInteractions.removeReference(); + else + mMergeProcessedTriggerInteractions.runInternal(); + } + else + { + Ps::getFoundation().getErrorCallback().reportError(PxErrorCode::eOUT_OF_MEMORY, "Temporary memory for trigger pair processing could not be allocated. Trigger overlap tests will not take place.", __FILE__, __LINE__); + } + } +} + + +void Sc::NPhaseCore::mergeProcessedTriggerInteractions(PxBaseTask*) +{ + if (mTmpTriggerProcessingBlock) + { + // deactivate pairs that do not need trigger checks any longer (until woken up again) + TriggerInteraction** triggerPairsToDeactivate = reinterpret_cast<TriggerInteraction**>(mTmpTriggerProcessingBlock); + for(PxI32 i=0; i < mTriggerPairsToDeactivateCount; i++) + { + mOwnerScene.notifyInteractionDeactivated(triggerPairsToDeactivate[i]); + } + mTriggerPairsToDeactivateCount = 0; + + mOwnerScene.getLowLevelContext()->getScratchAllocator().free(mTmpTriggerProcessingBlock); + mTmpTriggerProcessingBlock = NULL; + } +} + + +void Sc::NPhaseCore::visualize(Cm::RenderOutput& renderOut, PxsContactManagerOutputIterator& outputs) +{ + if(mOwnerScene.getVisualizationScale() == 0.0f) + return; + + Interaction** interactions = mOwnerScene.getActiveInteractions(InteractionType::eOVERLAP); + PxU32 nbActiveInteractions = mOwnerScene.getNbActiveInteractions(InteractionType::eOVERLAP); + while(nbActiveInteractions--) + static_cast<ShapeInteraction*>(*interactions++)->visualize(renderOut, outputs); + +} + + +void Sc::NPhaseCore::processPersistentContactEvents(PxsContactManagerOutputIterator& outputs) +{ + //TODO: put back this optimization -- now we have to do this stuff if at least one client has a callback registered. + // if (ownerScene.getSimulatonEventCallbackFast() != NULL) + { + // Go through ShapeInteractions which requested persistent contact event reports. This is necessary since there are no low level events for persistent contact. + ShapeInteraction*const* persistentEventPairs = getCurrentPersistentContactEventPairs(); + PxU32 size = getCurrentPersistentContactEventPairCount(); + while(size--) + { + ShapeInteraction* pair = *persistentEventPairs++; + if(size) + { + ShapeInteraction* nextPair = *persistentEventPairs; + Ps::prefetchLine(nextPair); + } + + ActorPair* aPair = pair->getActorPair(); + Ps::prefetchLine(aPair); + + PX_ASSERT(pair->hasTouch()); + PX_ASSERT(pair->isReportPair()); + + const PxU32 pairFlags = pair->getPairFlags(); + if ((pairFlags & PxU32(PxPairFlag::eNOTIFY_TOUCH_PERSISTS | PxPairFlag::eDETECT_DISCRETE_CONTACT)) == PxU32(PxPairFlag::eNOTIFY_TOUCH_PERSISTS | PxPairFlag::eDETECT_DISCRETE_CONTACT)) + { + // do not process the pair if only eDETECT_CCD_CONTACT is enabled because at this point CCD did not run yet. Plus the current CCD implementation can not reliably provide eNOTIFY_TOUCH_PERSISTS events + // for performance reasons. + //KS - filter based on edge activity! + + const BodySim* bodySim0 = pair->getShape0().getBodySim(); + const BodySim* bodySim1 = pair->getShape1().getBodySim(); + PX_ASSERT(bodySim0); // the first shape always belongs to a dynamic body + + if (bodySim0->isActive() || + (bodySim1 && bodySim1->isActive())) + { + pair->processUserNotification(PxPairFlag::eNOTIFY_TOUCH_PERSISTS, 0, false, 0, false, outputs); + } + } + } + } +} + + +void Sc::NPhaseCore::fireCustomFilteringCallbacks(PxsContactManagerOutputIterator& outputs, bool useAdaptiveForce) +{ + PX_PROFILE_ZONE("Sim.fireCustomFilteringCallbacks", mOwnerScene.getContextId()); + + PxSimulationFilterCallback* callback = mOwnerScene.getFilterCallbackFast(); + + if (callback) + { + // Ask user for pair filter status changes + PxU32 pairID; + PxFilterFlags filterFlags; + PxPairFlags pairFlags; + while(callback->statusChange(pairID, pairFlags, filterFlags)) + { + const FilterPair& fp = (*mFilterPairManager)[pairID]; + + PX_ASSERT(fp.getType() != FilterPair::INVALID); + // Check if the user tries to update a pair even though he deleted it earlier in the same frame + + filterFlags = checkFilterFlags(filterFlags); + + if (fp.getType() == FilterPair::ELEMENT_ELEMENT) + { + ElementSimInteraction* ei = fp.getPtr<ElementSimInteraction>(); + PX_ASSERT(ei->readInteractionFlag(InteractionFlag::eIS_FILTER_PAIR)); + + PxFilterInfo finfo; + finfo.filterFlags = filterFlags; + finfo.pairFlags = pairFlags; + finfo.filterPairIndex = pairID; + + ElementSimInteraction* refInt = refilterInteraction(ei, &finfo, true, outputs, useAdaptiveForce); + + // this gets called at the end of the simulation -> there should be no dirty interactions around + PX_ASSERT(!refInt->readInteractionFlag(InteractionFlag::eIN_DIRTY_LIST)); + PX_ASSERT(!refInt->getDirtyFlags()); + + if ((refInt == ei) && (refInt->getType() == InteractionType::eOVERLAP)) // No interaction conversion happened, the pairFlags were just updated + { + static_cast<ShapeInteraction*>(refInt)->updateState(InteractionDirtyFlag::eFILTER_STATE); + } + } + else + { + PX_ASSERT(fp.getType() == FilterPair::ELEMENT_ACTOR); + ActorElementPair* aep = fp.getPtr<ActorElementPair>(); + + PxFilterInfo finfo; + + if ((filterFlags & PxFilterFlag::eNOTIFY) != PxFilterFlag::eNOTIFY) + { + mFilterPairManager->releaseIndex(pairID); + aep->markAsFilterPair(false); + } + else + finfo.filterPairIndex = pairID; + + finfo.filterFlags = filterFlags; + finfo.pairFlags = pairFlags; + + aep->setPairFlags(pairFlags); + if (filterFlags & PxFilterFlag::eKILL) + aep->markAsKilled(true); + else if (filterFlags & PxFilterFlag::eSUPPRESS) + aep->markAsSuppressed(true); + +#if PX_USE_PARTICLE_SYSTEM_API + ActorSim* actor = &aep->getActor(); + ElementSim* element = &aep->getElement(); + + ElementSim::ElementInteractionReverseIterator iter = element->getElemInteractionsReverse(); + ElementSimInteraction* interaction = iter.getNext(); + while(interaction) + { + if(interaction->getType() == InteractionType::ePARTICLE_BODY) + { + ParticleElementRbElementInteraction* pri = static_cast<ParticleElementRbElementInteraction*>(interaction); + + PX_ASSERT(pri->getElement0().getElementType() == ElementType::ePARTICLE_PACKET); + if ((&pri->getElement1() == element) && (&pri->getActor0() == actor)) + { + PX_ASSERT(pri->readInteractionFlag(InteractionFlag::eIS_FILTER_PAIR)); + refilterInteraction(pri, &finfo, true, outputs, useAdaptiveForce); + + // this gets called at the end of the simulation -> there should be no dirty interactions around + PX_ASSERT(!pri->readInteractionFlag(InteractionFlag::eIN_DIRTY_LIST)); + PX_ASSERT(!pri->getDirtyFlags()); + } + } + + interaction = iter.getNext(); + } +#endif // PX_USE_PARTICLE_SYSTEM_API + } + } + } +} + + +void Sc::NPhaseCore::addToDirtyInteractionList(Interaction* pair) +{ + mDirtyInteractions.insert(pair); +} + + +void Sc::NPhaseCore::removeFromDirtyInteractionList(Interaction* pair) +{ + PX_ASSERT(mDirtyInteractions.contains(pair)); + + mDirtyInteractions.erase(pair); +} + + +void Sc::NPhaseCore::updateDirtyInteractions(PxsContactManagerOutputIterator& outputs, bool useAdaptiveForce) +{ + // The sleeping SIs will be updated on activation + // clow: Sleeping SIs are not awaken for visualization updates + const bool dirtyDominance = mOwnerScene.readFlag(SceneInternalFlag::eSCENE_SIP_STATES_DIRTY_DOMINANCE); + const bool dirtyVisualization = mOwnerScene.readFlag(SceneInternalFlag::eSCENE_SIP_STATES_DIRTY_VISUALIZATION); + if (dirtyDominance || dirtyVisualization) + { + // Update all interactions. + + const PxU8 mask = Ps::to8((dirtyDominance ? InteractionDirtyFlag::eDOMINANCE : 0) | (dirtyVisualization ? InteractionDirtyFlag::eVISUALIZATION : 0)); + + Interaction** it = mOwnerScene.getInteractions(Sc::InteractionType::eOVERLAP); + PxU32 size = mOwnerScene.getNbInteractions(Sc::InteractionType::eOVERLAP); + while(size--) + { + Interaction* pair = *it++; + + PX_ASSERT(pair->getType() == InteractionType::eOVERLAP); + + if (!pair->readInteractionFlag(InteractionFlag::eIN_DIRTY_LIST)) + { + PX_ASSERT(!pair->getDirtyFlags()); + static_cast<ShapeInteraction*>(pair)->updateState(mask); + } + else + pair->setDirty(mask); // the pair will get processed further below anyway, so just mark the flags dirty + } + } + + // Update all interactions in the dirty list + const PxU32 dirtyItcCount = mDirtyInteractions.size(); + Sc::Interaction* const* dirtyInteractions = mDirtyInteractions.getEntries(); + for (PxU32 i = 0; i < dirtyItcCount; i++) + { + Interaction* refInt = dirtyInteractions[i]; + Interaction* interaction = refInt; + + if (interaction->isElementInteraction() && interaction->needsRefiltering()) + { + ElementSimInteraction* pair = static_cast<ElementSimInteraction*>(interaction); + + refInt = refilterInteraction(pair, NULL, false, outputs, useAdaptiveForce); + } + + if (interaction == refInt) // Refiltering might convert the pair to another type and kill the old one. In that case we don't want to update the new pair since it has been updated on creation. + { + const InteractionType::Enum iType = interaction->getType(); + if (iType == InteractionType::eOVERLAP) + static_cast<ShapeInteraction*>(interaction)->updateState(0); + else if (iType == InteractionType::eCONSTRAINTSHADER) + static_cast<ConstraintInteraction*>(interaction)->updateState(); + + interaction->setClean(false); // false because the dirty interactions list gets cleard further below + } + } + + mDirtyInteractions.clear(); +} + + +void Sc::NPhaseCore::releaseElementPair(ElementSimInteraction* pair, PxU32 flags, const PxU32 ccdPass, bool removeFromDirtyList, PxsContactManagerOutputIterator& outputs, + bool useAdaptiveForce) +{ + pair->setClean(removeFromDirtyList); // Removes the pair from the dirty interaction list etc. + + if (pair->readInteractionFlag(InteractionFlag::eIS_FILTER_PAIR) && pair->isLastFilterInteraction()) + { + // Check if this is a filter callback pair + const PxU32 filterPairIndex = mFilterPairManager->findIndex(pair); + PX_ASSERT(filterPairIndex!=INVALID_FILTER_PAIR_INDEX); + + // Is this interaction removed because one of the pair object broadphase volumes got deleted by the user? + const bool userRemovedVolume = ((flags & PairReleaseFlag::eBP_VOLUME_REMOVED) != 0); + + callPairLost(pair->getElement0(), pair->getElement1(), filterPairIndex, userRemovedVolume); + + mFilterPairManager->releaseIndex(filterPairIndex); + } + + switch (pair->getType()) + { + case InteractionType::eTRIGGER: + { + TriggerInteraction* tri = static_cast<TriggerInteraction*>(pair); + PxTriggerPair triggerPair; + TriggerPairExtraData triggerPairExtra; + if (findTriggerContacts(tri, true, ((flags & PairReleaseFlag::eBP_VOLUME_REMOVED) != 0), + triggerPair, triggerPairExtra, + const_cast<SimStats::TriggerPairCountsNonVolatile&>(mOwnerScene.getStatsInternal().numTriggerPairs))) + // cast away volatile-ness (this is fine since the method does not run in parallel) + { + mOwnerScene.getTriggerBufferAPI().pushBack(triggerPair); + mOwnerScene.getTriggerBufferExtraData().pushBack(triggerPairExtra); + } + mTriggerInteractionPool.destroy(tri); + } + break; + case InteractionType::eMARKER: + { + ElementInteractionMarker* interactionMarker = static_cast<ElementInteractionMarker*>(pair); + mInteractionMarkerPool.destroy(interactionMarker); + } + break; + case InteractionType::eOVERLAP: + { + ShapeInteraction* si = static_cast<ShapeInteraction*>(pair); + releaseShapeInteraction(si, flags, ccdPass, outputs, useAdaptiveForce); + } + break; +#if PX_USE_PARTICLE_SYSTEM_API + case InteractionType::ePARTICLE_BODY: + { + ParticleElementRbElementInteraction* pbi = static_cast<ParticleElementRbElementInteraction*>(pair); + pool_deleteParticleElementRbElementPair(pbi, flags, ccdPass); + } + break; +#endif + case InteractionType::eCONSTRAINTSHADER: + case InteractionType::eARTICULATION: + case InteractionType::eTRACKED_IN_SCENE_COUNT: + case InteractionType::eINVALID: + PX_ASSERT(0); + return; + } +} + +void Sc::NPhaseCore::lostTouchReports(ShapeInteraction* si, PxU32 flags, PxU32 ccdPass, PxsContactManagerOutputIterator& outputs, bool useAdaptiveForce) +{ + if (si->hasTouch()) + { + if (si->isReportPair()) + { + si->sendLostTouchReport((flags & PairReleaseFlag::eBP_VOLUME_REMOVED) != 0, ccdPass, outputs); + } + + si->adjustCountersOnLostTouch(si->getShape0().getBodySim(), si->getShape1().getBodySim(), useAdaptiveForce); + } + + ActorPair* aPair = si->getActorPair(); + if (aPair && aPair->decRefCount() == 0) + { + RigidSim* sim0 = static_cast<RigidSim*>(&si->getActor0()); + RigidSim* sim1 = static_cast<RigidSim*>(&si->getActor1()); + if (sim0 > sim1) + Ps::swap(sim0, sim1); + + BodyPairKey pair; + pair.mSim0 = sim0; + pair.mSim1 = sim1; + + mActorPairMap.erase(pair); + + if (!aPair->isReportPair()) + { + mActorPairPool.destroy(aPair); + } + else + { + ActorPairReport& apr = ActorPairReport::cast(*aPair); + destroyActorPairReport(apr); + } + } + si->clearActorPair(); + + if (si->hasTouch() || (!si->hasKnownTouchState())) + { + BodySim* b0 = si->getShape0().getBodySim(); + BodySim* b1 = si->getShape1().getBodySim(); + + if (flags & PairReleaseFlag::eWAKE_ON_LOST_TOUCH) + { + if (!b0 || !b1) + { + if (b0) + b0->internalWakeUp(); + if (b1) + b1->internalWakeUp(); + } + else if (!si->readFlag(ShapeInteraction::CONTACTS_RESPONSE_DISABLED)) + { + mOwnerScene.addToLostTouchList(b0, b1); + } + } + } +} + + +void Sc::NPhaseCore::releaseShapeInteraction(ShapeInteraction* si, PxU32 flags, const PxU32 ccdPass, PxsContactManagerOutputIterator& outputs, bool useAdaptiveForce) +{ + + if (flags & PairReleaseFlag::eSHAPE_BP_VOLUME_REMOVED) + { + lostTouchReports(si, flags, ccdPass, outputs, useAdaptiveForce); + } + mShapeInteractionPool.destroy(si); + +} + + +void Sc::NPhaseCore::clearContactReportActorPairs(bool shrinkToZero) +{ + for(PxU32 i=0; i < mContactReportActorPairSet.size(); i++) + { + //TODO: prefetch? + ActorPairReport* aPair = mContactReportActorPairSet[i]; + const PxU32 refCount = aPair->getRefCount(); + PX_ASSERT(aPair->isInContactReportActorPairSet()); + PX_ASSERT(refCount > 0); + aPair->decRefCount(); // Reference held by contact callback + if (refCount > 1) + { + aPair->clearInContactReportActorPairSet(); + } + else + { + + RigidSim* sim0 = &aPair->getActorA(); + RigidSim* sim1 = &aPair->getActorB(); + + if(sim0 > sim1) + Ps::swap(sim0, sim1); + + BodyPairKey pair; + pair.mSim0 = sim0; + pair.mSim1 = sim1; + + mActorPairMap.erase(pair); + destroyActorPairReport(*aPair); + } + } + + if (!shrinkToZero) + mContactReportActorPairSet.clear(); + else + mContactReportActorPairSet.reset(); +} + + +#if PX_USE_PARTICLE_SYSTEM_API +Sc::ParticleElementRbElementInteraction* Sc::NPhaseCore::insertParticleElementRbElementPair(ParticlePacketShape& particleShape, ShapeSim& rbShape, ActorElementPair* actorElementPair, const PxU32 ccdPass) +{ + // The ccdPass parameter is needed to avoid concurrent interaction updates while the gpu particle pipeline is running. + ParticleElementRbElementInteraction* pbi = mParticleBodyPool.construct(particleShape, rbShape, *actorElementPair, ccdPass); + if (pbi) + actorElementPair->incRefCount(); + + return pbi; +} +#endif + + +void Sc::NPhaseCore::addToPersistentContactEventPairs(ShapeInteraction* si) +{ + // Pairs which request events which do not get triggered by the sdk and thus need to be tested actively every frame. + PX_ASSERT(si->getPairFlags() & (PxPairFlag::eNOTIFY_TOUCH_PERSISTS | ShapeInteraction::CONTACT_FORCE_THRESHOLD_PAIRS)); + PX_ASSERT(si->mReportPairIndex == INVALID_REPORT_PAIR_ID); + PX_ASSERT(!si->readFlag(ShapeInteraction::IS_IN_PERSISTENT_EVENT_LIST)); + PX_ASSERT(!si->readFlag(ShapeInteraction::IS_IN_FORCE_THRESHOLD_EVENT_LIST)); + PX_ASSERT(si->hasTouch()); // only pairs which can from now on lose or keep contact should be in this list + + si->raiseFlag(ShapeInteraction::IS_IN_PERSISTENT_EVENT_LIST); + if (mPersistentContactEventPairList.size() == mNextFramePersistentContactEventPairIndex) + { + si->mReportPairIndex = mPersistentContactEventPairList.size(); + mPersistentContactEventPairList.pushBack(si); + } + else + { + //swap with first entry that will be active next frame + ShapeInteraction* firstDelayedSi = mPersistentContactEventPairList[mNextFramePersistentContactEventPairIndex]; + firstDelayedSi->mReportPairIndex = mPersistentContactEventPairList.size(); + mPersistentContactEventPairList.pushBack(firstDelayedSi); + si->mReportPairIndex = mNextFramePersistentContactEventPairIndex; + mPersistentContactEventPairList[mNextFramePersistentContactEventPairIndex] = si; + } + + mNextFramePersistentContactEventPairIndex++; +} + + +void Sc::NPhaseCore::addToPersistentContactEventPairsDelayed(ShapeInteraction* si) +{ + // Pairs which request events which do not get triggered by the sdk and thus need to be tested actively every frame. + PX_ASSERT(si->getPairFlags() & (PxPairFlag::eNOTIFY_TOUCH_PERSISTS | ShapeInteraction::CONTACT_FORCE_THRESHOLD_PAIRS)); + PX_ASSERT(si->mReportPairIndex == INVALID_REPORT_PAIR_ID); + PX_ASSERT(!si->readFlag(ShapeInteraction::IS_IN_PERSISTENT_EVENT_LIST)); + PX_ASSERT(!si->readFlag(ShapeInteraction::IS_IN_FORCE_THRESHOLD_EVENT_LIST)); + PX_ASSERT(si->hasTouch()); // only pairs which can from now on lose or keep contact should be in this list + + si->raiseFlag(ShapeInteraction::IS_IN_PERSISTENT_EVENT_LIST); + si->mReportPairIndex = mPersistentContactEventPairList.size(); + mPersistentContactEventPairList.pushBack(si); +} + + +void Sc::NPhaseCore::removeFromPersistentContactEventPairs(ShapeInteraction* si) +{ + PX_ASSERT(si->getPairFlags() & (PxPairFlag::eNOTIFY_TOUCH_PERSISTS | ShapeInteraction::CONTACT_FORCE_THRESHOLD_PAIRS)); + PX_ASSERT(si->readFlag(ShapeInteraction::IS_IN_PERSISTENT_EVENT_LIST)); + PX_ASSERT(!si->readFlag(ShapeInteraction::IS_IN_FORCE_THRESHOLD_EVENT_LIST)); + PX_ASSERT(si->hasTouch()); // only pairs which could lose or keep contact should be in this list + + PxU32 index = si->mReportPairIndex; + PX_ASSERT(index != INVALID_REPORT_PAIR_ID); + + if (index < mNextFramePersistentContactEventPairIndex) + { + const PxU32 replaceIdx = mNextFramePersistentContactEventPairIndex - 1; + + if ((mNextFramePersistentContactEventPairIndex < mPersistentContactEventPairList.size()) && (index != replaceIdx)) + { + // keep next frame persistent pairs at the back of the list + ShapeInteraction* tmp = mPersistentContactEventPairList[replaceIdx]; + mPersistentContactEventPairList[index] = tmp; + tmp->mReportPairIndex = index; + index = replaceIdx; + } + + mNextFramePersistentContactEventPairIndex--; + } + + si->clearFlag(ShapeInteraction::IS_IN_PERSISTENT_EVENT_LIST); + si->mReportPairIndex = INVALID_REPORT_PAIR_ID; + mPersistentContactEventPairList.replaceWithLast(index); + if (index < mPersistentContactEventPairList.size()) // Only adjust the index if the removed SIP was not at the end of the list + mPersistentContactEventPairList[index]->mReportPairIndex = index; +} + + +void Sc::NPhaseCore::addToForceThresholdContactEventPairs(ShapeInteraction* si) +{ + PX_ASSERT(si->getPairFlags() & ShapeInteraction::CONTACT_FORCE_THRESHOLD_PAIRS); + PX_ASSERT(si->mReportPairIndex == INVALID_REPORT_PAIR_ID); + PX_ASSERT(!si->readFlag(ShapeInteraction::IS_IN_PERSISTENT_EVENT_LIST)); + PX_ASSERT(!si->readFlag(ShapeInteraction::IS_IN_FORCE_THRESHOLD_EVENT_LIST)); + PX_ASSERT(si->hasTouch()); + + si->raiseFlag(ShapeInteraction::IS_IN_FORCE_THRESHOLD_EVENT_LIST); + si->mReportPairIndex = mForceThresholdContactEventPairList.size(); + mForceThresholdContactEventPairList.pushBack(si); +} + + +void Sc::NPhaseCore::removeFromForceThresholdContactEventPairs(ShapeInteraction* si) +{ + PX_ASSERT(si->getPairFlags() & ShapeInteraction::CONTACT_FORCE_THRESHOLD_PAIRS); + PX_ASSERT(si->readFlag(ShapeInteraction::IS_IN_FORCE_THRESHOLD_EVENT_LIST)); + PX_ASSERT(!si->readFlag(ShapeInteraction::IS_IN_PERSISTENT_EVENT_LIST)); + PX_ASSERT(si->hasTouch()); + + const PxU32 index = si->mReportPairIndex; + PX_ASSERT(index != INVALID_REPORT_PAIR_ID); + + si->clearFlag(ShapeInteraction::IS_IN_FORCE_THRESHOLD_EVENT_LIST); + si->mReportPairIndex = INVALID_REPORT_PAIR_ID; + mForceThresholdContactEventPairList.replaceWithLast(index); + if (index < mForceThresholdContactEventPairList.size()) // Only adjust the index if the removed SIP was not at the end of the list + mForceThresholdContactEventPairList[index]->mReportPairIndex = index; +} + + +PxU8* Sc::NPhaseCore::reserveContactReportPairData(PxU32 pairCount, PxU32 extraDataSize, PxU32& bufferIndex) +{ + extraDataSize = Sc::ContactStreamManager::computeExtraDataBlockSize(extraDataSize); + return mContactReportBuffer.allocateNotThreadSafe(extraDataSize + (pairCount * sizeof(Sc::ContactShapePair)), bufferIndex); +} + + +PxU8* Sc::NPhaseCore::resizeContactReportPairData(PxU32 pairCount, PxU32 extraDataSize, Sc::ContactStreamManager& csm) +{ + PX_ASSERT((pairCount > csm.maxPairCount) || (extraDataSize > csm.getMaxExtraDataSize())); + PX_ASSERT((csm.currentPairCount == csm.maxPairCount) || (extraDataSize > csm.getMaxExtraDataSize())); + PX_ASSERT(extraDataSize >= csm.getMaxExtraDataSize()); // we do not support stealing memory from the extra data part when the memory for pair info runs out + + PxU32 bufferIndex; + Ps::prefetch(mContactReportBuffer.getData(csm.bufferIndex)); + + extraDataSize = Sc::ContactStreamManager::computeExtraDataBlockSize(extraDataSize); + PxU8* stream = mContactReportBuffer.reallocateNotThreadSafe(extraDataSize + (pairCount * sizeof(Sc::ContactShapePair)), bufferIndex, 16, csm.bufferIndex); + PxU8* oldStream = mContactReportBuffer.getData(csm.bufferIndex); + if(stream) + { + const PxU32 maxExtraDataSize = csm.getMaxExtraDataSize(); + if(csm.bufferIndex != bufferIndex) + { + if (extraDataSize <= maxExtraDataSize) + PxMemCopy(stream, oldStream, maxExtraDataSize + (csm.currentPairCount * sizeof(Sc::ContactShapePair))); + else + { + PxMemCopy(stream, oldStream, csm.extraDataSize); + PxMemCopy(stream + extraDataSize, oldStream + maxExtraDataSize, csm.currentPairCount * sizeof(Sc::ContactShapePair)); + } + csm.bufferIndex = bufferIndex; + } + else if (extraDataSize > maxExtraDataSize) + PxMemMove(stream + extraDataSize, oldStream + maxExtraDataSize, csm.currentPairCount * sizeof(Sc::ContactShapePair)); + + if (pairCount > csm.maxPairCount) + csm.maxPairCount = Ps::to16(pairCount); + if (extraDataSize > maxExtraDataSize) + csm.setMaxExtraDataSize(extraDataSize); + } + + return stream; +} + + +Sc::ActorPairContactReportData* Sc::NPhaseCore::createActorPairContactReportData() +{ + return mActorPairContactReportDataPool.construct(); +} + + +void Sc::NPhaseCore::releaseActorPairContactReportData(ActorPairContactReportData* data) +{ + mActorPairContactReportDataPool.destroy(data); +} + +#if PX_USE_PARTICLE_SYSTEM_API +void Sc::NPhaseCore::pool_deleteParticleElementRbElementPair(ParticleElementRbElementInteraction* pair, PxU32 flags, const PxU32 ccdPass) +{ + ActorElementPair* aep = pair->getActorElementPair(); + + // The ccdPass parameter is needed to avoid concurrent interaction updates while the gpu particle pipeline is running. + pair->ParticleElementRbElementInteraction::destroy(((flags & PairReleaseFlag::eSHAPE_BP_VOLUME_REMOVED) == PairReleaseFlag::eSHAPE_BP_VOLUME_REMOVED), ccdPass); + mParticleBodyPool.destroy(pair); + + if (aep->decRefCount() == 0) + mActorElementPairPool.destroy(aep); +} +#endif // PX_USE_PARTICLE_SYSTEM_API + + diff --git a/PhysX_3.4/Source/SimulationController/src/ScNPhaseCore.h b/PhysX_3.4/Source/SimulationController/src/ScNPhaseCore.h new file mode 100644 index 00000000..e9402801 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScNPhaseCore.h @@ -0,0 +1,385 @@ +// 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_NPHASE_CORE +#define PX_PHYSICS_SCP_NPHASE_CORE + +#include "CmPhysXCommon.h" +#include "CmRenderOutput.h" +#include "PxPhysXConfig.h" +#include "PsUserAllocated.h" +#include "PsMutex.h" +#include "PsAtomic.h" +#include "PsPool.h" +#include "PsHashSet.h" +#include "PsHashMap.h" +#include "PxSimulationEventCallback.h" +#include "ScTriggerPairs.h" +#include "ScScene.h" +#include "ScContactReportBuffer.h" +#include "PsHash.h" + + +namespace physx +{ + +namespace Bp +{ + struct AABBOverlap; + struct BroadPhasePair; +} + +struct PxFilterInfo; + +namespace Sc +{ + class ActorSim; + class ElementSim; + class ShapeSim; + class ClothSim; + +#if PX_USE_PARTICLE_SYSTEM_API + class ParticlePacketShape; +#endif + + class Interaction; + class ElementSimInteraction; + class ElementInteractionMarker; + class RbElementInteraction; + class TriggerInteraction; +#if PX_USE_PARTICLE_SYSTEM_API + class ParticleElementRbElementInteraction; +#endif + + class ShapeInteraction; + class ActorElementPair; + class ActorPair; + class ActorPairReport; + + class ActorPairContactReportData; + struct ContactShapePair; + + class NPhaseContext; + class ContactStreamManager; + + struct FilterPair; + class FilterPairManager; + + class RigidSim; + + + struct PairReleaseFlag + { + enum Enum + { + eBP_VOLUME_REMOVED = (1 << 0), // the broadphase volume of one pair object has been removed. + eSHAPE_BP_VOLUME_REMOVED = (1 << 1) | eBP_VOLUME_REMOVED, // the removed broadphase volume was from a rigid body shape. + eWAKE_ON_LOST_TOUCH = (1 << 2) + }; + }; + + /* + Description: NPhaseCore encapsulates the near phase processing to allow multiple implementations(eg threading and non + threaded). + + The broadphase inserts shape pairs into the NPhaseCore, which are then processed into contact point streams. + Pairs can then be processed into AxisConstraints by the GroupSolveCore. + + */ + + + + + struct BodyPairKey + { + RigidSim* mSim0; + RigidSim* mSim1; + + bool operator == (const BodyPairKey& pair) const { return mSim0 == pair.mSim0 && mSim1 == pair.mSim1; } + }; + + + + PX_INLINE PxU32 hash(const BodyPairKey& key) + { + PxU32 add0 = (size_t(key.mSim0))&0xFFFFFFFF; + PxU32 add1 = (size_t(key.mSim1))&0xFFFFFFFF; + + //Clear the lower 2 bits, they will be 0s anyway + add0 = add0 >> 2; + add1 = add1 >> 2; + + PxU32 base = PxU32((add0 & 0xFFFF) | (add1 << 16)); + + return physx::shdfnd::hash(base); + } + + struct ElementSimKey + { + ElementSim* mSim0, *mSim1; + + ElementSimKey(ElementSim* sim0 = NULL, ElementSim* sim1 = NULL) : mSim0(sim0), mSim1(sim1) + {} + + bool operator == (const ElementSimKey& pair) const { return mSim0 == pair.mSim0 && mSim1 == pair.mSim1; } + + }; + + PX_INLINE PxU32 hash(const ElementSimKey& key) + { + PxU32 add0 = (size_t(key.mSim0)) & 0xFFFFFFFF; + PxU32 add1 = (size_t(key.mSim1)) & 0xFFFFFFFF; + + //Clear the lower 2 bits, they will be 0s anyway + add0 = add0 >> 2; + add1 = add1 >> 2; + + PxU32 base = PxU32((add0 & 0xFFFF) | (add1 << 16)); + + return physx::shdfnd::hash(base); + } + + + class NPhaseCore : public Ps::UserAllocated + { + PX_NOCOPY(NPhaseCore) + + public: + NPhaseCore(Scene& scene, const PxSceneDesc& desc); + ~NPhaseCore(); + + void onOverlapCreated(const Bp::AABBOverlap* PX_RESTRICT pairs, PxU32 pairCount, const PxU32 ccdPass, Bp::BroadPhasePair* bpPairs); + Sc::Interaction* onOverlapCreated(ElementSim* volume0, ElementSim* volume1, const PxU32 ccdPass, Bp::BroadPhasePair* bpPairs); + PxFilterInfo onOverlapFilter(ElementSim* volume0, ElementSim* volume1, Bp::BroadPhasePair* pair); + + + ElementSimInteraction* onOverlapRemovedStage1(ElementSim* volume0, ElementSim* volume1); + void onOverlapRemoved(ElementSim* volume0, ElementSim* volume1, const PxU32 ccdPass, void* elemSim, PxsContactManagerOutputIterator& outputs, bool useAdaptiveForce); + void onVolumeRemoved(ElementSim* volume, PxU32 flags, PxsContactManagerOutputIterator& outputs, bool useAdaptiveForce); + + void managerNewTouch(Sc::ShapeInteraction& interaction, const PxU32 ccdPass, bool adjustCounters, PxsContactManagerOutputIterator& outputs); + +#if PX_USE_PARTICLE_SYSTEM_API + // The ccdPass parameter is needed to avoid concurrent interaction updates while the gpu particle pipeline is running. + ParticleElementRbElementInteraction* insertParticleElementRbElementPair(ParticlePacketShape& particleShape, ShapeSim& rbShape, ActorElementPair* actorElementPair, const PxU32 ccdPass); +#endif + +#if PX_USE_CLOTH_API + void removeClothOverlap(ClothSim* clothSim, const ShapeSim* shapeSim); +#endif + + PxU32 getDefaultContactReportStreamBufferSize() const; + + void fireCustomFilteringCallbacks(PxsContactManagerOutputIterator& outputs, bool useAdaptiveForce); + + void addToDirtyInteractionList(Interaction* interaction); + void removeFromDirtyInteractionList(Interaction* interaction); + void updateDirtyInteractions(PxsContactManagerOutputIterator& outputs, bool useAdaptiveForce); + + + /* + Description: Perform trigger overlap tests. + */ + void processTriggerInteractions(PxBaseTask* continuation); + + /* + Description: Gather results from trigger overlap tests and clean up. + */ + void mergeProcessedTriggerInteractions(PxBaseTask* continuation); + + + /* + Description: Check candidates for persistent touch contact events and create those events if necessary. + */ + void processPersistentContactEvents(PxsContactManagerOutputIterator& outputs); + + /* + Description: Displays visualizations associated with the near phase. + */ + void visualize(Cm::RenderOutput& out, PxsContactManagerOutputIterator& outputs); + + PX_FORCE_INLINE Scene& getScene() const { return mOwnerScene; } + + PX_FORCE_INLINE void addToContactReportActorPairSet(ActorPairReport* pair) { mContactReportActorPairSet.pushBack(pair); } + void clearContactReportActorPairs(bool shrinkToZero); + PX_FORCE_INLINE PxU32 getNbContactReportActorPairs() const { return mContactReportActorPairSet.size(); } + PX_FORCE_INLINE ActorPairReport* const* getContactReportActorPairs() const { return mContactReportActorPairSet.begin(); } + + void addToPersistentContactEventPairs(ShapeInteraction*); + void addToPersistentContactEventPairsDelayed(ShapeInteraction*); + void removeFromPersistentContactEventPairs(ShapeInteraction*); + PX_FORCE_INLINE PxU32 getCurrentPersistentContactEventPairCount() const { return mNextFramePersistentContactEventPairIndex; } + PX_FORCE_INLINE ShapeInteraction* const* getCurrentPersistentContactEventPairs() const { return mPersistentContactEventPairList.begin(); } + PX_FORCE_INLINE PxU32 getAllPersistentContactEventPairCount() const { return mPersistentContactEventPairList.size(); } + PX_FORCE_INLINE ShapeInteraction* const* getAllPersistentContactEventPairs() const { return mPersistentContactEventPairList.begin(); } + PX_FORCE_INLINE void preparePersistentContactEventListForNextFrame(); + + void addToForceThresholdContactEventPairs(ShapeInteraction*); + void removeFromForceThresholdContactEventPairs(ShapeInteraction*); + PX_FORCE_INLINE PxU32 getForceThresholdContactEventPairCount() const { return mForceThresholdContactEventPairList.size(); } + PX_FORCE_INLINE ShapeInteraction* const* getForceThresholdContactEventPairs() const { return mForceThresholdContactEventPairList.begin(); } + + PX_FORCE_INLINE PxU8* getContactReportPairData(const PxU32& bufferIndex) const { return mContactReportBuffer.getData(bufferIndex); } + PxU8* reserveContactReportPairData(PxU32 pairCount, PxU32 extraDataSize, PxU32& bufferIndex); + PxU8* resizeContactReportPairData(PxU32 pairCount, PxU32 extraDataSize, Sc::ContactStreamManager& csm); + PX_FORCE_INLINE void clearContactReportStream() { mContactReportBuffer.reset(); } // Do not free memory at all + PX_FORCE_INLINE void freeContactReportStreamMemory() { mContactReportBuffer.flush(); } + + ActorPairContactReportData* createActorPairContactReportData(); + void releaseActorPairContactReportData(ActorPairContactReportData* data); + + void registerInteraction(ElementSimInteraction* interaction); + void unregisterInteraction(ElementSimInteraction* interaction); + + ElementSimInteraction* createRbElementInteraction(const PxFilterInfo& fInfo, ShapeSim& s0, ShapeSim& s1, PxsContactManager* contactManager, Sc::ShapeInteraction* shapeInteraction, + Sc::ElementInteractionMarker* interactionMarker, PxU32 isTriggerPair); + + private: + ElementSimInteraction* createRbElementInteraction(ShapeSim& s0, ShapeSim& s1, PxsContactManager* contactManager, Sc::ShapeInteraction* shapeInteraction, + Sc::ElementInteractionMarker* interactionMarker); + +#if PX_USE_PARTICLE_SYSTEM_API + ElementSimInteraction* createParticlePacketBodyInteraction(ParticlePacketShape& ps, ShapeSim& s, const PxU32 ccdPass); +#endif + void releaseElementPair(ElementSimInteraction* pair, PxU32 flags, const PxU32 ccdPass, bool removeFromDirtyList, PxsContactManagerOutputIterator& outputs, bool useAdaptiveForce); + void releaseShapeInteraction(ShapeInteraction* pair, PxU32 flags, const PxU32 ccdPass, PxsContactManagerOutputIterator& outputs, bool useAdaptiveForce); + void lostTouchReports(ShapeInteraction* pair, PxU32 flags, const PxU32 ccdPass, PxsContactManagerOutputIterator& outputs, bool useAdaptiveForce); + + ShapeInteraction* createShapeInteraction(ShapeSim& s0, ShapeSim& s1, PxPairFlags pairFlags, PxsContactManager* contactManager, Sc::ShapeInteraction* shapeInteraction); + TriggerInteraction* createTriggerInteraction(ShapeSim& s0, ShapeSim& s1, PxPairFlags triggerFlags); + ElementInteractionMarker* createElementInteractionMarker(ElementSim& e0, ElementSim& e1, ElementInteractionMarker* marker); + + //------------- Filtering ------------- + + ElementSimInteraction* refilterInteraction(ElementSimInteraction* pair, const PxFilterInfo* filterInfo, bool removeFromDirtyList, PxsContactManagerOutputIterator& outputs, + bool useAdaptiveForce); + + PX_INLINE void callPairLost(const ElementSim& e0, const ElementSim& e1, PxU32 pairID, bool objVolumeRemoved) const; + PX_INLINE void runFilterShader(const ElementSim& e0, const ElementSim& e1, + PxFilterObjectAttributes& attr0, PxFilterData& filterData0, + PxFilterObjectAttributes& attr1, PxFilterData& filterData1, + PxFilterInfo& filterInfo); + PX_INLINE PxFilterInfo runFilter(const ElementSim& e0, const ElementSim& e1, PxU32 filterPairIndex, bool doCallbacks); + + // helper method for some cleanup code that is used multiple times for early outs in case a rigid body collision pair gets filtered out due to some hardwired filter criteria + PX_FORCE_INLINE PxFilterInfo filterOutRbCollisionPair(PxU32 filterPairIndex, const PxFilterFlags); + + // helper method to run the filter logic after some hardwired filter criteria have been passed successfully + PxFilterInfo filterRbCollisionPairSecondStage(const ShapeSim& s0, const ShapeSim& s1, const Sc::BodySim* b0, const Sc::BodySim* b1, PxU32 filterPairIndex, bool runCallbacks); + + PxFilterInfo filterRbCollisionPair(const ShapeSim& s0, const ShapeSim& s1, PxU32 filterPairIndex, PxU32& isTriggerPair, bool runCallbacks); + //------------------------------------- + + ElementSimInteraction* convert(ElementSimInteraction* pair, InteractionType::Enum type, PxFilterInfo& filterInfo, bool removeFromDirtyList, PxsContactManagerOutputIterator& outputs, + bool useAdaptiveForce); + + ActorPair* findActorPair(ShapeSim* s0, ShapeSim* s1, Ps::IntBool isReportPair); + PX_FORCE_INLINE void destroyActorPairReport(ActorPairReport&); + + Sc::ElementSimInteraction* findInteraction(ElementSim* _element0, ElementSim* _element1); + + // Pooling +#if PX_USE_PARTICLE_SYSTEM_API + void pool_deleteParticleElementRbElementPair(ParticleElementRbElementInteraction* pair, PxU32 flags, const PxU32 ccdPass); +#endif + + Scene& mOwnerScene; + + Ps::Array<ActorPairReport*> mContactReportActorPairSet; + Ps::Array<ShapeInteraction*> mPersistentContactEventPairList; // Pairs which request events which do not get triggered by the sdk and thus need to be tested actively every frame. + // May also contain force threshold event pairs (see mForceThresholdContactEventPairList) + // This list is split in two, the elements in front are for the current frame, the elements at the + // back will get added next frame. + PxU32 mNextFramePersistentContactEventPairIndex; // start index of the pairs which need to get added to the persistent list for next frame + + Ps::Array<ShapeInteraction*> mForceThresholdContactEventPairList; // Pairs which request force threshold contact events. A pair is only in this list if it does have contact. + // Note: If a pair additionally requests PxPairFlag::eNOTIFY_TOUCH_PERSISTS events, then it + // goes into mPersistentContactEventPairList instead. This allows to share the list index. + + // + // data layout: + // ContactActorPair0_ExtraData, ContactShapePair0_0, ContactShapePair0_1, ... ContactShapePair0_N, + // ContactActorPair1_ExtraData, ContactShapePair1_0, ... + // + ContactReportBuffer mContactReportBuffer; // Shape pair information for contact reports + + Ps::CoalescedHashSet<Interaction*> mDirtyInteractions; + FilterPairManager* mFilterPairManager; + + // Pools + Ps::Pool<ActorPair> mActorPairPool; + Ps::Pool<ActorPairReport> mActorPairReportPool; + Ps::Pool<ActorElementPair> mActorElementPairPool; + Ps::Pool<ShapeInteraction> mShapeInteractionPool; + Ps::Pool<TriggerInteraction> mTriggerInteractionPool; + Ps::Pool<ActorPairContactReportData> mActorPairContactReportDataPool; + Ps::Pool<ElementInteractionMarker> mInteractionMarkerPool; +#if PX_USE_PARTICLE_SYSTEM_API + Ps::Pool<ParticleElementRbElementInteraction> mParticleBodyPool; +#endif + +#if PX_USE_CLOTH_API + struct ClothListElement { + ClothListElement(ClothSim* clothSim = NULL, ClothListElement* next = NULL) + : mClothSim(clothSim), mNext(next) + {} + ClothSim* mClothSim; + ClothListElement* mNext; + }; + Ps::Pool<ClothListElement> mClothPool; + Ps::HashMap<const ShapeSim*, ClothListElement> mClothOverlaps; +#endif + + Cm::DelegateTask<Sc::NPhaseCore, &Sc::NPhaseCore::mergeProcessedTriggerInteractions> mMergeProcessedTriggerInteractions; + void* mTmpTriggerProcessingBlock; // temporary memory block to process trigger pairs in parallel + Ps::Mutex mTriggerWriteBackLock; + volatile PxI32 mTriggerPairsToDeactivateCount; + Ps::HashMap<BodyPairKey, ActorPair*> mActorPairMap; + + Ps::HashMap<ElementSimKey, ElementSimInteraction*> mElementSimMap; + + friend class Sc::Scene; + friend class Sc::ShapeInteraction; + + }; + +} // namespace Sc + + +PX_FORCE_INLINE void Sc::NPhaseCore::preparePersistentContactEventListForNextFrame() +{ + // reports have been processed -> "activate" next frame candidates for persistent contact events + mNextFramePersistentContactEventPairIndex = mPersistentContactEventPairList.size(); +} + + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/ScObjectIDTracker.h b/PhysX_3.4/Source/SimulationController/src/ScObjectIDTracker.h new file mode 100644 index 00000000..57c8d93d --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScObjectIDTracker.h @@ -0,0 +1,99 @@ +// 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_SC_OBJECT_ID_TRACKER +#define PX_PHYSICS_SC_OBJECT_ID_TRACKER + +#include "CmPhysXCommon.h" +#include "CmIDPool.h" +#include "CmBitMap.h" +#include "PsUserAllocated.h" + +namespace physx +{ +namespace Sc +{ + + class ObjectIDTracker : public Ps::UserAllocated + { + PX_NOCOPY(ObjectIDTracker) + public: + ObjectIDTracker() : mPendingReleasedIDs(PX_DEBUG_EXP("objectIDTrackerIDs")) {} + + PX_INLINE PxU32 createID() { return mIDPool.getNewID(); } + PX_INLINE void releaseID(PxU32 id) + { + markIDAsDeleted(id); + mPendingReleasedIDs.pushBack(id); + } + PX_INLINE Ps::IntBool isDeletedID(PxU32 id) const { return mDeletedIDsMap.boundedTest(id); } + PX_FORCE_INLINE PxU32 getDeletedIDCount() const { return mPendingReleasedIDs.size(); } + PX_INLINE void clearDeletedIDMap() { mDeletedIDsMap.clear(); } + PX_INLINE void resizeDeletedIDMap(PxU32 id, PxU32 numIds) + { + mDeletedIDsMap.resize(id); + mPendingReleasedIDs.reserve(numIds); + } + PX_INLINE void processPendingReleases() + { + for(PxU32 i=0; i < mPendingReleasedIDs.size(); i++) + { + mIDPool.freeID(mPendingReleasedIDs[i]); + } + mPendingReleasedIDs.clear(); + } + PX_INLINE void reset() + { + processPendingReleases(); + mPendingReleasedIDs.reset(); + + // Don't free stuff in IDPool, we still need the list of free IDs + + // And it does not seem worth freeing the memory of the bitmap + } + + PX_INLINE PxU32 getMaxID() + { + return mIDPool.getMaxID(); + } + private: + PX_INLINE void markIDAsDeleted(PxU32 id) { PX_ASSERT(!isDeletedID(id)); mDeletedIDsMap.growAndSet(id); } + + + private: + Cm::IDPool mIDPool; + Cm::BitMap mDeletedIDsMap; + Ps::Array<PxU32> mPendingReleasedIDs; // Buffer for released IDs to make sure newly created objects do not re-use these IDs immediately + }; + +} +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/ScPhysics.cpp b/PhysX_3.4/Source/SimulationController/src/ScPhysics.cpp new file mode 100644 index 00000000..d8851645 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScPhysics.cpp @@ -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. + + +#include "ScPhysics.h" +#include "ScScene.h" +#include "PxvGlobals.h" +#include "PxTolerancesScale.h" +#include "Factory.h" + +using namespace physx; + +Sc::Physics* Sc::Physics::mInstance = NULL; +const PxReal Sc::Physics::sWakeCounterOnCreation = 20.0f*0.02f; + +namespace physx +{ + namespace Sc + { + OffsetTable gOffsetTable; + } +} + +Sc::Physics::Physics(const PxTolerancesScale& scale, const PxvOffsetTable& pxvOffsetTable) +: mScale(scale) +, mLowLevelClothFactory(0) +{ + mInstance = this; + + PxvInit(pxvOffsetTable); +} + + +Sc::Physics::~Physics() +{ +#if PX_USE_CLOTH_API + if(mLowLevelClothFactory) + PX_DELETE(mLowLevelClothFactory); +#endif + + PxvTerm(); + + mInstance = 0; +} + +#if PX_USE_CLOTH_API +void Sc::Physics::registerCloth() +{ + if(!mLowLevelClothFactory) + mLowLevelClothFactory = cloth::Factory::createFactory(cloth::Factory::CPU); +} +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/ScRbElementInteraction.h b/PhysX_3.4/Source/SimulationController/src/ScRbElementInteraction.h new file mode 100644 index 00000000..a334be3b --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScRbElementInteraction.h @@ -0,0 +1,71 @@ +// 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_COLLISION_RB_ELEMENT_INTERACTION +#define PX_COLLISION_RB_ELEMENT_INTERACTION + +#include "ScElementSimInteraction.h" +#include "ScShapeSim.h" + +namespace physx +{ +namespace Sc +{ + + class RbElementInteraction : public ElementSimInteraction + { + public: + PX_INLINE RbElementInteraction(ShapeSim& shape0, ShapeSim& shape1, InteractionType::Enum type, PxU8 flags); + virtual ~RbElementInteraction() {} + + PX_INLINE ShapeSim& getShape0() const; + PX_INLINE ShapeSim& getShape1() const; + }; +} // namespace Sc + +////////////////////////////////////////////////////////////////////////// +Sc::RbElementInteraction::RbElementInteraction(ShapeSim& shape0, ShapeSim& shape1, InteractionType::Enum type, PxU8 flags) : + ElementSimInteraction (shape0, shape1, type, flags) +{ +} + +PX_INLINE Sc::ShapeSim& Sc::RbElementInteraction::getShape0() const +{ + return static_cast<ShapeSim&>(getElement0()); +} + +PX_INLINE Sc::ShapeSim& Sc::RbElementInteraction::getShape1() const +{ + return static_cast<ShapeSim&>(getElement1()); +} + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/ScRigidCore.cpp b/PhysX_3.4/Source/SimulationController/src/ScRigidCore.cpp new file mode 100644 index 00000000..93987c55 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScRigidCore.cpp @@ -0,0 +1,105 @@ +// 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 "ScBodyCore.h" +#include "ScStaticCore.h" +#include "ScRigidSim.h" +#include "ScShapeSim.h" +#include "ScScene.h" +#include "ScPhysics.h" + +using namespace physx; + +Sc::RigidCore::RigidCore(const PxActorType::Enum type) +: ActorCore(type, PxActorFlag::eVISUALIZATION, PX_DEFAULT_CLIENT, 0, 0) +{ +} + +Sc::RigidCore::~RigidCore() +{ +} + +void Sc::RigidCore::addShapeToScene(ShapeCore& shapeCore) +{ + Sc::RigidSim* sim = getSim(); + PX_ASSERT(sim); + if(!sim) + return; + sim->getScene().addShape(*sim, shapeCore, NULL); +} + +void Sc::RigidCore::removeShapeFromScene(ShapeCore& shapeCore, bool wakeOnLostTouch) +{ + Sc::RigidSim* sim = getSim(); + if(!sim) + return; + Sc::ShapeSim& s = sim->getSimForShape(shapeCore); + sim->getScene().removeShape(s, wakeOnLostTouch); +} + +void Sc::RigidCore::onShapeChange(Sc::ShapeCore& shape, ShapeChangeNotifyFlags notifyFlags, PxShapeFlags oldShapeFlags, bool forceBoundsUpdate) +{ + // DS: We pass flags to avoid searching multiple times or exposing RigidSim outside SC, and this form is + // more convenient for the Scb::Shape::syncState method. If we start hitting this a lot we should do it + // a different way, but shape modification after insertion is rare. + + Sc::RigidSim* sim = getSim(); + if(!sim) + return; + Sc::ShapeSim& s = sim->getSimForShape(shape); + + if(notifyFlags & ShapeChangeNotifyFlag::eGEOMETRY) + s.onVolumeOrTransformChange(false, forceBoundsUpdate); + if(notifyFlags & ShapeChangeNotifyFlag::eMATERIAL) + s.onMaterialChange(); + if(notifyFlags & ShapeChangeNotifyFlag::eRESET_FILTERING) + s.onResetFiltering(); + if(notifyFlags & ShapeChangeNotifyFlag::eSHAPE2BODY) + s.onVolumeOrTransformChange(false, forceBoundsUpdate); + if(notifyFlags & ShapeChangeNotifyFlag::eFILTERDATA) + s.onFilterDataChange(); + if(notifyFlags & ShapeChangeNotifyFlag::eFLAGS) + s.onFlagChange(oldShapeFlags); + if(notifyFlags & ShapeChangeNotifyFlag::eCONTACTOFFSET) + s.onContactOffsetChange(); + if(notifyFlags & ShapeChangeNotifyFlag::eRESTOFFSET) + s.onRestOffsetChange(); +} + +Sc::RigidSim* Sc::RigidCore::getSim() const +{ + return static_cast<RigidSim*>(Sc::ActorCore::getSim()); +} + +PxActor* Sc::RigidCore::getPxActor() const +{ + return Ps::pointerOffset<PxActor*>(const_cast<Sc::RigidCore*>(this), Sc::gOffsetTable.scCore2PxActor[getActorCoreType()]); +} + diff --git a/PhysX_3.4/Source/SimulationController/src/ScRigidSim.cpp b/PhysX_3.4/Source/SimulationController/src/ScRigidSim.cpp new file mode 100644 index 00000000..bbc715b9 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScRigidSim.cpp @@ -0,0 +1,97 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-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 "ScScene.h" +#include "ScRigidSim.h" +#include "ScShapeSim.h" +#include "ScObjectIDTracker.h" +#include "ScShapeIterator.h" +#include "PsFoundation.h" + +using namespace physx; + +/* + PT: + + The BP group ID comes from a Cm::IDPool, and RigidSim is the only class releasing the ID. + + The rigid tracker ID comes from a Cm::IDPool internal to an ObjectIDTracker, and RigidSim + is the only class using it. + + Thus we should: + - promote the BP group ID stuff to a "tracker" object + - use the BP group ID as a rigid ID +*/ + +Sc::RigidSim::RigidSim(Scene& scene, RigidCore& core) : + ActorSim(scene, core) +{ + mRigidId = scene.getRigidIDTracker().createID(); + +#if PX_CHECKED +#if PX_USE_16_BIT_HANDLES + PX_CHECK_MSG(getBroadphaseGroupId() < BP_INVALID_BP_HANDLE, "The total of actors in the scene plus the number of adds cannot exceed 65535 between simulate()/fetchResult() calls. The sdk will can now proceed with unexpected outcomes. \n"); +#endif +#endif +} + +Sc::RigidSim::~RigidSim() +{ + Sc::Scene& scScene = getScene(); + scScene.getRigidIDTracker().releaseID(mRigidId); +} + +void Sc::RigidSim::notifyShapesOfTransformChange() +{ + for(ElementSim* e = getElements_(); e!=0; e = e->mNextInActor) + { + if(e->getElementType() == ElementType::eSHAPE) + static_cast<Sc::ShapeSim*>(e)->onVolumeOrTransformChange(true); + } +} + +Sc::ShapeSim& Sc::RigidSim::getSimForShape(Sc::ShapeCore& core) const +{ + // DS: looks painful to traverse a linked list this way + Sc::ShapeIterator iterator(*this); + Sc::ShapeSim* sim; + while((sim = iterator.getNext())!=NULL) + { + if(&sim->getCore() == &core) + return *sim; + } + PX_ASSERT(0); // should never fail + return *reinterpret_cast<Sc::ShapeSim*>(1); +} + +PxActor* Sc::RigidSim::getPxActor() const +{ + return getRigidCore().getPxActor(); +} diff --git a/PhysX_3.4/Source/SimulationController/src/ScRigidSim.h b/PhysX_3.4/Source/SimulationController/src/ScRigidSim.h new file mode 100644 index 00000000..59820260 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScRigidSim.h @@ -0,0 +1,75 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-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_RB_SIM +#define PX_PHYSICS_SCP_RB_SIM + +#include "ScActorSim.h" +#include "ScRigidCore.h" +#include "BpSimpleAABBManager.h" + +namespace physx +{ + +class Interaction; + +namespace Sc +{ + class ShapeCore; + class ShapeSim; + class Scene; + + class RigidSim : public ActorSim + { + public: + RigidSim(Scene&, RigidCore&); + virtual ~RigidSim(); + + PX_FORCE_INLINE RigidCore& getRigidCore() const { return static_cast<RigidCore&>(mCore); } + + PX_FORCE_INLINE PxU32 getID() const { return mRigidId; } + + PX_FORCE_INLINE PxU32 getBroadphaseGroupId() const { return (getActorType()!=PxActorType::eRIGID_STATIC ? mRigidId + PxU32(Bp::FilterGroup::eDYNAMICS_BASE) : PxU32(Bp::FilterGroup::eSTATICS));} + + void notifyShapesOfTransformChange(); + + Sc::ShapeSim& getSimForShape(Sc::ShapeCore& shape) const; + + + PxActor* getPxActor() const; + private: + PxU32 mRigidId; + }; + +} // namespace Sc + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/ScScene.cpp b/PhysX_3.4/Source/SimulationController/src/ScScene.cpp new file mode 100644 index 00000000..afa02401 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScScene.cpp @@ -0,0 +1,6744 @@ +// 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. + + +#define NOMINMAX + +#include "foundation/PxProfiler.h" +#include "ScPhysics.h" +#include "ScScene.h" +#include "ScClient.h" +#include "BpSimpleAABBManager.h" +#include "BpBroadPhase.h" +#include "ScStaticSim.h" +#include "ScConstraintSim.h" +#include "ScConstraintProjectionManager.h" +#include "ScConstraintCore.h" +#include "ScArticulationCore.h" +#include "ScArticulationJointCore.h" +#include "ScMaterialCore.h" +#include "ScArticulationSim.h" +#include "ScArticulationJointSim.h" +#include "PsTime.h" +#include "ScConstraintInteraction.h" +#include "ScSimStats.h" +#include "ScTriggerPairs.h" +#include "ScObjectIDTracker.h" +#include "DyArticulation.h" +#include "ScShapeIterator.h" +#include "PxvManager.h" +#include "DyContext.h" +#include "PxsCCD.h" +#include "PxsSimpleIslandManager.h" +#include "PxsSimulationController.h" +#include "PxsContext.h" +#include "ScSqBoundsManager.h" +#include "ScElementSim.h" + +#if defined(__APPLE__) && defined(__POWERPC__) +#include <ppc_intrinsics.h> +#endif + +#if PX_SUPPORT_GPU_PHYSX +#include "PxPhysXGpu.h" +#include "PxsKernelWrangler.h" +#include "PxsHeapMemoryAllocator.h" +#include "cudamanager/PxCudaContextManager.h" +#endif + +#include "PxsMemoryManager.h" + +//////////// + +#include "PxvNphaseImplementationContext.h" +#include "ScShapeInteraction.h" +#include "ScElementInteractionMarker.h" +#include "PxsContext.h" + +#if PX_USE_PARTICLE_SYSTEM_API +#include "ScParticleSystemCore.h" +#include "ScParticleSystemSim.h" +#include "PtContext.h" +#endif // PX_USE_PARTICLE_SYSTEM_API + +#if PX_USE_CLOTH_API +#include "ScClothCore.h" +#include "ScClothSim.h" +#include "Factory.h" +#include "Fabric.h" +#include "Solver.h" +#include "Cloth.h" +#endif // PX_USE_CLOTH_API + +#if PX_SUPPORT_GPU_PHYSX +#include "task/PxGpuDispatcher.h" +#include "PxSceneGpu.h" +#endif // PX_SUPPORT_GPU_PHYSX + +#include "PxRigidDynamic.h" + +#include "PxvDynamics.h" +#include "DyArticulation.h" + +using namespace physx; +using namespace physx::shdfnd; +using namespace physx::Cm; +using namespace physx::Dy; + +// slightly ugly, but we don't want a compile-time dependency on DY_ARTICULATION_MAX_SIZE in the ScScene.h header +namespace physx { +#if PX_SUPPORT_GPU_PHYSX + +PX_PHYSX_GPU_API Bp::BPMemoryAllocator* createGpuMemoryAllocator(); + +#endif + +extern bool gUnifiedHeightfieldCollision; + + +namespace Sc { + +class LLArticulationPool: public Ps::Pool<Articulation, Ps::AlignedAllocator<DY_ARTICULATION_MAX_SIZE> > +{ +public: + LLArticulationPool() {} +}; + + +static const char* sFilterShaderDataMemAllocId = "SceneDesc filterShaderData"; + +}} + +void PxcClearContactCacheStats(); +void PxcDisplayContactCacheStats(); + +class ScAfterIntegrationTask : public Cm::Task +{ +public: + static const PxU32 MaxTasks = 128; +private: + const IG::NodeIndex* const mIndices; + const PxU32 mNumBodies; + PxsContext* mContext; + Context* mDynamicsContext; + PxsTransformCache& mCache; + Sc::Scene& mScene; + +public: + + ScAfterIntegrationTask(const IG::NodeIndex* const indices, PxU32 numBodies, PxsContext* context, Context* dynamicsContext, PxsTransformCache& cache, + Sc::Scene& scene) : + mIndices(indices), mNumBodies(numBodies), mContext(context), mDynamicsContext(dynamicsContext), + mCache(cache), mScene(scene) + { + } + + virtual void runInternal() + { + const PxU32 rigidBodyOffset = Sc::BodySim::getRigidBodyOffset(); + + Sc::BodySim* bpUpdates[MaxTasks]; + Sc::BodySim* ccdBodies[MaxTasks]; + Sc::BodySim* activateBodies[MaxTasks]; + Sc::BodySim* deactivateBodies[MaxTasks]; + PxU32 nbBpUpdates = 0, nbCcdBodies = 0; + + IG::SimpleIslandManager& manager = *mScene.getSimpleIslandManager(); + const IG::IslandSim& islandSim = manager.getAccurateIslandSim(); + Bp::BoundsArray& boundsArray = mScene.getBoundsArray(); + + Sc::BodySim* frozen[MaxTasks], * unfrozen[MaxTasks]; + PxU32 nbFrozen = 0, nbUnfrozen = 0; + PxU32 nbActivated = 0, nbDeactivated = 0; + + for(PxU32 i = 0; i < mNumBodies; i++) + { + PxsRigidBody* rigid = islandSim.getRigidBody(mIndices[i]); + Sc::BodySim* bodySim = reinterpret_cast<Sc::BodySim*>(reinterpret_cast<PxU8*>(rigid) - rigidBodyOffset); + //This move to PxgPostSolveWorkerTask for the gpu dynamic + //bodySim->sleepCheck(mDt, mOneOverDt, mEnableStabilization); + + PxsBodyCore& bodyCore = bodySim->getBodyCore().getCore(); + //If we got in this code, then this is an active object this frame. The solver computed the new wakeCounter and we + //commit it at this stage. We need to do it this way to avoid a race condition between the solver and the island gen, where + //the island gen may have deactivated a body while the solver decided to change its wake counter. + bodyCore.wakeCounter = bodyCore.solverWakeCounter; + PxsRigidBody& llBody = bodySim->getLowLevelBody(); + + const Ps::IntBool isFrozen = bodySim->isFrozen(); + if(!isFrozen) + { + bpUpdates[nbBpUpdates++] = bodySim; + + // PT: TODO: remove duplicate "isFrozen" test inside updateCached +// bodySim->updateCached(NULL); + bodySim->updateCached(mCache, boundsArray); + } + + if(llBody.isFreezeThisFrame() && isFrozen) + { + frozen[nbFrozen++] = bodySim; + } + else if(llBody.isUnfreezeThisFrame()) + { + unfrozen[nbUnfrozen++] = bodySim; + } + + if(bodyCore.mFlags & PxRigidBodyFlag::eENABLE_CCD) + ccdBodies[nbCcdBodies++] = bodySim; + + if(llBody.isActivateThisFrame()) + { + PX_ASSERT(!llBody.isDeactivateThisFrame()); + activateBodies[nbActivated++] = bodySim; + } + else if(llBody.isDeactivateThisFrame()) + { + deactivateBodies[nbDeactivated++] = bodySim; + } + llBody.clearAllFrameFlags(); + } + if(nbBpUpdates) + { + mCache.setChangedState(); + boundsArray.setChangedState(); + } + + if(nbBpUpdates>0 || nbFrozen > 0 || nbCcdBodies>0 || nbActivated>0 || nbDeactivated>0) + { + //Write active bodies to changed actor map + mContext->getLock().lock(); + Cm::BitMapPinned& changedAABBMgrHandles = mScene.getAABBManager()->getChangedAABBMgActorHandleMap(); + + for(PxU32 i = 0; i < nbBpUpdates; i++) + { + Sc::ShapeSim* sim; + for (Sc::ShapeIterator iterator(*bpUpdates[i]); (sim = iterator.getNext()) != NULL;) + { + // PT: TODO: what's the difference between this test and "isInBroadphase" as used in bodySim->updateCached ? + // PT: Also, shouldn't it be "isInAABBManager" rather than BP ? + if (sim->getFlags()&PxU32(PxShapeFlag::eSIMULATION_SHAPE | PxShapeFlag::eTRIGGER_SHAPE)) // TODO: need trigger shape here? + changedAABBMgrHandles.growAndSet(sim->getElementID()); + } + } + + Ps::Array<Sc::BodySim*>& sceneCcdBodies = mScene.getCcdBodies(); + for (PxU32 i = 0; i < nbCcdBodies; i++) + sceneCcdBodies.pushBack(ccdBodies[i]); + + for(PxU32 i=0;i<nbFrozen;i++) + { + PX_ASSERT(frozen[i]->isFrozen()); + frozen[i]->freezeTransforms(&changedAABBMgrHandles); + } + + for(PxU32 i=0;i<nbUnfrozen;i++) + { + PX_ASSERT(!unfrozen[i]->isFrozen()); + unfrozen[i]->createSqBounds(); + } + + for(PxU32 i = 0; i < nbActivated; ++i) + { + activateBodies[i]->notifyNotReadyForSleeping(); + } + + for(PxU32 i = 0; i < nbDeactivated; ++i) + { + deactivateBodies[i]->notifyReadyForSleeping(); + } + + mContext->getLock().unlock(); + } + } + + virtual const char* getName() const + { + return "ScScene.afterIntegration"; + } + +private: + ScAfterIntegrationTask& operator = (const ScAfterIntegrationTask&); +}; + + +class ScSimulationControllerCallback : public PxsSimulationControllerCallback +{ + + Sc::Scene* mScene; +public: + + ScSimulationControllerCallback(Sc::Scene* scene) : mScene(scene) + { + } + + virtual void updateScBodyAndShapeSim(PxBaseTask* continuation) + { + PxsContext* contextLL = mScene->getLowLevelContext(); + IG::SimpleIslandManager* islandManager = mScene->getSimpleIslandManager(); + Dy::Context* dynamicContext = mScene->getDynamicsContext(); + + Cm::FlushPool& flushPool = contextLL->getTaskPool(); + + const PxU32 MaxBodiesPerTask = ScAfterIntegrationTask::MaxTasks; + + PxsTransformCache& cache = contextLL->getTransformCache(); + + const IG::IslandSim& islandSim = islandManager->getAccurateIslandSim(); + + /*const*/ PxU32 numBodies = islandSim.getNbActiveNodes(IG::Node::eRIGID_BODY_TYPE); + + const IG::NodeIndex*const nodeIndices = islandSim.getActiveNodes(IG::Node::eRIGID_BODY_TYPE); + + if(0) + { + for(PxU32 i = 0; i < numBodies; i+=MaxBodiesPerTask) + { + ScAfterIntegrationTask* task = PX_PLACEMENT_NEW(flushPool.allocate(sizeof(ScAfterIntegrationTask)), ScAfterIntegrationTask(nodeIndices+i, PxMin(numBodies - i, MaxBodiesPerTask), + contextLL, dynamicContext, cache, *mScene)); + task->setContinuation(continuation); + task->removeReference(); + } + } + else + { + // PT: + const PxU32 numCpuTasks = continuation->getTaskManager()->getCpuDispatcher()->getWorkerCount(); + + PxU32 nbPerTask; + if(numCpuTasks) + { + nbPerTask = numBodies > numCpuTasks ? numBodies / numCpuTasks : numBodies; + } + else + { + nbPerTask = numBodies; + } + + // PT: we need to respect that limit even with a single thread, because of hardcoded buffer limits in ScAfterIntegrationTask. + if(nbPerTask>MaxBodiesPerTask) + nbPerTask = MaxBodiesPerTask; + + PxU32 start = 0; + while(numBodies) + { + const PxU32 nb = numBodies < nbPerTask ? numBodies : nbPerTask; + + ScAfterIntegrationTask* task = PX_PLACEMENT_NEW(flushPool.allocate(sizeof(ScAfterIntegrationTask)), ScAfterIntegrationTask(nodeIndices+start, nb, + contextLL, dynamicContext, cache, *mScene)); + + start += nb; + numBodies -= nb; + + task->setContinuation(continuation); + task->removeReference(); + } + + } + } + + virtual PxU32 getNbCcdBodies() + { + return mScene->getCcdBodies().size(); + } + +}; + +class PxgUpdateBodyAndShapeStatusTask : public Cm::Task +{ +public: + static const PxU32 MaxTasks = 256; +private: + const IG::NodeIndex* const mNodeIndices; + const PxU32 mNumBodies; + Sc::Scene& mScene; + PxsBodySim* mBodySimsLL; + PxU32* mActivatedBodies; + PxU32* mDeactivatedBodies; + PxI32& mCCDBodyWriteIndex; + + +public: + + PxgUpdateBodyAndShapeStatusTask(const IG::NodeIndex* const indices, PxU32 numBodies, PxsBodySim* bodySimsLL, PxU32* activatedBodies, PxU32* deactivatedBodies, + Sc::Scene& scene, PxI32& ccdBodyWriteIndex) : + mNodeIndices(indices), mNumBodies(numBodies), mScene(scene), mBodySimsLL(bodySimsLL), mActivatedBodies(activatedBodies), + mDeactivatedBodies(deactivatedBodies), mCCDBodyWriteIndex(ccdBodyWriteIndex) + { + } + + virtual void runInternal() + { + IG::SimpleIslandManager& islandManager = *mScene.getSimpleIslandManager(); + const IG::IslandSim& islandSim = islandManager.getAccurateIslandSim(); + + PxU32 nbCcdBodies = 0; + + Ps::Array<Sc::BodySim*>& sceneCcdBodies = mScene.getCcdBodies(); + Sc::BodySim* ccdBodies[MaxTasks]; + + const size_t bodyOffset = PX_OFFSET_OF_RT(Sc::BodySim, getLowLevelBody()); + + for(PxU32 i=0; i<mNumBodies; ++i) + { + const PxU32 nodeIndex = mNodeIndices[i].index(); + PxsBodySim& bodyLL = mBodySimsLL[nodeIndex]; + + PxsBodyCore* bodyCore = &bodyLL.mRigidBody->getCore(); + bodyCore->wakeCounter = bodyCore->solverWakeCounter; + //we can set the frozen/unfrozen flag in GPU, but we have copied the internalflags + //from the solverbodysleepdata to pxsbodycore, so we just need to clear the frozen flag in here + bodyLL.mRigidBody->clearAllFrameFlags(); + + PX_ASSERT(mActivatedBodies[nodeIndex] <= 1); + PX_ASSERT(mDeactivatedBodies[nodeIndex] <= 1); + if(mActivatedBodies[nodeIndex]) + { + PX_ASSERT(bodyCore->wakeCounter > 0.f); + islandManager.activateNode(mNodeIndices[i]); + } + else if(mDeactivatedBodies[nodeIndex]) + { + //KS - the CPU code can reset the wake counter due to lost touches in parallel with the solver, so we need to verify + //that the wakeCounter is still 0 before deactivating the node + if(bodyCore->wakeCounter == 0.f) + islandManager.deactivateNode(mNodeIndices[i]); + } + + if (bodyCore->mFlags & PxRigidBodyFlag::eENABLE_CCD) + { + PxsRigidBody* rigidBody = islandSim.getRigidBody(mNodeIndices[i]); + Sc::BodySim* bodySim = reinterpret_cast<Sc::BodySim*>(reinterpret_cast<PxU8*>(rigidBody) - bodyOffset); + ccdBodies[nbCcdBodies++] = bodySim; + } + } + if(nbCcdBodies > 0) + { + PxI32 startIndex = Ps::atomicAdd(&mCCDBodyWriteIndex, PxI32(nbCcdBodies)) - PxI32(nbCcdBodies); + for(PxU32 a = 0; a < nbCcdBodies; ++a) + { + sceneCcdBodies[startIndex + a] = ccdBodies[a]; + } + } + } + + virtual const char* getName() const + { + return "ScScene.PxgUpdateBodyAndShapeStatusTask"; + } + +private: + PxgUpdateBodyAndShapeStatusTask& operator = (const PxgUpdateBodyAndShapeStatusTask&); +}; + +class PxgSimulationControllerCallback : public PxsSimulationControllerCallback +{ + Sc::Scene* mScene; + PxI32 mCcdBodyWriteIndex; + +public: + PxgSimulationControllerCallback(Sc::Scene* scene) : mScene(scene), mCcdBodyWriteIndex(0) + { + } + + virtual void updateScBodyAndShapeSim(PxBaseTask* continuation) + { + + IG::SimpleIslandManager* islandManager = mScene->getSimpleIslandManager(); + PxsSimulationController* simulationController = mScene->getSimulationController(); + PxsContext* contextLL = mScene->getLowLevelContext(); + IG::IslandSim& islandSim = islandManager->getAccurateIslandSim(); + const PxU32 numBodies = islandSim.getNbActiveNodes(IG::Node::eRIGID_BODY_TYPE); + const IG::NodeIndex*const nodeIndices = islandSim.getActiveNodes(IG::Node::eRIGID_BODY_TYPE); + + PxU32* activatedBodies = simulationController->getActiveBodies(); + PxU32* deactivatedBodies = simulationController->getDeactiveBodies(); + + PxsBodySim* bodySimLL = simulationController->getBodySims(); + + Cm::FlushPool& flushPool = contextLL->getTaskPool(); + + Ps::Array<Sc::BodySim*>& ccdBodies = mScene->getCcdBodies(); + ccdBodies.forceSize_Unsafe(0); + ccdBodies.reserve(numBodies); + ccdBodies.forceSize_Unsafe(numBodies); + + mCcdBodyWriteIndex = 0; + + for(PxU32 i = 0; i < numBodies; i+=PxgUpdateBodyAndShapeStatusTask::MaxTasks) + { + PxgUpdateBodyAndShapeStatusTask* task = PX_PLACEMENT_NEW(flushPool.allocate(sizeof(PxgUpdateBodyAndShapeStatusTask)), PxgUpdateBodyAndShapeStatusTask(nodeIndices + i, + PxMin(PxgUpdateBodyAndShapeStatusTask::MaxTasks, numBodies - i), bodySimLL, activatedBodies, deactivatedBodies, *mScene, mCcdBodyWriteIndex)); + task->setContinuation(continuation); + task->removeReference(); + } + + + + PxU32* unfrozenShapeIndices = simulationController->getUnfrozenShapes(); + PxU32* frozenShapeIndices = simulationController->getFrozenShapes(); + const PxU32 nbFrozenShapes = simulationController->getNbFrozenShapes(); + const PxU32 nbUnfrozenShapes = simulationController->getNbUnfrozenShapes(); + + PxsShapeSim** shapeSimsLL = simulationController->getShapeSims(); + + const size_t shapeOffset = PX_OFFSET_OF_RT(Sc::ShapeSim, getLLShapeSim()); + + for(PxU32 i=0; i<nbFrozenShapes; ++i) + { + const PxU32 shapeIndex = frozenShapeIndices[i]; + PxsShapeSim* shapeLL = shapeSimsLL[shapeIndex]; + Sc::ShapeSim* shape = reinterpret_cast<Sc::ShapeSim*>(reinterpret_cast<PxU8*>(shapeLL) - shapeOffset); + shape->destroySqBounds(); + } + + for(PxU32 i=0; i<nbUnfrozenShapes; ++i) + { + const PxU32 shapeIndex = unfrozenShapeIndices[i]; + PxsShapeSim* shapeLL = shapeSimsLL[shapeIndex]; + Sc::ShapeSim* shape = reinterpret_cast<Sc::ShapeSim*>(reinterpret_cast<PxU8*>(shapeLL) - shapeOffset); + shape->createSqBounds(); + } + + + } + + virtual PxU32 getNbCcdBodies() + { + return PxU32(mCcdBodyWriteIndex); + } + +}; + + +Sc::Scene::Scene(const PxSceneDesc& desc, PxU64 contextID) : + mContextId (contextID), + mActiveBodies (PX_DEBUG_EXP("sceneActiveBodies")), + mActiveKinematicBodyCount (0), + mPointerBlock8Pool (PX_DEBUG_EXP("scenePointerBlock8Pool")), + mPointerBlock16Pool (PX_DEBUG_EXP("scenePointerBlock16Pool")), + mPointerBlock32Pool (PX_DEBUG_EXP("scenePointerBlock32Pool")), + mLLContext (0), + mBodyGravityDirty (true), + mDt (0), + mOneOverDt (0), + mTimeStamp (1), // PT: has to start to 1 to fix determinism bug. I don't know why yet but it works. + mReportShapePairTimeStamp (0), + mTriggerBufferAPI (PX_DEBUG_EXP("sceneTriggerBufferAPI")), + mRemovedShapeCountAtSimStart (0), + mArticulations (PX_DEBUG_EXP("sceneArticulations")), +#if PX_USE_PARTICLE_SYSTEM_API + mParticleContext (NULL), + mParticleSystems (PX_DEBUG_EXP("sceneParticleSystems")), + mEnabledParticleSystems (PX_DEBUG_EXP("sceneEnabledParticleSystems")), +#endif +#if PX_USE_CLOTH_API + mCloths (PX_DEBUG_EXP("sceneCloths")), +#endif + mBrokenConstraints (PX_DEBUG_EXP("sceneBrokenConstraints")), + mActiveBreakableConstraints (PX_DEBUG_EXP("sceneActiveBreakableConstraints")), + mMemBlock128Pool (PX_DEBUG_EXP("PxsContext ConstraintBlock128Pool")), + mMemBlock256Pool (PX_DEBUG_EXP("PxsContext ConstraintBlock256Pool")), + mMemBlock384Pool (PX_DEBUG_EXP("PxsContext ConstraintBlock384Pool")), + mNPhaseCore (NULL), + mSleepBodies (PX_DEBUG_EXP("sceneSleepBodies")), + mWokeBodies (PX_DEBUG_EXP("sceneWokeBodies")), + mEnableStabilization (desc.flags & PxSceneFlag::eENABLE_STABILIZATION), + mClients (PX_DEBUG_EXP("sceneClients")), + mInternalFlags (SceneInternalFlag::eSCENE_DEFAULT), + mPublicFlags (desc.flags), + mStaticAnchor (NULL), + mBatchRemoveState (NULL), + mLostTouchPairs (PX_DEBUG_EXP("sceneLostTouchPairs")), + mOutOfBoundsIDs (PX_DEBUG_EXP("sceneOutOfBoundsIds")), + mErrorState (0), + mVisualizationScale (0.0f), + mVisualizationParameterChanged (false), + mNbRigidStatics (0), + mNbRigidDynamics (0), + mClothPreprocessing (this, "ScScene.clothPreprocessing"), + mSecondPassNarrowPhase (this, "ScScene.secondPassNarrowPhase"), + mPostNarrowPhase (this, "ScScene.postNarrowPhase"), + mParticlePostCollPrep ("ScScene.particlePostCollPrep"), + mParticlePostShapeGen (this, "ScScene.particlePostShapeGen"), + mFinalizationPhase (this, "ScScene.finalizationPhase"), + mUpdateCCDMultiPass (this, "ScScene.updateCCDMultiPass"), + mAfterIntegration (this, "ScScene.afterIntegration"), + mConstraintProjection (this, "ScScene.constraintProjection"), + mPostSolver (this, "ScScene.postSolver"), + mSolver (this, "ScScene.rigidBodySolver"), + mUpdateBodiesAndShapes (this, "ScScene.updateBodiesAndShapes"), + mUpdateSimulationController (this, "ScScene.updateSimulationController"), + mUpdateDynamics (this, "ScScene.updateDynamics"), + mProcessLostContactsTask (this, "ScScene.processLostContact"), + mProcessLostContactsTask2 (this, "ScScene.processLostContact2"), + mProcessLostContactsTask3 (this, "ScScene.processLostContact3"), + mDestroyManagersTask (this, "ScScene.destroyManagers"), + mLostTouchReportsTask (this, "ScScene.lostTouchReports"), + mUnregisterInteractionsTask (this, "ScScene.unregisterInteractions"), + mProcessNarrowPhaseLostTouchTasks(this, "ScScene.processNpLostTouchTask"), + mProcessNPLostTouchEvents (this, "ScScene.processNPLostTouchEvents"), + mPostThirdPassIslandGenTask (this, "ScScene.postThirdPassIslandGenTask"), + mPostIslandGen (this, "ScScene.postIslandGen"), + mIslandGen (this, "ScScene.islandGen"), + mPreRigidBodyNarrowPhase (this, "ScScene.preRigidBodyNarrowPhase"), + mSetEdgesConnectedTask (this, "ScScene.setEdgesConnectedTask"), + mFetchPatchEventsTask (this, "ScScene.fetchPatchEventsTask"), + mProcessLostPatchesTask (this, "ScScene.processLostSolverPatchesTask"), + mRigidBodyNarrowPhase (this, "ScScene.rigidBodyNarrowPhase"), + mRigidBodyNPhaseUnlock (this, "ScScene.unblockNarrowPhase"), + mPostBroadPhase (this, "ScScene.postBroadPhase"), + mPostBroadPhase2 (this, "ScScene.postBroadPhase2"), + mPostBroadPhase3 (this, "ScScene.postBroadPhase3"), + mPreallocateContactManagers (this, "ScScene.preallocateContactManagers"), + mIslandInsertion (this, "ScScene.islandInsertion"), + mRegisterContactManagers (this, "ScScene.registerContactManagers"), + mRegisterInteractions (this, "ScScene.registerInteractions"), + mRegisterSceneInteractions (this, "ScScene.registerSceneInteractions"), + mBroadPhase (this, "ScScene.broadPhase"), + mAdvanceStep (this, "ScScene.advanceStep"), + mCollideStep (this, "ScScene.collideStep"), + mTaskPool (16384), + mContactReportsNeedPostSolverVelocity(false), + mSimulationStage (SimulationStage::eCOMPLETE), + mTmpConstraintGroupRootBuffer (NULL), + mPosePreviewBodies (PX_DEBUG_EXP("scenePosePreviewBodies")) +{ + mCCDPass = 0; + for (int i=0; i < InteractionType::eTRACKED_IN_SCENE_COUNT; ++i) + mActiveInteractionCount[i] = 0; + +#if PX_USE_CLOTH_API + PxMemZero(mClothSolvers, sizeof(mClothSolvers)); + PxMemZero(mClothTasks, sizeof(mClothTasks)); + PxMemZero(mClothFactories, sizeof(mClothFactories)); +#endif + + mStats = PX_NEW(SimStats); + mConstraintIDTracker = PX_NEW(ObjectIDTracker); + mShapeIDTracker = PX_NEW(ObjectIDTracker); + mRigidIDTracker = PX_NEW(ObjectIDTracker); + mElementIDPool = PX_NEW(ObjectIDTracker); + + mTriggerBufferExtraData = reinterpret_cast<TriggerBufferExtraData*>(PX_ALLOC(sizeof(TriggerBufferExtraData), "ScScene::TriggerBufferExtraData")); + new(mTriggerBufferExtraData) TriggerBufferExtraData(PX_DEBUG_EXP("ScScene::TriggerPairExtraData")); + + mStaticSimPool = PX_NEW(PreallocatingPool<StaticSim>)(64, "StaticSim"); + mBodySimPool = PX_NEW(PreallocatingPool<BodySim>)(64, "BodySim"); + mShapeSimPool = PX_NEW(PreallocatingPool<ShapeSim>)(64, "ShapeSim"); + mConstraintSimPool = PX_NEW(Ps::Pool<ConstraintSim>)(PX_DEBUG_EXP("ScScene::ConstraintSim")); + mConstraintInteractionPool = PX_NEW(Ps::Pool<ConstraintInteraction>)(PX_DEBUG_EXP("ScScene::ConstraintInteraction")); + mLLArticulationPool = PX_NEW(LLArticulationPool); + + mSimStateDataPool = PX_NEW(Ps::Pool<SimStateData>)(PX_DEBUG_EXP("ScScene::SimStateData")); + + mClients.pushBack(PX_NEW(Client)()); + mProjectionManager = PX_NEW(ConstraintProjectionManager)(); + + mSqBoundsManager = PX_NEW(SqBoundsManager); + + mTaskManager = physx::PxTaskManager::createTaskManager(Ps::getFoundation().getErrorCallback(), desc.cpuDispatcher, desc.gpuDispatcher); + + for(PxU32 i=0; i<PxGeometryType::eGEOMETRY_COUNT; i++) + mNbGeometries[i] = 0; + + bool useGpuDynamics = false; + bool useGpuBroadphase = false; + +#if PX_SUPPORT_GPU_PHYSX + if (desc.flags & PxSceneFlag::eENABLE_GPU_DYNAMICS) + { + useGpuDynamics = true; + if (mTaskManager->getGpuDispatcher() == NULL) + { + shdfnd::getFoundation().error(PxErrorCode::eDEBUG_WARNING, + __FILE__, __LINE__, "GPU solver pipeline failed, switching to software"); + + useGpuDynamics = false; + } + else if (!mTaskManager->getGpuDispatcher()->getCudaContextManager()->supportsArchSM30()) + useGpuDynamics = false; + } + + if (desc.broadPhaseType & PxBroadPhaseType::eGPU) + { + useGpuBroadphase = true; + if (mTaskManager->getGpuDispatcher() == NULL) + { + shdfnd::getFoundation().error(PxErrorCode::eDEBUG_WARNING, + __FILE__, __LINE__, "GPU Bp pipeline failed, switching to software"); + + useGpuBroadphase = false; + } + else if (!mTaskManager->getGpuDispatcher()->getCudaContextManager()->supportsArchSM30()) + useGpuBroadphase = false; + } +#endif + + mLLContext = PX_NEW(PxsContext)(desc, mTaskManager, mTaskPool, contextID); + + if (mLLContext == 0) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "Failed to create context!"); + return; + } + mLLContext->setMaterialManager(&getMaterialManager()); + + mMemoryManager = NULL; + +#if PX_SUPPORT_GPU_PHYSX + mHeapMemoryAllocationManager = NULL; + mGpuWranglerManagers = NULL; + + if (useGpuBroadphase || useGpuDynamics) + { + mMemoryManager = PxvGetPhysXGpu(true)->createGpuMemoryManager(mLLContext->getTaskManager().getGpuDispatcher(), NULL); + mGpuWranglerManagers = PxvGetPhysXGpu(true)->createGpuKernelWranglerManager(mLLContext->getTaskManager().getGpuDispatcher(), getFoundation().getErrorCallback(),desc.gpuComputeVersion); + mHeapMemoryAllocationManager = PxvGetPhysXGpu(true)->createGpuHeapMemoryAllocatorManager(desc.gpuDynamicsConfig.heapCapacity, mMemoryManager, desc.gpuComputeVersion); + } + else +#endif + { + mMemoryManager = createMemoryManager(); + } + + //Note: broadphase should be independent of AABBManager. MBP uses it to call getBPBounds but it has + //already been passed all bounds in BroadPhase::update() so should use that instead. + if(!useGpuBroadphase) + { + PxBroadPhaseType::Enum broadPhaseType = desc.broadPhaseType; + + if (broadPhaseType == PxBroadPhaseType::eGPU) + broadPhaseType = PxBroadPhaseType::eSAP; + + mBP = Bp::BroadPhase::create( + broadPhaseType, + desc.limits.maxNbRegions, + desc.limits.maxNbBroadPhaseOverlaps, + desc.limits.maxNbStaticShapes, + desc.limits.maxNbDynamicShapes, + contextID); + } + else + { +#if PX_SUPPORT_GPU_PHYSX + mBP = PxvGetPhysXGpu(true)->createGpuBroadPhase + ( + mGpuWranglerManagers, + mLLContext->getTaskManager().getGpuDispatcher(), + NULL, + desc.gpuComputeVersion, + desc.gpuDynamicsConfig, + mHeapMemoryAllocationManager); +#endif + } + + //create allocator + Ps::VirtualAllocatorCallback* allocatorCallback = mMemoryManager->createHostMemoryAllocator(desc.gpuComputeVersion); + Ps::VirtualAllocator allocator(allocatorCallback); + + typedef Ps::Array<PxReal, Ps::VirtualAllocator> ContactDistArray; + + mBoundsArray = PX_NEW(Bp::BoundsArray)(allocator); + //mBoundsArray = PX_NEW(Bp::BoundsArray); + mContactDistance = PX_PLACEMENT_NEW(PX_ALLOC(sizeof(ContactDistArray), PX_DEBUG_EXP("ContactDistance")), ContactDistArray)(allocator); + mHasContactDistanceChanged = false; + + const bool useEnhancedDeterminism = getPublicFlags() & PxSceneFlag::eENABLE_ENHANCED_DETERMINISM; + const bool useAdaptiveForce = mPublicFlags & PxSceneFlag::eADAPTIVE_FORCE; + + mSimpleIslandManager = PX_PLACEMENT_NEW(PX_ALLOC(sizeof(IG::SimpleIslandManager), PX_DEBUG_EXP("SimpleIslandManager")), IG::SimpleIslandManager)(useEnhancedDeterminism, contextID); + + if (!useGpuDynamics) + { + mDynamicsContext = createDynamicsContext + (&mLLContext->getNpMemBlockPool(), mLLContext->getScratchAllocator(), + mLLContext->getTaskPool(), mLLContext->getSimStats(), &mLLContext->getTaskManager(), allocatorCallback, &getMaterialManager(), + &mSimpleIslandManager->getAccurateIslandSim(), contextID, mEnableStabilization, useEnhancedDeterminism, useAdaptiveForce); + + mLLContext->setNphaseImplementationContext(createNphaseImplementationContext(*mLLContext, &mSimpleIslandManager->getAccurateIslandSim())); + + mSimulationControllerCallback = PX_PLACEMENT_NEW(PX_ALLOC(sizeof(ScSimulationControllerCallback), PX_DEBUG_EXP("ScSimulationControllerCallback")), ScSimulationControllerCallback(this)); + mSimulationController = createSimulationController(mSimulationControllerCallback); + + mAABBManager = PX_NEW(Bp::SimpleAABBManager)(*mBP, *mBoundsArray, *mContactDistance, desc.limits.maxNbAggregates, desc.limits.maxNbStaticShapes + desc.limits.maxNbDynamicShapes, allocator, contextID); + } + else + { +#if PX_SUPPORT_GPU_PHYSX + mDynamicsContext = PxvGetPhysXGpu(true)->createGpuDynamicsContext(mLLContext->getTaskPool(), mGpuWranglerManagers, mLLContext->getTaskManager().getGpuDispatcher(), NULL, + desc.gpuDynamicsConfig, &mSimpleIslandManager->getAccurateIslandSim(), desc.gpuMaxNumPartitions, mEnableStabilization, useEnhancedDeterminism, useAdaptiveForce, desc.gpuComputeVersion, mLLContext->getSimStats(), + mHeapMemoryAllocationManager); + + void* contactStreamBase = NULL; + void* patchStreamBase = NULL; + void* forceAndIndiceStreamBase = NULL; + + mDynamicsContext->getDataStreamBase(contactStreamBase, patchStreamBase, forceAndIndiceStreamBase); + + PxvNphaseImplementationContextUsableAsFallback* cpuNphaseImplementation = createNphaseImplementationContext(*mLLContext, &mSimpleIslandManager->getAccurateIslandSim()); + mLLContext->setNphaseFallbackImplementationContext(cpuNphaseImplementation); + + PxvNphaseImplementationContext* gpuNphaseImplementation = PxvGetPhysXGpu(true)->createGpuNphaseImplementationContext(*mLLContext, mGpuWranglerManagers, cpuNphaseImplementation, desc.gpuDynamicsConfig, contactStreamBase, patchStreamBase, + forceAndIndiceStreamBase, getBoundsArray().getBounds(), &mSimpleIslandManager->getAccurateIslandSim(), mDynamicsContext, desc.gpuComputeVersion, mHeapMemoryAllocationManager); + + mSimulationControllerCallback = PX_PLACEMENT_NEW(PX_ALLOC(sizeof(PxgSimulationControllerCallback), PX_DEBUG_EXP("PxgSimulationControllerCallback")), PxgSimulationControllerCallback(this)); + + mSimulationController = PxvGetPhysXGpu(true)->createGpuSimulationController(mGpuWranglerManagers, mLLContext->getTaskManager().getGpuDispatcher(), NULL, + mDynamicsContext, gpuNphaseImplementation, mBP, useGpuBroadphase, mSimpleIslandManager, mSimulationControllerCallback, desc.gpuComputeVersion, mHeapMemoryAllocationManager); + + mSimulationController->setBounds(mBoundsArray); + mDynamicsContext->setSimulationController(mSimulationController); + + mLLContext->setNphaseImplementationContext(gpuNphaseImplementation); + + mLLContext->mContactStreamPool = &mDynamicsContext->getContactStreamPool(); + mLLContext->mPatchStreamPool = &mDynamicsContext->getPatchStreamPool(); + mLLContext->mForceAndIndiceStreamPool = &mDynamicsContext->getForceStreamPool(); + + Ps::VirtualAllocator tAllocator(mHeapMemoryAllocationManager->mMappedMemoryAllocators); + + mAABBManager = PX_NEW(Bp::SimpleAABBManager)(*mBP, *mBoundsArray, *mContactDistance, desc.limits.maxNbAggregates, desc.limits.maxNbStaticShapes + desc.limits.maxNbDynamicShapes, tAllocator, contextID); +#endif + } + + //Construct the bitmap of updated actors required as input to the broadphase update + if(desc.limits.maxNbBodies) + { + // PT: TODO: revisit this. Why do we handle the added/removed and updated bitmaps entirely differently, in different places? And what is this weird formula here? + mAABBManager->getChangedAABBMgActorHandleMap().resize((2*desc.limits.maxNbBodies + 256) & ~255); + } + + //mLLContext->createTransformCache(mDynamicsContext->getAllocatorCallback()); + + mLLContext->createTransformCache(*allocatorCallback); + mLLContext->setContactDistance(mContactDistance); + + mCCDContext = physx::PxsCCDContext::create(mLLContext, mDynamicsContext->getThresholdStream(), *mLLContext->getNphaseImplementationContext()); + + setSolverBatchSize(desc.solverBatchSize); + mDynamicsContext->setFrictionOffsetThreshold(desc.frictionOffsetThreshold); + mDynamicsContext->setCCDSeparationThreshold(desc.ccdMaxSeparation); + + const PxTolerancesScale& scale = Physics::getInstance().getTolerancesScale(); + mDynamicsContext->setCorrelationDistance(0.025f * scale.length); + mLLContext->setMeshContactMargin(0.01f * scale.length); + mLLContext->setToleranceLength(scale.length); + + // the original descriptor uses + // bounce iff impact velocity > threshold + // but LL use + // bounce iff separation velocity < -threshold + // hence we negate here. + + mDynamicsContext->setBounceThreshold(-desc.bounceThresholdVelocity); + + StaticCore* anchorCore = PX_NEW(StaticCore)(PxTransform(PxIdentity)); + + mStaticAnchor = mStaticSimPool->construct(*this, *anchorCore); + + mNPhaseCore = PX_NEW(NPhaseCore)(*this, desc); + + initDominanceMatrix(); + +// DeterminismDebugger::begin(); + + mWokeBodyListValid = true; + mSleepBodyListValid = true; + + //load from desc: + setLimits(desc.limits); + + // Create broad phase + setBroadPhaseCallback(desc.broadPhaseCallback, PX_DEFAULT_CLIENT); + + setGravity(desc.gravity); + + setFrictionType(desc.frictionType); + + setPCM(desc.flags & PxSceneFlag::eENABLE_PCM); + + setContactCache(!(desc.flags & PxSceneFlag::eDISABLE_CONTACT_CACHE)); + setSimulationEventCallback(desc.simulationEventCallback, PX_DEFAULT_CLIENT); + setContactModifyCallback(desc.contactModifyCallback); + setCCDContactModifyCallback(desc.ccdContactModifyCallback); + setCCDMaxPasses(desc.ccdMaxPasses); + PX_ASSERT(mNPhaseCore); // refactor paranoia + + PX_ASSERT( ((desc.filterShaderData) && (desc.filterShaderDataSize > 0)) || + (!(desc.filterShaderData) && (desc.filterShaderDataSize == 0)) ); + if (desc.filterShaderData) + { + mFilterShaderData = PX_ALLOC(desc.filterShaderDataSize, sFilterShaderDataMemAllocId); + PxMemCopy(mFilterShaderData, desc.filterShaderData, desc.filterShaderDataSize); + mFilterShaderDataSize = desc.filterShaderDataSize; + mFilterShaderDataCapacity = desc.filterShaderDataSize; + } + else + { + mFilterShaderData = NULL; + mFilterShaderDataSize = 0; + mFilterShaderDataCapacity = 0; + } + mFilterShader = desc.filterShader; + mFilterCallback = desc.filterCallback; + +#if EXTRA_PROFILING + mExtraProfileFile = fopen("extraProfile.txt", "w"); + mLineNum = 0; +#endif + +#if PX_USE_CLOTH_API + createClothSolver(); +#endif // PX_USE_CLOTH_API + +#if PX_USE_PARTICLE_SYSTEM_API + mParticleContext = Pt::createParticleContext(mTaskManager + , mLLContext->getTaskPool() + ); +#endif // PX_USE_PARTICLE_SYSTEM_API +} + +void Sc::Scene::release() +{ + +#if PX_USE_PARTICLE_SYSTEM_API + if (mParticleContext) + { + mParticleContext->destroy(); + } +#endif // PX_USE_PARTICLE_SYSTEM_API + + // TODO: PT: check virtual stuff + + mTimeStamp++; + + //collisionSpace.purgeAllPairs(); + + //purgePairs(); + //releaseTagData(); + + // We know release all the shapes before the collision space + //collisionSpace.deleteAllShapes(); + + //collisionSpace.release(); + + //DeterminismDebugger::end(); + + ///clear broken constraint list: + clearBrokenConstraintBuffer(); + + PX_DELETE_AND_RESET(mNPhaseCore); + + PX_FREE_AND_RESET(mFilterShaderData); + + if (mStaticAnchor) + { + StaticCore& core = mStaticAnchor->getStaticCore(); + mStaticSimPool->destroy(mStaticAnchor); + delete &core; + } + +#if EXTRA_PROFILING + fclose(mExtraProfileFile); +#endif + + // Free object IDs and the deleted object id map + postReportsCleanup(); + + //before the task manager + if (mLLContext) + { + if(mLLContext->getNphaseFallbackImplementationContext()) + { + mLLContext->getNphaseFallbackImplementationContext()->destroy(); + mLLContext->setNphaseFallbackImplementationContext(NULL); + } + + if(mLLContext->getNphaseImplementationContext()) + { + mLLContext->getNphaseImplementationContext()->destroy(); + mLLContext->setNphaseImplementationContext(NULL); + } + } + + PX_DELETE_AND_RESET(mProjectionManager); + PX_DELETE_AND_RESET(mSqBoundsManager); + PX_DELETE_AND_RESET(mBoundsArray); + + + for(PxU32 i=0;i<mClients.size(); i++) + PX_DELETE_AND_RESET(mClients[i]); + + PX_DELETE(mConstraintInteractionPool); + PX_DELETE(mConstraintSimPool); + PX_DELETE(mSimStateDataPool); + PX_DELETE(mStaticSimPool); + PX_DELETE(mShapeSimPool); + PX_DELETE(mBodySimPool); + PX_DELETE(mLLArticulationPool); + +#if PX_USE_CLOTH_API + for(PxU32 i=0; i<mNumClothSolvers; ++i) + { + if(mClothSolvers[i]) + PX_DELETE(mClothSolvers[i]); + + if(i>0 && mClothFactories[i]) // don't delete sw factory + PX_DELETE(mClothFactories[i]); + } +#endif // PX_USE_CLOTH_API + + mTriggerBufferExtraData->~TriggerBufferExtraData(); + PX_FREE(mTriggerBufferExtraData); + + PX_DELETE(mElementIDPool); + PX_DELETE(mRigidIDTracker); + PX_DELETE(mShapeIDTracker); + PX_DELETE(mConstraintIDTracker); + PX_DELETE(mStats); + + mAABBManager->destroy(); + + mBP->destroy(); + + mSimulationControllerCallback->~PxsSimulationControllerCallback(); + PX_FREE(mSimulationControllerCallback); + mSimulationController->~PxsSimulationController(); + PX_FREE(mSimulationController); + + mDynamicsContext->destroy(); + + + mCCDContext->destroy(); + + + + mSimpleIslandManager->~SimpleIslandManager(); + PX_FREE(mSimpleIslandManager); + +#if PX_SUPPORT_GPU_PHYSX + + + if (mGpuWranglerManagers) + { + mGpuWranglerManagers->~PxsKernelWranglerManager(); + PX_FREE(mGpuWranglerManagers); + mGpuWranglerManagers = NULL; + } + + if (mHeapMemoryAllocationManager) + { + mHeapMemoryAllocationManager->~PxsHeapMemoryAllocatorManager(); + PX_FREE(mHeapMemoryAllocationManager); + mHeapMemoryAllocationManager = NULL; + } +#endif + + if (mTaskManager) + mTaskManager->release(); + + if (mLLContext) + { + PX_DELETE(mLLContext); + mLLContext = NULL; + } + + mContactDistance->~Array(); + PX_FREE(mContactDistance); + + + if (mMemoryManager) + { + mMemoryManager->~PxsMemoryManager(); + PX_FREE(mMemoryManager); + mMemoryManager = NULL; + } + +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void Sc::Scene::preAllocate(PxU32 nbStatics, PxU32 nbBodies, PxU32 nbStaticShapes, PxU32 nbDynamicShapes) +{ + // PT: TODO: this is only used for my addActors benchmark for now. Pre-allocate more arrays here. + + mActiveBodies.reserve(PxMax<PxU32>(64,nbBodies)); + + mStaticSimPool->preAllocate(nbStatics); + + mBodySimPool->preAllocate(nbBodies); + + mShapeSimPool->preAllocate(nbStaticShapes + nbDynamicShapes); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void Sc::Scene::addToActiveBodyList(BodySim& body) +{ + PX_ASSERT(body.getActiveListIndex() >= SC_NOT_IN_ACTIVE_LIST_INDEX); + + // Sort: kinematic before dynamic + const PxU32 size = mActiveBodies.size(); + BodyCore* appendedBodyCore = &body.getBodyCore(); // PT: by default we append the incoming body... + PxU32 incomingBodyActiveListIndex = size; // PT: ...at the end of the current array. + if(body.isKinematic()) // PT: Except if incoming body is kinematic, in which case: + { + const PxU32 nbKinematics = mActiveKinematicBodyCount++; // PT: - we increase their number + if(nbKinematics != size) // PT: - if there's at least one dynamic in the array... + { + appendedBodyCore = mActiveBodies[nbKinematics]; // PT: ...then we grab the first dynamic after the kinematics... + appendedBodyCore->getSim()->setActiveListIndex(size); // PT: ...and we move that one back to the end of the array... + + mActiveBodies[nbKinematics] = &body.getBodyCore(); // PT: ...while the incoming kine replaces the dynamic we moved out. + incomingBodyActiveListIndex = nbKinematics; // PT: ...thus the incoming kine's index is the prev #kines. + } + } + body.setActiveListIndex(incomingBodyActiveListIndex); // PT: will be 'size' or 'nbKinematics' + mActiveBodies.pushBack(appendedBodyCore); // PT: will be the incoming object or the first dynamic we moved out. +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void Sc::Scene::removeFromActiveBodyList(BodySim& body) +{ + PxU32 removedIndex = body.getActiveListIndex(); + PX_ASSERT(removedIndex < SC_NOT_IN_ACTIVE_LIST_INDEX); + PX_ASSERT(mActiveBodies[removedIndex]==&body.getBodyCore()); + body.setActiveListIndex(SC_NOT_IN_ACTIVE_LIST_INDEX); + + const PxU32 newSize = mActiveBodies.size() - 1; + + // Sort: kinematic before dynamic + if(removedIndex < mActiveKinematicBodyCount) // PT: same as 'body.isKinematic()' but without accessing the Core data + { + PX_ASSERT(mActiveKinematicBodyCount); + PX_ASSERT(body.isKinematic()); + const PxU32 swapIndex = --mActiveKinematicBodyCount; + if(newSize != swapIndex // PT: equal if the array only contains kinematics + && removedIndex < swapIndex) // PT: i.e. "if we don't remove the last kinematic" + { + BodyCore* swapBody = mActiveBodies[swapIndex]; + swapBody->getSim()->setActiveListIndex(removedIndex); + mActiveBodies[removedIndex] = swapBody; + removedIndex = swapIndex; + } + } + + if(removedIndex!=newSize) + { + Sc::BodyCore* lastBody = mActiveBodies[newSize]; + mActiveBodies[removedIndex] = lastBody; + lastBody->getSim()->setActiveListIndex(removedIndex); + } + mActiveBodies.forceSize_Unsafe(newSize); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void Sc::Scene::swapInActiveBodyList(BodySim& body) +{ + const PxU32 activeListIndex = body.getActiveListIndex(); + PX_ASSERT(activeListIndex < SC_NOT_IN_ACTIVE_LIST_INDEX); + + PxU32 swapIndex; + PxU32 newActiveKinematicBodyCount; + if(activeListIndex < mActiveKinematicBodyCount) + { + // kinematic -> dynamic + PX_ASSERT(!body.isKinematic()); // the corresponding flag gets switched before this call + PX_ASSERT(mActiveKinematicBodyCount > 0); // there has to be at least one kinematic body + + swapIndex = mActiveKinematicBodyCount - 1; + newActiveKinematicBodyCount = swapIndex; + } + else + { + // dynamic -> kinematic + PX_ASSERT(body.isKinematic()); // the corresponding flag gets switched before this call + PX_ASSERT(mActiveKinematicBodyCount < mActiveBodies.size()); // there has to be at least one dynamic body + + swapIndex = mActiveKinematicBodyCount; + newActiveKinematicBodyCount = swapIndex + 1; + } + + BodyCore*& swapBodyRef = mActiveBodies[swapIndex]; + body.setActiveListIndex(swapIndex); + BodyCore* swapBody = swapBodyRef; + swapBodyRef = &body.getBodyCore(); + + swapBody->getSim()->setActiveListIndex(activeListIndex); + mActiveBodies[activeListIndex] = swapBody; + + mActiveKinematicBodyCount = newActiveKinematicBodyCount; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void Sc::Scene::registerInteraction(Interaction* interaction, bool active) +{ + const InteractionType::Enum type = interaction->getType(); + const PxU32 sceneArrayIndex = mInteractions[type].size(); + interaction->setInteractionId(sceneArrayIndex); + if(mInteractions[type].capacity()==0) + mInteractions[type].reserve(64); + + mInteractions[type].pushBack(interaction); + if (active) + { + if (sceneArrayIndex > mActiveInteractionCount[type]) + swapInteractionArrayIndices(sceneArrayIndex, mActiveInteractionCount[type], type); + mActiveInteractionCount[type]++; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void Sc::Scene::unregisterInteraction(Interaction* interaction) +{ + const InteractionType::Enum type = interaction->getType(); + const PxU32 sceneArrayIndex = interaction->getInteractionId(); + mInteractions[type].replaceWithLast(sceneArrayIndex); + interaction->setInteractionId(PX_INVALID_INTERACTION_SCENE_ID); + if (sceneArrayIndex<mInteractions[type].size()) // The removed interaction was the last one, do not reset its sceneArrayIndex + mInteractions[type][sceneArrayIndex]->setInteractionId(sceneArrayIndex); + if (sceneArrayIndex<mActiveInteractionCount[type]) + { + mActiveInteractionCount[type]--; + if (mActiveInteractionCount[type]<mInteractions[type].size()) + swapInteractionArrayIndices(sceneArrayIndex, mActiveInteractionCount[type], type); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void Sc::Scene::swapInteractionArrayIndices(PxU32 id1, PxU32 id2, InteractionType::Enum type) +{ + Ps::Array<Interaction*>& interArray = mInteractions[type]; + Interaction* interaction1 = interArray[id1]; + Interaction* interaction2 = interArray[id2]; + interArray[id1] = interaction2; + interArray[id2] = interaction1; + interaction1->setInteractionId(id2); + interaction2->setInteractionId(id1); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void Sc::Scene::notifyInteractionActivated(Interaction* interaction) +{ + PX_ASSERT((interaction->getType() == InteractionType::eOVERLAP) || (interaction->getType() == InteractionType::eTRIGGER)); + PX_ASSERT(interaction->readInteractionFlag(InteractionFlag::eIS_ACTIVE)); + PX_ASSERT(interaction->getInteractionId() != PX_INVALID_INTERACTION_SCENE_ID); + + const InteractionType::Enum type = interaction->getType(); + + PX_ASSERT(interaction->getInteractionId() >= mActiveInteractionCount[type]); + + if (mActiveInteractionCount[type] < mInteractions[type].size()) + swapInteractionArrayIndices(mActiveInteractionCount[type], interaction->getInteractionId(), type); + mActiveInteractionCount[type]++; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void Sc::Scene::notifyInteractionDeactivated(Interaction* interaction) +{ + PX_ASSERT((interaction->getType() == InteractionType::eOVERLAP) || (interaction->getType() == InteractionType::eTRIGGER)); + PX_ASSERT(!interaction->readInteractionFlag(InteractionFlag::eIS_ACTIVE)); + PX_ASSERT(interaction->getInteractionId() != PX_INVALID_INTERACTION_SCENE_ID); + + const InteractionType::Enum type = interaction->getType(); + PX_ASSERT(interaction->getInteractionId() < mActiveInteractionCount[type]); + + if (mActiveInteractionCount[type] > 1) + swapInteractionArrayIndices(mActiveInteractionCount[type]-1, interaction->getInteractionId(), type); + mActiveInteractionCount[type]--; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void** Sc::Scene::allocatePointerBlock(PxU32 size) +{ + PX_ASSERT(size>32 || size == 32 || size == 16 || size == 8); + void* ptr; + if(size==8) + ptr = mPointerBlock8Pool.construct(); + else if(size == 16) + ptr = mPointerBlock16Pool.construct(); + else if(size == 32) + ptr = mPointerBlock32Pool.construct(); + else + ptr = PX_ALLOC(size * sizeof(void*), "void*"); + + return reinterpret_cast<void**>(ptr); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void Sc::Scene::deallocatePointerBlock(void** block, PxU32 size) +{ + PX_ASSERT(size>32 || size == 32 || size == 16 || size == 8); + if(size==8) + mPointerBlock8Pool.destroy(reinterpret_cast<PointerBlock8*>(block)); + else if(size == 16) + mPointerBlock16Pool.destroy(reinterpret_cast<PointerBlock16*>(block)); + else if(size == 32) + mPointerBlock32Pool.destroy(reinterpret_cast<PointerBlock32*>(block)); + else + return PX_FREE(block); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +PxBroadPhaseType::Enum Sc::Scene::getBroadPhaseType() const +{ + Bp::BroadPhase* bp = mAABBManager->getBroadPhase(); + return bp->getType(); +} + +bool Sc::Scene::getBroadPhaseCaps(PxBroadPhaseCaps& caps) const +{ + Bp::BroadPhase* bp = mAABBManager->getBroadPhase(); + return bp->getCaps(caps); +} + +PxU32 Sc::Scene::getNbBroadPhaseRegions() const +{ + Bp::BroadPhase* bp = mAABBManager->getBroadPhase(); + return bp->getNbRegions(); +} + +PxU32 Sc::Scene::getBroadPhaseRegions(PxBroadPhaseRegionInfo* userBuffer, PxU32 bufferSize, PxU32 startIndex) const +{ + Bp::BroadPhase* bp = mAABBManager->getBroadPhase(); + return bp->getRegions(userBuffer, bufferSize, startIndex); +} + +PxU32 Sc::Scene::addBroadPhaseRegion(const PxBroadPhaseRegion& region, bool populateRegion) +{ + Bp::BroadPhase* bp = mAABBManager->getBroadPhase(); + return bp->addRegion(region, populateRegion); +} + +bool Sc::Scene::removeBroadPhaseRegion(PxU32 handle) +{ + Bp::BroadPhase* bp = mAABBManager->getBroadPhase(); + return bp->removeRegion(handle); +} + +void** Sc::Scene::getOutOfBoundsAggregates() +{ + PxU32 dummy; + return mAABBManager->getOutOfBoundsAggregates(dummy); +} + +PxU32 Sc::Scene::getNbOutOfBoundsAggregates() +{ + PxU32 val; + mAABBManager->getOutOfBoundsAggregates(val); + return val; +} + +void Sc::Scene::clearOutOfBoundsAggregates() +{ + mAABBManager->clearOutOfBoundsAggregates(); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void Sc::Scene::setFilterShaderData(const void* data, PxU32 dataSize) +{ + PX_UNUSED(sFilterShaderDataMemAllocId); + + if (data) + { + PX_ASSERT(dataSize > 0); + + void* buffer; + + if (dataSize <= mFilterShaderDataCapacity) + buffer = mFilterShaderData; + else + { + buffer = PX_ALLOC(dataSize, sFilterShaderDataMemAllocId); + if (buffer) + { + mFilterShaderDataCapacity = dataSize; + if (mFilterShaderData) + PX_FREE(mFilterShaderData); + } + else + { + Ps::getFoundation().error(PxErrorCode::eOUT_OF_MEMORY, __FILE__, __LINE__, "Failed to allocate memory for filter shader data!"); + return; + } + } + + PxMemCopy(buffer, data, dataSize); + mFilterShaderData = buffer; + mFilterShaderDataSize = dataSize; + } + else + { + PX_ASSERT(dataSize == 0); + + if (mFilterShaderData) + PX_FREE_AND_RESET(mFilterShaderData); + mFilterShaderDataSize = 0; + mFilterShaderDataCapacity = 0; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +Cm::RenderBuffer& Sc::Scene::getRenderBuffer() +{ + return mLLContext->getRenderBuffer(); +} + +void Sc::Scene::prepareCollide() +{ + mReportShapePairTimeStamp++; // deleted actors/shapes should get separate pair entries in contact reports + mContactReportsNeedPostSolverVelocity = false; + + mRemovedShapeCountAtSimStart = mShapeIDTracker->getDeletedIDCount(); + + getRenderBuffer().clear(); + + ///clear broken constraint list: + clearBrokenConstraintBuffer(); + + updateFromVisualizationParameters(); + +#if PX_USE_PARTICLE_SYSTEM_API + // Build list of enabled particle systems + mEnabledParticleSystems.clear(); + mEnabledParticleSystems.reserve(mParticleSystems.size()); + ParticleSystemCore* const* pSystems = mParticleSystems.getEntries(); + for(PxU32 i=0; i < mParticleSystems.size(); i++) + { + ParticleSystemCore* ps = pSystems[i]; + if (ps->getFlags() & PxParticleBaseFlag::eENABLED) + { + mEnabledParticleSystems.pushBack(ps->getSim()); + } + } +#endif // PX_USE_PARTICLE_SYSTEM_API + + visualizeStartStep(); + +#ifdef DUMP_PROFILER + dumpProfiler(this); +#endif + + PxcClearContactCacheStats(); +} + + +void Sc::Scene::simulate(PxReal timeStep, PxBaseTask* continuation) +{ + if(timeStep != 0.f) + { + mDt = timeStep; + mOneOverDt = 0.0f < mDt ? 1.0f/mDt : 0.0f; + + prepareCollide(); + stepSetupCollide(); + + mAdvanceStep.setContinuation(continuation); + mCollideStep.setContinuation(&mAdvanceStep); + + mAdvanceStep.removeReference(); + mCollideStep.removeReference(); + } +} + +void Sc::Scene::advance(PxReal timeStep, PxBaseTask* continuation) +{ + if(timeStep != 0.0f) + { + mDt = timeStep; + mOneOverDt = 0.0f < mDt ? 1.0f/mDt : 0.0f; + + stepSetupSolve(); + + mAdvanceStep.setContinuation(continuation); + mAdvanceStep.removeReference(); + } +} + +void Sc::Scene::setBounceThresholdVelocity(const PxReal t) +{ + mDynamicsContext->setBounceThreshold(-t); +} + +PxReal Sc::Scene::getBounceThresholdVelocity() const +{ + return -mDynamicsContext->getBounceThreshold(); +} + +void Sc::Scene::collide(PxReal timeStep, PxBaseTask* continuation) +{ + mDt = timeStep; + + prepareCollide(); + stepSetupCollide(); + + mLLContext->beginUpdate(); + + mCollideStep.setContinuation(continuation); + mCollideStep.removeReference(); +} + +void Sc::Scene::setFrictionType(PxFrictionType::Enum model) +{ + mDynamicsContext->setFrictionType(model); +} + +PxFrictionType::Enum Sc::Scene::getFrictionType() const +{ + return mDynamicsContext->getFrictionType(); +} + +void Sc::Scene::setPCM(bool enabled) +{ + mLLContext->setPCM(enabled); +} + +void Sc::Scene::setContactCache(bool enabled) +{ + mLLContext->setContactCache(enabled); +} + +void Sc::Scene::endSimulation() +{ + // Handle user contact filtering + // Note: Do this before the contact callbacks get fired since the filter callback might + // trigger contact reports (touch lost due to re-filtering) + + PxsContactManagerOutputIterator outputs = mLLContext->getNphaseImplementationContext()->getContactManagerOutputs(); + + mNPhaseCore->fireCustomFilteringCallbacks(outputs, mPublicFlags & PxSceneFlag::eADAPTIVE_FORCE); + + mNPhaseCore->preparePersistentContactEventListForNextFrame(); + + endStep(); // - Update time stamps + + PxcDisplayContactCacheStats(); +} + + +void Sc::Scene::flush(bool sendPendingReports) +{ + if (sendPendingReports) + { + fireQueuedContactCallbacks(true); + mNPhaseCore->clearContactReportStream(); + mNPhaseCore->clearContactReportActorPairs(true); + + fireTriggerCallbacks(); + } + else + { + mNPhaseCore->clearContactReportActorPairs(true); // To clear the actor pair set + } + postReportsCleanup(); + mNPhaseCore->freeContactReportStreamMemory(); + + mTriggerBufferAPI.reset(); + mTriggerBufferExtraData->reset(); + + clearBrokenConstraintBuffer(); + mBrokenConstraints.reset(); + + clearSleepWakeBodies(); //!!! If we send out these reports on flush then this would not be necessary + + mClients.shrink(); + + mShapeIDTracker->reset(); + mRigidIDTracker->reset(); + + processLostTouchPairs(); // Processes the lost touch bodies + PX_ASSERT(mLostTouchPairs.size() == 0); + mLostTouchPairs.reset(); + // Does not seem worth deleting the bitmap for the lost touch pair list + + mActiveBodies.shrink(); + + for(PxU32 i=0; i < InteractionType::eTRACKED_IN_SCENE_COUNT; i++) + { + mInteractions[i].shrink(); + } + + //!!! TODO: look into retrieving memory from the NPhaseCore & Broadphase class (all the pools in there etc.) + +#if PX_USE_PARTICLE_SYSTEM_API + mEnabledParticleSystems.reset(); +#endif + + mLLContext->getNpMemBlockPool().releaseUnusedBlocks(); +} + + +// User callbacks + +void Sc::Scene::setSimulationEventCallback(PxSimulationEventCallback* callback, PxClientID client) +{ + PX_ASSERT(client < mClients.size()); + PxSimulationEventCallback*& current = mClients[client]->simulationEventCallback; + if (!current && callback) + { + // if there was no callback before, the sleeping bodies have to be prepared for potential notification events (no shortcut possible anymore) + BodyCore* const* sleepingBodies = mSleepBodies.getEntries(); + for(PxU32 i=0; i < mSleepBodies.size(); i++) + sleepingBodies[i]->getSim()->raiseInternalFlag(BodySim::BF_SLEEP_NOTIFY); + } + + current = callback; +} + +PxSimulationEventCallback* Sc::Scene::getSimulationEventCallback(PxClientID client) const +{ + PX_ASSERT(client < mClients.size()); + return mClients[client]->simulationEventCallback; +} + +void Sc::Scene::setContactModifyCallback(PxContactModifyCallback* callback) +{ + mLLContext->setContactModifyCallback(callback); +} + +PxContactModifyCallback* Sc::Scene::getContactModifyCallback() const +{ + return mLLContext->getContactModifyCallback(); +} + +void Sc::Scene::setCCDContactModifyCallback(PxCCDContactModifyCallback* callback) +{ + mCCDContext->setCCDContactModifyCallback(callback); +} + +PxCCDContactModifyCallback* Sc::Scene::getCCDContactModifyCallback() const +{ + return mCCDContext->getCCDContactModifyCallback(); +} + +void Sc::Scene::setCCDMaxPasses(PxU32 ccdMaxPasses) +{ + mCCDContext->setCCDMaxPasses(ccdMaxPasses); +} + +PxU32 Sc::Scene::getCCDMaxPasses() const +{ + return mCCDContext->getCCDMaxPasses(); +} + + +void Sc::Scene::setBroadPhaseCallback(PxBroadPhaseCallback* callback, PxClientID client) +{ + PX_ASSERT(client < mClients.size()); + mClients[client]->broadPhaseCallback = callback; +} + +PxBroadPhaseCallback* Sc::Scene::getBroadPhaseCallback(PxClientID client) const +{ + PX_ASSERT(client < mClients.size()); + return mClients[client]->broadPhaseCallback; +} + +void Sc::Scene::removeBody(BodySim& body) //this also notifies any connected joints! +{ + ConstraintGroupNode* node = body.getConstraintGroup(); + if (node) + { + //invalidate the constraint group: + //this adds all constraints of the group to the dirty list such that groups get re-generated next frame + getProjectionManager().invalidateGroup(*node, NULL); + } + + BodyCore& core = body.getBodyCore(); + + // Remove from sleepBodies array + mSleepBodies.erase(&core); + PX_ASSERT(!mSleepBodies.contains(&core)); + + // Remove from wokeBodies array + mWokeBodies.erase(&core); + PX_ASSERT(!mWokeBodies.contains(&core)); + + if (body.isActive() && (core.getFlags() & PxRigidBodyFlag::eENABLE_POSE_INTEGRATION_PREVIEW)) + removeFromPosePreviewList(body); + else + PX_ASSERT(!isInPosePreviewList(body)); + + markReleasedBodyIDForLostTouch(body.getID()); +} + + +void Sc::Scene::addConstraint(ConstraintCore& constraint, RigidCore* body0, RigidCore* body1) +{ + ConstraintSim* sim = mConstraintSimPool->construct(constraint, body0, body1, *this); + PX_UNUSED(sim); + + mConstraints.insert(&constraint); +} + + +void Sc::Scene::removeConstraint(ConstraintCore& constraint) +{ + ConstraintSim* cSim = constraint.getSim(); + + if (cSim) + { + BodySim* b = cSim->getAnyBody(); + ConstraintGroupNode* n = b->getConstraintGroup(); + + if (n) + getProjectionManager().invalidateGroup(*n, cSim); + mConstraintSimPool->destroy(cSim); + } + + mConstraints.erase(&constraint); +} + + +void Sc::Scene::addArticulation(ArticulationCore& articulation, BodyCore& root) +{ + ArticulationSim* sim = PX_NEW(ArticulationSim)(articulation, *this, root); + + if (sim && (sim->getLowLevelArticulation() == NULL)) + { + PX_DELETE(sim); + return; + } + mArticulations.insert(&articulation); +} + + +void Sc::Scene::removeArticulation(ArticulationCore& articulation) +{ + ArticulationSim* a = articulation.getSim(); + if (a) + PX_DELETE(a); + mArticulations.erase(&articulation); +} + + +void Sc::Scene::addArticulationJoint(ArticulationJointCore& joint, BodyCore& parent, BodyCore& child) +{ + ArticulationJointSim* sim = PX_NEW(ArticulationJointSim)(joint, *parent.getSim(), *child.getSim()); + PX_UNUSED(sim); +} + + +void Sc::Scene::removeArticulationJoint(ArticulationJointCore& joint) +{ + if (joint.getSim()) + PX_DELETE(joint.getSim()); +} + + +void Sc::Scene::addBrokenConstraint(Sc::ConstraintCore* c) +{ + PX_ASSERT(mBrokenConstraints.find(c) == mBrokenConstraints.end()); + mBrokenConstraints.pushBack(c); +} + +void Sc::Scene::addActiveBreakableConstraint(Sc::ConstraintSim* c, Sc::ConstraintInteraction* ci) +{ + PX_ASSERT(ci && ci->readInteractionFlag(InteractionFlag::eIS_ACTIVE)); + PX_UNUSED(ci); + PX_ASSERT(!mActiveBreakableConstraints.contains(c)); + PX_ASSERT(!c->isBroken()); + mActiveBreakableConstraints.insert(c); + c->setFlag(ConstraintSim::eCHECK_MAX_FORCE_EXCEEDED); +} + +void Sc::Scene::removeActiveBreakableConstraint(Sc::ConstraintSim* c) +{ + const bool exists = mActiveBreakableConstraints.erase(c); + PX_ASSERT(exists); + PX_UNUSED(exists); + c->clearFlag(ConstraintSim::eCHECK_MAX_FORCE_EXCEEDED); +} + +void* Sc::Scene::allocateConstraintBlock(PxU32 size) +{ + if(size<=128) + return mMemBlock128Pool.construct(); + else if(size<=256) + return mMemBlock256Pool.construct(); + else if(size<=384) + return mMemBlock384Pool.construct(); + else + return PX_ALLOC(size, "ConstraintBlock"); +} + +void Sc::Scene::deallocateConstraintBlock(void* ptr, PxU32 size) +{ + if(size<=128) + mMemBlock128Pool.destroy(reinterpret_cast<MemBlock128*>(ptr)); + else if(size<=256) + mMemBlock256Pool.destroy(reinterpret_cast<MemBlock256*>(ptr)); + else if(size<=384) + mMemBlock384Pool.destroy(reinterpret_cast<MemBlock384*>(ptr)); + else + PX_FREE(ptr); +} + +PxBaseTask& Sc::Scene::scheduleCloth(PxBaseTask& continuation, bool afterBroadPhase) +{ +#if PX_USE_CLOTH_API + if(*mClothSolvers) + { + bool hasCollision = false; + ClothCore* const* clothList = mCloths.getEntries(); + for (PxU32 i = 0; !hasCollision && i < mCloths.size(); ++i) + hasCollision |= bool(clothList[i]->getClothFlags() & PxClothFlag::eSCENE_COLLISION); + + if(hasCollision == afterBroadPhase) + { + // if no cloth uses scene collision, kick off cloth processing task + PxBaseTask* solverTask = &mClothSolvers[0]->simulate(mDt, continuation); + mClothPreprocessing.setContinuation(solverTask); + solverTask->removeReference(); + return mClothPreprocessing; + } + } + + continuation.addReference(); + +#else // PX_USE_CLOTH_API +PX_UNUSED(continuation); +PX_UNUSED(afterBroadPhase); +#endif + return continuation; +} + +void Sc::Scene::scheduleClothGpu(PxBaseTask& continuation) +{ +#if PX_USE_CLOTH_API + for(PxU32 i=1; i<mNumClothSolvers; ++i) + { + if(!mClothSolvers[i]) + continue; + + // if there was a CUDA error last fame then we switch + // all cloth instances to Sw and destroy the GpuSolver + if (mClothSolvers[i]->hasError()) + { + shdfnd::getFoundation().error(PxErrorCode::eDEBUG_WARNING, + __FILE__, __LINE__, "GPU cloth pipeline failed, switching to software"); + + PxClothFlags maskSolver = ~PxClothFlag::Enum(i); + ClothCore* const* clothList = mCloths.getEntries(); + for (PxU32 j = 0; j < mCloths.size(); ++j) + clothList[j]->setClothFlags(clothList[j]->getClothFlags() & maskSolver); + + PX_DELETE_AND_RESET(mClothSolvers[i]); + mClothTasks[i] = NULL; + } + else + { + mClothTasks[i] = &mClothSolvers[i]->simulate(mDt, continuation); + } + + PX_ASSERT(*mClothSolvers); // make sure cpu cloth is scheduled if gpu cloth is + } + +#else + PX_UNUSED(continuation); +#endif // PX_USE_CLOTH_API +} + +PxBaseTask& Sc::Scene::scheduleParticleShapeGeneration(PxBaseTask& broadPhaseDependent, PxBaseTask& dynamicsCpuDependent) +{ + mParticlePostShapeGen.addDependent(broadPhaseDependent); + mParticlePostShapeGen.addDependent(dynamicsCpuDependent); + mParticlePostShapeGen.removeReference(); + +#if PX_USE_PARTICLE_SYSTEM_API + if (mEnabledParticleSystems.size() > 0) + { + PxBaseTask& task = Sc::ParticleSystemSim::scheduleShapeGeneration(*mParticleContext, mEnabledParticleSystems, mParticlePostShapeGen); + mParticlePostShapeGen.removeReference(); + return task; + } +#endif + + return mParticlePostShapeGen; +} + +PxBaseTask& Sc::Scene::scheduleParticleDynamicsCpu(PxBaseTask& continuation) +{ +#if PX_USE_PARTICLE_SYSTEM_API + if (mEnabledParticleSystems.size() > 0) + { + return Sc::ParticleSystemSim::scheduleDynamicsCpu(*mParticleContext, mEnabledParticleSystems, continuation); + } +#endif + + continuation.addReference(); + return continuation; +} + +PxBaseTask& Sc::Scene::scheduleParticleCollisionPrep(PxBaseTask& collisionCpuDependent, + PxBaseTask& gpuDependent) +{ + mParticlePostCollPrep.addDependent(collisionCpuDependent); + mParticlePostCollPrep.addDependent(gpuDependent); + mParticlePostCollPrep.removeReference(); + +#if PX_USE_PARTICLE_SYSTEM_API + if (mEnabledParticleSystems.size() > 0) + { + PxBaseTask& task = Sc::ParticleSystemSim::scheduleCollisionPrep(*mParticleContext, mEnabledParticleSystems, mParticlePostCollPrep); + mParticlePostCollPrep.removeReference(); + return task; + } +#endif + + return mParticlePostCollPrep; +} + +PxBaseTask& Sc::Scene::scheduleParticleCollisionCpu(PxBaseTask& continuation) +{ +#if PX_USE_PARTICLE_SYSTEM_API + if (mEnabledParticleSystems.size() > 0) + { + return Sc::ParticleSystemSim::scheduleCollisionCpu(*mParticleContext, mEnabledParticleSystems, continuation); + } +#endif + + continuation.addReference(); + return continuation; +} + +PxBaseTask& Sc::Scene::scheduleParticleGpu(PxBaseTask& continuation) +{ +#if PX_USE_PARTICLE_SYSTEM_API && PX_SUPPORT_GPU_PHYSX + if (mEnabledParticleSystems.size() > 0) + { + return Sc::ParticleSystemSim::schedulePipelineGpu(*mParticleContext, mEnabledParticleSystems, continuation); + } +#endif + + continuation.addReference(); + return continuation; +} + +//int testAxisConstraint(Sc::Scene& scene); +//int testCasts(Shape* shape); +//int testCasts(Shape& shape); + +/*-------------------------------*\ +| Adam's explanation of the RB solver: +| This is a novel idea of mine, +| a combination of ideas on +| Milenkovic's Optimization +| Based Animation, and Trinkle's +| time stepping schemes. +| +| A time step goes like this: +| +| Taking no substeps: +| 0) Compute contact points. +| 1) Update external forces. This may include friction. +| 2) Integrate external forces to current velocities. +| 3) Solve for impulses at contacts which will prevent +| interpenetration at next timestep given some +| velocity integration scheme. +| 4) Use the integration scheme on velocity to +| reach the next state. Here we should not have any +| interpenetration at the old contacts, but perhaps +| at new contacts. If interpenetrating at new contacts, +| just add these to the contact list; no need to repeat +| the time step, because the scheme will get rid of the +| penetration by the next step. +| +| +| Advantages: +| + Large steps, LOD realism. +| + very simple. +| +\*-------------------------------*/ + +void Sc::Scene::advanceStep(PxBaseTask* continuation) +{ + PX_PROFILE_ZONE("Sim.solveQueueTasks", getContextId()); + + if (mDt != 0.0f) + { + mFinalizationPhase.addDependent(*continuation); + mFinalizationPhase.removeReference(); + + if (mPublicFlags & PxSceneFlag::eENABLE_CCD) + { + mUpdateCCDMultiPass.setContinuation(&mFinalizationPhase); + mAfterIntegration.setContinuation(&mUpdateCCDMultiPass); + mUpdateCCDMultiPass.removeReference(); + } + else + { + mAfterIntegration.setContinuation(&mFinalizationPhase); + } + + mPostSolver.setContinuation(&mAfterIntegration); + PxBaseTask& clothTask = scheduleCloth(mPostSolver, true); + mUpdateSimulationController.setContinuation(&clothTask); + mUpdateDynamics.setContinuation(&mUpdateSimulationController); + mUpdateBodiesAndShapes.setContinuation(&mUpdateDynamics); + mSolver.setContinuation(&mUpdateBodiesAndShapes); + mPostIslandGen.setContinuation(&mSolver); + mIslandGen.setContinuation(&mPostIslandGen); + mPostNarrowPhase.addDependent(mIslandGen); + mPostNarrowPhase.removeReference(); + + mSecondPassNarrowPhase.setContinuation(&mPostNarrowPhase); + + mFinalizationPhase.removeReference(); + mAfterIntegration.removeReference(); + mPostSolver.removeReference(); + clothTask.removeReference(); + mUpdateSimulationController.removeReference(); + mUpdateDynamics.removeReference(); + mUpdateBodiesAndShapes.removeReference(); + mSolver.removeReference(); + mPostIslandGen.removeReference(); + mIslandGen.removeReference(); + mPostNarrowPhase.removeReference(); + mSecondPassNarrowPhase.removeReference(); + } +} + + +//void Sc::Scene::advanceStep(PxBaseTask* continuation) +//{ +// PX_PROFILE_ZONE("Sim.solveQueueTasks", getContextId()); +// +// if(mDt!=0.0f) +// { +// mFinalizationPhase.addDependent(*continuation); +// mFinalizationPhase.removeReference(); +// +// if(mPublicFlags & PxSceneFlag::eENABLE_CCD) +// { +// mUpdateCCDMultiPass.setContinuation(&mFinalizationPhase); +// mAfterIntegration.setContinuation(&mUpdateCCDMultiPass); +// mUpdateCCDMultiPass.removeReference(); +// } +// else +// { +// mAfterIntegration.setContinuation(&mFinalizationPhase); +// } +// +// mPostSolver.setContinuation(&mAfterIntegration); +// PxBaseTask& clothTask = scheduleCloth(mPostSolver, true); +// mUpdateSimulationController.setContinuation(&clothTask); +// mUpdateDynamics.setContinuation(&mUpdateSimulationController); +// mSolver.setContinuation(&mUpdateDynamics); +// mProcessTriggerInteractions.setContinuation(&mSolver); +// mPostIslandGen.setContinuation(&mProcessTriggerInteractions); +// mIslandGen.setContinuation(&mPostIslandGen); +// +// mFinalizationPhase.removeReference(); +// mAfterIntegration.removeReference(); +// mPostSolver.removeReference(); +// clothTask.removeReference(); +// mUpdateSimulationController.removeReference(); +// mUpdateDynamics.removeReference(); +// mSolver.removeReference(); +// mProcessTriggerInteractions.removeReference(); +// mPostIslandGen.removeReference(); +// mIslandGen.removeReference(); +// } +//} + +/*-------------------------------*\ +| For generating a task graph of the runtime task +| execution have a look at the DOT_LOG define and +| https://wiki.nvidia.com/engwiki/index.php/PhysX/sdk/InternalDoc_Example_TaskGraph +| +| A method for understanding the code used to schedule tasks +| is to read from the bottom to the top. +| Functions like Task& taskA = scheduleTask(taskB, taskC) +| can be read as "taskB and taskC depend on taskA" +\*-------------------------------*/ + +void Sc::Scene::collideStep(PxBaseTask* continuation) +{ + PX_PROFILE_ZONE("Sim.collideQueueTasks", getContextId()); + PX_PROFILE_START_CROSSTHREAD("Basic.collision", getContextId()); + + mStats->simStart(); + mLLContext->beginUpdate(); + + prepareParticleSystems(); + + mPostNarrowPhase.setTaskManager(*continuation->getTaskManager()); + mPostNarrowPhase.addReference(); + + mFinalizationPhase.setTaskManager(*continuation->getTaskManager()); + mFinalizationPhase.addReference(); + + mRigidBodyNarrowPhase.setContinuation(continuation); + mPreRigidBodyNarrowPhase.setContinuation(&mRigidBodyNarrowPhase); + + scheduleClothGpu(mFinalizationPhase); + PxBaseTask& clothTask = scheduleCloth(mFinalizationPhase, false); + clothTask.removeReference(); + + mRigidBodyNarrowPhase.removeReference(); + mPreRigidBodyNarrowPhase.removeReference(); +} + + +void Sc::Scene::clothPreprocessing(PxBaseTask* /*continuation*/) +{ +#if PX_USE_CLOTH_API + ClothCore* const* clothList = mCloths.getEntries(); + for (PxU32 i = 0; i < mCloths.size(); ++i) + clothList[i]->getSim()->startStep(); + + for(PxU32 i=0; i<mNumClothSolvers; ++i) + { + if (mClothTasks[i]) + mClothTasks[i]->removeReference(); + } +#endif +} + +void Sc::Scene::broadPhase(PxBaseTask* continuation) +{ + PX_PROFILE_START_CROSSTHREAD("Basic.broadPhase", getContextId()); + +#if PX_USE_CLOTH_API + ClothCore* const* clothList = mCloths.getEntries(); + for (PxU32 i = 0; i < mCloths.size(); ++i) + clothList[i]->getSim()->updateBounds(); +#endif + + const PxU32 numCpuTasks = continuation->getTaskManager()->getCpuDispatcher()->getWorkerCount(); + mAABBManager->updateAABBsAndBP(numCpuTasks, mLLContext->getTaskPool(), &mLLContext->getScratchAllocator(), mHasContactDistanceChanged, continuation, &mRigidBodyNPhaseUnlock); +} + +void Sc::Scene::postBroadPhase(PxBaseTask* continuation) +{ + PX_PROFILE_START_CROSSTHREAD("Basic.postBroadPhase", getContextId()); + mAABBManager->getChangedAABBMgActorHandleMap().clear(); + + // - Finishes broadphase update + // - Adds new interactions (and thereby contact managers if needed) + finishBroadPhase(0, continuation); +} + +void Sc::Scene::postBroadPhaseStage2(PxBaseTask* continuation) +{ + //Release unused Cms back to the pool (later, this needs to be done in a thread-safe way from multiple worker threads + mIslandInsertion.setContinuation(continuation); + mRegisterContactManagers.setContinuation(continuation); + mRegisterInteractions.setContinuation(continuation); + mRegisterSceneInteractions.setContinuation(continuation); + mIslandInsertion.removeReference(); + mRegisterContactManagers.removeReference(); + mRegisterInteractions.removeReference(); + mRegisterSceneInteractions.removeReference(); + + { + PX_PROFILE_ZONE("Sim.processNewOverlaps.release", getContextId()); + for (PxU32 a = 0; a < mPreallocatedContactManagers.size(); ++a) + { + if ((reinterpret_cast<size_t>(mPreallocatedContactManagers[a]) & 1) == 0) + mLLContext->getContactManagerPool().put(mPreallocatedContactManagers[a]); + } + + for (PxU32 a = 0; a < mPreallocatedShapeInteractions.size(); ++a) + { + if ((reinterpret_cast<size_t>(mPreallocatedShapeInteractions[a]) & 1) == 0) + mNPhaseCore->mShapeInteractionPool.deallocate(mPreallocatedShapeInteractions[a]); + } + + for (PxU32 a = 0; a < mPreallocatedInteractionMarkers.size(); ++a) + { + if ((reinterpret_cast<size_t>(mPreallocatedInteractionMarkers[a]) & 1) == 0) + mNPhaseCore->mInteractionMarkerPool.deallocate(mPreallocatedInteractionMarkers[a]); + } + } +} + +void Sc::Scene::postBroadPhaseStage3(PxBaseTask* /*continuation*/) +{ + finishBroadPhaseStage2(0); + + PX_PROFILE_STOP_CROSSTHREAD("Basic.postBroadPhase", getContextId()); + PX_PROFILE_STOP_CROSSTHREAD("Basic.broadPhase", getContextId()); +} + +class DirtyShapeUpdatesTask : public Cm::Task +{ +public: + static const PxU32 MaxShapes = 256; + + PxsTransformCache& mCache; + Bp::BoundsArray& mBoundsArray; + Sc::ShapeSim* mShapes[MaxShapes]; + PxU32 mNbShapes; + + DirtyShapeUpdatesTask(PxsTransformCache& cache, Bp::BoundsArray& boundsArray) : + mCache(cache), mBoundsArray(boundsArray), mNbShapes(0) + { + } + + virtual void runInternal() + { + for (PxU32 a = 0; a < mNbShapes; ++a) + { + mShapes[a]->updateCached(mCache, mBoundsArray); + } + } + + virtual const char* getName() const { return "DirtyShapeUpdatesTask"; } + + +private: + PX_NOCOPY(DirtyShapeUpdatesTask) +}; + +class SpeculativeCCDContactDistanceUpdateTask : public Cm::Task +{ +public: + static const PxU32 MaxBodies = 128; + PxReal* mContactDistances; + PxReal mDt; + Sc::BodySim* mBodySims[MaxBodies]; + PxU32 mNbBodies; + + Bp::BoundsArray& mBoundsArray; + + SpeculativeCCDContactDistanceUpdateTask(PxReal* contactDistances, const PxReal dt, Bp::BoundsArray& boundsArray) : + mContactDistances(contactDistances), mDt(dt), mNbBodies(0), mBoundsArray(boundsArray) + { + } + + virtual void runInternal() + { + for (PxU32 a = 0; a < mNbBodies; ++a) + { + mBodySims[a]->updateContactDistance(mContactDistances, mDt, mBoundsArray); + } + } + + virtual const char* getName() const { return "SpeculativeCCDContactDistanceUpdateTask"; } + +private: + PX_NOCOPY(SpeculativeCCDContactDistanceUpdateTask) +}; + +class SpeculativeCCDContactDistanceArticulationUpdateTask : public Cm::Task +{ +public: + PxReal* mContactDistances; + PxReal mDt; + Sc::ArticulationSim* mArticulation; + Bp::BoundsArray& mBoundsArray; + + SpeculativeCCDContactDistanceArticulationUpdateTask(PxReal* contactDistances, const PxReal dt, Bp::BoundsArray& boundsArray) : + mContactDistances(contactDistances), mDt(dt), mBoundsArray(boundsArray) + { + } + + virtual void runInternal() + { + mArticulation->updateContactDistance(mContactDistances, mDt, mBoundsArray); + } + + virtual const char* getName() const { return "SpeculativeCCDContactDistanceArticulationUpdateTask"; } + +private: + PX_NOCOPY(SpeculativeCCDContactDistanceArticulationUpdateTask) +}; + +void Sc::Scene::preRigidBodyNarrowPhase(PxBaseTask* continuation) +{ + PX_PROFILE_ZONE("Scene.preNarrowPhase", getContextId()); + + PxU32 index; + + Cm::FlushPool& pool = mLLContext->getTaskPool(); + + //calculate contact distance for speculative CCD shapes + Cm::BitMap::Iterator speculativeCCDIter(mSpeculativeCCDRigidBodyBitMap); + + SpeculativeCCDContactDistanceUpdateTask* ccdTask = PX_PLACEMENT_NEW(pool.allocate(sizeof(SpeculativeCCDContactDistanceUpdateTask)), SpeculativeCCDContactDistanceUpdateTask)(mContactDistance->begin(), mDt, *mBoundsArray); + + IG::IslandSim& islandSim = mSimpleIslandManager->getAccurateIslandSim(); + + const size_t bodyOffset = PX_OFFSET_OF_RT(Sc::BodySim, getLowLevelBody()); + + bool hasContactDistanceChanged = mHasContactDistanceChanged; + while ((index = speculativeCCDIter.getNext()) != Cm::BitMap::Iterator::DONE) + { + PxsRigidBody* rigidBody = islandSim.getRigidBody(IG::NodeIndex(index)); + Sc::BodySim* bodySim = reinterpret_cast<Sc::BodySim*>(reinterpret_cast<PxU8*>(rigidBody)-bodyOffset); + if (bodySim) + { + hasContactDistanceChanged = true; + ccdTask->mBodySims[ccdTask->mNbBodies++] = bodySim; + + if (ccdTask->mNbBodies == SpeculativeCCDContactDistanceUpdateTask::MaxBodies) + { + ccdTask->setContinuation(continuation); + ccdTask->removeReference(); + ccdTask = PX_PLACEMENT_NEW(pool.allocate(sizeof(SpeculativeCCDContactDistanceUpdateTask)), SpeculativeCCDContactDistanceUpdateTask)(mContactDistance->begin(), mDt, *mBoundsArray); + } + } + } + + if (ccdTask->mNbBodies != 0) + { + ccdTask->setContinuation(continuation); + ccdTask->removeReference(); + } + + //calculate contact distance for articulation links + SpeculativeCCDContactDistanceArticulationUpdateTask* articulationUpdateTask = NULL; + + Cm::BitMap::Iterator articulateCCDIter(mSpeculativeCDDArticulationBitMap); + while ((index = articulateCCDIter.getNext()) != Cm::BitMap::Iterator::DONE) + { + Sc::ArticulationSim* articulationSim = islandSim.getLLArticulation(IG::NodeIndex(index))->getArticulationSim(); + if (articulationSim) + { + hasContactDistanceChanged = true; + articulationUpdateTask = PX_PLACEMENT_NEW(pool.allocate(sizeof(SpeculativeCCDContactDistanceArticulationUpdateTask)), SpeculativeCCDContactDistanceArticulationUpdateTask)(mContactDistance->begin(), mDt, *mBoundsArray); + articulationUpdateTask->mArticulation = articulationSim; + articulationUpdateTask->setContinuation(continuation); + articulationUpdateTask->removeReference(); + } + } + + mHasContactDistanceChanged = hasContactDistanceChanged; + + //Process dirty shapeSims... + Cm::BitMap::Iterator dirtyShapeIter(mDirtyShapeSimMap); + + Cm::BitMapPinned& changedMap = mAABBManager->getChangedAABBMgActorHandleMap(); + + PxsTransformCache& cache = mLLContext->getTransformCache(); + Bp::BoundsArray& boundsArray = mAABBManager->getBoundsArray(); + + DirtyShapeUpdatesTask* task = PX_PLACEMENT_NEW(pool.allocate(sizeof(DirtyShapeUpdatesTask)), DirtyShapeUpdatesTask)(cache, boundsArray); + + while ((index = dirtyShapeIter.getNext()) != Cm::BitMap::Iterator::DONE) + { + Sc::ShapeSim* shapeSim = reinterpret_cast<Sc::ShapeSim*>(mAABBManager->getUserData(index)); + if (shapeSim) + { + changedMap.growAndSet(index); + task->mShapes[task->mNbShapes++] = shapeSim; + if (task->mNbShapes == DirtyShapeUpdatesTask::MaxShapes) + { + task->setContinuation(continuation); + task->removeReference(); + task = PX_PLACEMENT_NEW(pool.allocate(sizeof(DirtyShapeUpdatesTask)), DirtyShapeUpdatesTask)(cache, boundsArray); + } + } + } + + if (task->mNbShapes != 0) + { + task->setContinuation(continuation); + task->removeReference(); + } + + mDirtyShapeSimMap.clear(); +} + +void Sc::Scene::rigidBodyNarrowPhase(PxBaseTask* continuation) +{ + PX_PROFILE_START_CROSSTHREAD("Basic.narrowPhase", getContextId()); + + mCCDPass = 0; + + mPostBroadPhase3.addDependent(*continuation); + mPostBroadPhase2.setContinuation(&mPostBroadPhase3); + mPostBroadPhase.setContinuation(&mPostBroadPhase2); + mRigidBodyNPhaseUnlock.setContinuation(continuation); + mRigidBodyNPhaseUnlock.addReference(); //Must be decremented by both BP and NP before it runs + mBroadPhase.setContinuation(&mPostBroadPhase); + + mLLContext->resetThreadContexts(); + + mLLContext->updateContactManager(mDt, mBoundsArray->hasChanged(), mHasContactDistanceChanged, continuation, &mRigidBodyNPhaseUnlock); // Starts update of contact managers + + if (hasParticleSystems()) + { + PxBaseTask& particleGpuTask = scheduleParticleGpu(mFinalizationPhase); + PxBaseTask& particleCollisionCpuTask = scheduleParticleCollisionCpu(mPostNarrowPhase); + PxBaseTask& particleCollisionPrepTask = scheduleParticleCollisionPrep(particleCollisionCpuTask, particleGpuTask); + PxBaseTask& particleDynamicsCpuTask = scheduleParticleDynamicsCpu(particleCollisionCpuTask); + PxBaseTask& particleShapeGenTask = scheduleParticleShapeGeneration(mBroadPhase, particleDynamicsCpuTask); + + mPostBroadPhase3.addDependent(particleCollisionPrepTask); + mPostBroadPhase3.removeReference(); + + particleGpuTask.removeReference(); + particleCollisionCpuTask.removeReference(); + particleCollisionPrepTask.removeReference(); + particleDynamicsCpuTask.removeReference(); + particleShapeGenTask.removeReference(); + } + +#if PX_SUPPORT_GPU_PHYSX + //workaround to prevent premature launching of gpu launch task (needs to happen after gpu particles and gpu cloth have been scheduled) + PxGpuDispatcher* gpuDispatcher = getTaskManager().getGpuDispatcher(); + if (gpuDispatcher) + { + gpuDispatcher->getPreLaunchTask().removeReference(); + } +#endif + + mPostBroadPhase3.removeReference(); + mPostBroadPhase2.removeReference(); + mPostBroadPhase.removeReference(); + mBroadPhase.removeReference(); +} + +void Sc::Scene::unblockNarrowPhase(PxBaseTask*) +{ + this->mLLContext->getNphaseImplementationContext()->startNarrowPhaseTasks(); +} + +void Sc::Scene::postNarrowPhase(PxBaseTask* /*continuation*/) +{ + mHasContactDistanceChanged = false; + mLLContext->fetchUpdateContactManager(); //Sync on contact gen results! + + +#if PX_USE_PARTICLE_SYSTEM_API + if(hasParticleSystems()) + { + mParticleContext->getBodyTransformVaultFast().update(); + } +#endif + + releaseConstraints(false); + + PX_PROFILE_STOP_CROSSTHREAD("Basic.narrowPhase", getContextId()); + PX_PROFILE_STOP_CROSSTHREAD("Basic.collision", getContextId()); +} + +void Sc::Scene::particlePostShapeGen(PxBaseTask* /*continuation*/) +{ +#if PX_USE_PARTICLE_SYSTEM_API + for (PxU32 i = 0; i < mEnabledParticleSystems.size(); ++i) + mEnabledParticleSystems[i]->processShapesUpdate(); +#endif +} + +void Sc::Scene::fetchPatchEvents(PxBaseTask*) +{ + PxU32 foundPatchCount, lostPatchCount; + + { + PX_PROFILE_ZONE("Sim.preIslandGen.managerPatchEvents", getContextId()); + mLLContext->getManagerPatchEventCount(foundPatchCount, lostPatchCount); + + mFoundPatchManagers.forceSize_Unsafe(0); + mFoundPatchManagers.resizeUninitialized(foundPatchCount); + + mLostPatchManagers.forceSize_Unsafe(0); + mLostPatchManagers.resizeUninitialized(lostPatchCount); + + mLLContext->fillManagerPatchChangedEvents(mFoundPatchManagers.begin(), foundPatchCount, mLostPatchManagers.begin(), lostPatchCount); + + mFoundPatchManagers.forceSize_Unsafe(foundPatchCount); + mLostPatchManagers.forceSize_Unsafe(lostPatchCount); + } +} + +void Sc::Scene::processNarrowPhaseTouchEvents() +{ + PxsContext* context = mLLContext; + + { + PX_PROFILE_ZONE("Sim.preIslandGen", getContextId()); + + // Update touch states from LL + PxU32 newTouchCount, lostTouchCount; + PxU32 ccdTouchCount = 0; + { + PX_PROFILE_ZONE("Sim.preIslandGen.managerTouchEvents", getContextId()); + context->getManagerTouchEventCount(reinterpret_cast<PxI32*>(&newTouchCount), reinterpret_cast<PxI32*>(&lostTouchCount), NULL); + //PX_ALLOCA(newTouches, PxvContactManagerTouchEvent, newTouchCount); + //PX_ALLOCA(lostTouches, PxvContactManagerTouchEvent, lostTouchCount); + + mTouchFoundEvents.forceSize_Unsafe(0); + mTouchFoundEvents.reserve(newTouchCount); + mTouchFoundEvents.forceSize_Unsafe(newTouchCount); + + mTouchLostEvents.forceSize_Unsafe(0); + mTouchLostEvents.reserve(lostTouchCount); + mTouchLostEvents.forceSize_Unsafe(lostTouchCount); + + { + context->fillManagerTouchEvents(mTouchFoundEvents.begin(), reinterpret_cast<PxI32&>(newTouchCount), mTouchLostEvents.begin(), + reinterpret_cast<PxI32&>(lostTouchCount), NULL, reinterpret_cast<PxI32&>(ccdTouchCount)); + + mTouchFoundEvents.forceSize_Unsafe(newTouchCount); + mTouchLostEvents.forceSize_Unsafe(lostTouchCount); + } + } + + + getLowLevelContext()->getSimStats().mNbNewTouches = newTouchCount; + getLowLevelContext()->getSimStats().mNbLostTouches = lostTouchCount; + } +} + +class InteractionNewTouchTask : public Cm::Task +{ + PxvContactManagerTouchEvent* mEvents; + const PxU32 mNbEvents; + PxsContactManagerOutputIterator mOutputs; + const bool mUseAdaptiveForce; + +public: + InteractionNewTouchTask(PxvContactManagerTouchEvent* events, PxU32 nbEvents, PxsContactManagerOutputIterator& outputs, bool useAdaptiveForce) : mEvents(events), mNbEvents(nbEvents), mOutputs(outputs), + mUseAdaptiveForce(useAdaptiveForce) + { + } + + virtual const char* getName() const + { + return "InteractionNewTouchTask"; + } + + void hackInContinuation(PxBaseTask* cont) + { + PX_ASSERT(mCont == NULL); + mCont = cont; + if (mCont) + mCont->addReference(); + } + + virtual void runInternal() + { + for (PxU32 i = 0; i < mNbEvents; ++i) + { + Sc::ShapeInteraction* si = reinterpret_cast<Sc::ShapeInteraction*>(mEvents[i].userData); + PX_ASSERT(si); + si->managerNewTouch(0, true, mOutputs, mUseAdaptiveForce); + } + } +private: + PX_NOCOPY(InteractionNewTouchTask) +}; + +void Sc::Scene::processNarrowPhaseTouchEventsStage2(PxBaseTask* continuation) +{ + PxsContactManagerOutputIterator outputs = mLLContext->getNphaseImplementationContext()->getContactManagerOutputs(); + + bool useAdaptiveForce = mPublicFlags & PxSceneFlag::eADAPTIVE_FORCE; + + //Cm::FlushPool& flushPool = mLLContext->getTaskPool(); + + PxU32 newTouchCount = mTouchFoundEvents.size(); + + { + const PxU32 nbPerTask = 256; + PX_PROFILE_ZONE("Sim.preIslandGen.newTouches", getContextId()); + + InteractionNewTouchTask* prevTask = NULL; + + //for (PxU32 i = 0; i < newTouchCount; ++i) + for (PxU32 i = 0; i < newTouchCount; i+= nbPerTask) + { + const PxU32 nbToProcess = PxMin(newTouchCount - i, nbPerTask); + + for (PxU32 a = 0; a < nbToProcess; ++a) + { + ShapeInteraction* si = reinterpret_cast<ShapeInteraction*>(mTouchFoundEvents[i + a].userData); + PX_ASSERT(si); + mNPhaseCore->managerNewTouch(*si, 0, true, outputs); + si->managerNewTouch(0, true, outputs, useAdaptiveForce); + } + + //InteractionNewTouchTask* task = PX_PLACEMENT_NEW(flushPool.allocate(sizeof(InteractionNewTouchTask)), InteractionNewTouchTask)(mTouchFoundEvents.begin() + i, nbToProcess, outputs); + ////task->setContinuation(continuation); + //task->setContinuation(*continuation->getTaskManager(), NULL); + //if (prevTask) + //{ + // prevTask->hackInContinuation(task); + // prevTask->removeReference(); + //} + + //prevTask = task; + + //task->removeReference(); + } + + if (prevTask) + { + prevTask->hackInContinuation(continuation); + prevTask->removeReference(); + } + } + + /*{ + PX_PROFILE_ZONE("Sim.preIslandGen.newTouchesInteraction", getContextId()); + for (PxU32 i = 0; i < newTouchCount; ++i) + { + ShapeInteraction* si = reinterpret_cast<ShapeInteraction*>(mTouchFoundEvents[i].userData); + PX_ASSERT(si); + si->managerNewTouch(0, true, outputs); + } + }*/ + +} + +void Sc::Scene::setEdgesConnected(PxBaseTask*) +{ + { + PxU32 newTouchCount = mTouchFoundEvents.size(); + PX_PROFILE_ZONE("Sim.preIslandGen.islandTouches", getContextId()); + { + PX_PROFILE_ZONE("Sim.preIslandGen.setEdgesConnected", getContextId()); + for (PxU32 i = 0; i < newTouchCount; ++i) + { + ShapeInteraction* si = reinterpret_cast<ShapeInteraction*>(mTouchFoundEvents[i].userData); + if (!si->readFlag(ShapeInteraction::CONTACTS_RESPONSE_DISABLED)) + { + mSimpleIslandManager->setEdgeConnected(si->getEdgeIndex()); + } + } + } + + mSimpleIslandManager->secondPassIslandGen(); + + wakeObjectsUp(ActorSim::AS_PART_OF_ISLAND_GEN); + } +} + +void Sc::Scene::processNarrowPhaseLostTouchEventsIslands(PxBaseTask*) +{ + { + PX_PROFILE_ZONE("Sc::Scene.islandLostTouches", getContextId()); + for (PxU32 i = 0; i < mTouchLostEvents.size(); ++i) + { + ShapeInteraction* si = reinterpret_cast<ShapeInteraction*>(mTouchLostEvents[i].userData); + mSimpleIslandManager->setEdgeDisconnected(si->getEdgeIndex()); + } + } +} + +void Sc::Scene::processNarrowPhaseLostTouchEvents(PxBaseTask*) +{ + { + PX_PROFILE_ZONE("Sc::Scene.processNarrowPhaseLostTouchEvents", getContextId()); + PxsContactManagerOutputIterator outputs = this->mLLContext->getNphaseImplementationContext()->getContactManagerOutputs(); + bool useAdaptiveForce = mPublicFlags & PxSceneFlag::eADAPTIVE_FORCE; + for (PxU32 i = 0; i < mTouchLostEvents.size(); ++i) + { + ShapeInteraction* si = reinterpret_cast<ShapeInteraction*>(mTouchLostEvents[i].userData); + PX_ASSERT(si); + if (si->managerLostTouch(0, true, outputs, useAdaptiveForce) && !si->readFlag(ShapeInteraction::CONTACTS_RESPONSE_DISABLED)) + addToLostTouchList(si->getShape0().getBodySim(), si->getShape1().getBodySim()); + } + } + + +} + +void Sc::Scene::processLostSolverPatches(PxBaseTask* /*continuation*/) +{ + PxsContactManagerOutputIterator outputs = mLLContext->getNphaseImplementationContext()->getContactManagerOutputs(); + mDynamicsContext->processLostPatches(*mSimpleIslandManager, mLostPatchManagers.begin(), mLostPatchManagers.size(), outputs); +} + + +void Sc::Scene::islandGen(PxBaseTask* continuation) +{ + PX_PROFILE_START_CROSSTHREAD("Basic.rigidBodySolver", getContextId()); + + //mLLContext->runModifiableContactManagers(); //KS - moved here so that we can get up-to-date touch found/lost events in IG + + mProcessLostPatchesTask.setContinuation(&mUpdateDynamics); + mFetchPatchEventsTask.setContinuation(&mProcessLostPatchesTask); + mProcessLostPatchesTask.removeReference(); + mFetchPatchEventsTask.removeReference(); + processNarrowPhaseTouchEvents(); + + mSetEdgesConnectedTask.setContinuation(continuation); + mSetEdgesConnectedTask.removeReference(); + + processNarrowPhaseTouchEventsStage2(continuation); +} + +PX_FORCE_INLINE void Sc::Scene::putObjectsToSleep(PxU32 infoFlag) +{ + + const IG::IslandSim& islandSim = mSimpleIslandManager->getAccurateIslandSim(); + + //Set to sleep all bodies that were in awake islands that have just been put to sleep. + const PxU32 nbBodiesToSleep = islandSim.getNbNodesToDeactivate(IG::Node::eRIGID_BODY_TYPE); + const IG::NodeIndex*const bodyIndices = islandSim.getNodesToDeactivate(IG::Node::eRIGID_BODY_TYPE); + + for(PxU32 i=0;i<nbBodiesToSleep;i++) + { + PxsRigidBody* rigidBody = islandSim.getRigidBody(bodyIndices[i]); + if (rigidBody && !islandSim.getNode(bodyIndices[i]).isActive()) + { + Sc::BodySim* bodySim = reinterpret_cast<BodySim*>(reinterpret_cast<PxU8*>(rigidBody) - Sc::BodySim::getRigidBodyOffset()); + bodySim->setActive(false, infoFlag); + } + } + + const PxU32 nbArticulationsToSleep = islandSim.getNbNodesToDeactivate(IG::Node::eARTICULATION_TYPE); + const IG::NodeIndex*const articIndices = islandSim.getNodesToDeactivate(IG::Node::eARTICULATION_TYPE); + + for(PxU32 i=0;i<nbArticulationsToSleep;i++) + { + Sc::ArticulationSim* articSim = islandSim.getLLArticulation(articIndices[i])->getArticulationSim(); + if (articSim && !islandSim.getNode(articIndices[i]).isActive()) + articSim->setActive(false, infoFlag); + } + + + +} + +PX_FORCE_INLINE void Sc::Scene::putInteractionsToSleep(PxU32 infoFlag) +{ + const IG::IslandSim& islandSim = mSimpleIslandManager->getSpeculativeIslandSim(); + + for (PxU32 a = 0; a < IG::Edge::eEDGE_TYPE_COUNT; ++a) + { + PxU32 nbDeactivatingEdges = islandSim.getNbDeactivatingEdges(IG::Edge::EdgeType(a)); + const IG::EdgeIndex* deactivatingEdgeIds = islandSim.getDeactivatingEdges(IG::Edge::EdgeType(a)); + + for (PxU32 i = 0; i < nbDeactivatingEdges; ++i) + { + Sc::Interaction* interaction = mSimpleIslandManager->getInteraction(deactivatingEdgeIds[i]); + + if (interaction && interaction->readInteractionFlag(InteractionFlag::eIS_ACTIVE)) + { + if (!islandSim.getEdge(deactivatingEdgeIds[i]).isActive()) + { + const bool proceed = interaction->onDeactivate(infoFlag); + if (proceed && (interaction->getType() < InteractionType::eTRACKED_IN_SCENE_COUNT)) + notifyInteractionDeactivated(interaction); + } + } + } + } +} + +PX_FORCE_INLINE void Sc::Scene::wakeObjectsUp(PxU32 infoFlag) +{ + //Wake up all bodies that were in sleeping islands that have just been hit by a moving object. + + const IG::IslandSim& islandSim = mSimpleIslandManager->getAccurateIslandSim(); + + const PxU32 nbBodiesToWake = islandSim.getNbNodesToActivate(IG::Node::eRIGID_BODY_TYPE); + const IG::NodeIndex*const bodyIndices = islandSim.getNodesToActivate(IG::Node::eRIGID_BODY_TYPE); + + for(PxU32 i=0;i<nbBodiesToWake;i++) + { + PxsRigidBody* rigidBody = islandSim.getRigidBody(bodyIndices[i]); + if (rigidBody && islandSim.getNode(bodyIndices[i]).isActive()) + { + Sc::BodySim* bodySim = reinterpret_cast<Sc::BodySim*>(reinterpret_cast<PxU8*>(rigidBody) - Sc::BodySim::getRigidBodyOffset()); + bodySim->setActive(true, infoFlag); + } + } + + const PxU32 nbArticulationsToWake = islandSim.getNbNodesToActivate(IG::Node::eARTICULATION_TYPE); + const IG::NodeIndex*const articIndices = islandSim.getNodesToActivate(IG::Node::eARTICULATION_TYPE); + + for(PxU32 i=0;i<nbArticulationsToWake;i++) + { + Sc::ArticulationSim* articSim = islandSim.getLLArticulation(articIndices[i])->getArticulationSim(); + if (articSim && islandSim.getNode(articIndices[i]).isActive()) + articSim->setActive(true, infoFlag); + } +} + +PX_FORCE_INLINE void Sc::Scene::wakeInteractions(PxU32 /*infoFlag*/) +{ + const IG::IslandSim& speculativeSim = mSimpleIslandManager->getSpeculativeIslandSim(); + + for (PxU32 a = 0; a < IG::Edge::eEDGE_TYPE_COUNT; ++a) + { + PxU32 nbActivatingEdges = speculativeSim.getNbActivatedEdges(IG::Edge::EdgeType(a)); + const IG::EdgeIndex* activatingEdges = speculativeSim.getActivatedEdges(IG::Edge::EdgeType(a)); + + for (PxU32 i = 0; i < nbActivatingEdges; ++i) + { + Sc::Interaction* interaction = mSimpleIslandManager->getInteraction(activatingEdges[i]); + + if (interaction && !interaction->readInteractionFlag(InteractionFlag::eIS_ACTIVE)) + { + if (speculativeSim.getEdge(activatingEdges[i]).isActive()) + { + const bool proceed = interaction->onActivate(NULL); + if (proceed && (interaction->getType() < InteractionType::eTRACKED_IN_SCENE_COUNT)) + notifyInteractionActivated(interaction); + } + } + } + } +} + +void Sc::Scene::postIslandGen(PxBaseTask* continuationTask) +{ + { + PX_PROFILE_ZONE("Sim.postIslandGen", getContextId()); + + // - Performs collision detection for trigger interactions + { + mNPhaseCore->processTriggerInteractions(continuationTask); + } + } +} + +void Sc::Scene::solver(PxBaseTask* continuation) +{ + PX_PROFILE_STOP_CROSSTHREAD("Basic.narrowPhase", getContextId()); + PX_PROFILE_START_CROSSTHREAD("Basic.rigidBodySolver", getContextId()); + //Update forces per body in parallel. This can overlap with the other work in this phase. + beforeSolver(continuation); + + PX_PROFILE_ZONE("Sim.postNarrowPhaseSecondPass", getContextId()); + //Narrowphase is completely finished so the streams can be swapped. + mLLContext->swapStreams(); +} + +void Sc::Scene::updateBodiesAndShapes(PxBaseTask* continuation) +{ + PX_UNUSED(continuation); + //dma bodies and shapes data to gpu + mSimulationController->updateBodiesAndShapes(continuation, !physx::gUnifiedHeightfieldCollision); +} + +Cm::FlushPool* Sc::Scene::getFlushPool() +{ + return &mLLContext->getTaskPool(); +} + +void Sc::Scene::postThirdPassIslandGen(PxBaseTask* /*continuation*/) +{ + putObjectsToSleep(ActorSim::AS_PART_OF_ISLAND_GEN); + putInteractionsToSleep(ActorSim::AS_PART_OF_ISLAND_GEN); + + PxsContactManagerOutputIterator outputs = this->mLLContext->getNphaseImplementationContext()->getContactManagerOutputs(); + mNPhaseCore->processPersistentContactEvents(outputs); +} + +void Sc::Scene::processLostContacts(PxBaseTask* continuation) +{ + mProcessNarrowPhaseLostTouchTasks.setContinuation(continuation); + mProcessNarrowPhaseLostTouchTasks.removeReference(); + + //mLostTouchReportsTask.setContinuation(&mProcessLostContactsTask3); + mProcessNPLostTouchEvents.setContinuation(continuation); + mProcessNPLostTouchEvents.removeReference(); + + { + PX_PROFILE_ZONE("Sim.findInteractionsPtrs", getContextId()); + + Bp::SimpleAABBManager* aabbMgr = mAABBManager; + PxU32 destroyedOverlapCount; + Bp::AABBOverlap* PX_RESTRICT p = aabbMgr->getDestroyedOverlaps(Bp::VolumeBuckets::eSHAPE, destroyedOverlapCount); + while (destroyedOverlapCount--) + { + ElementSim* volume0 = reinterpret_cast<ElementSim*>(p->mUserData0); + ElementSim* volume1 = reinterpret_cast<ElementSim*>(p->mUserData1); + Sc::ElementSimInteraction* interaction = mNPhaseCore->onOverlapRemovedStage1(volume0, volume1); + p->mUserData = interaction; + p++; + } + } +} + +void Sc::Scene::lostTouchReports(PxBaseTask*) +{ + { + PX_PROFILE_ZONE("Sim.lostTouchReports", getContextId()); + PxsContactManagerOutputIterator outputs = mLLContext->getNphaseImplementationContext()->getContactManagerOutputs(); + + bool useAdaptiveForce = mPublicFlags & PxSceneFlag::eADAPTIVE_FORCE; + + Bp::SimpleAABBManager* aabbMgr = mAABBManager; + PxU32 destroyedOverlapCount; + + { + const Bp::AABBOverlap* PX_RESTRICT p = aabbMgr->getDestroyedOverlaps(Bp::VolumeBuckets::eSHAPE, destroyedOverlapCount); + while (destroyedOverlapCount--) + { + if (p->mUserData) + { + Sc::ElementSimInteraction* elemInteraction = reinterpret_cast<Sc::ElementSimInteraction*>(p->mUserData); + if (elemInteraction->getType() == Sc::InteractionType::eOVERLAP) + mNPhaseCore->lostTouchReports(static_cast<Sc::ShapeInteraction*>(elemInteraction), PxU32(PairReleaseFlag::eWAKE_ON_LOST_TOUCH), 0, outputs, useAdaptiveForce); + } + p++; + } + } + } +} + +void Sc::Scene::unregisterInteractions(PxBaseTask*) +{ + { + PX_PROFILE_ZONE("Sim.unregisterInteractions", getContextId()); + + Bp::SimpleAABBManager* aabbMgr = mAABBManager; + PxU32 destroyedOverlapCount; + + { + const Bp::AABBOverlap* PX_RESTRICT p = aabbMgr->getDestroyedOverlaps(Bp::VolumeBuckets::eSHAPE, destroyedOverlapCount); + while (destroyedOverlapCount--) + { + if (p->mUserData) + { + Sc::ElementSimInteraction* elemInteraction = reinterpret_cast<Sc::ElementSimInteraction*>(p->mUserData); + if (elemInteraction->getType() == Sc::InteractionType::eOVERLAP || elemInteraction->getType() == Sc::InteractionType::eMARKER) + { + unregisterInteraction(elemInteraction); + mNPhaseCore->unregisterInteraction(elemInteraction); + } + } + p++; + } + } + } +} + +void Sc::Scene::destroyManagers(PxBaseTask*) +{ + { + + PX_PROFILE_ZONE("Sim.destroyManagers", getContextId()); + + mPostThirdPassIslandGenTask.setContinuation(mProcessLostContactsTask3.getContinuation()); + + mSimpleIslandManager->thirdPassIslandGen(&mPostThirdPassIslandGenTask); + + Bp::SimpleAABBManager* aabbMgr = mAABBManager; + PxU32 destroyedOverlapCount; + const Bp::AABBOverlap* PX_RESTRICT p = aabbMgr->getDestroyedOverlaps(Bp::VolumeBuckets::eSHAPE, destroyedOverlapCount); + while (destroyedOverlapCount--) + { + if (p->mUserData) + { + Sc::ElementSimInteraction* elemInteraction = reinterpret_cast<Sc::ElementSimInteraction*>(p->mUserData); + if (elemInteraction->getType() == Sc::InteractionType::eOVERLAP) + { + Sc::ShapeInteraction* si = static_cast<Sc::ShapeInteraction*>(elemInteraction); + if (si->getContactManager()) + si->destroyManager(); + } + } + p++; + } + } +} + +void Sc::Scene::processLostContacts2(PxBaseTask* continuation) +{ + mDestroyManagersTask.setContinuation(continuation); + mLostTouchReportsTask.setContinuation(&mDestroyManagersTask); + mLostTouchReportsTask.removeReference(); + + + mUnregisterInteractionsTask.setContinuation(continuation); + mUnregisterInteractionsTask.removeReference(); + + + + { + PX_PROFILE_ZONE("Sim.clearIslandData", getContextId()); + // PxsContactManagerOutputIterator outputs = mLLContext->getNphaseImplementationContext()->getContactManagerOutputs(); + + Bp::SimpleAABBManager* aabbMgr = mAABBManager; + PxU32 destroyedOverlapCount; + { + Bp::AABBOverlap* PX_RESTRICT p = aabbMgr->getDestroyedOverlaps(Bp::VolumeBuckets::eSHAPE, destroyedOverlapCount); + while (destroyedOverlapCount--) + { + Sc::ElementSimInteraction* pair = reinterpret_cast<Sc::ElementSimInteraction*>(p->mUserData); + if (pair) + { + if (pair->getType() == InteractionType::eOVERLAP) + { + ShapeInteraction* si = static_cast<ShapeInteraction*>(pair); + si->clearIslandGenData(); + } + } + p++; + } + } + } + + mDestroyManagersTask.removeReference(); +} + +void Sc::Scene::processLostContacts3(PxBaseTask* /*continuation*/) +{ + { + PX_PROFILE_ZONE("Sim.processLostOverlapsStage2", getContextId()); + + bool useAdaptiveForce = mPublicFlags & PxSceneFlag::eADAPTIVE_FORCE; + PxsContactManagerOutputIterator outputs = mLLContext->getNphaseImplementationContext()->getContactManagerOutputs(); + + Bp::SimpleAABBManager* aabbMgr = mAABBManager; + PxU32 destroyedOverlapCount; + + { + const Bp::AABBOverlap* PX_RESTRICT p = aabbMgr->getDestroyedOverlaps(Bp::VolumeBuckets::eSHAPE, destroyedOverlapCount); + while (destroyedOverlapCount--) + { + ElementSim* volume0 = reinterpret_cast<ElementSim*>(p->mUserData0); + ElementSim* volume1 = reinterpret_cast<ElementSim*>(p->mUserData1); + + mNPhaseCore->onOverlapRemoved(volume0, volume1, false, p->mUserData, outputs, useAdaptiveForce); + p++; + } + } + for (PxU32 i = Bp::VolumeBuckets::ePARTICLE; i < Bp::VolumeBuckets::eCOUNT; ++i) + { + const Bp::AABBOverlap* PX_RESTRICT p = aabbMgr->getDestroyedOverlaps(i, destroyedOverlapCount); + while (destroyedOverlapCount--) + { + ElementSim* volume0 = reinterpret_cast<ElementSim*>(p->mUserData0); + ElementSim* volume1 = reinterpret_cast<ElementSim*>(p->mUserData1); + + mNPhaseCore->onOverlapRemoved(volume0, volume1, false, NULL, outputs, useAdaptiveForce); + p++; + } + } + + aabbMgr->getBroadPhase()->deletePairs(); + aabbMgr->freeBuffers(); + } + + mPostThirdPassIslandGenTask.removeReference(); +} + + + +//This is called after solver finish +void Sc::Scene::updateSimulationController(PxBaseTask* continuation) +{ + PX_PROFILE_ZONE("Sim.updateSimulationController", getContextId()); + //for pxgdynamicscontext: copy solver body data to body core + mDynamicsContext->updateBodyCore(continuation); + + PxsTransformCache& cache = getLowLevelContext()->getTransformCache(); + Bp::BoundsArray& boundArray = getBoundsArray(); + + Cm::BitMapPinned& changedAABBMgrActorHandles = mAABBManager->getChangedAABBMgActorHandleMap(); + //changedAABBMgrActorHandles.resizeAndClear(getElementIDPool().getMaxID()); + + mSimulationController->gpuDmabackData(cache, boundArray, changedAABBMgrActorHandles); + //mSimulationController->update(cache, boundArray, changedAABBMgrActorHandles); +} + +void Sc::Scene::updateDynamics(PxBaseTask* continuation) + +{ + mProcessLostContactsTask3.setContinuation(continuation); + mProcessLostContactsTask2.setContinuation(&mProcessLostContactsTask3); + mProcessLostContactsTask.setContinuation(&mProcessLostContactsTask2); + + ////dma bodies and shapes data to gpu + //mSimulationController->updateBodiesAndShapes(); + + mLLContext->getNpMemBlockPool().acquireConstraintMemory(); + + PX_PROFILE_START_CROSSTHREAD("Basic.dynamics", getContextId()); + PxU32 maxPatchCount = mLLContext->getMaxPatchCount(); + + PxsContactManagerOutputIterator outputs = mLLContext->getNphaseImplementationContext()->getContactManagerOutputs(); + + PxsContactManagerOutput* cmOutputBase = mLLContext->getNphaseImplementationContext()->getGPUContactManagerOutputBase(); + + Cm::BitMapPinned& changedAABBMgrActorHandles = mAABBManager->getChangedAABBMgActorHandleMap(); + changedAABBMgrActorHandles.resizeAndClear(getElementIDPool().getMaxID()); + + mDynamicsContext->update(*mSimpleIslandManager, continuation, &mProcessLostContactsTask, + mFoundPatchManagers.begin(), mFoundPatchManagers.size(), mLostPatchManagers.begin(), mLostPatchManagers.size(), + maxPatchCount, outputs, cmOutputBase, mDt, mGravity, changedAABBMgrActorHandles.getWordCount()); + + mSimpleIslandManager->clearDestroyedEdges(); + + mProcessLostContactsTask3.removeReference(); + mProcessLostContactsTask2.removeReference(); + mProcessLostContactsTask.removeReference(); + +} + + +void Sc::Scene::updateCCDMultiPass(PxBaseTask* parentContinuation) +{ + getCcdBodies().forceSize_Unsafe(mSimulationControllerCallback->getNbCcdBodies()); + + // second run of the broadphase for making sure objects we have integrated did not tunnel. + if(mPublicFlags & PxSceneFlag::eENABLE_CCD) + { + if (mContactReportsNeedPostSolverVelocity) + { + // the CCD code will overwrite the post solver body velocities, hence, we need to extract the info + // first if any CCD enabled pair requested it. + collectPostSolverVelocitiesBeforeCCD(); + } + + //We use 2 CCD task chains to be able to chain together an arbitrary number of ccd passes + if(mPostCCDPass.size() != 2) + { + mPostCCDPass.clear(); + mUpdateCCDSinglePass.clear(); + mCCDBroadPhase.clear(); + mCCDBroadPhaseAABB.clear(); + mPostCCDPass.reserve(2); + mUpdateCCDSinglePass.reserve(2); + mUpdateCCDSinglePass2.reserve(2); + mUpdateCCDSinglePass3.reserve(2); + mCCDBroadPhase.reserve(2); + mCCDBroadPhaseAABB.reserve(2); + for (int j = 0; j < 2; j++) + { + mPostCCDPass.pushBack( + Cm::DelegateTask<Sc::Scene, &Sc::Scene::postCCDPass>( + this, "ScScene.postCCDPass")); + mUpdateCCDSinglePass.pushBack( + Cm::DelegateTask<Sc::Scene, &Sc::Scene::updateCCDSinglePass>( + this, "ScScene.updateCCDSinglePass")); + mUpdateCCDSinglePass2.pushBack( + Cm::DelegateTask<Sc::Scene, &Sc::Scene::updateCCDSinglePassStage2>( + this, "ScScene.updateCCDSinglePassStage2")); + mUpdateCCDSinglePass3.pushBack(Cm::DelegateTask<Sc::Scene, &Sc::Scene::updateCCDSinglePassStage3>( + this, "ScScene.updateCCDSinglePassStage3")); + mCCDBroadPhase.pushBack( + Cm::DelegateTask<Sc::Scene, &Sc::Scene::ccdBroadPhase>( + this, "ScScene.ccdBroadPhase")); + mCCDBroadPhaseAABB.pushBack(Cm::DelegateTask<Sc::Scene, &Sc::Scene::ccdBroadPhaseAABB>( + this, "ScScene.ccdBroadPhaseAABB")); + } + } + + + //reset thread context in a place we know all tasks possibly accessing it, are in sync with. (see US6664) + mLLContext->resetThreadContexts(); + + mCCDContext->updateCCDBegin(); + + + mCCDBroadPhase[0].setContinuation(parentContinuation); + mCCDBroadPhaseAABB[0].setContinuation(&mCCDBroadPhase[0]); + mCCDBroadPhase[0].removeReference(); + mCCDBroadPhaseAABB[0].removeReference(); + + } +} + +class UpdateCCDBoundsTask : public Cm::Task +{ + + Sc::BodySim** mBodySims; + PxU32 mNbToProcess; + PxI32* mNumFastMovingShapes; + +public: + + static const PxU32 MaxPerTask = 256; + + UpdateCCDBoundsTask(Sc::BodySim** bodySims, PxU32 nbToProcess, PxI32* numFastMovingShapes) : mBodySims(bodySims), + mNbToProcess(nbToProcess), mNumFastMovingShapes(numFastMovingShapes) + { + } + + virtual const char* getName() const { return "UpdateCCDBoundsTask";} + + virtual void runInternal() + { + PxU32 activeShapes = 0; + for (PxU32 i = 0; i < mNbToProcess; i++) + { + Sc::ShapeSim* sim; + + PxU32 isFastMoving = 0; + Sc::BodySim& bodySim = *mBodySims[i]; + for (Sc::ShapeIterator iterator(bodySim); (sim = iterator.getNext()) != NULL;) + { + if (sim->getFlags()&PxU32(PxShapeFlag::eSIMULATION_SHAPE | PxShapeFlag::eTRIGGER_SHAPE)) + { + Ps::IntBool fastMovingShape = sim->updateSweptBounds(); + activeShapes += fastMovingShape; + + isFastMoving = isFastMoving | fastMovingShape; + } + } + + bodySim.getLowLevelBody().getCore().isFastMoving = PxU16(isFastMoving); + } + + Ps::atomicAdd(mNumFastMovingShapes, PxI32(activeShapes)); + } + +}; + +void Sc::Scene::ccdBroadPhaseAABB(PxBaseTask* continuation) +{ + PX_PROFILE_START_CROSSTHREAD("Sim.ccdBroadPhaseComplete", getContextId()); + PX_PROFILE_ZONE("Sim.ccdBroadPhaseAABB", getContextId()); + PX_UNUSED(continuation); + + PxU32 currentPass = mCCDContext->getCurrentCCDPass(); + + Cm::FlushPool& flushPool = mLLContext->getTaskPool(); + + mNumFastMovingShapes = 0; + + //If we are on the 1st pass or we had some sweep hits previous CCD pass, we need to run CCD again + if( currentPass == 0 || mCCDContext->getNumSweepHits()) + { + for (PxU32 i = 0; i < mCcdBodies.size(); i+= UpdateCCDBoundsTask::MaxPerTask) + { + const PxU32 nbToProcess = PxMin(UpdateCCDBoundsTask::MaxPerTask, mCcdBodies.size() - i); + UpdateCCDBoundsTask* task = PX_PLACEMENT_NEW(flushPool.allocate(sizeof(UpdateCCDBoundsTask)), UpdateCCDBoundsTask)(&mCcdBodies[i], nbToProcess, &mNumFastMovingShapes); + task->setContinuation(continuation); + task->removeReference(); + } + } + +} + + +void Sc::Scene::ccdBroadPhase(PxBaseTask* continuation) +{ + PX_PROFILE_ZONE("Sim.ccdBroadPhase", getContextId()); + + PxU32 currentPass = mCCDContext->getCurrentCCDPass(); + const PxU32 ccdMaxPasses = mCCDContext->getCCDMaxPasses(); + mCCDPass = currentPass+1; + + //If we are on the 1st pass or we had some sweep hits previous CCD pass, we need to run CCD again + if( (currentPass == 0 || mCCDContext->getNumSweepHits()) && mNumFastMovingShapes != 0) + { + const PxU32 currIndex = currentPass & 1; + const PxU32 nextIndex = 1 - currIndex; + //Initialize the CCD task chain unless this is the final pass + if(currentPass != (ccdMaxPasses - 1)) + { + mCCDBroadPhase[nextIndex].setContinuation(continuation); + mCCDBroadPhaseAABB[nextIndex].setContinuation(&mCCDBroadPhase[nextIndex]); + } + mPostCCDPass[currIndex].setContinuation(currentPass == ccdMaxPasses-1 ? continuation : &mCCDBroadPhaseAABB[nextIndex]); + mUpdateCCDSinglePass3[currIndex].setContinuation(&mPostCCDPass[currIndex]); + mUpdateCCDSinglePass2[currIndex].setContinuation(&mUpdateCCDSinglePass3[currIndex]); + mUpdateCCDSinglePass[currIndex].setContinuation(&mUpdateCCDSinglePass2[currIndex]); + + + //Do the actual broad phase + PxBaseTask* continuationTask = &mUpdateCCDSinglePass[currIndex]; + const PxU32 numCpuTasks = continuationTask->getTaskManager()->getCpuDispatcher()->getWorkerCount(); + + mAABBManager->updateAABBsAndBP(numCpuTasks, mLLContext->getTaskPool(), &mLLContext->getScratchAllocator(), false, continuationTask, NULL); + + //Allow the CCD task chain to continue + mPostCCDPass[currIndex].removeReference(); + mUpdateCCDSinglePass3[currIndex].removeReference(); + mUpdateCCDSinglePass2[currIndex].removeReference(); + mUpdateCCDSinglePass[currIndex].removeReference(); + if(currentPass != (ccdMaxPasses - 1)) + { + mCCDBroadPhase[nextIndex].removeReference(); + mCCDBroadPhaseAABB[nextIndex].removeReference(); + } + } + else if (currentPass == 0) + { + PX_PROFILE_STOP_CROSSTHREAD("Sim.ccdBroadPhaseComplete", getContextId()); + mCCDContext->resetContactManagers(); + } +} + + +void Sc::Scene::updateCCDSinglePass(PxBaseTask* continuation) +{ + PX_PROFILE_ZONE("Sim.updateCCDSinglePass", getContextId()); + mReportShapePairTimeStamp++; // This will makes sure that new report pairs will get created instead of re-using the existing ones. + + const PxU32 currentPass = mCCDContext->getCurrentCCDPass() + 1; // 0 is reserved for discrete collision phase + finishBroadPhase(currentPass, continuation); + + + if (currentPass == 1) // reset the handle map so we only update CCD objects from here on + { + Cm::BitMapPinned& changedAABBMgrActorHandles = mAABBManager->getChangedAABBMgActorHandleMap(); + //changedAABBMgrActorHandles.clear(); + for (PxU32 i = 0; i < mCcdBodies.size();i++) + { + Sc::ShapeSim* sim; + for (Sc::ShapeIterator iterator(*mCcdBodies[i]); (sim = iterator.getNext()) != NULL;) + { + if (sim->getFlags()&PxU32(PxShapeFlag::eSIMULATION_SHAPE | PxShapeFlag::eTRIGGER_SHAPE)) // TODO: need trigger shape here? + changedAABBMgrActorHandles.growAndSet(sim->getElementID()); + } + } + } +} + +void Sc::Scene::updateCCDSinglePassStage2(PxBaseTask* continuation) +{ + PX_PROFILE_ZONE("Sim.updateCCDSinglePassStage2", getContextId()); + postBroadPhaseStage2(continuation); +} + +void Sc::Scene::updateCCDSinglePassStage3(PxBaseTask* continuation) +{ + PX_PROFILE_ZONE("Sim.updateCCDSinglePassStage3", getContextId()); + mReportShapePairTimeStamp++; // This will makes sure that new report pairs will get created instead of re-using the existing ones. + + const PxU32 currentPass = mCCDContext->getCurrentCCDPass() + 1; // 0 is reserved for discrete collision phase + finishBroadPhaseStage2(currentPass); + PX_PROFILE_STOP_CROSSTHREAD("Sim.ccdBroadPhaseComplete", getContextId()); + + //reset thread context in a place we know all tasks possibly accessing it, are in sync with. (see US6664) + mLLContext->resetThreadContexts(); + + mCCDContext->updateCCD(mDt, continuation, (mPublicFlags & PxSceneFlag::eDISABLE_CCD_RESWEEP), mNumFastMovingShapes); +} + + +void Sc::Scene::integrateKinematicPose() +{ + PX_PROFILE_ZONE("Sim.integrateKinematicPose", getContextId()); + + PxU32 nbKinematics = getActiveKinematicBodiesCount(); + BodyCore*const* kinematics = getActiveKinematicBodies(); + BodyCore*const* kineEnd = kinematics + nbKinematics; + BodyCore*const* kinePrefetch = kinematics + 16; + + for(PxU32 i = 0; i < nbKinematics; ++i) + { + if(kinePrefetch < kineEnd) + { + Ps::prefetch(*kinePrefetch, 1024); + kinePrefetch++; + } + + BodyCore* b = kinematics[i]; + BodySim* sim = b->getSim(); + PX_ASSERT(sim->isKinematic()); + PX_ASSERT(sim->isActive()); + + sim->updateKinematicPose(); + } +} + +void Sc::Scene::updateKinematicCached() +{ + PX_PROFILE_ZONE("Sim.integrateKinematicPose", getContextId()); + + PxU32 nbKinematics = getActiveKinematicBodiesCount(); + BodyCore*const* kinematics = getActiveKinematicBodies(); + BodyCore*const* kineEnd = kinematics + nbKinematics; + BodyCore*const* kinePrefetch = kinematics + 16; + + for(PxU32 i = 0; i < nbKinematics; ++i) + { + if(kinePrefetch < kineEnd) + { + Ps::prefetch(*kinePrefetch, 1024); + kinePrefetch++; + } + + BodyCore* b = kinematics[i]; + BodySim* sim = b->getSim(); + PX_ASSERT(sim->isKinematic()); + PX_ASSERT(sim->isActive()); + + Cm::BitMapPinned& changedAABBMgrActorHandles = mAABBManager->getChangedAABBMgActorHandleMap(); + sim->updateCached(&changedAABBMgrActorHandles); + mSimulationController->addDynamic(&sim->getLowLevelBody(), sim->getNodeIndex().index()); + } +} + + +class ConstraintProjectionTask : public Cm::Task +{ +private: + ConstraintProjectionTask& operator = (const ConstraintProjectionTask&); + +public: + ConstraintProjectionTask(Sc::ConstraintGroupNode* const* projectionRoots, PxU32 projectionRootCount, Ps::Array<Sc::BodySim*>& projectedBodies, PxsContext* llContext) + : + mProjectionRoots(projectionRoots), + mProjectionRootCount(projectionRootCount), + mProjectedBodies(projectedBodies), + mLLContext(llContext) + { + } + + virtual void runInternal() + { + PxcNpThreadContext* context = mLLContext->getNpThreadContext(); + Ps::Array<Sc::BodySim*>& tempArray = context->mBodySimPool; + tempArray.forceSize_Unsafe(0); + for(PxU32 i=0; i < mProjectionRootCount; i++) + { + PX_ASSERT(mProjectionRoots[i]->hasProjectionTreeRoot()); // else, it must not be in the projection root list + Sc::ConstraintGroupNode::projectPose(*mProjectionRoots[i], tempArray); + mProjectionRoots[i]->clearFlag(Sc::ConstraintGroupNode::eIN_PROJECTION_PASS_LIST); + } + + if (tempArray.size() > 0) + { + mLLContext->getLock().lock(); + for (PxU32 a = 0; a < tempArray.size(); ++a) + mProjectedBodies.pushBack(tempArray[a]); + mLLContext->getLock().unlock(); + } + + mLLContext->putNpThreadContext(context); + } + + virtual const char* getName() const + { + return "ScScene.constraintProjectionWork"; + } + + +public: + static const PxU32 sProjectingConstraintsPerTask = 256; // just a guideline, will not match exactly most of the time + +private: + Sc::ConstraintGroupNode* const* mProjectionRoots; + const PxU32 mProjectionRootCount; + Ps::Array<Sc::BodySim*>& mProjectedBodies; + PxsContext* mLLContext; +}; + +void Sc::Scene::constraintProjection(PxBaseTask* continuation) +{ + PxU32 constraintGroupRootCount = 0; + //BodyCore*const* activeBodies = getActiveBodiesArray(); + //PxU32 activeBodyCount = getNumActiveBodies(); + IG::IslandSim& islandSim = mSimpleIslandManager->getAccurateIslandSim(); + PxU32 activeBodyCount = islandSim.getNbActiveNodes(IG::Node::eRIGID_BODY_TYPE); + const IG::NodeIndex* activeNodeIds = islandSim.getActiveNodes(IG::Node::eRIGID_BODY_TYPE); + + PX_ASSERT(!mTmpConstraintGroupRootBuffer); + PxU32 index = 0; + + const PxU32 rigidBodyOffset = Sc::BodySim::getRigidBodyOffset(); + + if(activeBodyCount) + { + mTmpConstraintGroupRootBuffer = reinterpret_cast<ConstraintGroupNode**>(mLLContext->getScratchAllocator().alloc(sizeof(ConstraintGroupNode*) * activeBodyCount, true)); + if(mTmpConstraintGroupRootBuffer) + { + while(activeBodyCount--) + { + PxsRigidBody* rBody = islandSim.getRigidBody(activeNodeIds[index++]); + + Sc::BodySim* sim = reinterpret_cast<Sc::BodySim*>(reinterpret_cast<PxU8*>(rBody) - rigidBodyOffset); + //This move to PxgPostSolveWorkerTask for the gpu dynamic + //bodySim->sleepCheck(mDt, mOneOverDt, mEnableStabilization); + + if(sim->getConstraintGroup()) + { + ConstraintGroupNode& root = sim->getConstraintGroup()->getRoot(); + if(!root.readFlag(ConstraintGroupNode::eIN_PROJECTION_PASS_LIST) && root.hasProjectionTreeRoot()) + { + mTmpConstraintGroupRootBuffer[constraintGroupRootCount++] = &root; + root.raiseFlag(ConstraintGroupNode::eIN_PROJECTION_PASS_LIST); + } + } + } + + Cm::FlushPool& flushPool = mLLContext->getTaskPool(); + + PxU32 constraintsToProjectCount = 0; + PxU32 startIndex = 0; + for(PxU32 i=0; i < constraintGroupRootCount; i++) + { + ConstraintGroupNode* root = mTmpConstraintGroupRootBuffer[i]; + + constraintsToProjectCount += root->getProjectionCountHint(); // for load balancing + if (constraintsToProjectCount >= ConstraintProjectionTask::sProjectingConstraintsPerTask) + { + ConstraintProjectionTask* task = PX_PLACEMENT_NEW(flushPool.allocate(sizeof(ConstraintProjectionTask)), + ConstraintProjectionTask(mTmpConstraintGroupRootBuffer + startIndex, i - startIndex + 1, mProjectedBodies, mLLContext)); + task->setContinuation(continuation); + task->removeReference(); + + constraintsToProjectCount = 0; + startIndex = i + 1; + } + } + + if (constraintsToProjectCount) + { + PX_ASSERT(startIndex < constraintGroupRootCount); + + ConstraintProjectionTask* task = PX_PLACEMENT_NEW(flushPool.allocate(sizeof(ConstraintProjectionTask)), + ConstraintProjectionTask(mTmpConstraintGroupRootBuffer + startIndex, constraintGroupRootCount - startIndex, mProjectedBodies, mLLContext)); + task->setContinuation(continuation); + task->removeReference(); + } + } + else + { + getFoundation().getErrorCallback().reportError(PxErrorCode::eOUT_OF_MEMORY, "List for collecting constraint projection roots could not be allocated. No projection will take place.", __FILE__, __LINE__); + } + } +} + +void Sc::Scene::postSolver(PxBaseTask* continuation) +{ + PxcNpMemBlockPool& blockPool = mLLContext->getNpMemBlockPool(); + + //Merge... + mDynamicsContext->mergeResults(); + blockPool.releaseConstraintMemory(); + //Swap friction! + blockPool.swapFrictionStreams(); + + mCcdBodies.clear(); + mProjectedBodies.clear(); + +#if PX_ENABLE_SIM_STATS + mLLContext->getSimStats().mPeakConstraintBlockAllocations = blockPool.getPeakConstraintBlockCount(); +#endif + + integrateKinematicPose(); + + if (mConstraints.size()) // conservative (the real criteria would be to check for any active constraint with projection enabled which is only known + // once islands have been woken up) + { + //note that there might be a dependency to integrateKinematicPose(), so we can't start it earlier + + mConstraintProjection.setContinuation(continuation); + mConstraintProjection.removeReference(); + } + + //afterIntegration(continuation); + +} + +void Sc::Scene::postCCDPass(PxBaseTask* /*continuation*/) +{ + // - Performs sleep check + // - Updates touch flags + + PxU32 currentPass = mCCDContext->getCurrentCCDPass(); + PX_ASSERT(currentPass > 0); // to make sure changes to the CCD pass counting get noticed. For contact reports, 0 means discrete collision phase. + + int newTouchCount, lostTouchCount, ccdTouchCount; + mLLContext->getManagerTouchEventCount(&newTouchCount, &lostTouchCount, &ccdTouchCount); + PX_ALLOCA(newTouches, PxvContactManagerTouchEvent, newTouchCount); + PX_ALLOCA(lostTouches, PxvContactManagerTouchEvent, lostTouchCount); + PX_ALLOCA(ccdTouches, PxvContactManagerTouchEvent, ccdTouchCount); + + PxsContactManagerOutputIterator outputs = mLLContext->getNphaseImplementationContext()->getContactManagerOutputs(); + + bool useAdaptiveForce = mPublicFlags & PxSceneFlag::eADAPTIVE_FORCE; + + // Note: For contact notifications it is important that the new touch pairs get processed before the lost touch pairs. + // This allows to know for sure if a pair of actors lost all touch (see eACTOR_PAIR_LOST_TOUCH). + mLLContext->fillManagerTouchEvents(newTouches, newTouchCount, lostTouches, lostTouchCount, ccdTouches, ccdTouchCount); + for(PxI32 i=0; i<newTouchCount; ++i) + { + ShapeInteraction* si = reinterpret_cast<ShapeInteraction*>(newTouches[i].userData); + PX_ASSERT(si); + mNPhaseCore->managerNewTouch(*si, currentPass, true, outputs); + si->managerNewTouch(currentPass, true, outputs, useAdaptiveForce); + if (!si->readFlag(ShapeInteraction::CONTACTS_RESPONSE_DISABLED)) + { + mSimpleIslandManager->setEdgeConnected(si->getEdgeIndex()); + } + } + for(PxI32 i=0; i<lostTouchCount; ++i) + { + ShapeInteraction* si = reinterpret_cast<ShapeInteraction*>(lostTouches[i].userData); + PX_ASSERT(si); + if (si->managerLostTouch(currentPass, true, outputs, useAdaptiveForce) && !si->readFlag(ShapeInteraction::CONTACTS_RESPONSE_DISABLED)) + addToLostTouchList(si->getShape0().getBodySim(), si->getShape1().getBodySim()); + + mSimpleIslandManager->setEdgeDisconnected(si->getEdgeIndex()); + } + for(PxI32 i=0; i<ccdTouchCount; ++i) + { + ShapeInteraction* si = reinterpret_cast<ShapeInteraction*>(ccdTouches[i].userData); + PX_ASSERT(si); + si->sendCCDRetouch(currentPass, outputs); + } + checkForceThresholdContactEvents(currentPass); + { + Cm::BitMapPinned& changedAABBMgrActorHandles = mAABBManager->getChangedAABBMgActorHandleMap(); + + for (PxU32 i = 0, s = mCcdBodies.size(); i < s; i++) + { + BodySim*const body = mCcdBodies[i]; + if(i+8 < s) + Ps::prefetch(mCcdBodies[i+8], 512); + + PX_ASSERT(body->getBody2World().p.isFinite()); + PX_ASSERT(body->getBody2World().q.isFinite()); + + body->updateCached(&changedAABBMgrActorHandles); + } + + ArticulationCore* const* articList = mArticulations.getEntries(); + for(PxU32 i=0;i<mArticulations.size();i++) + { + articList[i]->getSim()->updateCached(&changedAABBMgrActorHandles); + } + } +} + +void Sc::Scene::finalizationPhase(PxBaseTask* /*continuation*/) +{ + PX_PROFILE_ZONE("Sim.sceneFinalization", getContextId()); + + if (mCCDContext) + { + //KS - force simulation controller to update any bodies updated by the CCD. When running GPU simulation, this would be required + //to ensure that cached body states are updated + const PxU32 nbUpdatedBodies = mCCDContext->getNumUpdatedBodies(); + PxsRigidBody*const* updatedBodies = mCCDContext->getUpdatedBodies(); + + const PxU32 rigidBodyOffset = Sc::BodySim::getRigidBodyOffset(); + + for (PxU32 a = 0; a < nbUpdatedBodies; ++a) + { + Sc::BodySim* bodySim = reinterpret_cast<Sc::BodySim*>(reinterpret_cast<PxU8*>(updatedBodies[a]) - rigidBodyOffset); + mSimulationController->addDynamic(updatedBodies[a], bodySim->getNodeIndex().index()); + } + + mCCDContext->clearUpdatedBodies(); + } + + if (mTmpConstraintGroupRootBuffer) + { + mLLContext->getScratchAllocator().free(mTmpConstraintGroupRootBuffer); + mTmpConstraintGroupRootBuffer = NULL; + } + + fireOnAdvanceCallback(); // placed here because it needs to be done after sleep check and afrer potential CCD passes + + checkConstraintBreakage(); // Performs breakage tests on breakable constraints + + PX_PROFILE_STOP_CROSSTHREAD("Basic.rigidBodySolver", getContextId()); + + //KS - process deleted elementIDs now - before GPU particles releases elements, causing issues + mElementIDPool->processPendingReleases(); + mElementIDPool->clearDeletedIDMap(); + + // Finish particleSystem simulation step + // - Apply forces to rigid bodies (two-way interaction) + // - Update particle id management structures + // - Update packet bounds + finishParticleSystems(); + + visualizeEndStep(); + + mTaskPool.clear(); + + mReportShapePairTimeStamp++; // important to do this before fetchResults() is called to make sure that delayed deleted actors/shapes get + // separate pair entries in contact reports +} + +void Sc::Scene::postReportsCleanup() +{ + mShapeIDTracker->processPendingReleases(); + mShapeIDTracker->clearDeletedIDMap(); + + mRigidIDTracker->processPendingReleases(); + mRigidIDTracker->clearDeletedIDMap(); + + + mConstraintIDTracker->processPendingReleases(); + mConstraintIDTracker->clearDeletedIDMap(); + +} + +void Sc::Scene::syncSceneQueryBounds(SqBoundsSync& sync, SqRefFinder& finder) +{ + mSqBoundsManager->syncBounds(sync, finder, mBoundsArray->begin(), getContextId()); +} + +// Let the particle systems do some preparations before doing the "real" stuff. +// - Creation / deletion of particles +// - Particle update +// ... +void Sc::Scene::prepareParticleSystems() +{ +#if PX_USE_PARTICLE_SYSTEM_API + for(PxU32 i=0; i < mEnabledParticleSystems.size(); i++) + { + mEnabledParticleSystems[i]->startStep(); + } +#endif +} + +// Do some postprocessing on particle systems. +void Sc::Scene::finishParticleSystems() +{ +#if PX_USE_PARTICLE_SYSTEM_API + for(PxU32 i=0; i < mEnabledParticleSystems.size(); i++) + { + mEnabledParticleSystems[i]->endStep(); + } +#endif +} + +void Sc::Scene::kinematicsSetup() +{ + const PxU32 nbKinematics = getActiveKinematicBodiesCount(); + BodyCore*const* kinematics = getActiveKinematicBodies(); + BodyCore*const* kineEnd = kinematics + nbKinematics; + BodyCore*const* kinePrefetch = kinematics + 16; + for(PxU32 i = 0; i < nbKinematics; ++i) + { + if(kinePrefetch < kineEnd) + { + Ps::prefetch(*kinePrefetch, 1024); + kinePrefetch++; + } + + BodyCore* b = kinematics[i]; + PX_ASSERT(b->getSim()->isKinematic()); + PX_ASSERT(b->getSim()->isActive()); + + b->getSim()->calculateKinematicVelocity(mOneOverDt); + } +} + +//stepSetup is called in solve, but not collide +void Sc::Scene::stepSetupSolve() +{ + PX_PROFILE_ZONE("Sim.stepSetupSolve", getContextId()); + + kinematicsSetup(); +} + +void Sc::Scene::stepSetupCollide() +{ + PX_PROFILE_ZONE("Sim.stepSetupCollide", getContextId()); + + //KS - todo - get this working!!!!!!!!!!!!!!!!! + { + PX_PROFILE_ZONE("Sim.projectionTreeUpdates", getContextId()); + mProjectionManager->processPendingUpdates(mLLContext->getScratchAllocator()); + } + + kinematicsSetup(); + PxsContactManagerOutputIterator outputs = mLLContext->getNphaseImplementationContext()->getContactManagerOutputs(); + // Update all dirty interactions + mNPhaseCore->updateDirtyInteractions(outputs, mPublicFlags & PxSceneFlag::eADAPTIVE_FORCE); + mInternalFlags &= ~(SceneInternalFlag::eSCENE_SIP_STATES_DIRTY_DOMINANCE | SceneInternalFlag::eSCENE_SIP_STATES_DIRTY_VISUALIZATION); +} + + + +void Sc::Scene::processLostTouchPairs() +{ + PX_PROFILE_ZONE("Sc::Scene::processLostTouchPairs", getContextId()); + for (PxU32 i=0; i<mLostTouchPairs.size(); ++i) + { + // If one has been deleted, we wake the other one + const Ps::IntBool deletedBody1 = mLostTouchPairsDeletedBodyIDs.boundedTest(mLostTouchPairs[i].body1ID); + const Ps::IntBool deletedBody2 = mLostTouchPairsDeletedBodyIDs.boundedTest(mLostTouchPairs[i].body2ID); + if (deletedBody1 || deletedBody2) + { + if (!deletedBody1) + mLostTouchPairs[i].body1->internalWakeUp(); + if (!deletedBody2) + mLostTouchPairs[i].body2->internalWakeUp(); + continue; + } + + // If both are sleeping, we let them sleep + // (for example, two sleeping objects touch and the user teleports one (without waking it up)) + if (!mLostTouchPairs[i].body1->isActive() && + !mLostTouchPairs[i].body2->isActive()) + { + continue; + } + + // If only one has fallen asleep, we wake them both + if (!mLostTouchPairs[i].body1->isActive() || + !mLostTouchPairs[i].body2->isActive()) + { + mLostTouchPairs[i].body1->internalWakeUp(); + mLostTouchPairs[i].body2->internalWakeUp(); + } + } + + + mLostTouchPairs.clear(); + mLostTouchPairsDeletedBodyIDs.clear(); +} + +class ScBeforeSolverTask : public Cm::Task +{ +public: + static const PxU32 MaxBodiesPerTask = 256; + IG::NodeIndex mBodies[MaxBodiesPerTask]; + PxU32 mNumBodies; + const PxReal mDt; + IG::SimpleIslandManager* mIslandManager; + PxsSimulationController* mSimulationController; + PxU64 mContextID; + bool mSimUsesAdaptiveForce; + +public: + + ScBeforeSolverTask(PxReal dt, IG::SimpleIslandManager* islandManager, PxsSimulationController* simulationController, PxU64 contextID, bool simUsesAdaptiveForce) : + mDt (dt), + mIslandManager (islandManager), + mSimulationController (simulationController), + mContextID (contextID), + mSimUsesAdaptiveForce (simUsesAdaptiveForce) + { + } + + virtual void runInternal() + { + PX_PROFILE_ZONE("Sim.ScBeforeSolverTask", mContextID); + const IG::IslandSim& islandSim = mIslandManager->getAccurateIslandSim(); + const PxU32 rigidBodyOffset = Sc::BodySim::getRigidBodyOffset(); + + PxsRigidBody* updatedBodySims[MaxBodiesPerTask]; + PxU32 updatedBodyNodeIndices[MaxBodiesPerTask]; + PxU32 nbUpdatedBodySims = 0; + + for(PxU32 i = 0; i < mNumBodies; i++) + { + IG::NodeIndex index = mBodies[i]; + if(islandSim.getActiveNodeIndex(index) != IG_INVALID_NODE) + { + if (islandSim.getNode(index).mType == IG::Node::eRIGID_BODY_TYPE) + { + PxsRigidBody* body = islandSim.getRigidBody(index); + Sc::BodySim* bodySim = reinterpret_cast<Sc::BodySim*>(reinterpret_cast<PxU8*>(body) - rigidBodyOffset); + bodySim->updateForces(mDt, updatedBodySims, updatedBodyNodeIndices, nbUpdatedBodySims, NULL, mSimUsesAdaptiveForce); + } + } + } + + if(nbUpdatedBodySims) + mSimulationController->updateBodies(updatedBodySims, updatedBodyNodeIndices, nbUpdatedBodySims); + } + + virtual const char* getName() const + { + return "ScScene.beforeSolver"; + } + +private: + ScBeforeSolverTask& operator = (const ScBeforeSolverTask&); +}; + + +void Sc::Scene::beforeSolver(PxBaseTask* continuation) +{ + PX_PROFILE_ZONE("Sim.updateForces", getContextId()); + + ArticulationCore* const* articList = mArticulations.getEntries(); + for(PxU32 i=0;i<mArticulations.size();i++) + articList[i]->getSim()->checkResize(); + + // Note: For contact notifications it is important that force threshold checks are done after new/lost touches have been processed + // because pairs might get added to the list processed below + + // Atoms that passed contact force threshold + ThresholdStream& thresholdStream = mDynamicsContext->getThresholdStream(); + thresholdStream.clear(); + + const IG::IslandSim& islandSim = mSimpleIslandManager->getAccurateIslandSim(); + + const PxU32 nbActiveBodies = islandSim.getNbActiveNodes(IG::Node::eRIGID_BODY_TYPE); + + mNumDeactivatingNodes[IG::Node::eRIGID_BODY_TYPE] = 0;//islandSim.getNbNodesToDeactivate(IG::Node::eRIGID_BODY_TYPE); + mNumDeactivatingNodes[IG::Node::eARTICULATION_TYPE] = 0;//islandSim.getNbNodesToDeactivate(IG::Node::eARTICULATION_TYPE); + + const PxU32 MaxBodiesPerTask = ScBeforeSolverTask::MaxBodiesPerTask; + + Cm::FlushPool& flushPool = mLLContext->getTaskPool(); + + mSimulationController->reserve(nbActiveBodies); + + Cm::BitMap::Iterator iter(mVelocityModifyMap); + + bool simUsesAdaptiveForce = mPublicFlags & PxSceneFlag::eADAPTIVE_FORCE; + + for (PxU32 i = iter.getNext(); i != Cm::BitMap::Iterator::DONE; /*i = iter.getNext()*/) + { + ScBeforeSolverTask* task = PX_PLACEMENT_NEW(flushPool.allocate(sizeof(ScBeforeSolverTask)), ScBeforeSolverTask(mDt, mSimpleIslandManager, mSimulationController, getContextId(), simUsesAdaptiveForce)); + PxU32 count = 0; + for(; count < MaxBodiesPerTask && i != Cm::BitMap::Iterator::DONE; count++, i = iter.getNext()) + { + task->mBodies[count] = IG::NodeIndex(i); + } + task->mNumBodies = count; + task->setContinuation(continuation); + task->removeReference(); + } + + //KS - wipe the changed map + mVelocityModifyMap.clear(); + + const PxU32 nbActiveArticulations = islandSim.getNbActiveNodes(IG::Node::eARTICULATION_TYPE); + const IG::NodeIndex* const articIndices = islandSim.getActiveNodes(IG::Node::eARTICULATION_TYPE); + + for(PxU32 a = 0; a < nbActiveArticulations; ++a) + { + ArticulationSim* PX_RESTRICT articSim= islandSim.getLLArticulation(articIndices[a])->getArticulationSim(); + articSim->updateForces(mDt, simUsesAdaptiveForce); + articSim->saveLastCCDTransform(); + } + + mBodyGravityDirty = false; +} + + +#if PX_DEBUG +bool DEBUG_solverlock = false; +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class UpdatProjectedPoseTask : public Cm::Task +{ + Sc::BodySim** mProjectedBodies; + PxU32 mNbBodiesToProcess; + +public: + UpdatProjectedPoseTask(Sc::BodySim** projectedBodies, PxU32 nbBodiesToProcess) : mProjectedBodies(projectedBodies), mNbBodiesToProcess(nbBodiesToProcess) + { + } + + virtual void runInternal() + { + for (PxU32 a = 0; a < mNbBodiesToProcess; ++a) + { + mProjectedBodies[a]->updateCached(NULL); + } + } + + virtual const char* getName() const + { + return "ScScene.UpdatProjectedPoseTask"; + } +}; + + +void Sc::Scene::afterIntegration(PxBaseTask* continuation) +{ + mLLContext->getTransformCache().resetChangedState(); //Reset the changed state. If anything outside of the GPU kernels updates any shape's transforms, this will be raised again + getBoundsArray().resetChangedState(); + + PxsTransformCache& cache = getLowLevelContext()->getTransformCache(); + Bp::BoundsArray& boundArray = getBoundsArray(); + + mSimulationController->udpateScBodyAndShapeSim(cache, boundArray, continuation); + + + + { + PX_PROFILE_ZONE("AfterIntegration::lockStage", getContextId()); + mLLContext->getLock().lock(); + + const IG::IslandSim& islandSim = mSimpleIslandManager->getAccurateIslandSim(); + + const PxU32 rigidBodyOffset = Sc::BodySim::getRigidBodyOffset(); + + const PxU32 numBodiesToDeactivate = islandSim.getNbNodesToDeactivate(IG::Node::eRIGID_BODY_TYPE); + + const IG::NodeIndex*const deactivatingIndices = islandSim.getNodesToDeactivate(IG::Node::eRIGID_BODY_TYPE); + + PxU32 previousNumBodiesToDeactivate = mNumDeactivatingNodes[IG::Node::eRIGID_BODY_TYPE]; + + { + Cm::BitMapPinned& changedAABBMgrActorHandles = mAABBManager->getChangedAABBMgActorHandleMap(); + PX_PROFILE_ZONE("AfterIntegration::deactivateStage", getContextId()); + for (PxU32 i = previousNumBodiesToDeactivate; i < numBodiesToDeactivate; i++) + { + PxsRigidBody* rigid = islandSim.getRigidBody(deactivatingIndices[i]); + Sc::BodySim* bodySim = reinterpret_cast<Sc::BodySim*>(reinterpret_cast<PxU8*>(rigid) - rigidBodyOffset); + //we need to set the rigid body back to the previous pose for the deactivated objects. This emulates the previous behavior where island gen ran before the solver, ensuring + //that bodies that should be deactivated this frame never reach the solver. We now run the solver in parallel with island gen, so objects that should be deactivated this frame + //still reach the solver and are integrated. However, on the frame when they should be deactivated, we roll back to their state at the beginning of the frame to ensure that the + //user perceives the same behavior as before. + + PxsBodyCore& bodyCore = bodySim->getBodyCore().getCore(); + + //if(!islandSim.getNode(bodySim->getNodeIndex()).isActive()) + rigid->setPose(rigid->getLastCCDTransform()); + + + bodySim->updateCached(&changedAABBMgrActorHandles); + mSimulationController->addDynamic(rigid, bodySim->getNodeIndex().index()); + + //solver is running in parallel with IG(so solver might solving the body which IG identify as deactivatedNodes). After we moved sleepCheck into the solver after integration, sleepChecks + //might have processed bodies that are now considered deactivated. This could have resulted in either freezing or unfreezing one of these bodies this frame, so we need to process those + //events to ensure that the SqManager's bounds arrays are consistently maintained. Also, we need to clear the frame flags for these bodies. + + if (rigid->isFreezeThisFrame()) + bodySim->freezeTransforms(&mAABBManager->getChangedAABBMgActorHandleMap()); + /*else if(bodyCore.isUnfreezeThisFrame()) + bodySim->createSqBounds();*/ + + //PX_ASSERT(bodyCore.wakeCounter == 0.f); + //KS - the IG deactivates bodies in parallel with the solver. It appears that under certain circumstances, the solver's integration (which performs + //sleep checks) could decide that the body is no longer a candidate for sleeping on the same frame that the island gen decides to deactivate the island + //that the body is contained in. This is a rare occurrence but the behavior we want to emulate is that of IG running before solver so we should therefore + //permit the IG to make the authoritative decision over whether the body should be active or inactive. + bodyCore.wakeCounter = 0.f; + bodyCore.linearVelocity = PxVec3(0); + bodyCore.angularVelocity = PxVec3(0); + + rigid->clearAllFrameFlags(); + + /*Sc::ShapeSim* sim; + for (Sc::ShapeIterator iterator(*bodySim); (sim = iterator.getNext()) != NULL;) + { + if (sim->isInBroadPhase()) + changedAABBMgrActorHandles.growAndSet(sim->getElementID()); + }*/ + } + } + + const PxU32 maxBodiesPerTask = 256; + + Cm::FlushPool& flushPool = mLLContext->getTaskPool(); + + { + PX_PROFILE_ZONE("AfterIntegration::dispatchTasks", getContextId()); + for (PxU32 a = 0; a < mProjectedBodies.size(); a += maxBodiesPerTask) + { + UpdatProjectedPoseTask* task = + PX_PLACEMENT_NEW(flushPool.allocate(sizeof(UpdatProjectedPoseTask)), UpdatProjectedPoseTask)(&mProjectedBodies[a], PxMin(maxBodiesPerTask, mProjectedBodies.size() - a)); + task->setContinuation(continuation); + task->removeReference(); + } + } + + { + Cm::BitMapPinned& changedAABBMgrActorHandles = mAABBManager->getChangedAABBMgActorHandleMap(); + PX_PROFILE_ZONE("AfterIntegration::growAndSet", getContextId()); + for (PxU32 a = 0; a < mProjectedBodies.size(); ++a) + { + if (!mProjectedBodies[a]->isFrozen()) + { + Sc::ShapeSim* sim; + for (Sc::ShapeIterator iterator(*mProjectedBodies[a]); (sim = iterator.getNext()) != NULL;) + { + if (sim->isInBroadPhase()) + changedAABBMgrActorHandles.growAndSet(sim->getElementID()); + } + } + } + } + { + PX_PROFILE_ZONE("AfterIntegration::managerAndDynamic", getContextId()); + const PxU32 unrollSize = 256; + for (PxU32 a = 0; a < mProjectedBodies.size(); a += unrollSize) + { + PxsRigidBody* tempBodies[unrollSize]; + PxU32 nodeIds[unrollSize]; + const PxU32 nbToProcess = PxMin(unrollSize, mProjectedBodies.size() - a); + for (PxU32 i = 0; i < nbToProcess; ++i) + { + tempBodies[i] = &mProjectedBodies[a + i]->getLowLevelBody(); + nodeIds[i] = mProjectedBodies[a + i]->getNodeIndex().index(); + } + //KS - it seems that grabbing the CUDA context/releasing it is expensive so we should minimize how + //frequently we do that. Batch processing like this helps + mSimulationController->addDynamics(tempBodies, nodeIds, nbToProcess); + } + } + + updateKinematicCached(); + + mLLContext->getLock().unlock(); + } + + if(mArticulations.size()) + { + mLLContext->getLock().lock(); + Cm::BitMapPinned& changedAABBMgrActorHandles = mAABBManager->getChangedAABBMgActorHandleMap(); + ArticulationCore* const* articList = mArticulations.getEntries(); + + Sc::BodySim* ccdBodySims[DY_ARTICULATION_MAX_SIZE]; + + for(PxU32 i=0;i<mArticulations.size();i++) + { + Sc::ArticulationSim* articSim = articList[i]->getSim(); + articSim->sleepCheck(mDt); + articSim->updateCached(&changedAABBMgrActorHandles); + + //KS - check links for CCD flags and add to mCcdBodies list if required.... + PxU32 nbIdx = articSim->getCCDLinks(ccdBodySims); + + for (PxU32 a = 0; a < nbIdx; ++a) + { + mCcdBodies.pushBack(ccdBodySims[a]); + } + + + } + mLLContext->getLock().unlock(); + } + + PX_PROFILE_STOP_CROSSTHREAD("Basic.dynamics", getContextId()); + + checkForceThresholdContactEvents(0); +} + +void Sc::Scene::checkForceThresholdContactEvents(const PxU32 ccdPass) +{ + PX_PROFILE_ZONE("Sim.checkForceThresholdContactEvents", getContextId()); + + // Note: For contact notifications it is important that force threshold checks are done after new/lost touches have been processed + // because pairs might get added to the list processed below + + // Bodies that passed contact force threshold + + PxsContactManagerOutputIterator outputs = mLLContext->getNphaseImplementationContext()->getContactManagerOutputs(); + + ThresholdStream& thresholdStream = mDynamicsContext->getForceChangedThresholdStream(); + + const PxU32 nbThresholdElements = thresholdStream.size(); + + + for (PxU32 i = 0; i< nbThresholdElements; ++i) + { + ThresholdStreamElement& elem = thresholdStream[i]; + ShapeInteraction* si = elem.shapeInteraction; + + //If there is a shapeInteraction and the shapeInteraction points to a contactManager (i.e. the CM was not destroyed in parallel with the solver) + if (si != NULL) + { + PxU32 pairFlags = si->getPairFlags(); + if (pairFlags & ShapeInteraction::CONTACT_FORCE_THRESHOLD_PAIRS) + { + si->swapAndClearForceThresholdExceeded(); + + if (elem.accumulatedForce > elem.threshold * mDt) + { + si->raiseFlag(ShapeInteraction::FORCE_THRESHOLD_EXCEEDED_NOW); + + PX_ASSERT(si->hasTouch()); + + //If the accumulatedForce is large than the threshold in the current frame and the accumulatedForce is less than the threshold in the previous frame, + //and the user request notify for found event, we will raise eNOTIFY_THRESHOLD_FORCE_FOUND + if ((!si->readFlag(ShapeInteraction::FORCE_THRESHOLD_EXCEEDED_BEFORE)) && (pairFlags & PxPairFlag::eNOTIFY_THRESHOLD_FORCE_FOUND)) + { + si->processUserNotification(PxPairFlag::eNOTIFY_THRESHOLD_FORCE_FOUND, 0, false, ccdPass, false, outputs); + } + else if (si->readFlag(ShapeInteraction::FORCE_THRESHOLD_EXCEEDED_BEFORE) && (pairFlags & PxPairFlag::eNOTIFY_THRESHOLD_FORCE_PERSISTS)) + { + si->processUserNotification(PxPairFlag::eNOTIFY_THRESHOLD_FORCE_PERSISTS, 0, false, ccdPass, false, outputs); + } + } + else + { + //If the accumulatedForce is less than the threshold in the current frame and the accumulatedForce is large than the threshold in the previous frame, + //and the user request notify for found event, we will raise eNOTIFY_THRESHOLD_FORCE_LOST + if (si->readFlag(ShapeInteraction::FORCE_THRESHOLD_EXCEEDED_BEFORE) && (pairFlags & PxPairFlag::eNOTIFY_THRESHOLD_FORCE_LOST)) + { + si->processUserNotification(PxPairFlag::eNOTIFY_THRESHOLD_FORCE_LOST, 0, false, ccdPass, false, outputs); + } + } + } + } + } +} + +void Sc::Scene::endStep() +{ + mTimeStamp++; +// INVALID_SLEEP_COUNTER is 0xffffffff. Therefore the last bit is masked. Look at Body::isForcedToSleep() for example. +// if(timeStamp==PX_INVALID_U32) timeStamp = 0; // Reserve INVALID_ID for something else + mTimeStamp &= 0x7fffffff; + + mReportShapePairTimeStamp++; // to make sure that deleted shapes/actors after fetchResults() create new report pairs +} + +void Sc::Scene::resizeReleasedBodyIDMaps(PxU32 maxActors, PxU32 numActors) +{ + mLostTouchPairsDeletedBodyIDs.resize(maxActors); + mRigidIDTracker->resizeDeletedIDMap(maxActors,numActors); + mShapeIDTracker->resizeDeletedIDMap(maxActors,numActors); +} + +/** +Render objects before simulation starts +*/ +void Sc::Scene::visualizeStartStep() +{ + PX_PROFILE_ZONE("Sim.visualizeStartStep", getContextId()); + +#if PX_ENABLE_DEBUG_VISUALIZATION + if(!getVisualizationScale()) + { + // make sure visualization inside simulate was skipped + PX_ASSERT(getRenderBuffer().empty()); + return; // early out if visualization scale is 0 + } + + Cm::RenderOutput out(getRenderBuffer()); + + if(getVisualizationParameter(PxVisualizationParameter::eCOLLISION_COMPOUNDS)) + mAABBManager->visualize(out); + + // Visualize joints + Sc::ConstraintCore*const * constraints = mConstraints.getEntries(); + for(PxU32 i=0, size = mConstraints.size();i<size; i++) + constraints[i]->getSim()->visualize(getRenderBuffer()); + + PxsContactManagerOutputIterator outputs = mLLContext->getNphaseImplementationContext()->getContactManagerOutputs(); + + mNPhaseCore->visualize(out, outputs); + + #if PX_USE_PARTICLE_SYSTEM_API + ParticleSystemCore* const* partList = mParticleSystems.getEntries(); + for(PxU32 i=0; i < mParticleSystems.size(); i++) + partList[i]->getSim()->visualizeStartStep(out); + #endif // PX_USE_PARTICLE_SYSTEM_API +#endif +} + +/** +Render objects after simulation finished. Use this for data that is only available after simulation. +*/ +void Sc::Scene::visualizeEndStep() +{ + PX_PROFILE_ZONE("Sim.visualizeEndStep", getContextId()); + +#if PX_ENABLE_DEBUG_VISUALIZATION + if(!getVisualizationScale()) + { + // make sure any visualization before was skipped + PX_ASSERT(getRenderBuffer().empty()); + return; // early out if visualization scale is 0 + } + + Cm::RenderOutput out(getRenderBuffer()); + +#if PX_USE_PARTICLE_SYSTEM_API + ParticleSystemCore* const* partList = mParticleSystems.getEntries(); + for(PxU32 i=0; i < mParticleSystems.size(); i++) + partList[i]->getSim()->visualizeEndStep(out); +#endif // PX_USE_PARTICLE_SYSTEM_API +#endif +} + + +void Sc::Scene::collectPostSolverVelocitiesBeforeCCD() +{ + if (mContactReportsNeedPostSolverVelocity) + { + ActorPairReport*const* actorPairs = mNPhaseCore->getContactReportActorPairs(); + PxU32 nbActorPairs = mNPhaseCore->getNbContactReportActorPairs(); + for(PxU32 i=0; i < nbActorPairs; i++) + { + if (i < (nbActorPairs - 1)) + Ps::prefetchLine(actorPairs[i+1]); + + ActorPairReport* aPair = actorPairs[i]; + + ContactStreamManager& cs = aPair->getContactStreamManager(); + + PxU32 streamManagerFlag = cs.getFlags(); + if(streamManagerFlag & ContactStreamManagerFlag::eINVALID_STREAM) + continue; + + PxU8* stream = mNPhaseCore->getContactReportPairData(cs.bufferIndex); + + if(i + 1 < nbActorPairs) + Ps::prefetch(&(actorPairs[i+1]->getContactStreamManager())); + + if (!cs.extraDataSize) + continue; + else if (streamManagerFlag & ContactStreamManagerFlag::eNEEDS_POST_SOLVER_VELOCITY) + cs.setContactReportPostSolverVelocity(stream, aPair->getActorA(), aPair->getActorB()); + } + } +} + + +void Sc::Scene::finalizeContactStreamAndCreateHeader(PxContactPairHeader& header, const ActorPairReport& aPair, ContactStreamManager& cs, PxU32 removedShapeTestMask) +{ + PxU8* stream = mNPhaseCore->getContactReportPairData(cs.bufferIndex); + PxU32 streamManagerFlag = cs.getFlags(); + ContactShapePair* contactPairs = cs.getShapePairs(stream); + const PxU16 nbShapePairs = cs.currentPairCount; + PX_ASSERT(nbShapePairs > 0); + + if (streamManagerFlag & removedShapeTestMask) + { + // At least one shape of this actor pair has been deleted. Need to traverse the contact buffer, + // find the pairs which contain deleted shapes and set the flags accordingly. + + ContactStreamManager::convertDeletedShapesInContactStream(contactPairs, nbShapePairs, getShapeIDTracker()); + } + PX_ASSERT(contactPairs); + + ObjectIDTracker& RigidIDTracker = getRigidIDTracker(); + header.actors[0] = static_cast<PxRigidActor*>(aPair.getPxActorA()); + header.actors[1] = static_cast<PxRigidActor*>(aPair.getPxActorB()); + PxU16 headerFlags = 0; + if (RigidIDTracker.isDeletedID(aPair.getActorAID())) + headerFlags |= PxContactPairHeaderFlag::eREMOVED_ACTOR_0; + if (RigidIDTracker.isDeletedID(aPair.getActorBID())) + headerFlags |= PxContactPairHeaderFlag::eREMOVED_ACTOR_1; + header.flags = PxContactPairHeaderFlags(headerFlags); + header.pairs = reinterpret_cast<PxContactPair*>(contactPairs); + header.nbPairs = nbShapePairs; + + PxU16 extraDataSize = cs.extraDataSize; + if (!extraDataSize) + header.extraDataStream = NULL; + else + { + PX_ASSERT(extraDataSize >= sizeof(ContactStreamHeader)); + extraDataSize -= sizeof(ContactStreamHeader); + header.extraDataStream = stream + sizeof(ContactStreamHeader); + + if (streamManagerFlag & ContactStreamManagerFlag::eNEEDS_POST_SOLVER_VELOCITY) + { + PX_ASSERT(!(headerFlags & Ps::to16(PxContactPairHeaderFlag::eREMOVED_ACTOR_0 | PxContactPairHeaderFlag::eREMOVED_ACTOR_1))); + cs.setContactReportPostSolverVelocity(stream, aPair.getActorA(), aPair.getActorB()); + } + } + header.extraDataStreamSize = extraDataSize; + +} + + +const Ps::Array<PxContactPairHeader>& Sc::Scene::getQueuedContactPairHeaders() +{ + // if buffered shape removals occured, then the criteria for testing the contact stream for events with removed shape pointers needs to be more strict. + PX_ASSERT(mRemovedShapeCountAtSimStart <= mShapeIDTracker->getDeletedIDCount()); + bool reducedTestForRemovedShapes = mRemovedShapeCountAtSimStart == mShapeIDTracker->getDeletedIDCount(); + const PxU32 removedShapeTestMask = PxU32((reducedTestForRemovedShapes ? ContactStreamManagerFlag::eTEST_FOR_REMOVED_SHAPES : (ContactStreamManagerFlag::eTEST_FOR_REMOVED_SHAPES | ContactStreamManagerFlag::eHAS_PAIRS_THAT_LOST_TOUCH))); + + ActorPairReport*const* actorPairs = mNPhaseCore->getContactReportActorPairs(); + PxU32 nbActorPairs = mNPhaseCore->getNbContactReportActorPairs(); + mQueuedContactPairHeaders.reserve(nbActorPairs); + mQueuedContactPairHeaders.clear(); + + for (PxU32 i = 0; i < nbActorPairs; i++) + { + if (i < (nbActorPairs - 1)) + Ps::prefetchLine(actorPairs[i + 1]); + + ActorPairReport* aPair = actorPairs[i]; + ContactStreamManager& cs = aPair->getContactStreamManager(); + if (cs.getFlags() & ContactStreamManagerFlag::eINVALID_STREAM) + continue; + + if (i + 1 < nbActorPairs) + Ps::prefetch(&(actorPairs[i + 1]->getContactStreamManager())); + + PxContactPairHeader &pairHeader = mQueuedContactPairHeaders.insert(); + finalizeContactStreamAndCreateHeader(pairHeader, *aPair, cs, removedShapeTestMask); + + cs.maxPairCount = cs.currentPairCount; + cs.setMaxExtraDataSize(cs.extraDataSize); + } + + return mQueuedContactPairHeaders; +} + +/* +Threading: called in the context of the user thread, but only after the physics thread has finished its run +*/ +void Sc::Scene::fireQueuedContactCallbacks(bool asPartOfFlush) +{ + //if(contactNotifyCallback) //TODO: not sure if this is a key optimization, but to do something like this, we'd have to check if there are ANY contact reports set for any client. + { + // if buffered shape removals occured, then the criteria for testing the contact stream for events with removed shape pointers needs to be more strict. + PX_ASSERT(asPartOfFlush || (mRemovedShapeCountAtSimStart <= mShapeIDTracker->getDeletedIDCount())); + bool reducedTestForRemovedShapes = asPartOfFlush || (mRemovedShapeCountAtSimStart == mShapeIDTracker->getDeletedIDCount()); + const PxU32 removedShapeTestMask = PxU32(reducedTestForRemovedShapes ? ContactStreamManagerFlag::eTEST_FOR_REMOVED_SHAPES : (ContactStreamManagerFlag::eTEST_FOR_REMOVED_SHAPES | ContactStreamManagerFlag::eHAS_PAIRS_THAT_LOST_TOUCH)); + + ActorPairReport*const* actorPairs = mNPhaseCore->getContactReportActorPairs(); + PxU32 nbActorPairs = mNPhaseCore->getNbContactReportActorPairs(); + for(PxU32 i=0; i < nbActorPairs; i++) + { + if (i < (nbActorPairs - 1)) + Ps::prefetchLine(actorPairs[i+1]); + + ActorPairReport* aPair = actorPairs[i]; + ContactStreamManager& cs = aPair->getContactStreamManager(); + if (cs.getFlags() & ContactStreamManagerFlag::eINVALID_STREAM) + continue; + + if (i + 1 < nbActorPairs) + Ps::prefetch(&(actorPairs[i+1]->getContactStreamManager())); + + PxContactPairHeader pairHeader; + finalizeContactStreamAndCreateHeader(pairHeader, *aPair, cs, removedShapeTestMask); + + //multiclient support: + PxClientID clientActor0 = aPair->getActorAClientID(); + PxClientID clientActor1 = aPair->getActorBClientID(); + + PxU8 actor0ClientBehaviorFlags = aPair->getActorAClientBehavior(); + PxU8 actor1ClientBehaviorFlags = aPair->getActorBClientBehavior(); + + if (mClients[clientActor0]->simulationEventCallback && + ( + (clientActor0 == clientActor1) //easy common case: the same client owns both shapes + || ( //else actor1 has a different owner -- see if we can still send this pair to the client of actor0: + (mClients[clientActor0]->behaviorFlags & PxClientBehaviorFlag::eREPORT_FOREIGN_OBJECTS_TO_CONTACT_NOTIFY)//this client accepts foreign objects + && (actor1ClientBehaviorFlags & PxActorClientBehaviorFlag::eREPORT_TO_FOREIGN_CLIENTS_CONTACT_NOTIFY)//this actor can be sent to foreign client + ) + )) + mClients[clientActor0]->simulationEventCallback->onContact(pairHeader, pairHeader.pairs, pairHeader.nbPairs); + + if ( + (clientActor0 != clientActor1) //don't call the same client twice + && mClients[clientActor1]->simulationEventCallback + && (mClients[clientActor1]->behaviorFlags & PxClientBehaviorFlag::eREPORT_FOREIGN_OBJECTS_TO_CONTACT_NOTIFY)//this client accepts foreign objects + && (actor0ClientBehaviorFlags & PxActorClientBehaviorFlag::eREPORT_TO_FOREIGN_CLIENTS_CONTACT_NOTIFY)//this actor can be sent to foreign client + ) + mClients[clientActor1]->simulationEventCallback->onContact(pairHeader, pairHeader.pairs, pairHeader.nbPairs); + + // estimates for next frame + cs.maxPairCount = cs.currentPairCount; + cs.setMaxExtraDataSize(cs.extraDataSize); + } + } +} + + +PX_FORCE_INLINE void markDeletedShapes(Sc::ObjectIDTracker& idTracker, Sc::TriggerPairExtraData& tped, PxTriggerPair& pair) +{ + PxTriggerPairFlags::InternalType flags = 0; + if (idTracker.isDeletedID(tped.shape0ID)) + flags |= PxTriggerPairFlag::eREMOVED_SHAPE_TRIGGER; + if (idTracker.isDeletedID(tped.shape1ID)) + flags |= PxTriggerPairFlag::eREMOVED_SHAPE_OTHER; + + pair.flags = PxTriggerPairFlags(flags); +} + + +void Sc::Scene::fireTriggerCallbacks() +{ + // triggers + const PxU32 nbTriggerPairs = mTriggerBufferAPI.size(); + PX_ASSERT(nbTriggerPairs == mTriggerBufferExtraData->size()); + if(nbTriggerPairs) + { + // cases to take into account: + // - no simulation/trigger shape has been removed -> no need to test shape references for removed shapes + // - simulation/trigger shapes have been removed but only while the simulation was not running -> only test the events that have + // a marker for removed shapes set + // - simulation/trigger shapes have been removed while the simulation was running -> need to test all events (see explanation + // below) + // + // If buffered shape removals occured, then all trigger events need to be tested for removed shape pointers. + // An optimization like in the contact report case is not applicable here because trigger interactions do not + // have a reference to their reported events. It can happen that a trigger overlap found event is created but + // a shape of that pair gets removed while the simulation is running. When processing the lost touch from the + // shape removal, no link to the overlap found event is possible and thus it can not be marked as dirty. + const bool hasRemovedShapes = mShapeIDTracker->getDeletedIDCount() > 0; + const bool forceTestsForRemovedShapes = (mRemovedShapeCountAtSimStart < mShapeIDTracker->getDeletedIDCount()); + + if((mClients.size() == 1) && mClients[0]->simulationEventCallback) // Simple and probably more common case + { + if (!hasRemovedShapes) + mClients[0]->simulationEventCallback->onTrigger(mTriggerBufferAPI.begin(), nbTriggerPairs); + else + { + for(PxU32 i = 0; i < nbTriggerPairs; i++) + { + PxTriggerPair& triggerPair = mTriggerBufferAPI[i]; + + if (forceTestsForRemovedShapes || (PxTriggerPairFlags::InternalType(triggerPair.flags) & TriggerPairFlag::eTEST_FOR_REMOVED_SHAPES)) + markDeletedShapes(*mShapeIDTracker, (*mTriggerBufferExtraData)[i], triggerPair); + } + + mClients[0]->simulationEventCallback->onTrigger(mTriggerBufferAPI.begin(), nbTriggerPairs); + } + } + else + { + PxU32 activeClients[(PX_MAX_CLIENTS+7)/8]; + PxMemSet(activeClients, 0, (PX_MAX_CLIENTS+7)/8); + + PxU16 activeClientLimit = 0; + + PxU32 nbValidPairs = 0; + for(PxU32 i = 0; i < nbTriggerPairs; i++) + { + Sc::TriggerPairExtraData& tped = (*mTriggerBufferExtraData)[nbValidPairs]; + + const PxU32 client0Broadcasting = PxU32(tped.actor0ClientBehavior & PxActorClientBehaviorFlag::eREPORT_TO_FOREIGN_CLIENTS_TRIGGER_NOTIFY); + const PxU32 client1Broadcasting = PxU32(tped.actor1ClientBehavior & PxActorClientBehaviorFlag::eREPORT_TO_FOREIGN_CLIENTS_TRIGGER_NOTIFY); + + const PxU32 client0Listening = getClientBehaviorFlags(tped.client0ID) & PxClientBehaviorFlag::eREPORT_FOREIGN_OBJECTS_TO_TRIGGER_NOTIFY; + const PxU32 client1Listening = getClientBehaviorFlags(tped.client1ID) & PxClientBehaviorFlag::eREPORT_FOREIGN_OBJECTS_TO_TRIGGER_NOTIFY; + + const bool reportTo0 = mClients[tped.client0ID]->simulationEventCallback && (tped.client0ID == tped.client1ID || (client0Listening && client1Broadcasting)); + const bool reportTo1 = mClients[tped.client1ID]->simulationEventCallback && (tped.client0ID != tped.client1ID && (client0Broadcasting && client1Listening)); + + if(reportTo0 || reportTo1) + { + PxTriggerPair& triggerPair = mTriggerBufferAPI[nbValidPairs]; + + if (forceTestsForRemovedShapes || (PxTriggerPairFlags::InternalType(triggerPair.flags) & TriggerPairFlag::eTEST_FOR_REMOVED_SHAPES)) + markDeletedShapes(*mShapeIDTracker, (*mTriggerBufferExtraData)[nbValidPairs], triggerPair); + + if(reportTo0) + { + activeClients[tped.client0ID>>3] |= 1<<(tped.client0ID&7); + activeClientLimit = PxMax<PxU16>(PxU16(tped.client0ID+1), activeClientLimit); + } + else + tped.client0ID = PX_MAX_CLIENTS; + + if(reportTo1) + { + activeClients[tped.client1ID>>3] |= 1<<(tped.client1ID&7); + activeClientLimit = PxMax<PxU16>(PxU16(tped.client1ID+1), activeClientLimit); + } + else + tped.client1ID = PX_MAX_CLIENTS; + + nbValidPairs++; + } + else + { + mTriggerBufferAPI.replaceWithLast(nbValidPairs); + mTriggerBufferExtraData->replaceWithLast(nbValidPairs); + } + } + + Ps::InlineArray<PxTriggerPair, 32, Ps::TempAllocator> perClientArray; + for(PxU32 i=0; i < activeClientLimit; i++) + { + if(!(activeClients[i>>3]&(1<<(i&7)))) + continue; + perClientArray.clear(); + perClientArray.reserve(nbValidPairs); + for(PxU32 j=0; j < nbValidPairs; j++) + { + if((*mTriggerBufferExtraData)[j].client0ID == i || (*mTriggerBufferExtraData)[j].client1ID == i) + perClientArray.pushBack(mTriggerBufferAPI[j]); + } + + mClients[i]->simulationEventCallback->onTrigger(perClientArray.begin(), perClientArray.size()); + } + } + } + + // PT: clear the buffer **even when there's no simulationEventCallback**. + mTriggerBufferAPI.clear(); + mTriggerBufferExtraData->clear(); +} + + +namespace +{ + struct BrokenConstraintReportData + { + BrokenConstraintReportData(PxConstraint* c, void* externalRef, PxU32 typeID, PxU16 i0, PxU16 i1): constraintInfo(c, externalRef, typeID), client0(i0), client1(i1) {} + PxConstraintInfo constraintInfo; + PxU16 client0; + PxU16 client1; + }; +} + +static const PxU16 NO_CLIENT = 0xffff; +static const PxActorClientBehaviorFlags ACTOR_BROADCASTING = PxActorClientBehaviorFlag::eREPORT_TO_FOREIGN_CLIENTS_CONSTRAINT_BREAK_NOTIFY; +static const PxClientBehaviorFlags CLIENT_LISTENING = PxClientBehaviorFlag::eREPORT_FOREIGN_OBJECTS_TO_CONSTRAINT_BREAK_NOTIFY; +void Sc::Scene::fireBrokenConstraintCallbacks() +{ + PxU32 count = mBrokenConstraints.size(); + Ps::InlineArray<BrokenConstraintReportData, 32, Ps::TempAllocator> notifyArray; + notifyArray.reserve(count); + + PxU32 activeClients[(PX_MAX_CLIENTS+7)/8]; + PxMemSet(activeClients, 0, (PX_MAX_CLIENTS+7)/8); + + + PxU16 activeClientLimit = 0; + + for(PxU32 i=0;i<count;i++) + { + Sc::ConstraintCore* c = mBrokenConstraints[i]; + + Sc::RigidCore* mActors[2]; + if (c->getSim()) // the constraint might have been removed while the simulation was running + { + mActors[0] = (&c->getSim()->getRigid(0) != mStaticAnchor) ? &c->getSim()->getRigid(0).getRigidCore() : NULL; + mActors[1] = (&c->getSim()->getRigid(1) != mStaticAnchor) ? &c->getSim()->getRigid(1).getRigidCore() : NULL; + + PxClientID clientID0 = mActors[0] ? mActors[0]->getOwnerClient() : PX_DEFAULT_CLIENT, + clientID1 = mActors[1] ? mActors[1]->getOwnerClient() : PX_DEFAULT_CLIENT; + + PxActorClientBehaviorFlags client0Broadcasting = mActors[0] ? mActors[0]->getClientBehaviorFlags() & ACTOR_BROADCASTING : PxActorClientBehaviorFlags(0); + PxActorClientBehaviorFlags client1Broadcasting = mActors[1] ? mActors[1]->getClientBehaviorFlags() & ACTOR_BROADCASTING : PxActorClientBehaviorFlags(0); + + PxClientBehaviorFlags client0Listening = getClientBehaviorFlags(clientID0) & CLIENT_LISTENING; + PxClientBehaviorFlags client1Listening = getClientBehaviorFlags(clientID1) & CLIENT_LISTENING; + + bool reportTo0 = mClients[clientID0]->simulationEventCallback && (clientID0 == clientID1 || (client0Listening && client1Broadcasting)); + bool reportTo1 = mClients[clientID1]->simulationEventCallback && (clientID0 != clientID1 && client0Broadcasting && client1Listening); + + if(reportTo0 || reportTo1) + { + PxU32 typeID = 0xffffffff; + void* externalRef = c->getPxConnector()->getExternalReference(typeID); + PX_CHECK_MSG(typeID != 0xffffffff, "onConstraintBreak: Invalid constraint type ID."); + + BrokenConstraintReportData d(c->getPxConstraint(), externalRef, typeID, reportTo0 ? PxU16(clientID0) : NO_CLIENT, PxU16(reportTo1) ? PxU16(clientID1) : NO_CLIENT); + notifyArray.pushBack(d); + if(reportTo0) + { + activeClients[clientID0>>3] |= 1<<(clientID0&7); + activeClientLimit = PxMax<PxU16>(PxU16(clientID0+1), activeClientLimit); + } + + if(reportTo1) + { + activeClients[clientID1>>3] |= 1<<(clientID1&7); + activeClientLimit = PxMax<PxU16>(PxU16(clientID1+1), activeClientLimit); + } + } + } + } + + Ps::InlineArray<PxConstraintInfo, 32, Ps::TempAllocator> perClientArray; + for(PxU32 i=0;i<activeClientLimit;i++) + { + if(!(activeClients[i>>3]&(1<<(i&7)))) + continue; + perClientArray.clear(); + perClientArray.reserve(notifyArray.size()); + for(PxU32 j=0;j<notifyArray.size();j++) + { + if(notifyArray[j].client0 == i || notifyArray[j].client1 == i) + perClientArray.pushBack(notifyArray[j].constraintInfo); + } + + mClients[i]->simulationEventCallback->onConstraintBreak(perClientArray.begin(), perClientArray.size()); + } +} + + +/* +Threading: called in the context of the user thread, but only after the physics thread has finished its run +*/ +void Sc::Scene::fireCallbacksPostSync() +{ + //Temp-data + PxActor** actors = NULL; + + // + // Fire sleep & woken callbacks + // + + // used to be + //if (simulationEventCallback) + //... + //comment from AM: TODO: not sure if this is a key optimization, but to do something like this, we'd have to check if there are ANY contact reports set for any client. + // + { + // A body should be either in the sleep or the woken list. If it is in both, remove it from the list it was + // least recently added to. + + if (!mSleepBodyListValid) + cleanUpSleepBodies(); + + if (!mWokeBodyListValid) + cleanUpWokenBodies(); + + // allocate temporary data + PxU32 nbSleep = mSleepBodies.size(); + PxU32 nbWoken = mWokeBodies.size(); + PxU32 arrSize = PxMax(nbSleep, nbWoken); + actors = arrSize ? reinterpret_cast<PxActor**>(PX_ALLOC_TEMP(arrSize*sizeof(PxActor*), "PxActor*")) : NULL; + + if ((nbSleep > 0) && actors) + { + PxU32 destSlot = 0; + PxClientID prevClient = PxClientID(-1); + BodyCore* const* sleepingBodies = mSleepBodies.getEntries(); + for(PxU32 i=0; i < nbSleep; i++) + { + BodyCore* body = sleepingBodies[i]; + if (prevClient != body->getOwnerClient()) + { + prevClient = body->getOwnerClient(); + //send off stuff buffered so far, then reset list: + if(mClients[prevClient]->simulationEventCallback && destSlot) + mClients[prevClient]->simulationEventCallback->onSleep(actors, destSlot); + destSlot = 0; + } + if (body->getActorFlags() & PxActorFlag::eSEND_SLEEP_NOTIFIES) + actors[destSlot++] = body->getPxActor(); + } + + if(mClients[prevClient]->simulationEventCallback && destSlot) + mClients[prevClient]->simulationEventCallback->onSleep(actors, destSlot); + + //if (PX_DBG_IS_CONNECTED()) + //{ + // for (PxU32 i = 0; i < nbSleep; ++i) + // { + // BodyCore* body = mSleepBodies[i]; + // PX_ASSERT(body->getActorType() == PxActorType::eRIGID_DYNAMIC); + // } + //} + } + + // do the same thing for bodies that have just woken up + + if ((nbWoken > 0) && actors) + { + PxU32 destSlot = 0; + PxClientID prevClient = PxClientID(-1); + BodyCore* const* wokenBodies = mWokeBodies.getEntries(); + for(PxU32 i=0; i < nbWoken; i++) + { + BodyCore* body = wokenBodies[i]; + if (prevClient != body->getOwnerClient()) + { + prevClient = body->getOwnerClient(); + //send off stuff buffered so far, then reset list: + if(mClients[prevClient]->simulationEventCallback && destSlot) + mClients[prevClient]->simulationEventCallback->onWake(actors, destSlot); + destSlot = 0; + } + if (body->getActorFlags() & PxActorFlag::eSEND_SLEEP_NOTIFIES) + actors[destSlot++] = body->getPxActor(); + } + + if(mClients[prevClient]->simulationEventCallback && destSlot) + mClients[prevClient]->simulationEventCallback->onWake(actors, destSlot); + + //if (PX_DBG_IS_CONNECTED()) + //{ + // for (PxU32 i = 0; i < nbWoken; ++i) + // { + // BodyCore* body = mWokeBodies[i]; + // PX_ASSERT(actors[i]->getType() == PxActorType::eRIGID_DYNAMIC); + // } + //} + } + + clearSleepWakeBodies(); + } + + PX_FREE_AND_RESET(actors); +} + +void Sc::Scene::prepareOutOfBoundsCallbacks() +{ + PxU32 nbOut0; + void** outObjects = mAABBManager->getOutOfBoundsObjects(nbOut0); + + mOutOfBoundsIDs.clear(); + for(PxU32 i=0;i<nbOut0;i++) + { + ElementSim* volume = reinterpret_cast<ElementSim*>(outObjects[i]); + + Sc::ShapeSim* sim = static_cast<Sc::ShapeSim*>(volume); + PxU32 id = sim->getID(); + mOutOfBoundsIDs.pushBack(id); + } +} + + +bool Sc::Scene::fireOutOfBoundsCallbacks() +{ + bool outputWarning = false; + const Ps::Array<Client*>& clients = mClients; + + // Actors + { + PxU32 nbOut0; + void** outObjects = mAABBManager->getOutOfBoundsObjects(nbOut0); + + const ObjectIDTracker& tracker = getShapeIDTracker(); + + for(PxU32 i=0;i<nbOut0;i++) + { + ElementSim* volume = reinterpret_cast<ElementSim*>(outObjects[i]); + + Sc::ShapeSim* sim = static_cast<Sc::ShapeSim*>(volume); + if(tracker.isDeletedID(mOutOfBoundsIDs[i])) + continue; + + ActorSim& actor = volume->getActor(); + RigidSim& rigidSim = static_cast<RigidSim&>(actor); + PxActor* pxActor = rigidSim.getPxActor(); + + const PxClientID clientID = pxActor->getOwnerClient(); + PX_ASSERT(clients[clientID]); + PxBroadPhaseCallback* cb = clients[clientID]->broadPhaseCallback; + if(cb) + { + PxShape* px = sim->getPxShape(); + cb->onObjectOutOfBounds(*px, *pxActor); + } + else + { + outputWarning = true; + } + } + mAABBManager->clearOutOfBoundsObjects(); + } + + return outputWarning; +} + +PX_FORCE_INLINE void addToPosePreviewBuffer(Sc::Client& cl, const Sc::BodySim& b) +{ + PxsBodyCore& c = b.getBodyCore().getCore(); + + if(!b.isFrozen()) + { + cl.posePreviewBodies.pushBack(static_cast<const PxRigidBody*>(b.getPxActor())); + cl.posePreviewBuffer.pushBack(c.body2World * c.getBody2Actor().getInverse()); + } +} + +void Sc::Scene::fireOnAdvanceCallback() +{ + const PxU32 nbPosePreviews = mPosePreviewBodies.size(); + if (nbPosePreviews) + { + const BodySim*const* PX_RESTRICT posePreviewBodies = mPosePreviewBodies.getEntries(); + + Client** PX_RESTRICT clients = mClients.begin(); + const PxU32 numClients = mClients.size(); + + for(PxU32 i=0; i < numClients; i++) + { + if (clients[i]->simulationEventCallback) + { + clients[i]->posePreviewBodies.clear(); + clients[i]->posePreviewBodies.reserve(nbPosePreviews); + + clients[i]->posePreviewBuffer.clear(); + clients[i]->posePreviewBuffer.reserve(nbPosePreviews); + } + } + + if((numClients == 1) && clients[0]->simulationEventCallback) // Simple and probably more common case + { + Client& cl = *clients[0]; + + for(PxU32 i=0; i < nbPosePreviews; i++) + { + const BodySim& b = *posePreviewBodies[i]; + addToPosePreviewBuffer(cl, b); + } + + const PxU32 bodyCount = cl.posePreviewBodies.size(); + if (bodyCount) + cl.simulationEventCallback->onAdvance(cl.posePreviewBodies.begin(), cl.posePreviewBuffer.begin(), bodyCount); + } + else + { + for(PxU32 i=0; i < nbPosePreviews; i++) + { + const BodySim& b = *posePreviewBodies[i]; + Client& cl = *clients[b.getBodyCore().getOwnerClient()]; + if (cl.simulationEventCallback) + addToPosePreviewBuffer(cl, b); + } + + for(PxU32 i=0; i < numClients; i++) + { + Client& cl = *clients[i]; + const PxU32 bodyCount = cl.posePreviewBodies.size(); + if (bodyCount) + { + PX_ASSERT(cl.simulationEventCallback); + cl.simulationEventCallback->onAdvance(cl.posePreviewBodies.begin(), cl.posePreviewBuffer.begin(), bodyCount); + } + } + } + } +} + +void Sc::Scene::postCallbacksPreSync() +{ + // clear contact stream data + mNPhaseCore->clearContactReportStream(); + mNPhaseCore->clearContactReportActorPairs(false); + + // Put/prepare kinematics to/for sleep and invalidate target pose + // note: this needs to get done after the contact callbacks because + // the target might get read there. + // + PxU32 nbKinematics = getActiveKinematicBodiesCount(); + BodyCore*const* kinematics = getActiveKinematicBodies(); + BodyCore*const* kineEnd = kinematics + nbKinematics; + BodyCore*const* kinePrefetch = kinematics + 16; + while(nbKinematics--) + { + if(kinePrefetch < kineEnd) + { + Ps::prefetchLine(*kinePrefetch); + kinePrefetch++; + } + + BodyCore* b = kinematics[nbKinematics]; + PX_ASSERT(b->getSim()->isKinematic()); + PX_ASSERT(b->getSim()->isActive()); + + b->getSim()->deactivateKinematic(); + b->invalidateKinematicTarget(); + } + + releaseConstraints(true); //release constraint blocks at the end of the frame, so user can retrieve the blocks +} + +PxU32 Sc::Scene::getErrorState() +{ + return mErrorState; // we only signal critical errors from the HW core +} + + +void Sc::Scene::setLimits(const PxSceneLimits & limits) +{ + mLimits = limits; +} + + +const PxSceneLimits& Sc::Scene::getLimits() const +{ + return mLimits; +} + +void Sc::Scene::setNbContactDataBlocks(PxU32 numBlocks) +{ + mLLContext->getNpMemBlockPool().setBlockCount(numBlocks); +} + +PxU32 Sc::Scene::getNbContactDataBlocksUsed() const +{ + return mLLContext->getNpMemBlockPool().getUsedBlockCount(); +} + +PxU32 Sc::Scene::getMaxNbContactDataBlocksUsed() const +{ + return mLLContext->getNpMemBlockPool().getMaxUsedBlockCount(); +} + +PxU32 Sc::Scene::getMaxNbConstraintDataBlocksUsed() const +{ + return mLLContext->getNpMemBlockPool().getPeakConstraintBlockCount(); +} + +void Sc::Scene::setScratchBlock(void* addr, PxU32 size) +{ + return mLLContext->setScratchBlock(addr, size); +} + +void Sc::Scene::checkConstraintBreakage() +{ + PX_PROFILE_ZONE("Sim.checkConstraintBreakage", getContextId()); + + PxU32 count = mActiveBreakableConstraints.size(); + ConstraintSim* const* constraints = mActiveBreakableConstraints.getEntries(); + while(count) + { + count--; + constraints[count]->checkMaxForceExceeded(); // start from the back because broken constraints get removed from the list + } +} + +void Sc::Scene::getStats(PxSimulationStatistics& s) const +{ + mStats->readOut(s, mLLContext->getSimStats()); + s.nbStaticBodies = mNbRigidStatics; + s.nbDynamicBodies = mNbRigidDynamics; + s.nbArticulations = mArticulations.size(); + + s.nbAggregates = mAABBManager->getNbActiveAggregates(); + for(PxU32 i=0; i<PxGeometryType::eGEOMETRY_COUNT; i++) + s.nbShapes[i] = mNbGeometries[i]; +} + +void Sc::Scene::addShapes(void *const* shapes, PxU32 nbShapes, size_t ptrOffset, RigidSim& bodySim, PxBounds3* outBounds) +{ + for(PxU32 i=0;i<nbShapes;i++) + { + ShapeCore& sc = *reinterpret_cast<ShapeCore*>(reinterpret_cast<size_t>(shapes[i])+ptrOffset); + + //PxBounds3* target = uninflatedBounds ? uninflatedBounds + i : uninflatedBounds; + //mShapeSimPool->construct(sim, sc, llBody, target); + + ShapeSim* shapeSim = mShapeSimPool->construct(bodySim, sc); + mNbGeometries[sc.getGeometryType()]++; + + mSimulationController->addShape(&shapeSim->getLLShapeSim(), shapeSim->getID()); + + if (outBounds) + outBounds[i] = mBoundsArray->getBounds(shapeSim->getElementID()); + + mLLContext->getNphaseImplementationContext()->registerShape(sc.getCore()); + } +} + +void Sc::Scene::removeShapes(Sc::RigidSim& sim, Ps::InlineArray<Sc::ShapeSim*, 64>& shapesBuffer , Ps::InlineArray<const Sc::ShapeCore*,64>& removedShapes, bool wakeOnLostTouch) +{ + // DS: usual faff with deleting while iterating through an opaque iterator + Sc::ShapeIterator iterator(sim); + + ShapeSim* s; + while((s = iterator.getNext())!=NULL) + { + // can do two 2x the allocs in the worst case, but actors with >64 shapes are not common + shapesBuffer.pushBack(s); + removedShapes.pushBack(&s->getCore()); + } + + for(PxU32 i=0;i<shapesBuffer.size();i++) + removeShape(*shapesBuffer[i], wakeOnLostTouch); +} + + +void Sc::Scene::addStatic(StaticCore& ro, void*const *shapes, PxU32 nbShapes, size_t shapePtrOffset, PxBounds3* uninflatedBounds) +{ + PX_ASSERT(ro.getActorCoreType() == PxActorType::eRIGID_STATIC); + + // sim objects do all the necessary work of adding themselves to broad phase, + // activation, registering with the interaction system, etc + + StaticSim* sim = mStaticSimPool->construct(*this, ro); + + mNbRigidStatics++; + addShapes(shapes, nbShapes, shapePtrOffset, *sim, uninflatedBounds); +} + +void Sc::Scene::prefetchForRemove(const StaticCore& core) const +{ + StaticSim* sim = core.getSim(); + if(sim) + { + Ps::prefetch(sim,sizeof(Sc::StaticSim)); + Ps::prefetch(sim->getElements_(),sizeof(Sc::ElementSim)); + } +} + +void Sc::Scene::prefetchForRemove(const BodyCore& core) const +{ + BodySim *sim = core.getSim(); + if(sim) + { + Ps::prefetch(sim,sizeof(Sc::BodySim)); + Ps::prefetch(sim->getElements_(),sizeof(Sc::ElementSim)); + } +} + +void Sc::Scene::removeStatic(StaticCore& ro, Ps::InlineArray<const Sc::ShapeCore*,64>& removedShapes, bool wakeOnLostTouch) +{ + PX_ASSERT(ro.getActorCoreType() == PxActorType::eRIGID_STATIC); + + StaticSim* sim = ro.getSim(); + if(sim) + { + if(mBatchRemoveState) + { + removeShapes(*sim, mBatchRemoveState->bufferedShapes ,removedShapes, wakeOnLostTouch); + } + else + { + Ps::InlineArray<Sc::ShapeSim*, 64> shapesBuffer; + removeShapes(*sim, shapesBuffer ,removedShapes, wakeOnLostTouch); + } + mStaticSimPool->destroy(static_cast<Sc::StaticSim*>(ro.getSim())); + mNbRigidStatics--; + } +} + + +void Sc::Scene::addBody(BodyCore& body, void*const *shapes, PxU32 nbShapes, size_t shapePtrOffset, PxBounds3* outBounds) +{ + // sim objects do all the necessary work of adding themselves to broad phase, + // activation, registering with the interaction system, etc + + BodySim* sim = mBodySimPool->construct(*this, body); + if (sim->getLowLevelBody().mCore->mFlags & PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD) + { + if (sim->isArticulationLink()) + mSpeculativeCDDArticulationBitMap.growAndSet(sim->getNodeIndex().index()); + else + mSpeculativeCCDRigidBodyBitMap.growAndSet(sim->getNodeIndex().index()); + } + mSimulationController->addDynamic(&sim->getLowLevelBody(), sim->getNodeIndex().index()); + mNbRigidDynamics++; + addShapes(shapes, nbShapes, shapePtrOffset, *sim, outBounds); +} + +void Sc::Scene::removeBody(BodyCore& body, Ps::InlineArray<const Sc::ShapeCore*,64>& removedShapes, bool wakeOnLostTouch) +{ + BodySim *sim = body.getSim(); + if(sim) + { + if(mBatchRemoveState) + { + removeShapes(*sim, mBatchRemoveState->bufferedShapes ,removedShapes, wakeOnLostTouch); + } + else + { + Ps::InlineArray<Sc::ShapeSim*, 64> shapesBuffer; + removeShapes(*sim,shapesBuffer, removedShapes, wakeOnLostTouch); + } + + if (!sim->isArticulationLink()) + { + //clear bit map + if (sim->getLowLevelBody().mCore->mFlags & PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD) + mSpeculativeCCDRigidBodyBitMap.reset(sim->getNodeIndex().index()); + } + mBodySimPool->destroy(sim); + mNbRigidDynamics--; + } +} + + +void Sc::Scene::addShape(RigidSim& owner, ShapeCore& shapeCore, PxBounds3* uninflatedBounds) +{ + ShapeSim* sim = mShapeSimPool->construct(owner, shapeCore); + mNbGeometries[shapeCore.getGeometryType()]++; + + //register shape + mSimulationController->addShape(&sim->getLLShapeSim(), sim->getID()); + if (uninflatedBounds) + *uninflatedBounds = mBoundsArray->getBounds(sim->getElementID()); + registerShapeInNphase(shapeCore); +} + +void Sc::Scene::removeShape(ShapeSim& shape, bool wakeOnLostTouch) +{ + //BodySim* body = shape.getBodySim(); + //if(body) + // body->postShapeDetach(); + + unregisterShapeFromNphase(shape.getCore()); + + mSimulationController->removeShape(shape.getID()); + + mNbGeometries[shape.getCore().getGeometryType()]--; + shape.removeFromBroadPhase(wakeOnLostTouch); + mShapeSimPool->destroy(&shape); +} + +void Sc::Scene::registerShapeInNphase(const ShapeCore& shape) +{ + mLLContext->getNphaseImplementationContext()->registerShape(shape.getCore()); +} + +void Sc::Scene::unregisterShapeFromNphase(const ShapeCore& shape) +{ + mLLContext->getNphaseImplementationContext()->unregisterShape(shape.getCore()); +} + +void Sc::Scene::notifyNphaseOnUpdateShapeMaterial(const ShapeCore& shapeCore) +{ + mLLContext->getNphaseImplementationContext()->updateShapeMaterial(shapeCore.getCore()); +} + +void Sc::Scene::startBatchInsertion(BatchInsertionState&state) +{ + state.shapeSim = mShapeSimPool->allocateAndPrefetch(); + state.staticSim = mStaticSimPool->allocateAndPrefetch(); + state.bodySim = mBodySimPool->allocateAndPrefetch(); +} + + +void Sc::Scene::addShapes(void *const* shapes, PxU32 nbShapes, size_t ptrOffset, RigidSim& rigidSim, ShapeSim*& prefetchedShapeSim, PxBounds3* outBounds) +{ + for(PxU32 i=0;i<nbShapes;i++) + { + if(i+1<nbShapes) + Ps::prefetch(shapes[i+1], PxU32(ptrOffset+sizeof(Sc::ShapeCore))); + ShapeSim* nextShapeSim = mShapeSimPool->allocateAndPrefetch(); + const ShapeCore& sc = *Ps::pointerOffset<const ShapeCore*>(shapes[i], ptrdiff_t(ptrOffset)); + new(prefetchedShapeSim) ShapeSim(rigidSim, sc); + outBounds[i] = mBoundsArray->getBounds(prefetchedShapeSim->getElementID()); + + mSimulationController->addShape(&prefetchedShapeSim->getLLShapeSim(), prefetchedShapeSim->getID()); + prefetchedShapeSim = nextShapeSim; + mNbGeometries[sc.getGeometryType()]++; + + + mLLContext->getNphaseImplementationContext()->registerShape(sc.getCore()); + } +} + +void Sc::Scene::addStatic(PxActor* actor, BatchInsertionState& s, PxBounds3* outBounds) +{ + // static core has been prefetched by caller + Sc::StaticSim* sim = s.staticSim; // static core has been prefetched by the caller + + const Cm::PtrTable* shapeTable = Ps::pointerOffset<const Cm::PtrTable*>(actor, s.staticShapeTableOffset); + void*const* shapes = shapeTable->getPtrs(); + if(shapeTable->getCount()) + Ps::prefetch(shapes[0],PxU32(s.shapeOffset+sizeof(Sc::ShapeCore))); + + mStaticSimPool->construct(sim, *this, *Ps::pointerOffset<Sc::StaticCore*>(actor, s.staticActorOffset)); + s.staticSim = mStaticSimPool->allocateAndPrefetch(); + + addShapes(shapes, shapeTable->getCount(), size_t(s.shapeOffset), *sim, s.shapeSim, outBounds); + mNbRigidStatics++; +} + +void Sc::Scene::addBody(PxActor* actor, BatchInsertionState& s, PxBounds3* outBounds) +{ + Sc::BodySim* sim = s.bodySim; // body core has been prefetched by the caller + + const Cm::PtrTable* shapeTable = Ps::pointerOffset<const Cm::PtrTable*>(actor, s.dynamicShapeTableOffset); + void*const* shapes = shapeTable->getPtrs(); + if(shapeTable->getCount()) + Ps::prefetch(shapes[0], PxU32(s.shapeOffset+sizeof(Sc::ShapeCore))); + + mBodySimPool->construct(sim, *this, *Ps::pointerOffset<Sc::BodyCore*>(actor, s.dynamicActorOffset)); + s.bodySim = mBodySimPool->allocateAndPrefetch(); + + if (sim->isArticulationLink()) + { + if (sim->getLowLevelBody().mCore->mFlags & PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD) + mSpeculativeCDDArticulationBitMap.growAndSet(sim->getNodeIndex().index()); + } + else + { + if (sim->getLowLevelBody().mCore->mFlags & PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD) + mSpeculativeCCDRigidBodyBitMap.growAndSet(sim->getNodeIndex().index()); + } + + mSimulationController->addDynamic(&sim->getLowLevelBody(), sim->getNodeIndex().index()); + + addShapes(shapes, shapeTable->getCount(), size_t(s.shapeOffset), *sim, s.shapeSim, outBounds); + mNbRigidDynamics++; +} + +void Sc::Scene::finishBatchInsertion(BatchInsertionState& state) +{ + // a little bit lazy - we could deal with the last one in the batch specially to avoid overallocating by one. + + mStaticSimPool->releasePreallocated(static_cast<Sc::StaticSim*>(state.staticSim)); + mBodySimPool->releasePreallocated(static_cast<Sc::BodySim*>(state.bodySim)); + mShapeSimPool->releasePreallocated(state.shapeSim); +} + +void Sc::Scene::initContactsIterator(ContactIterator& contactIterator, PxsContactManagerOutputIterator& outputs) +{ + outputs = mLLContext->getNphaseImplementationContext()->getContactManagerOutputs(); + Interaction** first = mInteractions[Sc::InteractionType::eOVERLAP].begin(); + contactIterator = ContactIterator(first, first + mActiveInteractionCount[Sc::InteractionType::eOVERLAP], outputs); +} + +void Sc::Scene::setDominanceGroupPair(PxDominanceGroup group1, PxDominanceGroup group2, const PxDominanceGroupPair& dominance) +{ + struct { + void operator()(PxU32& bits, PxDominanceGroup shift, PxReal weight) + { + if(weight != PxReal(0)) + bits |= (PxU32(1) << shift); + else + bits &= ~(PxU32(1) << shift); + } + } bitsetter; + + bitsetter(mDominanceBitMatrix[group1], group2, dominance.dominance0); + bitsetter(mDominanceBitMatrix[group2], group1, dominance.dominance1); + + mInternalFlags |= SceneInternalFlag::eSCENE_SIP_STATES_DIRTY_DOMINANCE; //force an update on all interactions on matrix change -- very expensive but we have no choice!! +} + + +PxDominanceGroupPair Sc::Scene::getDominanceGroupPair(PxDominanceGroup group1, PxDominanceGroup group2) const +{ + PxU8 dom0 = PxU8((mDominanceBitMatrix[group1]>>group2) & 0x1 ? 1u : 0u); + PxU8 dom1 = PxU8((mDominanceBitMatrix[group2]>>group1) & 0x1 ? 1u : 0u); + return PxDominanceGroupPair(dom0, dom1); +} + +void Sc::Scene::setCreateContactReports(bool s) +{ + if(mLLContext) + mLLContext->setCreateContactStream(s); +} + +void Sc::Scene::setSolverBatchSize(PxU32 solverBatchSize) +{ + mDynamicsContext->setSolverBatchSize(solverBatchSize); +} + + +PxU32 Sc::Scene::getSolverBatchSize() const +{ + return mDynamicsContext->getSolverBatchSize(); +} + + +void Sc::Scene::setVisualizationParameter(PxVisualizationParameter::Enum param, PxReal value) +{ + mVisualizationParameterChanged = true; + + PX_ASSERT(mLLContext->getVisualizationParameter(PxVisualizationParameter::eSCALE) == mVisualizationScale); // Safety check because the scale is duplicated for performance reasons + + mLLContext->setVisualizationParameter(param, value); + + if (param == PxVisualizationParameter::eSCALE) + mVisualizationScale = value; +} + + +PxReal Sc::Scene::getVisualizationParameter(PxVisualizationParameter::Enum param) const +{ + PX_ASSERT(mLLContext->getVisualizationParameter(PxVisualizationParameter::eSCALE) == mVisualizationScale); // Safety check because the scale is duplicated for performance reasons + + return mLLContext->getVisualizationParameter(param); +} + + +void Sc::Scene::setVisualizationCullingBox(const PxBounds3& box) +{ + mLLContext->setVisualizationCullingBox(box); +} + +const PxBounds3& Sc::Scene::getVisualizationCullingBox() const +{ + return mLLContext->getVisualizationCullingBox(); +} + +PxReal Sc::Scene::getFrictionOffsetThreshold() const +{ + return mDynamicsContext->getFrictionOffsetThreshold(); +} + +PxU32 Sc::Scene::getDefaultContactReportStreamBufferSize() const +{ + return mNPhaseCore->getDefaultContactReportStreamBufferSize(); +} + +PX_DEPRECATED static PX_FORCE_INLINE void buildActiveTransform(Sc::BodyCore*const PX_RESTRICT body, Sc::Client** PX_RESTRICT clients, const PxU32 numClients) +{ + if(!body->isFrozen()) + { + PxRigidActor* ra = static_cast<PxRigidActor*>(body->getPxActor()); + PX_ASSERT(ra != NULL); + + PxActiveTransform activeTransform; + + activeTransform.actor = ra; + activeTransform.userData = ra->userData; + activeTransform.actor2World = ra->getGlobalPose(); + + PxClientID client = body->getOwnerClient(); + PX_ASSERT(client < numClients); + PX_UNUSED(numClients); + + const PxU32 clientActiveTransformsSize = clients[client]->activeTransforms.size(); + clients[client]->activeTransforms.pushBack(activeTransform); + Ps::prefetchLine(reinterpret_cast<void*>((reinterpret_cast<size_t>(clients[client]->activeTransforms.begin() + clientActiveTransformsSize + 1) + 128) & ~127)); + } +} + +PX_DEPRECATED void Sc::Scene::buildActiveTransforms() +{ + PxU32 numActiveBodies; + BodyCore*const* PX_RESTRICT activeBodies; + if (!(getPublicFlags() & PxSceneFlag::eEXCLUDE_KINEMATICS_FROM_ACTIVE_ACTORS)) + { + numActiveBodies = getNumActiveBodies(); + activeBodies = getActiveBodiesArray(); + } + else + { + numActiveBodies = getActiveDynamicBodiesCount(); + activeBodies = getActiveDynamicBodies(); + } + + Client** PX_RESTRICT clients = mClients.begin(); + const PxU32 numClients = mClients.size(); + + Ps::prefetchLine(activeBodies); + + for (PxU32 i = 0; i < numClients; i++) + { + clients[i]->activeTransforms.clear(); + Ps::prefetchLine(reinterpret_cast<void*>((reinterpret_cast<size_t>(mClients[i]->activeTransforms.begin()) + 0) & ~127)); + Ps::prefetchLine(reinterpret_cast<void*>((reinterpret_cast<size_t>(mClients[i]->activeTransforms.begin()) + 128) & ~127)); + } + + const PxU32 numActiveBodies32 = numActiveBodies & ~31; + + for(PxU32 i=0;i<numActiveBodies32;i+=32) + { + Ps::prefetchLine(activeBodies+32); + + for(PxU32 j=0;j<32;j++) + { + // handle case where numActiveBodies is a multiple of 32 + // and we need to avoid reading one past end of the array + if (i+j < numActiveBodies-1) + Ps::prefetchLine(activeBodies[i+j+1]); + + buildActiveTransform(activeBodies[i+j],clients,numClients); + } + } + + for(PxU32 i=numActiveBodies32;i<numActiveBodies;i++) + { + if (i < numActiveBodies-1) + Ps::prefetchLine(activeBodies[i+1]); + + buildActiveTransform(activeBodies[i],clients,numClients); + } +} + +PX_DEPRECATED PxActiveTransform* Sc::Scene::getActiveTransforms(PxU32& nbTransformsOut, PxClientID client) +{ + PX_ASSERT(client < mClients.size()); + + const PxU32 nb = mClients[client]->activeTransforms.size(); + nbTransformsOut = nb; + if(!nb) + return NULL; + + return mClients[client]->activeTransforms.begin(); +} + +void Sc::Scene::buildActiveActors() +{ + PxU32 numActiveBodies; + BodyCore*const* PX_RESTRICT activeBodies; + if (!(getPublicFlags() & PxSceneFlag::eEXCLUDE_KINEMATICS_FROM_ACTIVE_ACTORS)) + { + numActiveBodies = getNumActiveBodies(); + activeBodies = getActiveBodiesArray(); + } + else + { + numActiveBodies = getActiveDynamicBodiesCount(); + activeBodies = getActiveDynamicBodies(); + } + + Client** PX_RESTRICT clients = mClients.begin(); + const PxU32 numClients = mClients.size(); + + for (PxU32 i = 0; i < numClients; i++) + clients[i]->activeActors.clear(); + + for(PxU32 i=0; i<numActiveBodies; i++) + { + if(!activeBodies[i]->isFrozen()) + { + PxRigidActor* ra = static_cast<PxRigidActor*>(activeBodies[i]->getPxActor()); + PX_ASSERT(ra != NULL); + + const PxClientID client = activeBodies[i]->getOwnerClient(); + PX_ASSERT(client < numClients); + PX_UNUSED(numClients); + + clients[client]->activeActors.pushBack(ra); + } + } +} + +PxActor** Sc::Scene::getActiveActors(PxU32& nbActorsOut, PxClientID client) +{ + PX_ASSERT(client < mClients.size()); + + nbActorsOut = mClients[client]->activeActors.size(); + + if(nbActorsOut == 0) + { + return NULL; + } + return mClients[client]->activeActors.begin(); +} + +void Sc::Scene::reserveTriggerReportBufferSpace(const PxU32 pairCount, PxTriggerPair*& triggerPairBuffer, TriggerPairExtraData*& triggerPairExtraBuffer) +{ + const PxU32 oldSize = mTriggerBufferAPI.size(); + const PxU32 newSize = oldSize + pairCount; + const PxU32 newCapacity = PxU32(newSize * 1.5f); + mTriggerBufferAPI.reserve(newCapacity); + mTriggerBufferAPI.forceSize_Unsafe(newSize); + triggerPairBuffer = mTriggerBufferAPI.begin() + oldSize; + + PX_ASSERT(oldSize == mTriggerBufferExtraData->size()); + mTriggerBufferExtraData->reserve(newCapacity); + mTriggerBufferExtraData->forceSize_Unsafe(newSize); + triggerPairExtraBuffer = mTriggerBufferExtraData->begin() + oldSize; +} + +PxClientID Sc::Scene::createClient() +{ + mClients.pushBack(PX_NEW(Client)()); + return PxClientID(mClients.size()-1); +} + +void Sc::Scene::setClientBehaviorFlags(PxClientID client, PxClientBehaviorFlags clientBehaviorFlags) +{ + PX_ASSERT(client < mClients.size()); + mClients[client]->behaviorFlags = clientBehaviorFlags; +} + +PxClientBehaviorFlags Sc::Scene::getClientBehaviorFlags(PxClientID client) const +{ + PX_ASSERT(client < mClients.size()); + return mClients[client]->behaviorFlags; +} + +#if PX_USE_CLOTH_API + +void Sc::Scene::setClothInterCollisionDistance(PxF32 distance) +{ + PX_ASSERT(*mClothSolvers); + for(PxU32 i=0; i<mNumClothSolvers; ++i) + { + if(mClothSolvers[i]) + mClothSolvers[i]->setInterCollisionDistance(distance); + } +} + +PxF32 Sc::Scene::getClothInterCollisionDistance() const +{ + PX_ASSERT(*mClothSolvers); + return mClothSolvers[0]->getInterCollisionDistance(); +} + +void Sc::Scene::setClothInterCollisionStiffness(PxF32 stiffness) +{ + PX_ASSERT(*mClothSolvers); + for(PxU32 i=0; i<mNumClothSolvers; ++i) + { + if(mClothSolvers[i]) + mClothSolvers[i]->setInterCollisionStiffness(stiffness); + } +} + +PxF32 Sc::Scene::getClothInterCollisionStiffness() const +{ + PX_ASSERT(*mClothSolvers); + return mClothSolvers[0]->getInterCollisionStiffness(); +} + +void Sc::Scene::setClothInterCollisionNbIterations(PxU32 nbIterations) +{ + PX_ASSERT(*mClothSolvers); + for(PxU32 i=0; i<mNumClothSolvers; ++i) + { + if(mClothSolvers[i]) + mClothSolvers[i]->setInterCollisionNbIterations(nbIterations); + } +} + +PxU32 Sc::Scene::getClothInterCollisionNbIterations() const +{ + PX_ASSERT(*mClothSolvers); + return mClothSolvers[0]->getInterCollisionNbIterations(); +} + +#endif // #if PX_USE_CLOTH_API + +void Sc::Scene::clearSleepWakeBodies(void) +{ + // Clear sleep/woken marker flags + BodyCore* const* sleepingBodies = mSleepBodies.getEntries(); + for(PxU32 i=0; i < mSleepBodies.size(); i++) + { + BodySim* body = sleepingBodies[i]->getSim(); + + PX_ASSERT(!body->readInternalFlag(BodySim::BF_WAKEUP_NOTIFY)); + body->clearInternalFlag(BodySim::BF_SLEEP_NOTIFY); + + // A body can be in both lists depending on the sequence of events + body->clearInternalFlag(BodySim::BF_IS_IN_SLEEP_LIST); + body->clearInternalFlag(BodySim::BF_IS_IN_WAKEUP_LIST); + } + + BodyCore* const* wokenBodies = mWokeBodies.getEntries(); + for(PxU32 i=0; i < mWokeBodies.size(); i++) + { + BodySim* body = wokenBodies[i]->getSim(); + + PX_ASSERT(!body->readInternalFlag(BodySim::BF_SLEEP_NOTIFY)); + body->clearInternalFlag(BodySim::BF_WAKEUP_NOTIFY); + + // A body can be in both lists depending on the sequence of events + body->clearInternalFlag(BodySim::BF_IS_IN_SLEEP_LIST); + body->clearInternalFlag(BodySim::BF_IS_IN_WAKEUP_LIST); + } + + mSleepBodies.clear(); + mWokeBodies.clear(); + mWokeBodyListValid = true; + mSleepBodyListValid = true; +} + + +void Sc::Scene::onBodySleep(BodySim* body) +{ + //temp: TODO: Add support for other clients + PxSimulationEventCallback* simulationEventCallback = mClients[PX_DEFAULT_CLIENT]->simulationEventCallback; + + if (simulationEventCallback) + { + if (body->readInternalFlag(BodySim::BF_WAKEUP_NOTIFY)) + { + PX_ASSERT(!body->readInternalFlag(BodySim::BF_SLEEP_NOTIFY)); + + // Body is in the list of woken bodies, hence, mark this list as dirty such that it gets cleaned up before + // being sent to the user + body->clearInternalFlag(BodySim::BF_WAKEUP_NOTIFY); + mWokeBodyListValid = false; + } + + body->raiseInternalFlag(BodySim::BF_SLEEP_NOTIFY); + + // Avoid multiple insertion (the user can do multiple transitions between asleep and awake) + if (!body->readInternalFlag(BodySim::BF_IS_IN_SLEEP_LIST)) + { + PX_ASSERT(!mSleepBodies.contains(&body->getBodyCore())); + mSleepBodies.insert(&body->getBodyCore()); + body->raiseInternalFlag(BodySim::BF_IS_IN_SLEEP_LIST); + } + } + else + { + // even if no sleep events are requested, we still need to track the objects which were put to sleep because + // for those we need to sync the buffered state (strictly speaking this only applies to sleep changes that are + // triggered by the simulation and not the user but we do not distinguish here) + if (!body->readInternalFlag(BodySim::BF_IS_IN_SLEEP_LIST)) + mSleepBodies.insert(&body->getBodyCore()); + body->raiseInternalFlag(BodySim::BF_IS_IN_SLEEP_LIST); + } +} + + +void Sc::Scene::onBodyWakeUp(BodySim* body) +{ + //temp: TODO: Add support for other clients + PxSimulationEventCallback* simulationEventCallback = mClients[PX_DEFAULT_CLIENT]->simulationEventCallback; + + if (!simulationEventCallback) + return; + + if (body->readInternalFlag(BodySim::BF_SLEEP_NOTIFY)) + { + PX_ASSERT(!body->readInternalFlag(BodySim::BF_WAKEUP_NOTIFY)); + + // Body is in the list of sleeping bodies, hence, mark this list as dirty such it gets cleaned up before + // being sent to the user + body->clearInternalFlag(BodySim::BF_SLEEP_NOTIFY); + mSleepBodyListValid = false; + } + + body->raiseInternalFlag(BodySim::BF_WAKEUP_NOTIFY); + + // Avoid multiple insertion (the user can do multiple transitions between asleep and awake) + if (!body->readInternalFlag(BodySim::BF_IS_IN_WAKEUP_LIST)) + { + PX_ASSERT(!mWokeBodies.contains(&body->getBodyCore())); + mWokeBodies.insert(&body->getBodyCore()); + body->raiseInternalFlag(BodySim::BF_IS_IN_WAKEUP_LIST); + } +} + + +PX_INLINE void Sc::Scene::cleanUpSleepBodies() +{ + BodyCore* const* bodyArray = mSleepBodies.getEntries(); + PxU32 bodyCount = mSleepBodies.size(); + + IG::IslandSim& islandSim = mSimpleIslandManager->getAccurateIslandSim(); + + while (bodyCount--) + { + BodySim* body = bodyArray[bodyCount]->getSim(); + + if (body->readInternalFlag(static_cast<BodySim::InternalFlags>(BodySim::BF_WAKEUP_NOTIFY))) + { + body->clearInternalFlag(static_cast<BodySim::InternalFlags>(BodySim::BF_IS_IN_WAKEUP_LIST)); + mSleepBodies.erase(bodyArray[bodyCount]); + } + else if (islandSim.getNode(body->getNodeIndex()).isActive()) + { + //This body is still active in the island simulation, so the request to deactivate the actor by the application must have failed. Recover by undoing this + mSleepBodies.erase(bodyArray[bodyCount]); + body->internalWakeUp(); + + } + } + + mSleepBodyListValid = true; + +} + + +PX_INLINE void Sc::Scene::cleanUpWokenBodies() +{ + cleanUpSleepOrWokenBodies(mWokeBodies, BodySim::BF_SLEEP_NOTIFY, mWokeBodyListValid); +} + + +PX_INLINE void Sc::Scene::cleanUpSleepOrWokenBodies(Ps::CoalescedHashSet<BodyCore*>& bodyList, PxU32 removeFlag, bool& validMarker) +{ + // With our current logic it can happen that a body is added to the sleep as well as the woken body list in the + // same frame. + // + // Examples: + // - Kinematic is created (added to woken list) but has not target (-> deactivation -> added to sleep list) + // - Dynamic is created (added to woken list) but is forced to sleep by user (-> deactivation -> added to sleep list) + // + // This code traverses the sleep/woken body list and removes bodies which have been initially added to the given + // list but do not belong to it anymore. + + BodyCore* const* bodyArray = bodyList.getEntries(); + PxU32 bodyCount = bodyList.size(); + while (bodyCount--) + { + BodySim* body = bodyArray[bodyCount]->getSim(); + + if (body->readInternalFlag(static_cast<BodySim::InternalFlags>(removeFlag))) + bodyList.erase(bodyArray[bodyCount]); + } + + validMarker = true; +} + + +void Sc::Scene::releaseConstraints(bool endOfScene) +{ + PX_ASSERT(mLLContext); + + if(getStabilizationEnabled()) + { + //If stabilization is enabled, we're caching contacts for next frame + if(!endOfScene) + { + //So we only clear memory (flip buffers) when not at the end-of-scene. + //This means we clear after narrow phase completed so we can + //release the previous frame's contact buffers before we enter the solve phase. + mLLContext->getNpMemBlockPool().releaseContacts(); + } + } + else if(endOfScene) + { + //We now have a double-buffered pool of mem blocks so we must + //release both pools (which actually triggers the memory used this + //frame to be released + mLLContext->getNpMemBlockPool().releaseContacts(); + mLLContext->getNpMemBlockPool().releaseContacts(); + } +} + + +PX_INLINE void Sc::Scene::clearBrokenConstraintBuffer() +{ + mBrokenConstraints.clear(); +} + + +void Sc::Scene::updateFromVisualizationParameters() +{ + if (!mVisualizationParameterChanged) // All up to date + return; + + // Update SIPs if visualization is enabled + if (getVisualizationParameter(PxVisualizationParameter::eCONTACT_POINT) || getVisualizationParameter(PxVisualizationParameter::eCONTACT_NORMAL) || + getVisualizationParameter(PxVisualizationParameter::eCONTACT_ERROR) || getVisualizationParameter(PxVisualizationParameter::eCONTACT_FORCE)) + mInternalFlags |= SceneInternalFlag::eSCENE_SIP_STATES_DIRTY_VISUALIZATION; + + mVisualizationParameterChanged = false; +} + + +bool Sc::Scene::isValid() const +{ + return (mLLContext != NULL); +} + + +void Sc::Scene::addToLostTouchList(BodySim* body1, BodySim* body2) +{ + PX_ASSERT(body1 != 0); + PX_ASSERT(body2 != 0); + SimpleBodyPair p = { body1, body2, body1->getID(), body2->getID() }; + mLostTouchPairs.pushBack(p); +} + + +void Sc::Scene::initDominanceMatrix() +{ + //init all dominance pairs such that: + //if g1 == g2, then (1.0f, 1.0f) is returned + //if g1 < g2, then (0.0f, 1.0f) is returned + //if g1 > g2, then (1.0f, 0.0f) is returned + + PxU32 mask = ~PxU32(1); + for (unsigned i = 0; i < PX_MAX_DOMINANCE_GROUP; ++i, mask <<= 1) + mDominanceBitMatrix[i] = ~mask; +} + +Articulation* Sc::Scene::createLLArticulation(Sc::ArticulationSim* sim) +{ + return mLLArticulationPool->construct(sim); +} + + +void Sc::Scene::destroyLLArticulation(Articulation& articulation) +{ + mLLArticulationPool->destroy(&articulation); +} + + +#if PX_USE_PARTICLE_SYSTEM_API + +void Sc::Scene::addParticleSystem(ParticleSystemCore& ps) +{ + // sim objects do all the necessary work of adding themselves to broad phase, + // activation, registering with the interaction system, etc + + ParticleSystemSim* psSim = PX_NEW(ParticleSystemSim)(*this, ps); + + if (!psSim) + { + getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __LINE__, "PxScene::addParticleSystem() failed."); + return; + } + + PX_ASSERT(ps.getSim()); + + mParticleSystems.insert(&ps); +} + + +void Sc::Scene::removeParticleSystem(ParticleSystemCore& ps, bool isRelease) +{ + const bool exists = mParticleSystems.erase(&ps); + PX_ASSERT(exists); + PX_UNUSED(exists); + ps.getSim()->release(isRelease); +} + + +PxU32 Sc::Scene::getNbParticleSystems() const +{ + return mParticleSystems.size(); +} + + +Sc::ParticleSystemCore* const* Sc::Scene::getParticleSystems() +{ + return mParticleSystems.getEntries(); +} +#endif // PX_USE_PARTICLE_SYSTEM_API + +bool Sc::Scene::hasParticleSystems() const +{ +#if PX_USE_PARTICLE_SYSTEM_API + return !mEnabledParticleSystems.empty(); +#else + return false; +#endif +} + +PxSceneGpu* Sc::Scene::getSceneGpu(bool createIfNeeded) +{ +#if PX_USE_PARTICLE_SYSTEM_API && PX_SUPPORT_GPU_PHYSX + if (mParticleContext) + { + if(createIfNeeded) + return mParticleContext->createOrGetSceneGpu(); + else + return mParticleContext->getSceneGpuFast(); + } + return NULL; +#else + { + PX_UNUSED(createIfNeeded); + return NULL; + } +#endif +} + +#if PX_USE_CLOTH_API + +bool Sc::Scene::addCloth(ClothCore& clothCore) +{ + // sim objects do all the necessary work of adding themselves to broad phase, + // activation, registering with the interaction system, etc + + cloth::Cloth* cloth = clothCore.getLowLevelCloth(); + PxU32 type = clothCore.getClothFlags() & PxClothFlag::eCUDA; + PX_ASSERT(type < mNumClothSolvers); + + if(type) + { + if(cloth::Cloth* clone = mClothSolvers[type] ? mClothFactories[type]->clone(*cloth) : NULL) + { + clothCore.switchCloth(cloth = clone); + } + else + { + // clone failed, warn and fallback to CPU + getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, + "GPU cloth creation failed. Falling back to CPU implementation."); + + clothCore.setClothFlags(clothCore.getClothFlags() & ~PxClothFlag::Enum(type)); + type = 0; + } + } + + mClothSolvers[type]->addCloth(cloth); + mCloths.insert(&clothCore); + + PX_NEW(ClothSim)(*this, clothCore); + + return true; // always returns true, remove return value +} + +void Sc::Scene::removeCloth(ClothCore& clothCore) +{ + const bool exists = mCloths.erase(&clothCore); + PX_ASSERT(exists); + PX_UNUSED(exists); + + clothCore.getSim()->clearCollisionShapes(); + + cloth::Cloth* cloth = clothCore.getLowLevelCloth(); + PxU32 type = cloth->getFactory().getPlatform(); + + // platform and cloth flag need to match for the above to work + PX_COMPILE_TIME_ASSERT(PxU32(cloth::Factory::CUDA) == PxU32(PxClothFlag::eCUDA)); + + mClothSolvers[type]->removeCloth(cloth); + + if(type) + clothCore.switchCloth(mClothFactories[0]->clone(*cloth)); + + PX_DELETE(clothCore.getSim()); +} + +void Sc::Scene::createClothSolver() +{ + if(*mClothSolvers) + return; // already called before + + if(Sc::Physics::getInstance().hasLowLevelClothFactory()) + mClothFactories[0] = &Sc::Physics::getInstance().getLowLevelClothFactory(); + + if (mTaskManager && mTaskManager->getGpuDispatcher()) + { +#if PX_SUPPORT_GPU_PHYSX + mClothFactories[PxClothFlag::eCUDA] = PxvGetPhysXGpu(true)->createClothFactory( + cloth::Factory::CUDA, mTaskManager->getGpuDispatcher()->getCudaContextManager()); +#endif + } + + for(PxU32 i=0; i<mNumClothSolvers; ++i) + { + if(mClothFactories[i]) + mClothSolvers[i] = mClothFactories[i]->createSolver(mTaskManager); + if(mClothSolvers[i]) + mClothSolvers[i]->setInterCollisionFilter(Sc::DefaultClothInterCollisionFilter); + } +} + +#endif // PX_USE_CLOTH_API + +bool Sc::Scene::hasCloths() const +{ +#if PX_USE_CLOTH_API + return (mCloths.size() > 0); +#else + return false; +#endif +} + +PxU32 Sc::Scene::getNbArticulations() const +{ + return mArticulations.size(); +} + +Sc::ArticulationCore* const* Sc::Scene::getArticulations() +{ + return mArticulations.getEntries(); +} + +PxU32 Sc::Scene::getNbConstraints() const +{ + return mConstraints.size(); +} + +Sc::ConstraintCore*const * Sc::Scene::getConstraints() +{ + return mConstraints.getEntries(); +} + + + + +// PX_AGGREGATE +PxU32 Sc::Scene::createAggregate(void* userData, bool selfCollisions) +{ + const physx::Bp::BoundsIndex index = getElementIDPool().createID(); + mBoundsArray->initEntry(index); + return mAABBManager->createAggregate(index, userData, selfCollisions); +} + +void Sc::Scene::deleteAggregate(PxU32 id) +{ + const physx::Bp::BoundsIndex index = mAABBManager->destroyAggregate(id); + getElementIDPool().releaseID(index); +} + +//~PX_AGGREGATE +void Sc::Scene::shiftOrigin(const PxVec3& shift) +{ + // + // adjust low level context + // + mLLContext->shiftOrigin(shift); + + // adjust bounds array + // + mBoundsArray->shiftOrigin(shift); + + // + // adjust broadphase + // + mAABBManager->shiftOrigin(shift); + + // + // adjust active transforms + // + Client** PX_RESTRICT clients = mClients.begin(); + const PxU32 numClients = mClients.size(); + const PxU32 prefetchLookAhead = 6; // fits more or less into 2x128 byte prefetches + + for (PxU32 c = 0; c < numClients; c++) + { + PxActiveTransform* activeTransform = clients[c]->activeTransforms.begin(); + const PxU32 activeTransformCount = clients[c]->activeTransforms.size(); + + PxU32 batchIterCount = activeTransformCount / prefetchLookAhead; + + PxU32 idx = 0; + PxU8* prefetchPtr = reinterpret_cast<PxU8*>(activeTransform) + 256; + for(PxU32 i=0; i < batchIterCount; i++) + { + Ps::prefetchLine(prefetchPtr); + Ps::prefetchLine(prefetchPtr + 128); + + for(PxU32 j=idx; j < (idx + prefetchLookAhead); j++) + { + activeTransform[j].actor2World.p -= shift; + } + + idx += prefetchLookAhead; + prefetchPtr += 256; + } + // process remaining objects + for(PxU32 i=idx; i < activeTransformCount; i++) + { + activeTransform[i].actor2World.p -= shift; + } + } + + // + // adjust constraints + // + ConstraintCore*const * constraints = mConstraints.getEntries(); + for(PxU32 i=0, size = mConstraints.size(); i < size; i++) + { + constraints[i]->getPxConnector()->onOriginShift(shift); + } + + // + // adjust cloth + // +#if PX_USE_CLOTH_API + ClothCore* const* clothList = mCloths.getEntries(); + for(PxU32 i=0; i < mCloths.size(); i++) + { + clothList[i]->onOriginShift(shift); + } +#endif + + // + // adjust particles + // +#if PX_USE_PARTICLE_SYSTEM_API + PxU32 count = mParticleSystems.size(); + ParticleSystemCore* const* partList = mParticleSystems.getEntries(); + for(PxU32 i=0; i < count; i++) + { + ParticleSystemCore* ps = partList[i]; + ps->getSim()->release(false); + ps->onOriginShift(shift); + ParticleSystemSim* psSim = PX_NEW(ParticleSystemSim)(*this, *ps); + if (!psSim) + { + getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __LINE__, "PxScene::shiftOrigin() failed for particle system."); + } + PX_ASSERT(ps->getSim()); + } +#endif +} + +/////////////////////////////////////////////////////////////////////////////// + +void Sc::Scene::islandInsertion(PxBaseTask* /*continuation*/) +{ + { + PX_PROFILE_ZONE("Sim.processNewOverlaps.islandInsertion", getContextId()); + + const PxU32 nbShapeIdxCreated = mPreallocatedShapeInteractions.size(); + for (PxU32 a = 0; a < nbShapeIdxCreated; ++a) + { + size_t address = reinterpret_cast<size_t>(mPreallocatedShapeInteractions[a]); + if (address & 1) + { + ShapeInteraction* interaction = reinterpret_cast<ShapeInteraction*>(address&size_t(~1)); + + PxsContactManager* contactManager = const_cast<PxsContactManager*>(interaction->getContactManager()); + + Sc::BodySim* bs0 = interaction->getShape0().getBodySim(); + Sc::BodySim* bs1 = interaction->getShape1().getBodySim(); + + IG::NodeIndex nodeIndexB; + if (bs1) + nodeIndexB = bs1->getNodeIndex(); + + IG::EdgeIndex edgeIdx = mSimpleIslandManager->addContactManager(contactManager, bs0->getNodeIndex(), nodeIndexB, interaction); + interaction->mEdgeIndex = edgeIdx; + + if (contactManager) + contactManager->getWorkUnit().mEdgeIndex = edgeIdx; + } + } + + // - Wakes actors that lost touch if appropriate + processLostTouchPairs(); + + if(mCCDPass == 0) + { + mSimpleIslandManager->firstPassIslandGen(); + } + } +} + +void Sc::Scene::registerContactManagers(PxBaseTask* /*continuation*/) +{ + { + PxvNphaseImplementationContext* nphaseContext = mLLContext->getNphaseImplementationContext(); + PX_PROFILE_ZONE("Sim.processNewOverlaps.registerCms", getContextId()); + //nphaseContext->registerContactManagers(mPreallocatedContactManagers.begin(), mPreallocatedContactManagers.size(), mLLContext->getContactManagerPool().getMaxUsedIndex()); + const PxU32 nbCmsCreated = mPreallocatedContactManagers.size(); + for (PxU32 a = 0; a < nbCmsCreated; ++a) + { + size_t address = reinterpret_cast<size_t>(mPreallocatedContactManagers[a]); + if (address & 1) + { + PxsContactManager* cm = reinterpret_cast<PxsContactManager*>(address&size_t(~1)); + nphaseContext->registerContactManager(cm, 0, 0); + } + } + + } +} + +void Sc::Scene::registerInteractions(PxBaseTask* /*continuation*/) +{ + { + PX_PROFILE_ZONE("Sim.processNewOverlaps.registerInteractions", getContextId()); + const PxU32 nbShapeIdxCreated = mPreallocatedShapeInteractions.size(); + for (PxU32 a = 0; a < nbShapeIdxCreated; ++a) + { + size_t address = reinterpret_cast<size_t>(mPreallocatedShapeInteractions[a]); + if (address & 1) + { + ShapeInteraction* interaction = reinterpret_cast<ShapeInteraction*>(address&size_t(~1)); + + Sc::BodySim* bs0 = interaction->getShape0().getBodySim(); + Sc::BodySim* bs1 = interaction->getShape1().getBodySim(); + + bs0->registerInteraction(interaction); + bs0->registerCountedInteraction(); + + interaction->getActor1().registerInteraction(interaction); + + if (bs1) + bs1->registerCountedInteraction(); + } + } + + const PxU32 nbMarkersCreated = mPreallocatedInteractionMarkers.size(); + for (PxU32 a = 0; a < nbMarkersCreated; ++a) + { + size_t address = reinterpret_cast<size_t>(mPreallocatedInteractionMarkers[a]); + if (address & 1) + { + ElementInteractionMarker* interaction = reinterpret_cast<ElementInteractionMarker*>(address&size_t(~1)); + interaction->registerInActors(NULL); + } + } + } +} + +void Sc::Scene::registerSceneInteractions(PxBaseTask* /*continuation*/) +{ + PX_PROFILE_ZONE("Sim.processNewOverlaps.registerInteractionsScene", getContextId()); + const PxU32 nbShapeIdxCreated = mPreallocatedShapeInteractions.size(); + for (PxU32 a = 0; a < nbShapeIdxCreated; ++a) + { + size_t address = reinterpret_cast<size_t>(mPreallocatedShapeInteractions[a]); + if (address & 1) + { + ShapeInteraction* interaction = reinterpret_cast<ShapeInteraction*>(address&size_t(~1)); + registerInteraction(interaction, interaction->getContactManager() != NULL); + mNPhaseCore->registerInteraction(interaction); + + const PxsContactManager* cm = interaction->getContactManager(); + if (cm != NULL) + { + mLLContext->setActiveContactManager(cm); + } + } + } + + const PxU32 nbInteractionMarkers = mPreallocatedInteractionMarkers.size(); + for (PxU32 a = 0; a < nbInteractionMarkers; ++a) + { + size_t address = reinterpret_cast<size_t>(mPreallocatedInteractionMarkers[a]); + if (address & 1) + { + ElementInteractionMarker* interaction = reinterpret_cast<ElementInteractionMarker*>(address&size_t(~1)); + registerInteraction(interaction, false); + mNPhaseCore->registerInteraction(interaction); + } + } +} + +class OverlapFilterTask : public Cm::Task +{ +public: + static const PxU32 MaxPairs = 512; + Sc::NPhaseCore* mNPhaseCore; + const Bp::AABBOverlap* PX_RESTRICT mPairs; + + Bp::BroadPhasePair* mBpPairs; + PxU32 mNbToProcess; + + PxU32 mKeepMap[MaxPairs/32]; + PxU32 mCallbackMap[MaxPairs/32]; + + PxFilterInfo* mFinfo; + + PxU32 mNbToKeep; + PxU32 mNbToSuppress; + PxU32 mNbToCallback; + + OverlapFilterTask(Sc::NPhaseCore* nPhaseCore, PxFilterInfo* fInfo, const Bp::AABBOverlap* PX_RESTRICT pairs, Bp::BroadPhasePair* bpPairs, const PxU32 nbToProcess) : mNPhaseCore(nPhaseCore), + mPairs(pairs), mBpPairs(bpPairs), mNbToProcess(nbToProcess), mFinfo(fInfo), mNbToKeep(0), mNbToSuppress(0), mNbToCallback(0) + { + PxMemZero(mKeepMap, sizeof(mKeepMap)); + PxMemZero(mCallbackMap, sizeof(mCallbackMap)); + } + + virtual void runInternal() + { + for(PxU32 a = 0; a < mNbToProcess; ++a) + { + const Bp::AABBOverlap& pair = mPairs[a]; + Sc::ElementSim* e0 = reinterpret_cast<Sc::ElementSim*>(pair.mUserData0); + Sc::ElementSim* e1 = reinterpret_cast<Sc::ElementSim*>(pair.mUserData1); + + Bp::BroadPhasePair* thisPair = NULL; + if(pair.mPairHandle != BP_INVALID_BP_HANDLE && mBpPairs != NULL) + thisPair = &mBpPairs[pair.mPairHandle]; + + PxFilterInfo finfo = mNPhaseCore->onOverlapFilter(e0, e1, thisPair); + + mFinfo[a] = finfo; + + if(!(finfo.filterFlags & PxFilterFlag::eKILL)) + { + if ((finfo.filterFlags & PxFilterFlag::eCALLBACK) == true) + { + mCallbackMap[a / 32] |= (1 << (a & 31)); + mNbToCallback++; + } + else + { + if ((finfo.filterFlags & PxFilterFlag::eSUPPRESS) == false) + mNbToKeep++; + else + mNbToSuppress++; + mKeepMap[a / 32] |= (1 << (a & 31)); + } + } + } + } + + virtual const char* getName() const { return "OverlapFilterTask"; } +}; + + +class OnOverlapCreatedTask : public Cm::Task +{ +public: + Sc::NPhaseCore* mNPhaseCore; + const Bp::AABBOverlap* PX_RESTRICT mPairs; + PxFilterInfo* mFinfo; + PxsContactManager** mContactManagers; + Sc::ShapeInteraction** mShapeInteractions; + Sc::ElementInteractionMarker** mInteractionMarkers; + Bp::BroadPhasePair* mBpPairs; + PxU32 mNbToProcess; + + + OnOverlapCreatedTask(Sc::NPhaseCore* nPhaseCore, const Bp::AABBOverlap* PX_RESTRICT pairs, PxFilterInfo* fInfo, PxsContactManager** contactManagers, Sc::ShapeInteraction** shapeInteractions, Sc::ElementInteractionMarker** interactionMarkers, + Bp::BroadPhasePair* bpPairs, PxU32 nbToProcess) : mNPhaseCore(nPhaseCore), mPairs(pairs), mFinfo(fInfo), mContactManagers(contactManagers), mShapeInteractions(shapeInteractions), + mInteractionMarkers(interactionMarkers), mBpPairs(bpPairs), mNbToProcess(nbToProcess) + { + } + + virtual void runInternal() + { + PxsContactManager** currentCm = mContactManagers; + Sc::ShapeInteraction** currentSI = mShapeInteractions; + Sc::ElementInteractionMarker** currentEI = mInteractionMarkers; + + for(PxU32 a = 0; a < mNbToProcess; ++a) + { + const Bp::AABBOverlap& pair = mPairs[a]; + Sc::ShapeSim* s0 = reinterpret_cast<Sc::ShapeSim*>(pair.mUserData1); + Sc::ShapeSim* s1 = reinterpret_cast<Sc::ShapeSim*>(pair.mUserData0); + + Bp::BroadPhasePair* thisPair = NULL; + if(pair.mPairHandle != BP_INVALID_BP_HANDLE && mBpPairs != NULL) + thisPair = &mBpPairs[pair.mPairHandle]; + + Sc::ElementSimInteraction* interaction = mNPhaseCore->createRbElementInteraction(mFinfo[a], *s0, *s1, *currentCm, *currentSI, *currentEI, 0); + + if(thisPair) + thisPair->mUserData = interaction; + + if(interaction) + { + if (interaction->getType() == Sc::InteractionType::eOVERLAP) + { + *currentSI = reinterpret_cast<Sc::ShapeInteraction*>(reinterpret_cast<size_t>(*currentSI) | 1); + currentSI++; + + if (static_cast<Sc::ShapeInteraction*>(interaction)->getContactManager()) + { + *currentCm = reinterpret_cast<PxsContactManager*>(reinterpret_cast<size_t>(*currentCm) | 1); + currentCm++; + } + } + else if(interaction->getType() == Sc::InteractionType::eMARKER) + { + *currentEI = reinterpret_cast<Sc::ElementInteractionMarker*>(reinterpret_cast<size_t>(*currentEI) | 1); + currentEI++; + } + } + } + + } + + virtual const char* getName() const { return "OnOverlapCreatedTask"; } + +}; + +#include <stdio.h> + +void Sc::Scene::preallocateContactManagers(PxBaseTask* continuation) +{ + //Iterate over all filter tasks and work out how many pairs we need... + + PxU32 createdOverlapCount = 0; + + PxU32 totalCreatedPairs = 0; + PxU32 totalSuppressPairs = 0; + + PxU32 overlapCount; + Bp::AABBOverlap* PX_RESTRICT p = mAABBManager->getCreatedOverlaps(Bp::VolumeBuckets::eSHAPE, overlapCount); + PxFilterInfo* fInfo = mFilterInfo.begin(); + PxU32 currentReadIdx = 0; + + for(PxU32 a = 0; a < mOverlapFilterTasks.size(); ++a) + { + OverlapFilterTask* task = mOverlapFilterTasks[a]; + + + if (task->mNbToCallback) + { + //Iterate and process callbacks. Refilter then increment the results, setting the appropriate settings + + for (PxU32 w = 0; w < (OverlapFilterTask::MaxPairs / 32); ++w) + { + for (PxU32 b = task->mCallbackMap[w]; b; b &= b - 1) + { + const PxU32 index = (w << 5) + Ps::lowestSetBit(b); + const Bp::AABBOverlap& pair = task->mPairs[index]; + Sc::ShapeSim* s0 = reinterpret_cast<Sc::ShapeSim*>(pair.mUserData0); + Sc::ShapeSim* s1 = reinterpret_cast<Sc::ShapeSim*>(pair.mUserData1); + + PxFilterInfo finfo = mNPhaseCore->filterRbCollisionPairSecondStage(*s0, *s1, s0->getBodySim(), s1->getBodySim(), INVALID_FILTER_PAIR_INDEX, true); + + task->mFinfo[index] = finfo; + + if (!(finfo.filterFlags & PxFilterFlag::eKILL)) + { + if ((finfo.filterFlags & PxFilterFlag::eSUPPRESS) == false) + task->mNbToKeep++; + else + task->mNbToSuppress++; + task->mKeepMap[index / 32] |= (1 << (index & 31)); + } + } + } + } + + totalCreatedPairs += task->mNbToKeep; + totalSuppressPairs += task->mNbToSuppress; + + } + + { + //We allocate at least 1 element in this array to ensure that the onOverlapCreated functions don't go bang! + mPreallocatedContactManagers.reserve(totalCreatedPairs); + mPreallocatedShapeInteractions.reserve(totalCreatedPairs); + mPreallocatedInteractionMarkers.reserve(totalSuppressPairs); + + mPreallocatedContactManagers.forceSize_Unsafe(totalCreatedPairs); + mPreallocatedShapeInteractions.forceSize_Unsafe(totalCreatedPairs); + mPreallocatedInteractionMarkers.forceSize_Unsafe(totalSuppressPairs); + + } + + const PxU32 nbPairsPerTask = 256; + PxsContactManager** cms = mPreallocatedContactManagers.begin(); + Sc::ShapeInteraction** shapeInter = mPreallocatedShapeInteractions.begin(); + Sc::ElementInteractionMarker** markerIter = mPreallocatedInteractionMarkers.begin(); + + Bp::BroadPhasePair* bpPairs = mAABBManager->getBroadPhase()->getBroadPhasePairs(); + + + + Cm::FlushPool& flushPool = mLLContext->getTaskPool(); + + + + OnOverlapCreatedTask* createTask = PX_PLACEMENT_NEW(flushPool.allocate(sizeof(OnOverlapCreatedTask)), OnOverlapCreatedTask)(mNPhaseCore, p, + fInfo, cms, shapeInter, markerIter, bpPairs, 0); + + PxU32 batchSize = 0; + PxU32 suppressedStartIdx = 0; + PxU32 createdStartIdx = 0; + PxU32 suppressedCurrIdx = 0; + PxU32 createdCurrIdx = 0; + + for(PxU32 a = 0; a < mOverlapFilterTasks.size(); ++a) + { + OverlapFilterTask* task = mOverlapFilterTasks[a]; + + for(PxU32 w = 0; w < (OverlapFilterTask::MaxPairs/32); ++w) + { + for(PxU32 b = task->mKeepMap[w]; b; b &= b-1) + { + const PxU32 index = (w<<5) + Ps::lowestSetBit(b); + + if(createdOverlapCount < (index + currentReadIdx)) + { + p[createdOverlapCount] = task->mPairs[index]; + fInfo[createdOverlapCount] = task->mFinfo[index]; + } + createdOverlapCount++; + batchSize++; + } + } + + suppressedCurrIdx += task->mNbToSuppress; + createdCurrIdx += task->mNbToKeep; + + if(batchSize >= nbPairsPerTask) + { + + const PxU32 nbToCreate = createdCurrIdx - createdStartIdx; + const PxU32 nbToSuppress = suppressedCurrIdx - suppressedStartIdx; + + mLLContext->getContactManagerPool().preallocate(nbToCreate, cms + createdStartIdx); + for (PxU32 i = 0; i < nbToCreate; ++i) + shapeInter[createdStartIdx + i] = mNPhaseCore->mShapeInteractionPool.allocate(); + for (PxU32 i = 0; i < nbToSuppress; ++i) + markerIter[suppressedStartIdx + i] = mNPhaseCore->mInteractionMarkerPool.allocate(); + + createdStartIdx = createdCurrIdx; + suppressedStartIdx = suppressedCurrIdx; + + createTask->mNbToProcess = batchSize; + createTask->setContinuation(continuation); + createTask->removeReference(); + + + + createTask = PX_PLACEMENT_NEW(flushPool.allocate(sizeof(OnOverlapCreatedTask)), OnOverlapCreatedTask)(mNPhaseCore, p + createdOverlapCount, + fInfo + createdOverlapCount, cms + createdStartIdx, shapeInter + createdStartIdx, markerIter + suppressedStartIdx, bpPairs, 0); + + batchSize = 0; + } + currentReadIdx += OverlapFilterTask::MaxPairs; + } + + if(batchSize > 0) + { + const PxU32 nbToCreate = createdCurrIdx - createdStartIdx; + const PxU32 nbToSuppress = suppressedCurrIdx - suppressedStartIdx; + + mLLContext->getContactManagerPool().preallocate(nbToCreate, cms + createdStartIdx); + for (PxU32 i = 0; i < nbToCreate; ++i) + shapeInter[createdStartIdx + i] = mNPhaseCore->mShapeInteractionPool.allocate(); + for (PxU32 i = 0; i < nbToSuppress; ++i) + markerIter[suppressedStartIdx + i] = mNPhaseCore->mInteractionMarkerPool.allocate(); + + createdStartIdx = createdCurrIdx; + suppressedStartIdx = suppressedCurrIdx; + + createTask->mNbToProcess = batchSize; + createTask->setContinuation(continuation); + createTask->removeReference(); + } +} + +void Sc::Scene::finishBroadPhase(PxU32 ccdPass, PxBaseTask* continuation) +{ + PX_UNUSED(continuation); + PX_PROFILE_ZONE("Sc::Scene::finishBroadPhase", getContextId()); + + Bp::SimpleAABBManager* aabbMgr = mAABBManager; + Bp::BroadPhasePair* bpPairs = aabbMgr->getBroadPhase()->getBroadPhasePairs(); + + { + PX_PROFILE_ZONE("Sim.processNewOverlaps", getContextId()); + { + + PxU32 createdOverlapCount; + const Bp::AABBOverlap* PX_RESTRICT p = aabbMgr->getCreatedOverlaps(Bp::VolumeBuckets::eSHAPE, createdOverlapCount); + { + //We allocate at least 1 element in this array to ensure that the onOverlapCreated functions don't go bang! + mPreallocatedContactManagers.reserve(1); + mPreallocatedShapeInteractions.reserve(1); + mPreallocatedInteractionMarkers.reserve(1); + + mPreallocatedContactManagers.forceSize_Unsafe(1); + mPreallocatedShapeInteractions.forceSize_Unsafe(1); + mPreallocatedInteractionMarkers.forceSize_Unsafe(1); + + } + + mLLContext->getSimStats().mNbNewPairs += createdOverlapCount; + + mPreallocateContactManagers.setContinuation(continuation); + Cm::FlushPool& flushPool = mLLContext->getTaskPool(); + + mOverlapFilterTasks.clear(); + mFilterInfo.forceSize_Unsafe(0); + mFilterInfo.reserve(createdOverlapCount); + mFilterInfo.forceSize_Unsafe(createdOverlapCount); + const PxU32 nbPairsPerTask = OverlapFilterTask::MaxPairs; + for (PxU32 a = 0; a < createdOverlapCount; a += nbPairsPerTask) + { + PxU32 nbToProcess = PxMin(createdOverlapCount - a, nbPairsPerTask); + OverlapFilterTask* task = PX_PLACEMENT_NEW(flushPool.allocate(sizeof(OverlapFilterTask)), OverlapFilterTask)(mNPhaseCore, mFilterInfo.begin() + a, + p + a, bpPairs, nbToProcess); + + task->setContinuation(&mPreallocateContactManagers); + task->removeReference(); + mOverlapFilterTasks.pushBack(task); + } + + } + + mPreallocateContactManagers.removeReference(); + + { + PX_PROFILE_ZONE("Sim.processNewOverlaps.createOverlapsNoShapeInteractions", getContextId()); + for (PxU32 i = Bp::VolumeBuckets::ePARTICLE; i < Bp::VolumeBuckets::eCOUNT; ++i) + { + + PxU32 createdOverlapCount; + const Bp::AABBOverlap* PX_RESTRICT p = aabbMgr->getCreatedOverlaps(i, createdOverlapCount); + + + mLLContext->getSimStats().mNbNewPairs += createdOverlapCount; + mNPhaseCore->onOverlapCreated(p, createdOverlapCount, ccdPass, bpPairs); + } + } + } +} + +void Sc::Scene::finishBroadPhaseStage2(const PxU32 ccdPass) +{ + PX_PROFILE_ZONE("Sc::Scene::finishBroadPhase2", getContextId()); + + Bp::SimpleAABBManager* aabbMgr = mAABBManager; + //Bp::BroadPhasePair* bpPairs = aabbMgr->getBroadPhase()->getBroadPhasePairs(); + + for (PxU32 i = 0; i < Bp::VolumeBuckets::eCOUNT; ++i) + { + PxU32 destroyedOverlapCount; + aabbMgr->getDestroyedOverlaps(i, destroyedOverlapCount); + mLLContext->getSimStats().mNbLostPairs += destroyedOverlapCount; + + } + + //KS - we need to defer processing lost overlaps until later! + if (ccdPass) + { + PX_PROFILE_ZONE("Sim.processLostOverlaps", getContextId()); + PxsContactManagerOutputIterator outputs = mLLContext->getNphaseImplementationContext()->getContactManagerOutputs(); + + bool useAdaptiveForce = mPublicFlags & PxSceneFlag::eADAPTIVE_FORCE; + + PxU32 destroyedOverlapCount; + + { + Bp::AABBOverlap* PX_RESTRICT p = aabbMgr->getDestroyedOverlaps(Bp::VolumeBuckets::eSHAPE, destroyedOverlapCount); + + while (destroyedOverlapCount--) + { + ElementSim* volume0 = reinterpret_cast<ElementSim*>(p->mUserData0); + ElementSim* volume1 = reinterpret_cast<ElementSim*>(p->mUserData1); + + //KS - this is a bit ugly. We split the "onOverlapRemoved" for shape interactions to parallelize it and that means + //that we have to call each of the individual stages of the remove here. + + //First, we have to get the interaction pointer... + Sc::ElementSimInteraction* interaction = mNPhaseCore->onOverlapRemovedStage1(volume0, volume1); + p->mUserData = interaction; + if (interaction) + { + if (interaction->getType() == Sc::InteractionType::eOVERLAP || interaction->getType() == Sc::InteractionType::eMARKER) + { + //If it's a standard "overlap" interaction, we have to send a lost touch report, unregister it, and destroy its manager and island gen data. + if (interaction->getType() == Sc::InteractionType::eOVERLAP) + { + Sc::ShapeInteraction* si = static_cast<Sc::ShapeInteraction*>(interaction); + mNPhaseCore->lostTouchReports(si, PxU32(PairReleaseFlag::eWAKE_ON_LOST_TOUCH), 0, outputs, useAdaptiveForce); + si->destroyManager(); + si->clearIslandGenData(); + } + + unregisterInteraction(interaction); + mNPhaseCore->unregisterInteraction(interaction); + } + + + //Then call "onOverlapRemoved" to actually free the interaction + mNPhaseCore->onOverlapRemoved(volume0, volume1, ccdPass, interaction, outputs, useAdaptiveForce); + } + p++; + } + } + for (PxU32 i = Bp::VolumeBuckets::ePARTICLE; i < Bp::VolumeBuckets::eCOUNT; ++i) + { + Bp::AABBOverlap* PX_RESTRICT p = aabbMgr->getDestroyedOverlaps(i, destroyedOverlapCount); + + while (destroyedOverlapCount--) + { + ElementSim* volume0 = reinterpret_cast<ElementSim*>(p->mUserData0); + ElementSim* volume1 = reinterpret_cast<ElementSim*>(p->mUserData1); + + p->mUserData = NULL; + + //KS - this is a bit ugly. + mNPhaseCore->onOverlapRemoved(volume0, volume1, ccdPass, NULL, outputs, useAdaptiveForce); + p++; + } + } + } + + // - Wakes actors that lost touch if appropriate + processLostTouchPairs(); + + if (ccdPass) + { + aabbMgr->getBroadPhase()->deletePairs(); + + aabbMgr->freeBuffers(); + } +} + +void Sc::Scene::secondPassNarrowPhase(PxBaseTask* /*continuation*/) +{ + { + PX_PROFILE_ZONE("Sim.postIslandGen", getContextId()); + mSimpleIslandManager->additionalSpeculativeActivation(); + wakeInteractions(ActorSim::AS_PART_OF_ISLAND_GEN); + } + mLLContext->secondPassUpdateContactManager(mDt, &mPostNarrowPhase); // Starts update of contact managers +} + +//~BROADPHASE + +void Sc::Scene::registerMaterialInNP(const PxsMaterialCore& materialCore) +{ + mLLContext->getNphaseImplementationContext()->registerMaterial(materialCore); +} + +void Sc::Scene::updateMaterialInNP(const PxsMaterialCore& materialCore) +{ + mLLContext->getNphaseImplementationContext()->updateMaterial(materialCore); +} + +void Sc::Scene::unregisterMaterialInNP(const PxsMaterialCore& materialCore) +{ + mLLContext->getNphaseImplementationContext()->unregisterMaterial(materialCore); +} diff --git a/PhysX_3.4/Source/SimulationController/src/ScShapeCore.cpp b/PhysX_3.4/Source/SimulationController/src/ScShapeCore.cpp new file mode 100644 index 00000000..71b4987c --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScShapeCore.cpp @@ -0,0 +1,373 @@ +// 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 "foundation/PxErrorCallback.h" +#include "ScShapeSim.h" +#include "ScPhysics.h" +#include "GuConvexMesh.h" +#include "GuTriangleMesh.h" +#include "GuHeightField.h" +#include "ScMaterialCore.h" + +using namespace physx; +using namespace Sc; + +// djs: temporary cruft + +static PxConvexMeshGeometryLL extendForLL(const PxConvexMeshGeometry& hlGeom) +{ + PxConvexMeshGeometryLL llGeom; + static_cast<PxConvexMeshGeometry&>(llGeom) = hlGeom; + + Gu::ConvexMesh* cm = static_cast<Gu::ConvexMesh*>(hlGeom.convexMesh); + + llGeom.hullData = &(cm->getHull()); + llGeom.gpuCompatible = hlGeom.convexMesh->isGpuCompatible(); + + return llGeom; +} + +static PxTriangleMeshGeometryLL extendForLL(const PxTriangleMeshGeometry& hlGeom) +{ + PxTriangleMeshGeometryLL llGeom; + static_cast<PxTriangleMeshGeometry&>(llGeom) = hlGeom; + + Gu::TriangleMesh* tm = static_cast<Gu::TriangleMesh*>(hlGeom.triangleMesh); + llGeom.meshData = tm; + llGeom.materialIndices = tm->getMaterials(); + llGeom.materials = static_cast<const PxTriangleMeshGeometryLL&>(hlGeom).materials; + + return llGeom; +} + +static PxHeightFieldGeometryLL extendForLL(const PxHeightFieldGeometry& hlGeom) +{ + PxHeightFieldGeometryLL llGeom; + static_cast<PxHeightFieldGeometry&>(llGeom) = hlGeom; + + Gu::HeightField* hf = static_cast<Gu::HeightField*>(hlGeom.heightField); + + llGeom.heightFieldData = &hf->getData(); + + llGeom.materials = static_cast<const PxHeightFieldGeometryLL&>(hlGeom).materials; + + return llGeom; +} + +ShapeCore::ShapeCore(const PxGeometry& geometry, + PxShapeFlags shapeFlags, + const PxU16* materialIndices, + PxU16 materialCount) : + mRestOffset (0.0f) +{ + mCore.mOwnsMaterialIdxMemory = true; + + PX_ASSERT(materialCount > 0); + + const PxTolerancesScale& scale = Physics::getInstance().getTolerancesScale(); + mCore.geometry.set(geometry); + mCore.transform = PxTransform(PxIdentity); + mCore.contactOffset = 0.02f * scale.length; + + mCore.mShapeFlags = shapeFlags; + + setMaterialIndices(materialIndices, materialCount); +} + +// PX_SERIALIZATION +ShapeCore::ShapeCore(const PxEMPTY) : + mQueryFilterData (PxEmpty), + mSimulationFilterData (PxEmpty), + mCore (PxEmpty) +{ + mCore.mOwnsMaterialIdxMemory = false; +} +//~PX_SERIALIZATION + +ShapeCore::~ShapeCore() +{ + if(mCore.geometry.getType() == PxGeometryType::eTRIANGLEMESH) + { + PxTriangleMeshGeometryLL& meshGeom = mCore.geometry.get<PxTriangleMeshGeometryLL>(); + if(mCore.mOwnsMaterialIdxMemory) + meshGeom.materials.deallocate(); + } + else if(mCore.geometry.getType() == PxGeometryType::eHEIGHTFIELD) + { + PxHeightFieldGeometryLL& hfGeom = mCore.geometry.get<PxHeightFieldGeometryLL>(); + if(mCore.mOwnsMaterialIdxMemory) + hfGeom.materials.deallocate(); + } +} + +PxU16 Sc::ShapeCore::getNbMaterialIndices() const +{ + PxGeometryType::Enum geomType = mCore.geometry.getType(); + + if ((geomType != PxGeometryType::eTRIANGLEMESH) && (geomType != PxGeometryType::eHEIGHTFIELD)) + { + return 1; + } + else if(geomType == PxGeometryType::eTRIANGLEMESH) + { + const PxTriangleMeshGeometryLL& meshGeom = mCore.geometry.get<PxTriangleMeshGeometryLL>(); + return meshGeom.materials.numIndices; + } + else + { + PX_ASSERT(geomType == PxGeometryType::eHEIGHTFIELD); + const PxHeightFieldGeometryLL& hfGeom = mCore.geometry.get<PxHeightFieldGeometryLL>(); + return hfGeom.materials.numIndices; + } +} + +const PxU16* Sc::ShapeCore::getMaterialIndices() const +{ + PxGeometryType::Enum geomType = mCore.geometry.getType(); + + if ((geomType != PxGeometryType::eTRIANGLEMESH) && (geomType != PxGeometryType::eHEIGHTFIELD)) + { + return &mCore.materialIndex; + } + else if(geomType == PxGeometryType::eTRIANGLEMESH) + { + const PxTriangleMeshGeometryLL& meshGeom = mCore.geometry.get<PxTriangleMeshGeometryLL>(); + return meshGeom.materials.indices; + } + else + { + PX_ASSERT(geomType == PxGeometryType::eHEIGHTFIELD); + const PxHeightFieldGeometryLL& hfGeom = mCore.geometry.get<PxHeightFieldGeometryLL>(); + return hfGeom.materials.indices; + } +} + +PX_FORCE_INLINE void setMaterialsHelper(MaterialIndicesStruct& materials, const PxU16* materialIndices, PxU16 materialIndexCount, PxU8& ownsMemory) +{ + if (materials.numIndices < materialIndexCount) + { + if (materials.indices && ownsMemory) + materials.deallocate(); + materials.allocate(materialIndexCount); + ownsMemory = true; + } + PxMemCopy(materials.indices, materialIndices, sizeof(PxU16)*materialIndexCount); + materials.numIndices = materialIndexCount; +} + +void ShapeCore::setMaterialIndices(const PxU16* materialIndices, PxU16 materialIndexCount) +{ + PxGeometryType::Enum geomType = mCore.geometry.getType(); + mCore.materialIndex = materialIndices[0]; + + if(geomType == PxGeometryType::eTRIANGLEMESH) + { + PxTriangleMeshGeometryLL& meshGeom = mCore.geometry.get<PxTriangleMeshGeometryLL>(); + setMaterialsHelper(meshGeom.materials, materialIndices, materialIndexCount, mCore.mOwnsMaterialIdxMemory); + } + else if(geomType == PxGeometryType::eHEIGHTFIELD) + { + PxHeightFieldGeometryLL& hfGeom = mCore.geometry.get<PxHeightFieldGeometryLL>(); + setMaterialsHelper(hfGeom.materials, materialIndices, materialIndexCount, mCore.mOwnsMaterialIdxMemory); + } +} + +void ShapeCore::setGeometry(const PxGeometry& geom) +{ + PxGeometryType::Enum oldGeomType = mCore.geometry.getType(); + PxGeometryType::Enum newGeomType = geom.getType(); + + // copy material related data to restore it after the new geometry has been set + MaterialIndicesStruct materials; + PX_ASSERT(materials.numIndices == 0); + + if (oldGeomType == PxGeometryType::eTRIANGLEMESH) + { + PxTriangleMeshGeometryLL& meshGeom = mCore.geometry.get<PxTriangleMeshGeometryLL>(); + materials = meshGeom.materials; + } + else if(oldGeomType == PxGeometryType::eHEIGHTFIELD) + { + PxHeightFieldGeometryLL& hfGeom = mCore.geometry.get<PxHeightFieldGeometryLL>(); + materials = hfGeom.materials; + } + + mCore.geometry.set(geom); + + if ((newGeomType == PxGeometryType::eTRIANGLEMESH) || (newGeomType == PxGeometryType::eHEIGHTFIELD)) + { + MaterialIndicesStruct* newMaterials; + + if (newGeomType == PxGeometryType::eTRIANGLEMESH) + { + PxTriangleMeshGeometryLL& meshGeom = mCore.geometry.get<PxTriangleMeshGeometryLL>(); + newMaterials = &meshGeom.materials; + } + else + { + PX_ASSERT(newGeomType == PxGeometryType::eHEIGHTFIELD); + PxHeightFieldGeometryLL& hfGeom = mCore.geometry.get<PxHeightFieldGeometryLL>(); + newMaterials = &hfGeom.materials; + } + + if (materials.numIndices != 0) // old type was mesh type + *newMaterials = materials; + else + { // old type was non-mesh type + newMaterials->allocate(1); + *newMaterials->indices = mCore.materialIndex; + mCore.mOwnsMaterialIdxMemory = true; + } + } + else if ((materials.numIndices != 0) && mCore.mOwnsMaterialIdxMemory) + { + // geometry changed to non-mesh type + materials.deallocate(); + } +} + +PxShape* ShapeCore::getPxShape() +{ + return Sc::gOffsetTable.convertScShape2Px(this); +} + +const PxShape* ShapeCore::getPxShape() const +{ + return Sc::gOffsetTable.convertScShape2Px(this); +} + +// PX_SERIALIZATION + +PX_FORCE_INLINE void exportExtraDataMaterials(PxSerializationContext& stream, const MaterialIndicesStruct& materials) +{ + stream.alignData(PX_SERIAL_ALIGN); + stream.writeData(materials.indices, sizeof(PxU16)*materials.numIndices); +} + +void ShapeCore::exportExtraData(PxSerializationContext& stream) +{ + PxGeometryType::Enum geomType = mCore.geometry.getType(); + + if(geomType == PxGeometryType::eTRIANGLEMESH) + { + PxTriangleMeshGeometryLL& meshGeom = mCore.geometry.get<PxTriangleMeshGeometryLL>(); + exportExtraDataMaterials(stream, meshGeom.materials); + } + else if (geomType == PxGeometryType::eHEIGHTFIELD) + { + PxHeightFieldGeometryLL& hfGeom = mCore.geometry.get<PxHeightFieldGeometryLL>(); + exportExtraDataMaterials(stream, hfGeom.materials); + } +} + +void ShapeCore::importExtraData(PxDeserializationContext& context) +{ + PxGeometryType::Enum geomType = mCore.geometry.getType(); + + if(geomType == PxGeometryType::eTRIANGLEMESH) + { + MaterialIndicesStruct& materials = mCore.geometry.get<PxTriangleMeshGeometryLL>().materials; + materials.indices = context.readExtraData<PxU16, PX_SERIAL_ALIGN>(materials.numIndices); + } + else if (geomType == PxGeometryType::eHEIGHTFIELD) + { + MaterialIndicesStruct& materials = mCore.geometry.get<PxHeightFieldGeometryLL>().materials; + materials.indices = context.readExtraData<PxU16, PX_SERIAL_ALIGN>(materials.numIndices); + } +} + +void ShapeCore::resolveMaterialReference(PxU32 materialTableIndex, PxU16 materialIndex) +{ + if (materialTableIndex == 0) + { + mCore.materialIndex = materialIndex; + } + + PxGeometry& geom = const_cast<PxGeometry&>(mCore.geometry.getGeometry()); + + if (geom.getType() == PxGeometryType::eHEIGHTFIELD) + { + PxHeightFieldGeometryLL& hfGeom = static_cast<PxHeightFieldGeometryLL&>(geom); + hfGeom.materials.indices[materialTableIndex] = materialIndex; + } + else if (geom.getType() == PxGeometryType::eTRIANGLEMESH) + { + PxTriangleMeshGeometryLL& meshGeom = static_cast<PxTriangleMeshGeometryLL&>(geom); + meshGeom.materials.indices[materialTableIndex] = materialIndex; + } +} + +void ShapeCore::resolveReferences(PxDeserializationContext& context) +{ + // Resolve geometry pointers if needed + PxGeometry& geom = const_cast<PxGeometry&>(mCore.geometry.getGeometry()); + + switch(geom.getType()) + { + case PxGeometryType::eCONVEXMESH: + { + PxConvexMeshGeometryLL& convexGeom = static_cast<PxConvexMeshGeometryLL&>(geom); + context.translatePxBase(convexGeom.convexMesh); + + // update the hullData pointer + static_cast<PxConvexMeshGeometryLL&>(geom) = extendForLL(convexGeom); + } + break; + + case PxGeometryType::eHEIGHTFIELD: + { + PxHeightFieldGeometryLL& hfGeom = static_cast<PxHeightFieldGeometryLL&>(geom); + context.translatePxBase(hfGeom.heightField); + + // update hf pointers + static_cast<PxHeightFieldGeometryLL&>(geom) = extendForLL(hfGeom); + } + break; + + case PxGeometryType::eTRIANGLEMESH: + { + PxTriangleMeshGeometryLL& meshGeom = static_cast<PxTriangleMeshGeometryLL&>(geom); + context.translatePxBase(meshGeom.triangleMesh); + + // update mesh pointers + static_cast<PxTriangleMeshGeometryLL&>(geom) = extendForLL(meshGeom); + } + break; + case PxGeometryType::eSPHERE: + case PxGeometryType::ePLANE: + case PxGeometryType::eCAPSULE: + case PxGeometryType::eBOX: + case PxGeometryType::eGEOMETRY_COUNT: + case PxGeometryType::eINVALID: + break; + + } +} + +//~PX_SERIALIZATION diff --git a/PhysX_3.4/Source/SimulationController/src/ScShapeInteraction.cpp b/PhysX_3.4/Source/SimulationController/src/ScShapeInteraction.cpp new file mode 100644 index 00000000..2235eb9d --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScShapeInteraction.cpp @@ -0,0 +1,1159 @@ +// 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 "ScShapeInteraction.h" +#include "ScPhysics.h" +#include "PxsContext.h" +#include "PxsMaterialCombiner.h" +#include "GuTriangleMesh.h" +#include "ScStaticSim.h" +#include "PxvManager.h" +#include "PxsSimpleIslandManager.h" +#include "PxvNphaseImplementationContext.h" + +using namespace physx; + + +Sc::ShapeInteraction::ShapeInteraction(ShapeSim& s1, ShapeSim& s2, ActorPair* aPair, PxPairFlags pairFlags, PxsContactManager* contactManager) : + RbElementInteraction (s1, s2, InteractionType::eOVERLAP, InteractionFlag::eRB_ELEMENT|InteractionFlag::eFILTERABLE), + mContactReportStamp (PX_INVALID_U32), + mFlags (0), + mActorPair (aPair), + mReportPairIndex (INVALID_REPORT_PAIR_ID), + mManager (NULL), + mEdgeIndex (IG_INVALID_EDGE), + mReportStreamIndex (0) +{ + // The PxPairFlags get stored in the SipFlag, make sure any changes get noticed + PX_COMPILE_TIME_ASSERT(PxPairFlag::eSOLVE_CONTACT == (1<<0)); + PX_COMPILE_TIME_ASSERT(PxPairFlag::eMODIFY_CONTACTS == (1<<1)); + PX_COMPILE_TIME_ASSERT(PxPairFlag::eNOTIFY_TOUCH_FOUND == (1<<2)); + PX_COMPILE_TIME_ASSERT(PxPairFlag::eNOTIFY_TOUCH_PERSISTS == (1<<3)); + PX_COMPILE_TIME_ASSERT(PxPairFlag::eNOTIFY_TOUCH_LOST == (1<<4)); + PX_COMPILE_TIME_ASSERT(PxPairFlag::eNOTIFY_TOUCH_CCD == (1<<5)); + PX_COMPILE_TIME_ASSERT(PxPairFlag::eNOTIFY_THRESHOLD_FORCE_FOUND == (1<<6)); + PX_COMPILE_TIME_ASSERT(PxPairFlag::eNOTIFY_THRESHOLD_FORCE_PERSISTS == (1<<7)); + PX_COMPILE_TIME_ASSERT(PxPairFlag::eNOTIFY_THRESHOLD_FORCE_LOST == (1<<8)); + PX_COMPILE_TIME_ASSERT(PxPairFlag::eNOTIFY_CONTACT_POINTS == (1<<9)); + PX_COMPILE_TIME_ASSERT(PxPairFlag::eDETECT_DISCRETE_CONTACT == (1<<10)); + PX_COMPILE_TIME_ASSERT(PxPairFlag::eDETECT_CCD_CONTACT == (1<<11)); + PX_COMPILE_TIME_ASSERT(PxPairFlag::ePRE_SOLVER_VELOCITY == (1<<12)); + PX_COMPILE_TIME_ASSERT(PxPairFlag::ePOST_SOLVER_VELOCITY == (1<<13)); + PX_COMPILE_TIME_ASSERT(PxPairFlag::eCONTACT_EVENT_POSE == (1<<14)); + PX_COMPILE_TIME_ASSERT((PAIR_FLAGS_MASK & PxPairFlag::eSOLVE_CONTACT) == PxPairFlag::eSOLVE_CONTACT); + PX_COMPILE_TIME_ASSERT((PxPairFlag::eSOLVE_CONTACT | PAIR_FLAGS_MASK) == PAIR_FLAGS_MASK); + PX_COMPILE_TIME_ASSERT((PAIR_FLAGS_MASK & PxPairFlag::eCONTACT_EVENT_POSE) == PxPairFlag::eCONTACT_EVENT_POSE); + PX_COMPILE_TIME_ASSERT((PxPairFlag::eCONTACT_EVENT_POSE | PAIR_FLAGS_MASK) == PAIR_FLAGS_MASK); + + setPairFlags(pairFlags); + + //Add a fresh edge to the island manager. + Scene& scene = getScene(); + Sc::BodySim* bs0 = getShape0().getBodySim(); + Sc::BodySim* bs1 = getShape1().getBodySim(); + + PX_ASSERT(bs0); // The shapes have to be sorted such that the first shape belongs to a dynamic + + updateFlags(scene, bs0, bs1, pairFlags); + + + if (contactManager == NULL) + { + IG::NodeIndex indexA, indexB; + //if(bs0) // the first shape always belongs to a dynamic body (we assert for this above) + { + indexA = bs0->getNodeIndex(); + bs0->registerCountedInteraction(); + } + if (bs1) + { + indexB = bs1->getNodeIndex(); + bs1->registerCountedInteraction(); + } + + IG::SimpleIslandManager* simpleIslandManager = scene.getSimpleIslandManager(); + + + mEdgeIndex = simpleIslandManager->addContactManager(NULL, indexA, indexB, this); + + bool active = registerInActors(contactManager); + scene.registerInteraction(this, active); // this will call onActivate() on the interaction + + } + else + { + onActivate(contactManager); + } + + PX_ASSERT((&getShape0()) && (&getShape1())); + + if(aPair) + aPair->incRefCount(); +} + + +Sc::ShapeInteraction::~ShapeInteraction() +{ + Sc::BodySim* body0 = getShape0().getBodySim(); + Sc::BodySim* body1 = getShape1().getBodySim(); + PX_ASSERT(body0); // the first shape always belongs to a dynamic body + + body0->unregisterCountedInteraction(); + if (body1) + body1->unregisterCountedInteraction(); + + if (mManager) + { + destroyManager(); + } + + if (mEdgeIndex != IG_INVALID_EDGE) + { + Scene& scene = getScene(); + + scene.getSimpleIslandManager()->removeConnection(mEdgeIndex); + mEdgeIndex = IG_INVALID_EDGE; + + scene.unregisterInteraction(this); + scene.getNPhaseCore()->unregisterInteraction(this); + } + + // This will remove the interaction from the actors list, which will prevent + // update calls to this actor because of Body::wakeUp below. + unregisterFromActors(); + + if (mReportPairIndex != INVALID_REPORT_PAIR_ID) + { + removeFromReportPairList(); + } +} + +void Sc::ShapeInteraction::clearIslandGenData() +{ + if (mEdgeIndex != IG_INVALID_EDGE) + { + Scene& scene = getScene(); + scene.getSimpleIslandManager()->removeConnection(mEdgeIndex); + mEdgeIndex = IG_INVALID_EDGE; + } +} + + +void Sc::ShapeInteraction::visualize(Cm::RenderOutput& out, PxsContactManagerOutputIterator& outputs) +{ + if (mManager) // sleeping pairs have no contact points -> do not visualize + { + Scene& scene = getScene(); + PxReal scale = scene.getVisualizationScale(); + + size_t ptrActor0 = reinterpret_cast<size_t>(&getShape0().getRbSim()); + size_t ptrActor1 = reinterpret_cast<size_t>(&getShape1().getRbSim()); + const PxReal flipNormal = (ptrActor0 < ptrActor1) ? 1.0f : -1.0f; + + PxU32 offset; + PxU32 nextOffset = 0; + do + { + const void* contactPatches; + const void* contactPoints; + PxU32 contactDataSize; + PxU32 contactPointCount; + PxU32 contactPatchCount; + const PxReal* impulses; + + offset = nextOffset; + nextOffset = getContactPointData(contactPatches, contactPoints, contactDataSize, contactPointCount, contactPatchCount, impulses, offset, outputs); + + const PxReal param_contactForce = scene.getVisualizationParameter(PxVisualizationParameter::eCONTACT_FORCE); + const PxReal param_contactNormal = scene.getVisualizationParameter(PxVisualizationParameter::eCONTACT_NORMAL); + const PxReal param_contactError = scene.getVisualizationParameter(PxVisualizationParameter::eCONTACT_ERROR); + const PxReal param_contactPoint = scene.getVisualizationParameter(PxVisualizationParameter::eCONTACT_POINT); + + const PxU32* faceIndices = reinterpret_cast<const PxU32*>(impulses + contactPointCount); + PxContactStreamIterator iter(reinterpret_cast<const PxU8*>(contactPatches), reinterpret_cast<const PxU8*>(contactPoints), faceIndices, contactPatchCount, contactPointCount); + + PxU32 i = 0; + while(iter.hasNextPatch()) + { + iter.nextPatch(); + while(iter.hasNextContact()) + { + iter.nextContact(); + + PxReal length = 0; + PxU32 color = 0; + + if ((param_contactForce != 0.0f) && impulses) + { + length = scale * param_contactForce * impulses[i]; + color = 0xff0000; + } + else if (param_contactNormal != 0.0f) + { + length = scale * param_contactNormal; + color = 0x0000ff; + } + else if (param_contactError != 0.0f) + { + length = PxAbs(scale * param_contactError * iter.getSeparation()); + color = 0xffff00; + } + + if (length != 0) + out << Cm::RenderOutput::LINES << color << iter.getContactPoint() << iter.getContactPoint() + iter.getContactNormal() * length * flipNormal; + + if (param_contactPoint != 0) + { + PxReal s = scale * 0.1f; + PxVec3 point = iter.getContactPoint(); + + if(0) //temp debug to see identical contacts + point.x += scale * 0.01f * (contactPointCount - i + 1); + + out << Cm::RenderOutput::LINES << PxU32(PxDebugColor::eARGB_RED); + out << point + PxVec3(-s,0,0) << point + PxVec3(s,0,0); + out << point + PxVec3(0,-s,0) << point + PxVec3(0,s,0); + out << point + PxVec3(0,0,-s) << point + PxVec3(0,0,s); + + } + } + } + } + while(nextOffset != offset); + } +} + + +PX_FORCE_INLINE void Sc::ShapeInteraction::processReportPairOnActivate() +{ + PX_ASSERT(isReportPair()); + PX_ASSERT(mReportPairIndex == INVALID_REPORT_PAIR_ID); + + if (readFlag(WAS_IN_PERSISTENT_EVENT_LIST)) + { + getScene().getNPhaseCore()->addToPersistentContactEventPairs(this); + mFlags &= ~WAS_IN_PERSISTENT_EVENT_LIST; + } +} + + +PX_FORCE_INLINE void Sc::ShapeInteraction::processReportPairOnDeactivate() +{ + PX_ASSERT(isReportPair()); + PX_ASSERT(mReportPairIndex != INVALID_REPORT_PAIR_ID); + PX_COMPILE_TIME_ASSERT(IS_IN_PERSISTENT_EVENT_LIST == (WAS_IN_PERSISTENT_EVENT_LIST >> 1)); + PX_ASSERT(!(readFlag(WAS_IN_PERSISTENT_EVENT_LIST))); + + PxU32 wasInPersList = (mFlags & IS_IN_PERSISTENT_EVENT_LIST) << 1; + mFlags |= wasInPersList; + + removeFromReportPairList(); +} + + +void Sc::ShapeInteraction::setContactReportPostSolverVelocity(ContactStreamManager& cs) +{ + Scene& scene = getScene(); + NPhaseCore* npcore = scene.getNPhaseCore(); + PxU8* stream = npcore->getContactReportPairData(cs.bufferIndex); + + ActorPairReport& apr = getActorPairReport(); + cs.setContactReportPostSolverVelocity(stream, apr.getActorA(), apr.getActorB()); +} + +void Sc::ShapeInteraction::resetManagerCachedState() const +{ + if (mManager) + { + Sc::Scene& scene = getScene(); + PxvNphaseImplementationContext* nphaseImplementationContext = scene.getLowLevelContext()->getNphaseImplementationContext(); + PX_ASSERT(nphaseImplementationContext); + + mManager->resetFrictionCachedState(); + nphaseImplementationContext->refreshContactManager(mManager); + } +} + +/* + This method can be called from various stages in the pipeline, some of which operate before the actor has advanced its pose and some after it has advanced its pose. + Discrete touch found events operate before the pose has been updated. This is because we are using the found event to active the bodies before solve so that we can just + solve the activated bodies. + Lost touch events occur after the pose has been updated. +*/ +void Sc::ShapeInteraction::processUserNotification(PxU32 contactEvent, PxU16 infoFlags, bool touchLost, const PxU32 ccdPass, const bool useCurrentTransform, PxsContactManagerOutputIterator& outputs) +{ + PX_ASSERT(hasTouch()); + + contactEvent = (!ccdPass) ? contactEvent : (contactEvent | PxPairFlag::eNOTIFY_TOUCH_CCD); + + if(mManager) + Ps::prefetchLine(mManager); + + Scene& scene = getScene(); + NPhaseCore* npcore = scene.getNPhaseCore(); + + PxU32 pairFlags = getPairFlags(); + PX_ASSERT(pairFlags & contactEvent); + const PxU32 extraDataFlags = pairFlags & CONTACT_REPORT_EXTRA_DATA; + + // make sure shape A and shape B are the same way round as the actors (in compounds they may be swapped) + // TODO: make "unswapped" a SIP flag and set it in updateState() + if (mActorPair == NULL) + { + return; + } + ActorPairReport& aPairReport = getActorPairReport(); + const bool unswapped = &aPairReport.getActorA() == &getShape0().getRbSim(); + const Sc::ShapeSim& shapeA = unswapped ? getShape0() : getShape1(); + const Sc::ShapeSim& shapeB = unswapped ? getShape1() : getShape0(); + + if(!aPairReport.isInContactReportActorPairSet()) + { + aPairReport.setInContactReportActorPairSet(); + npcore->addToContactReportActorPairSet(&aPairReport); + aPairReport.incRefCount(); + } + + // Prepare user notification + PxU32 timeStamp = scene.getTimeStamp(); + PxU32 shapePairTimeStamp = scene.getReportShapePairTimeStamp(); + + PxU8* stream = NULL; + ContactShapePair* pairStream = NULL; + ContactStreamManager& cs = aPairReport.createContactStreamManager(*npcore); + if(aPairReport.streamResetStamp(timeStamp)) + { + PX_ASSERT(mContactReportStamp != shapePairTimeStamp); // actor pair and shape pair timestamps must both be out of sync in this case + + PxU16 maxCount; + if (cs.maxPairCount != 0) + maxCount = cs.maxPairCount; // use value from previous report + else + { + // TODO: Use some kind of heuristic + maxCount = 2; + cs.maxPairCount = maxCount; + } + + PxU32 maxExtraDataSize; + if (!extraDataFlags || touchLost) + { + maxExtraDataSize = 0; + cs.setMaxExtraDataSize(maxExtraDataSize); + } + else + { + PxU32 currentMaxExtraDataSize = cs.getMaxExtraDataSize(); + maxExtraDataSize = ContactStreamManager::computeContactReportExtraDataSize(extraDataFlags, true); + PX_ASSERT(maxExtraDataSize > 0); + if (maxExtraDataSize <= currentMaxExtraDataSize) + maxExtraDataSize = currentMaxExtraDataSize; // use value from previous report + else + cs.setMaxExtraDataSize(maxExtraDataSize); + } + + stream = npcore->reserveContactReportPairData(maxCount, maxExtraDataSize, cs.bufferIndex); + + if (!maxExtraDataSize) // this is the usual case, so set it first for branch prediction + cs.reset(); + else if (stream) + { + cs.reset(); + PX_ASSERT(extraDataFlags); + PX_ASSERT(!touchLost); + + cs.fillInContactReportExtraData(stream, extraDataFlags, aPairReport.getActorA(), aPairReport.getActorB(), ccdPass, useCurrentTransform, 0, sizeof(ContactStreamHeader)); + if ((extraDataFlags & PxPairFlag::ePOST_SOLVER_VELOCITY) && (pairFlags & PxPairFlag::eDETECT_CCD_CONTACT)) + scene.setPostSolverVelocityNeeded(); + } + } + else + { + const PxU32 currentPairCount = cs.currentPairCount; + if(currentPairCount != 0) + { + PxU8* tmpStreamPtr = npcore->getContactReportPairData(cs.bufferIndex); + if (!extraDataFlags) + stream = tmpStreamPtr; // this is the usual case, so set it first for branch prediction + else + { + if (!touchLost) + { + // - the first few shape pair events might not request extra data + // - the events so far were due to touch lost + // - multiple reports due to CCD multiple passes + // Hence, the extra data has to be created/extended now. + // + PxU16 oldExtraDataSize = cs.extraDataSize; + PxI32 lastContactPass; + if (oldExtraDataSize) + { + ContactStreamHeader* strHeader = reinterpret_cast<ContactStreamHeader*>(tmpStreamPtr); + lastContactPass = strHeader->contactPass; + } + else + lastContactPass = -1; + + if (PxI32(ccdPass) > lastContactPass) // do not send extra data mulitple times for the same contact pass + { + PxU16 extraDataSize = PxU16(oldExtraDataSize + ContactStreamManager::computeContactReportExtraDataSize(extraDataFlags, (oldExtraDataSize == 0))); + PxU8* strPtr; + if (extraDataSize <= cs.getMaxExtraDataSize()) + strPtr = tmpStreamPtr; + else + strPtr = npcore->resizeContactReportPairData(currentPairCount < cs.maxPairCount ? cs.maxPairCount : PxU32(cs.maxPairCount+1), extraDataSize, cs); + // the check for max pair count is there to avoid another potential allocation further below + + if (strPtr) + { + stream = strPtr; + PxU32 sizeOffset; + if (oldExtraDataSize) + sizeOffset = oldExtraDataSize; + else + sizeOffset = sizeof(ContactStreamHeader); + cs.fillInContactReportExtraData(strPtr, extraDataFlags, aPairReport.getActorA(), aPairReport.getActorB(), ccdPass, useCurrentTransform, currentPairCount, sizeOffset); + if ((extraDataFlags & PxPairFlag::ePOST_SOLVER_VELOCITY) && (pairFlags & PxPairFlag::eDETECT_CCD_CONTACT)) + scene.setPostSolverVelocityNeeded(); + } + else + { + stream = tmpStreamPtr; + cs.raiseFlags(ContactStreamManagerFlag::eINCOMPLETE_STREAM); + } + } + else + stream = tmpStreamPtr; + } + else + stream = tmpStreamPtr; + } + } + } + + if(stream) + pairStream = cs.getShapePairs(stream); + else + { + cs.raiseFlags(ContactStreamManagerFlag::eINVALID_STREAM); + return; + } + + ContactShapePair* cp; + if (mContactReportStamp != shapePairTimeStamp) + { + // this shape pair is not in the contact notification stream yet + + if (cs.currentPairCount < cs.maxPairCount) + cp = pairStream + cs.currentPairCount; + else + { + PxU32 newSize = PxU32(cs.currentPairCount + (cs.currentPairCount >> 1) + 1); + stream = npcore->resizeContactReportPairData(newSize, cs.getMaxExtraDataSize(), cs); + if(stream) + { + pairStream = cs.getShapePairs(stream); + cp = pairStream + cs.currentPairCount; + } + else + { + cs.raiseFlags(ContactStreamManagerFlag::eINCOMPLETE_STREAM); + return; + } + } + + //!!! why is alignment important here? Looks almost like some refactor nonsense + PX_ASSERT(0==(reinterpret_cast<uintptr_t>(stream) & 0x0f)); // check 16Byte alignment + + mReportStreamIndex = cs.currentPairCount; + cp->shapes[0] = shapeA.getPxShape(); + cp->shapes[1] = shapeB.getPxShape(); + cp->contactPatches = NULL; + cp->contactPoints = NULL; + cp->contactForces = NULL; + cp->contactCount = 0; + cp->patchCount = 0; + cp->constraintStreamSize = 0; + cp->requiredBufferSize = 0; + cp->flags = infoFlags; + PX_ASSERT(contactEvent <= 0xffff); + cp->events = PxU16(contactEvent); + cp->shapeID[0] = shapeA.getID(); + cp->shapeID[1] = shapeB.getID(); + + cs.currentPairCount++; + + mContactReportStamp = shapePairTimeStamp; + } + else + { + // this shape pair is in the contact notification stream already but there is a second event (can happen with force threshold reports, for example). + + PX_ASSERT(mReportStreamIndex < cs.currentPairCount); + cp = &pairStream[mReportStreamIndex]; + cp->events |= contactEvent; + if (touchLost && cp->events & PxPairFlag::eNOTIFY_TOUCH_PERSISTS) + cp->events &= PxU16(~PxPairFlag::eNOTIFY_TOUCH_PERSISTS); + cp->flags |= infoFlags; + } + + if ((getPairFlags() & PxPairFlag::eNOTIFY_CONTACT_POINTS) && mManager && (!cp->contactPatches) && !(contactEvent & PxU32(PxPairFlag::eNOTIFY_TOUCH_LOST | PxPairFlag::eNOTIFY_THRESHOLD_FORCE_LOST))) + { + + const PxcNpWorkUnit& workUnit = mManager->getWorkUnit(); + PxsContactManagerOutput* output = NULL; + if(workUnit.mNpIndex & PxsContactManagerBase::NEW_CONTACT_MANAGER_MASK) + output = &getScene().getLowLevelContext()->getNphaseImplementationContext()->getNewContactManagerOutput(workUnit.mNpIndex); + else + output = &outputs.getContactManager(workUnit.mNpIndex); + + const PxsCCDContactHeader* ccdContactData = reinterpret_cast<const PxsCCDContactHeader*>(workUnit.ccdContacts); + + bool isCCDPass = (ccdPass != 0); + if ((output->nbPatches && !isCCDPass) || (ccdContactData && (!ccdContactData->isFromPreviousPass) && isCCDPass)) + { + const PxU8* contactPatchData; + const PxU8* contactPointData; + PxU32 cDataSize; + PxU32 alignedContactDataSize; + const PxReal* impulses; + + PxU32 nbPoints = output->nbContacts; + PxU32 contactPatchCount = output->nbPatches; + + if (!isCCDPass) + { + PX_ASSERT(0==(reinterpret_cast<const uintptr_t>(output->contactPatches) & 0x0f)); // check 16Byte alignment + contactPatchData = output->contactPatches; + contactPointData = output->contactPoints; + cDataSize = sizeof(PxContactPatch)*output->nbPatches + sizeof(PxContact)*output->nbContacts; + alignedContactDataSize = (cDataSize + 0xf) & 0xfffffff0; + impulses = output->contactForces; + } + else + { + PX_ASSERT(0==(reinterpret_cast<const uintptr_t>(ccdContactData) & 0x0f)); // check 16Byte alignment + contactPatchData = reinterpret_cast<const PxU8*>(ccdContactData) + sizeof(PxsCCDContactHeader); + contactPointData = contactPatchData + sizeof(PxContactPatch); + cDataSize = ccdContactData->contactStreamSize - sizeof(PxsCCDContactHeader); + PxU32 tmpAlignedSize = (ccdContactData->contactStreamSize + 0xf) & 0xfffffff0; + alignedContactDataSize = tmpAlignedSize - sizeof(PxsCCDContactHeader); + impulses = reinterpret_cast<const PxReal*>(contactPatchData + alignedContactDataSize); + nbPoints = 1; + contactPatchCount = 1; + } + + infoFlags = cp->flags; + infoFlags |= unswapped ? 0 : PxContactPairFlag::eINTERNAL_CONTACTS_ARE_FLIPPED; + + //PX_ASSERT(0==(reinterpret_cast<const uintptr_t>(impulses) & 0x0f)); + + PxU32 impulseSize = impulses ? (nbPoints * sizeof(PxReal)) : 0; + if (impulseSize) + infoFlags |= PxContactPairFlag::eINTERNAL_HAS_IMPULSES; + cp->contactPatches = contactPatchData; + cp->contactPoints = contactPointData; + cp->contactCount = Ps::to8(nbPoints); + cp->patchCount = Ps::to8(contactPatchCount); + cp->constraintStreamSize = Ps::to16(cDataSize); + cp->requiredBufferSize = alignedContactDataSize + impulseSize; + cp->contactForces = impulses; + + cp->flags = infoFlags; + } + } +} + +PxU32 Sc::ShapeInteraction::getContactPointData(const void*& contactPatches, const void*& contactPoints, PxU32& contactDataSize, PxU32& contactPointCount, PxU32& numPatches, const PxReal*& impulses, PxU32 startOffset, + PxsContactManagerOutputIterator& outputs) +{ + // Process LL generated contacts + if (mManager != NULL) + { + PxcNpWorkUnit& workUnit = mManager->getWorkUnit(); + + PxsContactManagerOutput* output = NULL; + + if(workUnit.mNpIndex & PxsContactManagerBase::NEW_CONTACT_MANAGER_MASK) + { + output = &getScene().getLowLevelContext()->getNphaseImplementationContext()->getNewContactManagerOutput(workUnit.mNpIndex); + } + else + { + output = &outputs.getContactManager(workUnit.mNpIndex); + } + + /*const void* dcdContactPatches; + const void* dcdContactPoints; + PxU32 dcdContactPatchCount; + const PxReal* dcdImpulses; + const PxsCCDContactHeader* ccdContactStream; + PxU32 dcdContactCount = mManager->getContactPointData(dcdContactPatches, dcdContactPoints, dcdContactPatchCount, dcdImpulses, ccdContactStream); + + PX_ASSERT(((dcdContactCount == 0) && (!ccdContactStream)) || ((dcdContactCount > 0) && hasTouch()) || (ccdContactStream && hasCCDTouch()));*/ + + const PxsCCDContactHeader* ccdContactStream = reinterpret_cast<const PxsCCDContactHeader*>(workUnit.ccdContacts); + + PxU32 idx = 0; + if (output->nbContacts) + { + if (startOffset == 0) + { + contactPatches = output->contactPatches; + contactPoints = output->contactPoints; + contactDataSize = sizeof(PxContactPatch) * output->nbPatches + sizeof(PxContact) * output->nbContacts; + contactPointCount = output->nbContacts; + numPatches = output->nbPatches; + impulses = output->contactForces; + + if (!ccdContactStream) + return startOffset; + else + return (startOffset + 1); + } + + idx++; + } + + while(ccdContactStream) + { + if (startOffset == idx) + { + const PxU8* stream = reinterpret_cast<const PxU8*>(ccdContactStream); + PxU16 streamSize = ccdContactStream->contactStreamSize; + contactPatches = stream + sizeof(PxsCCDContactHeader); + contactPoints = stream + sizeof(PxsCCDContactHeader) + sizeof(PxContactPatch); + contactDataSize = streamSize - sizeof(PxsCCDContactHeader); + contactPointCount = 1; + numPatches = 1; + impulses = reinterpret_cast<const PxReal*>(stream + ((streamSize + 0xf) & 0xfffffff0)); + + if (!ccdContactStream->nextStream) + return startOffset; + else + return (startOffset + 1); + } + + idx++; + ccdContactStream = ccdContactStream->nextStream; + } + } + + contactPatches = NULL; + contactPoints = NULL; + contactDataSize = 0; + contactPointCount = 0; + numPatches = 0; + impulses = NULL; + return startOffset; +} + + +// Note that LL will not send end touch events for managers that are destroyed while having contact +void Sc::ShapeInteraction::managerNewTouch(const PxU32 ccdPass, bool adjustCounters, PxsContactManagerOutputIterator& outputs, bool useAdaptiveForce) +{ + if (readFlag(HAS_TOUCH)) + return; // Do not count the touch twice (for instance when recreating a manager with touch) + // We have contact this frame + setHasTouch(); + + if (adjustCounters) + adjustCountersOnNewTouch(useAdaptiveForce); + + if(!isReportPair()) + return; + else + { + PX_ASSERT(hasTouch()); + PX_ASSERT(!readFlag(IS_IN_PERSISTENT_EVENT_LIST)); + PX_ASSERT(!readFlag(IS_IN_FORCE_THRESHOLD_EVENT_LIST)); + + PxU32 pairFlags = getPairFlags(); + if (pairFlags & PxPairFlag::eNOTIFY_TOUCH_FOUND) + { + PxU16 infoFlag = 0; + if (mActorPair->getTouchCount() == 1) // this code assumes that the actor pair touch count does get incremented beforehand + { + infoFlag = PxContactPairFlag::eACTOR_PAIR_HAS_FIRST_TOUCH; + } + + processUserNotification(PxPairFlag::eNOTIFY_TOUCH_FOUND, infoFlag, false, ccdPass, true, outputs); + } + + if (pairFlags & PxPairFlag::eNOTIFY_TOUCH_PERSISTS) + { + getScene().getNPhaseCore()->addToPersistentContactEventPairsDelayed(this); // to make sure that from now on, the pairs are tested for persistent contact events + } + else if (pairFlags & ShapeInteraction::CONTACT_FORCE_THRESHOLD_PAIRS) + { + // new touch -> need to start checking for force threshold events + // Note: this code assumes that it runs before the pairs get tested for force threshold exceeded + getScene().getNPhaseCore()->addToForceThresholdContactEventPairs(this); + } + } +} + + +bool Sc::ShapeInteraction::managerLostTouch(const PxU32 ccdPass, bool adjustCounters, PxsContactManagerOutputIterator& outputs, bool useAdaptiveForce) +{ + if (!readFlag(HAS_TOUCH)) + return false; + + // We do not have LL contacts this frame and also we lost LL contact this frame + + if (!isReportPair()) + { + setHasNoTouch(); + } + else + { + PX_ASSERT(hasTouch()); + + sendLostTouchReport(false, ccdPass, outputs); + + if (readFlag(IS_IN_CONTACT_EVENT_LIST)) + { + // don't need to worry about persistent/force-threshold contact events until next new touch + + if (readFlag(IS_IN_FORCE_THRESHOLD_EVENT_LIST)) + { + getScene().getNPhaseCore()->removeFromForceThresholdContactEventPairs(this); + } + else + { + PX_ASSERT(readFlag(IS_IN_PERSISTENT_EVENT_LIST)); + getScene().getNPhaseCore()->removeFromPersistentContactEventPairs(this); + } + + clearFlag(FORCE_THRESHOLD_EXCEEDED_FLAGS); + } + + setHasNoTouch(); + } + + BodySim* body0 = getShape0().getBodySim(); + BodySim* body1 = getShape1().getBodySim(); + PX_ASSERT(body0); // the first shape always belongs to a dynamic body + + if (adjustCounters) + adjustCountersOnLostTouch(body0, body1, useAdaptiveForce); + + if (!body1) + { + body0->internalWakeUp(); + return false; + } + return true; +} + + +PX_FORCE_INLINE void Sc::ShapeInteraction::updateFlags(const Sc::Scene& scene, const Sc::BodySim* bs0, const Sc::BodySim* bs1, const PxU32 pairFlags) +{ + PX_ASSERT(bs0); // the first shape always belongs to a dynamic body + + // Check if collision response is disabled + bool enabled = (!bs0->isKinematic()) || (bs1 && !bs1->isKinematic()); // If the pair has no dynamic body then disable response + enabled = enabled && (pairFlags & PxPairFlag::eSOLVE_CONTACT); + setFlag(CONTACTS_RESPONSE_DISABLED, !enabled); + + // Check if contact points needed + setFlag(CONTACTS_COLLECT_POINTS, ( (pairFlags & PxPairFlag::eNOTIFY_CONTACT_POINTS) || + (pairFlags & PxPairFlag::eMODIFY_CONTACTS) || + scene.getVisualizationParameter(PxVisualizationParameter::eCONTACT_POINT) || + scene.getVisualizationParameter(PxVisualizationParameter::eCONTACT_NORMAL) || + scene.getVisualizationParameter(PxVisualizationParameter::eCONTACT_ERROR) || + scene.getVisualizationParameter(PxVisualizationParameter::eCONTACT_FORCE)) ); +} + + +void Sc::ShapeInteraction::updateState(const PxU8 externalDirtyFlags) +{ + const PxU32 oldContactState = getManagerContactState(); + + const PxU8 dirtyFlags = PxU8(getDirtyFlags() | externalDirtyFlags); + const PxU32 pairFlags = getPairFlags(); + Scene& scene = getScene(); + + if (dirtyFlags & (InteractionDirtyFlag::eFILTER_STATE | InteractionDirtyFlag::eVISUALIZATION)) + { + Sc::BodySim* bs0 = getShape0().getBodySim(); + Sc::BodySim* bs1 = getShape1().getBodySim(); + + Ps::IntBool wasDisabled = readFlag(CONTACTS_RESPONSE_DISABLED); + + updateFlags(scene, bs0, bs1, pairFlags); + + Ps::IntBool isDisabled = readFlag(CONTACTS_RESPONSE_DISABLED); + + if (!wasDisabled && isDisabled) + { + scene.getSimpleIslandManager()->setEdgeDisconnected(mEdgeIndex); + } + else if (wasDisabled && !isDisabled) + { + if (readFlag(ShapeInteraction::HAS_TOUCH)) + { + scene.getSimpleIslandManager()->setEdgeConnected(mEdgeIndex); + } + } + } + + PxU32 newContactState = getManagerContactState(); + bool recreateManager = (oldContactState != newContactState); + + // No use in updating manager properties if the manager is going to be re-created or does not exist yet + if ((!recreateManager) && (mManager != 0)) + { + ShapeSim& shapeSim0 = getShape0(); + ShapeSim& shapeSim1 = getShape1(); + + // Update dominance + if (dirtyFlags & InteractionDirtyFlag::eDOMINANCE) + { + Sc::BodySim* bs0 = shapeSim0.getBodySim(); + Sc::BodySim* bs1 = shapeSim1.getBodySim(); + PX_ASSERT(bs0); // the first shape always belongs to a dynamic body + + // Static actors are in dominance group zero and must remain there + const PxDominanceGroup dom0 = bs0->getActorCore().getDominanceGroup(); + const PxDominanceGroup dom1 = bs1 ? bs1->getActorCore().getDominanceGroup() : PxDominanceGroup(0); + + const PxDominanceGroupPair cdom = getScene().getDominanceGroupPair(dom0, dom1); + mManager->setDominance0(cdom.dominance0); + mManager->setDominance1(cdom.dominance1); + } + + // Update skin width + if (dirtyFlags & InteractionDirtyFlag::eREST_OFFSET) + { + mManager->setRestDistance(shapeSim0.getRestOffset() + shapeSim1.getRestOffset()); + } + + //we may want to only write these if they have changed, the set code is a bit painful for the integration flags because of bit unpacking + packing. + mManager->setCCD((getPairFlags() & PxPairFlag::eDETECT_CCD_CONTACT) != 0); + } + else if (readInteractionFlag(InteractionFlag::eIS_ACTIVE)) // only re-create the manager if the pair is active + { + PX_ASSERT(mManager); // if the pair is active, there has to be a manager + PX_ASSERT(activeManagerAllowed()); + + // A) This is a newly created pair + // + // B) The contact notification or processing state has changed. + // All existing managers need to be deleted and recreated with the correct flag set + // These flags can only be set at creation in LL + destroyManager(); + createManager(NULL); + } +} + + +bool Sc::ShapeInteraction::onActivate(void* contactManager) +{ + if (isReportPair())// && !(infoFlag & ActorSim::AS_PART_OF_ISLAND_GEN_PASS_1)) + { + // for pairs that go through a second island pass, there is the possibility that they get put to sleep again after the second pass. + // So we do not want to check for re-insertion into the persistent report pair list yet. + processReportPairOnActivate(); + } + + if (updateManager(contactManager)) + { + raiseInteractionFlag(InteractionFlag::eIS_ACTIVE); + return true; + } + else + return false; +} + + +bool Sc::ShapeInteraction::onDeactivate(PxU32 /*infoFlag*/) +{ + PX_ASSERT(getShape0().getActor().isDynamicRigid() || getShape1().getActor().isDynamicRigid()); + + const BodySim* bodySim0 = getShape0().getBodySim(); + const BodySim* bodySim1 = getShape1().getBodySim(); + PX_ASSERT(bodySim0); // the first shape always belongs to a dynamic body + + PX_ASSERT( (!bodySim0 && bodySim1 && !bodySim1->isActive()) || + (!bodySim1 && bodySim0 && !bodySim0->isActive()) || + ((bodySim0 && bodySim1 && (!bodySim0->isActive() || !bodySim1->isActive()))) ); + + if ((!bodySim0->isActive()) && (!bodySim1 || !bodySim1->isActive())) + { + if (mReportPairIndex != INVALID_REPORT_PAIR_ID) + { + + processReportPairOnDeactivate(); + } + + PX_ASSERT((mManager->getTouchStatus() > 0) == (hasTouch() > 0)); + + if (mManager != 0) + { + if ((!readFlag(TOUCH_KNOWN)) && mManager->touchStatusKnown() && (!mManager->getTouchStatus())) + { + // for pairs that are inserted asleep, we do not know the touch state. If they run through narrowphase and a touch is found, + // then a managerNewTouch() call will inform this object about the found touch. However, if narrowphase detects that there + // is no touch, this object will not be informed about it. The low level manager will always know though. Now, before destroying + // the pair manager, we need to record "does not have touch" state if available. + raiseFlag(HAS_NO_TOUCH); + } + + destroyManager(); + if (mEdgeIndex != IG_INVALID_EDGE) + getScene().getSimpleIslandManager()->clearEdgeRigidCM(mEdgeIndex); + } + Scene& scene = getScene(); + scene.getSimpleIslandManager()->deactivateEdge(mEdgeIndex); + + // + // We distinguish two scenarios here: + // + // A) island generation deactivates objects: + // -> the deactivated body was active + // -> narrowphase ran on this pair + // -> the touch status is known + // -> touch: the objects of the pair are in the same island + // -> no touch: the objects of the pair are in different islands + // + // As a consequence, the edge state is not changed. The assumption is that anything that could break the touch status + // from here on will have to mark the edges connected (for example if the object gets moved). + // + // B) user deactivates objects: + // -> the touch status might not be known (for example, the pose gets integrated after the solver which might cause a change + // in touch status. If the object gets put to sleep after that, we have to be conservative and mark the edge connected. + // other example: an active object gets moved by the user and then deactivated). + // + + clearInteractionFlag(InteractionFlag::eIS_ACTIVE); + return true; + } + else + { + return false; + } +} + + +void Sc::ShapeInteraction::createManager(void* contactManager) +{ + //PX_PROFILE_ZONE("ShapeInteraction.createManager", 0); + + Sc::Scene& scene = getScene(); + + const PxU32 pairFlags = getPairFlags(); + + const int disableCCDContact = !(pairFlags & PxPairFlag::eDETECT_CCD_CONTACT); + + PxsContactManager* manager = scene.getLowLevelContext()->createContactManager(reinterpret_cast<PxsContactManager*>(contactManager), !disableCCDContact); + PxcNpWorkUnit& mNpUnit = manager->getWorkUnit(); + + + + // Check if contact generation callback has been ordered on the pair + int contactChangeable = 0; + if (pairFlags & PxPairFlag::eMODIFY_CONTACTS) + contactChangeable = 1; + + ShapeSim& shapeSim0 = getShape0(); + ShapeSim& shapeSim1 = getShape1(); + + PxActorType::Enum type0 = shapeSim0.getActor().getActorType(), type1 = shapeSim1.getActor().getActorType(); + + + const int disableResponse = readFlag(CONTACTS_RESPONSE_DISABLED) ? 1 : 0; + const int disableDiscreteContact = !(pairFlags & PxPairFlag::eDETECT_DISCRETE_CONTACT); + const int reportContactInfo = readFlag(CONTACTS_COLLECT_POINTS); + const int hasForceThreshold = !disableResponse && (pairFlags & CONTACT_FORCE_THRESHOLD_PAIRS); + int touching; + if (readFlag(TOUCH_KNOWN)) + touching = readFlag(HAS_TOUCH) ? 1 : -1; + else + touching = 0; + + + + // Static actors are in dominance group zero and must remain there + + Sc::BodySim* bs0 = shapeSim0.getBodySim(); + Sc::BodySim* bs1 = shapeSim1.getBodySim(); + + PX_ASSERT(bs0); // The shapes have to be sorted such that the first shape belongs to a dynamic + + const PxDominanceGroup dom0 = bs0->getActorCore().getDominanceGroup(); + const PxDominanceGroup dom1 = bs1 ? bs1->getActorCore().getDominanceGroup() : PxDominanceGroup(0); + + const bool kinematicActor = bs1 ? bs1->isKinematic() : false; + + const PxDominanceGroupPair cdom = scene.getDominanceGroupPair(dom0, dom1); + + PxI32 hasArticulations = (type0 == PxActorType::eARTICULATION_LINK) | (type1 == PxActorType::eARTICULATION_LINK)<<1; + PxI32 hasDynamics = (type0 != PxActorType::eRIGID_STATIC) | (type1 != PxActorType::eRIGID_STATIC)<<1; + + const PxsShapeCore* shapeCore0 = &shapeSim0.getCore().getCore(); + const PxsShapeCore* shapeCore1 = &shapeSim1.getCore().getCore(); + + + + //Initialize the manager.... + + manager->mRigidBody0 = &bs0->getLowLevelBody(); + manager->mRigidBody1 = bs1 ? &bs1->getLowLevelBody() : NULL; + manager->mShapeInteraction = this; + mNpUnit.shapeCore0 = shapeCore0; + mNpUnit.shapeCore1 = shapeCore1; + + PX_ASSERT(shapeCore0->transform.isValid() && shapeCore1->transform.isValid()); + + mNpUnit.rigidCore0 = &shapeSim0.getPxsRigidCore(); + mNpUnit.rigidCore1 = &shapeSim1.getPxsRigidCore(); + + mNpUnit.restDistance = shapeSim0.getRestOffset() + shapeSim1.getRestOffset(); + mNpUnit.dominance0 = cdom.dominance0; + mNpUnit.dominance1 = cdom.dominance1; + mNpUnit.geomType0 = PxU8(shapeCore0->geometry.getType()); + mNpUnit.geomType1 = PxU8(shapeCore1->geometry.getType()); + mNpUnit.mTransformCache0 = shapeSim0.getTransformCacheID(); + mNpUnit.mTransformCache1 = shapeSim1.getTransformCacheID(); + + + PxU16 wuflags = 0; + + if(hasArticulations & 1) + wuflags |= PxcNpWorkUnitFlag::eARTICULATION_BODY0; + + if(hasArticulations & 2) + wuflags |= PxcNpWorkUnitFlag::eARTICULATION_BODY1; + + if(hasDynamics & 1) + wuflags |= PxcNpWorkUnitFlag::eDYNAMIC_BODY0; + + if(hasDynamics & 2) + wuflags |= PxcNpWorkUnitFlag::eDYNAMIC_BODY1; + + if(!disableResponse && !contactChangeable) + wuflags |= PxcNpWorkUnitFlag::eOUTPUT_CONSTRAINTS; + + if(!disableDiscreteContact) + wuflags |= PxcNpWorkUnitFlag::eDETECT_DISCRETE_CONTACT; + if(kinematicActor) + wuflags |= PxcNpWorkUnitFlag::eHAS_KINEMATIC_ACTOR; + + if(disableResponse) + wuflags |= PxcNpWorkUnitFlag::eDISABLE_RESPONSE; + if(!disableCCDContact) + wuflags |= PxcNpWorkUnitFlag::eDETECT_CCD_CONTACTS; + + // this is just the user req: contact reports can also be generated by body thresholding + if(reportContactInfo || contactChangeable) + wuflags |= PxcNpWorkUnitFlag::eOUTPUT_CONTACTS; + + if(hasForceThreshold) + wuflags |= PxcNpWorkUnitFlag::eFORCE_THRESHOLD; + + if(contactChangeable) + wuflags |= PxcNpWorkUnitFlag::eMODIFIABLE_CONTACT; + + mNpUnit.flags = wuflags; + + manager->mFlags = PxU32(contactChangeable ? PxsContactManager::PXS_CM_CHANGEABLE : 0) | PxU32(disableCCDContact ? 0 : PxsContactManager::PXS_CM_CCD_LINEAR); + + //manager->mUserData = this; + + mNpUnit.mNpIndex = 0xFFffFFff; + + mManager = manager; + + + PxU8 statusFlags = 0; + + if (touching > 0) + { + statusFlags |= PxcNpWorkUnitStatusFlag::eHAS_TOUCH; + } + else if (touching < 0) + { + statusFlags |= PxcNpWorkUnitStatusFlag::eHAS_NO_TOUCH; + } + + mNpUnit.statusFlags = statusFlags; + + //KS - do not register the CMs here if contactManager isn't null. This implies this is a newly-found pair so we'll do that addition outside in parallel + + + if (contactManager == NULL) + { + scene.getSimpleIslandManager()->setEdgeRigidCM(mEdgeIndex, mManager); + PxvNphaseImplementationContext* nphaseImplementationContext = scene.getLowLevelContext()->getNphaseImplementationContext(); + PX_ASSERT(nphaseImplementationContext); + nphaseImplementationContext->registerContactManager(mManager, touching, 0); + } +} + + +void Sc::ShapeInteraction::onShapeChangeWhileSleeping(bool shapeOfDynamicChanged) +{ + // + // if an operation that can break touch status occurs, all deactivated pairs need to set the sleep island edge + // to connected to make sure that potentially joined islands get detected once parts of the island wake up. + // Active interactions can be ignored because the edges of those will be marked connected on deactivation. + // + if (!mManager) + { + Scene& scene = getScene(); + + + BodySim* body0 = getShape0().getBodySim(); + PX_ASSERT(body0); // the first shape always belongs to a dynamic body + + if (shapeOfDynamicChanged && !readFlag(TOUCH_KNOWN)) + { + // conservative approach: if a pair was added asleep, and a body/shape gets moved, we want to check next frame + // whether the other body should get woken up. The motivation behind this is to get a similar behavior as in + // the case where the objects fell asleep rather than have been added asleep (in that case the object will be + // woken up with one frame delay). + + BodySim* body1 = getShape1().getBodySim(); + + if (body1 && !readFlag(ShapeInteraction::CONTACTS_RESPONSE_DISABLED)) // the first shape always belongs to a dynamic body, hence no need to test body0 + scene.addToLostTouchList(body0, body1); // note: this will cause duplicate entries if the pair loses AABB overlap the next frame + } + else if ((!shapeOfDynamicChanged) && !body0->isActive()) + { + // if the shape of a static rigid body moves or is scaled, then this can break touch status and a second island gen + // pass will be needed. However, statics do not have island nodes that can be marked accordinlgy and instead we mark + // the dynamics of all pairs if they are asleep (if they are awake, they will get marked when the user puts them to sleep). + + /*PX_ASSERT(!getShape1().getBodySim()); + body0->notifySecondIslandGenPassNeeded();*/ + } + } +} + diff --git a/PhysX_3.4/Source/SimulationController/src/ScShapeInteraction.h b/PhysX_3.4/Source/SimulationController/src/ScShapeInteraction.h new file mode 100644 index 00000000..fcfc8f44 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScShapeInteraction.h @@ -0,0 +1,402 @@ +// 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_COLLISION_SHAPE_INTERACTION +#define PX_COLLISION_SHAPE_INTERACTION + +#include "ScRbElementInteraction.h" +#include "ScActorPair.h" +#include "ScScene.h" +#include "ScBodySim.h" +#include "PxsContactManager.h" +#include "PxsContext.h" +#include "PxsSimpleIslandManager.h" + +#define INVALID_REPORT_PAIR_ID 0xffffffff + +namespace physx +{ +class PxsContactManagerOutputIterator; +namespace Sc +{ + /* + Description: A ShapeInteraction represents a pair of objects which _may_ have contacts. Created by the broadphase + and processed by the NPhaseCore. + */ + class ShapeInteraction : public RbElementInteraction + { + friend class NPhaseCore; + ShapeInteraction& operator=(const ShapeInteraction&); + public: + enum SiFlag + { + PAIR_FLAGS_MASK = (PxPairFlag::eNEXT_FREE - 1), // Bits where the PxPairFlags get stored + NEXT_FREE = ((PAIR_FLAGS_MASK << 1) & ~PAIR_FLAGS_MASK), + + HAS_TOUCH = (NEXT_FREE << 0), // Tracks the last know touch state + HAS_NO_TOUCH = (NEXT_FREE << 1), // Tracks the last know touch state + TOUCH_KNOWN = (HAS_TOUCH | HAS_NO_TOUCH), // If none of these flags is set, the touch state is not known (for example, this is true for pairs that never ran narrowphase + + CONTACTS_COLLECT_POINTS = (NEXT_FREE << 2), // The user wants to get the contact points (includes debug rendering) + CONTACTS_RESPONSE_DISABLED = (NEXT_FREE << 3), // Collision response disabled (either by the user through PxPairFlag::eSOLVE_CONTACT or because the pair has two kinematics) + + CONTACT_FORCE_THRESHOLD_PAIRS = PxU32(PxPairFlag::eNOTIFY_THRESHOLD_FORCE_FOUND) | PxU32(PxPairFlag::eNOTIFY_THRESHOLD_FORCE_PERSISTS) | PxU32(PxPairFlag::eNOTIFY_THRESHOLD_FORCE_LOST), + CONTACT_REPORT_EVENTS = PxU32(PxPairFlag::eNOTIFY_TOUCH_FOUND) | PxU32(PxPairFlag::eNOTIFY_TOUCH_PERSISTS) | PxU32(PxPairFlag::eNOTIFY_TOUCH_LOST) | + PxU32(PxPairFlag::eNOTIFY_THRESHOLD_FORCE_FOUND) | PxU32(PxPairFlag::eNOTIFY_THRESHOLD_FORCE_PERSISTS) | PxU32(PxPairFlag::eNOTIFY_THRESHOLD_FORCE_LOST), + CONTACT_REPORT_EXTRA_DATA = PxU32(PxPairFlag::ePRE_SOLVER_VELOCITY) | PxU32(PxPairFlag::ePOST_SOLVER_VELOCITY) | PxU32(PxPairFlag::eCONTACT_EVENT_POSE), + + FORCE_THRESHOLD_EXCEEDED_NOW = (NEXT_FREE << 4), + FORCE_THRESHOLD_EXCEEDED_BEFORE = (NEXT_FREE << 5), + FORCE_THRESHOLD_EXCEEDED_FLAGS = FORCE_THRESHOLD_EXCEEDED_NOW | FORCE_THRESHOLD_EXCEEDED_BEFORE, + + IS_IN_PERSISTENT_EVENT_LIST = (NEXT_FREE << 6), // The pair is in the list of persistent contact events + WAS_IN_PERSISTENT_EVENT_LIST = (NEXT_FREE << 7), // The pair is inactive but used to be in the list of persistent contact events + IN_PERSISTENT_EVENT_LIST = IS_IN_PERSISTENT_EVENT_LIST | WAS_IN_PERSISTENT_EVENT_LIST, + IS_IN_FORCE_THRESHOLD_EVENT_LIST= (NEXT_FREE << 8), // The pair is in the list of force threshold contact events + IS_IN_CONTACT_EVENT_LIST = IS_IN_PERSISTENT_EVENT_LIST | IS_IN_FORCE_THRESHOLD_EVENT_LIST, + + LL_MANAGER_RECREATE_EVENT = CONTACT_REPORT_EVENTS | CONTACTS_COLLECT_POINTS | + CONTACTS_RESPONSE_DISABLED | PxU32(PxPairFlag::eMODIFY_CONTACTS) + }; + ShapeInteraction(ShapeSim& s1, ShapeSim& s2, ActorPair* aPair, PxPairFlags pairFlags, PxsContactManager* contactManager); + virtual ~ShapeInteraction(); + + // Submits to contact stream + void processUserNotification(PxU32 contactEvent, PxU16 infoFlags, bool touchLost, const PxU32 ccdPass, const bool useCurrentTransform, + PxsContactManagerOutputIterator& outputs); // ccdPass is 0 for discrete collision and then 1,2,... for the CCD passes + + void visualize(Cm::RenderOutput&, PxsContactManagerOutputIterator&); + + PxU32 getContactPointData(const void*& contactPatches, const void*& contactPoints, PxU32& contactDataSize, PxU32& contactPointCount, PxU32& patchCount, const PxReal*& impulses, PxU32 startOffset, PxsContactManagerOutputIterator& outputs); + + bool managerLostTouch(const PxU32 ccdPass, bool adjustCounters, PxsContactManagerOutputIterator& outputs, bool useAdaptiveForce); + void managerNewTouch(const PxU32 ccdPass, bool adjustCounters, PxsContactManagerOutputIterator& outputs, bool useAdaptiveForce); + + PX_FORCE_INLINE void adjustCountersOnLostTouch(BodySim*, BodySim*, bool useAdaptiveForce); + PX_FORCE_INLINE void adjustCountersOnNewTouch(bool useAdaptiveForce); + + PX_FORCE_INLINE void sendCCDRetouch(const PxU32 ccdPass, PxsContactManagerOutputIterator& outputs); + void setContactReportPostSolverVelocity(ContactStreamManager& cs); + PX_FORCE_INLINE void sendLostTouchReport(bool shapeVolumeRemoved, const PxU32 ccdPass, PxsContactManagerOutputIterator& ouptuts); + void resetManagerCachedState() const; + + PX_FORCE_INLINE ActorPair* getActorPair() const { return mActorPair; } + PX_FORCE_INLINE void setActorPair(ActorPair& aPair) { mActorPair = &aPair; } + PX_FORCE_INLINE void clearActorPair() { mActorPair = NULL; } + PX_FORCE_INLINE ActorPairReport& getActorPairReport() const { return ActorPairReport::cast(*mActorPair); } + PX_INLINE Ps::IntBool isReportPair() const { /*PX_ASSERT(!(Ps::IntBool(getPairFlags() & CONTACT_REPORT_EVENTS)) || mActorPair->isReportPair());*/ return Ps::IntBool(getPairFlags() & CONTACT_REPORT_EVENTS); } + PX_INLINE Ps::IntBool hasTouch() const { return readFlag(HAS_TOUCH); } + PX_INLINE Ps::IntBool hasCCDTouch() const { PX_ASSERT(mManager); return mManager->getHadCCDContact(); } + PX_INLINE void swapAndClearForceThresholdExceeded(); + + PX_FORCE_INLINE void raiseFlag(SiFlag flag) { mFlags |= flag; } + PX_FORCE_INLINE Ps::IntBool readFlag(SiFlag flag) const { return Ps::IntBool(mFlags & flag); } + PX_FORCE_INLINE PxU32 getPairFlags() const; + + PX_FORCE_INLINE void removeFromReportPairList(); + + void onShapeChangeWhileSleeping(bool shapeOfDynamicChanged); + + PX_FORCE_INLINE Ps::IntBool hasKnownTouchState() const; + + virtual bool onActivate(void* data); + virtual bool onDeactivate(PxU32 infoFlag); + + void updateState(const PxU8 externalDirtyFlags); + + const PxsContactManager* getContactManager() const { return mManager; } + + void clearIslandGenData(); + + PX_FORCE_INLINE PxU32 getEdgeIndex() const { return mEdgeIndex; } + + private: + PxU32 mContactReportStamp; + PxU32 mFlags; + ActorPair* mActorPair; + PxU32 mReportPairIndex; // Owned by NPhaseCore for its report pair list + + PxsContactManager* mManager; + + PxU32 mEdgeIndex; + + PxU16 mReportStreamIndex; // position of this pair in the contact report stream + + // Internal functions: + + void createManager(void* contactManager); + PX_INLINE void resetManager(); + PX_INLINE bool updateManager(void* contactManager); + PX_INLINE void destroyManager(); + PX_FORCE_INLINE bool activeManagerAllowed() const; + PX_FORCE_INLINE PxU32 getManagerContactState() const { return mFlags & LL_MANAGER_RECREATE_EVENT; } + + PX_FORCE_INLINE void clearFlag(SiFlag flag) { mFlags &= ~flag; } + PX_INLINE void setFlag(SiFlag flag, bool value) + { + if (value) + raiseFlag(flag); + else + clearFlag(flag); + } + PX_FORCE_INLINE void setHasTouch() { clearFlag(HAS_NO_TOUCH); raiseFlag(HAS_TOUCH); } + PX_FORCE_INLINE void setHasNoTouch() { clearFlag(HAS_TOUCH); raiseFlag(HAS_NO_TOUCH); } + + PX_FORCE_INLINE void setPairFlags(PxPairFlags flags); + + PX_FORCE_INLINE void processReportPairOnActivate(); + PX_FORCE_INLINE void processReportPairOnDeactivate(); + + // Certain SiFlag cache properties of the pair. If these properties change then the flags have to be updated. + // For example: is collision enabled for this pair? are contact points requested for this pair? + PX_FORCE_INLINE void updateFlags(const Sc::Scene&, const Sc::BodySim*, const Sc::BodySim*, const PxU32 pairFlags); + + friend class Sc::Scene; + }; + +} // namespace Sc + + +PX_FORCE_INLINE void Sc::ShapeInteraction::sendLostTouchReport(bool shapeVolumeRemoved, const PxU32 ccdPass, PxsContactManagerOutputIterator& outputs) +{ + PX_ASSERT(hasTouch()); + PX_ASSERT(isReportPair()); + + PxU32 thresholdForceLost = readFlag(ShapeInteraction::FORCE_THRESHOLD_EXCEEDED_NOW) ? PxU32(PxPairFlag::eNOTIFY_THRESHOLD_FORCE_LOST) : 0; // make sure to only send report if force is still above threshold + PxU32 triggeredFlags = getPairFlags() & (PxU32(PxPairFlag::eNOTIFY_TOUCH_LOST) | thresholdForceLost); + if (triggeredFlags) + { + PxU16 infoFlag = 0; + if (mActorPair->getTouchCount() == 1) // this code assumes that the actor pair touch count does get decremented afterwards + { + infoFlag |= PxContactPairFlag::eACTOR_PAIR_LOST_TOUCH; + } + + //Lost touch is processed after solver, so we should use the previous transform to update the pose for objects if user request eCONTACT_EVENT_POSE + processUserNotification(triggeredFlags, infoFlag, true, ccdPass, false, outputs); + } + + ActorPairReport& apr = getActorPairReport(); + if (apr.hasReportData() && !apr.streamResetNeeded(getScene().getTimeStamp())) + { + // If there has been no event recorded yet, there is no need to worry about events with shape pointers which might later reference + // removed shapes due to buffered removal, i.e., removal while the simulation was running. + // This is also correct for CCD scenarios where a touch could get lost and then found again etc. If in such a case there ever is a contact event + // recorded, there will always be another sendLostTouchReport() call at some later point (caused by the simulation or when the shape gets + // removed at fetchResults). + PxU16 flagsToRaise = ContactStreamManagerFlag::eHAS_PAIRS_THAT_LOST_TOUCH; + + ContactStreamManager& cs = apr.getContactStreamManager(); + + if (shapeVolumeRemoved) + { + flagsToRaise |= ContactStreamManagerFlag::eTEST_FOR_REMOVED_SHAPES; + + // if an actor gets deleted while the simulation is running and the actor has a pending contact report with post solver + // velocity extra data, then the post solver velocity needs to get written now because it is too late when the reports + // get fired (the object will have been deleted already) + + if (cs.getFlags() & ContactStreamManagerFlag::eNEEDS_POST_SOLVER_VELOCITY) + setContactReportPostSolverVelocity(cs); + } + + cs.raiseFlags(flagsToRaise); + } +} + + +PX_FORCE_INLINE void Sc::ShapeInteraction::setPairFlags(PxPairFlags flags) +{ + PX_ASSERT(PxU32(flags) < PxPairFlag::eNEXT_FREE); // to find out if a new PxPairFlag has been added after eLAST instead of in front + + PxU32 newFlags = mFlags; + PxU32 fl = PxU32(flags) & PAIR_FLAGS_MASK; + newFlags &= (~PAIR_FLAGS_MASK); // clear old flags + newFlags |= fl; + + mFlags = newFlags; +} + + +// PT: returning PxU32 instead of PxPairFlags to remove LHS. Please do not undo this. +PX_FORCE_INLINE PxU32 Sc::ShapeInteraction::getPairFlags() const +{ + return (mFlags & PAIR_FLAGS_MASK); +} + + +PX_INLINE void Sc::ShapeInteraction::swapAndClearForceThresholdExceeded() +{ + PxU32 flags = mFlags; + + PX_COMPILE_TIME_ASSERT(FORCE_THRESHOLD_EXCEEDED_NOW == (FORCE_THRESHOLD_EXCEEDED_BEFORE >> 1)); + + PxU32 nowToBefore = (flags & FORCE_THRESHOLD_EXCEEDED_NOW) << 1; + flags &= ~(FORCE_THRESHOLD_EXCEEDED_NOW | FORCE_THRESHOLD_EXCEEDED_BEFORE); + flags |= nowToBefore; + + mFlags = flags; +} + +PX_FORCE_INLINE void Sc::ShapeInteraction::removeFromReportPairList() +{ + // this method should only get called if the pair is in the list for + // persistent or force based contact reports + PX_ASSERT(mReportPairIndex != INVALID_REPORT_PAIR_ID); + PX_ASSERT(readFlag(IS_IN_CONTACT_EVENT_LIST)); + + Scene& scene = getScene(); + + if (readFlag(IS_IN_FORCE_THRESHOLD_EVENT_LIST)) + scene.getNPhaseCore()->removeFromForceThresholdContactEventPairs(this); + else + { + PX_ASSERT(readFlag(IS_IN_PERSISTENT_EVENT_LIST)); + scene.getNPhaseCore()->removeFromPersistentContactEventPairs(this); + } +} + +PX_INLINE bool Sc::ShapeInteraction::updateManager(void* contactManager) +{ + if (activeManagerAllowed()) + { + if (mManager == 0) + createManager(contactManager); + + return (mManager != NULL); // creation might fail (pool reached limit, mem allocation failed etc.) + } + else + return false; +} + +PX_INLINE void Sc::ShapeInteraction::destroyManager() +{ + PX_ASSERT(mManager); + + Scene& scene = getScene(); + + PxvNphaseImplementationContext* nphaseImplementationContext = scene.getLowLevelContext()->getNphaseImplementationContext(); + PX_ASSERT(nphaseImplementationContext); + nphaseImplementationContext->unregisterContactManager(mManager); + + /*if (mEdgeIndex != IG_INVALID_EDGE) + scene.getSimpleIslandManager()->clearEdgeRigidCM(mEdgeIndex);*/ + scene.getLowLevelContext()->destroyContactManager(mManager); + mManager = 0; +} + + +PX_FORCE_INLINE bool Sc::ShapeInteraction::activeManagerAllowed() const +{ + PX_ASSERT(getShape0().getActor().isDynamicRigid() || getShape1().getActor().isDynamicRigid()); + + const BodySim* bodySim0 = getShape0().getBodySim(); + const BodySim* bodySim1 = getShape1().getBodySim(); + PX_ASSERT(bodySim0); // the first shape always belongs to a dynamic body + + const IG::IslandSim& islandSim = getScene().getSimpleIslandManager()->getSpeculativeIslandSim(); + + //if((bodySim0->isActive()) || (bodySim1 && bodySim1->isActive())) + //check whether active in the speculative sim! + if (islandSim.getNode(bodySim0->getNodeIndex()).isActive() || + (bodySim1 && islandSim.getNode(bodySim1->getNodeIndex()).isActive())) + { + return true; + } + else + { + //Sleeping kinematic 0 vs sleeping kinematic 1 + return false; + } +} + + +PX_FORCE_INLINE void Sc::ShapeInteraction::sendCCDRetouch(const PxU32 ccdPass, PxsContactManagerOutputIterator& outputs) +{ + PxU32 pairFlags = getPairFlags(); + if (pairFlags & PxPairFlag::eNOTIFY_TOUCH_CCD) + { + processUserNotification(PxPairFlag::eNOTIFY_TOUCH_CCD, 0, false, ccdPass, false, outputs); + } +} + + +PX_FORCE_INLINE void Sc::ShapeInteraction::adjustCountersOnLostTouch(BodySim* body0, BodySim* body1, bool useAdaptiveForce) +{ + PX_ASSERT(body0); // the first shape always belongs to a dynamic body + + PX_ASSERT(mActorPair->getTouchCount()); + + mActorPair->decTouchCount(); + + if (useAdaptiveForce || mActorPair->getTouchCount() == 0) + { + body0->decrementBodyConstraintCounter(); + if (body1) + body1->decrementBodyConstraintCounter(); + } +} + + +PX_FORCE_INLINE void Sc::ShapeInteraction::adjustCountersOnNewTouch(bool useAdaptiveForce) +{ + BodySim* body0 = getShape0().getBodySim(); + BodySim* body1 = getShape1().getBodySim(); + PX_ASSERT(body0); // the first shape always belongs to a dynamic body + + mActorPair->incTouchCount(); + //If using adaptive force, always record a body constraint, otherwise only record if this is the first constraint + //with this pair of bodies (doubling up usage of this counter for both adaptive force and stabilization) + if (useAdaptiveForce || mActorPair->getTouchCount() == 1) + { + body0->incrementBodyConstraintCounter(); + if (body1) + body1->incrementBodyConstraintCounter(); + } +} + + +PX_FORCE_INLINE Ps::IntBool Sc::ShapeInteraction::hasKnownTouchState() const +{ + // For a pair where the bodies were added asleep, the touch state is not known until narrowphase runs on the pair for the first time. + // If such a pair looses AABB overlap before, the conservative approach is to wake the bodies up. This method provides an indicator that + // this is such a pair. Note: this might also wake up objects that do not touch but that's the price to pay (unless we want to run + // overlap tests on such pairs). + + if (mManager) + return mManager->touchStatusKnown(); + else + return readFlag(TOUCH_KNOWN); +} + + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/ScShapeIterator.h b/PhysX_3.4/Source/SimulationController/src/ScShapeIterator.h new file mode 100644 index 00000000..0961178c --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScShapeIterator.h @@ -0,0 +1,70 @@ +// 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_SHAPEITERATOR +#define PX_PHYSICS_SCP_SHAPEITERATOR + +#include "foundation/PxVec3.h" +#include "ScActorSim.h" +#include "ScShapeSim.h" + +namespace physx +{ +namespace Sc +{ + class ShapeIterator + { + public: + PX_FORCE_INLINE ShapeIterator(const Sc::ActorSim& actorSim) + { + mCurrent = const_cast<ElementSim*>(actorSim.getElements_()); + } + + PX_INLINE Sc::ShapeSim* getNext() + { + while(1) + { + if(!mCurrent) + return NULL; + ElementSim* element = mCurrent; + mCurrent = mCurrent->mNextInActor; + if(element->getElementType() == Sc::ElementType::eSHAPE) // PT: this can also be a particle packet! + return static_cast<Sc::ShapeSim*>(element); + } + } + private: + ElementSim* mCurrent; + }; + +} // namespace Sc + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/ScShapeSim.cpp b/PhysX_3.4/Source/SimulationController/src/ScShapeSim.cpp new file mode 100644 index 00000000..46a20a62 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScShapeSim.cpp @@ -0,0 +1,524 @@ +// 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 "ScBodySim.h" +#include "ScStaticSim.h" +#include "ScScene.h" +#include "ScRbElementInteraction.h" +#include "ScParticleBodyInteraction.h" +#include "ScShapeInteraction.h" +#include "ScTriggerInteraction.h" +#include "ScSimStats.h" +#include "ScObjectIDTracker.h" +#include "GuHeightFieldUtil.h" +#include "GuTriangleMesh.h" +#include "GuConvexMeshData.h" +#include "GuHeightField.h" +#include "PxsContext.h" +#include "BpSimpleAABBManager.h" +#include "PxsTransformCache.h" +#include "CmTransformUtils.h" +#include "GuBounds.h" +#include "PxsRigidBody.h" +#include "ScSqBoundsManager.h" +#include "PxsSimulationController.h" + +#if PX_USE_PARTICLE_SYSTEM_API +#include "PtContext.h" +#endif + +#if PX_USE_PARTICLE_SYSTEM_API && PX_SUPPORT_GPU_PHYSX +#include "PxSceneGpu.h" +#endif + +using namespace physx; +using namespace Gu; + +// PT: keep local functions in cpp, no need to pollute the header. Don't force conversions to bool if not necessary. +static PX_FORCE_INLINE PxU32 hasTriggerFlags(PxShapeFlags flags) { return PxU32(flags) & PxU32(PxShapeFlag::eTRIGGER_SHAPE); } +static PX_FORCE_INLINE PxU32 isBroadPhase(PxShapeFlags flags) { return PxU32(flags) & PxU32(PxShapeFlag::eTRIGGER_SHAPE|PxShapeFlag::eSIMULATION_SHAPE); } + +namespace physx +{ + extern bool gUnifiedHeightfieldCollision; +} + +static PX_FORCE_INLINE void resetElementID(Sc::Scene& scene, Sc::ShapeSim& shapeSim) +{ + PX_ASSERT(!shapeSim.isInBroadPhase()); + + scene.getDirtyShapeSimMap().reset(shapeSim.getElementID()); + + if(shapeSim.getSqBoundsId() != PX_INVALID_U32) + shapeSim.destroySqBounds(); +} + +void Sc::ShapeSim::initSubsystemsDependingOnElementID() +{ + Sc::Scene& scScene = getScene(); + + Bp::BoundsArray& boundsArray = scScene.getBoundsArray(); + const PxU32 index = getElementID(); + + PX_ALIGN(16, PxTransform absPos); + getAbsPoseAligned(&absPos); + + PxsTransformCache& cache = scScene.getLowLevelContext()->getTransformCache(); + cache.initEntry(index); + cache.setTransformCache(absPos, 0, index); + + boundsArray.updateBounds(absPos, mCore.getGeometryUnion(), index, !gUnifiedHeightfieldCollision); + + { + PX_PROFILE_ZONE("API.simAddShapeToBroadPhase", scScene.getContextId()); + if(isBroadPhase(mCore.getFlags())) + { + internalAddToBroadPhase(); + + scScene.updateContactDistance(index, getContactOffset()); + } + } + + if(scScene.getDirtyShapeSimMap().size() <= index) + scScene.getDirtyShapeSimMap().resize(PxMax(index+1, (scScene.getDirtyShapeSimMap().size()+1) * 2u)); + + RigidSim& owner = getRbSim(); + if(owner.isDynamicRigid() && static_cast<BodySim&>(owner).isActive()) + createSqBounds(); + + // Init LL shape + { + mLLShape.mElementIndex = index; + mLLShape.mShapeCore = const_cast<PxsShapeCore*>(&mCore.getCore()); + + if(owner.getActorType()==PxActorType::eRIGID_STATIC) + { + mLLShape.mBodySimIndex = 0xffffffff; + } + else + { + BodySim& bodySim = static_cast<BodySim&>(getActor()); + const PxU32 nodeIndex = bodySim.getNodeIndex().index(); + mLLShape.mBodySimIndex = nodeIndex; + //mLLShape.mLocalBound = computeBounds(mCore.getGeometry(), PxTransform(PxIdentity)); + } + } +} + +Sc::ShapeSim::ShapeSim(RigidSim& owner, const ShapeCore& core) : + ElementSim (owner, ElementType::eSHAPE), + mCore (core), + mSqBoundsId (PX_INVALID_U32) +{ + // sizeof(ShapeSim) = 32 bytes + Sc::Scene& scScene = getScene(); + + mId = scScene.getShapeIDTracker().createID(); + + initSubsystemsDependingOnElementID(); +} + +Sc::ShapeSim::~ShapeSim() +{ + Sc::Scene& scScene = getScene(); + resetElementID(scScene, *this); + scScene.getShapeIDTracker().releaseID(mId); +} + +PX_FORCE_INLINE void Sc::ShapeSim::internalAddToBroadPhase() +{ + PX_ASSERT(!isInBroadPhase()); + addToAABBMgr(mCore.getContactOffset(), getRbSim().getBroadphaseGroupId(), !!(mCore.getCore().mShapeFlags & PxShapeFlag::eTRIGGER_SHAPE)); +} + +PX_FORCE_INLINE void Sc::ShapeSim::internalRemoveFromBroadPhase() +{ + PX_ASSERT(isInBroadPhase()); + removeFromAABBMgr(); + + Sc::Scene& scene = getScene(); + PxsContactManagerOutputIterator outputs = scene.getLowLevelContext()->getNphaseImplementationContext()->getContactManagerOutputs(); + scene.getNPhaseCore()->onVolumeRemoved(this, PxU32(PairReleaseFlag::eWAKE_ON_LOST_TOUCH), outputs, scene.getPublicFlags() & PxSceneFlag::eADAPTIVE_FORCE); +} + +void Sc::ShapeSim::removeFromBroadPhase(bool wakeOnLostTouch) +{ + if(isInBroadPhase()) + { + // PT: TODO: refactor with internalRemoveFromBroadPhase() + removeFromAABBMgr(); + Sc::Scene& scene = getScene(); + PxsContactManagerOutputIterator outputs = scene.getLowLevelContext()->getNphaseImplementationContext()->getContactManagerOutputs(); + scene.getNPhaseCore()->onVolumeRemoved(this, wakeOnLostTouch ? PxU32(PairReleaseFlag::eWAKE_ON_LOST_TOUCH) : 0, outputs, scene.getPublicFlags() & PxSceneFlag::eADAPTIVE_FORCE); + } +} + +void Sc::ShapeSim::reinsertBroadPhase() +{ + internalRemoveFromBroadPhase(); +// internalAddToBroadPhase(); + + Sc::Scene& scene = getScene(); + + // Sc::Scene::removeShape + { + //unregisterShapeFromNphase(shape.getCore()); + + // PT: "getID" is const but the addShape call used LLShape, which uses elementID, so.... + scene.getSimulationController()->removeShape(getID()); + } + + // Call ShapeSim dtor + { + resetElementID(scene, *this); + } + + // Call ElementSim dtor + { + releaseID(); + } + + // Call ElementSim ctor + { + initID(); + } + + // Call ShapeSim ctor + { + initSubsystemsDependingOnElementID(); + } + + // Sc::Scene::addShape + { + scene.getSimulationController()->addShape(&getLLShapeSim(), getID()); + // PT: TODO: anything else needed here? + //registerShapeInNphase(shapeCore); + } +} + +void Sc::ShapeSim::onFilterDataChange() +{ + setElementInteractionsDirty(InteractionDirtyFlag::eFILTER_STATE, InteractionFlag::eFILTERABLE); +} + +void Sc::ShapeSim::onResetFiltering() +{ + if(isInBroadPhase()) + reinsertBroadPhase(); +} + +void Sc::ShapeSim::onMaterialChange() +{ + setElementInteractionsDirty(InteractionDirtyFlag::eMATERIAL, InteractionFlag::eRB_ELEMENT); +} + +void Sc::ShapeSim::onRestOffsetChange() +{ + setElementInteractionsDirty(InteractionDirtyFlag::eREST_OFFSET, InteractionFlag::eRB_ELEMENT); +} + +void Sc::ShapeSim::onContactOffsetChange() +{ + if(isInBroadPhase()) + getScene().getAABBManager()->setContactOffset(getElementID(), mCore.getContactOffset()); +} + +void Sc::ShapeSim::onFlagChange(PxShapeFlags oldFlags) +{ + PxShapeFlags newFlags = mCore.getFlags(); + + const PxSceneFlags sceneFlags = getScene().getPublicFlags(); + + const bool oldBp = isBroadPhase(oldFlags)!=0; + const bool newBp = isBroadPhase(newFlags)!=0; + + // Change of collision shape flags requires removal/add to broadphase + if(oldBp != newBp) + { + if(!oldBp && newBp) + { + PX_ASSERT(!isInBroadPhase()); + internalAddToBroadPhase(); + } + else + { + internalRemoveFromBroadPhase(); + } + } + else + { + const bool wasTrigger = hasTriggerFlags(oldFlags)!=0; + const bool isTrigger = hasTriggerFlags(newFlags)!=0; + if(!(sceneFlags & PxSceneFlag::eDEPRECATED_TRIGGER_TRIGGER_REPORTS)) + { + if (wasTrigger != isTrigger) + reinsertBroadPhase(); // re-insertion is necessary because trigger-trigger pairs get killed + } + else + { + getScene().getAABBManager()->setVolumeType(this->getElementID(), PxU8((isTrigger ? Sc::ElementType::eTRIGGER : getElementType()))); + if (wasTrigger != isTrigger) + setElementInteractionsDirty(InteractionDirtyFlag::eFILTER_STATE, InteractionFlag::eFILTERABLE); + } + } + + PxShapeFlags hadSq = oldFlags&PxShapeFlag::eSCENE_QUERY_SHAPE, hasSq = newFlags&PxShapeFlag::eSCENE_QUERY_SHAPE; + if(hasSq && !hadSq) + { + if(getBodySim() && getBodySim()->isActive()) + createSqBounds(); + } + else if(hadSq && !hasSq) + destroySqBounds(); +} + +void Sc::ShapeSim::getFilterInfo(PxFilterObjectAttributes& filterAttr, PxFilterData& filterData) const +{ + filterAttr = 0; + const PxShapeFlags flags = mCore.getFlags(); + + if (hasTriggerFlags(flags)) + filterAttr |= PxFilterObjectFlag::eTRIGGER; + + BodySim* b = getBodySim(); + if (b) + { + if (!b->isArticulationLink()) + { + if (b->isKinematic()) + filterAttr |= PxFilterObjectFlag::eKINEMATIC; + + setFilterObjectAttributeType(filterAttr, PxFilterObjectType::eRIGID_DYNAMIC); + } + else + setFilterObjectAttributeType(filterAttr, PxFilterObjectType::eARTICULATION); + } + else + { + setFilterObjectAttributeType(filterAttr, PxFilterObjectType::eRIGID_STATIC); + } + + filterData = mCore.getSimulationFilterData(); +} + +void Sc::ShapeSim::getAbsPoseAligned(PxTransform* PX_RESTRICT globalPose) const +{ + const PxTransform& shape2Actor = mCore.getCore().transform; + const PxTransform* actor2World = NULL; + if(getActor().getActorType()==PxActorType::eRIGID_STATIC) + { + PxsRigidCore& core = static_cast<StaticSim&>(getActor()).getStaticCore().getCore(); + actor2World = &core.body2World; + } + else + { + PxsBodyCore& core = static_cast<BodySim&>(getActor()).getBodyCore().getCore(); + if(!core.mIdtBody2Actor) + { + Cm::getDynamicGlobalPoseAligned(core.body2World, shape2Actor, core.getBody2Actor(), *globalPose); + return; + } + actor2World = &core.body2World; + } + Cm::getStaticGlobalPoseAligned(*actor2World, shape2Actor, *globalPose); +} + +Sc::BodySim* Sc::ShapeSim::getBodySim() const +{ + ActorSim& a = getActor(); + return a.isDynamicRigid() ? static_cast<BodySim*>(&a) : NULL; +} + +PxsRigidCore& Sc::ShapeSim::getPxsRigidCore() const +{ + ActorSim& a = getActor(); + return a.isDynamicRigid() ? static_cast<BodySim&>(a).getBodyCore().getCore() + : static_cast<StaticSim&>(a).getStaticCore().getCore(); +} + +bool Sc::ShapeSim::actorIsDynamic() const +{ + return getActor().isDynamicRigid(); +} + +void Sc::ShapeSim::updateCached(PxU32 transformCacheFlags, Cm::BitMapPinned* shapeChangedMap) +{ + PX_ALIGN(16, PxTransform absPose); + getAbsPoseAligned(&absPose); + + Sc::Scene& scene = getScene(); + const PxU32 index = getElementID(); + + scene.getLowLevelContext()->getTransformCache().setTransformCache(absPose, transformCacheFlags, index); + scene.getBoundsArray().updateBounds(absPose, mCore.getGeometryUnion(), index, !gUnifiedHeightfieldCollision); + if (shapeChangedMap && isInBroadPhase()) + shapeChangedMap->growAndSet(index); +} + +void Sc::ShapeSim::updateCached(PxsTransformCache& transformCache, Bp::BoundsArray& boundsArray) +{ + const PxU32 index = getElementID(); + + PxsCachedTransform& ct = transformCache.getTransformCache(index); + Ps::prefetchLine(&ct); + + getAbsPoseAligned(&ct.transform); + + ct.flags = 0; + + PxBounds3& b = boundsArray.begin()[index]; + Gu::computeBounds(b, mCore.getGeometryUnion().getGeometry(), ct.transform, 0.0f, NULL, 1.0f, !physx::gUnifiedHeightfieldCollision); +} + +void Sc::ShapeSim::updateContactDistance(PxReal* contactDistance, const PxReal inflation, const PxVec3 angVel, const PxReal dt, Bp::BoundsArray& boundsArray) +{ + const PxU32 index = getElementID(); + + const PxBounds3& bounds = boundsArray.getBounds(index); + + PxReal radius = bounds.getExtents().magnitude(); + + //Heuristic for angular velocity... + PxReal angularInflation = angVel.magnitude() * dt * radius; + + contactDistance[index] = getContactOffset() + inflation + angularInflation; +} + +Ps::IntBool Sc::ShapeSim::updateSweptBounds() +{ + Vec3p endOrigin, endExtent; + const ShapeCore& shapeCore = mCore; + const PxTransform& endPose = getScene().getLowLevelContext()->getTransformCache().getTransformCache(getElementID()).transform; + PxReal ccdThreshold = computeBoundsWithCCDThreshold(endOrigin, endExtent, shapeCore.getGeometry(), endPose, NULL); + + PxBounds3 bounds = PxBounds3::centerExtents(endOrigin, endExtent); + + PxcRigidBody& rigidBody = getBodySim()->getLowLevelBody(); + PxsBodyCore& bodyCore = getBodySim()->getBodyCore().getCore(); + PX_ALIGN(16, PxTransform shape2World); + Cm::getDynamicGlobalPoseAligned(rigidBody.mLastTransform, shapeCore.getShape2Actor(), bodyCore.getBody2Actor(), shape2World); + PxBounds3 startBounds = computeBounds(shapeCore.getGeometry(), shape2World, !physx::gUnifiedHeightfieldCollision); + + Ps::IntBool isFastMoving = (startBounds.getCenter() - endOrigin).magnitudeSquared() >= ccdThreshold * ccdThreshold ? 1 : 0;; + + if (isFastMoving) + bounds.include(startBounds); + + PX_ASSERT(bounds.minimum.x <= bounds.maximum.x + && bounds.minimum.y <= bounds.maximum.y + && bounds.minimum.z <= bounds.maximum.z); + + getScene().getBoundsArray().setBounds(bounds, getElementID()); + + return isFastMoving; +} + +void Sc::ShapeSim::onVolumeOrTransformChange(bool asPartOfActorTransformChange, bool forceBoundsUpdate) +{ + Sc::Scene& scene = getScene(); + + Sc::BodySim* body = getBodySim(); + const bool isDynamic = (body != NULL); + bool isAsleep; + if (body) + { + isAsleep = !body->isActive(); + body->postShapeChange(asPartOfActorTransformChange); + } + else + isAsleep = true; + + ElementSim::ElementInteractionIterator iter = getElemInteractions(); + ElementSimInteraction* i = iter.getNext(); + while(i) + { + if(i->getType() == InteractionType::eOVERLAP) + { + Sc::ShapeInteraction* si = static_cast<Sc::ShapeInteraction*>(i); + si->resetManagerCachedState(); + + if (isAsleep) + si->onShapeChangeWhileSleeping(isDynamic); + } + else if (i->getType() == InteractionType::eTRIGGER) + (static_cast<Sc::TriggerInteraction*>(i))->forceProcessingThisFrame(scene); // trigger pairs need to be checked next frame +#if PX_USE_PARTICLE_SYSTEM_API + else if (i->getType() == InteractionType::ePARTICLE_BODY) + (static_cast<Sc::ParticleElementRbElementInteraction *>(i))->onRbShapeChange(); +#endif + + i = iter.getNext(); + } + + + const PxU32 elementID = getElementID(); + + if (forceBoundsUpdate) + { + updateCached(0, &scene.getAABBManager()->getChangedAABBMgActorHandleMap()); + } + else if (isInBroadPhase()) + scene.getDirtyShapeSimMap().growAndSet(elementID); + +#if PX_USE_PARTICLE_SYSTEM_API +#if PX_SUPPORT_GPU_PHYSX + // PT: onShapeChange currently only used for GPU physics. Inlined 'getSceneGpu' call avoids + // extra function calls and additional work from getPxsRigidCore(), etc + Pt::Context* context = scene.getParticleContext(); + if(context->getSceneGpuFast()) + { + context->getSceneGpuFast()->onShapeChange(size_t(&mCore.getCore()), size_t(&getPxsRigidCore()), (body != NULL)); + } +#endif +#endif +} + +void Sc::ShapeSim::createSqBounds() +{ + if(mSqBoundsId!=PX_INVALID_U32) + return; + + Sc::BodySim* bodySim = getBodySim(); + + PX_ASSERT(bodySim); + + if(bodySim->usingSqKinematicTarget() || bodySim->isFrozen() || !bodySim->isActive()) + return; + + if(mCore.getFlags() & PxShapeFlag::eSCENE_QUERY_SHAPE) + getScene().getSqBoundsManager().addShape(*this); +} + +void Sc::ShapeSim::destroySqBounds() +{ + if(mSqBoundsId!=PX_INVALID_U32) + getScene().getSqBoundsManager().removeShape(*this); +} + diff --git a/PhysX_3.4/Source/SimulationController/src/ScShapeSim.h b/PhysX_3.4/Source/SimulationController/src/ScShapeSim.h new file mode 100644 index 00000000..f59e4823 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScShapeSim.h @@ -0,0 +1,153 @@ +// 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_SHAPESIM +#define PX_PHYSICS_SCP_SHAPESIM + +#include "ScElementSim.h" +#include "ScShapeCore.h" +#include "CmPtrTable.h" +#include "ScRigidSim.h" +#include "PxsShapeSim.h" + +namespace physx +{ + + class PxsTransformCache; +namespace Gu +{ + class TriangleMesh; + class HeightField; +} + +/** Simulation object corresponding to a shape core object. This object is created when + a ShapeCore object is added to the simulation, and destroyed when it is removed +*/ + +struct PxsRigidCore; + +namespace Sc +{ + + class RigidSim; + class ShapeCore; + class Scene; + class BodySim; + class StaticSim; + + PX_ALIGN_PREFIX(16) + class ShapeSim : public ElementSim + { + ShapeSim &operator=(const ShapeSim &); + public: + + // passing in a pointer for the shape to output its bounds allows us not to have to compute them twice. + // A neater way to do this would be to ask the AABB Manager for the bounds after the shape has been + // constructed, but there is currently no spec for what the AABBMgr is allowed to do with the bounds, + // hence better not to assume anything. + + ShapeSim(RigidSim&, const ShapeCore& core); + virtual ~ShapeSim(); + + // ElementSim + virtual void getFilterInfo(PxFilterObjectAttributes& filterAttr, PxFilterData& filterData) const; + //~ElementSim + + void reinsertBroadPhase(); + + PX_FORCE_INLINE const ShapeCore& getCore() const { return mCore; } + + // TODO: compile time coupling + + PX_INLINE PxGeometryType::Enum getGeometryType() const { return mCore.getGeometryType(); } + + // This is just for getting a reference for the user, so we cast away const-ness + + PX_INLINE PxShape* getPxShape() const { return const_cast<PxShape*>(mCore.getPxShape()); } + + PX_FORCE_INLINE PxReal getRestOffset() const { return mCore.getRestOffset(); } + PX_FORCE_INLINE PxU32 getFlags() const { return mCore.getFlags(); } + PX_FORCE_INLINE PxReal getContactOffset() const { return mCore.getContactOffset(); } + + PX_FORCE_INLINE RigidSim& getRbSim() const { return static_cast<RigidSim&>(getActor()); } + BodySim* getBodySim() const; + + PxsRigidCore& getPxsRigidCore() const; + bool actorIsDynamic() const; + + void onFilterDataChange(); + void onRestOffsetChange(); + void onFlagChange(PxShapeFlags oldFlags); + void onResetFiltering(); + void onVolumeOrTransformChange(bool asPartOfActorTransformChange, bool forceBoundsUpdate = false); + void onMaterialChange(); // remove when material properties are gone from PxcNpWorkUnit + void onContactOffsetChange(); + + void getAbsPoseAligned(PxTransform* PX_RESTRICT globalPose) const; + + PX_FORCE_INLINE PxU32 getID() const { return mId; } + PX_FORCE_INLINE PxU32 getTransformCacheID() const { return getElementID(); } + + void removeFromBroadPhase(bool wakeOnLostTouch); + + void createSqBounds(); + void destroySqBounds(); + + PX_FORCE_INLINE PxU32 getSqBoundsId() const { return mSqBoundsId; } + PX_FORCE_INLINE void setSqBoundsId(PxU32 id) { mSqBoundsId = id; } + + void updateCached(PxU32 transformCacheFlags, Cm::BitMapPinned* shapeChangedMap); + void updateCached(PxsTransformCache& transformCache, Bp::BoundsArray& boundsArray); + void updateContactDistance(PxReal* contactDistance, const PxReal inflation, const PxVec3 angVel, const PxReal dt, Bp::BoundsArray& boundsArray); + Ps::IntBool updateSweptBounds(); + + PX_FORCE_INLINE PxsShapeSim& getLLShapeSim() { return mLLShape; } + private: + PxsShapeSim mLLShape; + const ShapeCore& mCore; + PxU32 mId; + PxU32 mSqBoundsId; + + PX_FORCE_INLINE void internalAddToBroadPhase(); + PX_FORCE_INLINE void internalRemoveFromBroadPhase(); + void initSubsystemsDependingOnElementID(); + } + PX_ALIGN_SUFFIX(16); + +#if !PX_P64_FAMILY +// PX_COMPILE_TIME_ASSERT(32==sizeof(Sc::ShapeSim)); // after removing bounds from shapes +// PX_COMPILE_TIME_ASSERT((sizeof(Sc::ShapeSim) % 16) == 0); // aligned mem bounds are better for prefetching +#endif + +} // namespace Sc + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/ScSimStateData.h b/PhysX_3.4/Source/SimulationController/src/ScSimStateData.h new file mode 100644 index 00000000..331031e8 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScSimStateData.h @@ -0,0 +1,135 @@ +// 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_SIMSTATEDATA +#define PX_SIMSTATEDATA + +#include "foundation/PxMemory.h" +#include "ScBodyCore.h" + +namespace physx +{ +namespace Sc +{ + struct Kinematic : public KinematicTransform + { + // The following members buffer the original body data to restore them when switching back to dynamic body + // (for kinematics the corresponding LowLevel properties are set to predefined values) + PxVec3 backupInverseInertia; // The inverse of the body space inertia tensor + PxReal backupInvMass; // The inverse of the body mass + PxReal backupLinearDamping; // The velocity is scaled by (1.0f - this * dt) inside integrateVelocity() every substep. + PxReal backupAngularDamping; + PxReal backupMaxAngVelSq; // The angular velocity's magnitude is clamped to this maximum value. + PxReal backupMaxLinVelSq; // The angular velocity's magnitude is clamped to this maximum value + }; + PX_COMPILE_TIME_ASSERT(0 == (sizeof(Kinematic) & 0x0f)); + + // Important: Struct is reset in setForcesToDefaults. + + enum VelocityModFlags + { + VMF_GRAVITY_DIRTY = (1 << 0), + VMF_ACC_DIRTY = (1 << 1), + VMF_VEL_DIRTY = (1 << 2) + }; + + struct VelocityMod + { + PxVec3 linearPerSec; // A request to change the linear velocity by this much each second. The velocity is changed by this * dt inside integrateVelocity(). + PxU8 flags; + PxU8 pad0[3]; + PxVec3 angularPerSec; + PxU8 pad1[3]; + PxU8 type; + PxVec3 linearPerStep; // A request to change the linear velocity by this much the next step. The velocity is changed inside updateForces(). + PxU32 pad2; + PxVec3 angularPerStep; + PxU32 pad3; + + PX_FORCE_INLINE void clear() { linearPerSec = angularPerSec = linearPerStep = angularPerStep = PxVec3(0.0f); } + + PX_FORCE_INLINE const PxVec3& getLinearVelModPerSec() const { return linearPerSec; } + PX_FORCE_INLINE void accumulateLinearVelModPerSec(const PxVec3& v) { linearPerSec += v; } + PX_FORCE_INLINE void clearLinearVelModPerSec() { linearPerSec = PxVec3(0.0f); } + + PX_FORCE_INLINE const PxVec3& getLinearVelModPerStep() const { return linearPerStep; } + PX_FORCE_INLINE void accumulateLinearVelModPerStep(const PxVec3& v) { linearPerStep += v; } + PX_FORCE_INLINE void clearLinearVelModPerStep() { linearPerStep = PxVec3(0.0f); } + + PX_FORCE_INLINE const PxVec3& getAngularVelModPerSec() const { return angularPerSec; } + PX_FORCE_INLINE void accumulateAngularVelModPerSec(const PxVec3& v) { angularPerSec += v; } + PX_FORCE_INLINE void clearAngularVelModPerSec() { angularPerSec = PxVec3(0.0f); } + + PX_FORCE_INLINE const PxVec3& getAngularVelModPerStep() const { return angularPerStep; } + PX_FORCE_INLINE void accumulateAngularVelModPerStep(const PxVec3& v) { angularPerStep += v; } + PX_FORCE_INLINE void clearAngularVelModPerStep() { angularPerStep = PxVec3(0.0f); } + + PX_FORCE_INLINE void notifyAddAcceleration() { flags |= VMF_ACC_DIRTY; } + PX_FORCE_INLINE void notifyClearAcceleration() { flags |= VMF_ACC_DIRTY; } + PX_FORCE_INLINE void notifyAddVelocity() { flags |= VMF_VEL_DIRTY; } + PX_FORCE_INLINE void notifyClearVelocity() { flags |= VMF_VEL_DIRTY; } + }; + PX_COMPILE_TIME_ASSERT(sizeof(VelocityMod) == sizeof(Kinematic)); + + + // Structure to store data for kinematics (target pose etc.) + // note: we do not delete this object for kinematics even if no target is set. + struct SimStateData : public Ps::UserAllocated // TODO: may want to optimize the allocation of this further. + { + PxU8 data[sizeof(Kinematic)]; + + enum Enum + { + eVelMod=0, + eKine + }; + + SimStateData(){} + SimStateData(const PxU8 type) + { + PxMemZero(data, sizeof(Kinematic)); + Kinematic* kine = reinterpret_cast<Kinematic*>(data); + kine->type = type; + } + + PX_FORCE_INLINE PxU32 getType() const { const Kinematic* kine = reinterpret_cast<const Kinematic*>(data); return kine->type;} + PX_FORCE_INLINE bool isKine() const {return eKine == getType();} + PX_FORCE_INLINE bool isVelMod() const {return eVelMod == getType();} + + Kinematic* getKinematicData() { Kinematic* kine = reinterpret_cast<Kinematic*>(data); PX_ASSERT(eKine == kine->type); return kine;} + VelocityMod* getVelocityModData() { VelocityMod* velmod = reinterpret_cast<VelocityMod*>(data); PX_ASSERT(eVelMod == velmod->type); return velmod;} + const Kinematic* getKinematicData() const { const Kinematic* kine = reinterpret_cast<const Kinematic*>(data); PX_ASSERT(eKine == kine->type); return kine;} + const VelocityMod* getVelocityModData() const { const VelocityMod* velmod = reinterpret_cast<const VelocityMod*>(data); PX_ASSERT(eVelMod == velmod->type); return velmod;} + }; + +} // namespace Sc + +} // namespace physx + +#endif //PX_SIMSTATEDATA diff --git a/PhysX_3.4/Source/SimulationController/src/ScSimStats.cpp b/PhysX_3.4/Source/SimulationController/src/ScSimStats.cpp new file mode 100644 index 00000000..459b81d2 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScSimStats.cpp @@ -0,0 +1,143 @@ +// 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 "foundation/PxMemory.h" +#include "ScSimStats.h" +#include "PxvSimStats.h" + +using namespace physx; + +static const PxU32 sBroadphaseAddRemoveSize = sizeof(PxU32) * PxSimulationStatistics::eVOLUME_COUNT; + +Sc::SimStats::SimStats() +{ + PxMemZero(&numBroadPhaseAdds, sBroadphaseAddRemoveSize); + PxMemZero(&numBroadPhaseRemoves, sBroadphaseAddRemoveSize); + + clear(); +} + + +void Sc::SimStats::clear() +{ +#if PX_ENABLE_SIM_STATS + PxMemZero(const_cast<void*>(reinterpret_cast<volatile void*>(&numTriggerPairs)), sizeof(TriggerPairCounts)); + PxMemZero(&numBroadPhaseAddsPending, sBroadphaseAddRemoveSize); + PxMemZero(&numBroadPhaseRemovesPending, sBroadphaseAddRemoveSize); +#endif +} + + +void Sc::SimStats::simStart() +{ +#if PX_ENABLE_SIM_STATS + // pending broadphase adds/removes are now the current ones + PxMemMove(numBroadPhaseAdds, numBroadPhaseAddsPending, sBroadphaseAddRemoveSize); + PxMemMove(numBroadPhaseRemoves, numBroadPhaseRemovesPending, sBroadphaseAddRemoveSize); + clear(); +#endif +} + + +void Sc::SimStats::readOut(PxSimulationStatistics& s, const PxvSimStats& simStats) const +{ +#if PX_ENABLE_SIM_STATS + s = PxSimulationStatistics(); // clear stats + + for(PxU32 i=0; i < PxGeometryType::eCONVEXMESH+1; i++) + { + for(PxU32 j=0; j < PxGeometryType::eGEOMETRY_COUNT; j++) + { + s.nbTriggerPairs[i][j] += PxU32(numTriggerPairs[i][j]); + if (i != j) + s.nbTriggerPairs[j][i] += PxU32(numTriggerPairs[i][j]); + } + } + + for(PxU32 i=0; i < PxSimulationStatistics::eVOLUME_COUNT; i++) + { + s.nbBroadPhaseAdds[i] = numBroadPhaseAdds[i]; + s.nbBroadPhaseRemoves[i] = numBroadPhaseRemoves[i]; + } + + for(PxU32 i=0; i < PxGeometryType::eGEOMETRY_COUNT; i++) + { + s.nbDiscreteContactPairs[i][i] = simStats.mNbDiscreteContactPairs[i][i]; + s.nbModifiedContactPairs[i][i] = simStats.mNbModifiedContactPairs[i][i]; + s.nbCCDPairs[i][i] = simStats.mNbCCDPairs[i][i]; + + for(PxU32 j=i+1; j < PxGeometryType::eGEOMETRY_COUNT; j++) + { + PxU32 c = simStats.mNbDiscreteContactPairs[i][j]; + s.nbDiscreteContactPairs[i][j] = c; + s.nbDiscreteContactPairs[j][i] = c; + + c = simStats.mNbModifiedContactPairs[i][j]; + s.nbModifiedContactPairs[i][j] = c; + s.nbModifiedContactPairs[j][i] = c; + + c = simStats.mNbCCDPairs[i][j]; + s.nbCCDPairs[i][j] = c; + s.nbCCDPairs[j][i] = c; + } +#if PX_DEBUG + for(PxU32 j=0; j < i; j++) + { + // PxvSimStats should only use one half of the matrix + PX_ASSERT(simStats.mNbDiscreteContactPairs[i][j] == 0); + PX_ASSERT(simStats.mNbModifiedContactPairs[i][j] == 0); + PX_ASSERT(simStats.mNbCCDPairs[i][j] == 0); + } +#endif + } + + s.nbDiscreteContactPairsTotal = simStats.mNbDiscreteContactPairsTotal; + s.nbDiscreteContactPairsWithCacheHits = simStats.mNbDiscreteContactPairsWithCacheHits; + s.nbDiscreteContactPairsWithContacts = simStats.mNbDiscreteContactPairsWithContacts; + s.nbActiveConstraints = simStats.mNbActiveConstraints; + s.nbActiveDynamicBodies = simStats.mNbActiveDynamicBodies; + s.nbActiveKinematicBodies = simStats.mNbActiveKinematicBodies; + + s.nbAxisSolverConstraints = simStats.mNbAxisSolverConstraints; + + s.peakConstraintMemory = simStats.mPeakConstraintBlockAllocations * 16 * 1024; + s.compressedContactSize = simStats.mTotalCompressedContactSize; + s.requiredContactConstraintMemory = simStats.mTotalConstraintSize; + s.nbNewPairs = simStats.mNbNewPairs; + s.nbLostPairs = simStats.mNbLostPairs; + s.nbNewTouches = simStats.mNbNewTouches; + s.nbLostTouches = simStats.mNbLostTouches; + s.nbPartitions = simStats.mNbPartitions; + +#else + PX_UNUSED(s); + PX_UNUSED(simStats); +#endif +} diff --git a/PhysX_3.4/Source/SimulationController/src/ScSimStats.h b/PhysX_3.4/Source/SimulationController/src/ScSimStats.h new file mode 100644 index 00000000..1078ba70 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScSimStats.h @@ -0,0 +1,89 @@ +// 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_SIM_STATS +#define PX_PHYSICS_SCP_SIM_STATS + +#include "PsAtomic.h" +#include "PsUserAllocated.h" +#include "CmPhysXCommon.h" +#include "PxGeometry.h" +#include "PxSimulationStatistics.h" + +namespace physx +{ + +struct PxvSimStats; + +namespace Sc +{ + + /* + Description: contains statistics for the scene. + */ + class SimStats : public Ps::UserAllocated + { + public: + SimStats(); + + void clear(); //set counters to zero + void simStart(); + void readOut(PxSimulationStatistics& dest, const PxvSimStats& simStats) const; + + PX_INLINE void incBroadphaseAdds(PxSimulationStatistics::VolumeType v) + { + numBroadPhaseAddsPending[v]++; + } + + PX_INLINE void incBroadphaseRemoves(PxSimulationStatistics::VolumeType v) + { + numBroadPhaseRemovesPending[v]++; + } + + private: + // Broadphase adds/removes for the current simulation step + PxU32 numBroadPhaseAdds[PxSimulationStatistics::eVOLUME_COUNT]; + PxU32 numBroadPhaseRemoves[PxSimulationStatistics::eVOLUME_COUNT]; + + // Broadphase adds/removes for the next simulation step + PxU32 numBroadPhaseAddsPending[PxSimulationStatistics::eVOLUME_COUNT]; + PxU32 numBroadPhaseRemovesPending[PxSimulationStatistics::eVOLUME_COUNT]; + + public: + typedef PxI32 TriggerPairCountsNonVolatile[PxGeometryType::eCONVEXMESH+1][PxGeometryType::eGEOMETRY_COUNT]; + typedef volatile TriggerPairCountsNonVolatile TriggerPairCounts; + TriggerPairCounts numTriggerPairs; + }; + +} // namespace Sc + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/ScSimulationController.cpp b/PhysX_3.4/Source/SimulationController/src/ScSimulationController.cpp new file mode 100644 index 00000000..53e09b19 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScSimulationController.cpp @@ -0,0 +1,43 @@ +// 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 "ScSimulationController.h" +#include "PsAllocator.h" + +using namespace physx; + +PxsSimulationController* physx::createSimulationController(PxsSimulationControllerCallback* callback) +{ + return PX_PLACEMENT_NEW(PX_ALLOC(sizeof(Sc::SimulationController), PX_DEBUG_EXP("ScSimulationController")), Sc::SimulationController(callback)); +} + +void Sc::SimulationController::udpateScBodyAndShapeSim(PxsTransformCache& /*cache*/, Bp::BoundsArray& /*boundArray*/, PxBaseTask* continuation) +{ + mCallback->updateScBodyAndShapeSim(continuation); +} diff --git a/PhysX_3.4/Source/SimulationController/src/ScSimulationController.h b/PhysX_3.4/Source/SimulationController/src/ScSimulationController.h new file mode 100644 index 00000000..fd6f4e68 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScSimulationController.h @@ -0,0 +1,87 @@ +// 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 "PxsSimulationController.h" + +#ifndef SC_SIMULATION_CONTROLLER_H +#define SC_SIMULATION_CONTROLLER_H + + +namespace physx +{ + +class PxsHeapMemoryAllocator; + +namespace Sc +{ + class SimulationController : public PxsSimulationController + { + PX_NOCOPY(SimulationController) + public: + SimulationController(PxsSimulationControllerCallback* callback): PxsSimulationController(callback) + { + } + + virtual ~SimulationController(){} + virtual void addJoint(const PxU32 /*edgeIndex*/, Dy::Constraint* /*constraint*/, IG::IslandSim& /*islandSim*/, Ps::Array<PxU32, Ps::VirtualAllocator>& /*jointIndices*/, + Ps::Array<PxgSolverConstraintManagerConstants, Ps::VirtualAllocator>& /*managerIter*/, PxU32 /*uniqueId*/){} + virtual void removeJoint(const PxU32 /*edgeIndex*/, Dy::Constraint* /*constraint*/, Ps::Array<PxU32, Ps::VirtualAllocator>& /*jointIndices*/, IG::IslandSim& /*islandSim*/){} + virtual void addShape(PxsShapeSim* /*shapeSim*/, const PxU32 /*index*/){} + virtual void removeShape(const PxU32 /*index*/){} + virtual void addDynamic(PxsRigidBody* /*rigidBody*/, const PxU32 /*nodeIndex*/){} + virtual void addDynamics(PxsRigidBody** /*rigidBody*/, const PxU32* /*nodeIndex*/, PxU32 /*nbBodies*/) {} + virtual void updateJoint(const PxU32 /*edgeIndex*/, Dy::Constraint* /*constraint*/){} + virtual void updateBodies(PxsRigidBody** /*rigidBodies*/, PxU32* /*nodeIndices*/, const PxU32 /*nbBodies*/) {} + virtual void updateBody(PxsRigidBody* /*rigidBody*/, const PxU32 /*nodeIndex*/) {} + virtual void updateBodiesAndShapes(PxBaseTask* /*continuation*/, bool /*extrudeHeightfields*/){} + virtual void update(const PxU32 /*bitMapWordCounts*/){} + virtual void gpuDmabackData(PxsTransformCache& /*cache*/, Bp::BoundsArray& /*boundArray*/, Cm::BitMapPinned& /*changedAABBMgrHandles*/){} + virtual void udpateScBodyAndShapeSim(PxsTransformCache& cache, Bp::BoundsArray& boundArray, PxBaseTask* continuation); + virtual PxU32* getActiveBodies() { return NULL; } + virtual PxU32* getDeactiveBodies() { return NULL; } + virtual PxsBodySim* getBodySims() { return NULL; } + virtual PxU32 getNbBodies() { return 0; } + virtual PxU32 getNbFrozenShapes() { return 0; } + virtual PxU32 getNbUnfrozenShapes() { return 0; } + + virtual PxU32* getUnfrozenShapes() { return NULL; } + virtual PxU32* getFrozenShapes() { return NULL; } + virtual PxsShapeSim** getShapeSims() { return NULL; } + virtual PxU32 getNbShapes() { return 0; } + + virtual void clear() { } + virtual void setBounds(Bp::BoundsArray* /*boundArray*/){} + virtual void reserve(const PxU32 /*nbBodies*/) {} + + }; +} + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/ScSqBoundsManager.cpp b/PhysX_3.4/Source/SimulationController/src/ScSqBoundsManager.cpp new file mode 100644 index 00000000..5ea2ebde --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScSqBoundsManager.cpp @@ -0,0 +1,122 @@ +// 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 "CmPhysXCommon.h" +#include "ScSqBoundsManager.h" +#include "ScBodySim.h" +#include "ScShapeSim.h" +#include "ScShapeIterator.h" +#include "CmTransformUtils.h" +#include "PxsTransformCache.h" +#include <stdio.h> + +namespace physx +{ +namespace Sc +{ + + SqBoundsManager::SqBoundsManager() : + mShapes(PX_DEBUG_EXP("SqBoundsManager::mRefs")), + mRefs(PX_DEBUG_EXP("SqBoundsManager::mRefs")), + mBoundsIndices(PX_DEBUG_EXP("SqBoundsManager::mRefs")), + mRefless(PX_DEBUG_EXP("SqBoundsManager::mRefs")) + +{ +} + +void SqBoundsManager::addShape(ShapeSim& shape) +{ + PX_ASSERT(shape.getFlags() & PxShapeFlag::eSCENE_QUERY_SHAPE); + PX_ASSERT(!shape.getBodySim()->usingSqKinematicTarget()); + PX_ASSERT(!shape.getBodySim()->isFrozen()); + + PxU32 id = mShapes.size(); + mShapes.pushBack(&shape); + mRefs.pushBack(PX_INVALID_U32); + mBoundsIndices.pushBack(shape.getElementID()); + mRefless.insert(&shape); + + shape.setSqBoundsId(id); +} + +void SqBoundsManager::removeShape(ShapeSim& shape) +{ + PxU32 id = shape.getSqBoundsId(); + if(mRefs[id] == PX_INVALID_U32) + { + PX_ASSERT(mRefless.contains(&shape)); + mRefless.erase(&shape); + } + + shape.setSqBoundsId(PX_INVALID_U32); + mShapes[id] = mShapes.back(); + mBoundsIndices[id] = mBoundsIndices.back(); + mRefs[id] = mRefs.back(); + + if(id+1 != mShapes.size()) + mShapes[id]->setSqBoundsId(id); + + mShapes.popBack(); + mRefs.popBack(); + mBoundsIndices.popBack(); +} + + +void SqBoundsManager::syncBounds(SqBoundsSync& sync, SqRefFinder& finder, const PxBounds3* bounds, PxU64 contextID) +{ + PX_PROFILE_ZONE("Sim.sceneQuerySyncBounds", contextID); + PX_UNUSED(contextID); + +#if PX_DEBUG + for(PxU32 i=0;i<mShapes.size();i++) + { + ShapeSim& shape = *mShapes[i]; + PX_UNUSED(shape); + PX_ASSERT(shape.getFlags() & PxShapeFlag::eSCENE_QUERY_SHAPE); + PX_ASSERT(!shape.getBodySim()->usingSqKinematicTarget()); + PX_ASSERT(!shape.getBodySim()->isFrozen()); + } +#endif + + ShapeSim*const * shapes = mRefless.getEntries(); + for(PxU32 i=0, size = mRefless.size();i<size;i++) + { + PxU32 id = shapes[i]->getSqBoundsId(); + PX_ASSERT(mRefs[id] == PX_INVALID_U32); + mRefs[id] = finder.find(static_cast<PxRigidBody*>(shapes[i]->getBodySim()->getPxActor()), shapes[i]->getPxShape()); + } + mRefless.clear(); + + sync.sync(mRefs.begin(), mBoundsIndices.begin(), bounds, mShapes.size()); +} + + +} + +} diff --git a/PhysX_3.4/Source/SimulationController/src/ScSqBoundsManager.h b/PhysX_3.4/Source/SimulationController/src/ScSqBoundsManager.h new file mode 100644 index 00000000..46006622 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScSqBoundsManager.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_SCP_SQ_BOUNDS_MANAGER +#define PX_PHYSICS_SCP_SQ_BOUNDS_MANAGER + +#include "CmPhysXCommon.h" +#include "foundation/PxBounds3.h" +#include "PsArray.h" +#include "PsUserAllocated.h" +#include "CmTask.h" +#include "PsHashSet.h" + +namespace physx +{ + + +namespace Cm +{ + class FlushPool; + class EventProfiler; +} + +namespace Sc +{ + +struct SqBoundsSync; +struct SqRefFinder; +class Scene; +class ShapeSim; + +class SqBoundsManager : public Ps::UserAllocated +{ + PX_NOCOPY(SqBoundsManager) +public: + SqBoundsManager(); + + void addShape(ShapeSim& shape); + void removeShape(ShapeSim& shape); + void syncBounds(SqBoundsSync& sync, SqRefFinder& finder, const PxBounds3* bounds, PxU64 contextID); + +private: + + Ps::Array<ShapeSim*> mShapes; // + Ps::Array<PxU32> mRefs; // SQ pruner references + Ps::Array<PxU32> mBoundsIndices; // indices into the Sc bounds array + Ps::CoalescedHashSet<ShapeSim*> mRefless; // shapesims without references +}; +} +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/ScStaticCore.cpp b/PhysX_3.4/Source/SimulationController/src/ScStaticCore.cpp new file mode 100644 index 00000000..b32b10ee --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScStaticCore.cpp @@ -0,0 +1,49 @@ +// 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 "ScStaticCore.h" +#include "ScStaticSim.h" +#include "PxRigidStatic.h" + +using namespace physx; + +Sc::StaticSim* Sc::StaticCore::getSim() const +{ + return static_cast<StaticSim*>(Sc::ActorCore::getSim()); +} + +void Sc::StaticCore::setActor2World(const PxTransform& actor2World) +{ + mCore.body2World = actor2World; + + StaticSim* sim = getSim(); + if(sim) + sim->postActor2WorldChange(); +} diff --git a/PhysX_3.4/Source/SimulationController/src/ScStaticSim.cpp b/PhysX_3.4/Source/SimulationController/src/ScStaticSim.cpp new file mode 100644 index 00000000..19f6493a --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScStaticSim.cpp @@ -0,0 +1,52 @@ +// 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 "ScStaticSim.h" +#include "ScScene.h" +#include "ScShapeIterator.h" +#include "ScShapeSim.h" +#include "PxsContext.h" + +using namespace physx; + +Sc::StaticSim::StaticSim(Scene& scene, StaticCore& core) : + RigidSim(scene, core) +{ +} + +Sc::StaticSim::~StaticSim() +{ + getStaticCore().setSim(NULL); +} + +void Sc::StaticSim::postActor2WorldChange() +{ + notifyShapesOfTransformChange(); +} diff --git a/PhysX_3.4/Source/SimulationController/src/ScStaticSim.h b/PhysX_3.4/Source/SimulationController/src/ScStaticSim.h new file mode 100644 index 00000000..9f5568ae --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScStaticSim.h @@ -0,0 +1,59 @@ +// 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_STATIC_SIM +#define PX_PHYSICS_SCP_STATIC_SIM + +#include "ScRigidSim.h" +#include "ScStaticCore.h" + +namespace physx +{ +namespace Sc +{ + class StaticSim : public RigidSim + { + //--------------------------------------------------------------------------------- + // Construction, destruction & initialization + //--------------------------------------------------------------------------------- + public: + StaticSim(Scene&, StaticCore&); + ~StaticSim(); + + void postActor2WorldChange(); + + PX_FORCE_INLINE StaticCore& getStaticCore() const { return static_cast<StaticCore&>(getRigidCore()); } + }; + +} // namespace Sc + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/ScTriggerInteraction.cpp b/PhysX_3.4/Source/SimulationController/src/ScTriggerInteraction.cpp new file mode 100644 index 00000000..e75e8929 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScTriggerInteraction.cpp @@ -0,0 +1,136 @@ +// 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 "ScTriggerInteraction.h" +#include "ScBodySim.h" +#include "ScNPhaseCore.h" + +using namespace physx; + +Sc::TriggerInteraction::TriggerInteraction(ShapeSim& tShape, ShapeSim& oShape) : + RbElementInteraction(tShape, oShape, InteractionType::eTRIGGER, InteractionFlag::eRB_ELEMENT | InteractionFlag::eFILTERABLE), + mFlags(PROCESS_THIS_FRAME), + mLastFrameHadContacts(false) +{ + // The PxPairFlags eNOTIFY_TOUCH_FOUND and eNOTIFY_TOUCH_LOST get stored and mixed up with internal flags. Make sure any breaking change gets noticed. + PX_COMPILE_TIME_ASSERT(PxPairFlag::eNOTIFY_TOUCH_FOUND < PxPairFlag::eNOTIFY_TOUCH_LOST); + PX_COMPILE_TIME_ASSERT((PAIR_FLAGS_MASK & PxPairFlag::eNOTIFY_TOUCH_FOUND) == PxPairFlag::eNOTIFY_TOUCH_FOUND); + PX_COMPILE_TIME_ASSERT((PAIR_FLAGS_MASK & PxPairFlag::eNOTIFY_TOUCH_LOST) == PxPairFlag::eNOTIFY_TOUCH_LOST); + PX_COMPILE_TIME_ASSERT(PxPairFlag::eNOTIFY_TOUCH_FOUND < 0xffff); + PX_COMPILE_TIME_ASSERT(PxPairFlag::eNOTIFY_TOUCH_LOST < 0xffff); + PX_COMPILE_TIME_ASSERT(LAST < 0xffff); + + bool active = registerInActors(); + getScene().registerInteraction(this, active); + getScene().getNPhaseCore()->registerInteraction(this); + + PX_ASSERT(getShape0().getFlags() & PxShapeFlag::eTRIGGER_SHAPE); + mTriggerCache.state = Gu::TRIGGER_DISJOINT; +} + +Sc::TriggerInteraction::~TriggerInteraction() +{ + getScene().unregisterInteraction(this); + getScene().getNPhaseCore()->unregisterInteraction(this); + unregisterFromActors(); +} + + +bool Sc::TriggerInteraction::isOneActorActive() const +{ + const BodySim* bodySim0 = getTriggerShape().getBodySim(); + if (bodySim0 && bodySim0->isActive()) + { + PX_ASSERT(!bodySim0->isKinematic() || bodySim0->readInternalFlag(BodySim::BF_KINEMATIC_MOVED) || + bodySim0->readInternalFlag(BodySim::InternalFlags(BodySim::BF_KINEMATIC_SETTLING | BodySim::BF_KINEMATIC_SETTLING_2))); + return true; + } + + const BodySim* bodySim1 = getOtherShape().getBodySim(); + if (bodySim1 && bodySim1->isActive()) + { + PX_ASSERT(!bodySim1->isKinematic() || bodySim1->readInternalFlag(BodySim::BF_KINEMATIC_MOVED) || + bodySim1->readInternalFlag(BodySim::InternalFlags(BodySim::BF_KINEMATIC_SETTLING | BodySim::BF_KINEMATIC_SETTLING_2))); + return true; + } + + return false; +} + + +// +// Some general information about triggers and sleeping +// +// The goal is to avoid running overlap tests if both objects are sleeping. +// This is an optimization for eNOTIFY_TOUCH_LOST events since the overlap state +// can not change if both objects are sleeping. eNOTIFY_TOUCH_FOUND should be sent nonetheless. +// For this to work the following assumptions are made: +// - On creation or if the pose of an actor is set, the pair will always be checked. +// - If the scenario above does not apply, then a trigger pair can only be deactivated, if both actors are sleeping. +// - If an overlapping actor is activated/deactivated, the trigger interaction gets notified +// +bool Sc::TriggerInteraction::onActivate(void*) +{ + // IMPORTANT: this method can get called concurrently from multiple threads -> make sure shared resources + // are protected (note: there are none at the moment but it might change) + + if (!(readFlag(PROCESS_THIS_FRAME))) + { + if (isOneActorActive()) + { + raiseInteractionFlag(InteractionFlag::eIS_ACTIVE); + return true; + } + else + return false; + } + else + { + raiseInteractionFlag(InteractionFlag::eIS_ACTIVE); + return true; // newly created trigger pairs should always test for overlap, no matter the sleep state + } +} + + +bool Sc::TriggerInteraction::onDeactivate(PxU32) +{ + if (!readFlag(PROCESS_THIS_FRAME)) + { + if (!isOneActorActive()) + { + clearInteractionFlag(InteractionFlag::eIS_ACTIVE); + return true; + } + else + return false; + } + else + return false; +} diff --git a/PhysX_3.4/Source/SimulationController/src/ScTriggerInteraction.h b/PhysX_3.4/Source/SimulationController/src/ScTriggerInteraction.h new file mode 100644 index 00000000..618b6cba --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScTriggerInteraction.h @@ -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. + + +#ifndef PX_COLLISION_TRIGGERINTERACTION +#define PX_COLLISION_TRIGGERINTERACTION + +#include "ScRbElementInteraction.h" +#include "GuOverlapTests.h" + +namespace physx +{ +namespace Sc +{ + class TriggerInteraction : public RbElementInteraction + { + public: + enum TriggerFlag + { + PAIR_FLAGS_MASK = ((PxPairFlag::eNOTIFY_TOUCH_LOST << 1) - 1), // Bits where the PxPairFlags eNOTIFY_TOUCH_FOUND and eNOTIFY_TOUCH_LOST get stored + NEXT_FREE = ((PAIR_FLAGS_MASK << 1) & ~PAIR_FLAGS_MASK), + + PROCESS_THIS_FRAME = (NEXT_FREE << 0), // the trigger pair is new or the pose of an actor was set -> initial processing required. + // This is important to cover cases where a static or kinematic + // (non-moving) trigger is created and overlaps with a sleeping + // object. Or for the case where a static/kinematic is teleported to a new + // location. TOUCH_FOUND should still get sent in that case. + LAST = (NEXT_FREE << 1) + }; + + TriggerInteraction(ShapeSim& triggerShape, ShapeSim& otherShape); + virtual ~TriggerInteraction(); + + PX_FORCE_INLINE Gu::TriggerCache& getTriggerCache() { return mTriggerCache; } + PX_FORCE_INLINE ShapeSim& getTriggerShape() const { return getShape0(); } + PX_FORCE_INLINE ShapeSim& getOtherShape() const { return getShape1(); } + + PX_FORCE_INLINE bool lastFrameHadContacts() const { return mLastFrameHadContacts; } + PX_FORCE_INLINE void updateLastFrameHadContacts(bool hasContact) { mLastFrameHadContacts = hasContact; } + + PX_FORCE_INLINE PxPairFlags getTriggerFlags() const { return PxPairFlags(PxU32(mFlags) & PAIR_FLAGS_MASK); } + PX_FORCE_INLINE void setTriggerFlags(PxPairFlags triggerFlags); + + PX_FORCE_INLINE void raiseFlag(TriggerFlag flag) { mFlags |= flag; } + PX_FORCE_INLINE void clearFlag(TriggerFlag flag) { mFlags &= ~flag; } + PX_FORCE_INLINE Ps::IntBool readFlag(TriggerFlag flag) const { return Ps::IntBool(mFlags & flag); } + + PX_FORCE_INLINE void forceProcessingThisFrame(Sc::Scene& scene); + + //////////////////////// interaction //////////////////////// + virtual bool onActivate(void*); + virtual bool onDeactivate(PxU32 infoFlag); + + private: + bool isOneActorActive() const; + + protected: + Gu::TriggerCache mTriggerCache; + PxU16 mFlags; + bool mLastFrameHadContacts; + }; + +} // namespace Sc + + +PX_FORCE_INLINE void Sc::TriggerInteraction::setTriggerFlags(PxPairFlags triggerFlags) +{ + PX_ASSERT(PxU32(triggerFlags) < (PxPairFlag::eDETECT_CCD_CONTACT << 1)); // to find out if a new PxPairFlag has been added in which case PAIR_FLAGS_MASK needs to get adjusted + +#if PX_CHECKED + if (triggerFlags & PxPairFlag::eNOTIFY_TOUCH_PERSISTS) + { + PX_WARN_ONCE("Trigger pairs do not support PxPairFlag::eNOTIFY_TOUCH_PERSISTS events any longer."); + } +#endif + + PxU32 newFlags = mFlags; + PxU32 fl = PxU32(triggerFlags) & PxU32(PxPairFlag::eNOTIFY_TOUCH_FOUND|PxPairFlag::eNOTIFY_TOUCH_LOST); + newFlags &= (~PAIR_FLAGS_MASK); // clear old flags + newFlags |= fl; + + mFlags = PxU16(newFlags); +} + + +PX_FORCE_INLINE void Sc::TriggerInteraction::forceProcessingThisFrame(Sc::Scene& scene) +{ + raiseFlag(PROCESS_THIS_FRAME); + + if (!readInteractionFlag(InteractionFlag::eIS_ACTIVE)) + { + raiseInteractionFlag(InteractionFlag::eIS_ACTIVE); + scene.notifyInteractionActivated(this); + } +} + +} + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/ScTriggerPairs.h b/PhysX_3.4/Source/SimulationController/src/ScTriggerPairs.h new file mode 100644 index 00000000..a180a0b9 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/ScTriggerPairs.h @@ -0,0 +1,106 @@ +// 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_TRIGGER_PAIRS +#define PX_PHYSICS_SCP_TRIGGER_PAIRS + +#include "PsArray.h" +#include "CmPhysXCommon.h" +#include "PxFiltering.h" +#include "PxClient.h" +#include "PxSimulationEventCallback.h" + +namespace physx +{ + +class PxShape; + +namespace Sc +{ + struct TriggerPairFlag + { + enum Enum + { + eTEST_FOR_REMOVED_SHAPES = PxTriggerPairFlag::eNEXT_FREE // for cases where the pair got deleted because one of the shape volumes got removed from broadphase. + // This covers scenarios like volume re-insertion into broadphase as well since the shape might get removed + // after such an operation. The scenarios to consider are: + // + // - shape gets removed (this includes raising PxActorFlag::eDISABLE_SIMULATION) + // - shape switches to eSCENE_QUERY_SHAPE only + // - shape switches to eSIMULATION_SHAPE + // - resetFiltering() + // - actor gets removed from an aggregate + }; + }; + + PX_COMPILE_TIME_ASSERT((1 << (8*sizeof(PxTriggerPairFlags::InternalType))) > TriggerPairFlag::eTEST_FOR_REMOVED_SHAPES); + + + struct TriggerPairExtraData + { + PX_INLINE TriggerPairExtraData() : + shape0ID(0xffffffff), + shape1ID(0xffffffff), + client0ID(0xff), + client1ID(0xff), + actor0ClientBehavior(0), + actor1ClientBehavior(0) + { + } + + PX_INLINE TriggerPairExtraData(PxU32 s0ID, PxU32 s1ID, + PxClientID cl0ID, PxClientID cl1ID, + PxU8 a0ClientBehaviorFlag, PxU8 a1ClientBehaviorFlag) : + shape0ID(s0ID), + shape1ID(s1ID), + client0ID(cl0ID), + client1ID(cl1ID), + actor0ClientBehavior(a0ClientBehaviorFlag), + actor1ClientBehavior(a1ClientBehaviorFlag) + { + } + + PxU32 shape0ID; + PxU32 shape1ID; + PxClientID client0ID; + PxClientID client1ID; + PxU8 actor0ClientBehavior; // for PxActorClientBehaviorFlag + PxU8 actor1ClientBehavior; + }; + + + typedef Ps::Array<TriggerPairExtraData> TriggerBufferExtraData; + typedef Ps::Array<PxTriggerPair> TriggerBufferAPI; + +} // namespace Sc + +} + +#endif 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 diff --git a/PhysX_3.4/Source/SimulationController/src/particles/ScParticleBodyInteraction.cpp b/PhysX_3.4/Source/SimulationController/src/particles/ScParticleBodyInteraction.cpp new file mode 100644 index 00000000..fc8e6723 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/particles/ScParticleBodyInteraction.cpp @@ -0,0 +1,112 @@ +// 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 "ScParticleBodyInteraction.h" +#if PX_USE_PARTICLE_SYSTEM_API + +#include "ScParticleSystemSim.h" +#include "ScScene.h" +#include "PxsContext.h" +#include "ScParticleSystemCore.h" +#include "ScBodySim.h" +#include "ScNPhaseCore.h" + +using namespace physx; + + +Sc::ParticleElementRbElementInteraction::ParticleElementRbElementInteraction(ParticlePacketShape &particleShape, ShapeSim& rbShape, ActorElementPair& actorElementPair, const PxU32 ccdPass) : + ElementSimInteraction (particleShape, rbShape, InteractionType::ePARTICLE_BODY, InteractionFlag::eFILTERABLE | InteractionFlag::eELEMENT_ELEMENT), + mActorElementPair (actorElementPair), + mPacketShapeIndex (PX_INVALID_PACKET_SHAPE_INDEX), + mIsActiveForLowLevel (false) +{ + registerInActors(); + + getScene().getNPhaseCore()->registerInteraction(this); + + mPacketShapeIndex = getParticleShape().addPacketShapeInteraction(this); + + if (!isDisabled()) + activateForLowLevel(ccdPass); // Collision with rigid body +} + + +Sc::ParticleElementRbElementInteraction::~ParticleElementRbElementInteraction() +{ + unregisterFromActors(); + getScene().getNPhaseCore()->unregisterInteraction(this); +} + + +void Sc::ParticleElementRbElementInteraction::destroy(bool isDyingRb, const PxU32 ccdPass) +{ + ParticlePacketShape& ps = getParticleShape(); + + if (mIsActiveForLowLevel) + deactivateForLowLevel(isDyingRb, ccdPass); + + const PxU16 idx = mPacketShapeIndex; + ps.removePacketShapeInteraction(idx); + if (idx < ps.getInteractionsCount()) + ps.getPacketShapeInteraction(idx)->setPacketShapeIndex(idx); + mPacketShapeIndex = PX_INVALID_PACKET_SHAPE_INDEX; +} + + +bool Sc::ParticleElementRbElementInteraction::onActivate(void*) +{ + return false; +} + + +bool Sc::ParticleElementRbElementInteraction::onDeactivate(PxU32) +{ + return true; +} + + +void Sc::ParticleElementRbElementInteraction::activateForLowLevel(const PxU32 ccdPass) +{ + //update active cm count and update transform hash/mirroring + getParticleShape().getParticleSystem().addInteraction(getParticleShape(), getRbShape(), ccdPass); + mIsActiveForLowLevel = true; +} + + +void Sc::ParticleElementRbElementInteraction::deactivateForLowLevel(bool isDyingRb, const PxU32 ccdPass) +{ + //update active cm count and update transform hash/mirroring + getParticleShape().getParticleSystem().removeInteraction(getParticleShape(), getRbShape(), isDyingRb, ccdPass); + mIsActiveForLowLevel = false; +} + + + +#endif // PX_USE_PARTICLE_SYSTEM_API diff --git a/PhysX_3.4/Source/SimulationController/src/particles/ScParticleBodyInteraction.h b/PhysX_3.4/Source/SimulationController/src/particles/ScParticleBodyInteraction.h new file mode 100644 index 00000000..78738d02 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/particles/ScParticleBodyInteraction.h @@ -0,0 +1,152 @@ +// 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_PARTICLEBODYINTERACTION +#define PX_PHYSICS_SCP_PARTICLEBODYINTERACTION + +#include "CmPhysXCommon.h" +#include "PxPhysXConfig.h" +#if PX_USE_PARTICLE_SYSTEM_API + +#include "ScElementSimInteraction.h" +#include "ScActorElementPair.h" +#include "ScParticlePacketShape.h" +#include "ScShapeSim.h" + + +#define PX_INVALID_PACKET_SHAPE_INDEX 0xffff + + +namespace physx +{ +namespace Sc +{ + + class ParticleElementRbElementInteraction : public ElementSimInteraction + { + public: + + // The ccdPass parameter is needed to avoid concurrent interaction updates while the gpu particle pipeline is running. + ParticleElementRbElementInteraction(ParticlePacketShape &particleShape, ShapeSim& rbShape, ActorElementPair& actorElementPair, const PxU32 ccdPass); + virtual ~ParticleElementRbElementInteraction(); + PX_INLINE void* operator new(size_t s, void* memory); + + void destroy(bool isDyingRb, const PxU32 ccdPass); + + //---------- Interaction ---------- + protected: + virtual bool onActivate(void*); + virtual bool onDeactivate(PxU32 infoFlag); + //----------------------------------- + + public: + //----- ElementSimInteraction ------ + virtual bool isLastFilterInteraction() const { return (mActorElementPair.getRefCount() == 1); } + //---------------------------------- + + PX_INLINE ParticlePacketShape& getParticleShape() const; + PX_INLINE ShapeSim& getRbShape() const; + + PX_INLINE void onRbShapeChange(); + + PX_FORCE_INLINE ActorElementPair* getActorElementPair() const { return &mActorElementPair; } + PX_FORCE_INLINE bool isDisabled() const { return (getActorElementPair()->isSuppressed() || isRbTrigger()); } + + PX_INLINE void setPacketShapeIndex(PxU16 idx); + + PX_INLINE void checkLowLevelActivationState(); + + private: + ParticleElementRbElementInteraction& operator=(const ParticleElementRbElementInteraction&); + void activateForLowLevel(const PxU32 ccdPass); + void deactivateForLowLevel(bool isDyingRb, const PxU32 ccdPass); + static void operator delete(void*) {} + + PX_FORCE_INLINE PxU32 isRbTrigger() const { return (getRbShape().getFlags() & PxShapeFlag::eTRIGGER_SHAPE); } + + + ActorElementPair& mActorElementPair; + PxU16 mPacketShapeIndex; + bool mIsActiveForLowLevel; + }; + +} // namespace Sc + +PX_INLINE void* Sc::ParticleElementRbElementInteraction::operator new(size_t, void* memory) +{ + return memory; +} + + +PX_INLINE Sc::ParticlePacketShape& Sc::ParticleElementRbElementInteraction::getParticleShape() const +{ + PX_ASSERT(getElement0().getElementType() == ElementType::ePARTICLE_PACKET); + return static_cast<ParticlePacketShape&>(getElement0()); +} + + +PX_INLINE Sc::ShapeSim& Sc::ParticleElementRbElementInteraction::getRbShape() const +{ + PX_ASSERT(getElement1().getElementType() == ElementType::eSHAPE); + PX_ASSERT(static_cast<ShapeSim&>(getElement1()).getActor().isDynamicRigid() || (static_cast<ShapeSim&>(getElement1()).getActor().getActorType() == PxActorType::eRIGID_STATIC)); + return static_cast<ShapeSim&>(getElement1()); +} + +PX_INLINE void Sc::ParticleElementRbElementInteraction::checkLowLevelActivationState() +{ + if (!isDisabled() && !mIsActiveForLowLevel) + { + // The interaction is now valid --> Create low level contact manager + activateForLowLevel(false); + } + else if (isDisabled() && mIsActiveForLowLevel) + { + // The interaction is not valid anymore --> Release low level contact manager + deactivateForLowLevel(false, false); + } +} + +PX_INLINE void Sc::ParticleElementRbElementInteraction::onRbShapeChange() +{ + getParticleShape().getParticleSystem().onRbShapeChange(getParticleShape(), getRbShape()); +} + +PX_INLINE void Sc::ParticleElementRbElementInteraction::setPacketShapeIndex(PxU16 idx) +{ + PX_ASSERT(idx != PX_INVALID_PACKET_SHAPE_INDEX); + mPacketShapeIndex = idx; +} + + +} + +#endif // PX_USE_PARTICLE_SYSTEM_API + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/particles/ScParticlePacketShape.cpp b/PhysX_3.4/Source/SimulationController/src/particles/ScParticlePacketShape.cpp new file mode 100644 index 00000000..8dd86f0a --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/particles/ScParticlePacketShape.cpp @@ -0,0 +1,191 @@ +// 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 "ScParticlePacketShape.h" +#if PX_USE_PARTICLE_SYSTEM_API + +#include "ScParticleBodyInteraction.h" +#include "ScNPhaseCore.h" +#include "ScScene.h" +#include "PtParticleSystemSim.h" +#include "ScParticleSystemCore.h" +#include "ScSimStats.h" +#include "ScSqBoundsManager.h" +#include "ScScene.h" +#include "PxsContext.h" + +using namespace physx; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +Sc::ParticlePacketShape::ParticlePacketShape(ParticleSystemSim& particleSystem, PxU32 index, Pt::ParticleShape* llParticleShape) : + ElementSim(particleSystem, ElementType::ePARTICLE_PACKET), + mLLParticleShape(llParticleShape) +{ + // Initialize LL shape. + PX_ASSERT(mLLParticleShape); + mLLParticleShape->setUserDataV(this); + + setIndex(index); + + // Add particle actor element to broadphase + createLowLevelVolume(); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +Sc::ParticlePacketShape::~ParticlePacketShape() +{ + getParticleSystem().unlinkParticleShape(this); // Let the particle system remove this shape from the list. + + // Remove particle actor element from broadphase and cleanup interactions + destroyLowLevelVolume(); + + // Destroy LowLevel shape + if (mLLParticleShape) + { + mLLParticleShape->destroyV(); + mLLParticleShape = 0; + } + + PX_ASSERT(mInteractions.size()==0); + mInteractions.releaseMem(*this); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void Sc::ParticlePacketShape::computeWorldBounds(PxBounds3& b) const +{ + b = getBounds(); + PX_ASSERT(b.isFinite()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void Sc::ParticlePacketShape::getFilterInfo(PxFilterObjectAttributes& filterAttr, PxFilterData& filterData) const +{ + filterAttr = 0; + if (getParticleSystem().getInternalFlags() & Pt::InternalParticleSystemFlag::eSPH) + ElementSim::setFilterObjectAttributeType(filterAttr, PxFilterObjectType::ePARTICLE_FLUID); + else + ElementSim::setFilterObjectAttributeType(filterAttr, PxFilterObjectType::ePARTICLE_SYSTEM); + + filterData = getParticleSystem().getSimulationFilterData(); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +Sc::ParticleSystemSim& Sc::ParticlePacketShape::getParticleSystem() const +{ + return static_cast<ParticleSystemSim&>(getActor()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void Sc::ParticlePacketShape::setInteractionsDirty(InteractionDirtyFlag::Enum flag) +{ + ParticleElementRbElementInteraction** interactions = getInteractions(); + PxU32 nbInteractions = getInteractionsCount(); + + while(nbInteractions--) + { + ParticleElementRbElementInteraction* interaction = *interactions++; + + PX_ASSERT(interaction->readInteractionFlag(InteractionFlag::eFILTERABLE)); + PX_ASSERT(interaction->readInteractionFlag(InteractionFlag::eELEMENT_ELEMENT)); + + interaction->setDirty(flag); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// PT: TODO: refactor with Sc::ActorSim::reallocInteractions +void Sc::ParticlePacketShape::reallocInteractions(Sc::ParticleElementRbElementInteraction**& mem, PxU16& capacity, PxU16 size, PxU16 requiredMinCapacity) +{ + ParticleElementRbElementInteraction** newMem; + PxU16 newCapacity; + + if(requiredMinCapacity==0) + { + newCapacity = 0; + newMem = 0; + } + else if(requiredMinCapacity<=INLINE_INTERACTION_CAPACITY) + { + newCapacity = INLINE_INTERACTION_CAPACITY; + newMem = mInlineInteractionMem; + } + else + { + const PxU32 desiredCapacity = Ps::nextPowerOfTwo(PxU32(requiredMinCapacity-1)); + PX_ASSERT(desiredCapacity<=65536); + + const PxU32 limit = 0xffff; + newCapacity = Ps::to16(PxMin(limit, desiredCapacity)); + newMem = reinterpret_cast<ParticleElementRbElementInteraction**>(getScene().allocatePointerBlock(newCapacity)); + } + + PX_ASSERT(newCapacity >= requiredMinCapacity && requiredMinCapacity>=size); + + PxMemCopy(newMem, mem, size*sizeof(ParticleElementRbElementInteraction*)); + + if(mem && mem!=mInlineInteractionMem) + getScene().deallocatePointerBlock(reinterpret_cast<void**>(mem), capacity); + + capacity = newCapacity; + mem = newMem; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void Sc::ParticlePacketShape::createLowLevelVolume() +{ + PX_ASSERT(getBounds().isFinite()); + + getScene().getBoundsArray().setBounds(getBounds(), getElementID()); + addToAABBMgr(0, Bp::FilterGroup::ePARTICLES, false); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void Sc::ParticlePacketShape::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_PARTICLE_SYSTEM_API diff --git a/PhysX_3.4/Source/SimulationController/src/particles/ScParticlePacketShape.h b/PhysX_3.4/Source/SimulationController/src/particles/ScParticlePacketShape.h new file mode 100644 index 00000000..a212d649 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/particles/ScParticlePacketShape.h @@ -0,0 +1,126 @@ +// 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_PARTICLESHAPE +#define PX_PHYSICS_PARTICLESHAPE + +#include "CmPhysXCommon.h" +#include "PxPhysXConfig.h" +#if PX_USE_PARTICLE_SYSTEM_API + +#include "ScElementSim.h" +#include "ScParticleSystemSim.h" +#include "PtParticleShape.h" + +namespace physx +{ +namespace Sc +{ + class ParticleElementRbElementInteraction; + + + /** + A collision detection primitive for particle systems. + */ + class ParticlePacketShape : public ElementSim + { + public: + ParticlePacketShape(ParticleSystemSim& particleSystem, PxU32 uid, Pt::ParticleShape* llParticleShape); + ~ParticlePacketShape(); + + // ElementSim implementation + virtual void getFilterInfo(PxFilterObjectAttributes& filterAttr, PxFilterData& filterData) const; + // ~ElementSim + + virtual void createLowLevelVolume(); + virtual void destroyLowLevelVolume(); + + public: + void setIndex(PxU32 index) { PX_ASSERT(index < ((1 << 16) - 1)); mIndex = static_cast<PxU16>(index); } + PX_FORCE_INLINE PxU16 getIndex() const { return mIndex; } + + PX_FORCE_INLINE PxBounds3 getBounds() const { return mLLParticleShape->getBoundsV(); } + + class ParticleSystemSim& getParticleSystem() const; + + void computeWorldBounds(PxBounds3&) const; + + PX_FORCE_INLINE ParticleElementRbElementInteraction** getInteractions() const { return mInteractions.begin(); } + PX_FORCE_INLINE PxU32 getInteractionsCount() const { return mInteractions.size(); } + + PX_FORCE_INLINE Pt::ParticleShape* getLowLevelParticleShape() const { return mLLParticleShape; } + + void setInteractionsDirty(InteractionDirtyFlag::Enum flag); + + PX_INLINE PxU16 addPacketShapeInteraction(ParticleElementRbElementInteraction* interaction); + PX_INLINE void removePacketShapeInteraction(PxU16 id); + PX_INLINE ParticleElementRbElementInteraction* getPacketShapeInteraction(PxU16 id) const; + + private: + void reallocInteractions(ParticleElementRbElementInteraction**& mem, PxU16& capacity, PxU16 size, PxU16 requiredMinCapacity); + + + static const PxU32 INLINE_INTERACTION_CAPACITY = 4; + ParticleElementRbElementInteraction* mInlineInteractionMem[INLINE_INTERACTION_CAPACITY]; + + Cm::OwnedArray<ParticleElementRbElementInteraction*, ParticlePacketShape, PxU16, &ParticlePacketShape::reallocInteractions> + mInteractions; + + Pt::ParticleShape* mLLParticleShape; // Low level handle of particle packet + PxU16 mIndex; + }; + +} // namespace Sc + + +//These are called from interaction creation/destruction +PX_INLINE PxU16 Sc::ParticlePacketShape::addPacketShapeInteraction(ParticleElementRbElementInteraction* interaction) +{ + mInteractions.pushBack(interaction, *this); + return PxU16(mInteractions.size()-1); +} + +PX_INLINE void Sc::ParticlePacketShape::removePacketShapeInteraction(PxU16 id) +{ + mInteractions.replaceWithLast(id); +} + +PX_INLINE Sc::ParticleElementRbElementInteraction* Sc::ParticlePacketShape::getPacketShapeInteraction(PxU16 id) const +{ + PX_ASSERT(id<mInteractions.size()); + return mInteractions[id]; +} + + +} + +#endif // PX_USE_PARTICLE_SYSTEM_API + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/particles/ScParticleSystemCore.cpp b/PhysX_3.4/Source/SimulationController/src/particles/ScParticleSystemCore.cpp new file mode 100644 index 00000000..e7e18e3b --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/particles/ScParticleSystemCore.cpp @@ -0,0 +1,705 @@ +// 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 "ScParticleSystemCore.h" +#if PX_USE_PARTICLE_SYSTEM_API + +#include "ScParticleSystemSim.h" +#include "ScPhysics.h" + +#include "PsBitUtils.h" +#include "PsMathUtils.h" + +#include "PxParticleReadData.h" +#include "PtParticleData.h" + +using namespace physx; + +//----------------------------------------------------------------------------// + +#if PX_SUPPORT_GPU_PHYSX +namespace physx +{ + struct PxCudaReadWriteParticleBuffers; +} +#endif + +//----------------------------------------------------------------------------// + +PxU32 computePacketSizeMultLog2(PxReal packetSize, PxReal cellSize) +{ + PX_FPU_GUARD; // unknown osx issue with ceil function (throwing fp exception), printf makes it go away. + const PxU32 mult = PxU32(Ps::ceil(packetSize / cellSize)); + PxU32 multPow2 = Ps::nextPowerOfTwo(mult-1); + multPow2 = PxMax(PxU32(4), multPow2); + return Ps::ilog2(multPow2); +} + +//----------------------------------------------------------------------------// + +Sc::ParticleSystemCore::ParticleSystemCore(const PxActorType::Enum& actorType, PxU32 maxParticles, bool perParticleRestOffset) : + ActorCore(actorType, PxActorFlag::eVISUALIZATION, PX_DEFAULT_CLIENT, 0, 0), + mStandaloneData(0), + mParticleMass(0.001f) +{ + // set simulation parameters + mSimulationFilterData.setToDefault(); + setExternalAcceleration(PxVec3(0)); + + mLLParameter.particleReadDataFlags = PxParticleReadDataFlag::ePOSITION_BUFFER | PxParticleReadDataFlag::eFLAGS_BUFFER;//desc.particleReadDataFlags; + mLLParameter.flags = PxParticleBaseFlag::eENABLED | + PxParticleBaseFlag::eCOLLISION_WITH_DYNAMIC_ACTORS | + PxParticleBaseFlag::ePER_PARTICLE_COLLISION_CACHE_HINT; + if(perParticleRestOffset) + mLLParameter.flags |= PxParticleBaseFlag::ePER_PARTICLE_REST_OFFSET; + + bool isFluid = actorType != PxActorType::ePARTICLE_SYSTEM; + + if (isFluid) + { + PX_ASSERT(actorType == PxActorType::ePARTICLE_FLUID); + + mLLParameter.flags |= Pt::InternalParticleSystemFlag::eSPH; + mLLParameter.restParticleDistance = 0.02f; + mLLParameter.kernelRadiusMultiplier = SPH_KERNEL_RADIUS_MULT; + mLLParameter.packetSizeMultiplierLog2 = computePacketSizeMultLog2(0.6f/*gridSize*/, mLLParameter.restParticleDistance*SPH_KERNEL_RADIUS_MULT); + mLLParameter.stiffness = 20.0f; + mLLParameter.viscosity = 6.0f; + mLLParameter.restDensity = SPH_REST_DENSITY; + } + else + { + mLLParameter.restParticleDistance = 0.06f; + mLLParameter.kernelRadiusMultiplier = 1.0f; + mLLParameter.packetSizeMultiplierLog2 = computePacketSizeMultLog2(0.6f/*gridSize*/, mLLParameter.restParticleDistance); + mLLParameter.stiffness = 0.0f; + mLLParameter.viscosity = 0.0f; + mLLParameter.restDensity = 0.0f; + } + + mLLParameter.maxMotionDistance = 0.06f; + mLLParameter.restOffset = 0.004f; + mLLParameter.contactOffset = 0.008f; + mLLParameter.damping = 0.0f; + mLLParameter.noiseCounter = 0; + + // Simon: This is a bit hacky. We should have better support for non sph in LL + mLLParameter.restitution = 0.5f; + mLLParameter.dynamicFriction = 0.05f; + mLLParameter.staticFriction = 0.0f; + + mLLParameter.projectionPlane = PxPlane(PxVec3(0.0f, 0.0f, 1.0f), 0.0f); + + // Create the low level standalone core + maxParticles = PxMin(maxParticles, MAX_PARTICLES_PER_PARTICLE_SYSTEM); + mStandaloneData = Pt::ParticleData::create(maxParticles, perParticleRestOffset); + if(perParticleRestOffset) + { + PxF32* restOffsetBuf = mStandaloneData->getRestOffsetBuffer(); + for(PxU32 i = 0; i < maxParticles; i++) + *restOffsetBuf++ = 0.f; + } +} + +//----------------------------------------------------------------------------// + +Sc::ParticleSystemCore::~ParticleSystemCore() +{ + PX_ASSERT(getSim() == NULL); + + if (mStandaloneData) + mStandaloneData->release(); +} + +//----------------------------------------------------------------------------// + +// PX_SERIALIZATION +void Sc::ParticleSystemCore::exportExtraData(PxSerializationContext& stream) +{ + if (mStandaloneData) + { + mStandaloneData->exportData(stream); + } + else + { + //sschirm, this could be made faster and more memory friendly for non-gpu fluids. do we care? + //if so, we would need to push this functionality into lowlevel and write platform dependent code. + //for faster gpu export, we would need to push the export into the gpu dll. + Pt::ParticleSystemStateDataDesc particles; + getParticleState().getParticlesV(particles, true, false); + Pt::ParticleData* tmp = Pt::ParticleData::create(particles, getParticleState().getWorldBoundsV()); + tmp->exportData(stream); + tmp->release(); + } +} + +void Sc::ParticleSystemCore::importExtraData(PxDeserializationContext& context) +{ + PX_ASSERT(!getSim()); + mStandaloneData = Pt::ParticleData::create(context); +} +//~PX_SERIALIZATION + +//----------------------------------------------------------------------------// + +Sc::ParticleSystemSim* Sc::ParticleSystemCore::getSim() const +{ + return static_cast<ParticleSystemSim*>(Sc::ActorCore::getSim()); +} + +//----------------------------------------------------------------------------// + +Pt::ParticleSystemState& Sc::ParticleSystemCore::getParticleState() +{ + return getSim() ? getSim()->getParticleState() : *mStandaloneData; +} + +//----------------------------------------------------------------------------// + +const Pt::ParticleSystemState& Sc::ParticleSystemCore::getParticleState() const +{ + return getSim() ? getSim()->getParticleState() : *mStandaloneData; +} + +//----------------------------------------------------------------------------// + +Pt::ParticleData* Sc::ParticleSystemCore::obtainStandaloneData() +{ + PX_ASSERT(mStandaloneData); + Pt::ParticleData* tmp = mStandaloneData; + mStandaloneData = NULL; + return tmp; +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemCore::returnStandaloneData(Pt::ParticleData* particleData) +{ + PX_ASSERT(particleData && !mStandaloneData); + mStandaloneData = particleData; +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemCore::onOriginShift(const PxVec3& shift) +{ + // hard to come up with a use case for this but we do it for the sake of consistency + PxReal delta = mLLParameter.projectionPlane.n.dot(shift); + mLLParameter.projectionPlane.d += delta; + + PX_ASSERT(mStandaloneData); + mStandaloneData->onOriginShift(shift); +} + +//----------------------------------------------------------------------------// + +PxParticleBase* Sc::ParticleSystemCore::getPxParticleBase() +{ + if (getActorCoreType() == PxActorType::ePARTICLE_SYSTEM) + return gOffsetTable.convertScParticleSystem2Px(this); + else + return gOffsetTable.convertScParticleSystem2PxParticleFluid(this); +} + +//----------------------------------------------------------------------------// + +PxReal Sc::ParticleSystemCore::getStiffness() const +{ + return mLLParameter.stiffness; +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemCore::setStiffness(PxReal t) +{ + mLLParameter.stiffness = t; +} + +//----------------------------------------------------------------------------// + +PxReal Sc::ParticleSystemCore::getViscosity() const +{ + return mLLParameter.viscosity; +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemCore::setViscosity(PxReal t) +{ + mLLParameter.viscosity = t; +} + +//----------------------------------------------------------------------------// + +PxReal Sc::ParticleSystemCore::getDamping() const +{ + return mLLParameter.damping; +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemCore::setDamping(PxReal t) +{ + mLLParameter.damping = t; +} + +//----------------------------------------------------------------------------// + +PxReal Sc::ParticleSystemCore::getParticleMass() const +{ + return mParticleMass; +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemCore::setParticleMass(PxReal mass) +{ + mParticleMass = mass; +} + +//----------------------------------------------------------------------------// + +PxReal Sc::ParticleSystemCore::getRestitution() const +{ + return mLLParameter.restitution; +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemCore::setRestitution(PxReal t) +{ + mLLParameter.restitution = t; +} + +//----------------------------------------------------------------------------// + +PxReal Sc::ParticleSystemCore::getDynamicFriction() const +{ + return mLLParameter.dynamicFriction; +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemCore::setDynamicFriction(PxReal t) +{ + mLLParameter.dynamicFriction = t; +} + +//----------------------------------------------------------------------------// + +PxReal Sc::ParticleSystemCore::getStaticFriction() const +{ + return mLLParameter.staticFriction; +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemCore::setStaticFriction(PxReal t) +{ + mLLParameter.staticFriction = t; +} + +//----------------------------------------------------------------------------// + +const PxFilterData& Sc::ParticleSystemCore::getSimulationFilterData() const +{ + return mSimulationFilterData; +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemCore::setSimulationFilterData(const PxFilterData& data) +{ + mSimulationFilterData = data; + + if (getSim()) + getSim()->scheduleRefiltering(); + // If no sim object then we have no particle packets anyway and nothing to worry about +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemCore::resetFiltering() +{ + if (getSim()) + getSim()->resetFiltering(); + // If no sim object then we have no particle packets anyway and nothing to worry about +} + +//----------------------------------------------------------------------------// + +PxParticleBaseFlags Sc::ParticleSystemCore::getFlags() const +{ + return PxParticleBaseFlags(PxU16(mLLParameter.flags)); +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemCore::setFlags(PxParticleBaseFlags flags) +{ + if (getSim()) + { + // flags that are immutable while in scene + PxParticleBaseFlags sceneImmutableFlags = + PxParticleBaseFlag::eGPU | + PxParticleBaseFlag::eCOLLISION_TWOWAY | + PxParticleBaseFlag::eCOLLISION_WITH_DYNAMIC_ACTORS | + PxParticleBaseFlag::ePER_PARTICLE_COLLISION_CACHE_HINT; + + if (flags & sceneImmutableFlags) + { + Sc::Scene* scene = &getSim()->getScene(); + scene->removeParticleSystem(*this, false); + setInternalFlags(flags); + scene->addParticleSystem(*this); + } + else + { + setInternalFlags(flags); + } + getSim()->setFlags(flags); + } + else + { + setInternalFlags(flags); + } +} + +//----------------------------------------------------------------------------// + +PxU32 Sc::ParticleSystemCore::getInternalFlags() const +{ + return mLLParameter.flags; +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemCore::setInternalFlags(PxParticleBaseFlags flags) +{ + mLLParameter.flags = (mLLParameter.flags & 0xffff0000) | PxU32(flags); +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemCore::notifyCpuFallback() +{ + setInternalFlags(getFlags() & ~PxParticleBaseFlag::eGPU); +} + +//----------------------------------------------------------------------------// + +PxParticleReadDataFlags Sc::ParticleSystemCore::getParticleReadDataFlags() const +{ + return mLLParameter.particleReadDataFlags; +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemCore::setParticleReadDataFlags(PxParticleReadDataFlags flags) +{ + mLLParameter.particleReadDataFlags = flags; +} + +//----------------------------------------------------------------------------// + +PxU32 Sc::ParticleSystemCore::getMaxParticles() const +{ + return getParticleState().getMaxParticlesV(); +} + +//----------------------------------------------------------------------------// + +PxReal Sc::ParticleSystemCore::getMaxMotionDistance() const +{ + return mLLParameter.maxMotionDistance; +} + +//---------------------------------------------------------------------------// +void Sc::ParticleSystemCore::setMaxMotionDistance(PxReal distance) +{ + PX_ASSERT(!getSim()); + mLLParameter.maxMotionDistance = distance; +} + +//----------------------------------------------------------------------------// + +PxReal Sc::ParticleSystemCore::getRestOffset() const +{ + return mLLParameter.restOffset; +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemCore::setRestOffset(PxReal restOffset) +{ + PX_ASSERT(!getSim()); + mLLParameter.restOffset = restOffset; +} + +//----------------------------------------------------------------------------// + +PxReal Sc::ParticleSystemCore::getContactOffset() const +{ + return mLLParameter.contactOffset; +} + +//---------------------------------------------------------------------------// +void Sc::ParticleSystemCore::setContactOffset(PxReal contactOffset) +{ + PX_ASSERT(!getSim()); + mLLParameter.contactOffset = contactOffset; +} + +//----------------------------------------------------------------------------// + +PxReal Sc::ParticleSystemCore::getRestParticleDistance() const +{ + return mLLParameter.restParticleDistance; +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemCore::setRestParticleDistance(PxReal restParticleDistance) +{ + PX_ASSERT(!getSim()); + PxReal gridSize = getGridSize(); + mLLParameter.restParticleDistance = restParticleDistance; + setGridSize(gridSize); +} + +//----------------------------------------------------------------------------// + +PxReal Sc::ParticleSystemCore::getGridSize() const +{ + const PxReal cellSize = mLLParameter.kernelRadiusMultiplier * mLLParameter.restParticleDistance; + const PxU32 packetMult = PxU32(1 << mLLParameter.packetSizeMultiplierLog2); + return packetMult * cellSize; +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemCore::setGridSize(PxReal gridSize) +{ + PX_ASSERT(!getSim()); + const PxReal cellSize = mLLParameter.kernelRadiusMultiplier * mLLParameter.restParticleDistance; + mLLParameter.packetSizeMultiplierLog2 = computePacketSizeMultLog2(gridSize, cellSize); +} + +//----------------------------------------------------------------------------// + +/** +Create new particles in the LL and the user particle data. +*/ +bool Sc::ParticleSystemCore::createParticles(const PxParticleCreationData& creationData) +{ + PX_ASSERT(creationData.numParticles > 0); + PX_ASSERT(creationData.numParticles <= (getParticleState().getMaxParticlesV() - getParticleCount())); + + // add particles to lowlevel + return getParticleState().addParticlesV(creationData); +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemCore::releaseParticles(PxU32 nbIndices, const PxStrideIterator<const PxU32>& indices) +{ + PX_ASSERT(indices.ptr()); + getParticleState().removeParticlesV(nbIndices, indices); +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemCore::releaseParticles() +{ + getParticleState().removeParticlesV(); +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemCore::setPositions(PxU32 numParticles, const PxStrideIterator<const PxU32>& indexBuffer, const PxStrideIterator<const PxVec3>& positionBuffer) +{ + PX_ASSERT(numParticles > 0 && indexBuffer.ptr() && positionBuffer.ptr()); + getParticleState().setPositionsV(numParticles, indexBuffer, positionBuffer); +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemCore::setVelocities(PxU32 numParticles, const PxStrideIterator<const PxU32>& indexBuffer, const PxStrideIterator<const PxVec3>& velocityBuffer) +{ + PX_ASSERT(numParticles > 0 && indexBuffer.ptr() && velocityBuffer.ptr()); + getParticleState().setVelocitiesV(numParticles, indexBuffer, velocityBuffer); +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemCore::setRestOffsets(PxU32 numParticles, const PxStrideIterator<const PxU32>& indexBuffer, const PxStrideIterator<const PxF32>& restOffsetBuffer) +{ + PX_ASSERT(numParticles > 0 && indexBuffer.ptr() && restOffsetBuffer.ptr()); + getParticleState().setRestOffsetsV(numParticles, indexBuffer, restOffsetBuffer); +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemCore::addDeltaVelocities(const Cm::BitMap& bufferMap, const PxVec3* buffer, PxReal multiplier) +{ + getParticleState().addDeltaVelocitiesV(bufferMap, buffer, multiplier); +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemCore::getParticleReadData(PxParticleFluidReadData& readData) const +{ + bool wantDeviceData = readData.getDataAccessFlags()&PxDataAccessFlag::eDEVICE; + + Pt::ParticleSystemStateDataDesc particles; + getParticleState().getParticlesV(particles, false, wantDeviceData); + PX_ASSERT(particles.maxParticles >= particles.numParticles); + PX_ASSERT(particles.maxParticles >= particles.validParticleRange); + + readData.nbValidParticles = particles.numParticles; + readData.validParticleRange = particles.validParticleRange; + readData.validParticleBitmap = particles.bitMap ? particles.bitMap->getWords() : NULL; + + readData.positionBuffer = PxStrideIterator<const PxVec3>(); + readData.velocityBuffer = PxStrideIterator<const PxVec3>(); + readData.restOffsetBuffer = PxStrideIterator<const PxF32>(); + readData.flagsBuffer = PxStrideIterator<const PxParticleFlags>(); + readData.collisionNormalBuffer = PxStrideIterator<const PxVec3>(); + readData.collisionVelocityBuffer = PxStrideIterator<const PxVec3>(); + readData.densityBuffer = PxStrideIterator<const PxReal>(); + + if (readData.validParticleRange > 0) + { + if (mLLParameter.particleReadDataFlags & PxParticleReadDataFlag::ePOSITION_BUFFER) + readData.positionBuffer = particles.positions; + + if (mLLParameter.particleReadDataFlags & PxParticleReadDataFlag::eVELOCITY_BUFFER) + readData.velocityBuffer = particles.velocities; + + if (mLLParameter.particleReadDataFlags & PxParticleReadDataFlag::eREST_OFFSET_BUFFER) + readData.restOffsetBuffer = particles.restOffsets; + + if (mLLParameter.particleReadDataFlags & PxParticleReadDataFlag::eFLAGS_BUFFER) + readData.flagsBuffer = PxStrideIterator<const PxParticleFlags>(reinterpret_cast<const PxParticleFlags*>(particles.flags.ptr()), particles.flags.stride()); + + Sc::ParticleSystemSim* sim = getSim(); + if (sim) + { + Pt::ParticleSystemSimDataDesc simParticleData; + sim->getSimParticleData(simParticleData, wantDeviceData); + + if (mLLParameter.particleReadDataFlags & PxParticleReadDataFlag::eCOLLISION_NORMAL_BUFFER) + readData.collisionNormalBuffer = simParticleData.collisionNormals; + + if (mLLParameter.particleReadDataFlags & PxParticleReadDataFlag::eCOLLISION_VELOCITY_BUFFER) + readData.collisionVelocityBuffer = simParticleData.collisionVelocities; + + if (mLLParameter.particleReadDataFlags & PxParticleReadDataFlag::eDENSITY_BUFFER) + readData.densityBuffer = simParticleData.densities; + } + } +} + +//----------------------------------------------------------------------------// + +const Cm::BitMap& Sc::ParticleSystemCore::getParticleMap() const +{ + Pt::ParticleSystemStateDataDesc particles; + getParticleState().getParticlesV(particles, false, false); + return *particles.bitMap; +} + +//----------------------------------------------------------------------------// + +PxU32 Sc::ParticleSystemCore::getParticleCount() const +{ + return getParticleState().getParticleCountV(); +} + +//----------------------------------------------------------------------------// + +PxBounds3 Sc::ParticleSystemCore::getWorldBounds() const +{ + return getParticleState().getWorldBoundsV(); +} + +//----------------------------------------------------------------------------// + +const PxVec3& Sc::ParticleSystemCore::getExternalAcceleration() const +{ + return mExternalAcceleration; +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemCore::setExternalAcceleration(const PxVec3& v) +{ + mExternalAcceleration = v; +} + +//----------------------------------------------------------------------------// + +const PxPlane& Sc::ParticleSystemCore::getProjectionPlane() const +{ + return mLLParameter.projectionPlane; +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemCore::setProjectionPlane(const PxPlane& plane) +{ + mLLParameter.projectionPlane = plane; +} + +//----------------------------------------------------------------------------// + +#if PX_SUPPORT_GPU_PHYSX + +void Sc::ParticleSystemCore::enableDeviceExclusiveModeGpu() +{ + PX_ASSERT(getSim()); + getSim()->enableDeviceExclusiveModeGpu(); +} + +PxParticleDeviceExclusiveAccess* Sc::ParticleSystemCore::getDeviceExclusiveAccessGpu() const +{ + PX_ASSERT(getSim()); + return getSim()->getDeviceExclusiveAccessGpu(); +} + +bool Sc::ParticleSystemCore::isGpu() const +{ + return getSim() && getSim()->isGpu(); +} +#endif + +//----------------------------------------------------------------------------// + +#endif // PX_USE_PARTICLE_SYSTEM_API diff --git a/PhysX_3.4/Source/SimulationController/src/particles/ScParticleSystemSim.cpp b/PhysX_3.4/Source/SimulationController/src/particles/ScParticleSystemSim.cpp new file mode 100644 index 00000000..7ebf1fde --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/particles/ScParticleSystemSim.cpp @@ -0,0 +1,868 @@ +// 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 "ScParticleSystemSim.h" +#if PX_USE_PARTICLE_SYSTEM_API + +#include "foundation/PxProfiler.h" +#include "ScParticlePacketShape.h" +#include "ScParticleBodyInteraction.h" +#include "ScParticleSystemCore.h" +#include "ScPhysics.h" +#include "ScNPhaseCore.h" +#include "ScBodySim.h" +#include "ScStaticSim.h" +#include "PxParticleReadData.h" +#include "PtParticleSystemSim.h" +#include "PtParticleContactManagerStream.h" +#include "PtContext.h" + +using namespace physx; + +//----------------------------------------------------------------------------// + +Sc::ParticleSystemSim::ParticleSystemSim(Scene& scene, ParticleSystemCore& core) +: ActorSim(scene, core) +, mParticlePacketShapePool(PX_DEBUG_EXP("ParticlePacketShapePool")) +, mParticlePacketShapes(PX_DEBUG_EXP("ParticleSysPacketShapes")) +, mInteractionCount(0) +, mCollisionInputPrepTask(this, "ScParticleSystemSim.prepareCollisionInput") +{ + // Set size of interaction list + ActorSim::setInteractionCountHint(32); + + Pt::Context* llContext = getScene().getParticleContext(); + Pt::ParticleData* particleData = core.obtainStandaloneData(); + PX_ASSERT(particleData); + + bool useGpu = getCore().getFlags() & PxParticleBaseFlag::eGPU; + mLLSim = llContext->addParticleSystem(particleData, core.getLowLevelParameter(), useGpu); + + //CPU fall back + if (!mLLSim && useGpu) + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "GPU particle system creation failed. Falling back to CPU implementation."); + mLLSim = llContext->addParticleSystem(particleData, core.getLowLevelParameter(), false); + getCore().notifyCpuFallback(); + } + + if (mLLSim) + { + if (getCore().getFlags() & PxParticleBaseFlag::eENABLED) + { + mLLSim->setSimulatedV(true); + } + } + else + { + core.setSim(NULL); + core.returnStandaloneData(particleData); + } +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemSim::release(bool releaseParticleData) +{ + releaseParticlePacketShapes(); + + if (mLLSim) //might be not the case if low level sim creation failed. + { + Pt::Context* llContext = getScene().getParticleContext(); + + Pt::ParticleData* particleData = llContext->removeParticleSystem(mLLSim, !releaseParticleData); + if (!releaseParticleData) + { + PX_ASSERT(particleData); + getCore().returnStandaloneData(particleData); + } + getCore().setSim(NULL); + } + delete this; +} + +//----------------------------------------------------------------------------// + +Sc::ParticleSystemCore& Sc::ParticleSystemSim::getCore() const +{ + return static_cast<ParticleSystemCore&>(Sc::ActorSim::getActorCore()); +} + +//----------------------------------------------------------------------------// + +#if PX_SUPPORT_GPU_PHYSX + +void Sc::ParticleSystemSim::enableDeviceExclusiveModeGpu() +{ + PX_ASSERT(mLLSim); + mLLSim->enableDeviceExclusiveModeGpuV(); +} + +PxParticleDeviceExclusiveAccess* Sc::ParticleSystemSim::getDeviceExclusiveAccessGpu() const +{ + PX_ASSERT(mLLSim); + return mLLSim->getDeviceExclusiveAccessGpuV(); +} + +#endif + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemSim::unlinkParticleShape(ParticlePacketShape* particleShape) +{ + // Remove the specified particle shape from the shape list + PX_ASSERT(particleShape); + PX_ASSERT(mParticlePacketShapes.size() > 0); + PxU32 index = particleShape->getIndex(); + PX_ASSERT(mParticlePacketShapes[index] == particleShape); + mParticlePacketShapes.back()->setIndex(index); + mParticlePacketShapes.replaceWithLast(index); +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemSim::releaseParticlePacketShapes() +{ + PxU32 shapesCount = mParticlePacketShapes.size(); + for(PxU32 i=0; i < shapesCount; i++) + { + ParticlePacketShape* fs = mParticlePacketShapes.back(); + mParticlePacketShapePool.destroy(fs); // The shape will remove itself from the particle shape list + } +} + +//----------------------------------------------------------------------------// + +PxU32 Sc::ParticleSystemSim::getInternalFlags() const +{ + return getCore().getInternalFlags(); +} + +//----------------------------------------------------------------------------// + +PxFilterData Sc::ParticleSystemSim::getSimulationFilterData() const +{ + return getCore().getSimulationFilterData(); +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemSim::scheduleRefiltering() +{ + // Schedule a refiltering + for (PxU32 i=0; i < mParticlePacketShapes.size(); i++) + { + mParticlePacketShapes[i]->setInteractionsDirty(InteractionDirtyFlag::eFILTER_STATE); + } +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemSim::resetFiltering() +{ + // Remove all shapes from broadphase and add again + const PxU32 size = mParticlePacketShapes.size(); + for (PxU32 i=0; i<size; i++) + { + mParticlePacketShapes[i]->destroyLowLevelVolume(); + mParticlePacketShapes[i]->createLowLevelVolume(); + } +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemSim::setFlags(PxU32 flags) +{ + if ((getCore().getFlags() & PxParticleBaseFlag::eENABLED) && !(flags & PxParticleBaseFlag::eENABLED)) + { + mLLSim->setSimulatedV(true); + } + else if (!(getCore().getFlags() & PxParticleBaseFlag::eENABLED) && (flags & PxParticleBaseFlag::eENABLED)) + { + mLLSim->setSimulatedV(false); + } +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemSim::getSimParticleData(Pt::ParticleSystemSimDataDesc& simParticleData, bool devicePtr) const +{ + PX_ASSERT(mLLSim); + mLLSim->getSimParticleDataV(simParticleData, devicePtr); +} + +//----------------------------------------------------------------------------// + +Pt::ParticleSystemState& Sc::ParticleSystemSim::getParticleState() +{ + PX_ASSERT(mLLSim); + return mLLSim->getParticleStateV(); +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemSim::addInteraction(const ParticlePacketShape& particleShape, const ShapeSim& shape, const PxU32 ccdPass) +{ + PX_ASSERT(mLLSim); + const PxsShapeCore& shapeCore = shape.getCore().getCore(); + bool isDynamic = shape.actorIsDynamic(); + PxsRigidCore& rigidCore = shape.getPxsRigidCore(); + if(isDynamic) + getScene().getParticleContext()->getBodyTransformVaultFast().addBody(static_cast<PxsBodyCore&>(rigidCore)); + + mLLSim->addInteractionV(*particleShape.getLowLevelParticleShape(), size_t(&shapeCore), size_t(&rigidCore), isDynamic, (ccdPass > 0)); + mInteractionCount++; +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemSim::removeInteraction(const ParticlePacketShape& particleShape, const ShapeSim& shape, bool isDyingRb, const PxU32 ccdPass) +{ + PX_ASSERT(mLLSim); + const PxsShapeCore& shapeCore = shape.getCore().getCore(); + bool isDynamic = shape.actorIsDynamic(); + PxsRigidCore& rigidCore = shape.getPxsRigidCore(); + if(isDynamic) + getScene().getParticleContext()->getBodyTransformVaultFast().removeBody(static_cast<PxsBodyCore&>(rigidCore)); + + mLLSim->removeInteractionV(*particleShape.getLowLevelParticleShape(), size_t(&shapeCore), size_t(&rigidCore), isDynamic, isDyingRb, (ccdPass > 0)); + mInteractionCount--; +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemSim::onRbShapeChange(const ParticlePacketShape& particleShape, const ShapeSim& shape) +{ + PX_ASSERT(mLLSim); + mLLSim->onRbShapeChangeV(*particleShape.getLowLevelParticleShape(), size_t(&shape.getCore().getCore())); +} + +//----------------------------------------------------------------------------// + +PX_FORCE_INLINE void addImpulseAtPos(PxsBodyCore& bodyCore, const PxVec3& impulse, const PxVec3& worldPos) +{ + const PxTransform& pose = bodyCore.body2World; + PxVec3 torque = (worldPos - pose.p).cross(impulse); + + bodyCore.linearVelocity += impulse * bodyCore.inverseMass; + bodyCore.angularVelocity += pose.q.rotate(bodyCore.inverseInertia.multiply(pose.q.rotateInv(torque))); +} + +//----------------------------------------------------------------------------// + +/** +currently, it may be that shape id's from removed shapes are reported. +Try to catch these and ignore them in order to avoid artefacts. +*/ +void Sc::ParticleSystemSim::updateRigidBodies() +{ + if (!(getCore().getFlags() & PxParticleBaseFlag::eCOLLISION_TWOWAY) + || !(getCore().getFlags() & PxParticleBaseFlag::eCOLLISION_WITH_DYNAMIC_ACTORS)) + return; + + PxReal particleMass = getCore().getParticleMass(); + + //Particle data might not even be available if count is zero. + if (getParticleState().getParticleCountV() == 0) + return; + + Pt::ParticleSystemStateDataDesc particlesCore; + getParticleState().getParticlesV(particlesCore, false, false); + + if (particlesCore.validParticleRange == 0) + return; + + PX_ASSERT(particlesCore.bitMap); + PX_ASSERT(particlesCore.flags.ptr()); + PX_ASSERT(particlesCore.positions.ptr()); + + Pt::ParticleSystemSimDataDesc particlesSim; + getSimParticleData(particlesSim, false); + PX_ASSERT(particlesSim.twoWayImpluses.ptr()); + PX_ASSERT(particlesSim.twoWayBodies.ptr()); + + Cm::BitMap::Iterator it(*particlesCore.bitMap); + for (PxU32 p = it.getNext(); p != Cm::BitMap::Iterator::DONE; p = it.getNext()) + { + if (!particlesSim.twoWayBodies[p]) + continue; + + Pt::ParticleFlags flags = particlesCore.flags[p]; + PX_ASSERT(flags.api & PxParticleFlag::eCOLLISION_WITH_DYNAMIC); + + PxsBodyCore& body = *reinterpret_cast<PxsBodyCore*>(particlesSim.twoWayBodies[p]); + BodyCore& scBody = BodyCore::getCore(body); + + if (scBody.getCore().inverseMass == 0.0f) // kinematic + continue; + + PxDominanceGroupPair cdom = getScene().getDominanceGroupPair(getCore().getDominanceGroup(), scBody.getDominanceGroup()); + + if (cdom.dominance0 == 0.0f) + continue; + + if (cdom.dominance1 == 0.0f) + PX_WARN_ONCE("Dominance: unsupport particle dominance is 1.0 and rigid body dominance is 0.0"); + + if (flags.api & PxParticleFlag::eCOLLISION_WITH_DRAIN) + continue; + + const PxVec3& position = particlesCore.positions[p]; + const PxVec3& impulse = particlesSim.twoWayImpluses[p]; + PX_ASSERT(impulse.isFinite()); + + if (!impulse.isZero()) + { + PX_ASSERT(scBody.getSim()); + scBody.getSim()->internalWakeUp(); + addImpulseAtPos(scBody.getCore(), impulse*particleMass, position); + } + } +} + +//----------------------------------------------------------------------------// + +/* particle update has the following structure: + * + * The update process for the particle array in low level is to process the active + * particle buffer by removing the deleted particles and moving particles from + * the top of the array to fill the spaces, then to append the new particles to + * the array. Using this knowledge we synchronize the IndexMap on the host. + * + * TODO: there's an obvious optimization here: replacing deleted particles in place with + * new particles, and then just processing remaining deletes and adds. + */ +void Sc::ParticleSystemSim::startStep() +{ + PX_PROFILE_ZONE("ParticleSim.startStep",0); + + PxVec3 externalAcceleration = getCore().getExternalAcceleration(); + if ((getCore().getActorFlags() & PxActorFlag::eDISABLE_GRAVITY) == false) + externalAcceleration += getScene().getGravity(); + + mLLSim->setExternalAccelerationV(externalAcceleration); + + // Set simulation time step + mLLSim->setSimulationTimeStepV(static_cast<PxReal>(getScene().getDt())); +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemSim::addParticlePacket(Pt::ParticleShape* llParticleShape) +{ + PX_ASSERT(llParticleShape); + + PxU32 index = mParticlePacketShapes.size(); + Sc::ParticlePacketShape* particleShape = mParticlePacketShapePool.construct(*this, index, llParticleShape); + + if (particleShape) + { + mParticlePacketShapes.pushBack(particleShape); // Add shape to list. + } + else + { + llParticleShape->destroyV(); + } +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemSim::removeParticlePacket(const Pt::ParticleShape * llParticleShape) +{ + // Find corresponding particle packet shape. + void* data = llParticleShape->getUserDataV(); + PX_ASSERT(data); + ParticlePacketShape* particleShape = reinterpret_cast<ParticlePacketShape*>(data); + // Cleanup shape. The shape will remove itself from particle shape list. + mParticlePacketShapePool.destroy(particleShape); +} + +//----------------------------------------------------------------------------// + +/** +- Create / delete / update particle shapes. + +Only call this function when the packet/shapes update task for the particle system has successful finished +and after the whole particle pipeline has finished. +*/ +void Sc::ParticleSystemSim::processShapesUpdate() +{ + PX_PROFILE_ZONE("ParticleSim.shapesUpdateProcessing",0); + + Pt::ParticleShapeUpdateResults updateResults; + mLLSim->getShapesUpdateV(updateResults); + + // + // Process particle shape update results + // + + for(PxU32 i=0; i < updateResults.destroyedShapeCount; i++) + { + // Delete particle packet + PX_ASSERT(updateResults.destroyedShapes[i]); + removeParticlePacket(updateResults.destroyedShapes[i]); + } + + for(PxU32 i=0; i < updateResults.createdShapeCount; i++) + { + // Create new particle packet + PX_ASSERT(updateResults.createdShapes[i]); + addParticlePacket(updateResults.createdShapes[i]); + } +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemSim::endStep() +{ + PX_PROFILE_ZONE("ParticleSim.endStep",0); + + // applies int buffered interaction updates that where produced asynchronously to gpu execution. + // this has to go before processShapesUpdate, since that will update interactions as well + mLLSim->flushBufferedInteractionUpdatesV(); + + // some lowlevel implementations (gpu) got an update at the end of the step. + processShapesUpdate(); + + // 2-way interaction + updateRigidBodies(); +} + +//----------------------------------------------------------------------------// + +#if PX_ENABLE_DEBUG_VISUALIZATION + +/** +Render particle system state before simulation starts. CollisionNormals are a product of of simulate and not available here. +*/ +void Sc::ParticleSystemSim::visualizeStartStep(Cm::RenderOutput& out) +{ + if (!(getCore().getActorFlags() & PxActorFlag::eVISUALIZATION)) + return; + + //all particle visualization in world space! + out << PxTransform(PxIdentity); + + if (getScene().getVisualizationParameter(PxVisualizationParameter::ePARTICLE_SYSTEM_BOUNDS) > 0.0f) + visualizeParticlesBounds(out); + + visualizeParticles(out); + + if (getScene().getVisualizationParameter(PxVisualizationParameter::ePARTICLE_SYSTEM_GRID) > 0.0f) + visualizeSpatialGrid(out); + + if (getScene().getVisualizationParameter(PxVisualizationParameter::ePARTICLE_SYSTEM_BROADPHASE_BOUNDS) > 0.0f) + visualizeBroadPhaseBounds(out); + + if(0) // MS: Might be helpful for debugging + visualizeInteractions(out); +} + +/** +Render particle system data that is available after simulation and not up to date after the application made updates (CollisionNormals). +*/ +void Sc::ParticleSystemSim::visualizeEndStep(Cm::RenderOutput& out) +{ + if (!(getCore().getActorFlags() & PxActorFlag::eVISUALIZATION)) + return; + + //all particle visualization in world space! + out << PxTransform(PxIdentity); + + visualizeCollisionNormals(out); +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemSim::visualizeParticlesBounds(Cm::RenderOutput& out) +{ + PxBounds3 bounds = getParticleState().getWorldBoundsV(); + out << PxU32(PxDebugColor::eARGB_RED) << Cm::DebugBox(bounds); +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemSim::visualizeSpatialGrid(Cm::RenderOutput& out) +{ + PxReal packetSize = getCore().getGridSize(); + + for (PxU32 i = 0; i < mParticlePacketShapes.size(); i++) + { + ParticlePacketShape* particleShape = mParticlePacketShapes[i]; + + PxBounds3 bounds = particleShape->getBounds(); + PxVec3 centerGridSpace = bounds.getCenter() / packetSize; + + for (PxU32 d = 0; d < 3; d++) + bounds.minimum[d] = Ps::floor(centerGridSpace[d]) * packetSize; + for (PxU32 d = 0; d < 3; d++) + bounds.maximum[d] = Ps::ceil(centerGridSpace[d]) * packetSize; + + out << PxU32(PxDebugColor::eARGB_BLUE) << Cm::DebugBox(bounds); + } +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemSim::visualizeBroadPhaseBounds(Cm::RenderOutput& out) +{ + for (PxU32 i = 0; i < mParticlePacketShapes.size(); i++) + { + ParticlePacketShape* particleShape = mParticlePacketShapes[i]; + PxBounds3 bounds = particleShape->getBounds(); + out << PxU32(PxDebugColor::eARGB_BLUE) << Cm::DebugBox(bounds); + } +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemSim::visualizeParticles(Cm::RenderOutput& out) +{ + PxReal timestep = getScene().getDt(); + + Pt::ParticleSystemStateDataDesc particlesCore; + getParticleState().getParticlesV(particlesCore, false, false); + + if (particlesCore.numParticles == 0) + return; + + PX_ASSERT(particlesCore.bitMap); + + bool arePositionsReadeable = getCore().getParticleReadDataFlags() & PxParticleReadDataFlag::ePOSITION_BUFFER; + bool areVelocitiesReadeable = getCore().getParticleReadDataFlags() & PxParticleReadDataFlag::eVELOCITY_BUFFER; + + if (getScene().getVisualizationParameter(PxVisualizationParameter::ePARTICLE_SYSTEM_MAX_MOTION_DISTANCE) > 0.0f) + { + if (arePositionsReadeable) + { + PxReal radius = getCore().getMaxMotionDistance(); + + PxQuat q0(0.0f, 0.0f, 0.0f, 1.0f ); + PxQuat q1(0.0f, PxSqrt(0.5f), 0.0f, PxSqrt(0.5f) ); + PxQuat q2(0.5f, 0.5f, 0.5f, 0.5f ); + + Cm::BitMap::Iterator it(*particlesCore.bitMap); + for (PxU32 p = it.getNext(); p != Cm::BitMap::Iterator::DONE; p = it.getNext()) + { + const PxVec3& position = particlesCore.positions[p]; + + if (areVelocitiesReadeable && particlesCore.velocities[p].magnitude()*timestep >= radius*0.99f) + out << PxU32(PxDebugColor::eARGB_RED); + else + out << PxU32(PxDebugColor::eARGB_GREEN); + + out << PxTransform(position, q0) << Cm::DebugCircle(12, radius); + out << PxTransform(position, q1) << Cm::DebugCircle(12, radius); + out << PxTransform(position, q2) << Cm::DebugCircle(12, radius); + } + } + else + { + PX_WARN_ONCE( + "PxVisualizationParameter::ePARTICLE_SYSTEM_MAX_MOTION_DISTANCE cannot be rendered without specifying PxParticleReadDataFlag::ePOSITION_BUFFER"); + } + } + + if (getScene().getVisualizationParameter(PxVisualizationParameter::ePARTICLE_SYSTEM_POSITION) > 0.0f) + { + if (arePositionsReadeable) + { + PxReal rad = getScene().getVisualizationParameter(PxVisualizationParameter::ePARTICLE_SYSTEM_POSITION) * getScene().getVisualizationScale()*0.5f; + PxVec3 a(0,0,rad); + PxVec3 b(0,rad,0); + PxVec3 c(rad,0,0); + + out << PxU32(PxDebugColor::eARGB_BLUE) << Cm::RenderOutput::LINES << PxMat44(PxIdentity); + + Cm::BitMap::Iterator it(*particlesCore.bitMap); + for (PxU32 p = it.getNext(); p != Cm::BitMap::Iterator::DONE; p = it.getNext()) + { + const PxVec3& position = particlesCore.positions[p]; + out << position + a << position - a; + out << position + b << position - b; + out << position + c << position - c; + } + } + else + { + PX_WARN_ONCE( + "PxVisualizationParameter::ePARTICLE_SYSTEM_POSITION cannot be rendered without specifying \ + PxParticleReadDataFlag::ePOSITION_BUFFER"); + } + } + + if (getScene().getVisualizationParameter(PxVisualizationParameter::ePARTICLE_SYSTEM_VELOCITY) > 0.0f) + { + if (arePositionsReadeable && areVelocitiesReadeable) + { + PxReal scale = getScene().getVisualizationParameter(PxVisualizationParameter::ePARTICLE_SYSTEM_VELOCITY) * getScene().getVisualizationScale(); + + out << PxU32(PxDebugColor::eARGB_RED) << PxMat44(PxIdentity); + + Cm::BitMap::Iterator it(*particlesCore.bitMap); + for (PxU32 p = it.getNext(); p != Cm::BitMap::Iterator::DONE; p = it.getNext()) + { + out << Cm::DebugArrow(particlesCore.positions[p], particlesCore.velocities[p] * timestep, scale); + } + } + else + { + PX_WARN_ONCE( + "PxVisualizationParameter::ePARTICLE_SYSTEM_VELOCITY cannot be rendered without specifying \ + PxParticleReadDataFlag::ePOSITION_BUFFER and PxParticleReadDataFlag::eVELOCITY_BUFFER"); + } + } +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemSim::visualizeCollisionNormals(Cm::RenderOutput& out) +{ + Pt::ParticleSystemStateDataDesc particlesCore; + getParticleState().getParticlesV(particlesCore, false, false); + + if (particlesCore.numParticles == 0) + return; + + PX_ASSERT(particlesCore.bitMap); + + bool arePositionsReadeable = getCore().getParticleReadDataFlags() & PxParticleReadDataFlag::ePOSITION_BUFFER; + bool areCollisionNormalsReadeable = getCore().getParticleReadDataFlags() & PxParticleReadDataFlag::eCOLLISION_NORMAL_BUFFER; + + if (getScene().getVisualizationParameter(PxVisualizationParameter::ePARTICLE_SYSTEM_COLLISION_NORMAL) > 0.0f) + { + if (arePositionsReadeable && areCollisionNormalsReadeable) + { + Pt::ParticleSystemSimDataDesc particlesSim; + getSimParticleData(particlesSim, false); + + PxReal scale = getScene().getVisualizationParameter(PxVisualizationParameter::ePARTICLE_SYSTEM_COLLISION_NORMAL) * getScene().getVisualizationScale(); + + out << PxU32(PxDebugColor::eARGB_GREEN) << PxMat44(PxIdentity); + + if(particlesSim.collisionNormals.ptr()) + { + Cm::BitMap::Iterator it(*particlesCore.bitMap); + for (PxU32 p = it.getNext(); p != Cm::BitMap::Iterator::DONE; p = it.getNext()) + { + if (!particlesSim.collisionNormals[p].isZero()) + { + const PxVec3& position = particlesCore.positions[p]; + const PxVec3& normal = particlesSim.collisionNormals[p]; + out << Cm::DebugArrow(position, normal*scale, 0.1f*scale); + } + } + } + } + else + { + PX_WARN_ONCE( + "PxVisualizationParameter::ePARTICLE_SYSTEM_COLLISION_NORMAL cannot be rendered without specifying \ + PxParticleReadDataFlag::ePOSITION_BUFFER and PxParticleReadDataFlag::eCOLLISION_NORMAL_BUFFER"); + } + } +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemSim::visualizeInteractions(Cm::RenderOutput& out) +{ + out << PxU32(PxDebugColor::eARGB_GREEN) << Cm::RenderOutput::LINES; + for(PxU32 i=0; i < mParticlePacketShapes.size(); i++) + { + ParticlePacketShape* particleShape = mParticlePacketShapes[i]; + + ParticleElementRbElementInteraction** interactions = particleShape->getInteractions(); + PxU32 nbInteractions = particleShape->getInteractionsCount(); + + while(nbInteractions--) + { + ParticleElementRbElementInteraction* interaction = *interactions++; + + PX_ASSERT(interaction->getType() == InteractionType::ePARTICLE_BODY); + + const PxBounds3 bounds = particleShape->getBounds(); + + PX_ALIGN(16, PxTransform absPos); + interaction->getRbShape().getAbsPoseAligned(&absPos); + + out << bounds.getCenter() << absPos.p; + } + } +} + +//----------------------------------------------------------------------------// + +PxBaseTask& Sc::ParticleSystemSim::scheduleShapeGeneration(Pt::Context& context, const Ps::Array<ParticleSystemSim*>& particleSystems, PxBaseTask& continuation) +{ + Ps::Array<Pt::ParticleSystemSim*, Ps::TempAllocator> llParticleSystems(particleSystems.size()); + Ps::Array<Pt::ParticleShapesUpdateInput, Ps::TempAllocator> llInputs(particleSystems.size()); + + for (PxU32 i = 0; i < particleSystems.size(); ++i) + { + PX_ASSERT(particleSystems[i]->getScene().getParticleContext() == &context); + particleSystems[i]->createShapeUpdateInput(llInputs[i]); + llParticleSystems[i] = particleSystems[i]->mLLSim; + } + + return context.scheduleShapeGeneration(llParticleSystems.begin(), llInputs.begin(), particleSystems.size(), continuation); +} + +//----------------------------------------------------------------------------// + +PxBaseTask& Sc::ParticleSystemSim::scheduleDynamicsCpu(Pt::Context& context, const Ps::Array<ParticleSystemSim*>& particleSystems, PxBaseTask& continuation) +{ + Ps::Array<Pt::ParticleSystemSim*, Ps::TempAllocator> llParticleSystems(particleSystems.size()); + + for (PxU32 i = 0; i < particleSystems.size(); ++i) + { + PX_ASSERT(particleSystems[i]->getScene().getParticleContext() == &context); + llParticleSystems[i] = particleSystems[i]->mLLSim; + } + + return context.scheduleDynamicsCpu(llParticleSystems.begin(), particleSystems.size(), continuation); +} + +//----------------------------------------------------------------------------// + +PxBaseTask& Sc::ParticleSystemSim::scheduleCollisionPrep(Pt::Context& context, const Ps::Array<ParticleSystemSim*>& particleSystems, PxBaseTask& continuation) +{ + Ps::Array<Pt::ParticleSystemSim*, Ps::TempAllocator> llParticleSystems(particleSystems.size()); + Ps::Array<PxLightCpuTask*, Ps::TempAllocator> inputPrepTasks(particleSystems.size()); + + for (PxU32 i = 0; i < particleSystems.size(); ++i) + { + PX_ASSERT(particleSystems[i]->getScene().getParticleContext() == &context); + inputPrepTasks[i] = &particleSystems[i]->mCollisionInputPrepTask; + llParticleSystems[i] = particleSystems[i]->mLLSim; + } + + return context.scheduleCollisionPrep(llParticleSystems.begin(), inputPrepTasks.begin(), inputPrepTasks.size(), continuation); +} + +//----------------------------------------------------------------------------// + +PxBaseTask& Sc::ParticleSystemSim::scheduleCollisionCpu(Pt::Context& context, const Ps::Array<ParticleSystemSim*>& particleSystems, PxBaseTask& continuation) +{ + Ps::Array<Pt::ParticleSystemSim*, Ps::TempAllocator> llParticleSystems(particleSystems.size()); + + for (PxU32 i = 0; i < particleSystems.size(); ++i) + { + PX_ASSERT(particleSystems[i]->getScene().getParticleContext() == &context); + llParticleSystems[i] = particleSystems[i]->mLLSim; + } + + return context.scheduleCollisionCpu(llParticleSystems.begin(), particleSystems.size(), continuation); +} + +//----------------------------------------------------------------------------// + +PxBaseTask& Sc::ParticleSystemSim::schedulePipelineGpu(Pt::Context& context, const Ps::Array<ParticleSystemSim*>& particleSystems, PxBaseTask& continuation) +{ + Ps::Array<Pt::ParticleSystemSim*, Ps::TempAllocator> llParticleSystems(particleSystems.size()); + for (PxU32 i = 0; i < particleSystems.size(); ++i) + { + PX_ASSERT(particleSystems[i]->getScene().getParticleContext() == &context); + llParticleSystems[i] = particleSystems[i]->mLLSim; + } + + return context.schedulePipelineGpu(llParticleSystems.begin(), particleSystems.size(), continuation); +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemSim::createShapeUpdateInput(Pt::ParticleShapesUpdateInput& input) +{ + Pt::ParticleShape** llShapes = NULL; + if (mParticlePacketShapes.size() > 0) + { + //note: this buffer needs to be deallocated in LL + llShapes = reinterpret_cast<Pt::ParticleShape**>(PX_ALLOC_TEMP(mParticlePacketShapes.size()*sizeof(Pt::ParticleShape*), "Pt::ParticleShape*")); + for (PxU32 i = 0; i < mParticlePacketShapes.size(); ++i) + llShapes[i] = mParticlePacketShapes[i]->getLowLevelParticleShape(); + } + + input.shapes = llShapes; + input.shapeCount = mParticlePacketShapes.size(); +} + +//----------------------------------------------------------------------------// + +void Sc::ParticleSystemSim::prepareCollisionInput(PxBaseTask* /*continuation*/) +{ + PxU32 numParticleShapes = mParticlePacketShapes.size(); + PxU32 numInteractionsTest = 0; + + //note: this buffer needs to be deallocated in LL + PxU32 cmStreamSize = Pt::ParticleContactManagerStreamWriter::getStreamSize(numParticleShapes, mInteractionCount); + PxU8* cmStream = reinterpret_cast<PxU8*>(PX_ALLOC_TEMP(cmStreamSize, "ParticleContactManagerStream")); + + Pt::ParticleContactManagerStreamWriter swriter(cmStream, numParticleShapes, mInteractionCount); + + for (PxU32 s = 0; s < mParticlePacketShapes.size(); ++s) + { + const Sc::ParticlePacketShape& particleShape = *mParticlePacketShapes[s]; + swriter.addParticleShape(particleShape.getLowLevelParticleShape()); + + //count number of interactions... could be cached + ParticleElementRbElementInteraction*const* interactions = particleShape.getInteractions(); + PxU32 nbInteractions = particleShape.getInteractionsCount(); + while(nbInteractions--) + { + PX_ASSERT((*interactions)->getType() == InteractionType::ePARTICLE_BODY); + const Sc::ParticleElementRbElementInteraction& cm = *(*interactions++); + + if (!cm.isDisabled()) + { + PX_ASSERT(cm.getElement1().getElementType() == ElementType::eSHAPE); + const Sc::ShapeSim& shapeSim = cm.getRbShape(); + bool isDynamic = shapeSim.actorIsDynamic(); + const RigidSim& rigidSim = shapeSim.getRbSim(); + PxsRigidCore& rigidCore = static_cast<BodyCore&>(rigidSim.getActorCore()).getCore(); + const PxTransform* w2sOld = isDynamic ? getScene().getParticleContext()->getBodyTransformVaultFast().getTransform(static_cast<const PxsBodyCore&>(rigidCore)) : NULL; + swriter.addContactManager(&rigidCore, &shapeSim.getCore().getCore(), w2sOld, (shapeSim.getFlags() & PxShapeFlag::ePARTICLE_DRAIN) != 0, isDynamic); + numInteractionsTest++; + } + } + } + PX_ASSERT(numInteractionsTest == mInteractionCount); + + //passes ownership to low level object + Pt::ParticleCollisionUpdateInput input; + input.contactManagerStream = cmStream; + mLLSim->passCollisionInputV(input); +} + +//----------------------------------------------------------------------------// + +#endif // PX_ENABLE_DEBUG_VISUALIZATION + + +#endif // PX_USE_PARTICLE_SYSTEM_API diff --git a/PhysX_3.4/Source/SimulationController/src/particles/ScParticleSystemSim.h b/PhysX_3.4/Source/SimulationController/src/particles/ScParticleSystemSim.h new file mode 100644 index 00000000..c020ca18 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/particles/ScParticleSystemSim.h @@ -0,0 +1,174 @@ +// 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_PARTICLE_SYSTEM_SIM +#define PX_PHYSICS_SCP_PARTICLE_SYSTEM_SIM + +#include "CmPhysXCommon.h" +#include "PxPhysXConfig.h" +#if PX_USE_PARTICLE_SYSTEM_API + +#include "ScScene.h" +#include "ScActorSim.h" +#include "ScRigidSim.h" +#include "PsPool.h" + +#include "ScParticlePacketShape.h" +#include "PtParticleSystemSim.h" + +namespace physx +{ + +#if PX_SUPPORT_GPU_PHYSX +class PxParticleDeviceExclusiveAccess; +#endif + +namespace Pt +{ + class Context; + class ParticleSystemSim; + class ParticleShape; + class ParticleSystemState; + struct ParticleSystemSimDataDesc; + struct ParticleShapesUpdateInput; + struct ParticleCollisionUpdateInput; +} + +namespace Sc +{ + class ParticleSystemCore; + class ShapeSim; + class ParticlePacketShape; + +#define PX_PARTICLE_SYSTEM_DEBUG_RENDERING 1 + + class ParticleSystemSim : public ActorSim + { + public: + + ParticleSystemSim(Scene&, ParticleSystemCore&); + + void release(bool releaseStateBuffers); + + PxFilterData getSimulationFilterData() const; + void scheduleRefiltering(); + void resetFiltering(); + + void setFlags(PxU32 flags); + PxU32 getInternalFlags() const; + + void getSimParticleData(Pt::ParticleSystemSimDataDesc& simParticleData, bool devicePtr) const; + Pt::ParticleSystemState& getParticleState(); + + void addInteraction(const ParticlePacketShape& particleShape, const ShapeSim& shape, const PxU32 ccdPass); + void removeInteraction(const ParticlePacketShape& particleShape, const ShapeSim& shape, bool isDyingRb, const PxU32 ccdPass); + void onRbShapeChange(const ParticlePacketShape& particleShape, const ShapeSim& shape); + + void processShapesUpdate(); +#if PX_SUPPORT_GPU_PHYSX + Ps::IntBool isGpu() const { return mLLSim->isGpuV(); } +#endif + // batched updates + static PxBaseTask& scheduleShapeGeneration(Pt::Context& context, const Ps::Array<ParticleSystemSim*>& particleSystems, PxBaseTask& continuation); + static PxBaseTask& scheduleDynamicsCpu(Pt::Context& context, const Ps::Array<ParticleSystemSim*>& particleSystems, PxBaseTask& continuation); + static PxBaseTask& scheduleCollisionPrep(Pt::Context& context, const Ps::Array<ParticleSystemSim*>& particleSystems, PxBaseTask& continuation); + static PxBaseTask& scheduleCollisionCpu(Pt::Context& context, const Ps::Array<ParticleSystemSim*>& particleSystems, PxBaseTask& continuation); + static PxBaseTask& schedulePipelineGpu(Pt::Context& context, const Ps::Array<ParticleSystemSim*>& particleSystems, PxBaseTask& continuation); + + //--------------------------------------------------------------------------------- + // Actor implementation + //--------------------------------------------------------------------------------- + public: + // non-DDI methods: + + // Core functionality + void startStep(); + void endStep(); + + void unlinkParticleShape(ParticlePacketShape* particleShape); + + ParticleSystemCore& getCore() const; + +#if PX_SUPPORT_GPU_PHYSX + void enableDeviceExclusiveModeGpu(); + PxParticleDeviceExclusiveAccess* + getDeviceExclusiveAccessGpu() const; +#endif + + private: + ~ParticleSystemSim() {} + + void createShapeUpdateInput(Pt::ParticleShapesUpdateInput& input); + void createCollisionUpdateInput(Pt::ParticleCollisionUpdateInput& input); + void updateRigidBodies(); + void prepareCollisionInput(PxBaseTask* continuation); + + // ParticleSystem packet handling + void releaseParticlePacketShapes(); + PX_INLINE void addParticlePacket(Pt::ParticleShape* llParticleShape); + PX_INLINE void removeParticlePacket(const Pt::ParticleShape * llParticleShape); + + +#if PX_ENABLE_DEBUG_VISUALIZATION + public: + void visualizeStartStep(Cm::RenderOutput& out); + void visualizeEndStep(Cm::RenderOutput& out); + + private: + void visualizeParticlesBounds(Cm::RenderOutput& out); + void visualizeParticles(Cm::RenderOutput& out); + void visualizeCollisionNormals(Cm::RenderOutput& out); + void visualizeSpatialGrid(Cm::RenderOutput& out); + void visualizeBroadPhaseBounds(Cm::RenderOutput& out); + void visualizeInteractions(Cm::RenderOutput& out); // MS: Might be helpful for debugging +#endif // PX_ENABLE_DEBUG_VISUALIZATION + + + private: + Pt::ParticleSystemSim* mLLSim; + + // Array of particle packet shapes + Ps::Pool<ParticlePacketShape> mParticlePacketShapePool; + Ps::Array<ParticlePacketShape*> mParticlePacketShapes; + + // Count interactions for sizing the contact manager stream + PxU32 mInteractionCount; + + typedef Cm::DelegateTask<Sc::ParticleSystemSim, &Sc::ParticleSystemSim::prepareCollisionInput> CollisionInputPrepTask; + CollisionInputPrepTask mCollisionInputPrepTask; + }; + +} // namespace Sc + +} + +#endif // PX_USE_PARTICLE_SYSTEM_API + +#endif |