diff options
Diffstat (limited to 'PhysX_3.4/Source/PhysX/src/buffering')
27 files changed, 10982 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/PhysX/src/buffering/ScbActor.cpp b/PhysX_3.4/Source/PhysX/src/buffering/ScbActor.cpp new file mode 100644 index 00000000..9c91235a --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/buffering/ScbActor.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 "ScbBase.h" + +using namespace physx; +using namespace Scb; + +using namespace physx; +using namespace Scb; + +#include "ScbActor.h" +#include "ScbRigidStatic.h" +#include "ScbBody.h" +#include "ScbParticleSystem.h" +#include "ScbCloth.h" + +namespace physx +{ +namespace Scb +{ + +Actor::Offsets::Offsets() +{ + size_t staticOffset = reinterpret_cast<size_t>(&(reinterpret_cast<Scb::RigidStatic*>(0)->getScStatic())); + size_t bodyOffset = reinterpret_cast<size_t>(&(reinterpret_cast<Scb::Body*>(0)->getScBody())); + + scToScb[PxActorType::eRIGID_STATIC] = staticOffset; + scToScb[PxActorType::eRIGID_DYNAMIC] = bodyOffset; + scToScb[PxActorType::eARTICULATION_LINK] = bodyOffset; + + scbToSc[ScbType::RIGID_STATIC] = staticOffset; + scbToSc[ScbType::BODY] = bodyOffset; + scbToSc[ScbType::BODY_FROM_ARTICULATION_LINK] = bodyOffset; + +#if PX_USE_PARTICLE_SYSTEM_API + size_t particleOffset = reinterpret_cast<size_t>(&(reinterpret_cast<Scb::ParticleSystem*>(0)->getScParticleSystem())); + scToScb[PxActorType::ePARTICLE_FLUID] = particleOffset; + scToScb[PxActorType::ePARTICLE_SYSTEM] = particleOffset; + scbToSc[ScbType::PARTICLE_SYSTEM] = particleOffset; +#endif + +#if PX_USE_CLOTH_API + size_t clothOffset = reinterpret_cast<size_t>(&(reinterpret_cast<Scb::Cloth*>(0)->getScCloth())); + scToScb[PxActorType::eCLOTH] = clothOffset; + scbToSc[ScbType::CLOTH] = clothOffset; +#endif + + +} + + + + +const Actor::Offsets Actor::sOffsets; +} +} diff --git a/PhysX_3.4/Source/PhysX/src/buffering/ScbActor.h b/PhysX_3.4/Source/PhysX/src/buffering/ScbActor.h new file mode 100644 index 00000000..364972b1 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/buffering/ScbActor.h @@ -0,0 +1,186 @@ +// 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_SCB_FSACTOR +#define PX_PHYSICS_SCB_FSACTOR + +#include "ScActorCore.h" +#include "PsUtilities.h" +#include "ScbBase.h" +#include "ScbDefs.h" + +#include "PxClient.h" + +namespace physx +{ +namespace Scb +{ +struct ActorBuffer +{ + template <PxU32 I, PxU32 Dummy> struct Fns {}; + typedef Sc::ActorCore Core; + typedef ActorBuffer Buf; + + SCB_REGULAR_ATTRIBUTE (0, PxActorFlags, ActorFlags) + SCB_REGULAR_ATTRIBUTE (1, PxDominanceGroup, DominanceGroup) + SCB_REGULAR_ATTRIBUTE (2, PxActorClientBehaviorFlags, ClientBehaviorFlags) + + enum { AttrCount = 3 }; + +protected: + ~ActorBuffer(){} +}; + + +class Actor : public Base +{ +//= 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. +//================================================================================================== + + typedef ActorBuffer Buf; + typedef Sc::ActorCore Core; + +public: +// PX_SERIALIZATION + Actor(const PxEMPTY) : Base(PxEmpty) {} + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + + PX_INLINE Actor() {} + + //--------------------------------------------------------------------------------- + // Wrapper for Sc::Actor interface + //--------------------------------------------------------------------------------- + PX_INLINE PxActorFlags getActorFlags() const { return read<Buf::BF_ActorFlags>(); } + PX_INLINE void setActorFlags(PxActorFlags v); + + PX_INLINE PxDominanceGroup getDominanceGroup() const { return read<Buf::BF_DominanceGroup>(); } + PX_INLINE void setDominanceGroup(PxDominanceGroup v) { write<Buf::BF_DominanceGroup>(v); } + + PX_INLINE PxActorClientBehaviorFlags getClientBehaviorFlags() const { return read<Buf::BF_ClientBehaviorFlags>(); } + PX_INLINE void setClientBehaviorFlags(PxActorClientBehaviorFlags v){ write<Buf::BF_ClientBehaviorFlags>(v); } + + PX_INLINE void setOwnerClient( PxClientID inId ); + PX_INLINE PxClientID getOwnerClient() const { return getActorCore().getOwnerClient(); } //immutable, so this should be fine. + + //--------------------------------------------------------------------------------- + // Miscellaneous + //--------------------------------------------------------------------------------- + + PX_FORCE_INLINE const Core& getActorCore() const { return *reinterpret_cast<const Core*>(reinterpret_cast<size_t>(this) + sOffsets.scbToSc[getScbType()]); } + PX_FORCE_INLINE Core& getActorCore() { return *reinterpret_cast<Core*>(reinterpret_cast<size_t>(this) + sOffsets.scbToSc[getScbType()]); } + + PX_FORCE_INLINE static const Actor& fromSc(const Core& a) { return *reinterpret_cast<const Actor*>(reinterpret_cast<size_t>(&a) - sOffsets.scToScb[a.getActorCoreType()]); } + PX_FORCE_INLINE static Actor& fromSc(Core &a) { return *reinterpret_cast<Actor*>(reinterpret_cast<size_t>(&a) - sOffsets.scToScb[a.getActorCoreType()]); } + + PX_FORCE_INLINE PxActorType::Enum getActorType() const { return getActorCore().getActorCoreType(); } + +protected: + PX_INLINE void syncState(); + + //--------------------------------------------------------------------------------- + // Infrastructure for regular attributes + //--------------------------------------------------------------------------------- + + struct Access: public BufferedAccess<Buf, Core, Actor> {}; + template<PxU32 f> PX_FORCE_INLINE typename Buf::Fns<f,0>::Arg read() const { return Access::read<Buf::Fns<f,0> >(*this, getActorCore()); } + template<PxU32 f> PX_FORCE_INLINE void write(typename Buf::Fns<f,0>::Arg v) { Access::write<Buf::Fns<f,0> >(*this, getActorCore(), v); } + template<PxU32 f> PX_FORCE_INLINE void flush(Core& core, const Buf& buf) { Access::flush<Buf::Fns<f,0> >(*this, core, buf); } + +protected: + ~Actor() {} + + struct Offsets + { + size_t scToScb[PxActorType::eACTOR_COUNT]; + size_t scbToSc[ScbType::TYPE_COUNT]; + Offsets(); + }; + static const Offsets sOffsets; +}; + + +PX_INLINE void Actor::setActorFlags(PxActorFlags v) +{ +#if PX_CHECKED + PxActorFlags aFlags = getActorFlags(); + PxActorType::Enum aType = getActorType(); + if ((!aFlags.isSet(PxActorFlag::eDISABLE_SIMULATION)) && v.isSet(PxActorFlag::eDISABLE_SIMULATION) && + (aType != PxActorType::eRIGID_DYNAMIC) && (aType != PxActorType::eRIGID_STATIC)) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, + "PxActor::setActorFlag: PxActorFlag::eDISABLE_SIMULATION is only supported by PxRigidDynamic and PxRigidStatic objects."); + } +#endif + + write<Buf::BF_ActorFlags>(v); +} + +PX_INLINE void Actor::setOwnerClient( PxClientID inId ) +{ + //This call is only valid if we aren't in a scene. + //Thus we can't be buffering yet + if (!isBuffering()) + { + getActorCore().setOwnerClient( inId ); + UPDATE_PVD_PROPERTIES_OBJECT() + } + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, + "Attempt to set the client id when an actor is buffering"); + } +} + +PX_INLINE void Actor::syncState() +{ + //this should be called from syncState() of derived classes + + const PxU32 flags = getBufferFlags(); + if (flags & (Buf::BF_ActorFlags|Buf::BF_DominanceGroup|Buf::BF_ClientBehaviorFlags)) + { + Core& core = getActorCore(); + Buf& buffer = *reinterpret_cast<Buf*>(getStream()); + + flush<Buf::BF_ActorFlags>(core, buffer); + flush<Buf::BF_DominanceGroup>(core, buffer); + flush<Buf::BF_ClientBehaviorFlags>(core, buffer); + } +} + +} // namespace Scb + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/buffering/ScbAggregate.cpp b/PhysX_3.4/Source/PhysX/src/buffering/ScbAggregate.cpp new file mode 100644 index 00000000..22a26abd --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/buffering/ScbAggregate.cpp @@ -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. + + +#include "ScbAggregate.h" +#include "ScbActor.h" + +using namespace physx; + + +void Scb::Aggregate::addActor(Scb::Actor& actor) +{ + const ControlState::Enum state = getControlState(); + + if(!isBufferingSpecial(state)) + { + actor.getActorCore().setAggregateID(mAggregateID); + PvdAttachActorToAggregate( this, &actor ); + PvdUpdateProperties( this ); + } + else if ((state != ControlState::eREMOVE_PENDING)) // If the aggregate is pending for deletion, adding/removing an actor should not be double buffered because the aggregateID must not be set for the actors + { + // if available, search in list of removed actors to cover the remove-add case + Scb::AggregateBuffer* PX_RESTRICT bufferedData = getBufferedData(); + if (bufferedData->removeBufferIdx != 0xffffffff) + { + Scb::Actor** removeBuffer = getScbScene()->getActorBuffer(bufferedData->removeBufferIdx); + for(PxU32 i=0; i < bufferedData->removeCount; i++) + { + if (removeBuffer[i] == &actor) + { + removeBuffer[i] = removeBuffer[bufferedData->removeCount - 1]; + PX_ASSERT(bufferedData->removeCount > 0); + bufferedData->removeCount--; + break; + } + } + } + + Scb::Actor** actorBuffer; + if (bufferedData->addBufferIdx == 0xffffffff) + { + actorBuffer = getScbScene()->allocActorBuffer(mMaxNbActors, bufferedData->addBufferIdx); + } + else + { + actorBuffer = getScbScene()->getActorBuffer(bufferedData->addBufferIdx); + } + + PX_ASSERT(bufferedData->addCount < mMaxNbActors); + actorBuffer[bufferedData->addCount] = &actor; + bufferedData->addCount++; + + if (state != ControlState::eINSERT_PENDING) + markUpdated(BF_ADD_ACTOR); + else + { + // Not a great solution but aggregates are special in the sense that even in the pending insert case, data needs to be double buffered + // (see isBufferingSpecial() for details) + setBufferFlag(BF_ADD_ACTOR); + } + } +} + + +void Scb::Aggregate::removeActor(Scb::Actor& actor, bool reinsert) +{ + const ControlState::Enum state = getControlState(); + const ControlState::Enum actorState = actor.getControlState(); + + if(!isBufferingSpecial(state)) + { + Sc::ActorCore& ac = actor.getActorCore(); + ac.setAggregateID(PX_INVALID_U32); + + if(getScbSceneForAPI() && reinsert) + { + ac.reinsertShapes(); + } + } + else if ((state != ControlState::eREMOVE_PENDING)) + { + // if available, search in list of added actors to cover the add-remove case + Scb::AggregateBuffer* PX_RESTRICT bufferedData = getBufferedData(); + if (bufferedData->addBufferIdx != 0xffffffff) + { + Scb::Actor** addBuffer = getScbScene()->getActorBuffer(bufferedData->addBufferIdx); + for(PxU32 i=0; i < bufferedData->addCount; i++) + { + if (addBuffer[i] == &actor) + { + addBuffer[i] = addBuffer[bufferedData->addCount - 1]; + PX_ASSERT(bufferedData->addCount > 0); + bufferedData->addCount--; + return; // It's fine to abort here because the aggregateID has not been set yet + } + } + } + + Scb::Actor** actorBuffer; + if (bufferedData->removeBufferIdx == 0xffffffff) + { + actorBuffer = getScbScene()->allocActorBuffer(mMaxNbActors, bufferedData->removeBufferIdx); + } + else + { + actorBuffer = getScbScene()->getActorBuffer(bufferedData->removeBufferIdx); + } + + PX_ASSERT(bufferedData->removeCount < mMaxNbActors); + actorBuffer[bufferedData->removeCount] = &actor; + bufferedData->removeCount++; + + markUpdated(BF_REMOVE_ACTOR); + } + + //Update pvd status if not buffer OR the actor release while aggregate is already in scene + if(!isBufferingSpecial(state) + || ((actorState == ControlState::eIN_SCENE || actorState == ControlState::eREMOVE_PENDING ) + && state != ControlState::eINSERT_PENDING + && !reinsert)) + { + PvdDetachActorFromAggregate( this, &actor ); + PvdUpdateProperties( this ); + } +} diff --git a/PhysX_3.4/Source/PhysX/src/buffering/ScbAggregate.h b/PhysX_3.4/Source/PhysX/src/buffering/ScbAggregate.h new file mode 100644 index 00000000..55911d22 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/buffering/ScbAggregate.h @@ -0,0 +1,249 @@ +// 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_SCB_AGGREGATE +#define PX_PHYSICS_SCB_AGGREGATE + +#include "CmPhysXCommon.h" +#include "PxAggregate.h" +#include "ScbActor.h" +#include "ScbAggregate.h" +#include "ScbBase.h" + +// PX_SERIALIZATION +#include "PxSerialFramework.h" +//~PX_SERIALIZATION + +namespace physx +{ +namespace Scb +{ + +class Actor; + +struct AggregateBuffer +{ + AggregateBuffer() : addBufferIdx(0xffffffff), addCount(0), removeBufferIdx(0xffffffff), removeCount(0) {} + + PxU32 addBufferIdx; + PxU32 addCount; + PxU32 removeBufferIdx; + PxU32 removeCount; +}; + + +class Aggregate : public Base +{ +//= 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. +//================================================================================================== +private: + enum BufferFlag + { + BF_ADD_ACTOR = (1 << 0), + BF_REMOVE_ACTOR = (1 << 1) + }; + +public: + +// PX_SERIALIZATION + Aggregate(const PxEMPTY) : Base(PxEmpty) {} + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + PX_INLINE Aggregate(PxAggregate* px, PxU32 maxActors, bool selfCollision); + PX_INLINE ~Aggregate(); + + void addActor(Scb::Actor&); + void removeActor(Scb::Actor& actor, bool reinsert); + + + //--------------------------------------------------------------------------------- + // Data synchronization + //--------------------------------------------------------------------------------- + PX_INLINE void syncState(Scb::Scene& scene); + + //--------------------------------------------------------------------------------- + // Miscellaneous + //--------------------------------------------------------------------------------- + PX_FORCE_INLINE PxU32 getMaxActorCount() const { return mMaxNbActors; } + PX_FORCE_INLINE bool getSelfCollide() const { return mSelfCollide; } + PX_FORCE_INLINE PxU32 getAggregateID() const { return mAggregateID; } + PX_FORCE_INLINE void setAggregateID(PxU32 cid) { mAggregateID = cid; } + + PX_FORCE_INLINE bool isBufferingSpecial(ControlState::Enum state) const; + + PxAggregate* mPxAggregate; // Back pointer +private: + PxU32 mAggregateID; + PxU32 mMaxNbActors; + bool mSelfCollide; + + PX_FORCE_INLINE const Scb::AggregateBuffer* getBufferedData() const { return reinterpret_cast<const Scb::AggregateBuffer*>(getStream()); } + PX_FORCE_INLINE Scb::AggregateBuffer* getBufferedData() { return reinterpret_cast<Scb::AggregateBuffer*>(getStream()); } +}; + + +PX_INLINE Aggregate::Aggregate(PxAggregate* px, PxU32 maxActors, bool selfCollision) : + mPxAggregate (px), + mAggregateID (PX_INVALID_U32), + mMaxNbActors (maxActors), + mSelfCollide (selfCollision) +{ + setScbType(ScbType::AGGREGATE); +} + + +PX_INLINE Aggregate::~Aggregate() +{ +} + +PX_FORCE_INLINE bool Aggregate::isBufferingSpecial(ControlState::Enum state) const +{ + // A special version of the buffer check is needed for aggregates because it is not fine for adding/removing + // an actor to be not double buffered if the aggregate is pending for insertion. + // For example: Adding an actor can not be processed if the aggregate is pending for insertion because the aggregateID + // is not yet available (an there is no Sc::Aggregate object to store the actors) + + Scb::Scene* scbScene = getScbSceneForAPI(); + return state == ControlState::eREMOVE_PENDING || // pending remove not possible if not buffered + (scbScene && scbScene->isPhysicsBuffering()); +} + +//-------------------------------------------------------------- +// +// PVD Events +// +//-------------------------------------------------------------- + +namespace +{ +#if PX_SUPPORT_PVD + PX_FORCE_INLINE void PvdAttachActorToAggregate(Scb::Aggregate* pAggregate, Scb::Actor* pScbActor) + { + Scb::Scene* scbScene = pAggregate->getScbSceneForAPI(); + if( scbScene/* && scbScene->getScenePvdClient().isInstanceValid(pAggregate)*/) + { + scbScene->getScenePvdClient().attachAggregateActor( pAggregate, pScbActor ); + } + } + + PX_FORCE_INLINE void PvdDetachActorFromAggregate(Scb::Aggregate* pAggregate, Scb::Actor* pScbActor) + { + Scb::Scene* scbScene = pAggregate->getScbSceneForAPI(); + if( scbScene/*&& scbScene->getScenePvdClient().isInstanceValid(pAggregate)*/) + { + scbScene->getScenePvdClient().detachAggregateActor( pAggregate, pScbActor ); + } + } + + PX_FORCE_INLINE void PvdUpdateProperties(Scb::Aggregate* pAggregate) + { + Scb::Scene* scbScene = pAggregate->getScbSceneForAPI(); + if( scbScene /*&& scbScene->getScenePvdClient().isInstanceValid(pAggregate)*/) + { + scbScene->getScenePvdClient().updatePvdProperties( pAggregate ); + } + } +#else +#define PvdAttachActorToAggregate(aggregate, scbActor) {} +#define PvdDetachActorFromAggregate(aggregate, scbActor) {} +#define PvdUpdateProperties(aggregate) {} +#endif +} + +//-------------------------------------------------------------- +// +// Data synchronization +// +//-------------------------------------------------------------- + +PX_INLINE void Aggregate::syncState(Scb::Scene& scene) +{ + PxU32 flags = getBufferFlags(); + + enum AggregateSyncDirtyType + { + DIRTY_NONE = 0, + DIRTY_ADD_ACTOR = 1<<0, + DIRTY_REMOVE_ACTOR = 1<<1 + }; + + PxU32 dirtyType = DIRTY_NONE; + + if (flags) + { + const Scb::AggregateBuffer* PX_RESTRICT bufferedData = getBufferedData(); + + if (flags & BF_ADD_ACTOR) + { + dirtyType |= DIRTY_ADD_ACTOR; + + Scb::Actor* const* actorBuffer = scene.getActorBuffer(bufferedData->addBufferIdx); + + PX_ASSERT(mAggregateID != PX_INVALID_U32); + for(PxU32 i=0; i < bufferedData->addCount; i++) + { + actorBuffer[i]->getActorCore().setAggregateID(mAggregateID); + PvdAttachActorToAggregate( this, actorBuffer[i] ); + } + } + + if (flags & BF_REMOVE_ACTOR) + { + dirtyType |= DIRTY_REMOVE_ACTOR; + Scb::Actor* const* actorBuffer = scene.getActorBuffer(bufferedData->removeBufferIdx); + + for(PxU32 i=0; i < bufferedData->removeCount; i++) + { + const ControlState::Enum state = actorBuffer[i]->getControlState(); + + Sc::ActorCore& ac = actorBuffer[i]->getActorCore(); + ac.setAggregateID(PX_INVALID_U32); + if(state != ControlState::eREMOVE_PENDING) + PvdDetachActorFromAggregate( this, actorBuffer[i] ); + if (state == ControlState::eINSERT_PENDING || state == ControlState::eIN_SCENE) + ac.reinsertShapes(); + } + } + + if(dirtyType != DIRTY_NONE) + PvdUpdateProperties( this ); + } + + postSyncState(); +} + +}// namespace Scb +}// namespace physx + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/buffering/ScbArticulation.h b/PhysX_3.4/Source/PhysX/src/buffering/ScbArticulation.h new file mode 100644 index 00000000..424cf34b --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/buffering/ScbArticulation.h @@ -0,0 +1,353 @@ +// 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_SCB_ARTICULATION +#define PX_PHYSICS_SCB_ARTICULATION + +#include "ScArticulationCore.h" +#include "ScbBase.h" +#include "ScbDefs.h" + +namespace physx +{ + +namespace Scb +{ + +struct ArticulationBuffer +{ + template <PxU32 I, PxU32 Dummy> struct Fns {}; + typedef Sc::ArticulationCore Core; + typedef ArticulationBuffer Buf; + + SCB_REGULAR_ATTRIBUTE(0, PxU32, InternalDriveIterations) + SCB_REGULAR_ATTRIBUTE(1, PxU32, ExternalDriveIterations) + SCB_REGULAR_ATTRIBUTE(2, PxU32, MaxProjectionIterations) + SCB_REGULAR_ATTRIBUTE(3, PxReal, SeparationTolerance) + SCB_REGULAR_ATTRIBUTE(4, PxReal, SleepThreshold) + SCB_REGULAR_ATTRIBUTE(5, PxU16, SolverIterationCounts) + SCB_REGULAR_ATTRIBUTE(6, PxReal, FreezeThreshold) + + enum { BF_WakeCounter = 1<<7 }; + enum { BF_PutToSleep = 1<<8 }; + enum { BF_WakeUp = 1<<9 }; + +}; + +class Articulation : public Base +{ +//= 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. +//================================================================================================== + + typedef ArticulationBuffer Buf; + typedef Sc::ArticulationCore Core; + +// PX_SERIALIZATION +public: + Articulation(const PxEMPTY) : Base(PxEmpty), mArticulation(PxEmpty), mBufferedIsSleeping(1) {} + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + +private: + +public: + PX_INLINE Articulation(); + PX_INLINE ~Articulation() {} + + //--------------------------------------------------------------------------------- + // Wrapper for Sc::Articulation interface + //--------------------------------------------------------------------------------- + + PX_INLINE PxU32 getInternalDriveIterations() const { return read<Buf::BF_InternalDriveIterations>(); } + PX_INLINE void setInternalDriveIterations(const PxU32 v) { write<Buf::BF_InternalDriveIterations>(v); } + + PX_INLINE PxU32 getExternalDriveIterations() const { return read<Buf::BF_ExternalDriveIterations>(); } + PX_INLINE void setExternalDriveIterations(const PxU32 v) { write<Buf::BF_ExternalDriveIterations>(v); } + + PX_INLINE PxU32 getMaxProjectionIterations() const { return read<Buf::BF_MaxProjectionIterations>(); } + PX_INLINE void setMaxProjectionIterations(const PxU32 v) { write<Buf::BF_MaxProjectionIterations>(v); } + + PX_INLINE PxU16 getSolverIterationCounts() const { return read<Buf::BF_SolverIterationCounts>(); } + PX_INLINE void setSolverIterationCounts(PxU16 v) { write<Buf::BF_SolverIterationCounts>(v); } + + PX_INLINE PxReal getSeparationTolerance() const { return read<Buf::BF_SeparationTolerance>(); } + PX_INLINE void setSeparationTolerance(const PxReal v) { write<Buf::BF_SeparationTolerance>(v); } + + PX_INLINE PxReal getSleepThreshold() const { return read<Buf::BF_SleepThreshold>(); } + PX_INLINE void setSleepThreshold(const PxReal v) { write<Buf::BF_SleepThreshold>(v); } + + PX_INLINE PxReal getFreezeThreshold() const { return read<Buf::BF_SleepThreshold>(); } + PX_INLINE void setFreezeThreshold(const PxReal v) { write<Buf::BF_SleepThreshold>(v); } + + PX_INLINE PxReal getWakeCounter() const { return mBufferedWakeCounter; } + PX_INLINE void setWakeCounter(const PxReal v); + + PX_FORCE_INLINE void wakeUp(); + PX_FORCE_INLINE void putToSleep(); + PX_FORCE_INLINE bool isSleeping() const { return (mBufferedIsSleeping != 0); } + + //--------------------------------------------------------------------------------- + // Data synchronization + //--------------------------------------------------------------------------------- + PX_INLINE void syncState(); + + PX_FORCE_INLINE const Sc::ArticulationCore& getScArticulation() const { return mArticulation; } // Only use if you know what you're doing! + PX_FORCE_INLINE Sc::ArticulationCore& getScArticulation() { return mArticulation; } // Only use if you know what you're doing! + + PX_FORCE_INLINE static Articulation& fromSc(Core &a) { return *reinterpret_cast<Articulation*>(reinterpret_cast<PxU8*>(&a)-getScOffset()); } + PX_FORCE_INLINE static const Articulation& fromSc(const Core &a) { return *reinterpret_cast<const Articulation*>(reinterpret_cast<const PxU8*>(&a)-getScOffset()); } + static size_t getScOffset() + { + return reinterpret_cast<size_t>(&reinterpret_cast<Articulation*>(0)->mArticulation); + } + + PX_FORCE_INLINE void wakeUpInternal(PxReal wakeCounter); + + PX_FORCE_INLINE void initBufferedState(); + PX_FORCE_INLINE void clearBufferedState(); + PX_FORCE_INLINE void clearBufferedSleepStateChange(); + +private: + Sc::ArticulationCore mArticulation; + PxReal mBufferedWakeCounter; + PxU8 mBufferedIsSleeping; + + PX_FORCE_INLINE const Buf* getArticulationBuffer() const { return reinterpret_cast<const Buf*>(getStream()); } + PX_FORCE_INLINE Buf* getArticulationBuffer() { return reinterpret_cast<Buf*>(getStream()); } + + + //--------------------------------------------------------------------------------- + // Infrastructure for regular attributes + //--------------------------------------------------------------------------------- + + struct Access: public BufferedAccess<Buf, Core, Articulation> {}; + template<PxU32 f> PX_FORCE_INLINE typename Buf::Fns<f,0>::Arg read() const { return Access::read<Buf::Fns<f,0> >(*this, mArticulation); } + template<PxU32 f> PX_FORCE_INLINE void write(typename Buf::Fns<f,0>::Arg v) { Access::write<Buf::Fns<f,0> >(*this, mArticulation, v); } + template<PxU32 f> PX_FORCE_INLINE void flush(const Buf& buf) { Access::flush<Buf::Fns<f,0> >(*this, mArticulation, buf); } + +}; + + +Articulation::Articulation() +{ + setScbType(ScbType::ARTICULATION); + mBufferedWakeCounter = getScArticulation().getWakeCounter(); + mBufferedIsSleeping = 1; // this is the specified value for free standing objects +} + + +PX_INLINE void Articulation::setWakeCounter(PxReal counter) +{ + mBufferedWakeCounter = counter; + + if (!isBuffering()) + { + if (getScbScene() && (counter > 0.0f)) + mBufferedIsSleeping = 0; + + getScArticulation().setWakeCounter(counter); + UPDATE_PVD_PROPERTIES_OBJECT() + } + else + { + if (counter > 0.0f) + { + mBufferedIsSleeping = 0; + markUpdated(Buf::BF_WakeUp | Buf::BF_WakeCounter); + resetBufferFlag(Buf::BF_PutToSleep); + } + else + markUpdated(Buf::BF_WakeCounter); + } +} + + +PX_FORCE_INLINE void Articulation::wakeUp() +{ + Scene* scene = getScbScene(); + PX_ASSERT(scene); // only allowed for an object in a scene + + wakeUpInternal(scene->getWakeCounterResetValue()); +} + + +PX_FORCE_INLINE void Articulation::wakeUpInternal(PxReal wakeCounter) +{ + PX_ASSERT(getScbScene()); + + mBufferedWakeCounter = wakeCounter; + + mBufferedIsSleeping = 0; + if (!isBuffering()) + { + getScArticulation().wakeUp(wakeCounter); + } + else + { + markUpdated(Buf::BF_WakeUp | Buf::BF_WakeCounter); + resetBufferFlag(Buf::BF_PutToSleep); + } +} + + +PX_FORCE_INLINE void Articulation::putToSleep() +{ + mBufferedWakeCounter = 0.0f; + + mBufferedIsSleeping = 1; + if (!isBuffering()) + { + getScArticulation().putToSleep(); + } + else + { + markUpdated(Buf::BF_PutToSleep | Buf::BF_WakeCounter); + resetBufferFlag(Buf::BF_WakeUp); + } +} + + +PX_FORCE_INLINE void Articulation::initBufferedState() +{ + PX_ASSERT(mBufferedIsSleeping); // this method is only meant to get called when an object is added to the scene + + if (getWakeCounter() == 0.0f) + mBufferedIsSleeping = 1; + else + mBufferedIsSleeping = 0; + // note: to really know whether the articulation is awake/asleep on insertion, we need to go through every link and check whether any of them has + // a parameter setup that keeps it alive. However, the links get added after the articulation, so we do not test those here. After the links + // are added, an additional check will wake the articulation up if necessary. +} + + +PX_FORCE_INLINE void Articulation::clearBufferedState() +{ + mBufferedIsSleeping = 1; // the expected state when an object gets removed from the scene +} + + +PX_FORCE_INLINE void Articulation::clearBufferedSleepStateChange() +{ + resetBufferFlag(Buf::BF_WakeUp | Buf::BF_PutToSleep); +} + +//-------------------------------------------------------------- +// +// Data synchronization +// +//-------------------------------------------------------------- + +PX_INLINE void Articulation::syncState() +{ + // see comments in Body::syncState + PX_ASSERT( (getControlState() != ControlState::eREMOVE_PENDING) || + (mBufferedIsSleeping && (!isBuffered(Buf::BF_WakeUp | Buf::BF_PutToSleep))) ); + + PxU32 flags = getBufferFlags(); + + //---- + + if ((flags & Buf::BF_WakeCounter) == 0) + mBufferedWakeCounter = getScArticulation().getWakeCounter(); + else if (!(flags & (Buf::BF_WakeUp | Buf::BF_PutToSleep))) // if there has been at least one buffered sleep state transition, then there is no use in adjusting the wake counter separately because it will + // get done in the sleep state update. + { + PX_ASSERT(mBufferedWakeCounter == 0.0f); // a wake counter change is always connected to a sleep state change, except one case: if setWakeCounter(0.0f) was called + + getScArticulation().setWakeCounter(mBufferedWakeCounter); + } + + //---- + + bool isSimObjectSleeping = getScArticulation().isSleeping(); + if ((flags & (Buf::BF_WakeUp | Buf::BF_PutToSleep)) == 0) + { + if (getControlState() != ControlState::eREMOVE_PENDING) // we do not want the simulation sleep state to take effect if the object was removed (free standing objects have buffered state sleeping) + mBufferedIsSleeping = PxU8(isSimObjectSleeping); + else + PX_ASSERT(mBufferedIsSleeping); // this must get set immediately at remove + } + else + { + PX_ASSERT(flags & Buf::BF_WakeCounter); // sleep state transitions always mark the wake counter dirty + PX_ASSERT(getControlState() != ControlState::eREMOVE_PENDING); // removing an object should clear pending wakeUp/putToSleep operations since the state for a free standing object gets set according to specification. + + if (flags & Buf::BF_PutToSleep) + { + PX_ASSERT(mBufferedIsSleeping); + PX_ASSERT(!(flags & Buf::BF_WakeUp)); + PX_ASSERT(mBufferedWakeCounter == 0.0f); + getScArticulation().putToSleep(); + } + else + { + PX_ASSERT(!mBufferedIsSleeping); + PX_ASSERT(flags & Buf::BF_WakeUp); + + getScArticulation().wakeUp(mBufferedWakeCounter); + } + } + + //---- + + if(flags&~(Buf::BF_WakeCounter|Buf::BF_WakeUp|Buf::BF_PutToSleep)) // Optimization to avoid all the if-statements below if possible + { + const Buf* PX_RESTRICT buffer = getArticulationBuffer(); + + flush<Buf::BF_ExternalDriveIterations>(*buffer); + flush<Buf::BF_InternalDriveIterations>(*buffer); + flush<Buf::BF_MaxProjectionIterations>(*buffer); + flush<Buf::BF_SeparationTolerance>(*buffer); + flush<Buf::BF_SleepThreshold>(*buffer); + flush<Buf::BF_SolverIterationCounts>(*buffer); + flush<Buf::BF_FreezeThreshold>(*buffer); + } + + // -------------- + // postconditions + // + PX_ASSERT((getControlState() != ControlState::eREMOVE_PENDING) || mBufferedIsSleeping); // nothing in this method should change this + // + // postconditions + // -------------- + + postSyncState(); +} + +} // namespace Scb + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/buffering/ScbArticulationJoint.h b/PhysX_3.4/Source/PhysX/src/buffering/ScbArticulationJoint.h new file mode 100644 index 00000000..04a49f1c --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/buffering/ScbArticulationJoint.h @@ -0,0 +1,283 @@ +// 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_SCB_ARTICULATION_JOINT +#define PX_PHYSICS_SCB_ARTICULATION_JOINT + +#include "ScArticulationJointCore.h" +#include "ScbBody.h" +#include "ScbBase.h" +#include "ScbDefs.h" + +namespace physx +{ +namespace Scb +{ + +struct ArticulationJointBuffer +{ + template <PxU32 I, PxU32 Dummy> struct Fns {}; + typedef Sc::ArticulationJointCore Core; + typedef ArticulationJointBuffer Buf; + + SCB_REGULAR_ATTRIBUTE(0, PxTransform, ParentPose) + SCB_REGULAR_ATTRIBUTE(1, PxTransform, ChildPose) + SCB_REGULAR_ATTRIBUTE(2, PxQuat, TargetOrientation) + SCB_REGULAR_ATTRIBUTE(3, PxVec3, TargetVelocity) + SCB_REGULAR_ATTRIBUTE(4, PxReal, Stiffness) + SCB_REGULAR_ATTRIBUTE(5, PxReal, Damping) + SCB_REGULAR_ATTRIBUTE(6, PxReal, InternalCompliance) + SCB_REGULAR_ATTRIBUTE(7, PxReal, ExternalCompliance) + SCB_REGULAR_ATTRIBUTE(8, PxReal, SwingLimitContactDistance) + SCB_REGULAR_ATTRIBUTE(9, bool, SwingLimitEnabled) + SCB_REGULAR_ATTRIBUTE(10, PxReal, TangentialStiffness) + SCB_REGULAR_ATTRIBUTE(11, PxReal, TangentialDamping) + SCB_REGULAR_ATTRIBUTE(12, PxReal, TwistLimitContactDistance) + SCB_REGULAR_ATTRIBUTE(13, bool, TwistLimitEnabled) + SCB_REGULAR_ATTRIBUTE(14, PxArticulationJointDriveType::Enum, DriveType) + + enum { BF_SwingLimit = 1<<15 }; + enum { BF_TwistLimit = 1<<16 }; + + PxReal mSwingLimitY; + PxReal mSwingLimitZ; + PxReal mTwistLimitLower; + PxReal mTwistLimitUpper; +}; + +class ArticulationJoint : public Base +{ +//= 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. +//================================================================================================== + + typedef ArticulationJointBuffer Buf; + typedef Sc::ArticulationJointCore Core; + +public: +// PX_SERIALIZATION + ArticulationJoint(const PxEMPTY) : Base(PxEmpty), mJoint(PxEmpty) {} + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + + PX_INLINE ArticulationJoint(const PxTransform& parentFrame, + const PxTransform& childFrame); + PX_INLINE ~ArticulationJoint(); + + //--------------------------------------------------------------------------------- + // Wrapper for Sc::ArticulationJoint interface + //--------------------------------------------------------------------------------- + + PX_INLINE PxTransform getParentPose() const { return read<Buf::BF_ParentPose>(); } + PX_INLINE void setParentPose(const PxTransform& v) { write<Buf::BF_ParentPose>(v); } + + PX_INLINE PxTransform getChildPose() const { return read<Buf::BF_ChildPose>(); } + PX_INLINE void setChildPose(const PxTransform& v) { write<Buf::BF_ChildPose>(v); } + + PX_INLINE PxQuat getTargetOrientation() const { return read<Buf::BF_TargetOrientation>(); } + PX_INLINE void setTargetOrientation(const PxQuat& v) { write<Buf::BF_TargetOrientation>(v); } + + PX_INLINE PxVec3 getTargetVelocity() const { return read<Buf::BF_TargetVelocity>(); } + PX_INLINE void setTargetVelocity(const PxVec3& v) { write<Buf::BF_TargetVelocity>(v); } + + PX_INLINE PxReal getStiffness() const { return read<Buf::BF_Stiffness>(); } + PX_INLINE void setStiffness(PxReal v) { write<Buf::BF_Stiffness>(v); } + + PX_INLINE PxReal getDamping() const { return read<Buf::BF_Damping>(); } + PX_INLINE void setDamping(PxReal v) { write<Buf::BF_Damping>(v); } + + PX_INLINE PxReal getInternalCompliance() const { return read<Buf::BF_InternalCompliance>(); } + PX_INLINE void setInternalCompliance(PxReal v) { write<Buf::BF_InternalCompliance>(v); } + + PX_INLINE PxReal getExternalCompliance() const { return read<Buf::BF_ExternalCompliance>(); } + PX_INLINE void setExternalCompliance(PxReal v) { write<Buf::BF_ExternalCompliance>(v); } + + PX_INLINE PxReal getTangentialStiffness() const { return read<Buf::BF_TangentialStiffness>(); } + PX_INLINE void setTangentialStiffness(PxReal v) { write<Buf::BF_TangentialStiffness>(v); } + + PX_INLINE PxReal getTangentialDamping() const { return read<Buf::BF_TangentialDamping>(); } + PX_INLINE void setTangentialDamping(PxReal v) { write<Buf::BF_TangentialDamping>(v); } + + PX_INLINE PxReal getSwingLimitContactDistance() const { return read<Buf::BF_SwingLimitContactDistance>(); } + PX_INLINE void setSwingLimitContactDistance(PxReal v) { write<Buf::BF_SwingLimitContactDistance>(v); } + + PX_INLINE PxReal getTwistLimitContactDistance() const { return read<Buf::BF_TwistLimitContactDistance>(); } + PX_INLINE void setTwistLimitContactDistance(PxReal v) { write<Buf::BF_TwistLimitContactDistance>(v); } + + PX_INLINE PxArticulationJointDriveType::Enum + getDriveType() const { return read<Buf::BF_DriveType>(); } + PX_INLINE void setDriveType(PxArticulationJointDriveType::Enum v) + { write<Buf::BF_DriveType>(v); } + + PX_INLINE bool getSwingLimitEnabled() const { return read<Buf::BF_SwingLimitEnabled>(); } + PX_INLINE void setSwingLimitEnabled(bool v) { write<Buf::BF_SwingLimitEnabled>(v); } + + PX_INLINE bool getTwistLimitEnabled() const { return read<Buf::BF_TwistLimitEnabled>(); } + PX_INLINE void setTwistLimitEnabled(bool v) { write<Buf::BF_TwistLimitEnabled>(v); } + + PX_INLINE void getSwingLimit(PxReal& yLimit, PxReal& zLimit) const; + PX_INLINE void setSwingLimit(PxReal yLimit, PxReal zLimit); + + PX_INLINE void getTwistLimit(PxReal &lower, PxReal &upper) const; + PX_INLINE void setTwistLimit(PxReal lower, PxReal upper); + + //--------------------------------------------------------------------------------- + // Data synchronization + //--------------------------------------------------------------------------------- + PX_INLINE void syncState(); + + PX_FORCE_INLINE const Core& getScArticulationJoint() const { return mJoint; } // Only use if you know what you're doing! + PX_FORCE_INLINE Core& getScArticulationJoint() { return mJoint; } // Only use if you know what you're doing! + +private: + Core mJoint; + + PX_FORCE_INLINE const Buf* getBuffer() const { return reinterpret_cast<const Buf*>(getStream()); } + PX_FORCE_INLINE Buf* getBuffer() { return reinterpret_cast<Buf*>(getStream()); } + + //--------------------------------------------------------------------------------- + // Infrastructure for regular attributes + //--------------------------------------------------------------------------------- + + struct Access: public BufferedAccess<Buf, Core, ArticulationJoint> {}; + template<PxU32 f> PX_FORCE_INLINE typename Buf::Fns<f,0>::Arg read() const { return Access::read<Buf::Fns<f,0> >(*this, mJoint); } + template<PxU32 f> PX_FORCE_INLINE void write(typename Buf::Fns<f,0>::Arg v) { Access::write<Buf::Fns<f,0> >(*this, mJoint, v); } + template<PxU32 f> PX_FORCE_INLINE void flush(const Buf& buf) { Access::flush<Buf::Fns<f,0> >(*this, mJoint, buf); } +}; + + +ArticulationJoint::ArticulationJoint(const PxTransform& parentFrame, + const PxTransform& childFrame) : + mJoint(parentFrame, childFrame) +{ + setScbType(ScbType::ARTICULATION_JOINT); +} + + +ArticulationJoint::~ArticulationJoint() +{ +} + +PX_INLINE void ArticulationJoint::getSwingLimit(PxReal &yLimit, PxReal &zLimit) const +{ + if (isBuffered(Buf::BF_SwingLimit)) + { + yLimit = getBuffer()->mSwingLimitY; + zLimit = getBuffer()->mSwingLimitZ; + } + else + getScArticulationJoint().getSwingLimit(yLimit, zLimit); +} + + +PX_INLINE void ArticulationJoint::setSwingLimit(PxReal yLimit, PxReal zLimit) +{ + if (!isBuffering()) + getScArticulationJoint().setSwingLimit(yLimit, zLimit); + else + { + getBuffer()->mSwingLimitY = yLimit; + getBuffer()->mSwingLimitZ = zLimit; + markUpdated(Buf::BF_SwingLimit); + } +} + + +PX_INLINE void ArticulationJoint::getTwistLimit(PxReal &lower, PxReal &upper) const +{ + if (isBuffered(Buf::BF_TwistLimit)) + { + lower = getBuffer()->mTwistLimitLower; + upper = getBuffer()->mTwistLimitUpper; + } + else + mJoint.getTwistLimit(lower, upper); +} + + +PX_INLINE void ArticulationJoint::setTwistLimit(PxReal lower, PxReal upper) +{ + if (!isBuffering()) + mJoint.setTwistLimit(lower, upper); + else + { + getBuffer()->mTwistLimitLower = lower; + getBuffer()->mTwistLimitUpper = upper; + markUpdated(Buf::BF_TwistLimit); + } +} + + +//-------------------------------------------------------------- +// +// Data synchronization +// +//-------------------------------------------------------------- + +PX_INLINE void ArticulationJoint::syncState() +{ + PxU32 flags = getBufferFlags(); + if(flags) // Optimization to avoid all the if-statements below if possible + { + const Buf& buffer = *getBuffer(); + + flush<Buf::BF_ParentPose>(buffer); + flush<Buf::BF_ChildPose>(buffer); + flush<Buf::BF_TargetOrientation>(buffer); + flush<Buf::BF_TargetVelocity>(buffer); + flush<Buf::BF_Stiffness>(buffer); + flush<Buf::BF_Damping>(buffer); + flush<Buf::BF_InternalCompliance>(buffer); + flush<Buf::BF_ExternalCompliance>(buffer); + flush<Buf::BF_SwingLimitContactDistance>(buffer); + flush<Buf::BF_SwingLimitEnabled>(buffer); + flush<Buf::BF_TwistLimitContactDistance>(buffer); + flush<Buf::BF_TwistLimitEnabled>(buffer); + flush<Buf::BF_TangentialStiffness>(buffer); + flush<Buf::BF_TangentialDamping>(buffer); + + if (isBuffered(Buf::BF_SwingLimit)) + getScArticulationJoint().setSwingLimit( buffer.mSwingLimitY, buffer.mSwingLimitZ); + + if (isBuffered(Buf::BF_TwistLimit)) + getScArticulationJoint().setTwistLimit( buffer.mTwistLimitLower, buffer.mTwistLimitUpper); + } + + postSyncState(); +} + +} // namespace Scb + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/buffering/ScbBase.cpp b/PhysX_3.4/Source/PhysX/src/buffering/ScbBase.cpp new file mode 100644 index 00000000..fb23dad6 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/buffering/ScbBase.cpp @@ -0,0 +1,48 @@ +// 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 "ScbBase.h" +#include "ScbNpDeps.h" + +using namespace physx; +using namespace Scb; + +void Base::destroy() +{ + if(!isBuffering()) + NpDestroy(*this); + else + { + // Schedule for destroy + PX_ASSERT(!(getControlFlags() & ControlFlag::eIS_RELEASED)); + PX_ASSERT(getControlState() == ControlState::eREMOVE_PENDING); + setControlFlag(ControlFlag::eIS_RELEASED); + } +} diff --git a/PhysX_3.4/Source/PhysX/src/buffering/ScbBase.h b/PhysX_3.4/Source/PhysX/src/buffering/ScbBase.h new file mode 100644 index 00000000..15fb0f75 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/buffering/ScbBase.h @@ -0,0 +1,333 @@ +// 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_SCB_BASE +#define PX_PHYSICS_SCB_BASE + +#include "CmPhysXCommon.h" +#include "ScbScene.h" + +namespace physx +{ + +#if PX_SUPPORT_PVD + // PT: updatePvdProperties() is overloaded and the compiler needs to know 'this' type to do the right thing. + // Thus we can't just move this as an inlined Base function. + #define UPDATE_PVD_PROPERTIES_OBJECT() { \ + Scb::Scene* scene_ = getScbSceneForAPI(); \ + if(scene_ && !insertPending() ) \ + scene_->getScenePvdClient().updatePvdProperties(this); } +#else + #define UPDATE_PVD_PROPERTIES_OBJECT() {} +#endif + +namespace Scb +{ + struct ControlState + { + enum Enum + { + /** + \brief The object is not in the scene. + + The object has not been added to a scene yet. This is the default when an object gets created. + + In this state... + \li ...user changes get written to Core directly. + \li ...the object can not be in the list of dirty objects. + \li ...the object can not be marked as eIS_UPDATED or eIS_RELEASED. + */ + eNOT_IN_SCENE = 0, + + /** + \brief The object waits to get inserted into the scene internally. + + The object has been added to the scene while the simulation is running and is waiting to get fully registered in all layers. + + In this state... + \li ...user changes get written to Core directly (since the object has not yet registered in the inner layers, hence, will not get accessed internally). + \li ...the object is in the list of dirty objects. + \li ...the object can not be marked as eIS_UPDATED or eIS_RELEASED. + */ + eINSERT_PENDING = 1, + + /** + \brief The object is registered in the scene internally. + + The object has been added to the scene and is fully registered in all layers. + + In this state... + \li ...user changes get written to a buffer object and get synced with Core at a sync point. + \li ...the object can be in the list of dirty objects. + \li ...the object can be marked as eIS_UPDATED but not eIS_RELEASED. + */ + eIN_SCENE = 2, + + /** + \brief The object waits to get removed from the scene internally. + + The object is in the scene and fully registered in all layers but has been removed while the simulation is running and is now + waiting to get unregistered from all layers. + + In this state... + \li ...user changes get written to a buffer object and get synced with Core at a sync point. + \li ...the object is in the list of dirty objects. + \li ...the object can be marked as eIS_UPDATED or eIS_RELEASED. + */ + eREMOVE_PENDING = 3 + }; + }; + + struct ControlFlag + { + enum Enum + { + /** + \brief An object property/state has been changed. + + A property/state of the object has been changed and needs to get synced to Core. Insertion & removal don't count. + */ + eIS_UPDATED = 1, + + /** + \brief The object has been released. + + The object has not just been removed from the scene it has been released as well. The object will get destroyed after the sync has been completed. + */ + eIS_RELEASED = 2 + }; + }; + + + /** + \brief Base class for objects that should support buffering. + + This class has members to track the buffering related object state and mark which properties have been changed and need to get synced at sync points. + */ + class Base + { + //= 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. + //================================================================================================== + + protected: +// No-copy + Base(const Base& c); + Base& operator=(const Base& c); + public: + +// PX_SERIALIZATION + Base(const PxEMPTY) : + mScene (NULL), + mStreamPtr(NULL) + { + resetAllBufferFlags(); + resetControl(ControlState::eNOT_IN_SCENE); + } + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + Base() : + mScene (NULL), + mStreamPtr (NULL) + { + setScbType(ScbType::UNDEFINED); + resetControl(ControlState::eNOT_IN_SCENE); + resetAllBufferFlags(); + } + + PX_INLINE bool isBuffering() const + { + const ControlState::Enum state = getControlState(); + return state == ControlState::eREMOVE_PENDING || // pending remove not possible if not buffered + (state == ControlState::eIN_SCENE && mScene->isPhysicsBuffering()); + } + + + PX_FORCE_INLINE Ps::IntBool insertPending() const { return getControlState() == ControlState::eINSERT_PENDING; } + PX_FORCE_INLINE ScbType::Enum getScbType() const { return ScbType::Enum((mControlState&eTYPE_MASK)>>eTYPE_SHIFT); } + PX_FORCE_INLINE void setScbType(ScbType::Enum type) { mControlState = (mControlState&~eTYPE_MASK)|(type<<eTYPE_SHIFT); } + + // the scene value field set if the object is either inserted, in simulation, or waiting for removal. If any of these things + // is true, it can't be added to a different scene + + PX_FORCE_INLINE void setScbScene(Scb::Scene* scene) + { + mScene = scene; + } + + PX_FORCE_INLINE Scb::Scene* getScbScene() const + { + return mScene; + } + + /** + \brief Get scene pointer from a users perspective. + + When the user removes an object from the scene while the simulation is running, the scene pointer does not get set to NULL immediately. This will only happen + at the next sync point. However, from an API point of view, a NULL pointer is expected after a removal. This method provides the correct answer in such a case. + + \return The scene pointer as it should be visible from the users perspective. + */ + PX_FORCE_INLINE Scb::Scene* getScbSceneForAPI() const + { + ControlState::Enum state = getControlState(); + return state == ControlState::eINSERT_PENDING || state == ControlState::eIN_SCENE ? mScene : NULL; + } + + PX_FORCE_INLINE void resetScbScene() { mScene = NULL; } + + PX_FORCE_INLINE bool hasUpdates() const { return getControlFlags() & ControlFlag::eIS_UPDATED; } + PX_FORCE_INLINE PxU32 getControlFlags() const { return (mControlState&eCONTROLFLAG_MASK)>>eCONTROLFLAG_SHIFT; } + PX_FORCE_INLINE void setControlFlag(ControlFlag::Enum f) { mControlState |= (f<<eCONTROLFLAG_SHIFT); } + PX_FORCE_INLINE void resetControlFlag(ControlFlag::Enum f) { mControlState &=~(f<<eCONTROLFLAG_SHIFT); } + + PX_FORCE_INLINE ControlState::Enum getControlState() const { return ControlState::Enum((mControlState&PxU32(eCONTROLSTATE_MASK))>>eCONTROLSTATE_SHIFT);} + PX_FORCE_INLINE void setControlState(ControlState::Enum s) { mControlState = (mControlState&~eCONTROLSTATE_MASK)|(s<<eCONTROLSTATE_SHIFT); } + PX_FORCE_INLINE void resetControl(ControlState::Enum s) { mControlState = (mControlState&~eCONTROL_MASK) | (s<<eCONTROLSTATE_SHIFT); } + + PX_FORCE_INLINE void scheduleForUpdate() { mScene->scheduleForUpdate(*this); } + + /** + \brief Destroys the object. + + If the simulation is not running, this will release the object, else it will just mark the object as eIS_RELEASED and thus it will get deleted + when the next sync point is reached. This method expects that the object has been removed from the scene first (or waits for removal). + */ + void destroy(); + + /** + \brief Test if a property has been changed by the user. + + \param[in] flag The flag of the property to test for. Has to be within the bounds of eBUFFERFLAG_MASK. + \return Positive value if the property has been changed by the user. + */ + PX_FORCE_INLINE Ps::IntBool isBuffered(PxU32 flag) const + { + PX_ASSERT((flag & eBUFFERFLAG_MASK) == flag); + return Ps::IntBool(mControlState & flag); + } + + PX_FORCE_INLINE PxU8* getStream() { return mStreamPtr ? mStreamPtr : mStreamPtr = mScene->getStream(getScbType()); } + PX_FORCE_INLINE const PxU8* getStream() const { PX_ASSERT(mStreamPtr); return mStreamPtr; } + + /** + \brief Helper method to trigger object tracking after a property change. + + This method will flag the marked property as changed and will add the object to the list of updated objects if it is not + registered already. + + \param[in] flag The flag of the changed property. Has to be within the bounds of eBUFFERFLAG_MASK. + */ + PX_FORCE_INLINE void markUpdated(PxU32 flag) + { + PX_ASSERT((flag & eBUFFERFLAG_MASK) == flag); + scheduleForUpdate(); + mControlState |= flag; + } + + protected: + ~Base(){} + + PX_FORCE_INLINE PxU32 getBufferFlags() const { return mControlState & eBUFFERFLAG_MASK; } + PX_FORCE_INLINE void setBufferFlag(PxU32 flag) { PX_ASSERT((flag & eBUFFERFLAG_MASK) == flag); mControlState |= flag; } + PX_FORCE_INLINE void resetBufferFlag(PxU32 flag) { PX_ASSERT((flag & eBUFFERFLAG_MASK) == flag); mControlState &= ~flag; } + PX_FORCE_INLINE void resetAllBufferFlags() { mControlState &=~eBUFFERFLAG_MASK; } + + + /** + \brief Cleanup method after the object has been synced. + + Every buffering object should implement a syncState() method where the buffered user changes get synced with Core. Call this method at the end of the + syncState() method to clear all buffer flags and references. + */ + PX_FORCE_INLINE void postSyncState() + { + // DS: this can get called even when mScene == NULL, by removeAggregate (see AggregateFreeStandingCreateDelete test) + // TODO(dsequeira): investigate that when the dust settles on shape refactoring + PX_ASSERT(getControlState()!=ControlState::eNOT_IN_SCENE || mScene == NULL); + PX_ASSERT(getScbType()!=ScbType::UNDEFINED); + + mStreamPtr = NULL; + resetAllBufferFlags(); + } + + private: + enum { eBUFFERFLAG_MASK = (1<<24) - 1, + eTYPE_MASK = 15<<24, + eCONTROLFLAG_MASK = 3<<28, + eCONTROLSTATE_MASK = 3<<30, + eCONTROL_MASK = 15<<28}; + + enum { eTYPE_SHIFT = 24, + eCONTROLFLAG_SHIFT = 28, + eCONTROLSTATE_SHIFT = 30}; + + /** + \brief Scene pointer. + + The scene pointer get set as soon as the user adds an object to the scene. However, it does not get cleared until the object has been + removed from the scene internally, i.e., removing an object while the simulation is running will not set this pointer to NULL immediately. + */ + Scb::Scene* mScene; + + /** + \brief Mix of buffering related states/flags. + + highest lowest + | 2 | 2 | 4 | 24 | + | ControlState | ControlFlag | ScbType | buffer attribute flags | + + The buffer attribute flags mark which of the properties have been updated. The specific implementation of this class defines those flags. + */ + PxU32 mControlState; + + /** + \brief Data buffer to store property/state changes temporarily. + + Pointer to a temporary struct where user changes made while the simulation is running are buffered. The structure is currently as large as necessary to hold all + properties of a buffered object. Even if only a single property of an object gets changed, the whole structure is assigned. The motivation for this was to keep + the implementation complexity low based on the assumption that users will not change all objects in a scene every frame. The temporary buffer gets assigned on demand + and is returned to pools after the data has been synced to Core. The pointer is then set to NULL again. + This kind of buffer can not be used for properties that get written by the simulation (for example, pose, velocity, sleep state). Those need to be permanently buffered + in the specific implementation of this class, else the user might get an inconsistent picture of the scene object state. + + @see postSyncState() + */ + PxU8* mStreamPtr; + }; + +} // namespace Scb + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/buffering/ScbBody.h b/PhysX_3.4/Source/PhysX/src/buffering/ScbBody.h new file mode 100644 index 00000000..00ce9f52 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/buffering/ScbBody.h @@ -0,0 +1,1068 @@ +// 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_SCB_BODY +#define PX_PHYSICS_SCB_BODY + +#include "ScBodyCore.h" + +#include "ScbRigidObject.h" +#include "CmUtils.h" +#include "PsUtilities.h" +#include "PxRigidDynamic.h" +#include "ScbDefs.h" +#include "GuSIMDHelpers.h" + +namespace physx +{ +namespace Scb +{ +#if PX_VC + #pragma warning(push) + #pragma warning( disable : 4324 ) // Padding was added at the end of a structure because of a __declspec(align) value. +#endif + +struct BodyBuffer : public RigidObjectBuffer //once RigidObject has its own buffered elements, derive from that instead +{ + template <PxU32 I, PxU32 Dummy> struct Fns {}; // TODO: make the base class traits visible + typedef Sc::BodyCore Core; + typedef BodyBuffer Buf; + + // regular attributes + SCB_REGULAR_ATTRIBUTE(0, PxReal, InverseMass) + SCB_REGULAR_ATTRIBUTE(1, PxVec3, InverseInertia) + SCB_REGULAR_ATTRIBUTE(2, PxReal, LinearDamping) + SCB_REGULAR_ATTRIBUTE(3, PxReal, AngularDamping) + SCB_REGULAR_ATTRIBUTE(4, PxReal, MaxAngVelSq) + SCB_REGULAR_ATTRIBUTE(5, PxReal, SleepThreshold) + SCB_REGULAR_ATTRIBUTE(6, PxReal, CCDAdvanceCoefficient) + SCB_REGULAR_ATTRIBUTE(7, PxReal, ContactReportThreshold) + SCB_REGULAR_ATTRIBUTE(8, PxU16, SolverIterationCounts) + SCB_REGULAR_ATTRIBUTE_ALIGNED(9,PxTransform, Body2Actor, 16) + SCB_REGULAR_ATTRIBUTE(10, PxReal, MaxPenetrationBias) + SCB_REGULAR_ATTRIBUTE(11, PxReal, FreezeThreshold) + SCB_REGULAR_ATTRIBUTE(12, PxReal, MaxContactImpulse) + SCB_REGULAR_ATTRIBUTE(13, PxRigidDynamicLockFlags, RigidDynamicLockFlags) + + // irregular attributes + + PX_ALIGN(16, PxTransform) mKinematicTarget; + PxVec3 mLinAcceleration; + PxVec3 mAngAcceleration; + PxVec3 mLinDeltaVelocity; + PxVec3 mAngDeltaVelocity; + + PxRigidBodyFlags mRigidBodyFlags; + PxRigidDynamicLockFlags mRigidDynamicFlags; + + enum + { + BF_RigidBodyFlags = 1<<14, + BF_KinematicTarget = 1<<15, + BF_AccelerationLinear = 1<<16, + BF_AccelerationAngular = 1<<17, + BF_Acceleration = BF_AccelerationLinear|BF_AccelerationAngular, + BF_DeltaVelocityLinear = 1<<18, + BF_DeltaVelocityAngular = 1<<19, + BF_DeltaVelocity = BF_DeltaVelocityLinear|BF_DeltaVelocityAngular, + BF_Body2World = 1<<20, + BF_Body2World_CoM = 1<<21, // the body pose was adjusted because of a center of mass change only + BF_LinearVelocity = 1<<22, + BF_AngularVelocity = 1<<23, + BF_WakeCounter = 1<<24, + BF_PutToSleep = 1<<25, + BF_WakeUp = 1<<26, + BF_ClearAccelerationLinear = 1<<27, + BF_ClearAccelerationAngular = 1<<28, + BF_ClearAcceleration = BF_ClearAccelerationLinear|BF_ClearAccelerationAngular, + BF_ClearDeltaVelocityLinear = 1<<29, + BF_ClearDeltaVelocityAngular= 1<<30, + BF_ClearDeltaVelocity = BF_ClearDeltaVelocityLinear|BF_ClearDeltaVelocityAngular + }; + + BodyBuffer(): mLinAcceleration(0), mAngAcceleration(0), mLinDeltaVelocity(0), mAngDeltaVelocity(0) {} +}; + + +#if PX_VC + #pragma warning(pop) +#endif + +class Body : public Scb::RigidObject +{ +//= 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. +//================================================================================================== + + typedef BodyBuffer Buf; + typedef Sc::BodyCore Core; + +public: +// PX_SERIALIZATION + Body(const PxEMPTY) : Scb::RigidObject(PxEmpty), mBodyCore(PxEmpty), mBufferedIsSleeping(1) { PX_ASSERT(mBodyBufferFlags == 0); } + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + PX_INLINE Body(PxActorType::Enum type, const PxTransform& bodyPose); + PX_INLINE ~Body() {} + + //--------------------------------------------------------------------------------- + // Wrapper for Sc::BodyCore interface + //--------------------------------------------------------------------------------- + + + PX_FORCE_INLINE const PxTransform& getBody2World() const { return mBufferedBody2World; } // PT: important: keep returning an address here (else update prefetch in SceneQueryManager::addShapes) + PX_INLINE void setBody2World(const PxTransform& p, bool asPartOfBody2ActorChange); + + PX_FORCE_INLINE const PxVec3& getLinearVelocity() const { return mBufferedLinVelocity; } + PX_INLINE void setLinearVelocity(const PxVec3& v); + PX_FORCE_INLINE const PxVec3& getAngularVelocity() const { return mBufferedAngVelocity; } + PX_INLINE void setAngularVelocity(const PxVec3& v); + + PX_FORCE_INLINE void wakeUp(); + PX_FORCE_INLINE void putToSleep(); + PX_FORCE_INLINE PxReal getWakeCounter() const { return mBufferedWakeCounter; } + PX_INLINE void setWakeCounter(PxReal w); + PX_FORCE_INLINE bool isSleeping() const { return (mBufferedIsSleeping != 0); } + + PX_INLINE const PxTransform& getBody2Actor() const { return read<Buf::BF_Body2Actor>(); } + PX_INLINE void setBody2Actor(const PxTransform& m) { write<Buf::BF_Body2Actor>(m); } + + PX_INLINE PxReal getInverseMass() const { return read<Buf::BF_InverseMass>(); } + PX_INLINE void setInverseMass(PxReal m) { write<Buf::BF_InverseMass>(m); } + + PX_INLINE PxVec3 getInverseInertia() const { return read<Buf::BF_InverseInertia>(); } + PX_INLINE void setInverseInertia(const PxVec3& i) { write<Buf::BF_InverseInertia>(i); } + + PX_INLINE PxReal getLinearDamping() const { return read<Buf::BF_LinearDamping>(); } + PX_INLINE void setLinearDamping(PxReal d) { write<Buf::BF_LinearDamping>(d); } + + PX_INLINE PxReal getAngularDamping() const { return read<Buf::BF_AngularDamping>(); } + PX_INLINE void setAngularDamping(PxReal d) { write<Buf::BF_AngularDamping>(d); } + + PX_INLINE PxRigidBodyFlags getFlags() const { return (isBuffered(Buf::BF_RigidBodyFlags)) ? getBodyBuffer()->mRigidBodyFlags : mBodyCore.getFlags(); } + PX_INLINE void setFlags(PxRigidBodyFlags f); + + PX_INLINE PxRigidDynamicLockFlags getLockFlags() const { return read<Buf::BF_RigidDynamicLockFlags>(); } + PX_INLINE void setLockFlags(PxRigidDynamicLockFlags f) { write<Buf::BF_RigidDynamicLockFlags>(f); } + + PX_INLINE PxReal getSleepThreshold() const { return read<Buf::BF_SleepThreshold>(); } + PX_INLINE void setSleepThreshold(PxReal t) { write<Buf::BF_SleepThreshold>(t); } + + PX_INLINE PxReal getFreezeThreshold() const { return read<Buf::BF_FreezeThreshold>(); } + PX_INLINE void setFreezeThreshold(PxReal t) { write<Buf::BF_FreezeThreshold>(t); } + + PX_INLINE PxReal getMaxPenetrationBias() const { return read<Buf::BF_MaxPenetrationBias>(); } + PX_INLINE void setMaxPenetrationBias(PxReal t) { write<Buf::BF_MaxPenetrationBias>(t); } + + PX_INLINE PxReal getMaxAngVelSq() const { return read<Buf::BF_MaxAngVelSq>(); } + PX_INLINE void setMaxAngVelSq(PxReal v) { write<Buf::BF_MaxAngVelSq>(v); } + + PX_INLINE PxU16 getSolverIterationCounts() const { return Ps::to16(read<Buf::BF_SolverIterationCounts>()); } + PX_INLINE void setSolverIterationCounts(PxU16 c) { write<Buf::BF_SolverIterationCounts>(c); } + + PX_INLINE PxReal getContactReportThreshold() const { return read<Buf::BF_ContactReportThreshold>(); } + PX_INLINE void setContactReportThreshold(PxReal t) { write<Buf::BF_ContactReportThreshold>(t); } + + PX_INLINE PxReal getMaxContactImpulse() const { return read<Buf::BF_MaxContactImpulse>(); } + PX_INLINE void setMaxContactImpulse(PxReal t) { write<Buf::BF_MaxContactImpulse>(t); } + + PX_INLINE void addSpatialAcceleration(const PxVec3* linAcc, const PxVec3* angAcc); + PX_INLINE void clearSpatialAcceleration(bool force, bool torque); + PX_INLINE void addSpatialVelocity(const PxVec3* linVelDelta, const PxVec3* angVelDelta); + PX_INLINE void clearSpatialVelocity(bool force, bool torque); + + PX_INLINE bool getKinematicTarget(PxTransform& p) const; + PX_INLINE void setKinematicTarget(const PxTransform& p); + + PX_INLINE void setMinCCDAdvanceCoefficient(PxReal minCCDAdvanceCoefficient){write<Buf::BF_CCDAdvanceCoefficient>(minCCDAdvanceCoefficient);} + PX_INLINE PxReal getMinCCDAdvanceCoefficient() const { return read<Buf::BF_CCDAdvanceCoefficient>();} + + PX_FORCE_INLINE void onOriginShift(const PxVec3& shift); + + //--------------------------------------------------------------------------------- + // Data synchronization + //--------------------------------------------------------------------------------- + PX_INLINE void syncState(); + PX_INLINE void syncCollisionWriteThroughState(); + + static size_t getScOffset() + { + return reinterpret_cast<size_t>(&reinterpret_cast<Body*>(0)->mBodyCore); + } + + /** + \brief Shadowed method of #Scb::Base::markUpdated() to store the buffered property flags in a separate location (ran out of flag space) + */ + PX_FORCE_INLINE void markUpdated(PxU32 flag); + + /** + \brief Shadowed method of #Scb::Base::isBuffered() to check the buffered property flags (ran out of flag space) + */ + PX_FORCE_INLINE Ps::IntBool isBuffered(PxU32 flag) const; + + //--------------------------------------------------------------------------------- + // Miscellaneous + //--------------------------------------------------------------------------------- +public: + PX_FORCE_INLINE const Sc::BodyCore& getScBody() const { return mBodyCore; } // Only use if you know what you're doing! + PX_FORCE_INLINE Sc::BodyCore& getScBody() { return mBodyCore; } // Only use if you know what you're doing! + + PX_FORCE_INLINE static const Body& fromSc(const Core& a) { return static_cast<const Body&>(Actor::fromSc(a)); } + PX_FORCE_INLINE static Body& fromSc(Core &a) { return static_cast<Body&>(Actor::fromSc(a)); } + + PX_FORCE_INLINE bool hasKinematicTarget() const; + PX_FORCE_INLINE void clearSimStateDataForPendingInsert(); + PX_FORCE_INLINE void transitionSimStateDataForPendingInsert(); + + PX_INLINE PxMat33 getGlobalInertiaTensorInverse() const; + + PX_FORCE_INLINE bool checkSleepReadinessBesidesWakeCounter(); + PX_FORCE_INLINE void initBufferedState(); + PX_FORCE_INLINE void clearBufferedState(); + PX_FORCE_INLINE void clearBufferedSleepStateChange(); + + PX_INLINE void wakeUpInternal(PxReal wakeCounter); + PX_INLINE void putToSleepInternal(); + + PX_FORCE_INLINE void switchBodyToNoSim(); + +private: + Sc::BodyCore mBodyCore; + //--------------------------------------------------------------------------------- + // Permanently buffered data (simulation written data) + //--------------------------------------------------------------------------------- + PxTransform mBufferedBody2World; + PxVec3 mBufferedLinVelocity; + PxVec3 mBufferedAngVelocity; + PxReal mBufferedWakeCounter; + PxU32 mBufferedIsSleeping; // Note: If the object is not in a scene this value must be true, i.e., positive + // Don't need 4 bytes but otherwise there is padding here anyway. + PxU32 mBodyBufferFlags; // Stores the buffered property flags since there is not enough space in usual location in Scb::Base. + + PX_FORCE_INLINE const Buf* getBodyBuffer() const { return reinterpret_cast<const Buf*>(getStream()); } + PX_FORCE_INLINE Buf* getBodyBuffer() { return reinterpret_cast<Buf*>(getStream()); } + + PX_INLINE void accumulate(PxVec3& linear, PxVec3& angular, PxU32 linearFlag, PxU32 angularFlag, const PxVec3* linIncrement, const PxVec3* angIncrement) + { + PxU32 flag = 0; + if(linIncrement) + { + linear += *linIncrement; + flag |= linearFlag; + } + + if(angIncrement) + { + angular += *angIncrement; + flag |= angularFlag; + } + + markUpdated(flag); + } + + PX_INLINE void resetAccumulator(PxVec3& linear, PxVec3& angular, PxU32 linearFlag, PxU32 angularFlag, PxU32 raisedFlagLinear, PxU32 raisedFlagAngular, bool force, bool torque) + { + PxU32 flags = mBodyBufferFlags; + PxU32 raisedFlags = 0; + if(force) + { + linear = PxVec3(0.0f); + flags &= ~linearFlag; + raisedFlags |= raisedFlagLinear; + } + + if(torque) + { + angular = PxVec3(0.0f); + flags &= ~angularFlag; + raisedFlags |= raisedFlagAngular; + } + + //This is for the split sim logic to support write-through spatial accelerations. It is for the condition where a spatial acceleration has been applied prior to + //collide(). However, a clear spatial acceleration command is raised by the user between collide() and fetchCollision(), we need to raised this + //flag to clear the previous applied spatial acceleration in the unbuffered state so that this spatial acceleration can be cleared correctly in fetchCollision(). + flags |= raisedFlags; + mBodyBufferFlags = flags; + scheduleForUpdate(); + } + + PX_FORCE_INLINE void setBufferedParamsForAsleep() // use this in the non-buffered case to set the buffered properties + { + mBufferedIsSleeping = 1; + mBufferedWakeCounter = 0.0f; + mBufferedLinVelocity = PxVec3(0.0f); + mBufferedAngVelocity = PxVec3(0.0f); + // no need to clear forces since that will be the job of the corresponding core/sim methods + } + + PX_FORCE_INLINE void setBufferedParamsForAwake(PxReal wakeCounter) // use this in the non-buffered case to set the buffered properties + { + mBufferedIsSleeping = 0; + mBufferedWakeCounter = wakeCounter; + } + + //--------------------------------------------------------------------------------- + // Infrastructure for regular attributes + //--------------------------------------------------------------------------------- + + struct Access: public BufferedAccess<Buf, Core, Body, Body> {}; + + template<PxU32 f> PX_FORCE_INLINE typename Buf::Fns<f,0>::Arg read() const { return Access::read<Buf::Fns<f,0> >(*this, mBodyCore); } + template<PxU32 f> PX_FORCE_INLINE void write(typename Buf::Fns<f,0>::Arg v) { Access::write<Buf::Fns<f,0> >(*this, mBodyCore, v); } + template<PxU32 f> PX_FORCE_INLINE void flush(const Buf& buf) { Access::flush<Buf::Fns<f,0> >(*this, mBodyCore, buf); } + +}; + + +PX_INLINE Body::Body(PxActorType::Enum type, const PxTransform& bodyPose) : mBodyCore(type, bodyPose) +{ + setScbType(ScbType::BODY); + + mBufferedBody2World = mBodyCore.getBody2World(); + mBufferedLinVelocity = mBodyCore.getLinearVelocity(); + mBufferedAngVelocity = mBodyCore.getAngularVelocity(); + mBufferedWakeCounter = mBodyCore.getWakeCounter(); + mBufferedIsSleeping = 1; // this is the specified value for free standing objects + mBodyBufferFlags = 0; +} + +PX_INLINE void Body::setBody2World(const PxTransform& p, bool asPartOfBody2ActorChange) +{ + mBufferedBody2World = p; + + if (!isBuffering()) + { + mBodyCore.setBody2World(p); + UPDATE_PVD_PROPERTIES_OBJECT() + } + else + { + if (!asPartOfBody2ActorChange) + { + // call was triggered by a setGlobalPose(). This means the simulated body pose will get + // overwritten by the user value, so we do not need to adjust it. + + mBodyBufferFlags &= ~Buf::BF_Body2World_CoM; + } + else if (!(mBodyBufferFlags & Buf::BF_Body2World)) + { + // there has been no setGlobalPose() on the body yet and the center of mass changes. + // This case needs special treatment because the simulation results for such a body will be based on + // the old center of mass but need to get translated to the new center of mass. + + mBodyBufferFlags |= Buf::BF_Body2World_CoM; + } + + markUpdated(Buf::BF_Body2World); + } +} + +PX_INLINE void Body::setLinearVelocity(const PxVec3& v) +{ + mBufferedLinVelocity = v; + + if (!isBuffering()) + { + mBodyCore.setLinearVelocity(v); + UPDATE_PVD_PROPERTIES_OBJECT() + } + else + markUpdated(Buf::BF_LinearVelocity); +} + +PX_INLINE void Body::setAngularVelocity(const PxVec3& v) +{ + mBufferedAngVelocity = v; + + if (!isBuffering()) + { + mBodyCore.setAngularVelocity(v); + UPDATE_PVD_PROPERTIES_OBJECT() + } + else + markUpdated(Buf::BF_AngularVelocity); +} + + +PX_INLINE void Body::wakeUpInternal(PxReal wakeCounter) +{ + PX_ASSERT(getScbScene()); + + if (!isBuffering()) + { + setBufferedParamsForAwake(wakeCounter); + mBodyCore.wakeUp(wakeCounter); + } + else + { + mBufferedIsSleeping = 0; + mBufferedWakeCounter = wakeCounter; + markUpdated(Buf::BF_WakeUp | Buf::BF_WakeCounter); + mBodyBufferFlags &= ~Buf::BF_PutToSleep; + } +} + +PX_FORCE_INLINE void Body::wakeUp() +{ + PX_ASSERT(!(getFlags() & PxRigidBodyFlag::eKINEMATIC)); + Scene* scene = getScbScene(); + PX_ASSERT(scene); // only allowed for an object in a scene + + wakeUpInternal(scene->getWakeCounterResetValue()); +} + + +PX_INLINE void Body::putToSleepInternal() +{ + if (!isBuffering()) + { + setBufferedParamsForAsleep(); + mBodyCore.putToSleep(); + } + else + { + mBufferedIsSleeping = 1; + mBufferedWakeCounter = 0.0f; + // it is necessary to set the velocities as a buffered operation (not just adjust the buffered velocities) because + // a putToSleep can be followed by a wakeUp in which case only the wakeUp will get processed on sync, however, the velocities + // still need to get set to 0. + setLinearVelocity(PxVec3(0.0f)); + setAngularVelocity(PxVec3(0.0f)); + mBodyBufferFlags &= ~(Buf::BF_Acceleration | Buf::BF_DeltaVelocity | Buf::BF_KinematicTarget); + + markUpdated(Buf::BF_PutToSleep | Buf::BF_WakeCounter); + mBodyBufferFlags &= ~Buf::BF_WakeUp; + } +} + + +PX_FORCE_INLINE void Body::putToSleep() +{ + PX_ASSERT(!(getFlags() & PxRigidBodyFlag::eKINEMATIC)); + + putToSleepInternal(); +} + + +PX_INLINE void Body::setWakeCounter(PxReal w) +{ + PX_ASSERT(!(getFlags() & PxRigidBodyFlag::eKINEMATIC)); + + mBufferedWakeCounter = w; + + if (!isBuffering()) + { + if (getScbScene() && (w > 0.0f)) + mBufferedIsSleeping = 0; + + mBodyCore.setWakeCounter(w); + + UPDATE_PVD_PROPERTIES_OBJECT() + } + else + { + if (w > 0.0f) + wakeUpInternal(w); + else + markUpdated(Buf::BF_WakeCounter); + } +} + + +PX_INLINE void Body::setFlags(PxRigidBodyFlags f) +{ + PxU32 wasKinematic = getFlags() & PxRigidBodyFlag::eKINEMATIC; + PxU32 isKinematic = f & PxRigidBodyFlag::eKINEMATIC; + bool switchToKinematic = ((!wasKinematic) && isKinematic); + bool switchToDynamic = (wasKinematic && (!isKinematic)); + + if (!isBuffering()) + { + if (switchToKinematic) + setBufferedParamsForAsleep(); + + mBodyCore.setFlags(getScbScene() ? getScbScene()->getScScene().getSimStateDataPool() : NULL, f); + UPDATE_PVD_PROPERTIES_OBJECT() + } + else + { + if (switchToKinematic) + putToSleepInternal(); + else if (switchToDynamic) + mBodyBufferFlags &= ~Buf::BF_KinematicTarget; + + getBodyBuffer()->mRigidBodyFlags = f; + markUpdated(Buf::BF_RigidBodyFlags); + } +} + + +PX_INLINE void Body::addSpatialAcceleration(const PxVec3* linAcc, const PxVec3* angAcc) +{ + if (!isBuffering()) + { + mBodyCore.addSpatialAcceleration(getScbScene()->getScScene().getSimStateDataPool(), linAcc, angAcc); + //Spatial acceleration isn't sent to PVD. + } + else + { + Buf* b = getBodyBuffer(); + accumulate(b->mLinAcceleration, b->mAngAcceleration, Buf::BF_AccelerationLinear, Buf::BF_AccelerationAngular, linAcc, angAcc); + } +} + + +PX_INLINE void Body::clearSpatialAcceleration(bool force, bool torque) +{ + if (!isBuffering()) + { + mBodyCore.clearSpatialAcceleration(force, torque); + //Spatial acceleration isn't sent to PVD. + } + else + { + Buf* b = getBodyBuffer(); + resetAccumulator(b->mLinAcceleration, b->mAngAcceleration, Buf::BF_AccelerationLinear, Buf::BF_AccelerationAngular, Buf::BF_ClearAccelerationLinear, Buf::BF_ClearAccelerationAngular, force, torque); + } +} + + +PX_INLINE void Body::addSpatialVelocity(const PxVec3* linVelDelta, const PxVec3* angVelDelta) +{ + if (!isBuffering()) + { + mBodyCore.addSpatialVelocity(getScbScene()->getScScene().getSimStateDataPool(), linVelDelta, angVelDelta); + UPDATE_PVD_PROPERTIES_OBJECT() + } + else + { + Buf* b = getBodyBuffer(); + accumulate(b->mLinDeltaVelocity, b->mAngDeltaVelocity, Buf::BF_DeltaVelocityLinear, Buf::BF_DeltaVelocityAngular, linVelDelta, angVelDelta); + } +} + + +PX_INLINE void Body::clearSpatialVelocity(bool force, bool torque) +{ + if (!isBuffering()) + { + mBodyCore.clearSpatialVelocity(force, torque); + UPDATE_PVD_PROPERTIES_OBJECT() + } + else + { + Buf* b = getBodyBuffer(); + resetAccumulator(b->mLinDeltaVelocity, b->mAngDeltaVelocity, Buf::BF_DeltaVelocityLinear, Buf::BF_DeltaVelocityAngular, Buf::BF_ClearDeltaVelocityLinear, Buf::BF_ClearDeltaVelocityAngular, force, torque); + } +} + + +PX_INLINE bool Body::getKinematicTarget(PxTransform& p) const +{ + if (isBuffered(Buf::BF_KinematicTarget)) + { + p = getBodyBuffer()->mKinematicTarget; + return true; + } + else if (getControlState() != ControlState::eREMOVE_PENDING) + return mBodyCore.getKinematicTarget(p); + else + return false; +} + + +PX_INLINE void Body::setKinematicTarget(const PxTransform& p) +{ + Scene* scene = getScbScene(); + PX_ASSERT(scene); // only allowed for an object in a scene + PxReal wakeCounterResetValue = scene->getWakeCounterResetValue(); + + if (!isBuffering()) + { + mBodyCore.setKinematicTarget(scene->getScScene().getSimStateDataPool(), p, wakeCounterResetValue); + setBufferedParamsForAwake(wakeCounterResetValue); + + UPDATE_PVD_PROPERTIES_OBJECT() + } + else + { + PX_ASSERT((mBodyBufferFlags & (Buf::BF_DeltaVelocity|Buf::BF_Acceleration)) == 0); // switching to kinematic should do that. + getBodyBuffer()->mKinematicTarget = p; + markUpdated(Buf::BF_KinematicTarget); + + wakeUpInternal(wakeCounterResetValue); + } +#if PX_SUPPORT_PVD + if(getControlState() == ControlState::eIN_SCENE) + { + scene->getScenePvdClient().updateKinematicTarget(this, p); + } +#endif +} + + +PX_FORCE_INLINE void Body::onOriginShift(const PxVec3& shift) +{ + mBufferedBody2World.p -= shift; + mBodyCore.onOriginShift(shift); +} + + + +//-------------------------------------------------------------- +// +// Miscellaneous +// +//-------------------------------------------------------------- + +PX_FORCE_INLINE bool Body::hasKinematicTarget() const +{ + return + ( + isBuffered(BodyBuffer::BF_KinematicTarget) || mBodyCore.getHasValidKinematicTarget() + ); +} + + +PX_FORCE_INLINE void Body::clearSimStateDataForPendingInsert() +{ + Sc::BodyCore& core = getScBody(); + if (insertPending()) + { + // not-so-nice-code to cover the following cases: + // - user adds a kinematic to the scene, sets a target and removes the kinematic from scene again (all while the sim is running) + // - same as above but instead of removing the kinematic it gets switched to dynamic + // - user adds a dynamic to the scene, sets a target and removes the dynamic from scene again (all while the sim is running) + + if(core.getSimStateData(true)) + core.tearDownSimStateData(getScbScene()->getScScene().getSimStateDataPool(), true); + else if(core.getSimStateData(false)) + core.tearDownSimStateData(getScbScene()->getScScene().getSimStateDataPool(), false); + } +} + + +PX_FORCE_INLINE void Body::transitionSimStateDataForPendingInsert() +{ + Sc::BodyCore& core = getScBody(); + if (insertPending()) + { + // not-so-nice-code to cover the following case: + // - user adds a dynamic, adds force, then switches to kinematic (all while the sim is running) + + if(core.getSimStateData(false)) + { + core.setupSimStateData(getScbScene()->getScScene().getSimStateDataPool(), true); // note: this won't allocate the memory twice + } + } +} + + +PX_INLINE PxMat33 Body::getGlobalInertiaTensorInverse() const +{ + PxMat33 inverseInertiaWorldSpace; + Cm::transformInertiaTensor(getInverseInertia(), Gu::PxMat33Padded(getBody2World().q), inverseInertiaWorldSpace); + return inverseInertiaWorldSpace; +} + + +PX_FORCE_INLINE bool Body::checkSleepReadinessBesidesWakeCounter() +{ + return (getLinearVelocity().isZero() && getAngularVelocity().isZero()); + // no need to test for pending force updates yet since currently this is not supported on scene insertion +} + + +PX_FORCE_INLINE void Body::initBufferedState() +{ + PX_ASSERT(mBufferedIsSleeping); // this method is only meant to get called when an object is added to the scene + + if ((getWakeCounter() == 0.0f) && checkSleepReadinessBesidesWakeCounter()) + mBufferedIsSleeping = 1; + else + mBufferedIsSleeping = 0; +} + + +PX_FORCE_INLINE void Body::clearBufferedState() +{ + if (!(getFlags() & PxRigidBodyFlag::eKINEMATIC)) + { + mBufferedIsSleeping = 1; // the expected state when an object gets removed from the scene. + mBodyBufferFlags &= ~(Buf::BF_Acceleration | Buf::BF_DeltaVelocity); + } + else + { + // make sure the buffered properties for a kinematic that is not in a scene are set according to the specification + + // necessary to use the putToSleep method because buffered re-insertion case needs to be covered as well. Currently, re-insertion + // just clears the remove operation. This would prevent the core object parameters to get updated. Thus the operations need + // to be buffered and putToSleepInternal takes care of that. + putToSleepInternal(); + } + + RigidObject::clearBufferedState(); +} + + +PX_FORCE_INLINE void Body::clearBufferedSleepStateChange() +{ + mBodyBufferFlags &= ~(Buf::BF_WakeUp | Buf::BF_PutToSleep); +} + + +PX_FORCE_INLINE void Body::switchBodyToNoSim() +{ + Scb::Scene* scene = getScbScene(); + + switchToNoSim(true); + + if ((!scene) || (!getScbScene()->isPhysicsBuffering())) + { + setBufferedParamsForAsleep(); + getScBody().putToSleep(); + } + else + putToSleepInternal(); + + if (scene) + clearSimStateDataForPendingInsert(); +} + + +//-------------------------------------------------------------- +// +// Data synchronization +// +//-------------------------------------------------------------- + +PX_FORCE_INLINE void Body::markUpdated(PxU32 flag) +{ + scheduleForUpdate(); + mBodyBufferFlags |= flag; +} + +PX_FORCE_INLINE Ps::IntBool Body::isBuffered(PxU32 flag) const +{ + return Ps::IntBool(mBodyBufferFlags & flag); +} + +PX_INLINE void Body::syncCollisionWriteThroughState() +{ + PxU32 bufferFlags = mBodyBufferFlags; + + //---- + if ((bufferFlags & Buf::BF_LinearVelocity) == 0) + mBufferedLinVelocity = mBodyCore.getLinearVelocity(); + else + { + PX_ASSERT( (mBufferedIsSleeping && mBufferedLinVelocity.isZero()) || + (!mBufferedIsSleeping) || + (getControlState() == ControlState::eREMOVE_PENDING)); + PX_ASSERT( mBufferedLinVelocity.isZero() || + ((!mBufferedLinVelocity.isZero()) && (!mBufferedIsSleeping)) || + (getControlState() == ControlState::eREMOVE_PENDING)); + + mBodyCore.setLinearVelocity(mBufferedLinVelocity); + //clear the flag + bufferFlags &= ~Buf::BF_LinearVelocity; + } + + //---- + + if ((bufferFlags & Buf::BF_AngularVelocity) == 0) + mBufferedAngVelocity = mBodyCore.getAngularVelocity(); + else + { + PX_ASSERT( (mBufferedIsSleeping && mBufferedAngVelocity.isZero()) || + (!mBufferedIsSleeping) || + (getControlState() == ControlState::eREMOVE_PENDING)); + PX_ASSERT( mBufferedAngVelocity.isZero() || + ((!mBufferedAngVelocity.isZero()) && (!mBufferedIsSleeping)) || + (getControlState() == ControlState::eREMOVE_PENDING)); + + mBodyCore.setAngularVelocity(mBufferedAngVelocity); + //clear the flag + bufferFlags &= ~Buf::BF_AngularVelocity; + } + + //---- + + if (bufferFlags & Buf::BF_KinematicTarget) + { + //don't apply kinematic target unless the actor is kinematic already. setKinematicTarget is write-through properties for split sim but setRigidBodyFlag transition from rigid body to kinematic isn't write-through + if(mBodyCore.getFlags() & PxRigidBodyFlag::eKINEMATIC) + { + Buf& buffer = *getBodyBuffer(); + PX_ASSERT(mBufferedWakeCounter > 0.0f); // that is the expected behavior + + mBodyCore.setKinematicTarget(getScbScene()->getScScene().getSimStateDataPool(), buffer.mKinematicTarget, mBufferedWakeCounter); + //clear the flag + bufferFlags &= ~Buf::BF_KinematicTarget; + } + } + + //---- + //in case user call addForce(), collide(), clearForce(), which we need to clear the acclearation in the low-level + if(bufferFlags & Buf::BF_ClearAcceleration) + { + PX_ASSERT(!(mBodyCore.getFlags() & PxRigidBodyFlag::eKINEMATIC)); + PX_ASSERT(!mBufferedIsSleeping); + mBodyCore.clearSpatialAcceleration((bufferFlags & Buf::BF_ClearAccelerationLinear)!=0, (bufferFlags & Buf::BF_ClearAccelerationAngular)!=0); + + //clear the flag, we don't clear the buffered acceleration, because the user might call addForce() again after calling clearForce() + bufferFlags &= ~Buf::BF_ClearAcceleration; + } + + //---- + + //apply addForce/clearForce, addTorque/clearTorque + if(bufferFlags & Buf::BF_Acceleration) + { + Buf& buffer = *getBodyBuffer(); + PX_ASSERT(!(mBodyCore.getFlags() & PxRigidBodyFlag::eKINEMATIC)); + PX_ASSERT(!mBufferedIsSleeping || (buffer.mLinAcceleration.isZero() && buffer.mAngAcceleration.isZero())); + mBodyCore.addSpatialAcceleration(getScbScene()->getScScene().getSimStateDataPool(), &buffer.mLinAcceleration, &buffer.mAngAcceleration); + + //clear the flag + bufferFlags &= ~Buf::BF_Acceleration; + buffer.mLinAcceleration = PxVec3(0.0f); + buffer.mAngAcceleration = PxVec3(0.0f); + } + + //---- + + if(bufferFlags & Buf::BF_ClearDeltaVelocity) + { + PX_ASSERT(!(mBodyCore.getFlags() & PxRigidBodyFlag::eKINEMATIC)); + PX_ASSERT(!mBufferedIsSleeping ); + mBodyCore.clearSpatialVelocity((bufferFlags & Buf::BF_ClearDeltaVelocityLinear)!=0, (bufferFlags & Buf::BF_ClearDeltaVelocityAngular)!=0); + + //clear the flag, we don't clear the buffered velocity, because the user might call addForce() again after calling clearForce() + bufferFlags &= ~Buf::BF_ClearDeltaVelocity; + } + + //---- + + if(bufferFlags & Buf::BF_DeltaVelocity) + { + Buf& buffer = *getBodyBuffer(); + PX_ASSERT(!(mBodyCore.getFlags() & PxRigidBodyFlag::eKINEMATIC)); + PX_ASSERT(!mBufferedIsSleeping || (buffer.mLinDeltaVelocity.isZero() && buffer.mAngDeltaVelocity.isZero())); + mBodyCore.addSpatialVelocity(getScbScene()->getScScene().getSimStateDataPool(), &buffer.mLinDeltaVelocity, &buffer.mAngDeltaVelocity); + + //clear the flag + bufferFlags &= ~Buf::BF_DeltaVelocity; + buffer.mLinDeltaVelocity = PxVec3(0.0f); + buffer.mAngDeltaVelocity = PxVec3(0.0f); + } + + //---- + + if ((bufferFlags & Buf::BF_WakeCounter) == 0) + mBufferedWakeCounter = mBodyCore.getWakeCounter(); + else if (!(bufferFlags & (Buf::BF_WakeUp | Buf::BF_PutToSleep))) // if there has been at least one buffered sleep state transition, then there is no use in adjusting the wake counter separately because it will + // get done in the sleep state update. + { + PX_ASSERT((getControlState() == ControlState::eREMOVE_PENDING) || (mBufferedWakeCounter == 0.0f)); // a wake counter change is always connected to a sleep state change, except if setWakeCounter(0.0f) was called or an object gets removed from the scene after it was woken up. + + mBodyCore.setWakeCounter(mBufferedWakeCounter); + + bufferFlags &= ~Buf::BF_WakeCounter; + } + else if(bufferFlags & Buf::BF_WakeUp) + { + Buf& buffer = *getBodyBuffer(); + //Because in the split sim, transition from rigid body to kinematic isn't a write through properties. However, when the user call setKinematicTarget, the SDK wake up the actor so we want to avoid waking up the + //actor if the actor is transitioning from rigid body to kinematic or vice versa. + PxRigidBodyFlags changeFlags= mBodyCore.getFlags() ^ buffer.mRigidBodyFlags; + if(!((bufferFlags & Buf::BF_RigidBodyFlags) && (changeFlags & PxRigidBodyFlag::eKINEMATIC))) + { + PX_ASSERT(bufferFlags & Buf::BF_WakeCounter); // sleep state transitions always mark the wake counter dirty + PX_ASSERT(getControlState() != ControlState::eREMOVE_PENDING); // removing an object should clear pending wakeUp/putToSleep operations since the state for a free standing object gets set according to specification. + + // The sleep state ends up with the proper result that reflects the order of the original buffered operations because... + // - every operation that affects the sleep state makes a buffered call to wakeUp/putToSleep, hence, the buffered sleep transition + // will always reflect the latest change + // - a user triggered sleep state transition (wakeUp/putToSleep) always adjusts the affected properties (velocity, force, wake counter...) through separate + // buffered calls, hence, those properties will get adjusted to the correct values in the end + // - sleep state sync runs after all calls that have side effects on the sleep state. + // + PX_ASSERT(!mBufferedIsSleeping); + PX_ASSERT(bufferFlags & Buf::BF_WakeUp); + + // can not assert for any values here since it is possible, for example, to end up waking something up with a 0 wakeCounter here (as a consequence of a buffered wakeUp() followed by a setWakeCounter(0)) + + mBodyCore.wakeUp(mBufferedWakeCounter); + + bufferFlags &= ~(Buf::BF_WakeUp | Buf::BF_WakeCounter); + } + } + + //---- + + mBodyBufferFlags = bufferFlags; +} + +PX_INLINE void Body::syncState() +{ + // if the body was removed from the scene, we expect... + // ...it to be marked as sleeping (that is the specification) + // ...no pending sleep state change (because wakeUp/putTosleep is illegal for a free standing object and we clear such operations if pending). + // Note: a sleep state change might have happened before the removal but the corresponding wake counter change is then covered through the BF_WakeCounter dirty flag. + PX_ASSERT( (getControlState() != ControlState::eREMOVE_PENDING) || + (mBufferedIsSleeping && (!isBuffered(Buf::BF_WakeUp | Buf::BF_PutToSleep))) ); + + + // + // IMPORTANT: Since we ran out of space for buffered property flags, the Scb::Body property related flags are stored in mBodyBufferFlags. + // To get the buffer flags from the base classes, use getBufferFlags() + // + const PxU32 bufferFlags = mBodyBufferFlags; + const PxU32 baseBufferFlags = getBufferFlags(); + + if ((bufferFlags & Buf::BF_Body2World) == 0) + mBufferedBody2World = mBodyCore.getBody2World(); + else if ((bufferFlags & Buf::BF_Body2World_CoM) == 0) + mBodyCore.setBody2World(mBufferedBody2World); + else + { + // IMPORTANT: Do this before adjusting body2Actor + PX_ASSERT(bufferFlags & Buf::BF_Body2Actor); + Buf& buffer = *getBodyBuffer(); + const PxTransform newBody2oldBody = mBodyCore.getBody2Actor().transformInv(buffer.mBody2Actor); + + PxTransform b2w = mBodyCore.getBody2World(); + b2w = b2w.transform(newBody2oldBody); // translate simulation result from old CoM to new CoM + + mBufferedBody2World = b2w; + mBodyCore.setBody2World(b2w); + } + + //---- + + if (baseBufferFlags & Buf::BF_ActorFlags) + syncNoSimSwitch(*getBodyBuffer(), mBodyCore, true); + + //---- + + if(bufferFlags & ~( Buf::BF_WakeCounter|Buf::BF_Body2World|Buf::BF_LinearVelocity|Buf::BF_AngularVelocity + |Buf::BF_WakeUp|Buf::BF_PutToSleep)) // Optimization to avoid all the if-statements below if possible + { + Buf& buffer = *getBodyBuffer(); + + flush<Buf::BF_InverseMass>(buffer); + flush<Buf::BF_InverseInertia>(buffer); + flush<Buf::BF_LinearDamping>(buffer); + flush<Buf::BF_AngularDamping>(buffer); + flush<Buf::BF_MaxAngVelSq>(buffer); + flush<Buf::BF_SleepThreshold>(buffer); + flush<Buf::BF_SolverIterationCounts>(buffer); + flush<Buf::BF_ContactReportThreshold>(buffer); + flush<Buf::BF_Body2Actor>(buffer); + flush<Buf::BF_FreezeThreshold>(buffer); + flush<Buf::BF_MaxPenetrationBias>(buffer); + flush<Buf::BF_MaxContactImpulse>(buffer); + if (bufferFlags & Buf::BF_RigidBodyFlags) + { + mBodyCore.setFlags(getScbScene()->getScScene().getSimStateDataPool(), buffer.mRigidBodyFlags); + } + } + + + //This method sync all the write through properties in collision and is called in fetchCollision() + syncCollisionWriteThroughState(); + + //---- + + bool isSimObjectSleeping = mBodyCore.isSleeping(); + if ((bufferFlags & (Buf::BF_PutToSleep)) == 0) + { + if (getControlState() != ControlState::eREMOVE_PENDING) // we do not want to sync the simulation sleep state if the object was removed (free standing objects have buffered state sleeping) + mBufferedIsSleeping = PxU32(isSimObjectSleeping); + else + PX_ASSERT(mBufferedIsSleeping); // this must get set immediately at remove + } + else + { + PX_ASSERT(bufferFlags & Buf::BF_WakeCounter); // sleep state transitions always mark the wake counter dirty + PX_ASSERT(getControlState() != ControlState::eREMOVE_PENDING); // removing an object should clear pending wakeUp/putToSleep operations since the state for a free standing object gets set according to specification. + + // The sleep state ends up with the proper result that reflects the order of the original buffered operations because... + // - every operation that affects the sleep state makes a buffered call to wakeUp/putToSleep, hence, the buffered sleep transition + // will always reflect the latest change + // - a user triggered sleep state transition (wakeUp/putToSleep) always adjusts the affected properties (velocity, force, wake counter...) through separate + // buffered calls, hence, those properties will get adjusted to the correct values in the end + // - sleep state sync runs after all calls that have side effects on the sleep state. + // + + PX_ASSERT(mBufferedIsSleeping); + PX_ASSERT(!(bufferFlags & Buf::BF_WakeUp)); + PX_ASSERT(mBufferedWakeCounter == 0.0f); + PX_ASSERT(mBufferedLinVelocity.isZero()); + PX_ASSERT(mBufferedAngVelocity.isZero()); + PX_ASSERT(!(bufferFlags & Buf::BF_Acceleration)); + PX_ASSERT(!(bufferFlags & Buf::BF_DeltaVelocity)); + + mBodyCore.putToSleep(); + } + + // PT: we must call this even when there's no buffered data + RigidObject::syncState(); + + // -------------- + // postconditions + // + PX_ASSERT((getControlState() != ControlState::eREMOVE_PENDING) || mBufferedIsSleeping); // nothing in this method should change this +#ifdef _DEBUG + // make sure that for a removed kinematic, the buffered params hold the values as defined in our specification + if ((mBodyCore.getFlags() & PxRigidBodyFlag::eKINEMATIC) && (getControlState() == ControlState::eREMOVE_PENDING)) + { + PX_ASSERT(mBufferedLinVelocity.isZero()); + PX_ASSERT(mBufferedAngVelocity.isZero()); + PX_ASSERT(mBufferedWakeCounter == 0.0f); + } +#endif + // + // postconditions + // -------------- + + postSyncState(); + mBodyBufferFlags = 0; +} + +} // namespace Scb + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/buffering/ScbCloth.cpp b/PhysX_3.4/Source/PhysX/src/buffering/ScbCloth.cpp new file mode 100644 index 00000000..ecee8baa --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/buffering/ScbCloth.cpp @@ -0,0 +1,60 @@ +// 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 "PxPhysXConfig.h" + +#if PX_USE_CLOTH_API + +#include "ScbCloth.h" + +using namespace physx; + +Scb::Cloth::Cloth(const PxTransform& globalPose, Sc::ClothFabricCore& fabric, const PxClothParticle* particles, PxClothFlags flags) : + mCloth(globalPose, fabric, particles, flags) +{ + setScbType(ScbType::CLOTH); +} + + +Scb::Cloth::~Cloth() +{ +} + + +void Scb::Cloth::syncState() +{ + if (getBufferFlags()) // Optimization to avoid all the if-statements below if possible + { + Actor::syncState(); + } + + postSyncState(); +} + +#endif // PX_USE_CLOTH_API diff --git a/PhysX_3.4/Source/PhysX/src/buffering/ScbCloth.h b/PhysX_3.4/Source/PhysX/src/buffering/ScbCloth.h new file mode 100644 index 00000000..238df91f --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/buffering/ScbCloth.h @@ -0,0 +1,1195 @@ +// 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_SCB_CLOTH +#define PX_PHYSICS_SCB_CLOTH + +#include "PxPhysXConfig.h" + +#if PX_USE_CLOTH_API + +#include "ScbActor.h" + +#include "ScClothCore.h" +#include "NpClothParticleData.h" + +namespace physx +{ + +struct PxClothCollisionSphere; + +namespace Scb +{ + +class Cloth : public Scb::Actor +{ +//= 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 + Cloth(const PxEMPTY) : Scb::Actor(PxEmpty), mCloth(PxEmpty) {} + void exportExtraData(PxSerializationContext& stream) { mCloth.exportExtraData(stream); } + void importExtraData(PxDeserializationContext &context) { mCloth.importExtraData(context); } + void resolveReferences(Sc::ClothFabricCore& fabric) { mCloth.resolveReferences(fabric); } + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + Cloth(const PxTransform& globalPose, Sc::ClothFabricCore& fabric, const PxClothParticle* particles, PxClothFlags flags); + ~Cloth(); + + //--------------------------------------------------------------------------------- + // Wrapper for Sc::ClothCore interface + //--------------------------------------------------------------------------------- + + PX_INLINE Sc::ClothFabricCore* getFabric() const; + PX_INLINE void resetFabric(); + + PX_INLINE void setParticles(const PxClothParticle* currentParticles, const PxClothParticle* previousParticles); + PX_INLINE PxU32 getNbParticles() const; + + PX_INLINE void setMotionConstraints(const PxClothParticleMotionConstraint* motionConstraints); + PX_INLINE bool getMotionConstraints(PxClothParticleMotionConstraint* motionConstraintsBuffer) const; + PX_INLINE PxU32 getNbMotionConstraints() const; + + PX_INLINE PxClothMotionConstraintConfig getMotionConstraintConfig() const; + PX_INLINE void setMotionConstraintConfig(const PxClothMotionConstraintConfig& config); + + PX_INLINE void setSeparationConstraints(const PxClothParticleSeparationConstraint* separationConstraints); + PX_INLINE bool getSeparationConstraints(PxClothParticleSeparationConstraint* separationConstraintsBuffer) const; + PX_INLINE PxU32 getNbSeparationConstraints() const; + + PX_INLINE void clearInterpolation(); + + PX_INLINE void setParticleAccelerations(const PxVec4* particleAccelerations); + PX_INLINE bool getParticleAccelerations(PxVec4* particleAccelerationsBuffer) const; + PX_INLINE PxU32 getNbParticleAccelerations() const; + + PX_INLINE void addCollisionSphere(const PxClothCollisionSphere& sphere); + PX_INLINE void removeCollisionSphere(PxU32 index); + PX_INLINE void setCollisionSpheres(const PxClothCollisionSphere* spheresBuffer, PxU32 count); + PX_INLINE PxU32 getNbCollisionSpheres() const; + + PX_INLINE void getCollisionData(PxClothCollisionSphere* spheresBuffer, PxU32* capsulesBuffer, + PxClothCollisionPlane* planesBuffer, PxU32* convexesBuffer, PxClothCollisionTriangle* trianglesBuffer) const; + + PX_INLINE void addCollisionCapsule(PxU32 first, PxU32 second); + PX_INLINE void removeCollisionCapsule(PxU32 index); + PX_INLINE PxU32 getNbCollisionCapsules() const; + + PX_INLINE void addCollisionTriangle(const PxClothCollisionTriangle& triangle); + PX_INLINE void removeCollisionTriangle(PxU32 index); + PX_INLINE void setCollisionTriangles(const PxClothCollisionTriangle* trianglesBuffer, PxU32 count); + PX_INLINE PxU32 getNbCollisionTriangles() const; + + PX_INLINE void addCollisionPlane(const PxClothCollisionPlane& plane); + PX_INLINE void removeCollisionPlane(PxU32 index); + PX_INLINE void setCollisionPlanes(const PxClothCollisionPlane* planesBuffer, PxU32 count); + PX_INLINE PxU32 getNbCollisionPlanes() const; + + PX_INLINE void addCollisionConvex(PxU32 mask); + PX_INLINE void removeCollisionConvex(PxU32 index); + PX_INLINE PxU32 getNbCollisionConvexes() const; + + PX_INLINE void setVirtualParticles(PxU32 numParticles, const PxU32* indices, PxU32 numWeights, const PxVec3* weights); + + PX_INLINE PxU32 getNbVirtualParticles() const; + PX_INLINE void getVirtualParticles(PxU32* indicesBuffer) const; + + PX_INLINE PxU32 getNbVirtualParticleWeights() const; + PX_INLINE void getVirtualParticleWeights(PxVec3* weightsBuffer) const; + + PX_INLINE PxTransform getGlobalPose() const; + PX_INLINE void setGlobalPose(const PxTransform& pose); + + PX_INLINE void setTargetPose(const PxTransform& pose); + + PX_INLINE PxVec3 getExternalAcceleration() const; + PX_INLINE void setExternalAcceleration(PxVec3 acceleration); + + PX_INLINE PxVec3 getLinearInertiaScale() const; + PX_INLINE void setLinearInertiaScale(PxVec3 scale); + PX_INLINE PxVec3 getAngularInertiaScale() const; + PX_INLINE void setAngularInertiaScale(PxVec3 scale); + PX_INLINE PxVec3 getCentrifugalInertiaScale() const; + PX_INLINE void setCentrifugalInertiaScale(PxVec3 scale); + + PX_INLINE PxVec3 getDampingCoefficient() const; + PX_INLINE void setDampingCoefficient(PxVec3 dampingCoefficient); + + PX_INLINE PxReal getFrictionCoefficient() const; + PX_INLINE void setFrictionCoefficient(PxReal frictionCoefficient); + + PX_INLINE PxVec3 getLinearDragCoefficient() const; + PX_INLINE void setLinearDragCoefficient(PxVec3 dragCoefficient); + PX_INLINE PxVec3 getAngularDragCoefficient() const; + PX_INLINE void setAngularDragCoefficient(PxVec3 dragCoefficient); + + PX_INLINE PxReal getCollisionMassScale() const; + PX_INLINE void setCollisionMassScale(PxReal scalingCoefficient); + + PX_INLINE void setSelfCollisionDistance(PxReal distance); + PX_INLINE PxReal getSelfCollisionDistance() const; + PX_INLINE void setSelfCollisionStiffness(PxReal stiffness); + PX_INLINE PxReal getSelfCollisionStiffness() const; + + PX_INLINE void setSelfCollisionIndices(const PxU32* indices, PxU32 nbIndices); + PX_INLINE bool getSelfCollisionIndices(PxU32* indices) const; + PX_INLINE PxU32 getNbSelfCollisionIndices() const; + + PX_INLINE void setRestPositions(const PxVec4* restPositions); + PX_INLINE bool getRestPositions(PxVec4* restPositions) const; + PX_INLINE PxU32 getNbRestPositions() const; + + PX_INLINE PxReal getSolverFrequency() const; + PX_INLINE void setSolverFrequency(PxReal); + + PX_INLINE PxReal getStiffnessFrequency() const; + PX_INLINE void setStiffnessFrequency(PxReal); + + PX_INLINE void setStretchConfig(PxClothFabricPhaseType::Enum type, const PxClothStretchConfig& config); + PX_INLINE void setTetherConfig(const PxClothTetherConfig& config); + + PX_INLINE PxClothStretchConfig getStretchConfig(PxClothFabricPhaseType::Enum type) const; + PX_INLINE PxClothTetherConfig getTetherConfig() const; + + PX_INLINE PxClothFlags getClothFlags() const; + PX_INLINE void setClothFlags(PxClothFlags flags); + + PX_INLINE PxVec3 getWindVelocity() const; + PX_INLINE void setWindVelocity(PxVec3); + PX_INLINE PxReal getDragCoefficient() const; + PX_INLINE void setDragCoefficient(PxReal); + PX_INLINE PxReal getLiftCoefficient() const; + PX_INLINE void setLiftCoefficient(PxReal); + + PX_INLINE bool isSleeping() const; + PX_INLINE PxReal getSleepLinearVelocity() const; + PX_INLINE void setSleepLinearVelocity(PxReal threshold); + PX_INLINE void setWakeCounter(PxReal wakeCounterValue); + PX_INLINE PxReal getWakeCounter() const; + PX_INLINE void wakeUp(); + PX_INLINE void putToSleep(); + + PX_INLINE void getParticleData(NpClothParticleData&); + + PX_INLINE PxReal getPreviousTimeStep() const; + + PX_INLINE PxBounds3 getWorldBounds() const; + + PX_INLINE void setSimulationFilterData(const PxFilterData& data); + PX_INLINE PxFilterData getSimulationFilterData() const; + + PX_INLINE void setContactOffset(PxReal); + PX_INLINE PxReal getContactOffset() const; + PX_INLINE void setRestOffset(PxReal); + PX_INLINE PxReal getRestOffset() const; + + + //--------------------------------------------------------------------------------- + // Data synchronization + //--------------------------------------------------------------------------------- + + // Synchronously called with fetchResults. + void syncState(); + + //--------------------------------------------------------------------------------- + // Miscellaneous + //--------------------------------------------------------------------------------- + PX_FORCE_INLINE const Sc::ClothCore& getScCloth() const { return mCloth; } // Only use if you know what you're doing! + PX_FORCE_INLINE Sc::ClothCore& getScCloth() { return mCloth; } // Only use if you know what you're doing! + + static size_t getScOffset() + { + return reinterpret_cast<size_t>(&reinterpret_cast<Cloth*>(0)->mCloth); + } + +private: + Sc::ClothCore mCloth; +}; + + +PX_INLINE Sc::ClothFabricCore* Cloth::getFabric() const +{ + return mCloth.getFabric(); +} + +PX_INLINE void Cloth::resetFabric() +{ + return mCloth.resetFabric(); +} + +PX_INLINE void Cloth::setParticles(const PxClothParticle* currentParticles, const PxClothParticle* previousParticles) +{ + if (!isBuffering()) + mCloth.setParticles(currentParticles, previousParticles); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setParticles() not allowed while simulation is running."); +} + +PX_INLINE PxU32 Cloth::getNbParticles() const +{ + return mCloth.getNbParticles(); +} + +PX_INLINE void Cloth::setMotionConstraints(const PxClothParticleMotionConstraint* motionConstraints) +{ + if (!isBuffering()) + mCloth.setMotionConstraints(motionConstraints); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setMotionConstraints() not allowed while simulation is running."); +} + + +PX_INLINE bool Cloth::getMotionConstraints(PxClothParticleMotionConstraint* motionConstraintsBuffer) const +{ + if (!isBuffering()) + return mCloth.getMotionConstraints(motionConstraintsBuffer); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getMotionConstraints() not allowed while simulation is running."); + return false; + } +} + +PX_INLINE PxU32 Cloth::getNbMotionConstraints() const +{ + return mCloth.getNbMotionConstraints(); +} + +PX_INLINE PxClothMotionConstraintConfig Cloth::getMotionConstraintConfig() const +{ + if (!isBuffering()) + return mCloth.getMotionConstraintConfig(); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getMotionConstraintScaleBias() not allowed while simulation is running."); + + return PxClothMotionConstraintConfig(); +} + + +PX_INLINE void Cloth::setMotionConstraintConfig(const PxClothMotionConstraintConfig& config) +{ + if (!isBuffering()) + mCloth.setMotionConstraintConfig(config); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setMotionConstraintConfig() not allowed while simulation is running."); +} + +PX_INLINE void Cloth::setSeparationConstraints(const PxClothParticleSeparationConstraint* separationConstraints) +{ + if (!isBuffering()) + mCloth.setSeparationConstraints(separationConstraints); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setSeparationConstraints() not allowed while simulation is running."); +} + + +PX_INLINE bool Cloth::getSeparationConstraints(PxClothParticleSeparationConstraint* separationConstraintsBuffer) const +{ + if (!isBuffering()) + return mCloth.getSeparationConstraints(separationConstraintsBuffer); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getSeparationConstraints() not allowed while simulation is running."); + return false; + } +} + +PX_INLINE PxU32 Cloth::getNbSeparationConstraints() const +{ + return mCloth.getNbSeparationConstraints(); +} + +PX_INLINE void Cloth::clearInterpolation() +{ + return mCloth.clearInterpolation(); +} + +PX_INLINE void Cloth::setParticleAccelerations(const PxVec4* particleAccelerations) +{ + if (!isBuffering()) + mCloth.setParticleAccelerations(particleAccelerations); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setParticleAccelerations() not allowed while simulation is running."); +} + + +PX_INLINE bool Cloth::getParticleAccelerations(PxVec4* particleAccelerationsBuffer) const +{ + if (!isBuffering()) + return mCloth.getParticleAccelerations(particleAccelerationsBuffer); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getParticleAccelerations() not allowed while simulation is running."); + return false; + } +} + +PX_INLINE PxU32 Cloth::getNbParticleAccelerations() const +{ + return mCloth.getNbParticleAccelerations(); +} + +PX_INLINE void Cloth::addCollisionSphere(const PxClothCollisionSphere& sphere) +{ + if (!isBuffering()) + mCloth.addCollisionSphere(sphere); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::addCollisionSphere() not allowed while simulation is running."); +} +PX_INLINE void Cloth::removeCollisionSphere(PxU32 index) +{ + if (!isBuffering()) + mCloth.removeCollisionSphere(index); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::removeCollisionSphere() not allowed while simulation is running."); +} +PX_INLINE void Cloth::setCollisionSpheres(const PxClothCollisionSphere* spheresBuffer, PxU32 count) +{ + if (!isBuffering()) + mCloth.setCollisionSpheres(spheresBuffer, count); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setCollisionSpheres() not allowed while simulation is running."); +} +PX_INLINE PxU32 Cloth::getNbCollisionSpheres() const +{ + if (!isBuffering()) + return mCloth.getNbCollisionSpheres(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getNbCollisionSpheres() not allowed while simulation is running."); + return 0; + } +} + +PX_INLINE void Cloth::getCollisionData( PxClothCollisionSphere* spheresBuffer, PxU32* capsulesBuffer, + PxClothCollisionPlane* planesBuffer, PxU32* convexesBuffer, PxClothCollisionTriangle* trianglesBuffer ) const +{ + if (!isBuffering()) + mCloth.getCollisionData(spheresBuffer, capsulesBuffer, planesBuffer, convexesBuffer, trianglesBuffer); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getCollisionData() not allowed while simulation is running."); +} + + +PX_INLINE void Cloth::addCollisionCapsule(PxU32 first, PxU32 second) +{ + if (!isBuffering()) + mCloth.addCollisionCapsule(first, second); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::addCollisionCapsule() not allowed while simulation is running."); +} +PX_INLINE void Cloth::removeCollisionCapsule(PxU32 index) +{ + if (!isBuffering()) + mCloth.removeCollisionCapsule(index); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::removeCollisionCapsule() not allowed while simulation is running."); +} +PX_INLINE PxU32 Cloth::getNbCollisionCapsules() const +{ + if (!isBuffering()) + return mCloth.getNbCollisionCapsules(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getNbCollisionCapsules() not allowed while simulation is running."); + return 0; + } +} + +PX_INLINE void Cloth::addCollisionTriangle(const PxClothCollisionTriangle& triangle) +{ + if (!isBuffering()) + mCloth.addCollisionTriangle(triangle); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::addCollisionTriangle() not allowed while simulation is running."); +} +PX_INLINE void Cloth::removeCollisionTriangle(PxU32 index) +{ + if (!isBuffering()) + mCloth.removeCollisionTriangle(index); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::removeCollisionTriangle() not allowed while simulation is running."); +} +PX_INLINE void Cloth::setCollisionTriangles(const PxClothCollisionTriangle* trianglesBuffer, PxU32 count) +{ + if (!isBuffering()) + mCloth.setCollisionTriangles(trianglesBuffer, count); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setCollisionTriangles() not allowed while simulation is running."); +} +PX_INLINE PxU32 Cloth::getNbCollisionTriangles() const +{ + if (!isBuffering()) + return mCloth.getNbCollisionTriangles(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getNbCollisionTriangles() not allowed while simulation is running."); + return 0; + } +} + +PX_INLINE void Cloth::addCollisionPlane(const PxClothCollisionPlane& plane) +{ + if (!isBuffering()) + mCloth.addCollisionPlane(plane); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::addCollisionPlane() not allowed while simulation is running."); +} +PX_INLINE void Cloth::removeCollisionPlane(PxU32 index) +{ + if (!isBuffering()) + mCloth.removeCollisionPlane(index); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::removeCollisionPlane() not allowed while simulation is running."); +} +PX_INLINE void Cloth::setCollisionPlanes(const PxClothCollisionPlane* planesBuffer, PxU32 count) +{ + if (!isBuffering()) + mCloth.setCollisionPlanes(planesBuffer, count); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setCollisionPlanes() not allowed while simulation is running."); +} +PX_INLINE PxU32 Cloth::getNbCollisionPlanes() const +{ + if (!isBuffering()) + return mCloth.getNbCollisionPlanes(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getNbCollisionPlanes() not allowed while simulation is running."); + return 0; + } +} + +PX_INLINE void Cloth::addCollisionConvex(PxU32 mask) +{ + if (!isBuffering()) + mCloth.addCollisionConvex(mask); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::addCollisionConvex() not allowed while simulation is running."); +} +PX_INLINE void Cloth::removeCollisionConvex(PxU32 index) +{ + if (!isBuffering()) + mCloth.removeCollisionConvex(index); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::removeCollisionConvex() not allowed while simulation is running."); +} +PX_INLINE PxU32 Cloth::getNbCollisionConvexes() const +{ + if (!isBuffering()) + return mCloth.getNbCollisionConvexes(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getNbCollisionConvexes() not allowed while simulation is running."); + return 0; + } +} + + +PX_INLINE void Cloth::setVirtualParticles(PxU32 numParticles, const PxU32* indices, PxU32 numWeights, const PxVec3* weights) +{ + if (!isBuffering()) + mCloth.setVirtualParticles(numParticles, indices, numWeights, weights); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setVirtualParticles() not allowed while simulation is running."); +} + + +PX_INLINE PxU32 Cloth::getNbVirtualParticles() const +{ + if (!isBuffering()) + return mCloth.getNbVirtualParticles(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getNbVirtualParticles() not allowed while simulation is running."); + return 0; + } +} + + +PX_INLINE void Cloth::getVirtualParticles(PxU32* indicesBuffer) const +{ + if (!isBuffering()) + mCloth.getVirtualParticles(indicesBuffer); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getVirtualParticles() not allowed while simulation is running."); +} + + +PX_INLINE PxU32 Cloth::getNbVirtualParticleWeights() const +{ + if (!isBuffering()) + return mCloth.getNbVirtualParticleWeights(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getNbVirtualParticleWeights() not allowed while simulation is running."); + return 0; + } +} + + +PX_INLINE void Cloth::getVirtualParticleWeights(PxVec3* weightsBuffer) const +{ + if (!isBuffering()) + mCloth.getVirtualParticleWeights(weightsBuffer); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getVirtualParticleWeights() not allowed while simulation is running."); +} + + +PX_INLINE PxTransform Cloth::getGlobalPose() const +{ + if (!isBuffering()) + return mCloth.getGlobalPose(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getGlobalPose() not allowed while simulation is running."); + return PxTransform(PxIdentity); + } +} + + +PX_INLINE void Cloth::setGlobalPose(const PxTransform& pose) +{ + if (!isBuffering()) + mCloth.setGlobalPose(pose); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setGlobalPose() not allowed while simulation is running."); +} + + +PX_INLINE void Cloth::setTargetPose(const PxTransform& pose) +{ + if (!isBuffering()) + mCloth.setTargetPose(pose); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setTargetPose() not allowed while simulation is running."); +} + + +PX_INLINE PxVec3 Cloth::getExternalAcceleration() const +{ + if (!isBuffering()) + return mCloth.getExternalAcceleration(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getExternalAcceleration() not allowed while simulation is running."); + return PxVec3(0.0f); + } +} + + +PX_INLINE void Cloth::setExternalAcceleration(PxVec3 acceleration) +{ + if (!isBuffering()) + mCloth.setExternalAcceleration(acceleration); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setExternalAcceleration() not allowed while simulation is running."); +} + +PX_INLINE PxVec3 Cloth::getLinearInertiaScale() const +{ + if (!isBuffering()) + return mCloth.getLinearInertiaScale(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getLinearInertiaScale() not allowed while simulation is running."); + return PxVec3(0.0f); + } +} + + +PX_INLINE void Cloth::setLinearInertiaScale(PxVec3 scale) +{ + if (!isBuffering()) + mCloth.setLinearInertiaScale(scale); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setLinearInertiaScale() not allowed while simulation is running."); +} + +PX_INLINE PxVec3 Cloth::getAngularInertiaScale() const +{ + if (!isBuffering()) + return mCloth.getAngularInertiaScale(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getAngularInertiaScale() not allowed while simulation is running."); + return PxVec3(0.0f); + } +} + + +PX_INLINE void Cloth::setAngularInertiaScale(PxVec3 scale) +{ + if (!isBuffering()) + mCloth.setAngularInertiaScale(scale); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setAngularInertiaScale() not allowed while simulation is running."); +} + +PX_INLINE PxVec3 Cloth::getCentrifugalInertiaScale() const +{ + if (!isBuffering()) + return mCloth.getCentrifugalInertiaScale(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getCentrifugalInertiaScale() not allowed while simulation is running."); + return PxVec3(0.0f); + } +} + + +PX_INLINE void Cloth::setCentrifugalInertiaScale(PxVec3 scale) +{ + if (!isBuffering()) + mCloth.setCentrifugalInertiaScale(scale); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setCentrifugalInertiaScale() not allowed while simulation is running."); +} + +PX_INLINE PxVec3 Cloth::getDampingCoefficient() const +{ + if (!isBuffering()) + return mCloth.getDampingCoefficient(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getDampingCoefficient() not allowed while simulation is running."); + return PxVec3(0.0f); + } +} + + +PX_INLINE void Cloth::setDampingCoefficient(PxVec3 dampingCoefficient) +{ + if (!isBuffering()) + mCloth.setDampingCoefficient(dampingCoefficient); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setDampingCoefficient() not allowed while simulation is running."); +} + +PX_INLINE PxReal Cloth::getFrictionCoefficient() const +{ + if (!isBuffering()) + return mCloth.getFrictionCoefficient(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getFrictionCoefficient() not allowed while simulation is running."); + return 0.0f; + } +} + + +PX_INLINE void Cloth::setFrictionCoefficient(PxReal frictionCoefficient) +{ + if (!isBuffering()) + mCloth.setFrictionCoefficient(frictionCoefficient); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setFrictionCoefficient() not allowed while simulation is running."); +} + +PX_INLINE PxVec3 Cloth::getLinearDragCoefficient() const +{ + if (!isBuffering()) + return mCloth.getLinearDragCoefficient(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getLinearDragCoefficient() not allowed while simulation is running."); + return PxVec3(0.0f); + } +} + + +PX_INLINE void Cloth::setLinearDragCoefficient(PxVec3 dampingCoefficient) +{ + if (!isBuffering()) + mCloth.setLinearDragCoefficient(dampingCoefficient); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setLinearDragCoefficient() not allowed while simulation is running."); +} + +PX_INLINE PxVec3 Cloth::getAngularDragCoefficient() const +{ + if (!isBuffering()) + return mCloth.getAngularDragCoefficient(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getAngularDragCoefficient() not allowed while simulation is running."); + return PxVec3(0.0f); + } +} + + +PX_INLINE void Cloth::setAngularDragCoefficient(PxVec3 dampingCoefficient) +{ + if (!isBuffering()) + mCloth.setAngularDragCoefficient(dampingCoefficient); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setAngularDragCoefficient() not allowed while simulation is running."); +} + +PX_INLINE PxReal Cloth::getCollisionMassScale() const +{ + if (!isBuffering()) + return mCloth.getCollisionMassScale(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getCollisionMassScale() not allowed while simulation is running."); + return 0.0f; + } +} +PX_INLINE void Cloth::setCollisionMassScale(PxReal scalingCoefficient) +{ + if (!isBuffering()) + mCloth.setCollisionMassScale(scalingCoefficient); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setCollisionMassScale() not allowed while simulation is running."); +} + +PX_INLINE PxReal Cloth::getSelfCollisionDistance() const +{ + if (!isBuffering()) + return mCloth.getSelfCollisionDistance(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getSelfCollisionDistance() not allowed while simulation is running."); + return 0.0f; + } +} +PX_INLINE void Cloth::setSelfCollisionDistance(PxReal distance) +{ + if (!isBuffering()) + mCloth.setSelfCollisionDistance(distance); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setSelfCollisionDistance() not allowed while simulation is running."); +} +PX_INLINE PxReal Cloth::getSelfCollisionStiffness() const +{ + if (!isBuffering()) + return mCloth.getSelfCollisionStiffness(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getSelfCollisionStiffness() not allowed while simulation is running."); + return 0.0f; + } +} +PX_INLINE void Cloth::setSelfCollisionStiffness(PxReal stiffness) +{ + if (!isBuffering()) + mCloth.setSelfCollisionStiffness(stiffness); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setSelfCollisionStiffness() not allowed while simulation is running."); +} + +PX_INLINE void Cloth::setSelfCollisionIndices(const PxU32* indices, PxU32 nbIndices) +{ + if (!isBuffering()) + mCloth.setSelfCollisionIndices(indices, nbIndices); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setSelfCollisionIndices() not allowed while simulation is running."); +} + +PX_INLINE bool Cloth::getSelfCollisionIndices(PxU32* indices) const +{ + if (!isBuffering()) + return mCloth.getSelfCollisionIndices(indices); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getSelfCollisionIndices() not allowed while simulation is running."); + return false; + } +} + +PX_INLINE PxU32 Cloth::getNbSelfCollisionIndices() const +{ + return mCloth.getNbSelfCollisionIndices(); +} + + +PX_INLINE void Cloth::setRestPositions(const PxVec4* restPositions) +{ + if (!isBuffering()) + mCloth.setRestPositions(restPositions); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setRestPositions() not allowed while simulation is running."); +} + +PX_INLINE bool Cloth::getRestPositions(PxVec4* restPositions) const +{ + if (!isBuffering()) + return mCloth.getRestPositions(restPositions); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getRestPositions() not allowed while simulation is running."); + return false; + } +} + +PX_INLINE PxU32 Cloth::getNbRestPositions() const +{ + return mCloth.getNbRestPositions(); +} + +PX_INLINE PxReal Cloth::getSolverFrequency() const +{ + if (!isBuffering()) + return mCloth.getSolverFrequency(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getSolverFrequency() not allowed while simulation is running."); + return 60.0f; + } +} + + +PX_INLINE void Cloth::setSolverFrequency(PxReal solverFreq) +{ + if (!isBuffering()) + mCloth.setSolverFrequency(solverFreq); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setSolverFrequency() not allowed while simulation is running."); +} + +PX_INLINE PxReal Cloth::getStiffnessFrequency() const +{ + if (!isBuffering()) + return mCloth.getStiffnessFrequency(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getStiffnessFrequency() not allowed while simulation is running."); + return 60.0f; + } +} + + +PX_INLINE void Cloth::setStiffnessFrequency(PxReal solverFreq) +{ + if (!isBuffering()) + mCloth.setStiffnessFrequency(solverFreq); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setStiffnessFrequency() not allowed while simulation is running."); +} + + +PX_INLINE void Cloth::setStretchConfig(PxClothFabricPhaseType::Enum type, const PxClothStretchConfig& config) +{ + if (!isBuffering()) + mCloth.setStretchConfig(type, config); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setStretchConfig() not allowed while simulation is running."); +} + +PX_INLINE void Cloth::setTetherConfig(const PxClothTetherConfig& config) +{ + if (!isBuffering()) + mCloth.setTetherConfig(config); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setTetherConfig() not allowed while simulation is running."); +} + +PX_INLINE PxClothStretchConfig Cloth::getStretchConfig(PxClothFabricPhaseType::Enum type) const +{ + if (!isBuffering()) + return mCloth.getStretchConfig(type); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getStretchConfig() not allowed while simulation is running."); + return PxClothStretchConfig(); + } +} + +PX_INLINE PxClothTetherConfig Cloth::getTetherConfig() const +{ + if (!isBuffering()) + return mCloth.getTetherConfig(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getTetherConfig() not allowed while simulation is running."); + return PxClothTetherConfig(); + } +} + +PX_INLINE PxClothFlags Cloth::getClothFlags() const +{ + if (!isBuffering()) + return mCloth.getClothFlags(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getClothFlags() not allowed while simulation is running."); + return PxClothFlags(0); + } +} + + +PX_INLINE void Cloth::setClothFlags(PxClothFlags flags) +{ + if (!isBuffering()) + mCloth.setClothFlags(flags); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setClothFlag() not allowed while simulation is running."); +} + +PX_INLINE PxVec3 Cloth::getWindVelocity() const +{ + if (!isBuffering()) + return mCloth.getWindVelocity(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getWindVelocity() not allowed while simulation is running."); + return PxVec3(0.0f); + } +} + +PX_INLINE void Cloth::setWindVelocity(PxVec3 wind) +{ + if (!isBuffering()) + mCloth.setWindVelocity(wind); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setWindVelocity() not allowed while simulation is running."); +} + +PX_INLINE PxReal Cloth::getDragCoefficient() const +{ + if (!isBuffering()) + return mCloth.getDragCoefficient(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getDragCoefficient() not allowed while simulation is running."); + return 0.0f; + } +} + +PX_INLINE void Cloth::setDragCoefficient(PxReal value) +{ + if (!isBuffering()) + mCloth.setDragCoefficient(value); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setDragCoefficient() not allowed while simulation is running."); +} + +PX_INLINE PxReal Cloth::getLiftCoefficient() const +{ + if (!isBuffering()) + return mCloth.getLiftCoefficient(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getLiftCoefficient() not allowed while simulation is running."); + return 0.0f; + } +} + +PX_INLINE void Cloth::setLiftCoefficient(PxReal value) +{ + if (!isBuffering()) + mCloth.setLiftCoefficient(value); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setLiftCoefficient() not allowed while simulation is running."); +} + + +PX_INLINE bool Cloth::isSleeping() const +{ + if (!isBuffering()) + return mCloth.isSleeping(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::isSleeping() not allowed while simulation is running."); + return false; + } +} + + +PX_INLINE PxReal Cloth::getSleepLinearVelocity() const +{ + if (!isBuffering()) + return mCloth.getSleepLinearVelocity(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getSleepLinearVelocity() not allowed while simulation is running."); + return 0.0f; + } +} + + +PX_INLINE void Cloth::setSleepLinearVelocity(PxReal threshold) +{ + if (!isBuffering()) + mCloth.setSleepLinearVelocity(threshold); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setSleepLinearVelocity() not allowed while simulation is running."); +} + + +PX_INLINE void Cloth::setWakeCounter(PxReal wakeCounterValue) +{ + if (!isBuffering()) + mCloth.setWakeCounter(wakeCounterValue); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setWakeCounter() not allowed while simulation is running."); +} + + +PX_INLINE PxReal Cloth::getWakeCounter() const +{ + if (!isBuffering()) + return mCloth.getWakeCounter(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getWakeCounter() not allowed while simulation is running."); + return 0.0f; + } +} + + +PX_INLINE void Cloth::wakeUp() +{ + Scene* scene = getScbScene(); + PX_ASSERT(scene); // only allowed for an object in a scene + + if (!isBuffering()) + mCloth.wakeUp(scene->getWakeCounterResetValue()); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::wakeUp() not allowed while simulation is running."); +} + + +PX_INLINE void Cloth::putToSleep() +{ + if (!isBuffering()) + mCloth.putToSleep(); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::putToSleep() not allowed while simulation is running."); +} + + +PX_INLINE void Cloth::getParticleData(NpClothParticleData& particleData) +{ + if (!isBuffering()) + return getScCloth().getParticleData(particleData); + + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, + "Call to PxCloth::lockParticleData() not allowed while simulation is running."); + + particleData.particles = 0; + particleData.previousParticles = 0; +} + + +PxReal Cloth::getPreviousTimeStep() const +{ + if (!isBuffering()) + return mCloth.getPreviousTimeStep(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getPreviousTimeStep() not allowed while simulation is running."); + return 0.0f; + } +} + + +PX_INLINE PxBounds3 Cloth::getWorldBounds() const +{ + if (!isBuffering()) + return mCloth.getWorldBounds(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getWorldBounds() not allowed while simulation is running."); + return PxBounds3::empty(); + } +} + +PX_INLINE void Cloth::setSimulationFilterData(const PxFilterData& data) +{ + if (!isBuffering()) + mCloth.setSimulationFilterData(data); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setSimulationFilterData() not allowed while simulation is running."); +} + +PX_INLINE PxFilterData Cloth::getSimulationFilterData() const +{ + if (!isBuffering()) + return mCloth.getSimulationFilterData(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getSimulationFilterData() not allowed while simulation is running."); + return PxFilterData(); + } +} + +PX_INLINE void Cloth::setContactOffset(PxReal offset) +{ + if (!isBuffering()) + mCloth.setContactOffset(offset); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setContactOffset() not allowed while simulation is running."); +} + +PX_INLINE PxReal Cloth::getContactOffset() const +{ + if (!isBuffering()) + return mCloth.getContactOffset(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getContactOffset() not allowed while simulation is running."); + return 0.0f; + } +} + +PX_INLINE void Cloth::setRestOffset(PxReal offset) +{ + if (!isBuffering()) + mCloth.setRestOffset(offset); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::setRestOffset() not allowed while simulation is running."); +} + +PX_INLINE PxReal Cloth::getRestOffset() const +{ + if (!isBuffering()) + return mCloth.getRestOffset(); + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Call to PxCloth::getRestOffset() not allowed while simulation is running."); + return 0.0f; + } +} + +} // namespace Scb + +} + +#endif // PX_USE_CLOTH_API + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/buffering/ScbConstraint.h b/PhysX_3.4/Source/PhysX/src/buffering/ScbConstraint.h new file mode 100644 index 00000000..d4661e2d --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/buffering/ScbConstraint.h @@ -0,0 +1,332 @@ +// 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_SCB_CONSTRAINTSHADER +#define PX_PHYSICS_SCB_CONSTRAINTSHADER + +#include "CmPhysXCommon.h" +#include "../../../SimulationController/include/ScConstraintCore.h" + +#include "ScbBody.h" + +namespace physx +{ + +namespace Sc +{ + class RigidCore; +} + +namespace Scb +{ + +struct ConstraintBuffer +{ +public: + Sc::RigidCore* rigids[2]; + PxReal linBreakForce; + PxReal angBreakForce; + PxConstraintFlags flags; + PxReal minResponseThreshold; +}; + +enum ConstraintBufferFlag +{ + BF_BODIES = (1 << 0), + BF_BREAK_IMPULSE = (1 << 1), + BF_FLAGS = (1 << 2), + BF_MIN_RESPONSE_THRESHOLD = (1 << 3), + + BF_LAST_BUFFER_BIT = BF_FLAGS +}; + +class Constraint : public Base, 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: + + typedef ConstraintBuffer Buf; + typedef Sc::ConstraintCore Core; + +// PX_SERIALIZATION + Constraint(const PxEMPTY) : Base(PxEmpty), mConstraint(PxEmpty) {} + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + PX_INLINE Constraint(PxConstraintConnector& connector, const PxConstraintShaderTable& shaders, PxU32 dataSize); + PX_INLINE ~Constraint() {} + + //--------------------------------------------------------------------------------- + // Wrapper for Sc::ConstraintCore interface + //--------------------------------------------------------------------------------- + + PX_INLINE PxConstraint* getPxConstraint() const; + PX_INLINE PxConstraintConnector* getPxConnector() const; + + PX_INLINE void setFlags(PxConstraintFlags f); + PX_INLINE PxConstraintFlags getFlags() const; + + PX_INLINE void setBodies(Scb::RigidObject* r0, Scb::RigidObject* r1); + + PX_INLINE void getForce(PxVec3& force, PxVec3& torque) const; + + PX_INLINE void setBreakForce(PxReal linear, PxReal angular); + PX_INLINE void getBreakForce(PxReal& linear, PxReal& angular) const; + + PX_INLINE void setMinResponseThreshold(PxReal threshold); + PX_INLINE PxReal getMinResponseThreshold() const; + + PX_INLINE bool updateConstants(void* addr); + + + //--------------------------------------------------------------------------------- + // Data synchronization + //--------------------------------------------------------------------------------- + PX_INLINE void prepareForActorRemoval(); + PX_INLINE void syncState(); + + + //--------------------------------------------------------------------------------- + // Miscellaneous + //--------------------------------------------------------------------------------- + PX_FORCE_INLINE const Core& getScConstraint() const { return mConstraint; } // Only use if you know what you're doing! + PX_FORCE_INLINE Core& getScConstraint() { return mConstraint; } // Only use if you know what you're doing! + + PX_FORCE_INLINE static Constraint& fromSc(Core &a) { return *reinterpret_cast<Constraint*>(reinterpret_cast<PxU8*>(&a)-getScOffset()); } + PX_FORCE_INLINE static const Constraint& fromSc(const Core &a) { return *reinterpret_cast<const Constraint*>(reinterpret_cast<const PxU8*>(&a)-getScOffset()); } + + + static size_t getScOffset() + { + return reinterpret_cast<size_t>(&reinterpret_cast<Constraint*>(0)->mConstraint); + } + +private: + Core mConstraint; + + //--------------------------------------------------------------------------------- + // Permanently buffered data (simulation written data) + //--------------------------------------------------------------------------------- + PxVec3 mBufferedForce; + PxVec3 mBufferedTorque; + PxConstraintFlags mBrokenFlag; + + PX_FORCE_INLINE const Buf* getBufferedData() const { return reinterpret_cast<const Buf*>(getStream()); } + PX_FORCE_INLINE Buf* getBufferedData() { return reinterpret_cast<Buf*>(getStream()); } +}; + +} // namespace Scb + +PX_INLINE Scb::Constraint::Constraint(PxConstraintConnector& connector, const PxConstraintShaderTable& shaders, PxU32 dataSize) : + mConstraint(connector, shaders, dataSize), + mBufferedForce(0.0f), + mBufferedTorque(0.0f), + mBrokenFlag(0) +{ + setScbType(ScbType::CONSTRAINT); +} + +PX_INLINE PxConstraintConnector* Scb::Constraint::getPxConnector() const +{ + return mConstraint.getPxConnector(); +} + +PX_INLINE void Scb::Constraint::setFlags(PxConstraintFlags f) +{ + if (!isBuffering()) + { + mConstraint.setFlags(f); + UPDATE_PVD_PROPERTIES_OBJECT() + } + else + { + getBufferedData()->flags = f; + markUpdated(BF_FLAGS); + } +} + +PX_INLINE PxConstraintFlags Scb::Constraint::getFlags() const +{ + return isBuffered(BF_FLAGS) ? getBufferedData()->flags & (~(PxConstraintFlag::eBROKEN | PxConstraintFlag::eGPU_COMPATIBLE) | mBrokenFlag) + : mConstraint.getFlags() & (~(PxConstraintFlag::eBROKEN | PxConstraintFlag::eGPU_COMPATIBLE) | mBrokenFlag); +} + + +PX_INLINE void Scb::Constraint::setBodies(Scb::RigidObject* r0, Scb::RigidObject* r1) +{ + Sc::RigidCore* scR0 = r0 ? &r0->getScRigidCore() : NULL; + Sc::RigidCore* scR1 = r1 ? &r1->getScRigidCore() : NULL; + + if (!isBuffering()) + { + mConstraint.prepareForSetBodies(); + mConstraint.setBodies(scR0, scR1); + UPDATE_PVD_PROPERTIES_OBJECT() + } + else + { + Buf* PX_RESTRICT bufferedData = getBufferedData(); + bufferedData->rigids[0] = scR0; + bufferedData->rigids[1] = scR1; + markUpdated(BF_BODIES); + } + + mBufferedForce = PxVec3(0); + mBufferedTorque = PxVec3(0); +} + + + +PX_INLINE void Scb::Constraint::getForce(PxVec3& force, PxVec3& torque) const +{ + force = mBufferedForce; + torque = mBufferedTorque; +} + + +PX_INLINE void Scb::Constraint::setBreakForce(PxReal linear, PxReal angular) +{ + if (!isBuffering()) + { + mConstraint.setBreakForce(linear, angular); + UPDATE_PVD_PROPERTIES_OBJECT() + } + else + { + Buf* PX_RESTRICT bufferedData = getBufferedData(); + bufferedData->linBreakForce = linear; + bufferedData->angBreakForce = angular; + markUpdated(BF_BREAK_IMPULSE); + } +} + + +PX_INLINE void Scb::Constraint::getBreakForce(PxReal& linear, PxReal& angular) const +{ + if (isBuffered(BF_BREAK_IMPULSE)) + { + const Buf* PX_RESTRICT bufferedData = getBufferedData(); + linear = bufferedData->linBreakForce; + angular = bufferedData->angBreakForce; + } + else + mConstraint.getBreakForce(linear, angular); +} + + +PX_INLINE void Scb::Constraint::setMinResponseThreshold(PxReal threshold) +{ + if (!isBuffering()) + { + mConstraint.setMinResponseThreshold(threshold); + UPDATE_PVD_PROPERTIES_OBJECT() + } + else + { + Buf* PX_RESTRICT bufferedData = getBufferedData(); + bufferedData->minResponseThreshold = threshold; + markUpdated(BF_MIN_RESPONSE_THRESHOLD); + } +} + + +PX_INLINE PxReal Scb::Constraint::getMinResponseThreshold() const +{ + if (isBuffered(BF_MIN_RESPONSE_THRESHOLD)) + { + const Buf* PX_RESTRICT bufferedData = getBufferedData(); + return bufferedData->minResponseThreshold; + } + else + return mConstraint.getMinResponseThreshold(); +} + + + +PX_INLINE bool Scb::Constraint::updateConstants(void* addr) +{ + PX_ASSERT(!getScbScene()->isPhysicsBuffering()); + + return mConstraint.updateConstants(addr); +} + + +//-------------------------------------------------------------- +// +// Data synchronization +// +//-------------------------------------------------------------- + +PX_INLINE void Scb::Constraint::prepareForActorRemoval() +{ + // when the bodies of a constraint have been changed during buffering, it's possible the + // attached actor is going to get deleted. Sc expects that all interactions with that actor + // will have been removed, so we give the Sc::Constraint a chance to ensure that before + // the actors go away. + if(getBufferFlags() & BF_BODIES) + mConstraint.prepareForSetBodies(); +} + +PX_INLINE void Scb::Constraint::syncState() +{ + //!!! Force has to be synced every frame (might want to have a list of active constraint shaders?) + mConstraint.getForce(mBufferedForce, mBufferedTorque); + + mBrokenFlag = mConstraint.getFlags() & PxConstraintFlag::eBROKEN; + + PxU32 flags = getBufferFlags(); + if(flags) + { + const Buf* PX_RESTRICT bufferedData = getBufferedData(); + + if(flags & BF_BODIES) + mConstraint.setBodies(bufferedData->rigids[0], bufferedData->rigids[1]); + + if(flags & BF_BREAK_IMPULSE) + mConstraint.setBreakForce(bufferedData->linBreakForce, bufferedData->angBreakForce); + + if(flags & BF_MIN_RESPONSE_THRESHOLD) + mConstraint.setMinResponseThreshold(bufferedData->minResponseThreshold); + + if(flags & BF_FLAGS) + mConstraint.setFlags(bufferedData->flags | mBrokenFlag); + } + + postSyncState(); +} + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/buffering/ScbDefs.h b/PhysX_3.4/Source/PhysX/src/buffering/ScbDefs.h new file mode 100644 index 00000000..bd3fd4cd --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/buffering/ScbDefs.h @@ -0,0 +1,140 @@ +// 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_SCB_DEFS +#define PX_PHYSICS_SCB_DEFS + +#include "ScbBase.h" + +// a Regular attribute of type T is one for which +// * the SC method takes a single argument of type ArgType<T> (defined below) +// * Scb either passes that argument through, or dumps it in a buffer to flush later. +// * PVD is notified when the variable changes +// +// For each such, we can define static methods to read and write the core and buffered variables, +// and capture the buffering logic in the BufferedAccess class. +// +// The dummy arg is necessary here because ISO permits partial specialization of member templates +// but not full specialization. +// +// putting just accessors and mutators here allows us to change the behavior just by varying the +// BufferAccess template (e.g. to compile without buffering), and also to size-reduce that template +// by passing function pointers if necessary + +#define SCB_REGULAR_ATTRIBUTE(_val, _type, _name) \ +enum { BF_##_name = 1<<(_val) }; \ +_type m##_name; \ +template<PxU32 Dummy> struct Fns<1<<(_val),Dummy> \ +{ \ + typedef typename ArgType<_type>::Type Arg; \ + enum { flag = 1<<(_val) }; \ + static PX_FORCE_INLINE Arg getBuffered(const Buf& buf) { return Arg(buf.m##_name);} \ + static PX_FORCE_INLINE void setBuffered(Buf& buf, Arg v) { buf.m##_name = v;} \ + static PX_FORCE_INLINE Arg getCore(const Core& core) { return Arg(core.get##_name());} \ + static PX_FORCE_INLINE void setCore(Core& core, Arg v) { core.set##_name(v);} \ +}; + +#define SCB_REGULAR_ATTRIBUTE_ALIGNED(_val, _type, _name, _alignment) \ +enum { BF_##_name = 1<<(_val) }; \ +PX_ALIGN(_alignment, _type) m##_name; \ +template<PxU32 Dummy> struct Fns<1<<(_val),Dummy> \ +{ \ + typedef typename ArgType<_type>::Type Arg; \ + enum { flag = 1<<(_val) }; \ + static PX_FORCE_INLINE Arg getBuffered(const Buf& buf) { return buf.m##_name;} \ + static PX_FORCE_INLINE void setBuffered(Buf& buf, Arg v) { buf.m##_name = v;} \ + static PX_FORCE_INLINE Arg getCore(const Core& core) { return core.get##_name();} \ + static PX_FORCE_INLINE void setCore(Core& core, Arg v) { core.set##_name(v);} \ +}; + + + +namespace physx +{ + +namespace Scb +{ +class Scene; + +template<typename T> struct ArgType { typedef T Type; }; +template<> struct ArgType<PxVec3> { typedef const PxVec3& Type; }; +template<> struct ArgType<PxTransform> { typedef const PxTransform& Type; }; +template<> struct ArgType<PxQuat> { typedef const PxQuat& Type; }; +template<> struct ArgType<PxPlane> { typedef const PxPlane& Type; }; +template<> struct ArgType<PxFilterData> { typedef const PxFilterData& Type; }; + +// TODO: should be able to size-reduce this if necessary by just generating one set per +// arg type instead of one per arg, by passing function pointers to the accessors/mutators/flag +// instead of instancing per type. + +template<class Buf, class Core, class ScbClass, class BaseClass=Scb::Base> // BaseClass: introduced to have Scb::Body use custom location for storing buffered property flags +struct BufferedAccess +{ + template<typename Fns> + static PX_FORCE_INLINE typename Fns::Arg read(const BaseClass& base, const Core& core) + { + return base.isBuffered(Fns::flag) ? Fns::getBuffered(*reinterpret_cast<const Buf*>(base.getStream())) + : Fns::getCore(core); + } + + template<typename Fns> + static PX_FORCE_INLINE void write(BaseClass& base, Core& core, typename Fns::Arg v) + { + if (!base.isBuffering()) + { + Fns::setCore(core, v); +#if PX_SUPPORT_PVD + if(base.getControlState() == ControlState::eIN_SCENE) + { + Scb::Scene* scene = base.getScbScene(); + PX_ASSERT(scene); + scene->getScenePvdClient().updatePvdProperties(static_cast<ScbClass*>(&base)); + } +#endif + } + else + { + Fns::setBuffered(*reinterpret_cast<Buf*>(base.getStream()), v); + base.markUpdated(Fns::flag); + } + } + + template<typename Fns> + static PX_FORCE_INLINE void flush(const BaseClass& base, Core& core, const Buf& buf) + { + if(base.isBuffered(Fns::flag)) + Fns::setCore(core, Fns::getBuffered(buf)); + } +}; + +} +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/buffering/ScbMetaData.cpp b/PhysX_3.4/Source/PhysX/src/buffering/ScbMetaData.cpp new file mode 100644 index 00000000..fea9a5f3 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/buffering/ScbMetaData.cpp @@ -0,0 +1,203 @@ +// 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 "ScbShape.h" +#include "ScbBody.h" +#include "ScbRigidStatic.h" +#include "ScbConstraint.h" +#include "ScbArticulation.h" +#include "ScbArticulationJoint.h" +#include "ScbAggregate.h" +#include "ScbCloth.h" +#include "ScbParticleSystem.h" + +using namespace physx; + + +/////////////////////////////////////////////////////////////////////////////// + +void Scb::Base::getBinaryMetaData(PxOutputStream& stream) +{ + // 28 => 12 bytes + PX_DEF_BIN_METADATA_TYPEDEF(stream, ScbType::Enum, PxU32) + + PX_DEF_BIN_METADATA_CLASS(stream, Scb::Base) + + PX_DEF_BIN_METADATA_ITEM(stream, Scb::Base, Scb::Scene, mScene, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, Scb::Base, PxU32, mControlState, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Scb::Base, PxU8*, mStreamPtr, PxMetaDataFlag::ePTR) +} + +/////////////////////////////////////////////////////////////////////////////// + +void Scb::Shape::getBinaryMetaData(PxOutputStream& stream) +{ + // 176 => 160 bytes + PX_DEF_BIN_METADATA_CLASS(stream, Scb::Shape) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, Scb::Shape, Scb::Base) + PX_DEF_BIN_METADATA_ITEM(stream, Scb::Shape, ShapeCore, mShape, 0) +} + +/////////////////////////////////////////////////////////////////////////////// + +void Scb::Actor::getBinaryMetaData(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_CLASS(stream, Scb::Actor) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, Scb::Actor, Scb::Base) +} + +/////////////////////////////////////////////////////////////////////////////// + +void Scb::RigidObject::getBinaryMetaData(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_CLASS(stream, Scb::RigidObject) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, Scb::RigidObject, Scb::Actor) +} + +/////////////////////////////////////////////////////////////////////////////// + +void Scb::Body::getBinaryMetaData(PxOutputStream& stream) +{ + // 240 => 224 bytes + PX_DEF_BIN_METADATA_CLASS(stream, Scb::Body) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, Scb::Body, Scb::RigidObject) + +#ifdef EXPLICIT_PADDING_METADATA + PX_DEF_BIN_METADATA_ITEM(stream, Scb::Body, PxU32, mPaddingScbBody1, PxMetaDataFlag::ePADDING) +#endif + PX_DEF_BIN_METADATA_ITEM(stream, Scb::Body, Sc::BodyCore, mBodyCore, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Scb::Body, PxTransform, mBufferedBody2World, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Scb::Body, PxVec3, mBufferedLinVelocity, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Scb::Body, PxVec3, mBufferedAngVelocity, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Scb::Body, PxReal, mBufferedWakeCounter, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Scb::Body, PxU32, mBufferedIsSleeping, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Scb::Body, PxU32, mBodyBufferFlags, 0) +} + +/////////////////////////////////////////////////////////////////////////////// + +void Scb::RigidStatic::getBinaryMetaData(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_CLASS(stream, Scb::RigidStatic) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, Scb::RigidStatic, Scb::RigidObject) + + PX_DEF_BIN_METADATA_ITEM(stream, Scb::RigidStatic, Sc::StaticCore, mStatic, 0) +} + +/////////////////////////////////////////////////////////////////////////////// + +void Scb::Articulation::getBinaryMetaData(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_CLASS(stream, Scb::Articulation) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, Scb::Articulation, Scb::Base) + + PX_DEF_BIN_METADATA_ITEM(stream, Scb::Articulation, ArticulationCore, mArticulation, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Scb::Articulation, PxReal, mBufferedWakeCounter, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Scb::Articulation, PxU8, mBufferedIsSleeping, 0) +} + +/////////////////////////////////////////////////////////////////////////////// + +void Scb::ArticulationJoint::getBinaryMetaData(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_CLASS(stream, Scb::ArticulationJoint) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, Scb::ArticulationJoint, Scb::Base) + + PX_DEF_BIN_METADATA_ITEM(stream, Scb::ArticulationJoint, ArticulationJointCore, mJoint, 0) +} + +/////////////////////////////////////////////////////////////////////////////// + +void Scb::Constraint::getBinaryMetaData(PxOutputStream& stream) +{ + // 120 => 108 bytes + PX_DEF_BIN_METADATA_CLASS(stream, Scb::Constraint) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, Scb::Constraint, Scb::Base) + + PX_DEF_BIN_METADATA_ITEM(stream, Scb::Constraint, ConstraintCore, mConstraint, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Scb::Constraint, PxVec3, mBufferedForce, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Scb::Constraint, PxVec3, mBufferedTorque, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Scb::Constraint, PxConstraintFlags, mBrokenFlag, 0) +#ifdef EXPLICIT_PADDING_METADATA + PX_DEF_BIN_METADATA_ITEM(stream, Scb::Constraint, PxU16, mPaddingFromBrokenFlags, PxMetaDataFlag::ePADDING) +#endif +} + +/////////////////////////////////////////////////////////////////////////////// + +void Scb::Aggregate::getBinaryMetaData(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_CLASS(stream, Scb::Aggregate) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, Scb::Aggregate, Scb::Base) + + PX_DEF_BIN_METADATA_ITEM(stream, Scb::Aggregate, PxAggregate,mPxAggregate, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, Scb::Aggregate, PxU32, mAggregateID, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Scb::Aggregate, PxU32, mMaxNbActors, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Scb::Aggregate, bool, mSelfCollide, 0) + +#ifdef EXPLICIT_PADDING_METADATA + PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, Scb::Aggregate, bool, mPaddingFromBool, PxMetaDataFlag::ePADDING) +#endif +} + +/////////////////////////////////////////////////////////////////////////////// + +#if PX_USE_CLOTH_API +void Scb::Cloth::getBinaryMetaData(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_CLASS(stream, Scb::Cloth) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, Scb::Cloth, Scb::Actor) + + PX_DEF_BIN_METADATA_ITEM(stream, Scb::Cloth, Sc::ClothCore, mCloth, 0) +} +#endif + +/////////////////////////////////////////////////////////////////////////////// + +#if PX_USE_PARTICLE_SYSTEM_API +void Scb::ParticleSystem::getBinaryMetaData(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_CLASS(stream, ForceUpdates) + PX_DEF_BIN_METADATA_ITEM(stream, ForceUpdates, BitMap, map, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, ForceUpdates, PxVec3, values, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, ForceUpdates, bool, hasUpdates, 0) + + PX_DEF_BIN_METADATA_CLASS(stream, Scb::ParticleSystem) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, Scb::ParticleSystem, Scb::Actor) + + PX_DEF_BIN_METADATA_ITEM(stream, Scb::ParticleSystem, Sc::ParticleSystemCore, mParticleSystem, 0) + + PX_DEF_BIN_METADATA_ITEM(stream, Scb::ParticleSystem, NpParticleFluidReadData, mReadParticleFluidData, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, Scb::ParticleSystem, ForceUpdates, mForceUpdatesAcc, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Scb::ParticleSystem, ForceUpdates, mForceUpdatesVel, 0) +} +#endif + +/////////////////////////////////////////////////////////////////////////////// diff --git a/PhysX_3.4/Source/PhysX/src/buffering/ScbNpDeps.h b/PhysX_3.4/Source/PhysX/src/buffering/ScbNpDeps.h new file mode 100644 index 00000000..37517dc8 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/buffering/ScbNpDeps.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_SCB_NPDEPS +#define PX_PHYSICS_SCB_NPDEPS + +namespace physx +{ + +// The Scb layer needs to delete the owning Np objects, but we don't want to include the Np headers +// necessary to find their addresses. So we use link-level dependencies instead. + +namespace Scb +{ + class Base; + class Shape; + class RigidObject; + class Constraint; + class Scene; + class ArticulationJoint; + class Articulation; + class RigidStatic; + class Body; +} + +namespace Sc +{ + class RigidCore; +} + +class PxScene; + +extern void NpDestroy(Scb::Base&); + +// we want to get the pointer to the rigid object that owns a shape, and the two actor pointers for a constraint, so that we don't +// duplicate the scene graph in Scb + +extern PxU32 NpRigidStaticGetShapes(Scb::RigidStatic& rigid, void* const *&shapes); +extern PxU32 NpRigidDynamicGetShapes(Scb::Body& body, void* const *&shapes); +extern size_t NpShapeGetScPtrOffset(); +extern void NpShapeIncRefCount(Scb::Shape& shape); +extern void NpShapeDecRefCount(Scb::Shape& shape); + +extern Sc::RigidCore* NpShapeGetScRigidObjectFromScbSLOW(const Scb::Shape &); +extern void NpConstraintGetRigidObjectsFromScb(const Scb::Constraint&, Scb::RigidObject*&, Scb::RigidObject*&); +extern void NpArticulationJointGetBodiesFromScb(Scb::ArticulationJoint&, Scb::Body*&, Scb::Body*&); +extern Scb::Body* NpArticulationGetRootFromScb(Scb::Articulation&); +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/buffering/ScbParticleSystem.cpp b/PhysX_3.4/Source/PhysX/src/buffering/ScbParticleSystem.cpp new file mode 100644 index 00000000..078f3a24 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/buffering/ScbParticleSystem.cpp @@ -0,0 +1,311 @@ +// 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 "PxPhysXConfig.h" + +#if PX_USE_PARTICLE_SYSTEM_API + +#include "ScbParticleSystem.h" + +using namespace physx; + +//----------------------------------------------------------------------------// + +// lazy allocate. doesn't reset hasUpdates +void Scb::ParticleSystem::ForceUpdates::initialize(PxU32 maxParticles) +{ + PX_ASSERT((map == NULL) == (values == NULL)); + if (values) + return; + + values = reinterpret_cast<PxVec3*>(PX_ALLOC(maxParticles*sizeof(PxVec3), "PxVec3")); + map = PX_NEW(Cm::BitMap)(); + map->resizeAndClear(maxParticles); +} + +//----------------------------------------------------------------------------// + +void Scb::ParticleSystem::ForceUpdates::destroy() +{ + PX_ASSERT((map == NULL) == (values == NULL)); + + if (map) + { + PX_DELETE(map); + map = NULL; + PX_FREE(values); + values = NULL; + } + hasUpdates = false; +} + +//----------------------------------------------------------------------------// + +Scb::ParticleSystem::ParticleSystem(const PxActorType::Enum& actorType, PxU32 maxParticles, bool perParticleRestOffset) +: mParticleSystem(actorType, maxParticles, perParticleRestOffset) +, mReadParticleFluidData(NULL) +{ + setScbType(ScbType::PARTICLE_SYSTEM); +} + +//----------------------------------------------------------------------------// + +Scb::ParticleSystem::~ParticleSystem() +{ + if (mReadParticleFluidData) + PX_DELETE_AND_RESET(mReadParticleFluidData); +} + +//----------------------------------------------------------------------------// + +bool Scb::ParticleSystem::createParticles(const PxParticleCreationData& creationData) +{ + if (isBuffering()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, + "Particle operations are not allowed while simulation is running."); + return false; + } + else + { + LOCK_PARTICLE_USER_BUFFERS("PxParticleBase::createParticles()") + + bool ret = mParticleSystem.createParticles(creationData); + + return ret; + } +} + +//----------------------------------------------------------------------------// + +void Scb::ParticleSystem::releaseParticles(PxU32 numParticles, const PxStrideIterator<const PxU32>& indexBuffer) +{ + LOCK_PARTICLE_USER_BUFFERS("PxParticleBase::releaseParticles()") + + if (numParticles == 0) + return; + + if (isBuffering()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, + "Particle operations are not allowed while simulation is running."); + return; + } + else + { + mParticleSystem.releaseParticles(numParticles, indexBuffer); + } + + if (mForceUpdatesAcc.hasUpdates) + for (PxU32 i=0; i < numParticles; i++) + mForceUpdatesAcc.clear(indexBuffer[i]); + + if (mForceUpdatesVel.hasUpdates) + for (PxU32 i=0; i < numParticles; i++) + mForceUpdatesVel.clear(indexBuffer[i]); +} + +//----------------------------------------------------------------------------// + +void Scb::ParticleSystem::releaseParticles() +{ + LOCK_PARTICLE_USER_BUFFERS("PxParticleBase::releaseParticles()") + + if (isBuffering()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, + "Particle operations are not allowed while simulation is running."); + return; + } + else + { + mParticleSystem.releaseParticles(); + } + + mForceUpdatesAcc.clear(); + mForceUpdatesVel.clear(); +} + +//----------------------------------------------------------------------------// + +void Scb::ParticleSystem::setPositions(PxU32 numParticles, const PxStrideIterator<const PxU32>& indexBuffer, + const PxStrideIterator<const PxVec3>& positionBuffer) +{ + LOCK_PARTICLE_USER_BUFFERS("PxParticleBase::setPositions()") + + if (isBuffering()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, + "Particle operations are not allowed while simulation is running."); + return; + } + else + { + mParticleSystem.setPositions(numParticles, indexBuffer, positionBuffer); + } +} + +//----------------------------------------------------------------------------// + +void Scb::ParticleSystem::setVelocities(PxU32 numParticles, const PxStrideIterator<const PxU32>& indexBuffer, + const PxStrideIterator<const PxVec3>& velocityBuffer) +{ + LOCK_PARTICLE_USER_BUFFERS("PxParticleBase::setVelocities()") + + if (isBuffering()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, + "Particle operations are not allowed while simulation is running."); + return; + } + else + { + mParticleSystem.setVelocities(numParticles, indexBuffer, velocityBuffer); + } +} + +//----------------------------------------------------------------------------// + +void Scb::ParticleSystem::setRestOffsets(PxU32 numParticles, const PxStrideIterator<const PxU32>& indexBuffer, + const PxStrideIterator<const PxF32>& restOffsetBuffer) +{ + LOCK_PARTICLE_USER_BUFFERS("PxParticleBase::setRestOffsets()") + + if (isBuffering()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, + "Particle operations are not allowed while simulation is running."); + return; + } + else + { + mParticleSystem.setRestOffsets(numParticles, indexBuffer, restOffsetBuffer); + } +} + +//----------------------------------------------------------------------------// + +void Scb::ParticleSystem::addForces(PxU32 numParticles, const PxStrideIterator<const PxU32>& indexBuffer, + const PxStrideIterator<const PxVec3>& forceBuffer, PxForceMode::Enum forceMode) +{ + if (isBuffering()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, + "Particle operations are not allowed while simulation is running."); + return; + } + + PX_ASSERT(numParticles > 0); + PX_ASSERT(indexBuffer.ptr() && indexBuffer.stride() > 0); + + PxReal particleMass = getParticleMass(); + bool isAcceleration = false; + PxReal unitMult = 0.0; + switch(forceMode) + { + case PxForceMode::eFORCE: //!< parameter has unit of mass * distance/ time^2, i.e. a force + unitMult = 1.0f / particleMass; + isAcceleration = true; + break; + case PxForceMode::eIMPULSE: //!< parameter has unit of mass * distance /time + unitMult = 1.0f / particleMass; + isAcceleration = false; + break; + case PxForceMode::eVELOCITY_CHANGE: //!< parameter has unit of distance / time, i.e. the effect is mass independent: a velocity change. + unitMult = 1.0f; + isAcceleration = false; + break; + case PxForceMode::eACCELERATION: //!< parameter has unit of distance/ time^2, i.e. an acceleration. It gets treated just like a force except the mass is not divided out before integration. + unitMult = 1.0f; + isAcceleration = true; + break; + } + + ForceUpdates& forceUpdates = isAcceleration ? mForceUpdatesAcc : mForceUpdatesVel; + forceUpdates.initialize(mParticleSystem.getMaxParticles()); + + for (PxU32 i=0; i < numParticles; i++) + forceUpdates.add(indexBuffer[i], forceBuffer[i] * unitMult); +} + +//----------------------------------------------------------------------------// + +void Scb::ParticleSystem::submitForceUpdates(PxReal timeStep) +{ + LOCK_PARTICLE_USER_BUFFERS("PxParticleBase: Apply forces") + + if (mForceUpdatesAcc.hasUpdates) + { + mParticleSystem.addDeltaVelocities(*mForceUpdatesAcc.map, mForceUpdatesAcc.values, timeStep); + mForceUpdatesAcc.clear(); + } + + if (mForceUpdatesVel.hasUpdates) + { + mParticleSystem.addDeltaVelocities(*mForceUpdatesVel.map, mForceUpdatesVel.values, 1.0f); + mForceUpdatesVel.clear(); + } +} + +//----------------------------------------------------------------------------// + +void Scb::ParticleSystem::syncState() +{ + LOCK_PARTICLE_USER_BUFFERS("PxScene::fetchResults()") + + PxU32 flags = getBufferFlags(); + if (flags) // Optimization to avoid all the if-statements below if possible + { + const Buf& buffer = *getParticleSystemBuffer(); + + flush<Buf::BF_Stiffness>(buffer); + flush<Buf::BF_Viscosity>(buffer); + flush<Buf::BF_Damping>(buffer); + flush<Buf::BF_ExternalAcceleration>(buffer); + flush<Buf::BF_ProjectionPlane>(buffer); + flush<Buf::BF_ParticleMass>(buffer); + flush<Buf::BF_Restitution>(buffer); + flush<Buf::BF_DynamicFriction>(buffer); + flush<Buf::BF_StaticFriction>(buffer); + + if (flags & Buf::BF_ResetFiltering) + mParticleSystem.resetFiltering(); + + flush<Buf::BF_SimulationFilterData>(buffer); + flush<Buf::BF_Flags>(buffer); + + Actor::syncState(); + } + + postSyncState(); +} + +//----------------------------------------------------------------------------// + +#endif // PX_USE_PARTICLE_SYSTEM_API diff --git a/PhysX_3.4/Source/PhysX/src/buffering/ScbParticleSystem.h b/PhysX_3.4/Source/PhysX/src/buffering/ScbParticleSystem.h new file mode 100644 index 00000000..a0d720d1 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/buffering/ScbParticleSystem.h @@ -0,0 +1,484 @@ +// 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_SCB_PARTICLE_SYSTEM +#define PX_PHYSICS_SCB_PARTICLE_SYSTEM + +#include "PxPhysXConfig.h" + +#if PX_USE_PARTICLE_SYSTEM_API + +#include "ScParticleSystemCore.h" + +#include "ScbActor.h" + +#include "NpPhysics.h" +#include "NpParticleFluidReadData.h" + +namespace physx +{ + +struct PxCudaReadWriteParticleBuffers; + +namespace Scb +{ + +struct ParticleSystemBuffer : public Scb::ActorBuffer +{ + template <PxU32 I, PxU32 Dummy> struct Fns {}; // TODO : make the base class traits visible + typedef Sc::ParticleSystemCore Core; + typedef ParticleSystemBuffer Buf; + enum { BF_Base = ActorBuffer::AttrCount }; + + // Regular attributes + + SCB_REGULAR_ATTRIBUTE(BF_Base+2, PxReal, Stiffness) + SCB_REGULAR_ATTRIBUTE(BF_Base+3, PxReal, Viscosity) + SCB_REGULAR_ATTRIBUTE(BF_Base+4, PxReal, Damping) + SCB_REGULAR_ATTRIBUTE(BF_Base+5, PxVec3, ExternalAcceleration) + SCB_REGULAR_ATTRIBUTE(BF_Base+6, PxPlane, ProjectionPlane) + SCB_REGULAR_ATTRIBUTE(BF_Base+7, PxReal, ParticleMass) + SCB_REGULAR_ATTRIBUTE(BF_Base+8, PxReal, Restitution) + SCB_REGULAR_ATTRIBUTE(BF_Base+9, PxReal, DynamicFriction) + SCB_REGULAR_ATTRIBUTE(BF_Base+10, PxReal, StaticFriction) + SCB_REGULAR_ATTRIBUTE(BF_Base+11, PxFilterData, SimulationFilterData) + SCB_REGULAR_ATTRIBUTE(BF_Base+12, PxParticleBaseFlags, Flags) + + enum { BF_ResetFiltering = 1<<(BF_Base+13) }; + +}; + + +class DebugIndexPool; + +class ParticleSystem : public Scb::Actor +{ +//= 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. +//================================================================================================== + + typedef Sc::ParticleSystemCore Core; + typedef ParticleSystemBuffer Buf; + + struct UserBufferLock + { + UserBufferLock(NpParticleFluidReadData* db, const char* callerName) : dataBuffer(db) { if (dataBuffer) { dataBuffer->lock(callerName); } } + ~UserBufferLock() { if (dataBuffer) { dataBuffer->unlock(); } } + + NpParticleFluidReadData* dataBuffer; + private: + UserBufferLock& operator=(const UserBufferLock&); + }; + +#define LOCK_PARTICLE_USER_BUFFERS(callerName) UserBufferLock userBufferLock(mReadParticleFluidData, callerName); + + struct ForceUpdates + { + ForceUpdates() : map(NULL), values(NULL), hasUpdates(false) {} + void initialize(PxU32 maxParticles); + void destroy(); + + PX_INLINE void add(PxU32 index, const PxVec3& value) + { + hasUpdates = true; + if (!map->test(index)) + { + map->set(index); + values[index] = value; + return; + } + values[index] += value; + } + + PX_INLINE void clear(PxU32 index) + { + PX_ASSERT(map); + map->reset(index); + } + + PX_INLINE void clear() + { + if (!hasUpdates) + return; + + PX_ASSERT(map); + map->clear(); + hasUpdates = false; + } + + Cm::BitMap* map; // can we make this an instance? + PxVec3* values; + bool hasUpdates; + }; + +public: +// PX_SERIALIZATION + ParticleSystem(const PxEMPTY) : Scb::Actor(PxEmpty), mParticleSystem(PxEmpty) { mReadParticleFluidData = NULL; } + void exportExtraData(PxSerializationContext& stream) { mParticleSystem.exportExtraData(stream); } + void importExtraData(PxDeserializationContext& context) { mParticleSystem.importExtraData(context); } + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + ParticleSystem(const PxActorType::Enum&, PxU32, bool); + ~ParticleSystem(); + + //--------------------------------------------------------------------------------- + // Wrapper for Sc::ParticleSystemCore interface + //--------------------------------------------------------------------------------- + PX_INLINE PxParticleBase* getPxParticleSystem(); + + PX_INLINE void removeFromScene(); + + bool createParticles(const PxParticleCreationData& creationData); + void releaseParticles(PxU32 numParticles, const PxStrideIterator<const PxU32>& indexBuffer); + 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>& velocitiesBuffer); + void setRestOffsets(PxU32 numParticles, const PxStrideIterator<const PxU32>& indexBuffer, + const PxStrideIterator<const PxF32>& restOffsetBuffer); + void addForces(PxU32 numParticles, const PxStrideIterator<const PxU32>& indexBuffer, + const PxStrideIterator<const PxVec3>& forceBuffer, PxForceMode::Enum forceMode); + + PX_INLINE PxParticleReadData* lockParticleReadData(PxDataAccessFlags flags); + + PX_INLINE PxU32 getSimulationMethod() const; + + PX_INLINE PxReal getStiffness() const { return read<Buf::BF_Stiffness>(); } + PX_INLINE void setStiffness(PxReal v) { write<Buf::BF_Stiffness>(v); } + + PX_INLINE PxReal getViscosity() const { return read<Buf::BF_Viscosity>(); } + PX_INLINE void setViscosity(PxReal v) { write<Buf::BF_Viscosity>(v); } + + PX_INLINE PxReal getDamping() const { return read<Buf::BF_Damping>(); } + PX_INLINE void setDamping(PxReal v) { write<Buf::BF_Damping>(v); } + + PX_INLINE PxVec3 getExternalAcceleration() const { return read<Buf::BF_ExternalAcceleration>(); } + PX_INLINE void setExternalAcceleration(const PxVec3& v) { write<Buf::BF_ExternalAcceleration>(v); } + + PX_INLINE PxPlane getProjectionPlane() const { return read<Buf::BF_ProjectionPlane>(); } + PX_INLINE void setProjectionPlane(const PxPlane& v) { write<Buf::BF_ProjectionPlane>(v); } + + PX_INLINE PxReal getParticleMass() const { return read<Buf::BF_ParticleMass>(); } + PX_INLINE void setParticleMass(PxReal v) { write<Buf::BF_ParticleMass>(v); } + + PX_INLINE PxReal getRestitution() const { return read<Buf::BF_Restitution>(); } + PX_INLINE void setRestitution(PxReal v) { write<Buf::BF_Restitution>(v); } + + PX_INLINE PxReal getDynamicFriction() const { return read<Buf::BF_DynamicFriction>(); } + PX_INLINE void setDynamicFriction(PxReal v) { write<Buf::BF_DynamicFriction>(v);} + + PX_INLINE PxReal getStaticFriction() const { return read<Buf::BF_StaticFriction>(); } + PX_INLINE void setStaticFriction(PxReal v) { write<Buf::BF_StaticFriction>(v); } + + PX_INLINE PxParticleBaseFlags getFlags() const { return read<Buf::BF_Flags>();} + PX_INLINE void setFlags(PxParticleBaseFlags v) { write<Buf::BF_Flags>(v); } + + PX_INLINE PxFilterData getSimulationFilterData() const { return read<Buf::BF_SimulationFilterData>(); } + PX_INLINE void setSimulationFilterData(const PxFilterData& v) { write<Buf::BF_SimulationFilterData>(v); } + + PX_INLINE void resetFiltering(); + + PX_INLINE PxParticleReadDataFlags getParticleReadDataFlags() const; + PX_INLINE void setParticleReadDataFlags(PxParticleReadDataFlags); + + + PX_INLINE PxU32 getParticleCount() const; + PX_INLINE const Cm::BitMap& getParticleMap() const; + + PX_INLINE PxU32 getMaxParticles() const; + + PX_INLINE PxReal getMaxMotionDistance() const; + PX_INLINE void setMaxMotionDistance(PxReal); + PX_INLINE PxReal getRestOffset() const; + PX_INLINE void setRestOffset(PxReal); + PX_INLINE PxReal getContactOffset() const; + PX_INLINE void setContactOffset(PxReal); + PX_INLINE PxReal getRestParticleDistance() const; + PX_INLINE void setRestParticleDistance(PxReal); + PX_INLINE PxReal getGridSize() const; + PX_INLINE void setGridSize(PxReal); + + PX_INLINE PxBounds3 getWorldBounds() const; + + //--------------------------------------------------------------------------------- + // Data synchronization + //--------------------------------------------------------------------------------- + + // Synchronously called when the scene starts to be simulated. + void submitForceUpdates(PxReal timeStep); + + // Synchronously called with fetchResults. + void syncState(); + + //--------------------------------------------------------------------------------- + // Miscellaneous + //--------------------------------------------------------------------------------- + PX_FORCE_INLINE const Core& getScParticleSystem() const { return mParticleSystem; } // Only use if you know what you're doing! + PX_FORCE_INLINE Core& getScParticleSystem() { return mParticleSystem; } // Only use if you know what you're doing! + + PX_FORCE_INLINE static const ParticleSystem&fromSc(const Core& a) { return static_cast<const ParticleSystem&>(Actor::fromSc(a)); } + PX_FORCE_INLINE static ParticleSystem& fromSc(Core &a) { + + Scb::Actor& actor = Actor::fromSc(a); + ParticleSystem& ps = static_cast<ParticleSystem&>(actor); + PX_UNUSED(ps); + + return static_cast<ParticleSystem&>(Actor::fromSc(a)); + + } + + static size_t getScOffset() + { + return reinterpret_cast<size_t>(&reinterpret_cast<ParticleSystem*>(0)->mParticleSystem); + } + +#if PX_SUPPORT_GPU_PHYSX + PX_INLINE void enableDeviceExclusiveModeGpu(); + PX_INLINE PxParticleDeviceExclusiveAccess* getDeviceExclusiveAccessGpu() const; +#endif + +private: + Core mParticleSystem; + + NpParticleFluidReadData* mReadParticleFluidData; + + + ForceUpdates mForceUpdatesAcc; + ForceUpdates mForceUpdatesVel; + + PX_FORCE_INLINE const Scb::ParticleSystemBuffer* getParticleSystemBuffer() const { return reinterpret_cast<const Scb::ParticleSystemBuffer*>(getStream()); } + PX_FORCE_INLINE Scb::ParticleSystemBuffer* getParticleSystemBuffer() { return reinterpret_cast<Scb::ParticleSystemBuffer*>(getStream()); } + + //--------------------------------------------------------------------------------- + // Infrastructure for regular attributes + //--------------------------------------------------------------------------------- + + struct Access: public BufferedAccess<Buf, Core, ParticleSystem> {}; + template<PxU32 f> PX_FORCE_INLINE typename Buf::Fns<f,0>::Arg read() const { return Access::read<Buf::Fns<f, 0> >(*this, mParticleSystem); } + template<PxU32 f> PX_FORCE_INLINE void write(typename Buf::Fns<f,0>::Arg v) { Access::write<Buf::Fns<f, 0> >(*this, mParticleSystem, v); } + template<PxU32 f> PX_FORCE_INLINE void flush(const Buf& buf) { Access::flush<Buf::Fns<f, 0> >(*this, mParticleSystem, buf); } +}; + +PX_INLINE PxParticleBase* ParticleSystem::getPxParticleSystem() +{ + return getScParticleSystem().getPxParticleBase(); +} + + +PX_INLINE void ParticleSystem::removeFromScene() +{ + PX_ASSERT(!isBuffering() || getControlState()==ControlState::eREMOVE_PENDING); + + mForceUpdatesAcc.destroy(); + mForceUpdatesVel.destroy(); +} + + +PX_INLINE PxParticleReadData* ParticleSystem::lockParticleReadData(PxDataAccessFlags flags) +{ + // Don't use the macro here since releasing the lock should not be done automatically but by the user + if (isBuffering()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Particle data read not allowed while simulation is running."); + return NULL; + } + + if (!mReadParticleFluidData) + { + mReadParticleFluidData = PX_NEW(NpParticleFluidReadData)(); + } + + mReadParticleFluidData->lock("PxParticleBase::lockParticleReadData()"); + mReadParticleFluidData->setDataAccessFlags(flags); + getScParticleSystem().getParticleReadData(*mReadParticleFluidData); + return mReadParticleFluidData; +} + + + + +PX_INLINE void ParticleSystem::resetFiltering() +{ + if (!isBuffering()) + { + getScParticleSystem().resetFiltering(); + UPDATE_PVD_PROPERTIES_OBJECT() + } + else + { + markUpdated(Buf::BF_ResetFiltering); + } +} + + + +PX_INLINE PxParticleReadDataFlags ParticleSystem::getParticleReadDataFlags() const +{ + return getScParticleSystem().getParticleReadDataFlags(); +} + +PX_INLINE void ParticleSystem::setParticleReadDataFlags(PxParticleReadDataFlags flags) +{ + if (!isBuffering()) + { + getScParticleSystem().setParticleReadDataFlags(flags); + UPDATE_PVD_PROPERTIES_OBJECT() + } +} + +PX_INLINE PxU32 ParticleSystem::getParticleCount() const +{ + return getScParticleSystem().getParticleCount(); +} + +PX_INLINE const Cm::BitMap& ParticleSystem::getParticleMap() const +{ + return getScParticleSystem().getParticleMap(); +} + +PX_INLINE PxU32 ParticleSystem::getMaxParticles() const +{ + return getScParticleSystem().getMaxParticles(); +} + + +PX_INLINE PxReal ParticleSystem::getMaxMotionDistance() const +{ + return getScParticleSystem().getMaxMotionDistance(); +} + +PX_INLINE void ParticleSystem::setMaxMotionDistance(PxReal distance) +{ + if (!isBuffering()) + { + getScParticleSystem().setMaxMotionDistance(distance); + UPDATE_PVD_PROPERTIES_OBJECT() + } +} + +PX_INLINE PxReal ParticleSystem::getRestOffset() const +{ + return getScParticleSystem().getRestOffset(); +} + + +PX_INLINE void ParticleSystem::setRestOffset(PxReal restOffset) +{ + if (!isBuffering()) + { + getScParticleSystem().setRestOffset(restOffset); + UPDATE_PVD_PROPERTIES_OBJECT() + } +} + +PX_INLINE PxReal ParticleSystem::getContactOffset() const +{ + return getScParticleSystem().getContactOffset(); +} + +PX_INLINE void ParticleSystem::setContactOffset(PxReal contactOffset) +{ + if (!isBuffering()) + { + getScParticleSystem().setContactOffset(contactOffset); + UPDATE_PVD_PROPERTIES_OBJECT() + } +} + +PX_INLINE PxReal ParticleSystem::getRestParticleDistance() const +{ + return getScParticleSystem().getRestParticleDistance(); +} + +PX_INLINE void ParticleSystem::setRestParticleDistance(PxReal restParticleDistance) +{ + if (!isBuffering()) + { + getScParticleSystem().setRestParticleDistance(restParticleDistance); + UPDATE_PVD_PROPERTIES_OBJECT() + } +} + + +PX_INLINE PxReal ParticleSystem::getGridSize() const +{ + return getScParticleSystem().getGridSize(); +} + +PX_INLINE void ParticleSystem::setGridSize(PxReal gridSize) +{ + if (!isBuffering()) + { + getScParticleSystem().setGridSize(gridSize); + UPDATE_PVD_PROPERTIES_OBJECT() + } +} + +PX_INLINE PxBounds3 ParticleSystem::getWorldBounds() const +{ + if (isBuffering()) + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, + "PxActor::getWorldBounds(): Can't access particle world bounds during simulation without enabling bulk buffering."); + return PxBounds3(); + } + + return getScParticleSystem().getWorldBounds(); +} + +#if PX_SUPPORT_GPU_PHYSX + +PX_INLINE void ParticleSystem::enableDeviceExclusiveModeGpu() +{ + getScParticleSystem().enableDeviceExclusiveModeGpu(); +} + +PX_INLINE PxParticleDeviceExclusiveAccess* ParticleSystem::getDeviceExclusiveAccessGpu() const +{ + if (getFlags() & PxParticleBaseFlag::eGPU) + { + return getScParticleSystem().getDeviceExclusiveAccessGpu(); + } + return NULL; +} + +#endif + +} // namespace Scb + +} + +#endif // PX_USE_PARTICLE_SYSTEM_API + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/buffering/ScbRigidObject.h b/PhysX_3.4/Source/PhysX/src/buffering/ScbRigidObject.h new file mode 100644 index 00000000..e1ea7a43 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/buffering/ScbRigidObject.h @@ -0,0 +1,530 @@ +// 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_SCB_RIGID_OBJECT +#define PX_PHYSICS_SCB_RIGID_OBJECT + +#include "../../SimulationController/include/ScRigidCore.h" +#include "ScbScene.h" +#include "ScbActor.h" +#include "ScbShape.h" +#include "PsInlineArray.h" + +namespace physx +{ + +// base class for dynamic and static rigid objects, so that shapes can have something to refer to + +namespace Scb +{ + +struct RemovedShape +{ + RemovedShape() : mShape(NULL), mWakeTouching(0) {} + RemovedShape(Scb::Shape* s, PxU8 wakeTouching) : mShape(s), mWakeTouching(wakeTouching) {} + + PX_FORCE_INLINE bool operator == (const RemovedShape& other) const + { + return (mShape == other.mShape); + } + + PX_FORCE_INLINE bool operator != (const RemovedShape& other) const + { + return (mShape != other.mShape); + } + + Scb::Shape* mShape; + PxU8 mWakeTouching; +}; + + +struct RigidObjectBuffer : public ActorBuffer //once RigidObject has its own buffered elements, derive from that instead +{ + RigidObjectBuffer(): mResetFilterShape(0), mResetFilterShapeCount(0) {} + + // TODO(dsequeira): ideally we would use an allocator that allocates from the buffered memory stream + Ps::InlineArray<Scb::Shape*, 4> mAddedShapes; + Ps::InlineArray<Scb::RemovedShape, 4> mRemovedShapes; + union + { + PxU32 mResetFilterShapesIdx; + Scb::Shape* mResetFilterShape; + }; + PxU32 mResetFilterShapeCount; + + enum { BF_Base = ActorBuffer::AttrCount }; + + enum + { + BF_Shapes = 1<<BF_Base, + BF_WakeTouching = 1<<(BF_Base+1), + BF_ResetFiltering = 1<<(BF_Base+2) + }; + + enum { AttrCount = ActorBuffer::AttrCount+3 }; +}; + + +class RigidObject : public Scb::Actor +{ +//= 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. +//================================================================================================== + + typedef RigidObjectBuffer Buf; + typedef Sc::RigidCore Core; + +public: +// PX_SERIALIZATION + RigidObject() {} + RigidObject(const PxEMPTY) : Scb::Actor(PxEmpty) {} + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + + //--------------------------------------------------------------------------------- + // Wrapper for Sc::RigidCore interface + //--------------------------------------------------------------------------------- + + PX_INLINE void resetFiltering(Scb::Shape*const* shapes, PxU32 shapeCount); + + + //--------------------------------------------------------------------------------- + // Data synchronization + //--------------------------------------------------------------------------------- + + // the fetchResults order is to process removes, do callbacks, and then do the other synchronization. So we need to split sync'ing of + // adds and removes + // Note: The array of removed shapes must be reset here to avoid memory leaks: even if the control state means we don't process the + // array of removed shapes, we still need to clear the array. + PX_INLINE void processShapeRemoves() + { + if(getBufferFlags() & Buf::BF_Shapes) + { + RigidObjectBuffer* b = getBuffer(); + + if(getControlState() == ControlState::eIN_SCENE) + { +#if PX_SUPPORT_PVD + PxActor& pxActor = *getScRigidCore().getPxActor(); +#endif + for(PxU32 i=0;i<b->mRemovedShapes.size();i++) + { + RemovedShape& rs = b->mRemovedShapes[i]; + Shape& shape = *rs.mShape; + shape.setControlStateIfExclusive(NULL, Scb::ControlState::eNOT_IN_SCENE); + + Sc::RigidCore& rc = getScRigidCore(); + Scb::Scene* scene = getScbScene(); +#if PX_SUPPORT_PVD + scene->getScenePvdClient().releasePvdInstance(&shape, pxActor); +#endif + if (!isSimDisabledInternally()) + { + rc.removeShapeFromScene(shape.getScShape(), (rs.mWakeTouching != 0)); + + shape.checkUpdateOnRemove<true>(scene); + + NpShapeDecRefCount(shape); + } + } + } + + // The array of removed shapes must be reset to avoid memory leaks. + b->mRemovedShapes.reset(); + } + } + + PX_INLINE void syncState() + { + PxU32 bufferFlags = getBufferFlags(); + + if (bufferFlags & Buf::BF_ResetFiltering) + { + PX_ASSERT(getControlState() != ControlState::eREMOVE_PENDING); // removing the actor should have cleared BF_ResetFiltering + + Scb::Scene* scene = getScbScene(); + Sc::RigidCore& scCore = getScRigidCore(); + RigidObjectBuffer* b = getBuffer(); + Scb::Shape* const* shapes = (b->mResetFilterShapeCount == 1) ? &b->mResetFilterShape : scene->getShapeBuffer(b->mResetFilterShapesIdx); + for(PxU32 i=0; i < b->mResetFilterShapeCount; i++) + { + Sc::ShapeCore& scShape = shapes[i]->getScShape(); + + // do not process the call if the shape will not be a broadphase shape any longer + if (shapes[i]->getFlags() & (PxShapeFlag::eSIMULATION_SHAPE | PxShapeFlag::eTRIGGER_SHAPE)) + scCore.onShapeChange(scShape, Sc::ShapeChangeNotifyFlag::eRESET_FILTERING, PxShapeFlags()); + } + } + + if(bufferFlags & Buf::BF_Shapes) + { + RigidObjectBuffer* b = getBuffer(); + ControlState::Enum cs = getControlState(); +#if PX_SUPPORT_PVD + PxActor& pxActor = *getScRigidCore().getPxActor(); +#endif + for(PxU32 i=0;i<b->mAddedShapes.size();i++) + { + Shape& shape = *b->mAddedShapes[i]; + + // it can happen that a shape gets attached while the sim is running but then the actor is removed from the scene, + // so we need to distinguish those two cases + if (cs != ControlState::eREMOVE_PENDING) + { + shape.setControlStateIfExclusive(getScbScene(), Scb::ControlState::eIN_SCENE); + + if (!(getActorFlags() & PxActorFlag::eDISABLE_SIMULATION)) // important to use the buffered flags since we want the new state. + { + getScRigidCore().addShapeToScene(shape.getScShape()); + NpShapeIncRefCount(shape); + } +#if PX_SUPPORT_PVD + getScbScene()->getScenePvdClient().createPvdInstance(&shape, pxActor); +#endif + } + else + shape.setControlStateIfExclusive(getScbScene(), Scb::ControlState::eNOT_IN_SCENE); + } + + // reset the arrays, because destructors don't run on buffers + b->mAddedShapes.reset(); + } + + Actor::syncState(); + } + + PX_FORCE_INLINE void scheduleForWakeTouching() { PX_ASSERT(getScbScene() && getScbScene()->isPhysicsBuffering()); setBufferFlag(RigidObjectBuffer::BF_WakeTouching); } + + //--------------------------------------------------------------------------------- + // Miscellaneous + //--------------------------------------------------------------------------------- +public: + PX_INLINE const Sc::RigidCore& getScRigidCore() const { return static_cast<const Sc::RigidCore&>(getActorCore()); } // Only use if you know what you're doing! + PX_INLINE Sc::RigidCore& getScRigidCore() { return static_cast<Sc::RigidCore&>(getActorCore()); } // Only use if you know what you're doing! + + PX_INLINE void setShapeStateIfExclusive(Scb::Shape& shape, ControlState::Enum cs, Scb::Scene& scene) + { + if(shape.isExclusive()) + { + shape.setScbScene(&scene); + shape.setControlState(cs); + } + } + + PX_INLINE void onShapeAttach(Scb::Shape& shape) + { + // there are two things to do here: add the shape to the sim (if unbuffered) or set it up for + // * if unbuffered, add the shape to the sim and PVD and increment its refcount, else set it up for buffered insertion, + // * if the shape is exclusive, set its Scb control state appropriately. + + ControlState::Enum cs = getControlState(); + if(cs==ControlState::eNOT_IN_SCENE) + return; + + Scene* scbScene = getScbScene(); + if(!scbScene->isPhysicsBuffering()) + { + if (!(getActorFlags() & PxActorFlag::eDISABLE_SIMULATION)) + { + NpShapeIncRefCount(shape); + getScRigidCore().addShapeToScene(shape.getScShape()); + } + +#if PX_SUPPORT_PVD + getScbScene()->getScenePvdClient().createPvdInstance(&shape, *getScRigidCore().getPxActor()); +#endif + shape.setControlStateIfExclusive(scbScene, ControlState::eIN_SCENE); + return; + } + else if (cs == ControlState::eINSERT_PENDING) + { + shape.setControlStateIfExclusive(scbScene, ControlState::eINSERT_PENDING); + return; + } + + RigidObjectBuffer* b = getBuffer(); + if(!b->mRemovedShapes.findAndReplaceWithLast(RemovedShape(&shape, 0))) + b->mAddedShapes.pushBack(&shape); + markUpdated(Buf::BF_Shapes); + + shape.setControlStateIfExclusive(scbScene, ControlState::eINSERT_PENDING); + } + + + PX_INLINE void onShapeDetach(Scb::Shape& shape, bool wakeOnLostTouch, bool toBeReleased) + { + // see comments in onShapeAttach + ControlState::Enum cs = getControlState(); + if(cs==ControlState::eNOT_IN_SCENE) + return; + + Scene* scbScene = getScbScene(); + if(!scbScene->isPhysicsBuffering()) + { +#if PX_SUPPORT_PVD + scbScene->getScenePvdClient().releasePvdInstance(&shape, *getScRigidCore().getPxActor()); +#endif + if (!(getActorFlags() & PxActorFlag::eDISABLE_SIMULATION)) + { + getScRigidCore().removeShapeFromScene(shape.getScShape(), wakeOnLostTouch); + NpShapeDecRefCount(shape); + } + + shape.setControlStateIfExclusive(NULL, ControlState::eNOT_IN_SCENE); + return; + } + else if (cs == ControlState::eINSERT_PENDING) + { + shape.setControlStateIfExclusive(NULL, ControlState::eNOT_IN_SCENE); + return; + } + + RigidObjectBuffer* b = getBuffer(); + + // remove from the resetFiltering list + PxU32 bufferFlags = getBufferFlags(); + if (bufferFlags & Buf::BF_ResetFiltering) + { + if (b->mResetFilterShapeCount == 1) + { + if (b->mResetFilterShape == &shape) + { + b->mResetFilterShapeCount = 0; + b->mResetFilterShape = 0; + resetBufferFlag(Buf::BF_ResetFiltering); + } + } + else + { + Scb::Shape** shapes = scbScene->getShapeBuffer(b->mResetFilterShapesIdx); + PxU32 idx = 0; + PxU32 lastIdx = b->mResetFilterShapeCount; + for(PxU32 k=0; k < b->mResetFilterShapeCount; k++) // need to iterate over whole list, same shape can be in there multiple times + { + if (shapes[idx] != &shape) + idx++; + else + { + lastIdx--; + shapes[idx] = shapes[lastIdx]; + } + } + b->mResetFilterShapeCount = idx; + if (idx == 0) + { + b->mResetFilterShape = 0; + resetBufferFlag(Buf::BF_ResetFiltering); + } + else if (idx == 1) + b->mResetFilterShape = shapes[0]; + } + } + + if(b->mAddedShapes.findAndReplaceWithLast(&shape)) + shape.setControlStateIfExclusive(scbScene, ControlState::eIN_SCENE); + else + { + if (!isSimDisabledInternally()) + { + b->mRemovedShapes.pushBack(RemovedShape(&shape, PxU8(wakeOnLostTouch ? 1 : 0))); + } + else + { + PX_ASSERT(scbScene); + PX_ASSERT(scbScene->isPhysicsBuffering()); + if (toBeReleased) + { + shape.checkUpdateOnRemove<false>(scbScene); +#if PX_SUPPORT_PVD + scbScene->getScenePvdClient().releasePvdInstance(&shape, *getScRigidCore().getPxActor()); +#endif + } + else + b->mRemovedShapes.pushBack(RemovedShape(&shape, 0)); + } + shape.setControlStateIfExclusive(scbScene, ControlState::eREMOVE_PENDING); + } + markUpdated(Buf::BF_Shapes); + } + + PX_INLINE bool isAddedShape(Scb::Shape&); // check whether the specified shape is pending for insertion. Only call this method if you know that there are pending shape adds/removes. + + PX_FORCE_INLINE void switchToNoSim(bool isDynamic); + PX_FORCE_INLINE void switchFromNoSim(bool isDynamic); + PX_FORCE_INLINE void syncNoSimSwitch(const Buf& buf, Sc::RigidCore& rc, bool isDynamic); + + // IMPORTANT: This is the non-buffered state, for the case where it is important to know what the current internal state is. + // Reading is fine even if the sim is running because actor flags are read-only internally. + PX_FORCE_INLINE bool isSimDisabledInternally() const { return getScRigidCore().getActorFlags().isSet(PxActorFlag::eDISABLE_SIMULATION); } + + PX_FORCE_INLINE void clearBufferedState() { resetBufferFlag(Buf::BF_ResetFiltering); } + + PX_FORCE_INLINE static const RigidObject& fromSc(const Sc::RigidCore& a) { return static_cast<const RigidObject&>(Actor::fromSc(a)); } + PX_FORCE_INLINE static RigidObject& fromSc(Sc::RigidCore &a) { return static_cast<RigidObject&>(Actor::fromSc(a)); } +protected: + ~RigidObject() {} +private: + Buf* getBuffer() { return reinterpret_cast<Buf*>(getStream()); } + + PX_FORCE_INLINE void copyResetFilterShapes(Scb::Shape** shapePtrs, Scb::Shape*const* oldShapes, PxU32 oldShapeCount, Scb::Shape*const* newShapes, PxU32 newShapeCount); +}; + + +PX_INLINE void RigidObject::resetFiltering(Scb::Shape*const* shapes, PxU32 shapeCount) +{ + PX_ASSERT(!(getActorFlags() & PxActorFlag::eDISABLE_SIMULATION)); + + if(!isBuffering()) + { + for(PxU32 i=0; i < shapeCount; i++) + getScRigidCore().onShapeChange(shapes[i]->getScShape(), Sc::ShapeChangeNotifyFlag::eRESET_FILTERING, PxShapeFlags()); + } + else + { + RigidObjectBuffer* b = getBuffer(); + + if (b->mResetFilterShapeCount == 0) + { + if (shapeCount == 1) + { + b->mResetFilterShape = shapes[0]; + b->mResetFilterShapeCount = 1; + markUpdated(Buf::BF_ResetFiltering); + } + else + { + PxU32 bufferIdx; + Scb::Shape** shapePtrs = getScbScene()->allocShapeBuffer(shapeCount, bufferIdx); + if (shapePtrs) + { + for(PxU32 i=0; i < shapeCount; i++) + shapePtrs[i] = shapes[i]; + b->mResetFilterShapesIdx = bufferIdx; + b->mResetFilterShapeCount = shapeCount; + markUpdated(Buf::BF_ResetFiltering); + } + } + } + else + { + PxU32 newCount = b->mResetFilterShapeCount + shapeCount; + PxU32 bufferIdx; + Scb::Shape** shapePtrs = getScbScene()->allocShapeBuffer(newCount, bufferIdx); + if (shapePtrs) + { + if (b->mResetFilterShapeCount == 1) + copyResetFilterShapes(shapePtrs, &b->mResetFilterShape, 1, shapes, shapeCount); + else + copyResetFilterShapes(shapePtrs, getScbScene()->getShapeBuffer(b->mResetFilterShapesIdx), b->mResetFilterShapeCount, shapes, shapeCount); + b->mResetFilterShapesIdx = bufferIdx; + b->mResetFilterShapeCount = newCount; + markUpdated(Buf::BF_ResetFiltering); + } + } + } +} + + +PX_INLINE bool RigidObject::isAddedShape(Scb::Shape& shape) +{ + PX_ASSERT(isBuffered(Buf::BF_Shapes)); + + if (shape.isExclusive()) + { + return (shape.getControlState() == Scb::ControlState::eINSERT_PENDING); + } + else + { + // For shared shapes it is not clear from the shape alone whether it has been added while the simulation was running. + + RigidObjectBuffer* buf = getBuffer(); + PX_ASSERT(buf); + const PxU32 addedShapeCount = buf->mAddedShapes.size(); + for(PxU32 k=0; k < addedShapeCount; k++) + { + if (&shape == buf->mAddedShapes[k]) + { + return true; + } + } + + return false; + } +} + + +PX_FORCE_INLINE void RigidObject::switchToNoSim(bool isDynamic) +{ + Scb::Scene* scene = getScbScene(); + + if (scene && (!scene->isPhysicsBuffering())) + scene->switchRigidToNoSim(*this, isDynamic); +} + + +PX_FORCE_INLINE void RigidObject::switchFromNoSim(bool isDynamic) +{ + Scb::Scene* scene = getScbScene(); + + if (scene && (!scene->isPhysicsBuffering())) + scene->switchRigidFromNoSim(*this, isDynamic); +} + + +PX_FORCE_INLINE void RigidObject::syncNoSimSwitch(const Buf& buf, Sc::RigidCore& rc, bool isDynamic) +{ + PxActorFlags oldFlags = rc.getActorFlags(); + bool oldNoSim = oldFlags.isSet(PxActorFlag::eDISABLE_SIMULATION); + bool newNoSim = buf.mActorFlags.isSet(PxActorFlag::eDISABLE_SIMULATION); + + if (oldNoSim && (!newNoSim)) + getScbScene()->switchRigidFromNoSim(*this, isDynamic); + else if ((!oldNoSim) && newNoSim) + getScbScene()->switchRigidToNoSim(*this, isDynamic); +} + + +PX_FORCE_INLINE void RigidObject::copyResetFilterShapes(Scb::Shape** shapePtrs, Scb::Shape*const* oldShapes, PxU32 oldShapeCount, Scb::Shape*const* newShapes, PxU32 newShapeCount) +{ + for(PxU32 i=0; i < oldShapeCount; i++) + shapePtrs[i] = oldShapes[i]; + for(PxU32 i=0; i < newShapeCount; i++) + shapePtrs[i+oldShapeCount] = newShapes[i]; +} + + +} // namespace Scb + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/buffering/ScbRigidStatic.h b/PhysX_3.4/Source/PhysX/src/buffering/ScbRigidStatic.h new file mode 100644 index 00000000..d783f203 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/buffering/ScbRigidStatic.h @@ -0,0 +1,155 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-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_SCB_RIGID_STATIC +#define PX_PHYSICS_SCB_RIGID_STATIC + +#include "ScStaticCore.h" +#include "ScbScene.h" +#include "ScbActor.h" +#include "ScbRigidObject.h" + +namespace physx +{ + +namespace Scb +{ + +#if PX_VC + #pragma warning(push) + #pragma warning( disable : 4324 ) // Padding was added at the end of a structure because of a __declspec(align) value. +#endif + +struct RigidStaticBuffer : public RigidObjectBuffer +{ + template <PxU32 I, PxU32 Dummy> struct Fns {}; // TODO: make the base class traits visible + typedef Sc::StaticCore Core; + typedef RigidStaticBuffer Buf; + + // regular attributes + enum { BF_Base = RigidObjectBuffer::AttrCount }; + SCB_REGULAR_ATTRIBUTE_ALIGNED(BF_Base, PxTransform, Actor2World, 16) +}; + +#if PX_VC + #pragma warning(pop) +#endif + + +class RigidStatic : public Scb::RigidObject +{ +//= 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. +//================================================================================================== + + typedef RigidStaticBuffer Buf; + typedef Sc::StaticCore Core; + +public: +// PX_SERIALIZATION + RigidStatic(const PxEMPTY) : Scb::RigidObject(PxEmpty), mStatic(PxEmpty) {} + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + PX_INLINE RigidStatic(const PxTransform& actor2World); + PX_INLINE ~RigidStatic() {} + + PX_INLINE const PxTransform& getActor2World() const { return read<Buf::BF_Actor2World>(); } + PX_INLINE void setActor2World(const PxTransform& m) { write<Buf::BF_Actor2World>(m); } + + PX_FORCE_INLINE void onOriginShift(const PxVec3& shift) { mStatic.onOriginShift(shift); } + + //--------------------------------------------------------------------------------- + // Data synchronization + //--------------------------------------------------------------------------------- + PX_INLINE void syncState(); + + static size_t getScOffset() + { + return reinterpret_cast<size_t>(&reinterpret_cast<RigidStatic*>(0)->mStatic); + } + + PX_FORCE_INLINE Sc::StaticCore& getScStatic() { return mStatic; } + + PX_FORCE_INLINE void initBufferedState() {} + +private: + Sc::StaticCore mStatic; + + PX_FORCE_INLINE const Buf* getRigidActorBuffer() const { return reinterpret_cast<const Buf*>(getStream()); } + PX_FORCE_INLINE Buf* getRigidActorBuffer() { return reinterpret_cast<Buf*>(getStream()); } + + //--------------------------------------------------------------------------------- + // Infrastructure for regular attributes + //--------------------------------------------------------------------------------- + + struct Access: public BufferedAccess<Buf, Core, RigidStatic> {}; + + template<PxU32 f> PX_FORCE_INLINE typename Buf::Fns<f,0>::Arg read() const { return Access::read<Buf::Fns<f,0> >(*this, mStatic); } + template<PxU32 f> PX_FORCE_INLINE void write(typename Buf::Fns<f,0>::Arg v) { Access::write<Buf::Fns<f,0> >(*this, mStatic, v); } + template<PxU32 f> PX_FORCE_INLINE void flush(const Buf& buf) { Access::flush<Buf::Fns<f,0> >(*this, mStatic, buf); } + +}; + +RigidStatic::RigidStatic(const PxTransform& actor2World) : + mStatic(actor2World) +{ + setScbType(ScbType::RIGID_STATIC); +} + + +//-------------------------------------------------------------- +// +// Data synchronization +// +//-------------------------------------------------------------- + +PX_INLINE void RigidStatic::syncState() +{ + PxU32 bufferFlags = getBufferFlags(); + + if (bufferFlags & Buf::BF_ActorFlags) + syncNoSimSwitch(*getRigidActorBuffer(), mStatic, false); + + RigidObject::syncState(); + + if (bufferFlags & Buf::BF_Actor2World) + flush<Buf::BF_Actor2World>(*getRigidActorBuffer()); + + postSyncState(); +} + +} // namespace Scb + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/buffering/ScbScene.cpp b/PhysX_3.4/Source/PhysX/src/buffering/ScbScene.cpp new file mode 100644 index 00000000..0d0ac638 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/buffering/ScbScene.cpp @@ -0,0 +1,1514 @@ +// 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 "NpCast.h" +#include "ScbScene.h" +#include "ScbRigidStatic.h" +#include "ScbBody.h" +#include "ScbShape.h" +#include "ScbConstraint.h" +#include "ScbParticleSystem.h" +#include "ScbArticulation.h" +#include "ScbArticulationJoint.h" +#include "ScbCloth.h" +#include "ScbNpDeps.h" +#include "ScbAggregate.h" + +#include "PsFoundation.h" +#include "PxArticulation.h" + +namespace physx +{ + class NpMaterial; +} + +using namespace physx; + +// constants to make boolean template parameters more readable +static const bool tSimRunning = true; +static const bool tAdd = true; +static const bool tDynamic = true; +static const bool tNonSimObject = true; +static const bool tSyncOnRemove = true; +static const bool tWakeOnLostTouchCheck = true; + +void Scb::ObjectTracker::scheduleForInsert(Scb::Base& element) +{ + ControlState::Enum state = element.getControlState(); + PxU32 flags = element.getControlFlags(); + PX_ASSERT(!(flags & ControlFlag::eIS_RELEASED)); + PX_ASSERT(state == ControlState::eNOT_IN_SCENE || state == ControlState::eREMOVE_PENDING); + + if(state == ControlState::eREMOVE_PENDING) + { + element.setControlState(ControlState::eIN_SCENE); + if(!(flags & ControlFlag::eIS_UPDATED)) + remove(element); + } + else + { + PX_ASSERT(!(flags & ControlFlag::eIS_UPDATED)); + element.setControlState(ControlState::eINSERT_PENDING); + insert(element); + } +} + +void Scb::ObjectTracker::scheduleForRemove(Scb::Base& element) +{ + ControlState::Enum state = element.getControlState(); + PxU32 flags = element.getControlFlags(); + + PX_ASSERT(!(flags & ControlFlag::eIS_RELEASED)); + + if(state == ControlState::eINSERT_PENDING) + { + // if it's inserted this frame, just remove it - it can't be dirty + //ML: this assert wont' work because buffered insert raises this flag. We have a unit test which called TEST_F(ObserverTest, OnRelease) to verify it + //PX_ASSERT(!(flags & ControlFlag::eIS_UPDATED)); + element.setControlState(ControlState::eNOT_IN_SCENE); + remove(element); + } + else if(state == ControlState::eIN_SCENE) + { + element.setControlState(ControlState::eREMOVE_PENDING); + if(!(flags & ControlFlag::eIS_UPDATED)) + insert(element); + } + else + { + PX_ALWAYS_ASSERT_MESSAGE("Trying to remove element not in scene."); + } +} + +void Scb::ObjectTracker::scheduleForUpdate(Scb::Base& element) +{ + ControlState::Enum state = element.getControlState(); + PxU32 flags = element.getControlFlags(); + + PX_ASSERT(!(flags & ControlFlag::eIS_RELEASED)); + PX_ASSERT(state == ControlState::eIN_SCENE || state == ControlState::eREMOVE_PENDING || state == ControlState::eINSERT_PENDING); + + if(!(flags & ControlFlag::eIS_UPDATED)) + { + element.setControlFlag(ControlFlag::eIS_UPDATED); + if(state == ControlState::eIN_SCENE) + insert(element); + } +} + +void Scb::ObjectTracker::clear() +{ + Scb::Base *const * elements = mBuffered.getEntries(); + for(PxU32 i=0;i<mBuffered.size();i++) + { + ControlState::Enum state = elements[i]->getControlState(); + PxU32 flags = elements[i]->getControlFlags(); + + if(state == ControlState::eIN_SCENE || state == ControlState::eINSERT_PENDING) + elements[i]->resetControl(ControlState::eIN_SCENE); + else + { + elements[i]->resetControl(ControlState::eNOT_IN_SCENE); + elements[i]->resetScbScene(); + } + + if(flags & ControlFlag::eIS_RELEASED) + NpDestroy(*elements[i]); + } + mBuffered.clear(); +} + +void Scb::ObjectTracker::insert(Scb::Base& element) +{ + PX_ASSERT(!mBuffered.contains(&element)); + mBuffered.insert(&element); +} + +void Scb::ObjectTracker::remove(Scb::Base& element) +{ + mBuffered.erase(&element); +} + +/////////////////////////////////////////////////////////////////////////////// + +template <bool TSimRunning, bool TAdd, bool TIsDynamic, bool TIsNonSimObject, class T> +PX_FORCE_INLINE static void addOrRemoveRigidObject(Sc::Scene& s, T& rigidObject, bool wakeOnLostTouch, PxBounds3* uninflatedBounds); + +template <typename T>struct ScSceneFns {}; + +template<> struct ScSceneFns<Scb::Articulation> +{ + static PX_FORCE_INLINE void insert(Sc::Scene& s, Scb::Articulation& v, PxBounds3*) + { + Scb::Body* b = NpArticulationGetRootFromScb(v); + s.addArticulation(v.getScArticulation(), b->getScBody()); + } + static PX_FORCE_INLINE void remove(Sc::Scene& s, Scb::Articulation& v, bool wakeOnLostTouch) + { + PX_UNUSED(wakeOnLostTouch); + + v.clearBufferedSleepStateChange(); // see comment in remove code of Scb::Body + + s.removeArticulation(v.getScArticulation()); + } +}; + +template<> struct ScSceneFns<Scb::ArticulationJoint> +{ + static PX_FORCE_INLINE void insert(Sc::Scene& s, Scb::ArticulationJoint& v, PxBounds3*) + { + Scb::Body* scb0, * scb1; + NpArticulationJointGetBodiesFromScb(v, scb0, scb1); + s.addArticulationJoint(v.getScArticulationJoint(), scb0->getScBody(), scb1->getScBody()); + } + static PX_FORCE_INLINE void remove(Sc::Scene& s, Scb::ArticulationJoint& v, bool wakeOnLostTouch) { PX_UNUSED(wakeOnLostTouch); s.removeArticulationJoint(v.getScArticulationJoint()); } +}; + +template<> struct ScSceneFns<Scb::Constraint> +{ + static PX_FORCE_INLINE void insert(Sc::Scene& s, Scb::Constraint& v, PxBounds3*) + { + Scb::RigidObject* scb0, * scb1; + NpConstraintGetRigidObjectsFromScb(v, scb0, scb1); + + PX_ASSERT((!scb0) || (!(scb0->getActorFlags() & PxActorFlag::eDISABLE_SIMULATION))); + PX_ASSERT((!scb1) || (!(scb1->getActorFlags() & PxActorFlag::eDISABLE_SIMULATION))); + + s.addConstraint(v.getScConstraint(), scb0 ? &scb0->getScRigidCore() : NULL, scb1 ? &scb1->getScRigidCore() : NULL); + } + static PX_FORCE_INLINE void remove(Sc::Scene& s, Scb::Constraint& v, bool wakeOnLostTouch) + { + PX_UNUSED(wakeOnLostTouch); + s.removeConstraint(v.getScConstraint()); + } +}; + +template<> struct ScSceneFns<Scb::RigidStatic> +{ + static PX_FORCE_INLINE void insert(Sc::Scene& s, Scb::RigidStatic& v, PxBounds3* uninflatedBounds) + { + // important to use the buffered flags because for a pending insert those describe the end state the + // user expects. + + if (!(v.getActorFlags() & PxActorFlag::eDISABLE_SIMULATION)) + addOrRemoveRigidObject<!tSimRunning, tAdd, !tDynamic, !tNonSimObject>(s, v, false, uninflatedBounds); + else + addOrRemoveRigidObject<!tSimRunning, tAdd, !tDynamic, tNonSimObject>(s, v, false, uninflatedBounds); + } + static PX_FORCE_INLINE void remove(Sc::Scene& s, Scb::RigidStatic& v, bool wakeOnLostTouch) + { + // important to use the original flags because for a pending removal those describe the original state that needs + // to get cleaned up. + + if (!v.isSimDisabledInternally()) + addOrRemoveRigidObject<!tSimRunning, !tAdd, !tDynamic, !tNonSimObject>(s, v, wakeOnLostTouch, NULL); + else + addOrRemoveRigidObject<!tSimRunning, !tAdd, !tDynamic, tNonSimObject>(s, v, false, NULL); + } +}; + +template<> struct ScSceneFns<Scb::Body> +{ + static PX_FORCE_INLINE void insert(Sc::Scene& s, Scb::Body& v, PxBounds3* uninflatedBounds) + { + // see comments in rigid static case + if (!(v.getActorFlags() & PxActorFlag::eDISABLE_SIMULATION)) + addOrRemoveRigidObject<!tSimRunning, tAdd, tDynamic, !tNonSimObject>(s, v, false, uninflatedBounds); + else + addOrRemoveRigidObject<!tSimRunning, tAdd, tDynamic, tNonSimObject>(s, v, false, uninflatedBounds); + } + static PX_FORCE_INLINE void remove(Sc::Scene& s, Scb::Body& v, bool wakeOnLostTouch) + { + // strictly speaking, the following is only necessary for pending removes but it does not have a + // functional side effect if applied all the time. + // When an object gets removed from the scene, pending wakeUp/putToSleep events should be ignored because + // the internal sleep state for a free standing object is specified as sleeping. All the other parameter changes + // that go along with a sleep state change should still get processed though (zero vel, zero wake counter on + // putToSleep for example). Those are not affected because they are tracked through buffered updates + // of the velocity and wake counter. + // The clearing happens here because only here we are sure that the object does get removed for real. At earlier + // stages someone might remove and then re-insert and object and for such cases it is important to keep the + // sleep state change buffered. + v.clearBufferedSleepStateChange(); + + // see comments in rigid static case + if (!v.isSimDisabledInternally()) + addOrRemoveRigidObject<!tSimRunning, !tAdd, tDynamic, !tNonSimObject>(s, v, wakeOnLostTouch, NULL); + else + addOrRemoveRigidObject<!tSimRunning, !tAdd, tDynamic, tNonSimObject>(s, v, false, NULL); + } +}; + +#if PX_USE_PARTICLE_SYSTEM_API +template<> struct ScSceneFns<Scb::ParticleSystem> +{ + static PX_FORCE_INLINE void insert(Sc::Scene& s, Scb::ParticleSystem& v, PxBounds3*) { s.addParticleSystem(v.getScParticleSystem()); } + static PX_FORCE_INLINE void remove(Sc::Scene& s, Scb::ParticleSystem& v, bool wakeOnLostTouch) { PX_UNUSED(wakeOnLostTouch); s.removeParticleSystem(v.getScParticleSystem(), (v.getControlFlags() & Scb::ControlFlag::eIS_RELEASED) != 0); } +}; +#endif + +#if PX_USE_CLOTH_API +template<> struct ScSceneFns<Scb::Cloth> +{ +// static PX_FORCE_INLINE void insert(Sc::Scene& s, Scb::Cloth& v) { s.addRigidObject(v.getScCloth()); } + static PX_FORCE_INLINE void remove(Sc::Scene& s, Scb::Cloth& v, bool wakeOnLostTouch) { PX_UNUSED(wakeOnLostTouch); s.removeCloth(v.getScCloth()); } +}; +#endif + +/////////////////////////////////////////////////////////////////////////////// +#if PX_SUPPORT_PVD +template<typename T> struct PvdFns +{ + // PT: in the following functions, checkPvdDebugFlag() is done by the callers to save time when functions are called from a loop. + + static void createInstance(Scb::Scene& scene, Vd::ScbScenePvdClient& d, T* v) + { + PX_PROFILE_ZONE("PVD.createPVDInstance", scene.getContextId()); + PX_UNUSED(scene); + d.createPvdInstance(v); + } + + static void updateInstance(Scb::Scene& scene, Vd::ScbScenePvdClient& d, T* v) + { + PX_UNUSED(scene); + if(((v->getControlFlags() & Scb::ControlFlag::eIS_RELEASED) == 0) && (v->getControlState() != Scb::ControlState::eREMOVE_PENDING)) + { + PX_PROFILE_ZONE("PVD.updatePVDProperties", scene.getContextId()); + d.updatePvdProperties(v); + } + } + + static void releaseInstance(Scb::Scene& scene, Vd::ScbScenePvdClient& d, T* v) + { + PX_UNUSED(scene); + PX_PROFILE_ZONE("PVD.releasePVDInstance", scene.getContextId()); + d.releasePvdInstance(v); + } +}; + + #define CREATE_PVD_INSTANCE(obj) \ + { \ + if(mScenePvdClient.checkPvdDebugFlag()) \ + { \ + PX_PROFILE_ZONE("PVD.createPVDInstance", getContextId());\ + mScenePvdClient.createPvdInstance(obj); \ + } \ + } + #define RELEASE_PVD_INSTANCE(obj) \ + { \ + if(mScenePvdClient.checkPvdDebugFlag()) \ + { \ + PX_PROFILE_ZONE("PVD.releasePVDInstance", getContextId());\ + mScenePvdClient.releasePvdInstance(obj); \ + } \ + } + #define UPDATE_PVD_PROPERTIES(obj) \ + { \ + if(mScenePvdClient.checkPvdDebugFlag()) \ + { \ + PX_PROFILE_ZONE("PVD.updatePVDProperties", getContextId());\ + mScenePvdClient.updatePvdProperties(obj); \ + } \ + } + #define PVD_ORIGIN_SHIFT(shift) \ + { \ + if(mScenePvdClient.checkPvdDebugFlag()) \ + { \ + PX_PROFILE_ZONE("PVD.originShift", getContextId());\ + mScenePvdClient.originShift(shift); \ + } \ + } +#else + #define CREATE_PVD_INSTANCE(obj) {} + #define RELEASE_PVD_INSTANCE(obj) {} + #define UPDATE_PVD_PROPERTIES(obj) {} + #define PVD_ORIGIN_SHIFT(shift){} +#endif + +/////////////////////////////////////////////////////////////////////////////// + +Scb::Scene::Scene(const PxSceneDesc& desc, PxU64 contextID) : + mScene (desc, contextID), + mSimulationRunning (false), + mIsBuffering (false), + mStream (16384), + mShapeMaterialBuffer (PX_DEBUG_EXP("shapeMaterialBuffer")), + mShapePtrBuffer (PX_DEBUG_EXP("shapePtrBuffer")), + mActorPtrBuffer (PX_DEBUG_EXP("actorPtrBuffer")), +#if PX_SUPPORT_PVD + mScenePvdClient (*this), +#endif + mWakeCounterResetValue (desc.wakeCounterResetValue), + mBufferFlags (0) +{ +} + +void Scb::Scene::release() +{ +#if PX_SUPPORT_PVD + mScenePvdClient.releasePvdInstance(); +#endif + mScene.release(); + mShapeMaterialBuffer.clear(); + mShapePtrBuffer.clear(); + mActorPtrBuffer.clear(); + mStream.clear(); +} + +// PT: TODO: inline this +PxScene* Scb::Scene::getPxScene() +{ + return const_cast<NpScene*>(getNpScene(this)); +} + +/////////////////////////////////////////////////////////////////////////////// +template<typename T> +void Scb::Scene::add(T& v, ObjectTracker &tracker, PxBounds3* uninflatedBounds) +{ + v.setScbScene(this); + + if (!mIsBuffering) + { + v.resetControl(ControlState::eIN_SCENE); + ScSceneFns<T>::insert(mScene, v, uninflatedBounds); +#if PX_SUPPORT_PVD + if(mScenePvdClient.checkPvdDebugFlag()) + PvdFns<T>::createInstance(*this, mScenePvdClient, &v); +#endif + } + else + tracker.scheduleForInsert(v); +} + +template<typename T> +void Scb::Scene::remove(T& v, ObjectTracker &tracker, bool wakeOnLostTouch) +{ + if (!mIsBuffering) + { + ScSceneFns<T>::remove(mScene, v, wakeOnLostTouch); +#if PX_SUPPORT_PVD + if(mScenePvdClient.checkPvdDebugFlag()) + PvdFns<T>::releaseInstance(*this, mScenePvdClient, &v); +#endif + v.resetControl(ControlState::eNOT_IN_SCENE); + v.setScbScene(NULL); + } + else + { + tracker.scheduleForRemove(v); + } +} + + +/////////////////////////////////////////////////////////////////////////////// + +template<bool TIsDynamic, class T> +void Scb::Scene::addRigidNoSim(T& v, ObjectTracker &tracker) +{ + PX_ASSERT(v.getActorFlags() & PxActorFlag::eDISABLE_SIMULATION); + v.setScbScene(this); + + if (!mIsBuffering) + { + v.resetControl(ControlState::eIN_SCENE); +#if PX_SUPPORT_PVD + if(mScenePvdClient.checkPvdDebugFlag()) + PvdFns<T>::createInstance(*this, mScenePvdClient, &v); +#endif + addOrRemoveRigidObject<!tSimRunning, tAdd, TIsDynamic, tNonSimObject>(mScene, v, false, NULL); + } + else + { + tracker.scheduleForInsert(v); + addOrRemoveRigidObject<tSimRunning, tAdd, TIsDynamic, tNonSimObject>(mScene, v, false, NULL); + } +} + + +template<bool TIsDynamic, class T> +void Scb::Scene::removeRigidNoSim(T& v, ObjectTracker &tracker) +{ + PX_ASSERT(v.isSimDisabledInternally()); + + if (!mIsBuffering) + { + addOrRemoveRigidObject<!tSimRunning, !tAdd, TIsDynamic, tNonSimObject>(mScene, v, false, NULL); +#if PX_SUPPORT_PVD + if(mScenePvdClient.checkPvdDebugFlag()) + PvdFns<T>::releaseInstance(*this, mScenePvdClient, &v); +#endif + v.resetControl(ControlState::eNOT_IN_SCENE); + v.setScbScene(NULL); + } + else + { + tracker.scheduleForRemove(v); + addOrRemoveRigidObject<tSimRunning, !tAdd, TIsDynamic, tNonSimObject>(mScene, v, false, NULL); + } +} + + +void Scb::Scene::switchRigidToNoSim(Scb::RigidObject& r, bool isDynamic) +{ + PX_ASSERT(!mIsBuffering); + + // when a simulation objects has a pending remove and then gets switched to a non-simulation object, + // we must not process the code below. On sync the object will get removed before this call. + if (r.getControlState() == ControlState::eIN_SCENE) + { + size_t ptrOffset = -Scb::Shape::getScOffset(); + Ps::InlineArray<const Sc::ShapeCore*, 64> scShapes; + + if (isDynamic) + mScene.removeBody(static_cast<Sc::BodyCore&>(r.getScRigidCore()), scShapes, true); + else + mScene.removeStatic(static_cast<Sc::StaticCore&>(r.getScRigidCore()), scShapes, true); + + // not in simulation anymore -> decrement shape ref-counts + void* const* shapes = reinterpret_cast<void*const*>(const_cast<Sc::ShapeCore*const*>(scShapes.begin())); + for(PxU32 i=0; i < scShapes.size(); i++) + { + Scb::Shape& scbShape = *Ps::pointerOffset<Scb::Shape*>(shapes[i], ptrdiff_t(ptrOffset)); + NpShapeDecRefCount(scbShape); + } + } +} + + +void Scb::Scene::switchRigidFromNoSim(Scb::RigidObject& r, bool isDynamic) +{ + PX_ASSERT(!mIsBuffering); + + // when a non-simulation objects has a pending remove and then gets switched to a simulation object, + // we must not process the code below. On sync the object will get removed before this call. + if (r.getControlState() == ControlState::eIN_SCENE) + { + void* const* shapes; + size_t shapePtrOffset = NpShapeGetScPtrOffset(); + size_t ptrOffset = shapePtrOffset - Scb::Shape::getScOffset(); + + PxU32 nbShapes; + if (isDynamic) + { + nbShapes = NpRigidDynamicGetShapes(static_cast<Scb::Body&>(r), shapes); + mScene.addBody(static_cast<Sc::BodyCore&>(r.getScRigidCore()), shapes, nbShapes, shapePtrOffset, NULL); + } + else + { + nbShapes = NpRigidStaticGetShapes(static_cast<Scb::RigidStatic&>(r), shapes); + mScene.addStatic(static_cast<Sc::StaticCore&>(r.getScRigidCore()), shapes, nbShapes, shapePtrOffset, NULL); + } + + // add to simulation -> increment shape ref-counts + for(PxU32 i=0; i < nbShapes; i++) + { + Scb::Shape& scbShape = *Ps::pointerOffset<Scb::Shape*>(shapes[i], ptrdiff_t(ptrOffset)); + NpShapeIncRefCount(scbShape); + } + } +} + + +/////////////////////////////////////////////////////////////////////////////// + +// PT: TODO: +// - consider making these templates not scene member functions + +template<bool TIsDynamic, class T> +PX_FORCE_INLINE void Scb::Scene::addActorT(T& actor, Scb::ObjectTracker& tracker, bool noSim, PxBounds3* uninflatedBounds) +{ + PX_PROFILE_ZONE("API.addActorToSim", getContextId()); + if(!noSim) + { + add<T>(actor, tracker, uninflatedBounds); + actor.initBufferedState(); + + // copy buffer control state from rigid object to shapes and set scene + if(mIsBuffering) + addOrRemoveRigidObject<tSimRunning, tAdd, TIsDynamic, !tNonSimObject>(mScene, actor, false, NULL); + } + else + { + addRigidNoSim<TIsDynamic>(actor, tracker); + actor.initBufferedState(); + } +} + +void Scb::Scene::addActor(Scb::RigidStatic& rigidStatic, bool noSim, PxBounds3* uninflatedBounds) +{ + addActorT<false>(rigidStatic, mRigidStaticManager, noSim, uninflatedBounds); +} + +void Scb::Scene::addActor(Scb::Body& body, bool noSim, PxBounds3* uninflatedBounds) +{ + addActorT<true>(body, mBodyManager, noSim, uninflatedBounds); +} + +/////////////////////////////////////////////////////////////////////////////// + +void Scb::Scene::removeActor(Scb::RigidStatic& rigidStatic, bool wakeOnLostTouch, bool noSim) +{ + PX_PROFILE_ZONE("API.removeActorFromSim", getContextId()); + if (!noSim) + { + remove<Scb::RigidStatic>(rigidStatic, mRigidStaticManager, wakeOnLostTouch); + + // copy buffer control state from rigid object to shapes and set scene + if (mIsBuffering) + { + if (wakeOnLostTouch) + rigidStatic.scheduleForWakeTouching(); + addOrRemoveRigidObject<tSimRunning, !tAdd, !tDynamic, !tNonSimObject>(mScene, rigidStatic, wakeOnLostTouch, NULL); + } + } + else + { + removeRigidNoSim<!tDynamic>(rigidStatic, mRigidStaticManager); + } + + rigidStatic.clearBufferedState(); +} + +void Scb::Scene::removeActor(Scb::Body& body, bool wakeOnLostTouch, bool noSim) +{ + PX_PROFILE_ZONE("API.removeActorFromSim", getContextId()); + if (!noSim) + { + body.clearSimStateDataForPendingInsert(); + + remove<Scb::Body>(body, mBodyManager, wakeOnLostTouch); + body.clearBufferedState(); + + // copy buffer control state from rigid object to shapes and set scene + if (mIsBuffering) + { + if (wakeOnLostTouch) + body.scheduleForWakeTouching(); + addOrRemoveRigidObject<tSimRunning, !tAdd, tDynamic, !tNonSimObject>(mScene, body, wakeOnLostTouch, NULL); + } + } + else + { + removeRigidNoSim<tDynamic>(body, mBodyManager); + + // note: "noSim" refers to the internal state here. The following asserts only apply if the bufferd state has not switched to "sim". + PX_ASSERT(!(body.getActorFlags() & PxActorFlag::eDISABLE_SIMULATION) || body.isSleeping()); + PX_ASSERT(!(body.getActorFlags() & PxActorFlag::eDISABLE_SIMULATION) || !body.isBuffered(BodyBuffer::BF_KinematicTarget | BodyBuffer::BF_Acceleration | BodyBuffer::BF_DeltaVelocity)); + // What about velocity, wakeCounter, ...? + // Those are not allowed on a no-sim object, however, they might still be necessary due to complex buffering scenarios: + // Imagine the following operation flow (all buffered): + // - dynamic sim object awake with velocities + // - switch to no-sim -> needs to clear velocities, wake counter, put to sleep, ... + // - switch back to sim -> the velocities, wake counter, ... still need to get cleared and it needs to be asleep (that would be the non-buffered behavior of the operations) + + body.clearBufferedState(); // this also covers the buffered case where a noSim object gets switched to a sim object, followed by a wakeUp() call and then a remove. + // If we checked whether the buffered object is still a noSim object then only body.RigidObject::clearBufferedState() would be necessary. + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void Scb::Scene::addConstraint(Scb::Constraint& constraint) +{ + add<Scb::Constraint>(constraint, mConstraintManager, NULL); +} + +void Scb::Scene::removeConstraint(Scb::Constraint& constraint) +{ + if (!mIsBuffering) + { + mScene.removeConstraint(constraint.getScConstraint()); + + // Release pvd constraint immediately since delayed removal with already released ext::joints does not work, can't call callback. + if(constraint.getControlState() != ControlState::eINSERT_PENDING) + RELEASE_PVD_INSTANCE(&constraint) + + constraint.resetControl(ControlState::eNOT_IN_SCENE); + constraint.setScbScene(NULL); + } + else + { + mConstraintManager.scheduleForRemove(constraint); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void Scb::Scene::addArticulation(Scb::Articulation& articulation) +{ + add<Scb::Articulation>(articulation, mArticulationManager, NULL); + articulation.initBufferedState(); +} + +void Scb::Scene::removeArticulation(Scb::Articulation& articulation) +{ + remove<Scb::Articulation>(articulation, mArticulationManager); + articulation.clearBufferedState(); +} + +/////////////////////////////////////////////////////////////////////////////// + +void Scb::Scene::addArticulationJoint(Scb::ArticulationJoint& joint) +{ + add<Scb::ArticulationJoint>(joint, mArticulationJointManager, NULL); +} + +void Scb::Scene::removeArticulationJoint(Scb::ArticulationJoint& joint) +{ + remove<Scb::ArticulationJoint>(joint, mArticulationJointManager); +} + +/////////////////////////////////////////////////////////////////////////////// + +void Scb::Scene::addAggregate(Scb::Aggregate& agg) +{ + agg.setScbScene(this); + + if (!mIsBuffering) + { + PxU32 aggregateID = mScene.createAggregate(agg.mPxAggregate, agg.getSelfCollide()); + agg.setAggregateID(aggregateID); + agg.resetControl(ControlState::eIN_SCENE); +#if PX_SUPPORT_PVD + //Sending pvd events after all aggregates's actors are inserted into scene + mScenePvdClient.createPvdInstance(&agg); +#endif + } + else + mAggregateManager.scheduleForInsert(agg); +} + + +void Scb::Scene::removeAggregate(Scb::Aggregate& agg) +{ + if (!mIsBuffering) + { + mScene.deleteAggregate(agg.getAggregateID()); + agg.resetControl(ControlState::eNOT_IN_SCENE); + agg.setScbScene(NULL); +#if PX_SUPPORT_PVD + mScenePvdClient.releasePvdInstance(&agg); +#endif + } + else + { + mAggregateManager.scheduleForRemove(agg); + } +} + + +void Scb::Scene::addMaterial(const Sc::MaterialCore& material) +{ + Ps::Mutex::ScopedLock lock(mSceneMaterialBufferLock); + + mSceneMaterialBuffer.pushBack(MaterialEvent(material.getMaterialIndex(), MATERIAL_ADD)); + + CREATE_PVD_INSTANCE(&material) +} + +void Scb::Scene::updateMaterial(const Sc::MaterialCore& material) +{ + Ps::Mutex::ScopedLock lock(mSceneMaterialBufferLock); + + mSceneMaterialBuffer.pushBack(MaterialEvent(material.getMaterialIndex(), MATERIAL_UPDATE)); + + UPDATE_PVD_PROPERTIES(&material) +} + +void Scb::Scene::removeMaterial(const Sc::MaterialCore& material) +{ + if(material.getMaterialIndex() == MATERIAL_INVALID_HANDLE) + return; + + Ps::Mutex::ScopedLock lock(mSceneMaterialBufferLock); + + mSceneMaterialBuffer.pushBack(MaterialEvent(material.getMaterialIndex(), MATERIAL_REMOVE)); + + RELEASE_PVD_INSTANCE(&material); +} + +/////////////////////////////////////////////////////////////////////////////// + +#if PX_USE_PARTICLE_SYSTEM_API +void Scb::Scene::addParticleSystem(Scb::ParticleSystem& ps) +{ + add<Scb::ParticleSystem>(ps, mParticleSystemManager, NULL); +} + +void Scb::Scene::removeParticleSystem(Scb::ParticleSystem& ps, bool isRelease) +{ + if (!mIsBuffering) + { + RELEASE_PVD_INSTANCE(&ps) + ps.removeFromScene(); + mScene.removeParticleSystem(ps.getScParticleSystem(), isRelease); + ps.resetControl(ControlState::eNOT_IN_SCENE); + ps.setScbScene(NULL); + } + else + { + mParticleSystemManager.scheduleForRemove(ps); + } +} +#endif + + +/////////////////////////////////////////////////////////////////////////////// + +#if PX_USE_CLOTH_API +void Scb::Scene::addCloth(Scb::Cloth& cl) +{ + cl.setScbScene(this); + + if (!mIsBuffering) + { + if (mScene.addCloth(cl.getScCloth())) + { + cl.resetControl(ControlState::eIN_SCENE); + CREATE_PVD_INSTANCE(&cl) + } + else + Ps::getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __LINE__, "Adding cloth to the scene failed!"); + } + else + mClothManager.scheduleForInsert(cl); +} + +void Scb::Scene::removeCloth(Scb::Cloth& cl) +{ + if (!mIsBuffering) + { + RELEASE_PVD_INSTANCE(&cl) + mScene.removeCloth(cl.getScCloth()); + cl.resetControl(ControlState::eNOT_IN_SCENE); + cl.setScbScene(NULL); + } + else + { + mClothManager.scheduleForRemove(cl); + } +} +#endif // PX_USE_CLOTH_API + +/////////////////////////////////////////////////////////////////////////////// + +void Scb::Scene::updateLowLevelMaterial(NpMaterial** masterMaterial) +{ + Ps::Mutex::ScopedLock lock(mSceneMaterialBufferLock); + + //sync all the material events + PxsMaterialManager& manager = mScene.getMaterialManager(); + for(PxU32 i=0; i< mSceneMaterialBuffer.size(); ++i) + { + const MaterialEvent& event = mSceneMaterialBuffer[i]; + const NpMaterial* masMat = masterMaterial[event.mHandle]; + switch(event.mType) + { + case MATERIAL_ADD: + if(masMat) + { + Sc::MaterialCore* materialCore = &masterMaterial[event.mHandle]->getScMaterial(); + manager.setMaterial(materialCore); + mScene.registerMaterialInNP(*materialCore); + } + break; + case MATERIAL_UPDATE: + if(masMat) + { + Sc::MaterialCore* materialCore = &masterMaterial[event.mHandle]->getScMaterial(); + manager.updateMaterial(materialCore); + mScene.updateMaterialInNP(*materialCore); + } + break; + case MATERIAL_REMOVE: + if (event.mHandle < manager.getMaxSize()) // materials might get added and then removed again immediately. However, the add does not get processed (see case MATERIAL_ADD above), + { // so the remove might end up reading out of bounds memory unless checked. + PxsMaterialCore* materialCore = manager.getMaterial(event.mHandle); + mScene.unregisterMaterialInNP(*materialCore); + manager.removeMaterial(materialCore); + } + break; + }; + } + + mSceneMaterialBuffer.resize(0); +} + +/////////////////////////////////////////////////////////////////////////////// +#if PX_USE_PARTICLE_SYSTEM_API +void Scb::Scene::preSimulateUpdateAppThread(PxReal timeStep) +{ + // Submit applied forces to particle systems + PxU32 nbParticleSystems = mScene.getNbParticleSystems(); + Sc::ParticleSystemCore* const* particleSystems = mScene.getParticleSystems(); + for(PxU32 i=0; i < nbParticleSystems; i++) + Scb::ParticleSystem::fromSc(*particleSystems[i]).submitForceUpdates(timeStep); +} +#endif + +//-------------------------------------------------------------- +// +// Data synchronization +// +//-------------------------------------------------------------- +void Scb::Scene::syncState() +{ + //process client creation -- must be done before BF_CLIENT_BEHAVIOR_FLAGS processing in the below block: + while (mBufferedData.numClientsCreated) + { + mScene.createClient(); + mBufferedData.numClientsCreated--; + } + + if (mBufferFlags) + { + if (isBuffered(BF_GRAVITY)) + mScene.setGravity(mBufferedData.gravity); + + if(isBuffered(BF_BOUNCETHRESHOLDVELOCITY)) + mScene.setBounceThresholdVelocity(mBufferedData.bounceThresholdVelocity); + + if (isBuffered(BF_FLAGS)) + mScene.setPublicFlags(mBufferedData.flags); + + if (isBuffered(BF_DOMINANCE_PAIRS)) + mBufferedData.syncDominancePairs(mScene); + + if (isBuffered(BF_SOLVER_BATCH_SIZE)) + mScene.setSolverBatchSize(mBufferedData.solverBatchSize); + + if (isBuffered(BF_CLIENT_BEHAVIOR_FLAGS)) + { + for (PxU32 i = 0; i < mBufferedData.clientBehaviorFlags.size(); i++) + { + if (mBufferedData.clientBehaviorFlags[i] != PxClientBehaviorFlag_eNOT_BUFFERED) //not PxClientBehaviorFlag_eNOT_BUFFERED means it was written. + { + mScene.setClientBehaviorFlags(PxClientID(i), mBufferedData.clientBehaviorFlags[i]); + mBufferedData.clientBehaviorFlags[i] = PxClientBehaviorFlag_eNOT_BUFFERED; + } + + } + } + + if (isBuffered(BF_VISUALIZATION)) + { + for(PxU32 i=0; i < PxVisualizationParameter::eNUM_VALUES; i++) + { + if (mBufferedData.visualizationParamChanged[i]) + { + mScene.setVisualizationParameter(static_cast<PxVisualizationParameter::Enum>(i), mBufferedData.visualizationParam[i]); + } + } + } + +#if PX_SUPPORT_PVD + if(mScenePvdClient.checkPvdDebugFlag()) + mScenePvdClient.updatePvdProperties(); +#endif + } + + + mBufferFlags = 0; + mBufferedData.clearDominanceBuffer(); + mBufferedData.clearVisualizationParams(); +} + +template<typename T> +void Scb::Scene::processUserUpdates(ObjectTracker &tracker) +{ +#if PX_SUPPORT_PVD + bool isPvdValid = mScenePvdClient.checkPvdDebugFlag(); +#endif + Base*const * buffered = tracker.getBuffered(); + for(PxU32 i=0; i < tracker.getBufferedCount(); i++) + { + T& v = *static_cast<T*>(buffered[i]); + if (v.getControlState() == ControlState::eINSERT_PENDING) + { + ScSceneFns<T>::insert(mScene, v, NULL); +#if PX_SUPPORT_PVD + if(isPvdValid) + PvdFns<T>::createInstance(*this, mScenePvdClient, &v); +#endif + } + else if(v.getControlFlags() & ControlFlag::eIS_UPDATED) + { + v.syncState(); +#if PX_SUPPORT_PVD + if(isPvdValid) + PvdFns<T>::updateInstance(*this, mScenePvdClient, &v); +#endif + } + } +} + +template<typename T, typename S> +void Scb::Scene::processSimUpdates(S*const * scObjects, PxU32 nbObjects) +{ +#if PX_SUPPORT_PVD + bool isPvdValid = mScenePvdClient.checkPvdDebugFlag(); +#endif + for(PxU32 i=0;i<nbObjects;i++) + { + T& v = T::fromSc(*scObjects[i]); + + if(!(v.getControlFlags() & ControlFlag::eIS_UPDATED)) // else the data will be synced further below + { + v.syncState(); +#if PX_SUPPORT_PVD + if(isPvdValid) + PvdFns<T>::updateInstance(*this, mScenePvdClient, &v); +#endif + } + } +} + +#define ENABLE_PVD_ORIGINSHIFT_EVENT +void Scb::Scene::shiftOrigin(const PxVec3& shift) +{ + PX_ASSERT(!isPhysicsBuffering()); + mScene.shiftOrigin(shift); + +#ifdef ENABLE_PVD_ORIGINSHIFT_EVENT + PVD_ORIGIN_SHIFT(shift); +#endif +} + +void Scb::Scene::syncWriteThroughProperties() +{ + mStream.lock(); + + Base*const * buffered = mBodyManager.getBuffered(); + PxU32 count = mBodyManager.getBufferedCount(); + for(PxU32 i=0; i < count; i++) + { + Scb::Body& bufferedBody = *static_cast<Scb::Body*>(buffered[i]); + bufferedBody.syncCollisionWriteThroughState(); + } + + mStream.unlock(); +} + +void Scb::Scene::syncEntireScene(PxU32* error) +{ + PX_PROFILE_ZONE("Sim.syncState", getContextId()); + if (error) + *error = mScene.getErrorState(); + + mStream.lock(); + syncState(); + // + // Process aggregates (needs to be done before adding actors because the actor's aggregateID needs to get set) + // + + for(PxU32 i=0; i < mAggregateManager.getBufferedCount(); i++) + { + Aggregate* a = static_cast<Aggregate*>(mAggregateManager.getBuffered()[i]); + if (a->getControlState() == ControlState::eINSERT_PENDING) + { + PxU32 aggregateID = mScene.createAggregate(a->mPxAggregate, a->getSelfCollide()); + a->setAggregateID(aggregateID); +#if PX_SUPPORT_PVD + mScenePvdClient.createPvdInstance(a); +#endif + a->syncState(*this); // Necessary to set the aggregate ID for all actors of the aggregate + } + else if(a->getControlFlags() & ControlFlag::eIS_UPDATED) + { + a->syncState(*this); + } + } + mAggregateManager.clear(); + mActorPtrBuffer.clear(); + + + // rigid statics + processUserUpdates<Scb::RigidStatic>(mRigidStaticManager); + mRigidStaticManager.clear(); + + + // rigid dynamics and articulation links + // + // 1) Sync simulation changed data + { + Sc::BodyCore*const* activeBodies = mScene.getActiveBodiesArray(); + PxU32 nbActiveBodies = mScene.getNumActiveBodies(); + while(nbActiveBodies--) + { + Sc::BodyCore* bodyCore = *activeBodies++; + Scb::Body& bufferedBody = Scb::Body::fromSc(*bodyCore); + if (!(bufferedBody.getControlFlags() & ControlFlag::eIS_UPDATED)) // Else the data will be synced further below + bufferedBody.syncState(); + } + } + + // 2) Sync data of rigid dynamics which were put to sleep by the simulation + + PxU32 nbSleepingBodies; + Sc::BodyCore* const* sleepingBodies = mScene.getSleepBodiesArray(nbSleepingBodies); + processSimUpdates<Scb::Body, Sc::BodyCore>(sleepingBodies, nbSleepingBodies); + + // user updates + processUserUpdates<Scb::Body>(mBodyManager); + mBodyManager.clear(); + mShapePtrBuffer.clear(); + + + // rigid body shapes + // + // IMPORTANT: This has to run after the material update + // + // Sync user changed data. Inserts and removes are handled in actor sync + for(PxU32 i=0; i < mShapeManager.getBufferedCount(); i++) + { + Scb::Shape* s = static_cast<Scb::Shape*>(mShapeManager.getBuffered()[i]); + + if(s->getControlFlags() & ControlFlag::eIS_UPDATED) + { + s->syncState(); + UPDATE_PVD_PROPERTIES(s) + } + } + + mShapeManager.clear(); + mShapeMaterialBuffer.clear(); + + // constraints (get break force and broken status from sim) + + processSimUpdates<Scb::Constraint, Sc::ConstraintCore>(mScene.getConstraints(), mScene.getNbConstraints()); + processUserUpdates<Scb::Constraint>(mConstraintManager); + mConstraintManager.clear(); + + + // articulations (get sleep state from sim) + + processSimUpdates<Scb::Articulation, Sc::ArticulationCore>(mScene.getArticulations(), mScene.getNbArticulations()); + processUserUpdates<Scb::Articulation>(mArticulationManager); + mArticulationManager.clear(); + + + // Process articulation joints + + processUserUpdates<Scb::ArticulationJoint>(mArticulationJointManager); + mArticulationJointManager.clear(); + +#if PX_USE_PARTICLE_SYSTEM_API + // + // Process particle systems + // + // 1) Sync simulation changed data + + PxU32 nbParticleSystems = mScene.getNbParticleSystems(); + Sc::ParticleSystemCore* const* particleSystems = mScene.getParticleSystems(); + for(PxU32 i=0; i < nbParticleSystems; i++) + { + Scb::ParticleSystem& scbParticleSystem = Scb::ParticleSystem::fromSc(*particleSystems[i]); + scbParticleSystem.syncState(); + if(scbParticleSystem.hasUpdates()) + UPDATE_PVD_PROPERTIES(&scbParticleSystem) + } + + // 2) Sync user changed data + for(PxU32 i=0; i < mParticleSystemManager.getBufferedCount(); i++) + { + ParticleSystem* p = static_cast<ParticleSystem*>(mParticleSystemManager.getBuffered()[i]); + + //special handling to release bulk buffer data + if (p->getControlState() == ControlState::eREMOVE_PENDING) + p->removeFromScene(); + + else if (p->getControlState() == ControlState::eINSERT_PENDING) + { + mScene.addParticleSystem(p->getScParticleSystem()); + CREATE_PVD_INSTANCE(p) + } + } + mParticleSystemManager.clear(); +#endif + +#if PX_USE_CLOTH_API + // + // Process cloth + // + // Pending insert & sync user changed data + + for(PxU32 i=0; i < mClothManager.getBufferedCount(); i++) + { + Cloth* cl = static_cast<Cloth*>(mClothManager.getBuffered()[i]); + if (cl->getControlState() == ControlState::eINSERT_PENDING) + { + if (mScene.addCloth(cl->getScCloth())) + { + CREATE_PVD_INSTANCE(cl) + } + else + Ps::getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __LINE__, "Adding cloth to the scene failed!"); + } + // no need yet + //else if(cl->getControlFlags() & ControlFlag::eIS_UPDATED) + //{ + // cl->syncState(); + // UPDATE_PVD_PROPERTIES(pvdConnected, cl) + //} + } + mClothManager.clear(); +#endif // PX_USE_CLOTH_API + + mStream.clearNotThreadSafe(); + mStream.unlock(); +} + + + +template<typename T, bool syncOnRemove, bool wakeOnLostTouchCheck> +void Scb::Scene::processRemoves(ObjectTracker& tracker) +{ +#if PX_SUPPORT_PVD + bool isPvdValid = mScenePvdClient.checkPvdDebugFlag(); +#endif + typedef ScSceneFns<T> Fns; + for(PxU32 i=0; i < tracker.getBufferedCount(); i++) + { + T* v = static_cast<T*>(tracker.getBuffered()[i]); + if(v->getControlState() == ControlState::eREMOVE_PENDING) + { + bool wakeOnLostTouch = false; + if (wakeOnLostTouchCheck) + { + PX_ASSERT( (v->getScbType() == ScbType::BODY) || + (v->getScbType() == ScbType::BODY_FROM_ARTICULATION_LINK) || + (v->getScbType() == ScbType::RIGID_STATIC) ); + wakeOnLostTouch = (v->Base::isBuffered(RigidObjectBuffer::BF_WakeTouching) != 0); // important to use Scb::Base::isBuffered() because Scb::Body, for example, has a shadowed implementation of this method + } + + Fns::remove(mScene, *v, wakeOnLostTouch); + + // if no object param has been updated, the state sync still needs to be processed to write simulation results + // back to the permanently buffered params. + if (syncOnRemove && !(v->getControlFlags() & ControlFlag::eIS_UPDATED)) + v->syncState(); +#if PX_SUPPORT_PVD + if(isPvdValid) + PvdFns<T>::releaseInstance(*this, mScenePvdClient, v); +#endif + } + } +} + +template<typename T> +void Scb::Scene::processShapeRemoves(ObjectTracker& tracker) +{ + for(PxU32 i=0; i < tracker.getBufferedCount(); i++) + { + T* v = static_cast<T*>(tracker.getBuffered()[i]); + v->processShapeRemoves(); + } +} + +void Scb::Scene::processPendingRemove() +{ + processShapeRemoves<Scb::RigidStatic>(mRigidStaticManager); + processShapeRemoves<Scb::Body>(mBodyManager); + + processRemoves<Scb::Constraint, tSyncOnRemove, !tWakeOnLostTouchCheck>(mConstraintManager); + + Scb::Base *const * buffered = mConstraintManager.getBuffered(); + for(PxU32 i=0; i < mConstraintManager.getBufferedCount(); i++) + { + Scb::Constraint* constraint = static_cast<Scb::Constraint*>(buffered[i]); + + if(constraint->getControlFlags() & ControlFlag::eIS_UPDATED) + constraint->prepareForActorRemoval(); // see comments in Scb::Constraint + } + + processRemoves<Scb::ArticulationJoint, !tSyncOnRemove, !tWakeOnLostTouchCheck> (mArticulationJointManager); + processRemoves<Scb::RigidStatic, !tSyncOnRemove, tWakeOnLostTouchCheck> (mRigidStaticManager); + processRemoves<Scb::Body, tSyncOnRemove, tWakeOnLostTouchCheck> (mBodyManager); + processRemoves<Scb::Articulation, tSyncOnRemove, !tWakeOnLostTouchCheck> (mArticulationManager); + +#if PX_USE_PARTICLE_SYSTEM_API + processRemoves<Scb::ParticleSystem, !tSyncOnRemove, !tWakeOnLostTouchCheck> (mParticleSystemManager); +#endif + +#if PX_USE_CLOTH_API + processRemoves<Scb::Cloth, !tSyncOnRemove, !tWakeOnLostTouchCheck> (mClothManager); +#endif + + // Do after actors have been removed (coumpound can only be removed after all its elements are gone) + for(PxU32 i=0; i < mAggregateManager.getBufferedCount(); i++) + { + Aggregate* a = static_cast<Aggregate*>(mAggregateManager.getBuffered()[i]); + + if(a->getControlState() == ControlState::eREMOVE_PENDING) + { + a->syncState(*this); // Clears the aggregate ID for all actors of the aggregate + mScene.deleteAggregate(a->getAggregateID()); + +#if PX_SUPPORT_PVD + mScenePvdClient.releasePvdInstance(a); +#endif + } + } + + +} + +void Scb::Scene::scheduleForUpdate(Scb::Base& object) +{ + switch(object.getScbType()) + { + case ScbType::SHAPE_EXCLUSIVE: + case ScbType::SHAPE_SHARED: { mShapeManager.scheduleForUpdate(object); }break; + case ScbType::BODY: { mBodyManager.scheduleForUpdate(object); }break; + case ScbType::BODY_FROM_ARTICULATION_LINK: { mBodyManager.scheduleForUpdate(object); }break; + case ScbType::RIGID_STATIC: { mRigidStaticManager.scheduleForUpdate(object); }break; + case ScbType::CONSTRAINT: { mConstraintManager.scheduleForUpdate(object); }break; +#if PX_USE_PARTICLE_SYSTEM_API + case ScbType::PARTICLE_SYSTEM: { mParticleSystemManager.scheduleForUpdate(object); }break; +#endif + case ScbType::ARTICULATION: { mArticulationManager.scheduleForUpdate(object); }break; + case ScbType::ARTICULATION_JOINT: { mArticulationJointManager.scheduleForUpdate(object); }break; + case ScbType::AGGREGATE: { mAggregateManager.scheduleForUpdate(object); }break; +#if PX_USE_CLOTH_API + case ScbType::CLOTH: { mClothManager.scheduleForUpdate(object); }break; +#endif + case ScbType::UNDEFINED: + case ScbType::TYPE_COUNT: + PX_ALWAYS_ASSERT_MESSAGE( "scheduleForUpdate: missing type!"); + break; + } +} + +PxU8* Scb::Scene::getStream(ScbType::Enum type) +{ + PxU8* memory = NULL; + switch(type) + { + case ScbType::SHAPE_EXCLUSIVE: + case ScbType::SHAPE_SHARED: { memory = reinterpret_cast<PxU8*>(mStream.allocateNotThreadSafe(sizeof(Scb::ShapeBuffer))); new (memory) Scb::ShapeBuffer; }break; + case ScbType::BODY: { memory = reinterpret_cast<PxU8*>(mStream.allocateNotThreadSafe(sizeof(Scb::BodyBuffer))); new (memory) Scb::BodyBuffer; }break; + case ScbType::BODY_FROM_ARTICULATION_LINK: { memory = reinterpret_cast<PxU8*>(mStream.allocateNotThreadSafe(sizeof(Scb::BodyBuffer))); new (memory) Scb::BodyBuffer; }break; + case ScbType::RIGID_STATIC: { memory = reinterpret_cast<PxU8*>(mStream.allocateNotThreadSafe(sizeof(Scb::RigidStaticBuffer))); new (memory) Scb::RigidStaticBuffer; }break; + case ScbType::CONSTRAINT: { memory = reinterpret_cast<PxU8*>(mStream.allocateNotThreadSafe(sizeof(Scb::ConstraintBuffer))); new (memory) Scb::ConstraintBuffer; }break; +#if PX_USE_PARTICLE_SYSTEM_API + case ScbType::PARTICLE_SYSTEM: { memory = reinterpret_cast<PxU8*>(mStream.allocateNotThreadSafe(sizeof(Scb::ParticleSystemBuffer))); new (memory) Scb::ParticleSystemBuffer; }break; +#endif + case ScbType::ARTICULATION: { memory = reinterpret_cast<PxU8*>(mStream.allocateNotThreadSafe(sizeof(Scb::ArticulationBuffer))); new (memory) Scb::ArticulationBuffer; }break; + case ScbType::ARTICULATION_JOINT: { memory = reinterpret_cast<PxU8*>(mStream.allocateNotThreadSafe(sizeof(Scb::ArticulationJointBuffer))); new (memory) Scb::ArticulationJointBuffer; }break; + case ScbType::AGGREGATE: { memory = reinterpret_cast<PxU8*>(mStream.allocateNotThreadSafe(sizeof(Scb::AggregateBuffer))); new (memory) Scb::AggregateBuffer; }break; + +#if PX_USE_CLOTH_API + case ScbType::CLOTH: +#endif + case ScbType::UNDEFINED: + case ScbType::TYPE_COUNT: + PX_ALWAYS_ASSERT_MESSAGE("getStream: missing type!"); + return NULL; + } + return memory; +} + +/////////////////////////////////////////////////////////////////////////////// + +PxBroadPhaseType::Enum Scb::Scene::getBroadPhaseType() const +{ + return mScene.getBroadPhaseType(); +} + +bool Scb::Scene::getBroadPhaseCaps(PxBroadPhaseCaps& caps) const +{ + return mScene.getBroadPhaseCaps(caps); +} + +PxU32 Scb::Scene::getNbBroadPhaseRegions() const +{ + return mScene.getNbBroadPhaseRegions(); +} + +PxU32 Scb::Scene::getBroadPhaseRegions(PxBroadPhaseRegionInfo* userBuffer, PxU32 bufferSize, PxU32 startIndex) const +{ + return mScene.getBroadPhaseRegions(userBuffer, bufferSize, startIndex); +} + +PxU32 Scb::Scene::addBroadPhaseRegion(const PxBroadPhaseRegion& region, bool populateRegion) +{ + if(!isPhysicsBuffering()) + return mScene.addBroadPhaseRegion(region, populateRegion); + else + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::addBroadPhaseRegion() not allowed while simulation is running. Call will be ignored."); + return 0xffffffff; +} + +bool Scb::Scene::removeBroadPhaseRegion(PxU32 handle) +{ + if(!isPhysicsBuffering()) + return mScene.removeBroadPhaseRegion(handle); + else + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::removeBroadPhaseRegion() not allowed while simulation is running. Call will be ignored."); + return false; +} + +////////////////////////////////////////////////////////////////////////// + +// +// To avoid duplication of a lot of similar code, the following templated method was introduced. Its main purpose is to +// take care of all the operations related to adding/removing a rigid object to/from the scene. Depending on the type +// of rigid object and the simulation state, there are slight changes to the code flow necessary. Among the operations are: +// +// - Add/remove rigid object to/from scene +// - Add/remove shapes from PVD +// - Adjust buffer control state of shapes +// - Adjust ref-count of shapes +// +template <bool TSimRunning, bool TAdd, bool TIsDynamic, bool TIsNonSimObject, class T> +PX_FORCE_INLINE static void addOrRemoveRigidObject(Sc::Scene& s, T& rigidObject, bool wakeOnLostTouch, PxBounds3* uninflatedBounds) +{ + PX_ASSERT(TIsDynamic || (rigidObject.getScbType() == ScbType::RIGID_STATIC)); + if (TSimRunning && TIsNonSimObject && TAdd) + PX_ASSERT(rigidObject.getActorFlags() & PxActorFlag::eDISABLE_SIMULATION); + if (TSimRunning && TIsNonSimObject&& !TAdd) + PX_ASSERT(rigidObject.isSimDisabledInternally()); + if (!TSimRunning && TIsNonSimObject) + PX_ASSERT(rigidObject.isSimDisabledInternally()); // when the simulation flag gets cleared on an object with pending removal, only the core flag knows that internally it is still a non-simulation object. + PX_ASSERT(!uninflatedBounds || (TAdd && !TSimRunning && !TIsNonSimObject)); + + Ps::InlineArray<const Sc::ShapeCore*, 64> localShapes; + Ps::InlineArray<const Sc::ShapeCore*, 64>& scShapes = s.getBatchRemove() ? s.getBatchRemove()->removedShapes : localShapes; + + PxActor* pxActor = NULL; + void* const* shapes; + PxU32 nbShapes; + size_t shapePtrOffset = NpShapeGetScPtrOffset(); + + Scb::Body& dynamicObject = reinterpret_cast<Scb::Body&>(rigidObject); + Scb::RigidStatic& staticObject = reinterpret_cast<Scb::RigidStatic&>(rigidObject); + + if (!TSimRunning) + { + if (TIsDynamic) + pxActor = dynamicObject.getScBody().getPxActor(); + else + pxActor = staticObject.getScStatic().getPxActor(); + } + PX_UNUSED(pxActor); + size_t ptrOffset; + if (TAdd || TSimRunning || TIsNonSimObject) + { + // Np buffers are still valid when the object gets removed while the sim is running. + // Furthermore, for non-simulation objects, there exists no shape buffer in the simulation controller + // and we need to fetch from Np all the time. + + ptrOffset = shapePtrOffset - Scb::Shape::getScOffset(); + + if (TIsDynamic) + nbShapes = NpRigidDynamicGetShapes(dynamicObject, shapes); + else + nbShapes = NpRigidStaticGetShapes(staticObject, shapes); + } + + if ((!TSimRunning) && (!TIsNonSimObject)) + { + if (TAdd) + { + if (TIsDynamic) + s.addBody(dynamicObject.getScBody(), shapes, nbShapes, shapePtrOffset, uninflatedBounds); + else + s.addStatic(staticObject.getScStatic(), shapes, nbShapes, shapePtrOffset, uninflatedBounds); + } + else + { + ptrOffset = -Scb::Shape::getScOffset(); + + if (TIsDynamic) + s.removeBody(dynamicObject.getScBody(), scShapes, wakeOnLostTouch); + else + s.removeStatic(staticObject.getScStatic(), scShapes, wakeOnLostTouch); + + shapes = reinterpret_cast<void*const*>(const_cast<Sc::ShapeCore*const*>(scShapes.begin())); + nbShapes = scShapes.size(); + } + } + + Scb::Scene* scbScene = rigidObject.getScbScene(); + Scb::Scene* shapeScenePtr = scbScene; + Scb::ControlState::Enum controlState = rigidObject.getControlState(); + + if (!TSimRunning) + { + // hacky: in the non-buffered case the rigid objects might not have been updated properly at this point, so it's done explicitly. + + if (TAdd) + { + PX_ASSERT(shapeScenePtr == scbScene); + controlState = Scb::ControlState::eIN_SCENE; + } + else + { + shapeScenePtr = NULL; + controlState = Scb::ControlState::eNOT_IN_SCENE; + } + } + + for(PxU32 i=0; i < nbShapes; i++) + { + Scb::Shape& scbShape = *Ps::pointerOffset<Scb::Shape*>(shapes[i], ptrdiff_t(ptrOffset)); + + if (!TSimRunning) + { + PX_ASSERT(pxActor); + PX_ASSERT(scbScene); + + if (TAdd) + { + scbShape.setControlStateIfExclusive(shapeScenePtr, controlState); + + if (!TIsNonSimObject) + NpShapeIncRefCount(scbShape); // simulation increases the refcount to avoid that shapes get destroyed while the sim is running + +#if PX_SUPPORT_PVD + scbScene->getScenePvdClient().createPvdInstance(&scbShape, *pxActor); +#endif + } + else + { + scbShape.checkUpdateOnRemove<true>(scbScene); + +#if PX_SUPPORT_PVD + scbScene->getScenePvdClient().releasePvdInstance(&scbShape, *pxActor); +#endif + scbShape.setControlStateIfExclusive(shapeScenePtr, controlState); + + if (!TIsNonSimObject) + NpShapeDecRefCount(scbShape); // see comment in the "TAdd" section above + } + } + else + scbShape.setControlStateIfExclusive(shapeScenePtr, controlState); + } +} diff --git a/PhysX_3.4/Source/PhysX/src/buffering/ScbScene.h b/PhysX_3.4/Source/PhysX/src/buffering/ScbScene.h new file mode 100644 index 00000000..3a3ae43d --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/buffering/ScbScene.h @@ -0,0 +1,939 @@ +// 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_SCB_SCENE +#define PX_PHYSICS_SCB_SCENE + +#include "ScScene.h" + +#include "ScbSceneBuffer.h" +#include "ScbType.h" +#include "PsFoundation.h" +#include "PsMutex.h" +#include "PsHashSet.h" + +#if PX_SUPPORT_PVD +#include "PxPhysics.h" +#include "ScbScenePvdClient.h" +#endif + +namespace physx +{ + +class NpMaterial; + +namespace Sc +{ + class BodyDesc; +} + +namespace Scb +{ + class Base; + class RigidObject; + class RigidStatic; + class Body; + class Actor; + class Shape; + class Constraint; + class Material; + class ParticleSystem; + class Articulation; + class ArticulationJoint; + class Aggregate; + class Cloth; + + struct ShapeBuffer; + + /** + \brief Helper class to track inserted/removed/updated buffering objects. + */ + class ObjectTracker + { + public: + ObjectTracker() {} + + /** + \brief An object has been inserted while the simulation was running -> track it for insertion at sync point + */ + void scheduleForInsert(Base& element); + + /** + \brief An object has been removed while the simulation was running -> track it for removal at sync point + */ + void scheduleForRemove(Base& element); + + /** + \brief An object has been changed while the simulation was running -> track it for update at sync point + */ + void scheduleForUpdate(Base& element); + + /** + \brief Get the list of dirty objects that require processing at a sync point. + */ + Base*const * getBuffered() { return mBuffered.getEntries(); } + + /** + \brief Get number of dirty objects that require processing at a sync point. + */ + PxU32 getBufferedCount() const { return mBuffered.size(); } + + /** + \brief Cleanup dirty objects after sync point. + + \li Transition pending insertion objects from eINSERT_PENDING to eIN_SCENE. + \li Transition pending removal objects from eREMOVE_PENDING to eNOT_IN_SCENE. + \li Destroy objects marked as eIS_RELEASED. + \li Clear dirty list. + */ + void clear(); + + void insert(Base& element); + void remove(Base& element); + + private: + Ps::CoalescedHashSet<Base*> mBuffered; + }; + + typedef ObjectTracker ShapeManager; + typedef ObjectTracker RigidStaticManager; + typedef ObjectTracker BodyManager; + typedef ObjectTracker ParticleSystemManager; + typedef ObjectTracker ArticulationManager; + typedef ObjectTracker ConstraintManager; + typedef ObjectTracker ArticulationJointManager; + typedef ObjectTracker AggregateManager; + typedef ObjectTracker ClothManager; + + enum MATERIAL_EVENT + { + MATERIAL_ADD, + MATERIAL_UPDATE, + MATERIAL_REMOVE + }; + + class MaterialEvent + { + public: + PX_FORCE_INLINE MaterialEvent(PxU32 handle, MATERIAL_EVENT type) : mHandle(handle), mType(type) {} + PX_FORCE_INLINE MaterialEvent() {} + + PxU32 mHandle;//handle to the master material table + MATERIAL_EVENT mType; + }; + + class Scene : public Ps::UserAllocated + { + PX_NOCOPY(Scene) + public: + enum BufferFlag + { + BF_GRAVITY = (1 << 0), + BF_BOUNCETHRESHOLDVELOCITY = (1 << 1), + BF_FLAGS = (1 << 2), + BF_DOMINANCE_PAIRS = (1 << 3), + BF_SOLVER_BATCH_SIZE = (1 << 4), + BF_CLIENT_BEHAVIOR_FLAGS = (1 << 5), + BF_VISUALIZATION = (1 << 6), + BF_SCENE_PARAMS = (1 << 7) + + }; + + public: + Scene(const PxSceneDesc& desc, PxU64 contextID); + ~Scene() {} //use release() plz. + + //--------------------------------------------------------------------------------- + // Wrapper for Sc::Scene interface + //--------------------------------------------------------------------------------- + void release(); + + PxScene* getPxScene(); + + PX_INLINE void setGravity(const PxVec3& gravity); + PX_INLINE PxVec3 getGravity() const; + + PX_INLINE void setBounceThresholdVelocity(const PxReal t); + PX_INLINE PxReal getBounceThresholdVelocity() const; + + PX_INLINE void setFlags(PxSceneFlags flags); + PX_INLINE PxSceneFlags getFlags() const; + + PX_INLINE void setFrictionType(PxFrictionType::Enum); + PX_INLINE PxFrictionType::Enum getFrictionType() const; + + void addActor(Scb::RigidStatic&, bool noSim, PxBounds3* uninflatedBounds); + void removeActor(Scb::RigidStatic&, bool wakeOnLostTouch, bool noSim); + + void addActor(Scb::Body&, bool noSim, PxBounds3* uninflatedBounds); + void removeActor(Scb::Body&, bool wakeOnLostTouch, bool noSim); + + void addConstraint(Scb::Constraint&); + void removeConstraint(Scb::Constraint&); + + void addArticulation(Scb::Articulation&); + void removeArticulation(Scb::Articulation&); + + void addArticulationJoint(Scb::ArticulationJoint&); + void removeArticulationJoint(Scb::ArticulationJoint&); + + void addAggregate(Scb::Aggregate&); + void removeAggregate(Scb::Aggregate&); + + #if PX_USE_PARTICLE_SYSTEM_API + void addParticleSystem(Scb::ParticleSystem&); + void removeParticleSystem(Scb::ParticleSystem&, bool isRelease); + #endif + + #if PX_USE_CLOTH_API + void addCloth(Scb::Cloth&); + void removeCloth(Scb::Cloth&); + #endif + + void addMaterial(const Sc::MaterialCore& mat); + void updateMaterial(const Sc::MaterialCore& mat); + void removeMaterial(const Sc::MaterialCore& mat); + void updateLowLevelMaterial(NpMaterial** masterMaterials); + // These methods are only to be called at fetchResults! + PX_INLINE PxU32 getNumActiveBodies() const; + PX_INLINE Sc::BodyCore* const* getActiveBodiesArray() const; + PX_INLINE PxSimulationEventCallback* getSimulationEventCallback(PxClientID client) const; + PX_INLINE void setSimulationEventCallback(PxSimulationEventCallback* callback, PxClientID client); + PX_INLINE PxContactModifyCallback* getContactModifyCallback() const; + PX_INLINE void setContactModifyCallback(PxContactModifyCallback* callback); + PX_INLINE PxCCDContactModifyCallback* getCCDContactModifyCallback() const; + PX_INLINE void setCCDContactModifyCallback(PxCCDContactModifyCallback* callback); + PX_INLINE PxU32 getCCDMaxPasses() const; + PX_INLINE void setCCDMaxPasses(PxU32 ccdMaxPasses); + PX_INLINE void setBroadPhaseCallback(PxBroadPhaseCallback* callback, PxClientID client); + PX_INLINE PxBroadPhaseCallback* getBroadPhaseCallback(PxClientID client) const; + 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); + + // Collision filtering + PX_INLINE void setFilterShaderData(const void* data, PxU32 dataSize); + PX_INLINE const void* getFilterShaderData() const; + PX_INLINE PxU32 getFilterShaderDataSize() const; + PX_INLINE PxSimulationFilterShader getFilterShader() const; + PX_INLINE PxSimulationFilterCallback* getFilterCallback() const; + + // Groups + PX_INLINE void setDominanceGroupPair(PxDominanceGroup group1, PxDominanceGroup group2, const PxDominanceGroupPair& dominance); + PX_INLINE PxDominanceGroupPair getDominanceGroupPair(PxDominanceGroup group1, PxDominanceGroup group2) const; + + PX_INLINE void setSolverBatchSize(PxU32 solverBatchSize); + PX_INLINE PxU32 getSolverBatchSize() const; + + PX_INLINE void simulate(PxReal timeStep, PxBaseTask* continuation); + PX_INLINE void collide(PxReal timeStep, PxBaseTask* continuation); + PX_INLINE void advance(PxReal timeStep, PxBaseTask* continuation); + PX_INLINE void endSimulation(); + PX_INLINE void flush(bool sendPendingReports); + PX_INLINE void fireBrokenConstraintCallbacks() { mScene.fireBrokenConstraintCallbacks(); } + PX_INLINE void fireTriggerCallbacks() { mScene.fireTriggerCallbacks(); } + PX_INLINE void fireQueuedContactCallbacks() { mScene.fireQueuedContactCallbacks(false); } + PX_INLINE const Ps::Array<PxContactPairHeader>& + getQueuedContactPairHeaders() { return mScene.getQueuedContactPairHeaders(); } + PX_FORCE_INLINE void postCallbacksPreSync() { mScene.postCallbacksPreSync(); } //cleanup tasks after the pre-sync callbacks have fired + + + PX_INLINE void fireCallBacksPostSync() { mScene.fireCallbacksPostSync(); } //callbacks that are fired on the core side, after the buffers get synced + PX_INLINE void postReportsCleanup(); + + PX_INLINE const PxSceneLimits& getLimits() const; + PX_INLINE void setLimits(const PxSceneLimits& limits); + + PX_INLINE void getStats(PxSimulationStatistics& stats) const; + + PX_DEPRECATED PX_INLINE void buildActiveTransforms(); // build the list of active transforms + PX_DEPRECATED PX_INLINE PxActiveTransform* getActiveTransforms(PxU32& nbTransformsOut, PxClientID client); + + PX_INLINE void buildActiveActors(); // build the list of active actors + PX_INLINE PxActor** getActiveActors(PxU32& nbActorsOut, PxClientID client); + + PX_INLINE PxClientID createClient(); + PX_INLINE void setClientBehaviorFlags(PxClientID client, PxClientBehaviorFlags clientBehaviorFlags); + PX_INLINE PxClientBehaviorFlags getClientBehaviorFlags(PxClientID client) const; + +#if PX_USE_CLOTH_API + PX_INLINE void setClothInterCollisionDistance(PxF32 distance); + PX_INLINE PxF32 getClothInterCollisionDistance() const; + PX_INLINE void setClothInterCollisionStiffness(PxF32 stiffness); + PX_INLINE PxF32 getClothInterCollisionStiffness() const; + PX_INLINE void setClothInterCollisionNbIterations(PxU32 nbIterations); + PX_INLINE PxU32 getClothInterCollisionNbIterations() const; +#endif + + PX_INLINE void setVisualizationParameter(PxVisualizationParameter::Enum param, PxReal value); + PX_INLINE PxReal getVisualizationParameter(PxVisualizationParameter::Enum param) const; + + PX_INLINE void setVisualizationCullingBox(const PxBounds3& box); + PX_INLINE const PxBounds3& getVisualizationCullingBox() const; + + void shiftOrigin(const PxVec3& shift); + + //--------------------------------------------------------------------------------- + // Data synchronization + //--------------------------------------------------------------------------------- + public: + void syncWriteThroughProperties(); + void syncEntireScene(PxU32* error); + void processPendingRemove(); + + PX_FORCE_INLINE PxU16* allocShapeMaterialBuffer(PxU32 count, PxU32& startIdx) { return allocArrayBuffer(mShapeMaterialBuffer, count, startIdx); } + PX_FORCE_INLINE const PxU16* getShapeMaterialBuffer(PxU32 startIdx) const { return &mShapeMaterialBuffer[startIdx]; } + PX_FORCE_INLINE Scb::Shape** allocShapeBuffer(PxU32 count, PxU32& startIdx) { return allocArrayBuffer(mShapePtrBuffer, count, startIdx); } + PX_FORCE_INLINE Scb::Shape** getShapeBuffer(PxU32 startIdx) { return &mShapePtrBuffer[startIdx]; } + PX_FORCE_INLINE Scb::Actor** allocActorBuffer(PxU32 count, PxU32& startIdx) { return allocArrayBuffer(mActorPtrBuffer, count, startIdx); } + PX_FORCE_INLINE Scb::Actor** getActorBuffer(PxU32 startIdx) { return &mActorPtrBuffer[startIdx]; } + + void scheduleForUpdate(Scb::Base& object); + PxU8* getStream(ScbType::Enum type); + + PX_FORCE_INLINE void removeShapeFromPendingUpdateList(Scb::Base& shape) { mShapeManager.remove(shape); } + + PX_FORCE_INLINE const Sc::Scene& getScScene() const { return mScene; } + PX_FORCE_INLINE Sc::Scene& getScScene() { return mScene; } + PX_FORCE_INLINE void prepareOutOfBoundsCallbacks() { mScene.prepareOutOfBoundsCallbacks(); } + + private: + void syncState(); + PX_FORCE_INLINE Ps::IntBool isBuffered(BufferFlag f) const { return Ps::IntBool(mBufferFlags& f); } + PX_FORCE_INLINE void markUpdated(BufferFlag f) { mBufferFlags |= f; } + + //--------------------------------------------------------------------------------- + // Miscellaneous + //--------------------------------------------------------------------------------- + public: + + PX_FORCE_INLINE bool isPhysicsBuffering() const { return mIsBuffering; } + PX_FORCE_INLINE void setPhysicsBuffering(bool buffering) { mIsBuffering = buffering; } + + PX_FORCE_INLINE Sc::SimulationStage::Enum getSimulationStage() const { return mScene.getSimulationStage(); } + PX_FORCE_INLINE void setSimulationStage(Sc::SimulationStage::Enum stage) { mScene.setSimulationStage(stage); } + +#if PX_USE_PARTICLE_SYSTEM_API + void preSimulateUpdateAppThread(PxReal timeStep); // Data updates that need to be handled in the application thread before the simulation potentially switches // to its own thread. +#endif + + PX_FORCE_INLINE bool isValid() const { return mScene.isValid(); } + + PX_FORCE_INLINE PxReal getWakeCounterResetValue() const { return mWakeCounterResetValue; } + + void switchRigidToNoSim(Scb::RigidObject&, bool isDynamic); + void switchRigidFromNoSim(Scb::RigidObject&, bool isDynamic); + + static size_t getScOffset() { return reinterpret_cast<size_t>(&reinterpret_cast<Scene*>(0)->mScene); } + +#if PX_SUPPORT_PVD + PX_FORCE_INLINE Vd::ScbScenePvdClient& getScenePvdClient() { return mScenePvdClient; } + PX_FORCE_INLINE const Vd::ScbScenePvdClient& getScenePvdClient() const { return mScenePvdClient; } +#endif + + PX_FORCE_INLINE PxU64 getContextId() const { return mScene.getContextId(); } + + private: + void addShapeInternal(Scb::Shape&); + void addShapesInternal(PxU32 nbShapes, PxShape** PX_RESTRICT shapes, size_t scbOffset, PxActor** PX_RESTRICT owners, PxU32 offsetNpToCore, bool isDynamic); + + template<typename T> T* allocArrayBuffer(Ps::Array<T>& buffer, PxU32 count, PxU32& startIdx); + + private: + + template<bool TIsDynamic, class T> + PX_FORCE_INLINE void addActorT(T& actor, ObjectTracker& tracker, bool noSim, PxBounds3* uninflatedBounds); + + template<typename T> void add(T& v, ObjectTracker &tracker, PxBounds3* uninflatedBounds); + template<typename T> void remove(T& v, ObjectTracker &tracker, bool wakeOnLostTouch = false); + template<bool TIsDynamic, typename T> void addRigidNoSim(T& v, ObjectTracker &tracker); + template<bool TIsDynamic, typename T> void removeRigidNoSim(T& v, ObjectTracker &tracker); + template<typename T, typename S> void processSimUpdates(S*const * scObjects, PxU32 nbObjects); + template<typename T> void processUserUpdates(ObjectTracker& tracker); + template<typename T, bool syncOnRemove, bool wakeOnLostTouchCheck> void processRemoves(ObjectTracker& tracker); + template<typename T> void processShapeRemoves(ObjectTracker& tracker); + + Sc::Scene mScene; + + Ps::Array<MaterialEvent> mSceneMaterialBuffer; + Ps::Mutex mSceneMaterialBufferLock; + + bool mSimulationRunning; + bool mIsBuffering; + + Cm::FlushPool mStream; // Pool for temporarily buffering user changes on objects + ShapeManager mShapeManager; + Ps::Array<PxU16> mShapeMaterialBuffer; // Buffered setMaterial() call might need to track list of materials (for multi material shapes) + Ps::Array<Scb::Shape*> mShapePtrBuffer; // List of shape pointers to track buffered calls to resetFiltering(), for example + Ps::Array<Scb::Actor*> mActorPtrBuffer; + RigidStaticManager mRigidStaticManager; + BodyManager mBodyManager; +#if PX_USE_PARTICLE_SYSTEM_API + ParticleSystemManager mParticleSystemManager; +#endif + ConstraintManager mConstraintManager; + ArticulationManager mArticulationManager; + ArticulationJointManager mArticulationJointManager; + AggregateManager mAggregateManager; +#if PX_USE_CLOTH_API + ClothManager mClothManager; +#endif +#if PX_SUPPORT_PVD + Vd::ScbScenePvdClient mScenePvdClient; +#endif + + PX_FORCE_INLINE void updatePvdProperties() + { +#if PX_SUPPORT_PVD + // PT: TODO: shouldn't we test PxPvdInstrumentationFlag::eDEBUG here? + if(mScenePvdClient.isConnected()) + mScenePvdClient.updatePvdProperties(); +#endif + } + + PxReal mWakeCounterResetValue; + + // note: If deletion of rigid objects is done before the sync of the simulation data then we + // might wanna consider having a separate list for deleted rigid objects (for performance + // reasons) + + //--------------------------------------------------------------------------------- + // On demand buffered data (simulation read-only data) + //--------------------------------------------------------------------------------- + Scb::SceneBuffer mBufferedData; + PxU32 mBufferFlags; + }; + +} // namespace Scb + + +template<typename T> +T* Scb::Scene::allocArrayBuffer(Ps::Array<T>& buffer, PxU32 count, PxU32& startIdx) +{ + PxU32 oldSize = buffer.size(); + buffer.resize(oldSize + count); + startIdx = oldSize; + return &buffer[oldSize]; +} + +PX_INLINE void Scb::Scene::setGravity(const PxVec3& gravity) +{ + if (!isPhysicsBuffering()) + { + mScene.setGravity(gravity); + updatePvdProperties(); + } + else + { + mBufferedData.gravity = gravity; + markUpdated(BF_GRAVITY); + } +} + +PX_INLINE PxVec3 Scb::Scene::getGravity() const +{ + if (isBuffered(BF_GRAVITY)) + return mBufferedData.gravity; + else + return mScene.getGravity(); +} + +void Scb::Scene::setBounceThresholdVelocity(const PxReal t) +{ + if (!isPhysicsBuffering()) + { + mScene.setBounceThresholdVelocity(t); + updatePvdProperties(); + } + else + { + mBufferedData.bounceThresholdVelocity = t; + markUpdated(BF_BOUNCETHRESHOLDVELOCITY); + } +} + +PxReal Scb::Scene::getBounceThresholdVelocity() const +{ + if (isBuffered(BF_BOUNCETHRESHOLDVELOCITY)) + return mBufferedData.bounceThresholdVelocity; + else + return mScene.getBounceThresholdVelocity(); +} + +PX_INLINE void Scb::Scene::setFrictionType(PxFrictionType::Enum frictionType) +{ + mScene.setFrictionType(frictionType); +} + +PX_INLINE PxFrictionType::Enum Scb::Scene::getFrictionType() const +{ + return mScene.getFrictionType(); +} + + +PX_INLINE void Scb::Scene::setFlags(PxSceneFlags flags) +{ + if (!isPhysicsBuffering()) + { + mScene.setPublicFlags(flags); + const bool pcm = (flags & PxSceneFlag::eENABLE_PCM); + mScene.setPCM(pcm); + const bool contactCache = !(flags & PxSceneFlag::eDISABLE_CONTACT_CACHE); + mScene.setContactCache(contactCache); + updatePvdProperties(); + } + else + { + mBufferedData.flags = flags; + markUpdated(BF_FLAGS); + } +} + + +PX_INLINE PxSceneFlags Scb::Scene::getFlags() const +{ + if (isBuffered(BF_FLAGS)) + return mBufferedData.flags; + else + return mScene.getPublicFlags(); +} + +/////////////////////////////////////////////////////////////////////////////// + +PX_INLINE PxSimulationEventCallback* Scb::Scene::getSimulationEventCallback(PxClientID client) const +{ + return mScene.getSimulationEventCallback(client); +} + +PX_INLINE void Scb::Scene::setSimulationEventCallback(PxSimulationEventCallback* callback, PxClientID client) +{ + if(!isPhysicsBuffering()) + mScene.setSimulationEventCallback(callback, client); + else + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::setSimulationEventCallback() not allowed while simulation is running. Call will be ignored."); +} + +PX_INLINE PxContactModifyCallback* Scb::Scene::getContactModifyCallback() const +{ + return mScene.getContactModifyCallback(); +} + +PX_INLINE void Scb::Scene::setContactModifyCallback(PxContactModifyCallback* callback) +{ + if(!isPhysicsBuffering()) + mScene.setContactModifyCallback(callback); + else + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::setContactModifyCallback() not allowed while simulation is running. Call will be ignored."); +} + +PX_INLINE PxCCDContactModifyCallback* Scb::Scene::getCCDContactModifyCallback() const +{ + return mScene.getCCDContactModifyCallback(); +} + +PX_INLINE void Scb::Scene::setCCDContactModifyCallback(PxCCDContactModifyCallback* callback) +{ + if(!isPhysicsBuffering()) + mScene.setCCDContactModifyCallback(callback); + else + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::setCCDContactModifyCallback() not allowed while simulation is running. Call will be ignored."); +} + +PX_INLINE PxU32 Scb::Scene::getCCDMaxPasses() const +{ + return mScene.getCCDMaxPasses(); +} + +PX_INLINE void Scb::Scene::setCCDMaxPasses(PxU32 ccdMaxPasses) +{ + if(!isPhysicsBuffering()) + mScene.setCCDMaxPasses(ccdMaxPasses); + else + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::setCCDMaxPasses() not allowed while simulation is running. Call will be ignored."); +} + +PX_INLINE PxBroadPhaseCallback* Scb::Scene::getBroadPhaseCallback(PxClientID client) const +{ + return mScene.getBroadPhaseCallback(client); +} + +PX_INLINE void Scb::Scene::setBroadPhaseCallback(PxBroadPhaseCallback* callback, PxClientID client) +{ + if(!isPhysicsBuffering()) + mScene.setBroadPhaseCallback(callback, client); + else + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::setBroadPhaseCallback() not allowed while simulation is running. Call will be ignored."); +} + +/////////////////////////////////////////////////////////////////////////////// + +PX_INLINE void Scb::Scene::setFilterShaderData(const void* data, PxU32 dataSize) +{ + if(!isPhysicsBuffering()) + mScene.setFilterShaderData(data, dataSize); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxScene::setFilterShaderData() not allowed while simulation is running. Call will be ignored."); +} + + +PX_INLINE const void* Scb::Scene::getFilterShaderData() const +{ + return mScene.getFilterShaderDataFast(); +} + + +PX_INLINE PxU32 Scb::Scene::getFilterShaderDataSize() const +{ + return mScene.getFilterShaderDataSizeFast(); +} + + +PX_INLINE PxSimulationFilterShader Scb::Scene::getFilterShader() const +{ + return mScene.getFilterShaderFast(); +} + + +PX_INLINE PxSimulationFilterCallback* Scb::Scene::getFilterCallback() const +{ + return mScene.getFilterCallbackFast(); +} + + +PX_INLINE void Scb::Scene::simulate(PxReal timeStep, PxBaseTask* continuation) +{ + mScene.simulate(timeStep, continuation); +} + +PX_INLINE void Scb::Scene::advance(PxReal timeStep, PxBaseTask* continuation) +{ + mScene.advance(timeStep, continuation); +} + +PX_INLINE void Scb::Scene::collide(PxReal timeStep, PxBaseTask* continuation) +{ + mScene.collide(timeStep, continuation); +} + +PX_INLINE void Scb::Scene::endSimulation() +{ + mScene.endSimulation(); +} + + +PX_INLINE void Scb::Scene::flush(bool sendPendingReports) +{ + PX_ASSERT(!isPhysicsBuffering()); + + mShapeMaterialBuffer.reset(); + mShapePtrBuffer.reset(); + mActorPtrBuffer.reset(); + + //!!! TODO: Clear all buffers used for double buffering changes (see ObjectTracker::mBufferPool) + + mScene.flush(sendPendingReports); +} + + +PX_INLINE void Scb::Scene::postReportsCleanup() +{ + PX_ASSERT(!isPhysicsBuffering()); + mScene.postReportsCleanup(); +} + + +PX_INLINE const PxSceneLimits& Scb::Scene::getLimits() const +{ + return mScene.getLimits(); +} + +PX_INLINE void Scb::Scene::setLimits(const PxSceneLimits& limits) +{ + mScene.setLimits(limits); +} + +PX_INLINE void Scb::Scene::setDominanceGroupPair(PxDominanceGroup group1, PxDominanceGroup group2, const PxDominanceGroupPair& dominance) +{ + if (!isPhysicsBuffering()) + { + mScene.setDominanceGroupPair(group1, group2, dominance); + updatePvdProperties(); + } + else + { + mBufferedData.setDominancePair(group1, group2, dominance); + markUpdated(BF_DOMINANCE_PAIRS); + } +} + + +PX_INLINE PxDominanceGroupPair Scb::Scene::getDominanceGroupPair(PxDominanceGroup group1, PxDominanceGroup group2) const +{ + if (isBuffered(BF_DOMINANCE_PAIRS)) + { + PxDominanceGroupPair dominance(0, 0); + if (mBufferedData.getDominancePair(group1, group2, dominance)) + return dominance; + } + + return mScene.getDominanceGroupPair(group1, group2); +} + + +PX_INLINE void Scb::Scene::setSolverBatchSize(PxU32 solverBatchSize) +{ + if (!isPhysicsBuffering()) + { + mScene.setSolverBatchSize(solverBatchSize); + updatePvdProperties(); + } + else + { + mBufferedData.solverBatchSize = solverBatchSize; + markUpdated(BF_SOLVER_BATCH_SIZE); + } +} + +PX_INLINE PxU32 Scb::Scene::getSolverBatchSize() const +{ + if (isBuffered(BF_SOLVER_BATCH_SIZE)) + return mBufferedData.solverBatchSize; + else + return mScene.getSolverBatchSize(); +} + + +PX_INLINE void Scb::Scene::getStats(PxSimulationStatistics& stats) const +{ + PX_ASSERT(!isPhysicsBuffering()); + + mScene.getStats(stats); +} + + +PX_DEPRECATED PX_INLINE void Scb::Scene::buildActiveTransforms() +{ + PX_ASSERT(!isPhysicsBuffering()); + + mScene.buildActiveTransforms(); +} + + +PX_DEPRECATED PX_INLINE PxActiveTransform* Scb::Scene::getActiveTransforms(PxU32& nbTransformsOut, PxClientID client) +{ + if (!isPhysicsBuffering()) + { + return mScene.getActiveTransforms(nbTransformsOut, client); + } + else + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::getActiveTransforms() not allowed while simulation is running. Call will be ignored."); + nbTransformsOut = 0; + return NULL; + } +} + +PX_INLINE void Scb::Scene::buildActiveActors() +{ + PX_ASSERT(!isPhysicsBuffering()); + + mScene.buildActiveActors(); +} + +PX_INLINE PxActor** Scb::Scene::getActiveActors(PxU32& nbActorsOut, PxClientID client) +{ + if (!isPhysicsBuffering()) + { + return mScene.getActiveActors(nbActorsOut, client); + } + else + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::getActiveActors() not allowed while simulation is running. Call will be ignored."); + nbActorsOut = 0; + return NULL; + } +} + + +PX_INLINE PxClientID Scb::Scene::createClient() +{ + mBufferedData.clientBehaviorFlags.pushBack(PxClientBehaviorFlag_eNOT_BUFFERED); //PxClientBehaviorFlag_eNOT_BUFFERED means its not storing anything. Do this either way to make sure this buffer is big enough for behavior bit set/gets later. + + if (!isPhysicsBuffering()) + { + PxClientID i = mScene.createClient(); + PX_ASSERT(mBufferedData.clientBehaviorFlags.size()-1 == i); + return i; + } + else + { + mBufferedData.numClientsCreated++; + return PxClientID(mBufferedData.clientBehaviorFlags.size()-1); //mScene.createClient(); + } +} + +PX_INLINE void Scb::Scene::setClientBehaviorFlags(PxClientID client, PxClientBehaviorFlags clientBehaviorFlags) +{ + if (!isPhysicsBuffering()) + { + mScene.setClientBehaviorFlags(client, clientBehaviorFlags); + updatePvdProperties(); + } + else + { + PX_ASSERT(mBufferedData.clientBehaviorFlags.size() > client); + mBufferedData.clientBehaviorFlags[client] = clientBehaviorFlags; + markUpdated(BF_CLIENT_BEHAVIOR_FLAGS); + } +} + +PX_INLINE PxClientBehaviorFlags Scb::Scene::getClientBehaviorFlags(PxClientID client) const +{ + PX_ASSERT(mBufferedData.clientBehaviorFlags.size() > client); + if (isBuffered(BF_CLIENT_BEHAVIOR_FLAGS) && (mBufferedData.clientBehaviorFlags[client] != PxClientBehaviorFlag_eNOT_BUFFERED)) + return mBufferedData.clientBehaviorFlags[client]; + else + return mScene.getClientBehaviorFlags(client); +} + +#if PX_USE_CLOTH_API + +PX_INLINE void Scb::Scene::setClothInterCollisionDistance(PxF32 distance) +{ + if (!isPhysicsBuffering()) + { + mScene.setClothInterCollisionDistance(distance); + } + else + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::setClothInterCollisionDistance() not allowed while simulation is running. Call will be ignored."); + } +} + +PX_INLINE PxF32 Scb::Scene::getClothInterCollisionDistance() const +{ + return mScene.getClothInterCollisionDistance(); +} + +PX_INLINE void Scb::Scene::setClothInterCollisionStiffness(PxF32 stiffness) +{ + if (!isPhysicsBuffering()) + { + mScene.setClothInterCollisionStiffness(stiffness); + } + else + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::setClothInterCollisionStiffness() not allowed while simulation is running. Call will be ignored."); + } +} + +PX_INLINE PxF32 Scb::Scene::getClothInterCollisionStiffness() const +{ + return mScene.getClothInterCollisionStiffness(); +} + +PX_INLINE void Scb::Scene::setClothInterCollisionNbIterations(PxU32 nbIterations) +{ + if (!isPhysicsBuffering()) + { + mScene.setClothInterCollisionNbIterations(nbIterations); + } + else + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::setClothInterCollisionNbIterations() not allowed while simulation is running. Call will be ignored."); + } +} + +PX_INLINE PxU32 Scb::Scene::getClothInterCollisionNbIterations() const +{ + return mScene.getClothInterCollisionNbIterations(); +} + +#endif + + +PX_INLINE void Scb::Scene::setVisualizationParameter(PxVisualizationParameter::Enum param, PxReal value) +{ + if (!isPhysicsBuffering()) + mScene.setVisualizationParameter(param, value); + else + { + PX_ASSERT(param < PxVisualizationParameter::eNUM_VALUES); + mBufferedData.visualizationParamChanged[param] = 1; + mBufferedData.visualizationParam[param] = value; + markUpdated(BF_VISUALIZATION); + } +} + +PX_INLINE PxReal Scb::Scene::getVisualizationParameter(PxVisualizationParameter::Enum param) const +{ + PX_ASSERT(param < PxVisualizationParameter::eNUM_VALUES); + + if (isBuffered(BF_VISUALIZATION) && mBufferedData.visualizationParamChanged[param]) + return mBufferedData.visualizationParam[param]; + else + return mScene.getVisualizationParameter(param); +} + +PX_INLINE void Scb::Scene::setVisualizationCullingBox(const PxBounds3& box) +{ + if (!isPhysicsBuffering()) + mScene.setVisualizationCullingBox(box); + else + { + mBufferedData.visualizationCullingBoxChanged = 1; + mBufferedData.visualizationCullingBox = box; + markUpdated(BF_VISUALIZATION); + } +} + +PX_INLINE const PxBounds3& Scb::Scene::getVisualizationCullingBox() const +{ + if (isBuffered(BF_VISUALIZATION) && mBufferedData.visualizationCullingBoxChanged) + return mBufferedData.visualizationCullingBox; + else + return mScene.getVisualizationCullingBox(); +} + +PX_INLINE PxU32 Scb::Scene::getNumActiveBodies() const +{ + return mScene.getNumActiveBodies(); +} +PX_INLINE Sc::BodyCore* const* Scb::Scene::getActiveBodiesArray() const +{ + return mScene.getActiveBodiesArray(); +} + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/buffering/ScbSceneBuffer.h b/PhysX_3.4/Source/PhysX/src/buffering/ScbSceneBuffer.h new file mode 100644 index 00000000..61fea2af --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/buffering/ScbSceneBuffer.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_SCB_SCENE_BUFFER +#define PX_PHYSICS_SCB_SCENE_BUFFER + +#include "CmPhysXCommon.h" + +#include "ScScene.h" + +#define PxClientBehaviorFlag_eNOT_BUFFERED PxClientBehaviorFlags(0xff) + +namespace physx +{ +namespace Scb +{ + +struct SceneBuffer +{ +public: + static const PxU32 sMaxNbDominanceGroups = 32; + + PX_INLINE SceneBuffer(); + + PX_INLINE void clearDominanceBuffer(); + PX_INLINE void setDominancePair(PxU32 group1, PxU32 group2, const PxDominanceGroupPair& dominance); + PX_INLINE bool getDominancePair(PxU32 group1, PxU32 group2, PxDominanceGroupPair& dominance) const; + PX_INLINE void syncDominancePairs(Sc::Scene& scene); + + PX_INLINE void clearVisualizationParams(); + + PxReal visualizationParam[PxVisualizationParameter::eNUM_VALUES]; + PxU8 visualizationParamChanged[PxVisualizationParameter::eNUM_VALUES]; + PxBounds3 visualizationCullingBox; + PxU8 visualizationCullingBoxChanged; + PxU32 dominancePairFlag[sMaxNbDominanceGroups - 1]; + PxU32 dominancePairValues[sMaxNbDominanceGroups]; + PxVec3 gravity; + PxReal bounceThresholdVelocity; + PxSceneFlags flags; + PxU32 solverBatchSize; + PxU32 numClientsCreated; + Ps::Array<PxClientBehaviorFlags> clientBehaviorFlags; //a value is buffered if it is not -1. +}; + + +PX_INLINE SceneBuffer::SceneBuffer() : clientBehaviorFlags(PX_DEBUG_EXP("clientBehaviorFlags")) +{ + clearDominanceBuffer(); + clearVisualizationParams(); + numClientsCreated = 0; + clientBehaviorFlags.pushBack(PxClientBehaviorFlag_eNOT_BUFFERED); //need member for default client, PxClientBehaviorFlag_eNOT_BUFFERED means its not storing anything. +} + + +PX_INLINE void SceneBuffer::clearDominanceBuffer() +{ + PxMemSet(&dominancePairFlag, 0, (sMaxNbDominanceGroups - 1) * sizeof(PxU32)); +} + + +PX_INLINE void SceneBuffer::clearVisualizationParams() +{ + PxMemZero(visualizationParamChanged, PxVisualizationParameter::eNUM_VALUES * sizeof(PxU8)); +} + + +PX_INLINE void SceneBuffer::setDominancePair(PxU32 group1, PxU32 group2, const PxDominanceGroupPair& dominance) +{ + PX_ASSERT(group1 != group2); + PX_ASSERT(group1 < sMaxNbDominanceGroups); + PX_ASSERT(group2 < sMaxNbDominanceGroups); + + if (group1 < group2) + dominancePairFlag[group1] = dominancePairFlag[group1] | (1 << group2); + else + dominancePairFlag[group2] = dominancePairFlag[group2] | (1 << group1); + + if (dominance.dominance0 != 0.0f) + dominancePairValues[group1] = dominancePairValues[group1] | (1 << group2); + else + dominancePairValues[group1] = dominancePairValues[group1] & (~(1 << group2)); + + if (dominance.dominance1 != 0.0f) + dominancePairValues[group2] = dominancePairValues[group2] | (1 << group1); + else + dominancePairValues[group2] = dominancePairValues[group2] & (~(1 << group1)); +} + + +PX_INLINE bool SceneBuffer::getDominancePair(PxU32 group1, PxU32 group2, PxDominanceGroupPair& dominance) const +{ + PX_ASSERT(group1 != group2); + PX_ASSERT(group1 < sMaxNbDominanceGroups); + PX_ASSERT(group2 < sMaxNbDominanceGroups); + + PxU32 isBuffered = 0; + if (group1 < group2) + isBuffered = dominancePairFlag[group1] & (1 << group2); + else + isBuffered = dominancePairFlag[group2] & (1 << group1); + + if (isBuffered) + { + dominance.dominance0 = PxU8((dominancePairValues[group1] & (1 << group2)) >> group2 ); + dominance.dominance1 = PxU8((dominancePairValues[group2] & (1 << group1)) >> group1 ); + return true; + } + + return false; +} + + +PX_INLINE void SceneBuffer::syncDominancePairs(Sc::Scene& scene) +{ + for(PxU32 i=0; i < (sMaxNbDominanceGroups - 1); i++) + { + if (dominancePairFlag[i]) + { + for(PxU32 j=(i+1); j < sMaxNbDominanceGroups; j++) + { + PxDominanceGroupPair dominance(0, 0); + if (getDominancePair(i, j, dominance)) + { + scene.setDominanceGroupPair(PxDominanceGroup(i), PxDominanceGroup(j), dominance); + } + } + } + } +} + + +} // namespace Scb + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/buffering/ScbScenePvdClient.cpp b/PhysX_3.4/Source/PhysX/src/buffering/ScbScenePvdClient.cpp new file mode 100644 index 00000000..03161149 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/buffering/ScbScenePvdClient.cpp @@ -0,0 +1,1240 @@ +// 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. + +#if PX_SUPPORT_PVD +#include "NpCast.h" +#include "ScbScenePvdClient.h" +#include "PxActor.h" +#include "PxRenderBuffer.h" +#include "ScbScene.h" +#include "ScbNpDeps.h" +#include "PxPhysics.h" +#include "ScMaterialCore.h" +#include "PxsMaterialManager.h" +#include "ScBodySim.h" +#include "ScConstraintSim.h" +#include "ScParticleSystemCore.h" +#include "ScParticleSystemSim.h" + +#include "PxConstraintDesc.h" +#include "ScConstraintCore.h" +#include "PvdTypeNames.h" + +#include "gpu/PxParticleGpu.h" +#include "PxPvdUserRenderer.h" +#include "PxvNphaseImplementationContext.h" + +using namespace physx; +using namespace physx::Vd; +using namespace physx::pvdsdk; +using namespace Scb; + + +namespace +{ + PX_FORCE_INLINE PxU64 getContextId(Scb::Scene& scene) { return scene.getContextId(); } + + /////////////////////////////////////////////////////////////////////////////// + + // Sc-to-Np + PX_FORCE_INLINE static NpConstraint* getNpConstraint(Sc::ConstraintCore* scConstraint) + { + const size_t scOffset = reinterpret_cast<size_t>(&(reinterpret_cast<Scb::Constraint*>(0)->getScConstraint())); + const size_t scbOffset = reinterpret_cast<size_t>(&(reinterpret_cast<NpConstraint*>(0)->getScbConstraint())); + return reinterpret_cast<NpConstraint*>(reinterpret_cast<char*>(scConstraint) - scOffset - scbOffset); + } + +#if PX_USE_PARTICLE_SYSTEM_API + + // Sc-to-Scb + PX_FORCE_INLINE static Scb::ParticleSystem* getScbParticleSystem(Sc::ParticleSystemCore* scParticleSystem) + { + const size_t offset = reinterpret_cast<size_t>(&(reinterpret_cast<Scb::ParticleSystem*>(0)->getScParticleSystem())); + return reinterpret_cast<Scb::ParticleSystem*>(reinterpret_cast<char*>(scParticleSystem) - offset); + } + +#endif + + /////////////////////////////////////////////////////////////////////////////// + + PX_FORCE_INLINE static const PxActor* getPxActor(const Scb::Actor* scbActor) + { + const PxActorType::Enum type = scbActor->getActorCore().getActorCoreType(); + if(type == PxActorType::eRIGID_DYNAMIC) + { + return getNpRigidDynamic(static_cast<const Scb::Body*>(scbActor)); + } + else if(type == PxActorType::eRIGID_STATIC) + { + return getNpRigidStatic(static_cast<const Scb::RigidStatic*>(scbActor)); + } +#if PX_USE_PARTICLE_SYSTEM_API + else if(type == PxActorType::ePARTICLE_SYSTEM) + { + return getNpParticleSystem(static_cast<const Scb::ParticleSystem*>(scbActor)); + } + else if(type == PxActorType::ePARTICLE_FLUID) + { + return getNpParticleFluid(static_cast<const Scb::ParticleSystem*>(scbActor)); + } +#endif + else if(type == PxActorType::eARTICULATION_LINK) + { + return getNpArticulationLink(static_cast<const Scb::Body*>(scbActor)); + } +#if PX_USE_CLOTH_API + else if(type == PxActorType::eCLOTH) + { + return getNpCloth(const_cast<Scb::Cloth*>(static_cast<const Scb::Cloth*>(scbActor))); + } +#endif + + return NULL; + } + + struct CreateOp + { + CreateOp& operator=(const CreateOp&); + physx::pvdsdk::PvdDataStream& mStream; + PvdMetaDataBinding& mBinding; + PsPvd* mPvd; + PxScene& mScene; + CreateOp(physx::pvdsdk::PvdDataStream& str, PvdMetaDataBinding& bind, PsPvd* pvd, PxScene& scene) + : mStream(str), mBinding(bind), mPvd(pvd), mScene(scene) + { + } + template <typename TDataType> + void operator()(const TDataType& dtype) + { + mBinding.createInstance(mStream, dtype, mScene, mPvd); + } + void operator()(const PxArticulationLink&) + { + } +#if PX_USE_PARTICLE_SYSTEM_API + void operator()(const PxParticleSystem& dtype) + { + mBinding.createInstance(mStream, dtype, mScene); + } + void operator()(const PxParticleFluid& dtype) + { + mBinding.createInstance(mStream, dtype, mScene); + } +#endif + }; + + struct UpdateOp + { + UpdateOp& operator=(const UpdateOp&); + physx::pvdsdk::PvdDataStream& mStream; + PvdMetaDataBinding& mBinding; + UpdateOp(physx::pvdsdk::PvdDataStream& str, PvdMetaDataBinding& bind) : mStream(str), mBinding(bind) + { + } + template <typename TDataType> + void operator()(const TDataType& dtype) + { + mBinding.sendAllProperties(mStream, dtype); + } + }; + + struct DestroyOp + { + DestroyOp& operator=(const DestroyOp&); + physx::pvdsdk::PvdDataStream& mStream; + PvdMetaDataBinding& mBinding; + PxScene& mScene; + DestroyOp(physx::pvdsdk::PvdDataStream& str, PvdMetaDataBinding& bind, PxScene& scene) + : mStream(str), mBinding(bind), mScene(scene) + { + } + template <typename TDataType> + void operator()(const TDataType& dtype) + { + mBinding.destroyInstance(mStream, dtype, mScene); + } + void operator()(const PxArticulationLink& dtype) + { + mBinding.destroyInstance(mStream, dtype); + } +#if PX_USE_PARTICLE_SYSTEM_API + void operator()(const PxParticleSystem& dtype) + { + mBinding.destroyInstance(mStream, dtype, mScene); + } + void operator()(const PxParticleFluid& dtype) + { + mBinding.destroyInstance(mStream, dtype, mScene); + } +#endif + }; + + template <typename TOperator> + inline void BodyTypeOperation(const Scb::Body* scbBody, TOperator op) + { + bool isArticulationLink = scbBody->getActorType() == PxActorType::eARTICULATION_LINK; + if(isArticulationLink) + { + const NpArticulationLink* link = getNpArticulationLink(scbBody); + op(*static_cast<const PxArticulationLink*>(link)); + } + else + { + const NpRigidDynamic* npRigidDynamic = getNpRigidDynamic(scbBody); + op(*static_cast<const PxRigidDynamic*>(npRigidDynamic)); + } + } + + template <typename TOperator> + inline void ActorTypeOperation(const PxActor* actor, TOperator op) + { + switch(actor->getType()) + { + case PxActorType::eRIGID_STATIC: + op(*static_cast<const PxRigidStatic*>(actor)); + break; + case PxActorType::eRIGID_DYNAMIC: + op(*static_cast<const PxRigidDynamic*>(actor)); + break; + case PxActorType::eARTICULATION_LINK: + op(*static_cast<const PxArticulationLink*>(actor)); + break; +#if PX_USE_PARTICLE_SYSTEM_API + case PxActorType::ePARTICLE_SYSTEM: + op(*static_cast<const PxParticleSystem*>(actor)); + break; + case PxActorType::ePARTICLE_FLUID: + op(*static_cast<const PxParticleFluid*>(actor)); + break; +#endif +#if PX_USE_CLOTH_API + case PxActorType::eCLOTH: + op(*static_cast<const PxCloth*>(actor)); + break; +#endif + case PxActorType::eACTOR_COUNT: + case PxActorType::eACTOR_FORCE_DWORD: + PX_ASSERT(false); + break; + }; + } + + namespace + { + struct PvdConstraintVisualizer : public PxConstraintVisualizer + { + PX_NOCOPY(PvdConstraintVisualizer) + public: + physx::pvdsdk::PvdUserRenderer& mRenderer; + PvdConstraintVisualizer(const void* id, physx::pvdsdk::PvdUserRenderer& r) : mRenderer(r) + { + mRenderer.setInstanceId(id); + } + virtual void visualizeJointFrames(const PxTransform& parent, const PxTransform& child) + { + mRenderer.visualizeJointFrames(parent, child); + } + + virtual void visualizeLinearLimit(const PxTransform& t0, const PxTransform& t1, PxReal value, bool active) + { + mRenderer.visualizeLinearLimit(t0, t1, PxF32(value), active); + } + + virtual void visualizeAngularLimit(const PxTransform& t0, PxReal lower, PxReal upper, bool active) + { + mRenderer.visualizeAngularLimit(t0, PxF32(lower), PxF32(upper), active); + } + + virtual void visualizeLimitCone(const PxTransform& t, PxReal ySwing, PxReal zSwing, bool active) + { + mRenderer.visualizeLimitCone(t, PxF32(ySwing), PxF32(zSwing), active); + } + + virtual void visualizeDoubleCone(const PxTransform& t, PxReal angle, bool active) + { + mRenderer.visualizeDoubleCone(t, PxF32(angle), active); + } + }; + } + + class SceneRendererClient : public RendererEventClient, public physx::shdfnd::UserAllocated + { + PX_NOCOPY(SceneRendererClient) + public: + SceneRendererClient(PvdUserRenderer* renderer, PxPvd* pvd):mRenderer(renderer) + { + mStream = PvdDataStream::create(pvd); + mStream->createInstance(renderer); + } + + ~SceneRendererClient() + { + mStream->destroyInstance(mRenderer); + mStream->release(); + } + + virtual void handleBufferFlush(const uint8_t* inData, uint32_t inLength) + { + mStream->setPropertyValue(mRenderer, "events", inData, inLength); + } + + private: + + PvdUserRenderer* mRenderer; + PvdDataStream* mStream; + }; + +} // namespace + +ScbScenePvdClient::ScbScenePvdClient(Scb::Scene& scene) + : mPvd(NULL), mScbScene(scene), mPvdDataStream(NULL), mUserRender(NULL), mRenderClient(NULL), mIsConnected(false) +{ +} + +ScbScenePvdClient::~ScbScenePvdClient() +{ + if(mPvd) + mPvd->removeClient(this); +} + +void ScbScenePvdClient::updateCamera(const char* name, const PxVec3& origin, const PxVec3& up, const PxVec3& target) +{ + if(mIsConnected) + mPvdDataStream->updateCamera(name, origin, up, target); +} + +void ScbScenePvdClient::drawPoints(const PvdDebugPoint* points, PxU32 count) +{ + if(mUserRender) + mUserRender->drawPoints(points, count); +} + +void ScbScenePvdClient::drawLines(const PvdDebugLine* lines, PxU32 count) +{ + if(mUserRender) + mUserRender->drawLines(lines, count); +} + +void ScbScenePvdClient::drawTriangles(const PvdDebugTriangle* triangles, PxU32 count) +{ + if(mUserRender) + mUserRender->drawTriangles(triangles, count); +} + +void ScbScenePvdClient::drawText(const PvdDebugText& text) +{ + if(mUserRender) + mUserRender->drawText(text); +} + +PvdUserRenderer* ScbScenePvdClient::getUserRender() +{ + return mUserRender; +} + + +PsPvd* ScbScenePvdClient::getPsPvd() +{ + return mPvd; +} + +void ScbScenePvdClient::setPsPvd(PsPvd* pvd) +{ + mPvd = pvd; +} + +physx::pvdsdk::PvdClient* ScbScenePvdClient::getClientInternal() +{ + return this; +} + +void ScbScenePvdClient::setScenePvdFlag(PxPvdSceneFlag::Enum flag, bool value) +{ + if(value) + mFlags |= flag; + else + mFlags &= ~flag; +} + +void ScbScenePvdClient::setScenePvdFlags(PxPvdSceneFlags flags) +{ + mFlags = flags; +} + +PxPvdSceneFlags ScbScenePvdClient::getScenePvdFlags() const +{ + return mFlags; +} + +bool ScbScenePvdClient::isConnected() const +{ + return mIsConnected; +} + +void ScbScenePvdClient::onPvdConnected() +{ + if(mIsConnected || !mPvd) + return; + + mIsConnected = true; + + + mPvdDataStream = PvdDataStream::create(mPvd); + + mUserRender = PvdUserRenderer::create(); + mRenderClient = PX_NEW(SceneRendererClient)(mUserRender, mPvd); + mUserRender->setClient(mRenderClient); + sendEntireScene(); +} + +void ScbScenePvdClient::onPvdDisconnected() +{ + if(!mIsConnected) + return; + mIsConnected = false; + + PX_DELETE(mRenderClient); + mRenderClient = NULL; + mUserRender->release(); + mUserRender = NULL; + mPvdDataStream->release(); + mPvdDataStream = NULL; +} + +void ScbScenePvdClient::flush() +{ +} + +PvdDataStream* ScbScenePvdClient::getDataStream() +{ + return mPvdDataStream; +} + +PvdMetaDataBinding* ScbScenePvdClient::getMetaDataBinding() +{ + return &mMetaDataBinding; +} + +void ScbScenePvdClient::updatePvdProperties() +{ + mMetaDataBinding.sendAllProperties(*mPvdDataStream, *mScbScene.getPxScene()); +} + +void ScbScenePvdClient::releasePvdInstance() +{ + if(mPvdDataStream) + { + PxScene* theScene = mScbScene.getPxScene(); + // remove from parent + mPvdDataStream->removeObjectRef(&PxGetPhysics(), "Scenes", theScene); + mPvdDataStream->destroyInstance(theScene); + } +} + +// PT: this is only called once, from "onPvdConnected" +void ScbScenePvdClient::sendEntireScene() +{ + NpScene* npScene = static_cast<NpScene*>(mScbScene.getPxScene()); + + if(npScene->getFlagsFast() & PxSceneFlag::eREQUIRE_RW_LOCK) // getFlagsFast() will trigger a warning of lock check + npScene->lockRead(__FILE__, __LINE__); + + { + PxScene* theScene = mScbScene.getPxScene(); + mPvdDataStream->createInstance(theScene); + updatePvdProperties(); + + PxPhysics* physics = &PxGetPhysics(); + // Create parent/child relationship. + mPvdDataStream->setPropertyValue(theScene, "Physics", reinterpret_cast<const void*>(physics)); + mPvdDataStream->pushBackObjectRef(physics, "Scenes", theScene); + } + + // materials: + { + PxsMaterialManager& manager = mScbScene.getScScene().getMaterialManager(); + PxsMaterialManagerIterator iter(manager); + PxsMaterialCore* mat; + while(iter.getNextMaterial(mat)) + { + const PxMaterial* theMaterial = mat->getNxMaterial(); + if(mPvd->registerObject(theMaterial)) + mMetaDataBinding.createInstance(*mPvdDataStream, *theMaterial, PxGetPhysics()); + }; + } + + if(mPvd->getInstrumentationFlags() & PxPvdInstrumentationFlag::eDEBUG) + { + Ps::Array<PxActor*> actorArray; + + // RBs + // static: + { + PxU32 numActors = npScene->getNbActors(PxActorTypeFlag::eRIGID_STATIC | PxActorTypeFlag::eRIGID_DYNAMIC); + actorArray.resize(numActors); + npScene->getActors(PxActorTypeFlag::eRIGID_STATIC | PxActorTypeFlag::eRIGID_DYNAMIC, actorArray.begin(), + actorArray.size()); + for(PxU32 i = 0; i < numActors; i++) + { + PxActor* pxActor = actorArray[i]; + if(pxActor->is<PxRigidStatic>()) + mMetaDataBinding.createInstance(*mPvdDataStream, *static_cast<PxRigidStatic*>(pxActor), *npScene, mPvd); + else + mMetaDataBinding.createInstance(*mPvdDataStream, *static_cast<PxRigidDynamic*>(pxActor), *npScene, mPvd); + } + } + // articulations & links + { + Ps::Array<PxArticulation*> articulations; + PxU32 numArticulations = npScene->getNbArticulations(); + articulations.resize(numArticulations); + npScene->getArticulations(articulations.begin(), articulations.size()); + for(PxU32 i = 0; i < numArticulations; i++) + mMetaDataBinding.createInstance(*mPvdDataStream, *articulations[i], *npScene, mPvd); + } + +#if PX_USE_PARTICLE_SYSTEM_API + // particle systems & fluids: + { + PxU32 nbParticleSystems = mScbScene.getScScene().getNbParticleSystems(); + Sc::ParticleSystemCore* const* particleSystems = mScbScene.getScScene().getParticleSystems(); + for(PxU32 i = 0; i < nbParticleSystems; i++) + { + Sc::ParticleSystemCore* scParticleSystem = particleSystems[i]; + createPvdInstance(scParticleSystem->getPxParticleBase()); + } + } +#endif + +#if PX_USE_CLOTH_API + // cloth + { + Ps::Array<PxActor*> cloths; + PxU32 numActors = npScene->getNbActors(PxActorTypeFlag::eCLOTH); + cloths.resize(numActors); + npScene->getActors(PxActorTypeFlag::eCLOTH, cloths.begin(), cloths.size()); + for(PxU32 i = 0; i < numActors; i++) + { + Scb::Cloth* scbCloth = &static_cast<NpCloth*>(cloths[i])->getScbCloth(); + createPvdInstance(scbCloth); + } + } +#endif + + // joints + { + Sc::ConstraintCore*const * constraints = mScbScene.getScScene().getConstraints(); + PxU32 nbConstraints = mScbScene.getScScene().getNbConstraints(); + for(PxU32 i = 0; i < nbConstraints; i++) + { + updateConstraint(*constraints[i], PxPvdUpdateType::CREATE_INSTANCE); + updateConstraint(*constraints[i], PxPvdUpdateType::UPDATE_ALL_PROPERTIES); + } + } + } + + if(npScene->getFlagsFast() & PxSceneFlag::eREQUIRE_RW_LOCK) + npScene->unlockRead(); +} + +void ScbScenePvdClient::updateConstraint(const Sc::ConstraintCore& scConstraint, PxU32 updateType) +{ + PxConstraintConnector* conn = scConstraint.getPxConnector(); + if(conn && checkPvdDebugFlag()) + conn->updatePvdProperties(*mPvdDataStream, scConstraint.getPxConstraint(), PxPvdUpdateType::Enum(updateType)); +} + +void ScbScenePvdClient::createPvdInstance(const PxActor* actor) +{ + if(checkPvdDebugFlag()) + ActorTypeOperation(actor, CreateOp(*mPvdDataStream, mMetaDataBinding, mPvd, *mScbScene.getPxScene())); +} + +void ScbScenePvdClient::updatePvdProperties(const PxActor* actor) +{ + if(checkPvdDebugFlag()) + ActorTypeOperation(actor, UpdateOp(*mPvdDataStream, mMetaDataBinding)); +} + +void ScbScenePvdClient::releasePvdInstance(const PxActor* actor) +{ + if(checkPvdDebugFlag()) + ActorTypeOperation(actor, DestroyOp(*mPvdDataStream, mMetaDataBinding, *mScbScene.getPxScene())); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ScbScenePvdClient::createPvdInstance(const Scb::Actor* actor) +{ + // PT: why not UPDATE_PVD_PROPERTIES_CHECK() here? + createPvdInstance(getPxActor(actor)); +} + +void ScbScenePvdClient::updatePvdProperties(const Scb::Actor* actor) +{ + // PT: why not UPDATE_PVD_PROPERTIES_CHECK() here? + updatePvdProperties(getPxActor(actor)); +} + +void ScbScenePvdClient::releasePvdInstance(const Scb::Actor* actor) +{ + // PT: why not UPDATE_PVD_PROPERTIES_CHECK() here? + releasePvdInstance(getPxActor(actor)); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ScbScenePvdClient::createPvdInstance(const Scb::Body* body) +{ + if(checkPvdDebugFlag() && body->getActorType() != PxActorType::eARTICULATION_LINK) + BodyTypeOperation(body, CreateOp(*mPvdDataStream, mMetaDataBinding, mPvd, *mScbScene.getPxScene())); +} + +void ScbScenePvdClient::updatePvdProperties(const Scb::Body* body) +{ + if(checkPvdDebugFlag()) + BodyTypeOperation(body, UpdateOp(*mPvdDataStream, mMetaDataBinding)); +} + +void ScbScenePvdClient::updateKinematicTarget(const Scb::Body* body, const PxTransform& p) +{ + if(checkPvdDebugFlag()) + mPvdDataStream->setPropertyValue(getNpRigidDynamic(body), "KinematicTarget", p); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ScbScenePvdClient::createPvdInstance(const Scb::RigidStatic* rigidStatic) +{ + if(checkPvdDebugFlag()) + mMetaDataBinding.createInstance(*mPvdDataStream, *getNpRigidStatic(rigidStatic), *mScbScene.getPxScene(), mPvd); +} + +void ScbScenePvdClient::updatePvdProperties(const Scb::RigidStatic* rigidStatic) +{ + if(checkPvdDebugFlag()) + mMetaDataBinding.sendAllProperties(*mPvdDataStream, *getNpRigidStatic(rigidStatic)); +} + +void ScbScenePvdClient::releasePvdInstance(const Scb::RigidObject* rigidObject) +{ + releasePvdInstance(getPxActor(rigidObject)); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ScbScenePvdClient::createPvdInstance(const Scb::Constraint* constraint) +{ + if(checkPvdDebugFlag()) + updateConstraint(constraint->getScConstraint(), PxPvdUpdateType::CREATE_INSTANCE); +} + +void ScbScenePvdClient::updatePvdProperties(const Scb::Constraint* constraint) +{ + if(checkPvdDebugFlag()) + updateConstraint(constraint->getScConstraint(), PxPvdUpdateType::UPDATE_ALL_PROPERTIES); +} + +void ScbScenePvdClient::releasePvdInstance(const Scb::Constraint* constraint) +{ + const Sc::ConstraintCore& scConstraint = constraint->getScConstraint(); + PxConstraintConnector* conn; + if(checkPvdDebugFlag() && (conn = scConstraint.getPxConnector()) != NULL) + conn->updatePvdProperties(*mPvdDataStream, scConstraint.getPxConstraint(), PxPvdUpdateType::RELEASE_INSTANCE); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ScbScenePvdClient::createPvdInstance(const Scb::Articulation* articulation) +{ + if(checkPvdDebugFlag()) + mMetaDataBinding.createInstance(*mPvdDataStream, *getNpArticulation(articulation), *mScbScene.getPxScene(), mPvd); +} + +void ScbScenePvdClient::updatePvdProperties(const Scb::Articulation* articulation) +{ + if(checkPvdDebugFlag()) + mMetaDataBinding.sendAllProperties(*mPvdDataStream, *getNpArticulation(articulation)); +} + +void ScbScenePvdClient::releasePvdInstance(const Scb::Articulation* articulation) +{ + if(checkPvdDebugFlag()) + mMetaDataBinding.destroyInstance(*mPvdDataStream, *getNpArticulation(articulation), *mScbScene.getPxScene()); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ScbScenePvdClient::createPvdInstance(const Scb::ArticulationJoint* articulationJoint) +{ + PX_UNUSED(articulationJoint); +} + +void ScbScenePvdClient::updatePvdProperties(const Scb::ArticulationJoint* articulationJoint) +{ + if(checkPvdDebugFlag()) + mMetaDataBinding.sendAllProperties(*mPvdDataStream, *getNpArticulationJoint(articulationJoint)); +} + +void ScbScenePvdClient::releasePvdInstance(const Scb::ArticulationJoint* articulationJoint) +{ + PX_UNUSED(articulationJoint); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ScbScenePvdClient::createPvdInstance(const Sc::MaterialCore* materialCore) +{ + if(checkPvdDebugFlag()) + { + const PxMaterial* theMaterial = materialCore->getNxMaterial(); + if(mPvd->registerObject(theMaterial)) + mMetaDataBinding.createInstance(*mPvdDataStream, *theMaterial, PxGetPhysics()); + } +} + +void ScbScenePvdClient::updatePvdProperties(const Sc::MaterialCore* materialCore) +{ + if(checkPvdDebugFlag()) + mMetaDataBinding.sendAllProperties(*mPvdDataStream, *materialCore->getNxMaterial()); +} + +void ScbScenePvdClient::releasePvdInstance(const Sc::MaterialCore* materialCore) +{ + if(checkPvdDebugFlag() && mPvd->unRegisterObject(materialCore->getNxMaterial() ) ) + mMetaDataBinding.destroyInstance(*mPvdDataStream, *materialCore->getNxMaterial(), PxGetPhysics()); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ScbScenePvdClient::createPvdInstance(const Scb::Shape* shape, PxActor& owner) +{ + if(checkPvdDebugFlag()) + { + PX_PROFILE_ZONE("PVD.createPVDInstance", getContextId(mScbScene)); + const PxShape* npShape = getNpShape(shape); + mMetaDataBinding.createInstance(*mPvdDataStream, *npShape, static_cast<PxRigidActor&>(owner), mPvd); + } +} + +static void addShapesToPvd(PxU32 nbShapes, void* const* shapes, const size_t offset, PxActor& pxActor, PsPvd* pvd, PvdDataStream& stream, PvdMetaDataBinding& binding) +{ + for(PxU32 i=0;i<nbShapes;i++) + { + const Scb::Shape* shape = reinterpret_cast<Scb::Shape*>(reinterpret_cast<char*>(shapes[i]) + offset); + const PxShape* npShape = getNpShape(shape); + binding.createInstance(stream, *npShape, static_cast<PxRigidActor&>(pxActor), pvd); + } +} + +void ScbScenePvdClient::addBodyAndShapesToPvd(Scb::Body& b) +{ + if(checkPvdDebugFlag()) + { + PX_PROFILE_ZONE("PVD.createPVDInstance", getContextId(mScbScene)); + createPvdInstance(&b); + + const size_t offset = NpShapeGetScPtrOffset() - Scb::Shape::getScOffset(); + PxActor& pxActor = *b.getScBody().getPxActor(); + + void* const* shapes; + const PxU32 nbShapes = NpRigidDynamicGetShapes(b, shapes); + addShapesToPvd(nbShapes, shapes, offset, pxActor, mPvd, *mPvdDataStream, mMetaDataBinding); + } +} + +void ScbScenePvdClient::addStaticAndShapesToPvd(Scb::RigidStatic& s) +{ + if(checkPvdDebugFlag()) + { + PX_PROFILE_ZONE("PVD.createPVDInstance", getContextId(mScbScene)); + createPvdInstance(&s); + + const size_t offset = NpShapeGetScPtrOffset() - Scb::Shape::getScOffset(); + PxActor& pxActor = *s.getScStatic().getPxActor(); + + void* const* shapes; + const PxU32 nbShapes = NpRigidStaticGetShapes(s, shapes); + addShapesToPvd(nbShapes, shapes, offset, pxActor, mPvd, *mPvdDataStream, mMetaDataBinding); + } +} + +void ScbScenePvdClient::updateMaterials(const Scb::Shape* shape) +{ + if(checkPvdDebugFlag()) + mMetaDataBinding.updateMaterials(*mPvdDataStream, *getNpShape(const_cast<Scb::Shape*>(shape)), mPvd); +} + +void ScbScenePvdClient::updatePvdProperties(const Scb::Shape* shape) +{ + if(checkPvdDebugFlag()) + mMetaDataBinding.sendAllProperties(*mPvdDataStream, *getNpShape(const_cast<Scb::Shape*>(shape))); +} + +void ScbScenePvdClient::releaseAndRecreateGeometry(const Scb::Shape* shape) +{ + if(checkPvdDebugFlag()) + mMetaDataBinding.releaseAndRecreateGeometry(*mPvdDataStream, *getNpShape(const_cast<Scb::Shape*>(shape)), + NpPhysics::getInstance(), mPvd); +} + +void ScbScenePvdClient::releasePvdInstance(const Scb::Shape* shape, PxActor& owner) +{ + if(checkPvdDebugFlag()) + { + PX_PROFILE_ZONE("PVD.releasePVDInstance", getContextId(mScbScene)); + + const NpShape* npShape = getNpShape(shape); + mMetaDataBinding.destroyInstance(*mPvdDataStream, *npShape, static_cast<PxRigidActor&>(owner)); + + const PxU32 numMaterials = npShape->getNbMaterials(); + PX_ALLOCA(materialPtr, PxMaterial*, numMaterials); + npShape->getMaterials(materialPtr, numMaterials); + + for(PxU32 idx = 0; idx < numMaterials; ++idx) + releasePvdInstance(&(static_cast<NpMaterial*>(materialPtr[idx])->getScMaterial())); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void ScbScenePvdClient::originShift(PxVec3 shift) +{ + mMetaDataBinding.originShift(*mPvdDataStream, mScbScene.getPxScene(), shift); +} + +template <typename TPropertyType> +void ScbScenePvdClient::sendArray(const void* instance, const char* propName, const Cm::BitMap* bitMap, + PxU32 nbValidParticles, PxStrideIterator<const TPropertyType>& iterator) +{ + PX_ASSERT(nbValidParticles > 0); + if(!iterator.ptr()) + return; + + // setup the pvd array PxParticleFlags + pvdsdk::DataRef<const PxU8> propData; + Ps::Array<PxU8> mTempU8Array; + mTempU8Array.resize(nbValidParticles * sizeof(TPropertyType)); + TPropertyType* tmpArray = reinterpret_cast<TPropertyType*>(mTempU8Array.begin()); + propData = pvdsdk::DataRef<const PxU8>(mTempU8Array.begin(), mTempU8Array.size()); + + PxU32 tIdx = 0; + Cm::BitMap::Iterator it(*bitMap); + for(PxU32 index = it.getNext(); index != Cm::BitMap::Iterator::DONE; index = it.getNext()) + { + tmpArray[tIdx++] = iterator[index]; + } + PX_ASSERT(tIdx == nbValidParticles); + + mPvdDataStream->setPropertyValue(instance, propName, propData, + pvdsdk::getPvdNamespacedNameForType<TPropertyType>()); +} + +void ScbScenePvdClient::sendStateDatas(Sc::ParticleSystemCore* psCore) +{ + PX_UNUSED(psCore); +#if PX_USE_PARTICLE_SYSTEM_API + + if(!checkPvdDebugFlag()) + return; + + Scb::ParticleSystem* scbParticleSystem = getScbParticleSystem(psCore); + bool doProcess = scbParticleSystem->getFlags() & PxParticleBaseFlag::eENABLED; +#if PX_SUPPORT_GPU_PHYSX + doProcess &= (scbParticleSystem->getDeviceExclusiveAccessGpu() == NULL); +#endif + if(doProcess) + { + Sc::ParticleSystemSim* particleSystem = psCore->getSim(); + Pt::ParticleSystemStateDataDesc stateData; + particleSystem->getParticleState().getParticlesV(stateData, true, false); + Pt::ParticleSystemSimDataDesc simParticleData; + particleSystem->getSimParticleData(simParticleData, false); + + const PxActor* pxActor = getPxActor(scbParticleSystem); + + // mPvdDataStream->setPropertyValue( pxActor, "WorldBounds", psCore->getWorldBounds()); + mPvdDataStream->setPropertyValue(pxActor, "NbParticles", stateData.numParticles); + mPvdDataStream->setPropertyValue(pxActor, "ValidParticleRange", stateData.validParticleRange); + + if(stateData.validParticleRange > 0) + { + mPvdDataStream->setPropertyValue(pxActor, "ValidParticleBitmap", stateData.bitMap->getWords(), + (stateData.validParticleRange >> 5) + 1); + sendArray<PxVec3>(pxActor, "Positions", stateData.bitMap, stateData.numParticles, stateData.positions); + sendArray<PxVec3>(pxActor, "Velocities", stateData.bitMap, stateData.numParticles, stateData.velocities); + sendArray<PxF32>(pxActor, "RestOffsets", stateData.bitMap, stateData.numParticles, stateData.restOffsets); + sendArray<PxVec3>(pxActor, "CollisionNormals", stateData.bitMap, stateData.numParticles, + simParticleData.collisionNormals); + sendArray<PxF32>(pxActor, "Densities", stateData.bitMap, stateData.numParticles, simParticleData.densities); + // todo: twoway data if need more particle retrieval + + { // send PxParticleFlags, we have Pt::ParticleFlags here + pvdsdk::DataRef<const PxU8> propData; + Ps::Array<PxU8> mTempU8Array; + mTempU8Array.resize(stateData.numParticles * sizeof(PxU16)); + PxU16* tmpArray = reinterpret_cast<PxU16*>(mTempU8Array.begin()); + propData = pvdsdk::DataRef<const PxU8>(mTempU8Array.begin(), mTempU8Array.size()); + + PxU32 tIdx = 0; + PxStrideIterator<const Pt::ParticleFlags>& iterator = stateData.flags; + Cm::BitMap::Iterator it(*stateData.bitMap); + for(PxU32 index = it.getNext(); index != Cm::BitMap::Iterator::DONE; index = it.getNext()) + { + tmpArray[tIdx++] = iterator[index].api; + } + + mPvdDataStream->setPropertyValue(pxActor, "Flags", propData, + pvdsdk::getPvdNamespacedNameForType<PxU16>()); + } + } + } +#endif +} + +void ScbScenePvdClient::frameStart(PxReal simulateElapsedTime) +{ + PX_PROFILE_ZONE("Basic.pvdFrameStart", mScbScene.getContextId()); + + if(!mIsConnected) + return; + + mPvdDataStream->flushPvdCommand(); + mMetaDataBinding.sendBeginFrame(*mPvdDataStream, mScbScene.getPxScene(), simulateElapsedTime); +} + +void ScbScenePvdClient::frameEnd() +{ + PX_PROFILE_ZONE("Basic.pvdFrameEnd", mScbScene.getContextId()); + + if(!mIsConnected) + { + if(mPvd) + mPvd->flush(); // Even if we aren't connected, we may need to flush buffered events. + return; + } + + PxScene* theScene = mScbScene.getPxScene(); + + // Send the statistics for last frame. + void* tmp = NULL; +#if PX_SUPPORT_GPU_PHYSX + if(mScbScene.getScScene().getSceneGpu()) + { + NpPhysics& npPhysics = static_cast<NpPhysics&>(theScene->getPhysics()); + PxTriangleMeshCacheStatistics triMeshCacheStats = + npPhysics.getNpPhysicsGpu().getTriangleMeshCacheStatistics(*theScene); + tmp = &triMeshCacheStats; + } +#endif + mMetaDataBinding.sendStats(*mPvdDataStream, theScene, tmp); + + if(mPvd->getInstrumentationFlags() & PxPvdInstrumentationFlag::eDEBUG) + { +#if PX_USE_PARTICLE_SYSTEM_API + // particle systems & fluids: + { + PX_PROFILE_ZONE("PVD.updatePariclesAndFluids", getContextId(mScbScene)); + PxU32 nbParticleSystems = mScbScene.getScScene().getNbParticleSystems(); + Sc::ParticleSystemCore* const* particleSystems = mScbScene.getScScene().getParticleSystems(); + for(PxU32 i = 0; i < nbParticleSystems; i++) + { + sendStateDatas(particleSystems[i]); + } + } +#endif + +#if PX_USE_CLOTH_API + { + PX_PROFILE_ZONE("PVD.updateCloths", getContextId(mScbScene)); + mMetaDataBinding.updateCloths(*mPvdDataStream, *theScene); + } +#endif + } + + // flush our data to the main connection + mPvd->flush(); + + // End the frame *before* we send the dynamic object current data. + // This ensures that contacts end up synced with the rest of the system. + // Note that contacts were sent much earler in NpScene::fetchResults. + mMetaDataBinding.sendEndFrame(*mPvdDataStream, mScbScene.getPxScene()); + + if(mPvd->getInstrumentationFlags() & PxPvdInstrumentationFlag::eDEBUG) + { + PvdVisualizer* vizualizer = NULL; + const bool visualizeJoints = getScenePvdFlags() & PxPvdSceneFlag::eTRANSMIT_CONSTRAINTS; + if(visualizeJoints) + vizualizer = this; + + PX_PROFILE_ZONE("PVD.sceneUpdate", getContextId(mScbScene)); + mMetaDataBinding.updateDynamicActorsAndArticulations(*mPvdDataStream, theScene, vizualizer); + } + + // frame end moved to update contacts to have them in the previous frame. +} + +/////////////////////////////////////////////////////////////////////////////// + +void ScbScenePvdClient::createPvdInstance(const Scb::Aggregate* aggregate) +{ + if(checkPvdDebugFlag()) + { + PX_PROFILE_ZONE("PVD.createPVDInstance", getContextId(mScbScene)); + const NpAggregate* npAggregate = getNpAggregate(aggregate); + mMetaDataBinding.createInstance(*mPvdDataStream, *npAggregate, *mScbScene.getPxScene()); + } +} + +void ScbScenePvdClient::updatePvdProperties(const Scb::Aggregate* aggregate) +{ + if(checkPvdDebugFlag()) + mMetaDataBinding.sendAllProperties(*mPvdDataStream, *getNpAggregate(aggregate)); +} + +void ScbScenePvdClient::attachAggregateActor(const Scb::Aggregate* aggregate, Scb::Actor* actor) +{ + if(checkPvdDebugFlag()) + mMetaDataBinding.attachAggregateActor(*mPvdDataStream, *getNpAggregate(aggregate), *getPxActor(actor)); +} + +void ScbScenePvdClient::detachAggregateActor(const Scb::Aggregate* aggregate, Scb::Actor* actor) +{ + if(checkPvdDebugFlag()) + mMetaDataBinding.detachAggregateActor(*mPvdDataStream, *getNpAggregate(aggregate), *getPxActor(actor)); +} + +void ScbScenePvdClient::releasePvdInstance(const Scb::Aggregate* aggregate) +{ + if(checkPvdDebugFlag()) + { + PX_PROFILE_ZONE("PVD.releasePVDInstance", getContextId(mScbScene)); + const NpAggregate* npAggregate = getNpAggregate(aggregate); + mMetaDataBinding.destroyInstance(*mPvdDataStream, *npAggregate, *mScbScene.getPxScene()); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +#if PX_USE_CLOTH_API +static inline const PxCloth* toPx(const Scb::Cloth* cloth) +{ + const NpCloth* realCloth = getNpCloth(cloth); + return static_cast<const PxCloth*>(realCloth); +} + +void ScbScenePvdClient::createPvdInstance(const Scb::Cloth* cloth) +{ + if(checkPvdDebugFlag()) + mMetaDataBinding.createInstance(*mPvdDataStream, *getNpCloth(cloth), *mScbScene.getPxScene(), mPvd); +} + +void ScbScenePvdClient::sendSimpleProperties(const Scb::Cloth* cloth) +{ + if(checkPvdDebugFlag()) + mMetaDataBinding.sendSimpleProperties(*mPvdDataStream, *toPx(cloth)); +} + +void ScbScenePvdClient::sendMotionConstraints(const Scb::Cloth* cloth) +{ + if(checkPvdDebugFlag()) + mMetaDataBinding.sendMotionConstraints(*mPvdDataStream, *toPx(cloth)); +} + +void ScbScenePvdClient::sendSelfCollisionIndices(const Scb::Cloth* cloth) +{ + if(checkPvdDebugFlag()) + mMetaDataBinding.sendSelfCollisionIndices(*mPvdDataStream, *toPx(cloth)); +} + +void ScbScenePvdClient::sendRestPositions(const Scb::Cloth* cloth) +{ + if(checkPvdDebugFlag()) + mMetaDataBinding.sendRestPositions(*mPvdDataStream, *toPx(cloth)); +} + +void ScbScenePvdClient::sendSeparationConstraints(const Scb::Cloth* cloth) +{ + if(checkPvdDebugFlag()) + mMetaDataBinding.sendSeparationConstraints(*mPvdDataStream, *toPx(cloth)); +} + +void ScbScenePvdClient::sendCollisionSpheres(const Scb::Cloth* cloth) +{ + if(checkPvdDebugFlag()) + mMetaDataBinding.sendCollisionSpheres(*mPvdDataStream, *toPx(cloth)); +} + +void ScbScenePvdClient::sendCollisionCapsules(const Scb::Cloth* cloth) +{ + if(checkPvdDebugFlag()) + mMetaDataBinding.sendCollisionSpheres(*mPvdDataStream, *toPx(cloth), true); +} + +void ScbScenePvdClient::sendCollisionTriangles(const Scb::Cloth* cloth) +{ + if(checkPvdDebugFlag()) + mMetaDataBinding.sendCollisionTriangles(*mPvdDataStream, *toPx(cloth)); +} + +void ScbScenePvdClient::sendParticleAccelerations(const Scb::Cloth* cloth) +{ + if(checkPvdDebugFlag()) + mMetaDataBinding.sendParticleAccelerations(*mPvdDataStream, *toPx(cloth)); +} + +void ScbScenePvdClient::sendVirtualParticles(const Scb::Cloth* cloth) +{ + if(checkPvdDebugFlag()) + mMetaDataBinding.sendVirtualParticles(*mPvdDataStream, *toPx(cloth)); +} + +void ScbScenePvdClient::releasePvdInstance(const Scb::Cloth* cloth) +{ + if(checkPvdDebugFlag()) + mMetaDataBinding.destroyInstance(*mPvdDataStream, *toPx(cloth), *mScbScene.getPxScene()); +} +#endif // PX_USE_CLOTH_API + +/////////////////////////////////////////////////////////////////////////////// + +void ScbScenePvdClient::updateJoints() +{ + if(checkPvdDebugFlag()) + { + const bool visualizeJoints = getScenePvdFlags() & PxPvdSceneFlag::eTRANSMIT_CONTACTS; + + // joints + { + PX_PROFILE_ZONE("PVD.updateJoints", getContextId(mScbScene)); + Sc::ConstraintCore*const * constraints = mScbScene.getScScene().getConstraints(); + PxU32 nbConstraints = mScbScene.getScScene().getNbConstraints(); + PxI64 constraintCount = 0; + + for(PxU32 i = 0; i < nbConstraints; i++) + { + Sc::ConstraintCore* constraint = constraints[i]; + PxPvdUpdateType::Enum updateType = getNpConstraint(constraint)->isDirty() + ? PxPvdUpdateType::UPDATE_ALL_PROPERTIES + : PxPvdUpdateType::UPDATE_SIM_PROPERTIES; + updateConstraint(*constraint, updateType); + PxConstraintConnector* conn = constraint->getPxConnector(); + // visualization is updated here + { + PxU32 typeId = 0; + void* joint = NULL; + if(conn) + joint = conn->getExternalReference(typeId); + // visualize: + Sc::ConstraintSim* sim = constraint->getSim(); + if(visualizeJoints && sim && sim->getConstantsLL() && joint && constraint->getVisualize()) + { + Sc::BodySim* b0 = sim->getBody(0); + Sc::BodySim* b1 = sim->getBody(1); + PxTransform t0 = b0 ? b0->getBody2World() : PxTransform(PxIdentity); + PxTransform t1 = b1 ? b1->getBody2World() : PxTransform(PxIdentity); + PvdConstraintVisualizer viz(joint, *mUserRender); + (*constraint->getVisualize())(viz, sim->getConstantsLL(), t0, t1, 0xffffFFFF); + } + } + ++constraintCount; + } + + mUserRender->flushRenderEvents(); + } + } +} + +void ScbScenePvdClient::updateContacts() +{ + if(!checkPvdDebugFlag()) + return; + + // if contacts are disabled, send empty array and return + const PxScene* theScene(mScbScene.getPxScene()); + if(!(getScenePvdFlags() & PxPvdSceneFlag::eTRANSMIT_CONTACTS)) + { + mMetaDataBinding.sendContacts(*mPvdDataStream, *theScene); + return; + } + + PX_PROFILE_ZONE("PVD.updateContacts", getContextId(mScbScene)); + + PxsContactManagerOutputIterator outputIter; + + Sc::ContactIterator contactIter; + mScbScene.getScScene().initContactsIterator(contactIter, outputIter); + Sc::ContactIterator::Pair* pair; + Sc::Contact* contact; + Ps::Array<Sc::Contact> contacts; + while ((pair = contactIter.getNextPair()) != NULL) + { + while ((contact = pair->getNextContact()) != NULL) + contacts.pushBack(*contact); + } + + mMetaDataBinding.sendContacts(*mPvdDataStream, *theScene, contacts); +} + + +void ScbScenePvdClient::updateSceneQueries() +{ + // if contacts are disabled, send empty array and return + if(checkPvdDebugFlag() && (getScenePvdFlags() & PxPvdSceneFlag::eTRANSMIT_SCENEQUERIES)) + mMetaDataBinding.sendSceneQueries(*mPvdDataStream, *mScbScene.getPxScene(), mPvd); +} + +void ScbScenePvdClient::setCreateContactReports(bool b) +{ + mScbScene.getScScene().setCreateContactReports(b); +} + +void ScbScenePvdClient::visualize(PxArticulationLink& link) +{ + NpArticulationLink& npLink = static_cast<NpArticulationLink&>(link); + const void* itemId = npLink.getInboundJoint(); + if(itemId && mUserRender) + { + PvdConstraintVisualizer viz(itemId, *mUserRender); + npLink.visualizeJoint(viz); + } +} + +void ScbScenePvdClient::visualize(const PxRenderBuffer& debugRenderable) +{ + if(mUserRender) + { + mUserRender->drawRenderbuffer(reinterpret_cast<const PvdDebugPoint*>(debugRenderable.getPoints()), debugRenderable.getNbPoints(), + reinterpret_cast<const PvdDebugLine*>(debugRenderable.getLines()), debugRenderable.getNbLines(), + reinterpret_cast<const PvdDebugTriangle*>(debugRenderable.getTriangles()), debugRenderable.getNbTriangles()); + mUserRender->flushRenderEvents(); + } +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/buffering/ScbScenePvdClient.h b/PhysX_3.4/Source/PhysX/src/buffering/ScbScenePvdClient.h new file mode 100644 index 00000000..a7461571 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/buffering/ScbScenePvdClient.h @@ -0,0 +1,223 @@ +// 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 SCB_SCENE_PVD_CLIENT_H +#define SCB_SCENE_PVD_CLIENT_H + +#include "PxPhysXConfig.h" + +#if PX_SUPPORT_PVD + +#include "foundation/PxStrideIterator.h" +#include "pvd/PxPvdTransport.h" + +#include "PxPvdSceneClient.h" +#include "PvdMetaDataPvdBinding.h" + +#include "CmBitMap.h" + +#include "PxPvdClient.h" +#include "PxPvdUserRenderer.h" +#include "PsPvd.h" + +namespace physx +{ +class PxScene; +class PxActor; +class PxShape; +class PxGeometryHolder; +class PxArticulationLink; +class PxRenderBuffer; + +namespace Scb +{ +class Scene; +class Actor; +class Body; +class RigidStatic; +class RigidObject; +class Shape; +class ParticleSystem; +class Constraint; +class Articulation; +class ArticulationJoint; +class Cloth; +class Aggregate; +} + +namespace Sc +{ +class MaterialCore; +class ConstraintCore; +class ParticleSystemCore; +} + +namespace Vd +{ + +class ScbScenePvdClient : public PxPvdSceneClient, public PvdClient, public PvdVisualizer +{ + PX_NOCOPY(ScbScenePvdClient) + public: + ScbScenePvdClient(Scb::Scene& scene); + virtual ~ScbScenePvdClient(); + + // PxPvdSceneClient + virtual void setScenePvdFlag(PxPvdSceneFlag::Enum flag, bool value); + virtual void setScenePvdFlags(PxPvdSceneFlags flags); + virtual PxPvdSceneFlags getScenePvdFlags() const; + virtual void updateCamera(const char* name, const PxVec3& origin, const PxVec3& up, const PxVec3& target); + virtual void drawPoints(const PvdDebugPoint* points, PxU32 count); + virtual void drawLines(const PvdDebugLine* lines, PxU32 count); + virtual void drawTriangles(const PvdDebugTriangle* triangles, PxU32 count); + virtual void drawText(const PvdDebugText& text); + virtual PvdClient* getClientInternal(); + //~PxPvdSceneClient + + // pvdClient + virtual PvdDataStream* getDataStream(); + virtual PvdMetaDataBinding* getMetaDataBinding(); + virtual PvdUserRenderer* getUserRender(); + virtual bool isConnected() const ; + virtual void onPvdConnected(); + virtual void onPvdDisconnected(); + virtual void flush(); + //~pvdClient + + PsPvd* getPsPvd(); + void setPsPvd(PsPvd* pvd); + + PX_INLINE bool checkPvdDebugFlag() + { + return mIsConnected && (mPvd->getInstrumentationFlags() & PxPvdInstrumentationFlag::eDEBUG); + } + + void frameStart(PxReal simulateElapsedTime); + void frameEnd(); + + void updatePvdProperties(); + void releasePvdInstance(); + + void createPvdInstance (const PxActor* actor); // temporary for deformables and particle systems + void updatePvdProperties(const PxActor* actor); + void releasePvdInstance (const PxActor* actor); // temporary for deformables and particle systems + + void createPvdInstance (const Scb::Actor* actor); // temporary for deformables and particle systems + void updatePvdProperties(const Scb::Actor* actor); + void releasePvdInstance (const Scb::Actor* actor); // temporary for deformables and particle systems + + void createPvdInstance (const Scb::Body* body); + void updatePvdProperties (const Scb::Body* body); + void updateKinematicTarget (const Scb::Body* body, const PxTransform& p); + + void createPvdInstance (const Scb::RigidStatic* rigidStatic); + void updatePvdProperties (const Scb::RigidStatic* rigidStatic); + + void releasePvdInstance (const Scb::RigidObject* rigidObject); + + void createPvdInstance (const Scb::Constraint* constraint); + void updatePvdProperties(const Scb::Constraint* constraint); + void releasePvdInstance (const Scb::Constraint* constraint); + + void createPvdInstance (const Scb::Articulation* articulation); + void updatePvdProperties(const Scb::Articulation* articulation); + void releasePvdInstance (const Scb::Articulation* articulation); + + void createPvdInstance (const Scb::ArticulationJoint* articulationJoint); + void updatePvdProperties(const Scb::ArticulationJoint* articulationJoint); + void releasePvdInstance (const Scb::ArticulationJoint* articulationJoint); + + void createPvdInstance (const Sc::MaterialCore* materialCore); + void updatePvdProperties(const Sc::MaterialCore* materialCore); + void releasePvdInstance (const Sc::MaterialCore* materialCore); + + void createPvdInstance (const Scb::Shape* shape, PxActor& owner); + void updateMaterials (const Scb::Shape* shape); + void updatePvdProperties (const Scb::Shape* shape); + void releaseAndRecreateGeometry (const Scb::Shape* shape); + void releasePvdInstance (const Scb::Shape* shape, PxActor& owner); + void addBodyAndShapesToPvd (Scb::Body& b); + void addStaticAndShapesToPvd (Scb::RigidStatic& s); + + void createPvdInstance (const Scb::Aggregate* aggregate); + void updatePvdProperties (const Scb::Aggregate* aggregate); + void attachAggregateActor (const Scb::Aggregate* aggregate, Scb::Actor* actor); + void detachAggregateActor (const Scb::Aggregate* aggregate, Scb::Actor* actor); + void releasePvdInstance (const Scb::Aggregate* aggregate); + + void createPvdInstance (const Scb::Cloth* cloth); + void sendSimpleProperties (const Scb::Cloth* cloth); + void sendMotionConstraints (const Scb::Cloth* cloth); + void sendCollisionSpheres (const Scb::Cloth* cloth); + void sendCollisionCapsules (const Scb::Cloth* cloth); + void sendCollisionTriangles (const Scb::Cloth* cloth); + void sendVirtualParticles (const Scb::Cloth* cloth); + void sendSeparationConstraints (const Scb::Cloth* cloth); + void sendParticleAccelerations (const Scb::Cloth* cloth); + void sendSelfCollisionIndices (const Scb::Cloth* cloth); + void sendRestPositions (const Scb::Cloth* cloth); + void releasePvdInstance (const Scb::Cloth* cloth); + + void originShift(PxVec3 shift); + void updateJoints(); + void updateContacts(); + void updateSceneQueries(); + + // PvdVisualizer + void visualize(PxArticulationLink& link); + void visualize(const PxRenderBuffer& debugRenderable); + + private: + + template <typename TPropertyType> + void sendArray( const void* instance, const char* propName, const Cm::BitMap* bitMap, PxU32 nbValidParticles, + PxStrideIterator<const TPropertyType>& iterator); + + void sendStateDatas(Sc::ParticleSystemCore* psCore); + void sendEntireScene(); + void updateConstraint(const Sc::ConstraintCore& scConstraint, PxU32 updateType); + void setCreateContactReports(bool b); + + PxPvdSceneFlags mFlags; + PsPvd* mPvd; + Scb::Scene& mScbScene; + + PvdDataStream* mPvdDataStream; + PvdMetaDataBinding mMetaDataBinding; + PvdUserRenderer* mUserRender; + RendererEventClient* mRenderClient; + bool mIsConnected; +}; + +} // pvd + +} // physx +#endif // PX_SUPPORT_PVD + +#endif // SCB_SCENE_PVD_CLIENT_H diff --git a/PhysX_3.4/Source/PhysX/src/buffering/ScbShape.cpp b/PhysX_3.4/Source/PhysX/src/buffering/ScbShape.cpp new file mode 100644 index 00000000..59f07169 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/buffering/ScbShape.cpp @@ -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. + + +#include "ScbShape.h" + +using namespace physx; + +bool Scb::Shape::setMaterialsHelper(PxMaterial* const* materials, PxU16 materialCount) +{ + PX_ASSERT(!isBuffering()); + + if (materialCount == 1) + { + PxU16 materialIndex = Ps::to16((static_cast<NpMaterial*>(materials[0]))->getHandle()); + + mShape.setMaterialIndices(&materialIndex, 1); + } + else + { + PX_ASSERT(materialCount > 1); + + PX_ALLOCA(materialIndices, PxU16, materialCount); + + if (materialIndices) + { + NpMaterial::getMaterialIndices(materials, materialIndices, materialCount); + mShape.setMaterialIndices(materialIndices, materialCount); + } + else + { + Ps::getFoundation().error(PxErrorCode::eOUT_OF_MEMORY, __FILE__, __LINE__, + "PxShape::setMaterials() failed. Out of memory. Call will be ignored."); + return false; + } + } + + Scb::Scene* sc = getScbScene(); + + if (sc) + { + sc->getScScene().notifyNphaseOnUpdateShapeMaterial(mShape); + } + + return true; +} + + +void Scb::Shape::syncState() +{ + PxU32 flags = getBufferFlags(); + if (flags) + { + + PxShapeFlags oldShapeFlags = mShape.getFlags(); + + const Scb::ShapeBuffer& buffer = *getBufferedData(); + + if (flags & Buf::BF_Geometry) + { + Scb::Scene* sc = getScbScene(); + + if (sc) + { + sc->getScScene().unregisterShapeFromNphase(mShape); + } + + mShape.setGeometry(buffer.geometry.getGeometry()); + + if (sc) + { + sc->getScScene().registerShapeInNphase(mShape); + } + +#if PX_SUPPORT_PVD + if(getControlState() == ControlState::eIN_SCENE) + { + Scb::Scene* scbScene = getScbScene(); + PX_ASSERT(scbScene); + scbScene->getScenePvdClient().releaseAndRecreateGeometry(this); + } +#endif + } + + if (flags & Buf::BF_Material) + { + const PxU16* materialIndices = getMaterialBuffer(*getScbScene(), buffer); + mShape.setMaterialIndices(materialIndices, buffer.materialCount); + getScbScene()->getScScene().notifyNphaseOnUpdateShapeMaterial(mShape); + UPDATE_PVD_MATERIALS() + // TODO: So far we did not bother to fail gracefully in the case of running out of memory. If that should change then this + // method is somewhat problematic. The material ref counters have been adjusted at the time when the public API was called. + // Could be that one of the old materials was deleted afterwards. The problem now is what to do if this method fails? + // We can't adjust the material ref counts any longer since some of the old materials might have been deleted. + // One solution could be that this class allocates an array of material pointers when the buffered method is called. + // This array is then passed into the core object and is used by the core object, i.e., the core object does not allocate the + // buffer itself. + } + + flush<Buf::BF_Shape2Actor>(buffer); + flush<Buf::BF_SimulationFilterData>(buffer); + + if(isBuffered(Buf::BF_ContactOffset)) + { + mShape.setContactOffset(buffer.mContactOffset); + } + + flush<Buf::BF_RestOffset>(buffer); + flush<Buf::BF_Flags>(buffer); + + Sc::RigidCore* scRigidCore = NpShapeGetScRigidObjectFromScbSLOW(*this); + + if (scRigidCore) // may be NULL for exclusive shapes because of pending shape updates after buffered release of actor. + { + scRigidCore->onShapeChange(mShape, Sc::ShapeChangeNotifyFlags(flags), oldShapeFlags, true); + } + } + + postSyncState(); +} diff --git a/PhysX_3.4/Source/PhysX/src/buffering/ScbShape.h b/PhysX_3.4/Source/PhysX/src/buffering/ScbShape.h new file mode 100644 index 00000000..697017bf --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/buffering/ScbShape.h @@ -0,0 +1,452 @@ +// 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_SCB_SHAPE +#define PX_PHYSICS_SCB_SHAPE + +#include "NpMaterial.h" +#include "NpPhysics.h" +#include "ScbNpDeps.h" +#include "ScShapeCore.h" +#include "ScRigidCore.h" + +#include "PsUtilities.h" + +// PX_SERIALIZATION +#include "PxSerialFramework.h" +//~PX_SERIALIZATION + +#include "ScbDefs.h" + +namespace physx +{ + +#if PX_SUPPORT_PVD + #define UPDATE_PVD_MATERIALS() \ + if(getControlState() == ControlState::eIN_SCENE) \ + { \ + getScbScene()->getScenePvdClient().updateMaterials(this); \ + } +#else + #define UPDATE_PVD_MATERIALS() {} +#endif + +namespace Scb +{ + +class RigidObject; + +struct ShapeBuffer +{ + template <PxU32 I, PxU32 dummy> struct Fns {}; // TODO: make the base class traits visible + typedef Sc::ShapeCore Core; + typedef ShapeBuffer Buf; + + ShapeBuffer() : materialBufferIndex(0), materialCount(0) {} + + SCB_REGULAR_ATTRIBUTE_ALIGNED(2, PxTransform, Shape2Actor, 16) + SCB_REGULAR_ATTRIBUTE(3, PxFilterData, SimulationFilterData) + SCB_REGULAR_ATTRIBUTE(4, PxReal, ContactOffset) + SCB_REGULAR_ATTRIBUTE(5, PxReal, RestOffset) + SCB_REGULAR_ATTRIBUTE(6, PxShapeFlags, Flags) + + Gu::GeometryUnion geometry; + + union + { + PxU16 materialIndex; // for single material shapes + PxU32 materialBufferIndex; // for multi material shapes + }; + PxU16 materialCount; + + enum + { + BF_Geometry = 1<<0, + BF_Material = 1<<1 + }; + +}; + +class Shape : public Base +{ +//= 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. +//================================================================================================== + + typedef Sc::ShapeCore Core; + typedef ShapeBuffer Buf; +public: +// PX_SERIALIZATION + Shape(const PxEMPTY) : Base(PxEmpty), mShape(PxEmpty) {} + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + + PX_INLINE Shape(const PxGeometry& geometry, + PxShapeFlags shapeFlags, + const PxU16* materialIndices, + PxU16 materialCount, + bool isExclusive); + + PX_INLINE PxGeometryType::Enum getGeometryType() const; + + PX_INLINE const PxGeometry& getGeometry() const; + PX_INLINE const Gu::GeometryUnion&getGeometryUnion() const; + PX_INLINE Scb::ShapeBuffer* setGeometry(const PxGeometry& geom); + + PX_INLINE PxU16 getNbMaterials() const; + PX_INLINE PxMaterial* getMaterial(PxU32 index) const; + PX_INLINE PxU32 getMaterials(PxMaterial** buffer, PxU32 bufferSize, PxU32 startIndex=0) const; + PX_INLINE bool setMaterials(PxMaterial*const* materials, PxU16 materialCount); + + PX_INLINE const PxTransform& getShape2Actor() const { return read<Buf::BF_Shape2Actor>(); } + PX_INLINE void setShape2Actor(const PxTransform& v) { write<Buf::BF_Shape2Actor>(v); } + + PX_INLINE PxFilterData getSimulationFilterData() const { return read<Buf::BF_SimulationFilterData>(); } + PX_INLINE void setSimulationFilterData(const PxFilterData& v) { write<Buf::BF_SimulationFilterData>(v); } + + PX_INLINE PxReal getContactOffset() const { return read<Buf::BF_ContactOffset>(); } + PX_INLINE void setContactOffset(PxReal v); + + PX_INLINE PxReal getRestOffset() const { return read<Buf::BF_RestOffset>(); } + PX_INLINE void setRestOffset(PxReal v) { write<Buf::BF_RestOffset>(v); } + + PX_INLINE PxShapeFlags getFlags() const { return read<Buf::BF_Flags>(); } + PX_INLINE void setFlags(PxShapeFlags v) { write<Buf::BF_Flags>(v); } + + + //--------------------------------------------------------------------------------- + // Data synchronization + //--------------------------------------------------------------------------------- + void syncState(); + + + //--------------------------------------------------------------------------------- + // Miscellaneous + //--------------------------------------------------------------------------------- + PX_FORCE_INLINE const PxU16* getScMaterialIndices() const { return mShape.getMaterialIndices(); } // Only use if you know what you're doing! + + PX_FORCE_INLINE Sc::ShapeCore& getScShape() { return mShape; } // Only use if you know what you're doing! + PX_FORCE_INLINE const Sc::ShapeCore& getScShape() const { return mShape; } + + PX_FORCE_INLINE bool isExclusive() const { return getScbType() == ScbType::SHAPE_EXCLUSIVE; } + PX_FORCE_INLINE void setControlStateIfExclusive(Scene* s, ControlState::Enum cs); // for exclusive shapes + + template<bool sync> PX_FORCE_INLINE void checkUpdateOnRemove(Scene* s); + + static size_t getScOffset() + { + return reinterpret_cast<size_t>(&reinterpret_cast<Shape*>(0)->mShape); + } + +private: + bool setMaterialsHelper(PxMaterial* const* materials, PxU16 materialCount); + + Sc::ShapeCore mShape; + + PX_FORCE_INLINE const Scb::ShapeBuffer* getBufferedData() const { return reinterpret_cast<const Scb::ShapeBuffer*>(getStream()); } + PX_FORCE_INLINE Scb::ShapeBuffer* getBufferedData() { return reinterpret_cast<Scb::ShapeBuffer*>(getStream()); } + + + PX_FORCE_INLINE const PxU16* getMaterialBuffer(const Scb::Scene& scene, const Scb::ShapeBuffer& sb) const + { + if (sb.materialCount == 1) + return &sb.materialIndex; + else + return scene.getShapeMaterialBuffer(sb.materialBufferIndex); + } + + //--------------------------------------------------------------------------------- + // Infrastructure for regular attributes + //--------------------------------------------------------------------------------- + + struct Access: public BufferedAccess<Buf, Core, Shape> + { + template<typename Fns> + static PX_FORCE_INLINE void write(Shape& base, Core& core, typename Fns::Arg v) + { + if (!base.isBuffering()) + { + PxShapeFlags oldShapeFlags = core.getFlags(); + Fns::setCore(core, v); + + // shared shapes return NULL. But shared shapes aren't mutable when attached to an actor, so no notification needed. + Sc::RigidCore* rigidCore = NpShapeGetScRigidObjectFromScbSLOW(base); + if(rigidCore && base.getControlState() != ControlState::eINSERT_PENDING) + rigidCore->onShapeChange(core, Sc::ShapeChangeNotifyFlags(Fns::flag), oldShapeFlags); +#if PX_SUPPORT_PVD + Scb::Scene* scene = base.getScbSceneForAPI(); // shared shapes also return zero here + if(scene && !base.insertPending()) + scene->getScenePvdClient().updatePvdProperties(&base); +#endif + } + else + { + Fns::setBuffered(*reinterpret_cast<Buf*>(base.getStream()), v); + base.markUpdated(Fns::flag); + } + } + + }; + template<PxU32 f> PX_FORCE_INLINE typename Buf::Fns<f,0>::Arg read() const { return Access::read<Buf::Fns<f,0> >(*this, mShape); } + template<PxU32 f> PX_FORCE_INLINE void write(typename Buf::Fns<f,0>::Arg v) { Access::write<Buf::Fns<f,0> >(*this, mShape, v); } + template<PxU32 f> PX_FORCE_INLINE void flush(const Buf& buf) { Access::flush<Buf::Fns<f,0> >(*this, mShape, buf); } + +}; + + +PX_INLINE Shape::Shape(const PxGeometry& geometry, + PxShapeFlags shapeFlags, + const PxU16* materialIndices, + PxU16 materialCount, + bool isExclusive) : + mShape(geometry, shapeFlags, materialIndices, materialCount) +{ + // paranoia: the notify flags in Sc have to match up + + PX_COMPILE_TIME_ASSERT(PxU32(ShapeBuffer::BF_Geometry) == PxU32(Sc::ShapeChangeNotifyFlag::eGEOMETRY)); + PX_COMPILE_TIME_ASSERT(PxU32(ShapeBuffer::BF_Material) == PxU32(Sc::ShapeChangeNotifyFlag::eMATERIAL)); + PX_COMPILE_TIME_ASSERT(PxU32(ShapeBuffer::BF_Shape2Actor) == PxU32(Sc::ShapeChangeNotifyFlag::eSHAPE2BODY)); + PX_COMPILE_TIME_ASSERT(PxU32(ShapeBuffer::BF_SimulationFilterData) == PxU32(Sc::ShapeChangeNotifyFlag::eFILTERDATA)); + PX_COMPILE_TIME_ASSERT(PxU32(ShapeBuffer::BF_ContactOffset) == PxU32(Sc::ShapeChangeNotifyFlag::eCONTACTOFFSET)); + PX_COMPILE_TIME_ASSERT(PxU32(ShapeBuffer::BF_RestOffset) == PxU32(Sc::ShapeChangeNotifyFlag::eRESTOFFSET)); + PX_COMPILE_TIME_ASSERT(PxU32(ShapeBuffer::BF_Flags) == PxU32(Sc::ShapeChangeNotifyFlag::eFLAGS)); + PX_COMPILE_TIME_ASSERT(PxU32(ShapeBuffer::BF_Geometry) == PxU32(Sc::ShapeChangeNotifyFlag::eGEOMETRY)); + + if (isExclusive) + setScbType(ScbType::SHAPE_EXCLUSIVE); + else + setScbType(ScbType::SHAPE_SHARED); +} + + +PX_INLINE PxGeometryType::Enum Shape::getGeometryType() const +{ + return mShape.getGeometryType(); +} + +PX_INLINE const PxGeometry& Shape::getGeometry() const +{ + if (isBuffered(Buf::BF_Geometry)) + return getBufferedData()->geometry.getGeometry(); + else + return mShape.getGeometry(); +} + +PX_INLINE const Gu::GeometryUnion& Shape::getGeometryUnion() const +{ + if (isBuffered(Buf::BF_Geometry)) + return getBufferedData()->geometry; + else + return mShape.getGeometryUnion(); +} + + +PX_INLINE Scb::ShapeBuffer* Shape::setGeometry(const PxGeometry& geom) +{ + Scb::ShapeBuffer* shapeBuffer = NULL; + if (!isBuffering()) + { + Scb::Scene* sc = getScbScene(); + + if (sc) + { + sc->getScScene().unregisterShapeFromNphase(mShape); + } + + mShape.setGeometry(geom); + + if (sc) + { + sc->getScScene().registerShapeInNphase(mShape); + } + + Sc::RigidCore* rigidCore = NpShapeGetScRigidObjectFromScbSLOW(*this); + if(rigidCore) + rigidCore->onShapeChange(mShape, Sc::ShapeChangeNotifyFlag::eGEOMETRY, PxShapeFlags()); + +#if PX_SUPPORT_PVD + Scb::Scene* scbScene = getScbSceneForAPI(); + if(scbScene) + { + scbScene->getScenePvdClient().releaseAndRecreateGeometry( this ); + } +#endif + } + else + { + markUpdated(Buf::BF_Geometry); + shapeBuffer = getBufferedData(); + shapeBuffer->geometry.set(geom); + } + + return shapeBuffer; +} + + +PX_INLINE PxU16 Shape::getNbMaterials() const +{ + if (isBuffered(Buf::BF_Material)) + return getBufferedData()->materialCount; + else + return mShape.getNbMaterialIndices(); +} + + +PX_INLINE PxMaterial* Shape::getMaterial(PxU32 index) const +{ + PX_ASSERT(index < getNbMaterials()); + + NpMaterialManager& matManager = NpPhysics::getInstance().getMaterialManager(); + if (isBuffered(Buf::BF_Material)) + { + const PxU16* materialIndices = getMaterialBuffer(*getScbScene(), *getBufferedData()); + return matManager.getMaterial(materialIndices[index]); + } + else + { + PxU16 matTableIndex = mShape.getMaterialIndices()[index]; + return matManager.getMaterial(matTableIndex); + } +} + + +PX_INLINE PxU32 Shape::getMaterials(PxMaterial** buffer, PxU32 bufferSize, PxU32 startIndex) const +{ + const PxU16* materialIndices; + PxU32 matCount; + NpMaterialManager& matManager = NpPhysics::getInstance().getMaterialManager(); + if (isBuffered(Buf::BF_Material)) + { + // IMPORTANT: + // As long as the material pointers get copied to a user buffer, this works fine. + // Never give direct access to the internal material buffer because in the + // double buffered case the pointer changes on resize. + + const Scb::ShapeBuffer* PX_RESTRICT bufferedData = getBufferedData(); + + materialIndices = getMaterialBuffer(*getScbScene(), *bufferedData); + matCount = bufferedData->materialCount; + } + else + { + materialIndices = mShape.getMaterialIndices(); + matCount = mShape.getNbMaterialIndices(); + } + + // PT: this is copied from Cm::getArrayOfPointers(). We cannot use the Cm function here + // because of the extra indirection needed to access the materials. + PxU32 size = matCount; + const PxU32 remainder = PxU32(PxMax<PxI32>(PxI32(size - startIndex), 0)); + const PxU32 writeCount = PxMin(remainder, bufferSize); + materialIndices += startIndex; + for(PxU32 i=0;i<writeCount;i++) + buffer[i] = matManager.getMaterial(materialIndices[i]); + + return writeCount; +} + + +PX_INLINE bool Shape::setMaterials(PxMaterial* const* materials, PxU16 materialCount) +{ + if (!isBuffering()) + { + bool ret = setMaterialsHelper(materials, materialCount); + UPDATE_PVD_MATERIALS() + return ret; + } + else + { + Scb::ShapeBuffer* PX_RESTRICT bufferedData = getBufferedData(); + + PxU16* materialIndices; + if (materialCount == 1) + materialIndices = &bufferedData->materialIndex; + else + { + PxU32 bufferIdx; + materialIndices = getScbScene()->allocShapeMaterialBuffer(materialCount, bufferIdx); + bufferedData->materialBufferIndex = bufferIdx; + } + bufferedData->materialCount = materialCount; + + NpMaterial::getMaterialIndices(materials, materialIndices, materialCount); + + markUpdated(Buf::BF_Material); + + return true; + } +} + +PX_INLINE void Shape::setContactOffset(PxReal v) +{ + write<Buf::BF_ContactOffset>(v); +} + + +PX_FORCE_INLINE void Shape::setControlStateIfExclusive(Scene* s, ControlState::Enum cs) +{ + if (isExclusive()) + { + setControlState(cs); + setScbScene(s); + } +} + + +template<bool sync> +PX_FORCE_INLINE void Shape::checkUpdateOnRemove(Scene* s) +{ + // special code to cover the case where a shape has a pending update and gets released. The following operations have to be done + // before the ref-counter of the shape gets decremented because that could cause the shape to be deleted in which case it must not + // be in the pending update list any longer. + if (getControlFlags() & Scb::ControlFlag::eIS_UPDATED) + { + if (sync) + syncState(); + s->removeShapeFromPendingUpdateList(*this); + } +} + + +//-------------------------------------------------------------- +// +// Data synchronization +// +//-------------------------------------------------------------- + + +} // namespace Scb + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/buffering/ScbType.h b/PhysX_3.4/Source/PhysX/src/buffering/ScbType.h new file mode 100644 index 00000000..b1725661 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/buffering/ScbType.h @@ -0,0 +1,61 @@ +// 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_SCB_TYPE +#define PX_PHYSICS_SCB_TYPE + +namespace physx +{ + struct ScbType + { + enum Enum + { + UNDEFINED, + SHAPE_EXCLUSIVE, + SHAPE_SHARED, + BODY, + BODY_FROM_ARTICULATION_LINK, + RIGID_STATIC, + CONSTRAINT, +#if PX_USE_PARTICLE_SYSTEM_API + PARTICLE_SYSTEM, +#endif + ARTICULATION, + ARTICULATION_JOINT, + AGGREGATE, +#if PX_USE_CLOTH_API + CLOTH, +#endif + TYPE_COUNT + }; + }; +} + +#endif |