diff options
| author | git perforce import user <a@b> | 2016-10-25 12:29:14 -0600 |
|---|---|---|
| committer | Sheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees> | 2016-10-25 18:56:37 -0500 |
| commit | 3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch) | |
| tree | fa6485c169e50d7415a651bf838f5bcd0fd3bfbd /PhysX_3.4/Source/PhysX | |
| download | physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip | |
Initial commit:
PhysX 3.4.0 Update @ 21294896
APEX 1.4.0 Update @ 21275617
[CL 21300167]
Diffstat (limited to 'PhysX_3.4/Source/PhysX')
111 files changed, 38550 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/PhysX/src/NpActor.cpp b/PhysX_3.4/Source/PhysX/src/NpActor.cpp new file mode 100644 index 00000000..940c1dc8 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpActor.cpp @@ -0,0 +1,511 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + + +#include "NpActor.h" +#include "PxRigidActor.h" +#include "NpConstraint.h" +#include "NpFactory.h" +#include "NpShape.h" +#include "NpPhysics.h" +#include "NpAggregate.h" +#include "NpScene.h" +#include "NpRigidStatic.h" +#include "NpRigidDynamic.h" +#include "NpParticleSystem.h" +#include "NpParticleFluid.h" +#include "NpArticulationLink.h" +#include "NpCloth.h" +#include "CmTransformUtils.h" + +using namespace physx; + +/////////////////////////////////////////////////////////////////////////////// + +NpActor::NpActor(const char* name) : + mName(name), + mConnectorArray(NULL) +{ +} + +NpActor::~NpActor() +{ +} + + +typedef Ps::HashMap<NpActor*, NpConnectorArray*> ConnectorMap; +struct NpActorUserData +{ + PxU32 referenceCount; + ConnectorMap* tmpOriginalConnectors; +}; + +void NpActor::exportExtraData(PxSerializationContext& stream) +{ + const PxCollection& collection = stream.getCollection(); + if(mConnectorArray) + { + PxU32 connectorSize = mConnectorArray->size(); + PxU32 missedCount = 0; + for(PxU32 i = 0; i < connectorSize; ++i) + { + NpConnector& c = (*mConnectorArray)[i]; + PxBase* object = c.mObject; + if(!collection.contains(*object)) + { + ++missedCount; + } + } + + NpConnectorArray* exportConnectorArray = mConnectorArray; + + if(missedCount > 0) + { + exportConnectorArray = NpFactory::getInstance().acquireConnectorArray(); + if(missedCount < connectorSize) + { + exportConnectorArray->reserve(connectorSize - missedCount); + for(PxU32 i = 0; i < connectorSize; ++i) + { + NpConnector& c = (*mConnectorArray)[i]; + PxBase* object = c.mObject; + if(collection.contains(*object)) + { + exportConnectorArray->pushBack(c); + } + } + } + } + + stream.alignData(PX_SERIAL_ALIGN); + stream.writeData(exportConnectorArray, sizeof(NpConnectorArray)); + Cm::exportInlineArray(*exportConnectorArray, stream); + + if(missedCount > 0) + NpFactory::getInstance().releaseConnectorArray(exportConnectorArray); + } + stream.writeName(mName); +} + +void NpActor::importExtraData(PxDeserializationContext& context) +{ + if(mConnectorArray) + { + mConnectorArray = context.readExtraData<NpConnectorArray, PX_SERIAL_ALIGN>(); + new (mConnectorArray) NpConnectorArray(PxEmpty); + + if(mConnectorArray->size() == 0) + mConnectorArray = NULL; + else + Cm::importInlineArray(*mConnectorArray, context); + } + context.readName(mName); +} + +void NpActor::resolveReferences(PxDeserializationContext& context) +{ + // Resolve connector pointers if needed + if(mConnectorArray) + { + const PxU32 nbConnectors = mConnectorArray->size(); + for(PxU32 i=0; i<nbConnectors; i++) + { + NpConnector& c = (*mConnectorArray)[i]; + context.translatePxBase(c.mObject); + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpActor::releaseConstraints(PxRigidActor& owner) +{ + if(mConnectorArray) + { + PxU32 nbConnectors = mConnectorArray->size(); + PxU32 currentIndex = 0; + while(nbConnectors--) + { + NpConnector& connector = (*mConnectorArray)[currentIndex]; + if (connector.mType == NpConnectorType::eConstraint) + { + NpConstraint* c = static_cast<NpConstraint*>(connector.mObject); + c->actorDeleted(&owner); + + NpScene* s = c->getNpScene(); + if (s) + { + s->getScene().removeConstraint(c->getScbConstraint()); + s->removeFromConstraintList(*c); + } + + removeConnector(owner, currentIndex); + } + else + currentIndex++; + } + } +} + +void NpActor::release(PxActor& owner) +{ +// PX_AGGREGATE + if (mConnectorArray) // Need to test again because the code above might purge the connector array if no element remains + { + PX_ASSERT(mConnectorArray->size() == 1); // At this point only the aggregate should remain + PX_ASSERT((*mConnectorArray)[0].mType == NpConnectorType::eAggregate); + + NpAggregate* a = static_cast<NpAggregate*>((*mConnectorArray)[0].mObject); + bool status = a->removeActorAndReinsert(owner, false); + PX_ASSERT(status); + PX_UNUSED(status); + PX_ASSERT(!mConnectorArray); // Remove should happen in aggregate code + } +//~PX_AGGREGATE + + PX_ASSERT(!mConnectorArray); // All the connector objects should have been removed at this point +} + +/////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// + +PxU32 NpActor::findConnector(NpConnectorType::Enum type, PxBase* object) const +{ + if(!mConnectorArray) + return 0xffffffff; + + for(PxU32 i=0; i < mConnectorArray->size(); i++) + { + NpConnector& c = (*mConnectorArray)[i]; + if (c.mType == type && c.mObject == object) + return i; + } + + return 0xffffffff; +} + +void NpActor::addConnector(NpConnectorType::Enum type, PxBase* object, const char* errMsg) +{ + if(!mConnectorArray) + mConnectorArray = NpFactory::getInstance().acquireConnectorArray(); + + PX_CHECK_MSG(findConnector(type, object) == 0xffffffff, errMsg); + PX_UNUSED(errMsg); + + if(mConnectorArray->isInUserMemory() && mConnectorArray->size() == mConnectorArray->capacity()) + { + NpConnectorArray* newConnectorArray = NpFactory::getInstance().acquireConnectorArray(); + newConnectorArray->assign(mConnectorArray->begin(), mConnectorArray->end()); + mConnectorArray->~NpConnectorArray(); + mConnectorArray = newConnectorArray; + } + + NpConnector c(type, object); + mConnectorArray->pushBack(c); +} + +void NpActor::removeConnector(PxActor& /*owner*/, PxU32 index) +{ + PX_ASSERT(mConnectorArray); + PX_ASSERT(index < mConnectorArray->size()); + + mConnectorArray->replaceWithLast(index); + + if(mConnectorArray->size() == 0) + { + if(!mConnectorArray->isInUserMemory()) + NpFactory::getInstance().releaseConnectorArray(mConnectorArray); + else + mConnectorArray->~NpConnectorArray(); + mConnectorArray = NULL; + } +} + +void NpActor::removeConnector(PxActor& owner, NpConnectorType::Enum type, PxBase* object, const char* errorMsg) +{ + PX_CHECK_MSG(mConnectorArray, errorMsg); + PX_UNUSED(errorMsg); + + if(mConnectorArray) + { + PxU32 index = findConnector(type, object); + + PX_CHECK_MSG(index != 0xffffffff, errorMsg); + + removeConnector(owner, index); + } +} + +PxU32 NpActor::getNbConnectors(NpConnectorType::Enum type) const +{ + PxU32 nbConnectors = 0; + + if(mConnectorArray) + { + for(PxU32 i=0; i < mConnectorArray->size(); i++) + { + if ((*mConnectorArray)[i].mType == type) + nbConnectors++; + } + } + + return nbConnectors; +} + +/////////////////////////////////////////////////////////////////////////////// + +NpAggregate* NpActor::getNpAggregate(PxU32& index) const +{ + PX_ASSERT(getNbConnectors(NpConnectorType::eAggregate) <= 1); + + if(mConnectorArray) + { + // PT: TODO: sort by type to optimize this... + for(PxU32 i=0; i < mConnectorArray->size(); i++) + { + NpConnector& c = (*mConnectorArray)[i]; + if (c.mType == NpConnectorType::eAggregate) + { + index = i; + return static_cast<NpAggregate*>(c.mObject); + } + } + } + + return NULL; +} + +void NpActor::setAggregate(NpAggregate* np, PxActor& owner) +{ + PxU32 index = 0xffffffff; + NpAggregate* a = getNpAggregate(index); + + if (!a) + { + PX_ASSERT(np); + addConnector(NpConnectorType::eAggregate, np, "NpActor::setAggregate() failed"); + } + else + { + PX_ASSERT(mConnectorArray); + PX_ASSERT(index != 0xffffffff); + if (!np) + removeConnector(owner, index); + else + (*mConnectorArray)[index].mObject = np; + } +} + +PxAggregate* NpActor::getAggregate() const +{ + PxU32 index = 0xffffffff; + NpAggregate* a = getNpAggregate(index); + return static_cast<PxAggregate*>(a); +} + + +/////////////////////////////////////////////////////////////////////////////// + +void NpActor::removeConstraintsFromScene() +{ + NpConnectorIterator iter = getConnectorIterator(NpConnectorType::eConstraint); + while (PxBase* ser = iter.getNext()) + { + NpConstraint* c = static_cast<NpConstraint*>(ser); + + NpScene* s = c->getNpScene(); + + if (s) + { + s->removeFromConstraintList(*c); + s->getScene().removeConstraint(c->getScbConstraint()); + } + } +} + +void NpActor::addConstraintsToSceneInternal() +{ + if(!mConnectorArray) + return; + + NpConnectorIterator iter = getConnectorIterator(NpConnectorType::eConstraint); + while (PxBase* ser = iter.getNext()) + { + NpConstraint* c = static_cast<NpConstraint*>(ser); + PX_ASSERT(c->getNpScene() == NULL); + + c->markDirty(); // PT: "temp" fix for crash when removing/re-adding jointed actor from/to a scene + + NpScene* s = c->getSceneFromActors(); + if (s) + { + s->addToConstraintList(*c); + s->getScene().addConstraint(c->getScbConstraint()); + } + } +} + + + +/////////////////////////////////////////////////////////////////////////////// + +NpShapeManager* NpActor::getShapeManager(PxRigidActor& actor) +{ + // DS: if the performance here becomes an issue we can use the same kind of offset hack as below + + const PxType actorType = actor.getConcreteType(); + + if (actorType == PxConcreteType::eRIGID_DYNAMIC) + return &static_cast<NpRigidDynamic&>(actor).getShapeManager(); + else if(actorType == PxConcreteType::eRIGID_STATIC) + return &static_cast<NpRigidStatic&>(actor).getShapeManager(); + else if (actorType == PxConcreteType::eARTICULATION_LINK) + return &static_cast<NpArticulationLink&>(actor).getShapeManager(); + else + { + PX_ASSERT(0); + return NULL; + } +} + +const NpShapeManager* NpActor::getShapeManager(const PxRigidActor& actor) +{ + // DS: if the performance here becomes an issue we can use the same kind of offset hack as below + + const PxType actorType = actor.getConcreteType(); + + if (actorType == PxConcreteType::eRIGID_DYNAMIC) + return &static_cast<const NpRigidDynamic&>(actor).getShapeManager(); + else if(actorType == PxConcreteType::eRIGID_STATIC) + return &static_cast<const NpRigidStatic&>(actor).getShapeManager(); + else if (actorType == PxConcreteType::eARTICULATION_LINK) + return &static_cast<const NpArticulationLink&>(actor).getShapeManager(); + else + { + PX_ASSERT(0); + return NULL; + } +} + +void NpActor::getGlobalPose(PxTransform& globalPose, const NpShape& shape, const PxRigidActor& actor) +{ + const Scb::Actor& scbActor = NpActor::getScbFromPxActor(actor); + const Scb::Shape& scbShape = shape.getScbShape(); + + NpActor::getGlobalPose(globalPose, scbShape, scbActor); +} + +void NpActor::getGlobalPose(PxTransform& globalPose, const Scb::Shape& scbShape, const Scb::Actor& scbActor) +{ + const PxTransform& shape2Actor = scbShape.getShape2Actor(); + + // PT: TODO: duplicated from SqBounds.cpp. Refactor. + const ScbType::Enum actorType = scbActor.getScbType(); + if(actorType==ScbType::RIGID_STATIC) + { + Cm::getStaticGlobalPoseAligned(static_cast<const Scb::RigidStatic&>(scbActor).getActor2World(), shape2Actor, globalPose); + } + else + { + PX_ASSERT(actorType==ScbType::BODY || actorType == ScbType::BODY_FROM_ARTICULATION_LINK); + + const Scb::Body& body = static_cast<const Scb::Body&>(scbActor); + PX_ALIGN(16, PxTransform) kinematicTarget; + const PxU16 sqktFlags = PxRigidBodyFlag::eKINEMATIC | PxRigidBodyFlag::eUSE_KINEMATIC_TARGET_FOR_SCENE_QUERIES; + const bool useTarget = (PxU16(body.getFlags()) & sqktFlags) == sqktFlags; + const PxTransform& body2World = (useTarget && body.getKinematicTarget(kinematicTarget)) ? kinematicTarget : body.getBody2World(); + Cm::getDynamicGlobalPoseAligned(body2World, shape2Actor, body.getBody2Actor(), globalPose); + } +} + +namespace +{ + template <typename N> NpActor* pxToNpActor(PxActor *p) + { + return static_cast<NpActor*>(static_cast<N*>(p)); + } + + template <typename N> const NpActor* pxToNpActor(const PxActor *p) + { + return static_cast<const NpActor*>(static_cast<const N*>(p)); + } +} + +NpActor::Offsets::Offsets() +{ + for(PxU32 i=0;i<PxConcreteType::ePHYSX_CORE_COUNT;i++) + pxActorToScbActor[i] = pxActorToNpActor[i] = 0; + size_t addr = 0x100; // casting the null ptr takes a special-case code path, which we don't want + PxActor* n = reinterpret_cast<PxActor*>(addr); + pxActorToNpActor[PxConcreteType::eRIGID_STATIC] = reinterpret_cast<size_t>(pxToNpActor<NpRigidStatic>(n)) - addr; + pxActorToNpActor[PxConcreteType::eRIGID_DYNAMIC] = reinterpret_cast<size_t>(pxToNpActor<NpRigidDynamic>(n)) - addr; +#if PX_USE_PARTICLE_SYSTEM_API + pxActorToNpActor[PxConcreteType::ePARTICLE_SYSTEM] = reinterpret_cast<size_t>(pxToNpActor<NpParticleSystem>(n)) - addr; + pxActorToNpActor[PxConcreteType::ePARTICLE_FLUID] = reinterpret_cast<size_t>(pxToNpActor<NpParticleFluid>(n)) - addr; +#endif + pxActorToNpActor[PxConcreteType::eARTICULATION_LINK] = reinterpret_cast<size_t>(pxToNpActor<NpArticulationLink>(n)) - addr; +#if PX_USE_CLOTH_API + pxActorToNpActor[PxConcreteType::eCLOTH] = reinterpret_cast<size_t>(pxToNpActor<NpCloth>(n)) - addr; +#endif + + pxActorToScbActor[PxConcreteType::eRIGID_STATIC] = PX_OFFSET_OF_RT(NpRigidStatic, getScbActorFast()); + pxActorToScbActor[PxConcreteType::eRIGID_DYNAMIC] = PX_OFFSET_OF_RT(NpRigidDynamic, getScbActorFast()); +#if PX_USE_PARTICLE_SYSTEM_API + pxActorToScbActor[PxConcreteType::ePARTICLE_SYSTEM] = PX_OFFSET_OF_RT(NpParticleSystem, getScbActor()); + pxActorToScbActor[PxConcreteType::ePARTICLE_FLUID] = PX_OFFSET_OF_RT(NpParticleFluid, getScbActor()); +#endif + pxActorToScbActor[PxConcreteType::eARTICULATION_LINK] = PX_OFFSET_OF_RT(NpArticulationLink, getScbActorFast()); +#if PX_USE_CLOTH_API + pxActorToScbActor[PxConcreteType::eCLOTH] = PX_OFFSET_OF_RT(NpCloth, getScbCloth()); +#endif +} + +const NpActor::Offsets NpActor::sOffsets; + + +NpScene* NpActor::getOwnerScene(const PxActor& actor) +{ + const Scb::Actor& scbActor = getScbFromPxActor(actor); + Scb::Scene* scbScene = scbActor.getScbScene(); + return scbScene? static_cast<NpScene*>(scbScene->getPxScene()) : NULL; +} + +NpScene* NpActor::getAPIScene(const PxActor& actor) +{ + const Scb::Actor& scbActor = getScbFromPxActor(actor); + Scb::Scene* scbScene = scbActor.getScbSceneForAPI(); + return scbScene? static_cast<NpScene*>(scbScene->getPxScene()) : NULL; +} + +void NpActor::onActorRelease(PxActor* actor) +{ + NpFactory::getInstance().onActorRelease(actor); +} diff --git a/PhysX_3.4/Source/PhysX/src/NpActor.h b/PhysX_3.4/Source/PhysX/src/NpActor.h new file mode 100644 index 00000000..b9403cba --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpActor.h @@ -0,0 +1,163 @@ +// 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_NP_ACTOR +#define PX_PHYSICS_NP_ACTOR + +#include "NpConnector.h" +#include "ScbActor.h" // DM: without this inclusion PVD-diabled android build fails, lacking Scb::Actor definition + +namespace physx +{ + class NpShapeManager; + class NpAggregate; + class NpScene; + class NpShape; + +class NpActor +{ +//= 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. +//================================================================================================== + + // We sometimes pass in the PxActor here even though it's always a base class + // of the objects which inherit from this class too. But passing + // context to functions which need it allows this to be purely a mixin containing shared + // utility code rather than an abstract base class. + +public: +// PX_SERIALIZATION + NpActor(const PxEMPTY) {} + + void exportExtraData(PxSerializationContext& stream); + void importExtraData(PxDeserializationContext& context); + void resolveReferences(PxDeserializationContext& context); + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + NpActor(const char* name); + + void releaseConstraints(PxRigidActor& owner); + void release(PxActor& owner); + + NpAggregate* getNpAggregate(PxU32& index) const; + void setAggregate(NpAggregate* np, PxActor& owner); + PxAggregate* getAggregate() const; + + void removeConstraintsFromScene(); + PX_FORCE_INLINE void addConstraintsToScene() // inline the fast path for addActors() + { + if(mConnectorArray) + addConstraintsToSceneInternal(); + } + + PX_FORCE_INLINE NpConnectorArray** getConnectorArrayAddress() { return &mConnectorArray;} + PxU32 findConnector(NpConnectorType::Enum type, PxBase* object) const; + void addConnector(NpConnectorType::Enum type, PxBase* object, const char* errMsg); + void removeConnector(PxActor& owner, NpConnectorType::Enum type, PxBase* object, const char* errorMsg); + PxU32 getNbConnectors(NpConnectorType::Enum type) const; + + static NpShapeManager* getShapeManager(PxRigidActor& actor); // bit misplaced here, but we don't want a separate subclass just for this + static const NpShapeManager* getShapeManager(const PxRigidActor& actor); // bit misplaced here, but we don't want a separate subclass just for this + + static void getGlobalPose(PxTransform& globalPose, const NpShape& shape, const PxRigidActor& actor); + static void getGlobalPose(PxTransform& globalPose, const Scb::Shape& scbShape, const Scb::Actor& scbActor); + + static NpActor& getFromPxActor(PxActor& actor) { return *Ps::pointerOffset<NpActor*>(&actor, ptrdiff_t(sOffsets.pxActorToNpActor[actor.getConcreteType()])); } + static const NpActor& getFromPxActor(const PxActor& actor) { return *Ps::pointerOffset<const NpActor*>(&actor, ptrdiff_t(sOffsets.pxActorToNpActor[actor.getConcreteType()])); } + + static Scb::Actor& getScbFromPxActor(PxActor& actor) { return *Ps::pointerOffset<Scb::Actor*>(&actor, ptrdiff_t(sOffsets.pxActorToScbActor[actor.getConcreteType()])); } + static const Scb::Actor& getScbFromPxActor(const PxActor& actor) { return *Ps::pointerOffset<const Scb::Actor*>(&actor, ptrdiff_t(sOffsets.pxActorToScbActor[actor.getConcreteType()])); } + + static NpScene* getAPIScene(const PxActor& actor); // the scene the user thinks the actor is in + static NpScene* getOwnerScene(const PxActor& actor); // the scene the user thinks the actor is in, or from which the actor is pending removal + + PX_FORCE_INLINE NpConnectorIterator getConnectorIterator(NpConnectorType::Enum type) + { + if (mConnectorArray) + return NpConnectorIterator(&mConnectorArray->front(), mConnectorArray->size(), type); + else + return NpConnectorIterator(NULL, 0, type); + } + + // a couple of methods that sever include dependencies in NpActor.h + + static void onActorRelease(PxActor* actor); + + + +template<typename T> +PxU32 getConnectors(NpConnectorType::Enum type, T** userBuffer, PxU32 bufferSize, PxU32 startIndex=0) const +{ + PxU32 nbConnectors = 0; + + if(mConnectorArray) + { + for(PxU32 i=0; i < mConnectorArray->size(); i++) + { + NpConnector& c = (*mConnectorArray)[i]; + if (c.mType == type && nbConnectors < bufferSize && i>=startIndex) + { + userBuffer[nbConnectors] = static_cast<T*>(c.mObject); + nbConnectors++; + } + } + } + + return nbConnectors; +} + +protected: + ~NpActor(); + const char* mName; + // Lazy-create array for connector objects like constraints, observers, ... + // Most actors have no such objects, so we bias this class accordingly: + NpConnectorArray* mConnectorArray; + +private: + void addConstraintsToSceneInternal(); + void removeConnector(PxActor& owner, PxU32 index); + struct Offsets + { + size_t pxActorToNpActor[PxConcreteType::ePHYSX_CORE_COUNT]; + size_t pxActorToScbActor[PxConcreteType::ePHYSX_CORE_COUNT]; + Offsets(); + }; +public: + static const Offsets sOffsets; +}; + + + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/NpActorTemplate.h b/PhysX_3.4/Source/PhysX/src/NpActorTemplate.h new file mode 100644 index 00000000..0236bdbc --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpActorTemplate.h @@ -0,0 +1,270 @@ +// 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_NP_ACTOR_TEMPLATE +#define PX_PHYSICS_NP_ACTOR_TEMPLATE + +#include "PsUserAllocated.h" +#include "NpWriteCheck.h" +#include "NpReadCheck.h" +#include "NpActor.h" +#include "ScbActor.h" +#include "NpScene.h" + +namespace physx +{ + +// PT: only API (virtual) functions should be implemented here. Other shared non-virtual functions should go to NpActor. + +/** +This is an API class. API classes run in a different thread than the simulation. +For the sake of simplicity they have their own methods, and they do not call simulation +methods directly. To set simulation state, they also have their own custom set +methods in the implementation classes. + +Changing the data layout of this class breaks the binary serialization format. +See comments for PX_BINARY_SERIAL_VERSION. +*/ +template<class APIClass> +class NpActorTemplate : public APIClass, public NpActor, 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. +//================================================================================================== + PX_NOCOPY(NpActorTemplate) +public: +// PX_SERIALIZATION + NpActorTemplate(PxBaseFlags baseFlags) : APIClass(baseFlags), NpActor(PxEmpty) {} + virtual void exportExtraData(PxSerializationContext& stream) { NpActor::exportExtraData(stream); } + void importExtraData(PxDeserializationContext& context) { NpActor::importExtraData(context); } + virtual void resolveReferences(PxDeserializationContext& context) { NpActor::resolveReferences(context); } +//~PX_SERIALIZATION + + NpActorTemplate(PxType concreteType, PxBaseFlags baseFlags, const char* name, void* userData); + virtual ~NpActorTemplate(); + + //--------------------------------------------------------------------------------- + // PxActor implementation + //--------------------------------------------------------------------------------- + virtual void release() { NpActor::release(*this); } + + // The rule is: If an API method is used somewhere in here, it has to be redeclared, else GCC whines + virtual PxActorType::Enum getType() const = 0; + + virtual PxScene* getScene() const; + + // Debug name + virtual void setName(const char*); + virtual const char* getName() const; + + virtual PxBounds3 getWorldBounds(float inflation=1.01f) const = 0; + + // Flags + virtual void setActorFlag(PxActorFlag::Enum flag, bool value); + virtual void setActorFlags(PxActorFlags inFlags); + virtual PxActorFlags getActorFlags() const; + + // Dominance + virtual void setDominanceGroup(PxDominanceGroup dominanceGroup); + virtual PxDominanceGroup getDominanceGroup() const; + + // Multiclient + virtual void setOwnerClient( PxClientID inClient ); + virtual PxClientID getOwnerClient() const; + virtual void setClientBehaviorFlags(PxActorClientBehaviorFlags); + virtual PxActorClientBehaviorFlags getClientBehaviorFlags() const; + + // Aggregates + virtual PxAggregate* getAggregate() const { return NpActor::getAggregate(); } + + //--------------------------------------------------------------------------------- + // Miscellaneous + //--------------------------------------------------------------------------------- +protected: + PX_FORCE_INLINE void setActorFlagInternal(PxActorFlag::Enum flag, bool value); + PX_FORCE_INLINE void setActorFlagsInternal(PxActorFlags inFlags); +}; + +/////////////////////////////////////////////////////////////////////////////// + +template<class APIClass> +NpActorTemplate<APIClass>::NpActorTemplate(PxType concreteType, + PxBaseFlags baseFlags, + const char* name, + void* actorUserData) +:APIClass(concreteType, baseFlags), +NpActor(name) +{ + // don't ref Scb actor here, it hasn't been assigned yet + + APIClass::userData = actorUserData; +} + + +template<class APIClass> +NpActorTemplate<APIClass>::~NpActorTemplate() +{ + NpActor::onActorRelease(this); +} + +/////////////////////////////////////////////////////////////////////////////// + +// PT: this one is very slow +template<class APIClass> +PxScene* NpActorTemplate<APIClass>::getScene() const +{ + return NpActor::getAPIScene(*this); +} + +/////////////////////////////////////////////////////////////////////////////// + +template<class APIClass> +void NpActorTemplate<APIClass>::setName(const char* debugName) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + mName = debugName; + +#if PX_SUPPORT_PVD + Scb::Scene* scbScene = getScbFromPxActor(*this).getScbSceneForAPI(); + Scb::Actor& scbActor = NpActor::getScbFromPxActor(*this); + //Name changing is not bufferred + if(scbScene) + scbScene->getScenePvdClient().updatePvdProperties(&scbActor); +#endif +} + +template<class APIClass> +const char* NpActorTemplate<APIClass>::getName() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return mName; +} + +/////////////////////////////////////////////////////////////////////////////// + +template<class APIClass> +void NpActorTemplate<APIClass>::setDominanceGroup(PxDominanceGroup dominanceGroup) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + NpActor::getScbFromPxActor(*this).setDominanceGroup(dominanceGroup); +} + + +template<class APIClass> +PxDominanceGroup NpActorTemplate<APIClass>::getDominanceGroup() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return NpActor::getScbFromPxActor(*this).getDominanceGroup(); +} + +/////////////////////////////////////////////////////////////////////////////// + +template<class APIClass> +void NpActorTemplate<APIClass>::setOwnerClient( PxClientID inId ) +{ + if ( NpActor::getOwnerScene(*this) != NULL ) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, + "Attempt to set the client id when an actor is already in a scene."); + } + else + NpActor::getScbFromPxActor(*this).setOwnerClient( inId ); +} + +template<class APIClass> +PxClientID NpActorTemplate<APIClass>::getOwnerClient() const +{ + return NpActor::getScbFromPxActor(*this).getOwnerClient(); +} + +template<class APIClass> +void NpActorTemplate<APIClass>::setClientBehaviorFlags(PxActorClientBehaviorFlags bits) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + NpActor::getScbFromPxActor(*this).setClientBehaviorFlags(bits); +} + +template<class APIClass> +PxActorClientBehaviorFlags NpActorTemplate<APIClass>::getClientBehaviorFlags() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return NpActor::getScbFromPxActor(*this).getClientBehaviorFlags(); +} + +/////////////////////////////////////////////////////////////////////////////// + +template<class APIClass> +PX_FORCE_INLINE void NpActorTemplate<APIClass>::setActorFlagInternal(PxActorFlag::Enum flag, bool value) +{ + Scb::Actor& a = NpActor::getScbFromPxActor(*this); + if (value) + a.setActorFlags( a.getActorFlags() | flag ); + else + a.setActorFlags( a.getActorFlags() & (~PxActorFlags(flag)) ); +} + +template<class APIClass> +PX_FORCE_INLINE void NpActorTemplate<APIClass>::setActorFlagsInternal(PxActorFlags inFlags) +{ + Scb::Actor& a = NpActor::getScbFromPxActor(*this); + a.setActorFlags( inFlags ); +} + +template<class APIClass> +void NpActorTemplate<APIClass>::setActorFlag(PxActorFlag::Enum flag, bool value) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + setActorFlagInternal(flag, value); +} + +template<class APIClass> +void NpActorTemplate<APIClass>::setActorFlags(PxActorFlags inFlags) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + setActorFlagsInternal(inFlags); +} + +template<class APIClass> +PxActorFlags NpActorTemplate<APIClass>::getActorFlags() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return NpActor::getScbFromPxActor(*this).getActorFlags(); +} + +/////////////////////////////////////////////////////////////////////////////// + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/NpAggregate.cpp b/PhysX_3.4/Source/PhysX/src/NpAggregate.cpp new file mode 100644 index 00000000..4b6114fa --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpAggregate.cpp @@ -0,0 +1,394 @@ +// 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 "NpAggregate.h" + +/////////////////////////////////////////////////////////////////////////////// + +#include "PxActor.h" +#include "NpRigidStatic.h" +#include "NpRigidDynamic.h" +#include "NpParticleSystem.h" +#include "NpParticleFluid.h" +#include "NpArticulation.h" +#include "CmUtils.h" + +using namespace physx; + +PX_FORCE_INLINE void setAggregate(NpAggregate* aggregate, PxActor& actor) +{ + NpActor& np = NpActor::getFromPxActor(actor); + np.setAggregate(aggregate, actor); +} + +/////////////////////////////////////////////////////////////////////////////// + + +NpAggregate::NpAggregate(PxU32 maxActors, bool selfCollisions) +: PxAggregate(PxConcreteType::eAGGREGATE, PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE) +, mAggregate(this, maxActors, selfCollisions) +, mNbActors(0) +{ + mActors = reinterpret_cast<PxActor**>(PX_ALLOC(sizeof(PxActor*)*maxActors, "PxActor*")); +} + +NpAggregate::~NpAggregate() +{ + NpFactory::getInstance().onAggregateRelease(this); + if(getBaseFlags()&PxBaseFlag::eOWNS_MEMORY) + PX_FREE(mActors); +} + +void NpAggregate::removeAndReinsert(PxActor& actor, bool reinsert) +{ + NpActor& np = NpActor::getFromPxActor(actor); + Scb::Actor& scb = NpActor::getScbFromPxActor(actor); + + np.setAggregate(NULL, actor); + + mAggregate.removeActor(scb, reinsert); +} + +void NpAggregate::release() +{ + NP_WRITE_CHECK(getOwnerScene()); + PX_SIMD_GUARD; + + NpPhysics::getInstance().notifyDeletionListenersUserRelease(this, NULL); + + /* + "An aggregate should be empty when it gets released. If it isn't, the behavior should be: remove the actors from + the aggregate, then remove the aggregate from the scene (if any) then delete it. I guess that implies the actors + get individually reinserted into the broad phase if the aggregate is in a scene." + */ + for(PxU32 i=0;i<mNbActors;i++) + { + if (mActors[i]->getType() == PxActorType::eARTICULATION_LINK) + static_cast<NpArticulationLink*>(mActors[i])->getRoot().setAggregate(NULL); + + removeAndReinsert(*mActors[i], true); + } + + NpScene* s = getAPIScene(); + if(s) + { + s->getScene().removeAggregate(getScbAggregate()); + s->removeFromAggregateList(*this); + } + + mAggregate.destroy(); +} + +void NpAggregate::addActorInternal(PxActor& actor, NpScene& s) +{ + if (actor.getType() != PxActorType::eARTICULATION_LINK) + { + Scb::Actor& scb = NpActor::getScbFromPxActor(actor); + + mAggregate.addActor(scb); + + s.addActorInternal(actor); + } + else if (!actor.getScene()) // This check makes sure that a link of an articulation gets only added once. + { + NpArticulationLink& al = static_cast<NpArticulationLink&>(actor); + NpArticulation& npArt = al.getRoot(); + NpArticulationLink* const* links = npArt.getLinks(); + for(PxU32 i=0; i < npArt.getNbLinks(); i++) + { + mAggregate.addActor(links[i]->getScbActorFast()); + } + + s.addArticulationInternal(npArt); + } +} + +bool NpAggregate::addActor(PxActor& actor) +{ + NP_WRITE_CHECK(getOwnerScene()); + PX_SIMD_GUARD; + + if(mNbActors==mAggregate.getMaxActorCount()) + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxAggregate: can't add actor to aggregate, max number of actors reached"); + return false; + } + + if(actor.getAggregate()) + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxAggregate: can't add actor to aggregate, actor already belongs to an aggregate"); + return false; + } + + if(actor.getScene()) + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxAggregate: can't add actor to aggregate, actor already belongs to a scene"); + return false; + } + + if(actor.getType() == PxActorType::eARTICULATION_LINK) + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxAggregate: can't add articulation link to aggregate, only whole articulations can be added"); + return false; + } + + setAggregate(this, actor); + + mActors[mNbActors++] = &actor; + + // PT: when an object is added to a aggregate at runtime, i.e. when the aggregate has already been added to the scene, + // we need to immediately add the newcomer to the scene as well. + NpScene* s = getAPIScene(); + if(s) + { + addActorInternal(actor, *s); + } + + return true; +} + +bool NpAggregate::removeActorAndReinsert(PxActor& actor, bool reinsert) +{ + for(PxU32 i=0;i<mNbActors;i++) + { + if(mActors[i]==&actor) + { + mActors[i] = mActors[--mNbActors]; + removeAndReinsert(actor, reinsert); + return true; + } + } + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxAggregate: can't remove actor, actor doesn't belong to aggregate"); + return false; +} + +bool NpAggregate::removeActor(PxActor& actor) +{ + NP_WRITE_CHECK(getOwnerScene()); + PX_SIMD_GUARD; + + if(actor.getType() == PxActorType::eARTICULATION_LINK) + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxAggregate: can't remove articulation link, only whole articulations can be removed"); + return false; + } + + // PT: there are really 2 cases here: + // a) the user just wants to remove the actor from the aggregate, but the actor is still alive so if the aggregate has been added to a scene, + // we must reinsert the removed actor to that same scene + // b) this is called by the framework when releasing an actor, in which case we don't want to reinsert it anywhere. + // + // We assume that when called by the user, we always want to reinsert. The framework however will call the internal function + // without reinsertion. + return removeActorAndReinsert(actor, true); +} + +bool NpAggregate::addArticulation(PxArticulation& art) +{ + NP_WRITE_CHECK(getOwnerScene()); + PX_SIMD_GUARD; + + if((mNbActors+art.getNbLinks()) > mAggregate.getMaxActorCount()) + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxAggregate: can't add articulation links, max number of actors reached"); + return false; + } + + if(art.getAggregate()) + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxAggregate: can't add articulation to aggregate, articulation already belongs to an aggregate"); + return false; + } + + if(art.getScene()) + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxAggregate: can't add articulation to aggregate, articulation already belongs to a scene"); + return false; + } + + NpArticulation& npArt = static_cast<NpArticulation&>(art); + npArt.setAggregate(this); + NpArticulationLink* const* links = npArt.getLinks(); + for(PxU32 i=0; i < npArt.getNbLinks(); i++) + { + NpArticulationLink& l = *links[i]; + + setAggregate(this, l); + + mActors[mNbActors++] = &l; + + mAggregate.addActor(l.getScbActorFast()); + } + + // PT: when an object is added to a aggregate at runtime, i.e. when the aggregate has already been added to the scene, + // we need to immediately add the newcomer to the scene as well. + NpScene* s = getAPIScene(); + if(s) + { + s->addArticulationInternal(art); + } + + return true; +} + +bool NpAggregate::removeArticulationAndReinsert(PxArticulation& art, bool reinsert) +{ + NpArticulation* npArt = static_cast<NpArticulation*>(&art); + + bool found = false; + PxU32 idx = 0; + while(idx < mNbActors) + { + if ((mActors[idx]->getType() == PxActorType::eARTICULATION_LINK) && (&static_cast<NpArticulationLink*>(mActors[idx])->getRoot() == npArt)) + { + PxActor* a = mActors[idx]; + mActors[idx] = mActors[--mNbActors]; + removeAndReinsert(*a, reinsert); + found = true; + } + else + idx++; + } + + npArt->setAggregate(NULL); + + if (!found) + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxAggregate: can't remove articulation, articulation doesn't belong to aggregate"); + return found; +} + +bool NpAggregate::removeArticulation(PxArticulation& art) +{ + NP_WRITE_CHECK(getOwnerScene()); + PX_SIMD_GUARD; + + // see comments in removeActor() + return removeArticulationAndReinsert(art, true); +} + +PxU32 NpAggregate::getNbActors() const +{ + NP_READ_CHECK(getOwnerScene()); + return mNbActors; +} + +PxU32 NpAggregate::getMaxNbActors() const +{ + NP_READ_CHECK(getOwnerScene()); + return mAggregate.getMaxActorCount(); +} + +PxU32 NpAggregate::getActors(PxActor** userBuffer, PxU32 bufferSize, PxU32 startIndex) const +{ + NP_READ_CHECK(getOwnerScene()); + return Cm::getArrayOfPointers(userBuffer, bufferSize, startIndex, mActors, getCurrentSizeFast()); +} + +PxScene* NpAggregate::getScene() +{ + return getAPIScene(); +} + +NpScene* NpAggregate::getAPIScene() const +{ + return mAggregate.getScbSceneForAPI() ? static_cast<NpScene*>(mAggregate.getScbSceneForAPI()->getPxScene()) : NULL; +} + +NpScene* NpAggregate::getOwnerScene() const +{ + return mAggregate.getScbScene() ? static_cast<NpScene*>(mAggregate.getScbScene()->getPxScene()) : NULL; +} + +bool NpAggregate::getSelfCollision() const +{ + NP_READ_CHECK(getOwnerScene()); + return mAggregate.getSelfCollide(); +} + +// PX_SERIALIZATION +void NpAggregate::exportExtraData(PxSerializationContext& stream) +{ + if(mActors) + { + stream.alignData(PX_SERIAL_ALIGN); + stream.writeData(mActors, mNbActors * sizeof(PxActor*)); + } +} + +void NpAggregate::importExtraData(PxDeserializationContext& context) +{ + if(mActors) + mActors = context.readExtraData<PxActor*, PX_SERIAL_ALIGN>(mNbActors); +} + +void NpAggregate::resolveReferences(PxDeserializationContext& context) +{ + // Resolve actor pointers if needed + for(PxU32 i=0; i < mNbActors; i++) + { + context.translatePxBase(mActors[i]); + { + //update aggregate if mActors is in external reference + NpActor& np = NpActor::getFromPxActor(*mActors[i]); + if(np.getAggregate() == NULL) + { + np.setAggregate(this, *mActors[i]); + } + if(mActors[i]->getType() == PxActorType::eARTICULATION_LINK) + { + NpArticulation& articulation = static_cast<NpArticulationLink*>(mActors[i])->getRoot(); + if(!articulation.getAggregate()) + articulation.setAggregate(this); + } + } + } +} + +NpAggregate* NpAggregate::createObject(PxU8*& address, PxDeserializationContext& context) +{ + NpAggregate* obj = new (address) NpAggregate(PxBaseFlag::eIS_RELEASABLE); + address += sizeof(NpAggregate); + obj->importExtraData(context); + obj->resolveReferences(context); + return obj; +} + +void NpAggregate::requires(PxProcessPxBaseCallback& c) +{ + for(PxU32 i=0; i < mNbActors; i++) + { + PxArticulationLink* link = mActors[i]->is<PxArticulationLink>(); + if(link) + c.process(link->getArticulation()); + else + c.process(*mActors[i]); + } +} +// ~PX_SERIALIZATION diff --git a/PhysX_3.4/Source/PhysX/src/NpAggregate.h b/PhysX_3.4/Source/PhysX/src/NpAggregate.h new file mode 100644 index 00000000..fb2af9c6 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpAggregate.h @@ -0,0 +1,100 @@ +// 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_NP_AGGREGATE +#define PX_PHYSICS_NP_AGGREGATE + +#include "CmPhysXCommon.h" +#include "PxAggregate.h" +#include "ScbAggregate.h" +#include "PsUserAllocated.h" + +namespace physx +{ + +class NpScene; + +class NpAggregate : public PxAggregate, public Ps::UserAllocated +{ +//= ATTENTION! ===================================================================================== +// Changing the data layout of this class breaks the binary serialization format. See comments for +// PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData +// function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION +// accordingly. +//================================================================================================== +public: +// PX_SERIALIZATION + NpAggregate(PxBaseFlags baseFlags) : PxAggregate(baseFlags), mAggregate(PxEmpty) {} + virtual void exportExtraData(PxSerializationContext& stream); + void importExtraData(PxDeserializationContext& context); + void resolveReferences(PxDeserializationContext& context); + virtual void requires(PxProcessPxBaseCallback& c); + static NpAggregate* createObject(PxU8*& address, PxDeserializationContext& context); + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + NpAggregate(PxU32 maxActors, bool selfCollision); + virtual ~NpAggregate(); + + virtual void release(); + virtual bool addActor(PxActor&); + virtual bool removeActor(PxActor&); + virtual bool addArticulation(PxArticulation&); + virtual bool removeArticulation(PxArticulation&); + + virtual PxU32 getNbActors() const; + virtual PxU32 getMaxNbActors() const; + virtual PxU32 getActors(PxActor** userBuffer, PxU32 bufferSize, PxU32 startIndex) const; + + virtual PxScene* getScene(); + virtual bool getSelfCollision() const; + + PX_FORCE_INLINE PxU32 getCurrentSizeFast() const { return mNbActors; } + PX_FORCE_INLINE PxActor* getActorFast(PxU32 i) const { return mActors[i]; } + PX_FORCE_INLINE bool getSelfCollideFast() const { return mAggregate.getSelfCollide(); } + + NpScene* getAPIScene() const; + NpScene* getOwnerScene() const; // the scene the user thinks the actor is in, or from which the actor is pending removal + + void addActorInternal(PxActor& actor, NpScene& s); + void removeAndReinsert(PxActor& actor, bool reinsert); + bool removeActorAndReinsert(PxActor& actor, bool reinsert); + bool removeArticulationAndReinsert(PxArticulation& art, bool reinsert); + + PX_FORCE_INLINE Scb::Aggregate& getScbAggregate() { return mAggregate; } + +private: + Scb::Aggregate mAggregate; + PxU32 mNbActors; + PxActor** mActors; +}; + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/NpArticulation.cpp b/PhysX_3.4/Source/PhysX/src/NpArticulation.cpp new file mode 100644 index 00000000..5ec4e6ef --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpArticulation.cpp @@ -0,0 +1,528 @@ +// 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/PxTransform.h" +#include "NpArticulation.h" +#include "NpArticulationLink.h" +#include "NpWriteCheck.h" +#include "NpReadCheck.h" +#include "NpFactory.h" +#include "ScbArticulation.h" +#include "NpAggregate.h" +#include "CmUtils.h" + +namespace physx +{ + +// PX_SERIALIZATION +void NpArticulation::requires(PxProcessPxBaseCallback& c) +{ + // Collect articulation links + const PxU32 nbLinks = mArticulationLinks.size(); + for(PxU32 i=0; i<nbLinks; i++) + c.process(*mArticulationLinks[i]); +} + +void NpArticulation::exportExtraData(PxSerializationContext& stream) +{ + Cm::exportInlineArray(mArticulationLinks, stream); + stream.writeName(mName); +} + +void NpArticulation::importExtraData(PxDeserializationContext& context) +{ + Cm::importInlineArray(mArticulationLinks, context); + context.readName(mName); +} + +void NpArticulation::resolveReferences(PxDeserializationContext& context) +{ + const PxU32 nbLinks = mArticulationLinks.size(); + for(PxU32 i=0;i<nbLinks;i++) + { + context.translatePxBase(mArticulationLinks[i]); + } + + mAggregate = NULL; +} + +NpArticulation* NpArticulation::createObject(PxU8*& address, PxDeserializationContext& context) +{ + NpArticulation* obj = new (address) NpArticulation(PxBaseFlag::eIS_RELEASABLE); + address += sizeof(NpArticulation); + obj->importExtraData(context); + obj->resolveReferences(context); + return obj; +} +//~PX_SERIALIZATION + +NpArticulation::NpArticulation() +: PxArticulation(PxConcreteType::eARTICULATION, PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE) +, mAggregate(NULL) +, mName(NULL) +{ + PxArticulation::userData = NULL; +} + + +NpArticulation::~NpArticulation() +{ + NpFactory::getInstance().onArticulationRelease(this); +} + + +void NpArticulation::release() +{ + NP_WRITE_CHECK(getOwnerScene()); + + NpPhysics::getInstance().notifyDeletionListenersUserRelease(this, userData); + + //!!!AL TODO: Order should not matter in this case. Optimize by having a path which does not restrict release to leaf links or + // by using a more advanced data structure + PxU32 idx = 0; + while(mArticulationLinks.size()) + { + idx = idx % mArticulationLinks.size(); + + if (mArticulationLinks[idx]->getNbChildren() == 0) + { + mArticulationLinks[idx]->releaseInternal(); // deletes joint, link and removes link from list + } + else + { + idx++; + } + } + + NpScene* npScene = getAPIScene(); + if(npScene) + { + npScene->getScene().removeArticulation(getArticulation()); + + npScene->removeFromArticulationList(*this); + } + + mArticulationLinks.clear(); + + mArticulation.destroy(); +} + + +PxScene* NpArticulation::getScene() const +{ + return getAPIScene(); +} + + +PxU32 NpArticulation::getInternalDriveIterations() const +{ + NP_READ_CHECK(getOwnerScene()); + return getArticulation().getInternalDriveIterations(); +} + +void NpArticulation::setInternalDriveIterations(PxU32 iterations) +{ + NP_WRITE_CHECK(getOwnerScene()); + getArticulation().setInternalDriveIterations(iterations); +} + +PxU32 NpArticulation::getExternalDriveIterations() const +{ + NP_READ_CHECK(getOwnerScene()); + return getArticulation().getExternalDriveIterations(); +} + +void NpArticulation::setExternalDriveIterations(PxU32 iterations) +{ + NP_WRITE_CHECK(getOwnerScene()); + getArticulation().setExternalDriveIterations(iterations); +} + +PxU32 NpArticulation::getMaxProjectionIterations() const +{ + NP_READ_CHECK(getOwnerScene()); + return getArticulation().getMaxProjectionIterations(); +} + +void NpArticulation::setMaxProjectionIterations(PxU32 iterations) +{ + NP_WRITE_CHECK(getOwnerScene()); + getArticulation().setMaxProjectionIterations(iterations); +} + +PxReal NpArticulation::getSeparationTolerance() const +{ + NP_READ_CHECK(getOwnerScene()); + return getArticulation().getSeparationTolerance(); +} + +void NpArticulation::setSeparationTolerance(PxReal tolerance) +{ + NP_WRITE_CHECK(getOwnerScene()); + getArticulation().setSeparationTolerance(tolerance); +} + +void NpArticulation::setSolverIterationCounts(PxU32 positionIters, PxU32 velocityIters) +{ + NP_WRITE_CHECK(getOwnerScene()); + PX_CHECK_AND_RETURN(positionIters > 0, "Articulation::setSolverIterationCount: positionIters must be more than zero!"); + PX_CHECK_AND_RETURN(positionIters <= 255, "Articulation::setSolverIterationCount: positionIters must be no greater than 255!"); + PX_CHECK_AND_RETURN(velocityIters > 0, "Articulation::setSolverIterationCount: velocityIters must be more than zero!"); + PX_CHECK_AND_RETURN(velocityIters <= 255, "Articulation::setSolverIterationCount: velocityIters must be no greater than 255!"); + + getArticulation().setSolverIterationCounts((velocityIters & 0xff) << 8 | (positionIters & 0xff)); +} + + +void NpArticulation::getSolverIterationCounts(PxU32 & positionIters, PxU32 & velocityIters) const +{ + NP_READ_CHECK(getOwnerScene()); + PxU16 x = getArticulation().getSolverIterationCounts(); + velocityIters = PxU32(x >> 8); + positionIters = PxU32(x & 0xff); +} + + +bool NpArticulation::isSleeping() const +{ + NP_READ_CHECK(getOwnerScene()); + PX_CHECK_AND_RETURN_VAL(getAPIScene(), "Articulation::isSleeping: articulation must be in a scene.", true); + + return getArticulation().isSleeping(); +} + + +void NpArticulation::setSleepThreshold(PxReal threshold) +{ + NP_WRITE_CHECK(getOwnerScene()); + getArticulation().setSleepThreshold(threshold); +} + + +PxReal NpArticulation::getSleepThreshold() const +{ + NP_READ_CHECK(getOwnerScene()); + return getArticulation().getSleepThreshold(); +} + +void NpArticulation::setStabilizationThreshold(PxReal threshold) +{ + NP_WRITE_CHECK(getOwnerScene()); + getArticulation().setFreezeThreshold(threshold); +} + + +PxReal NpArticulation::getStabilizationThreshold() const +{ + NP_READ_CHECK(getOwnerScene()); + return getArticulation().getFreezeThreshold(); +} + + + +void NpArticulation::setWakeCounter(PxReal wakeCounterValue) +{ + NP_WRITE_CHECK(getOwnerScene()); + + for(PxU32 i=0; i < mArticulationLinks.size(); i++) + { + mArticulationLinks[i]->getScbBodyFast().setWakeCounter(wakeCounterValue); + } + + getArticulation().setWakeCounter(wakeCounterValue); +} + + +PxReal NpArticulation::getWakeCounter() const +{ + NP_READ_CHECK(getOwnerScene()); + return getArticulation().getWakeCounter(); +} + + +void NpArticulation::wakeUpInternal(bool forceWakeUp, bool autowake) +{ + NpScene* scene = getAPIScene(); + PX_ASSERT(scene); + PxReal wakeCounterResetValue = scene->getWakeCounterResetValueInteral(); + + Scb::Articulation& a = getArticulation(); + PxReal wakeCounter = a.getWakeCounter(); + + bool needsWakingUp = isSleeping() && (autowake || forceWakeUp); + if (autowake && (wakeCounter < wakeCounterResetValue)) + { + wakeCounter = wakeCounterResetValue; + needsWakingUp = true; + } + + if (needsWakingUp) + { + for(PxU32 i=0; i < mArticulationLinks.size(); i++) + { + mArticulationLinks[i]->getScbBodyFast().wakeUpInternal(wakeCounter); + } + + a.wakeUpInternal(wakeCounter); + } +} + + +void NpArticulation::wakeUp() +{ + NpScene* scene = getAPIScene(); + + NP_WRITE_CHECK(getOwnerScene()); // don't use the API scene, since it will be NULL on pending removal + PX_CHECK_AND_RETURN(scene, "Articulation::wakeUp: articulation must be in a scene."); + + for(PxU32 i=0; i < mArticulationLinks.size(); i++) + { + mArticulationLinks[i]->getScbBodyFast().wakeUpInternal(scene->getWakeCounterResetValueInteral()); + } + + getArticulation().wakeUp(); +} + + +void NpArticulation::putToSleep() +{ + NP_WRITE_CHECK(getOwnerScene()); + PX_CHECK_AND_RETURN(getAPIScene(), "Articulation::putToSleep: articulation must be in a scene."); + + for(PxU32 i=0; i < mArticulationLinks.size(); i++) + { + mArticulationLinks[i]->getScbBodyFast().putToSleepInternal(); + } + + getArticulation().putToSleep(); +} + + +PxArticulationLink* NpArticulation::createLink(PxArticulationLink* parent, const PxTransform& pose) +{ + PX_CHECK_AND_RETURN_NULL(pose.isSane(), "NpArticulation::createLink pose is not valid."); + PX_CHECK_AND_RETURN_NULL(mArticulationLinks.size()<64, "NpArticulation::createLink: at most 64 links allowed in an articulation"); + + NP_WRITE_CHECK(getOwnerScene()); + + if(parent && mArticulationLinks.empty()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Root articulation link must have NULL parent pointer!"); + return NULL; + } + + if(!parent && !mArticulationLinks.empty()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Non-root articulation link must have valid parent pointer!"); + return NULL; + } + + NpArticulationLink* parentLink = static_cast<NpArticulationLink*>(parent); + + NpArticulationLink* link = static_cast<NpArticulationLink*>(NpFactory::getInstance().createArticulationLink(*this, parentLink, pose.getNormalized())); + + if(link) + { + NpScene* scene = getAPIScene(); + if(scene) + scene->addArticulationLink(*link); + } + return link; +} + + +PxU32 NpArticulation::getNbLinks() const +{ + NP_READ_CHECK(getOwnerScene()); + return mArticulationLinks.size(); +} + + +PxU32 NpArticulation::getLinks(PxArticulationLink** userBuffer, PxU32 bufferSize, PxU32 startIndex) const +{ + NP_READ_CHECK(getOwnerScene()); + return Cm::getArrayOfPointers(userBuffer, bufferSize, startIndex, mArticulationLinks.begin(), mArticulationLinks.size()); +} + + +PxBounds3 NpArticulation::getWorldBounds(float inflation) const +{ + NP_READ_CHECK(getOwnerScene()); + PxBounds3 bounds = PxBounds3::empty(); + + for(PxU32 i=0; i < mArticulationLinks.size(); i++) + { + bounds.include(mArticulationLinks[i]->getWorldBounds()); + } + PX_ASSERT(bounds.isValid()); + + // PT: unfortunately we can't just scale the min/max vectors, we need to go through center/extents. + const PxVec3 center = bounds.getCenter(); + const PxVec3 inflatedExtents = bounds.getExtents() * inflation; + return PxBounds3::centerExtents(center, inflatedExtents); +} + + +PxAggregate* NpArticulation::getAggregate() const +{ + NP_READ_CHECK(getOwnerScene()); + return mAggregate; +} + + +void NpArticulation::setName(const char* debugName) +{ + NP_WRITE_CHECK(getOwnerScene()); + mName = debugName; +} + + +const char* NpArticulation::getName() const +{ + NP_READ_CHECK(getOwnerScene()); + return mName; +} + + +NpScene* NpArticulation::getAPIScene() const +{ + return static_cast<NpScene*>(mArticulation.getScbSceneForAPI() ? mArticulation.getScbSceneForAPI()->getPxScene() : NULL); +} + + +NpScene* NpArticulation::getOwnerScene() const +{ + return static_cast<NpScene*>(mArticulation.getScbScene() ? mArticulation.getScbScene()->getPxScene() : NULL); +} + + +#if PX_ENABLE_DEBUG_VISUALIZATION +void NpArticulation::visualize(Cm::RenderOutput& out, NpScene* scene) +{ + for(PxU32 i=0;i<mArticulationLinks.size();i++) + mArticulationLinks[i]->visualize(out, scene); +} +#endif // PX_ENABLE_DEBUG_VISUALIZATION + + +PxArticulationDriveCache* NpArticulation::createDriveCache(PxReal compliance, PxU32 driveIterations) const +{ + PX_CHECK_AND_RETURN_NULL(getAPIScene(), "PxArticulation::createDriveCache: object must be in a scene"); + NP_READ_CHECK(getOwnerScene()); // doesn't modify the scene, only reads + + return reinterpret_cast<PxArticulationDriveCache*>(mArticulation.getScArticulation().createDriveCache(compliance, driveIterations)); +} + + +void NpArticulation::updateDriveCache(PxArticulationDriveCache& cache, PxReal compliance, PxU32 driveIterations) const +{ + PX_CHECK_AND_RETURN(getAPIScene(), "PxArticulation::updateDriveCache: object must be in a scene"); + + Sc::ArticulationDriveCache& c = reinterpret_cast<Sc::ArticulationDriveCache&>(cache); + PX_CHECK_AND_RETURN(mArticulation.getScArticulation().getCacheLinkCount(c) == mArticulationLinks.size(), "PxArticulation::updateDriveCache: Articulation size has changed; drive cache is invalid"); + + NP_READ_CHECK(getOwnerScene()); // doesn't modify the scene, only reads + mArticulation.getScArticulation().updateDriveCache(c, compliance, driveIterations); +} + +void NpArticulation::releaseDriveCache(PxArticulationDriveCache&cache ) const +{ + PX_CHECK_AND_RETURN(getAPIScene(), "PxArticulation::releaseDriveCache: object must be in a scene"); + NP_READ_CHECK(getOwnerScene()); // doesn't modify the scene, only reads + + mArticulation.getScArticulation().releaseDriveCache(reinterpret_cast<Sc::ArticulationDriveCache&>(cache)); +} + +void NpArticulation::applyImpulse(PxArticulationLink* link, + const PxArticulationDriveCache& driveCache, + const PxVec3& force, + const PxVec3& torque) +{ + PX_CHECK_AND_RETURN(getAPIScene(), "PxArticulation::applyImpulse: object must be in a scene"); + PX_CHECK_AND_RETURN(force.isFinite() && torque.isFinite(), "PxArticulation::applyImpulse: invalid force/torque"); + const Sc::ArticulationDriveCache& c = reinterpret_cast<const Sc::ArticulationDriveCache&>(driveCache); + PX_CHECK_AND_RETURN(mArticulation.getScArticulation().getCacheLinkCount(c) == mArticulationLinks.size(), "PxArticulation::applyImpulse: Articulation size has changed; drive cache is invalid"); + + NP_WRITE_CHECK(getOwnerScene()); + + if(isSleeping()) + wakeUp(); + + mArticulation.getScArticulation().applyImpulse(static_cast<NpArticulationLink*>(link)->getScbBodyFast().getScBody(), c,force, torque); + for(PxU32 i=0;i<mArticulationLinks.size();i++) + { + PxVec3 lv = mArticulationLinks[i]->getScbBodyFast().getScBody().getLinearVelocity(), + av = mArticulationLinks[i]->getScbBodyFast().getScBody().getAngularVelocity(); + mArticulationLinks[i]->setLinearVelocity(lv); + mArticulationLinks[i]->setAngularVelocity(av); + } +} + +void NpArticulation::computeImpulseResponse(PxArticulationLink* link, + PxVec3& linearResponse, + PxVec3& angularResponse, + const PxArticulationDriveCache& driveCache, + const PxVec3& force, + const PxVec3& torque) const +{ + + PX_CHECK_AND_RETURN(getAPIScene(), "PxArticulation::computeImpulseResponse: object must be in a scene"); + PX_CHECK_AND_RETURN(force.isFinite() && torque.isFinite(), "PxArticulation::computeImpulseResponse: invalid force/torque"); + NP_READ_CHECK(getOwnerScene()); + + const Sc::ArticulationDriveCache& c = reinterpret_cast<const Sc::ArticulationDriveCache&>(driveCache); + PX_CHECK_AND_RETURN(mArticulation.getScArticulation().getCacheLinkCount(c) == mArticulationLinks.size(), "PxArticulation::computeImpulseResponse: Articulation size has changed; drive cache is invalid"); + PX_UNUSED(&c); + + mArticulation.getScArticulation().computeImpulseResponse(static_cast<NpArticulationLink*>(link)->getScbBodyFast().getScBody(), + linearResponse, angularResponse, + reinterpret_cast<const Sc::ArticulationDriveCache&>(driveCache), + force, torque); +} + +NpArticulationLink* NpArticulation::getRoot() +{ + if(!mArticulationLinks.size()) + return NULL; + + PX_ASSERT(mArticulationLinks[0]->getInboundJoint()==NULL); + return mArticulationLinks[0]; +} + + +Scb::Body* NpArticulationGetRootFromScb(Scb::Articulation&c) +{ + const size_t offset = size_t(&(reinterpret_cast<NpArticulation*>(0)->getScbArticulation())); + NpArticulation* np = reinterpret_cast<NpArticulation*>(reinterpret_cast<char*>(&c)-offset); + + NpArticulationLink* a = np->getRoot(); + return a ? &a->getScbBodyFast() : NULL; +} + +} diff --git a/PhysX_3.4/Source/PhysX/src/NpArticulation.h b/PhysX_3.4/Source/PhysX/src/NpArticulation.h new file mode 100644 index 00000000..13d68e28 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpArticulation.h @@ -0,0 +1,184 @@ +// 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_NP_ARTICULATION +#define PX_PHYSICS_NP_ARTICULATION + +#include "PxArticulation.h" +#include "CmPhysXCommon.h" + +#if PX_ENABLE_DEBUG_VISUALIZATION +#include "CmRenderOutput.h" +#endif + +#include "ScbArticulation.h" +#include "NpArticulationLink.h" + +namespace physx +{ + +class NpArticulationLink; +class NpScene; +class NpAggregate; +class PxAggregate; + + +class NpArticulation : public PxArticulation, 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: + virtual ~NpArticulation(); + +// PX_SERIALIZATION + NpArticulation(PxBaseFlags baseFlags) : PxArticulation(baseFlags), mArticulation(PxEmpty), mArticulationLinks(PxEmpty) {} + virtual void exportExtraData(PxSerializationContext& stream); + void importExtraData(PxDeserializationContext& context); + void resolveReferences(PxDeserializationContext& context); + virtual void requires(PxProcessPxBaseCallback& c); + static NpArticulation* createObject(PxU8*& address, PxDeserializationContext& context); + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + + //--------------------------------------------------------------------------------- + // PxArticulation implementation + //--------------------------------------------------------------------------------- + virtual void release(); + + virtual PxScene* getScene() const; + + virtual PxU32 getInternalDriveIterations() const; + virtual void setInternalDriveIterations(PxU32 iterations); + + virtual PxU32 getExternalDriveIterations() const; + virtual void setExternalDriveIterations(PxU32 iterations); + + virtual PxU32 getMaxProjectionIterations() const; + virtual void setMaxProjectionIterations(PxU32 iterations); + + virtual PxReal getSeparationTolerance() const; + virtual void setSeparationTolerance(PxReal tolerance); + + virtual void setSleepThreshold(PxReal threshold); + virtual PxReal getSleepThreshold() const; + + virtual void setStabilizationThreshold(PxReal threshold); + virtual PxReal getStabilizationThreshold() const; + + virtual void setWakeCounter(PxReal wakeCounterValue); + virtual PxReal getWakeCounter() const; + + virtual void setSolverIterationCounts(PxU32 positionIters, PxU32 velocityIters); + virtual void getSolverIterationCounts(PxU32 & positionIters, PxU32 & velocityIters) const; + + virtual bool isSleeping() const; + virtual void wakeUp(); + virtual void putToSleep(); + + virtual PxArticulationLink* createLink(PxArticulationLink* parent, const PxTransform& pose); + + virtual PxU32 getNbLinks() const; + virtual PxU32 getLinks(PxArticulationLink** userBuffer, PxU32 bufferSize, PxU32 startIndex) const; + + virtual PxBounds3 getWorldBounds(float inflation=1.01f) const; + + virtual PxAggregate* getAggregate() const; + + // Debug name + virtual void setName(const char*); + virtual const char* getName() const; + + virtual PxArticulationDriveCache* + createDriveCache(PxReal compliance, PxU32 driveIterations) const; + + virtual void updateDriveCache(PxArticulationDriveCache& cache, PxReal compliance, PxU32 driveIterations) const; + + virtual void releaseDriveCache(PxArticulationDriveCache&) const; + + virtual void applyImpulse(PxArticulationLink*, + const PxArticulationDriveCache& driveCache, + const PxVec3& force, + const PxVec3& torque); + + virtual void computeImpulseResponse(PxArticulationLink*, + PxVec3& linearResponse, + PxVec3& angularResponse, + const PxArticulationDriveCache& driveCache, + const PxVec3& force, + const PxVec3& torque) const; + + + + + //--------------------------------------------------------------------------------- + // Miscellaneous + //--------------------------------------------------------------------------------- + NpArticulation(); + + PX_INLINE void addToLinkList(NpArticulationLink& link) { mArticulationLinks.pushBack(&link); } + bool removeLinkFromList(NpArticulationLink& link) { PX_ASSERT(mArticulationLinks.find(&link) != mArticulationLinks.end()); return mArticulationLinks.findAndReplaceWithLast(&link); } + PX_FORCE_INLINE NpArticulationLink* const* getLinks() { return &mArticulationLinks.front(); } + + NpArticulationLink* getRoot(); + + PX_FORCE_INLINE const Scb::Articulation& getArticulation() const { return mArticulation; } + PX_FORCE_INLINE Scb::Articulation& getArticulation() { return mArticulation; } + + NpScene* getAPIScene() const; + NpScene* getOwnerScene() const; // the scene the user thinks the actor is in, or from which the actor is pending removal + + PX_FORCE_INLINE void setAggregate(NpAggregate* a) { mAggregate = a; } + + void wakeUpInternal(bool forceWakeUp, bool autowake); + + PX_FORCE_INLINE Scb::Articulation& getScbArticulation() { return mArticulation; } + PX_FORCE_INLINE const Scb::Articulation& getScbArticulation() const { return mArticulation; } + + +#if PX_ENABLE_DEBUG_VISUALIZATION +public: + void visualize(Cm::RenderOutput& out, NpScene* scene); +#endif + +private: + Scb::Articulation mArticulation; + NpArticulationLinkArray mArticulationLinks; + NpAggregate* mAggregate; + const char* mName; +}; + + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/NpArticulationJoint.cpp b/PhysX_3.4/Source/PhysX/src/NpArticulationJoint.cpp new file mode 100644 index 00000000..a519c8ec --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpArticulationJoint.cpp @@ -0,0 +1,403 @@ +// 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 "NpWriteCheck.h" +#include "NpReadCheck.h" + +namespace physx +{ + +// PX_SERIALIZATION +void NpArticulationJoint::resolveReferences(PxDeserializationContext& context) +{ + context.translatePxBase(mParent); + context.translatePxBase(mChild); + // temporary 3.3.1 -> 3.3.2 backwards compatibility patch; remove in 3.4. + PxU32 version = context.getPhysXVersion(); + if(version < 0x03030200) + mJoint.getScArticulationJoint().setDriveType(PxArticulationJointDriveType::eTARGET); +} + +NpArticulationJoint* NpArticulationJoint::createObject(PxU8*& address, PxDeserializationContext& context) +{ + NpArticulationJoint* obj = new (address) NpArticulationJoint(PxBaseFlags(0)); + address += sizeof(NpArticulationJoint); + obj->importExtraData(context); + obj->resolveReferences(context); + return obj; +} +// ~PX_SERIALIZATION + +NpArticulationJoint::NpArticulationJoint(NpArticulationLink& parent, + const PxTransform& parentFrame, + NpArticulationLink& child, + const PxTransform& childFrame) +: PxArticulationJoint(PxConcreteType::eARTICULATION_JOINT, PxBaseFlag::eOWNS_MEMORY) +, mJoint(parentFrame, childFrame) +, mParent(&parent) +, mChild(&child) +{} + + +NpArticulationJoint::~NpArticulationJoint() +{ +} + + +void NpArticulationJoint::release() +{ + NpPhysics::getInstance().notifyDeletionListenersUserRelease(this, NULL); + + if (mJoint.getScbSceneForAPI()) + mJoint.getScbSceneForAPI()->removeArticulationJoint(mJoint); + + mJoint.destroy(); +} + + + +PxTransform NpArticulationJoint::getParentPose() const +{ + NP_READ_CHECK(getOwnerScene()); + + return mParent->getCMassLocalPose().transform(mJoint.getParentPose()); +} + +void NpArticulationJoint::setParentPose(const PxTransform& t) +{ + PX_CHECK_AND_RETURN(t.isSane(), "NpArticulationJoint::setParentPose t is not valid."); + + NP_WRITE_CHECK(getOwnerScene()); + if(mParent==NULL) + return; + + mJoint.setParentPose(mParent->getCMassLocalPose().transformInv(t.getNormalized())); +} + + + +PxTransform NpArticulationJoint::getChildPose() const +{ + NP_READ_CHECK(getOwnerScene()); + + return mChild->getCMassLocalPose().transform(mJoint.getChildPose()); +} + +void NpArticulationJoint::setChildPose(const PxTransform& t) +{ + PX_CHECK_AND_RETURN(t.isSane(), "NpArticulationJoint::setChildPose t is not valid."); + + NP_WRITE_CHECK(getOwnerScene()); + + mJoint.setChildPose(mChild->getCMassLocalPose().transformInv(t.getNormalized())); +} + + + +void NpArticulationJoint::setTargetOrientation(const PxQuat& p) +{ + PX_CHECK_AND_RETURN(mJoint.getDriveType() != PxArticulationJointDriveType::eTARGET || p.isUnit(), "NpArticulationJoint::setTargetOrientation, quat orientation is not valid."); + PX_CHECK_AND_RETURN(mJoint.getDriveType() != PxArticulationJointDriveType::eERROR || (p.getImaginaryPart().isFinite() && p.w == 0), "NpArticulationJoint::setTargetOrientation rotation vector orientation is not valid."); + + NP_WRITE_CHECK(getOwnerScene()); + + mJoint.setTargetOrientation(p); +} + + +PxQuat NpArticulationJoint::getTargetOrientation() const +{ + NP_READ_CHECK(getOwnerScene()); + + return mJoint.getTargetOrientation(); +} + + +void NpArticulationJoint::setTargetVelocity(const PxVec3& v) +{ + PX_CHECK_AND_RETURN(v.isFinite(), "NpArticulationJoint::setTargetVelocity v is not valid."); + + NP_WRITE_CHECK(getOwnerScene()); + + mJoint.setTargetVelocity(v); +} + + +PxArticulationJointDriveType::Enum NpArticulationJoint::getDriveType() const +{ + NP_READ_CHECK(getOwnerScene()); + return mJoint.getDriveType(); +} + +void NpArticulationJoint::setDriveType(PxArticulationJointDriveType::Enum driveType) +{ + NP_WRITE_CHECK(getOwnerScene()); + mJoint.setDriveType(driveType); +} + + +PxVec3 NpArticulationJoint::getTargetVelocity() const +{ + NP_READ_CHECK(getOwnerScene()); + + return mJoint.getTargetVelocity(); +} + + +void NpArticulationJoint::setStiffness(PxReal s) +{ + PX_CHECK_AND_RETURN(PxIsFinite(s) && s >= 0.0f, "PxArticulationJoint::setStiffness: spring coefficient must be >= 0!"); + + NP_WRITE_CHECK(getOwnerScene()); + + mJoint.setStiffness(s); +} + + +PxReal NpArticulationJoint::getStiffness() const +{ + NP_READ_CHECK(getOwnerScene()); + + return mJoint.getStiffness(); +} + + +void NpArticulationJoint::setDamping(PxReal d) +{ + PX_CHECK_AND_RETURN(PxIsFinite(d) && d >= 0.0f, "PxArticulationJoint::setDamping: damping coefficient must be >= 0!"); + + NP_WRITE_CHECK(getOwnerScene()); + + mJoint.setDamping(d); +} + + +PxReal NpArticulationJoint::getDamping() const +{ + NP_READ_CHECK(getOwnerScene()); + + return mJoint.getDamping(); +} + + +void NpArticulationJoint::setSwingLimitContactDistance(PxReal d) +{ + PX_CHECK_AND_RETURN(PxIsFinite(d) && d >= 0.0f, "PxArticulationJoint::setSwingLimitContactDistance: padding coefficient must be > 0!"); + + NP_WRITE_CHECK(getOwnerScene()); + + mJoint.setSwingLimitContactDistance(d); +} + + +PxReal NpArticulationJoint::getSwingLimitContactDistance() const +{ + NP_READ_CHECK(getOwnerScene()); + + return mJoint.getSwingLimitContactDistance(); +} + + +void NpArticulationJoint::setTwistLimitContactDistance(PxReal d) +{ + PX_CHECK_AND_RETURN(PxIsFinite(d) && d >= 0.0f, "PxArticulationJoint::setTwistLimitContactDistance: padding coefficient must be > 0!"); + + NP_WRITE_CHECK(getOwnerScene()); + + mJoint.setTwistLimitContactDistance(d); +} + + +PxReal NpArticulationJoint::getTwistLimitContactDistance() const +{ + NP_READ_CHECK(getOwnerScene()); + + return mJoint.getTwistLimitContactDistance(); +} + + +void NpArticulationJoint::setInternalCompliance(PxReal r) +{ + PX_CHECK_AND_RETURN(PxIsFinite(r) && r>0, "PxArticulationJoint::setInternalCompliance: compliance must be > 0"); + + NP_WRITE_CHECK(getOwnerScene()); + + mJoint.setInternalCompliance(r); +} + + + +PxReal NpArticulationJoint::getInternalCompliance() const +{ + NP_READ_CHECK(getOwnerScene()); + + return mJoint.getInternalCompliance(); +} + + +void NpArticulationJoint::setExternalCompliance(PxReal r) +{ + PX_CHECK_AND_RETURN(PxIsFinite(r) && r>0, "PxArticulationJoint::setExternalCompliance: compliance must be > 0"); + NP_WRITE_CHECK(getOwnerScene()); + + mJoint.setExternalCompliance(r); +} + + +PxReal NpArticulationJoint::getExternalCompliance() const +{ + NP_READ_CHECK(getOwnerScene()); + + return mJoint.getExternalCompliance(); +} + + +void NpArticulationJoint::setSwingLimit(PxReal yLimit, PxReal zLimit) +{ + PX_CHECK_AND_RETURN(PxIsFinite(yLimit) && PxIsFinite(zLimit) && yLimit > 0 && zLimit > 0 && yLimit < PxPi && zLimit < PxPi, + "PxArticulationJoint::setSwingLimit: values must be >0 and < Pi"); + NP_WRITE_CHECK(getOwnerScene()); + + mJoint.setSwingLimit(yLimit, zLimit); +} + + +void NpArticulationJoint::getSwingLimit(PxReal &yLimit, PxReal &zLimit) const +{ + NP_READ_CHECK(getOwnerScene()); + + mJoint.getSwingLimit(yLimit, zLimit); +} + + +void NpArticulationJoint::setTangentialStiffness(PxReal stiffness) +{ + PX_CHECK_AND_RETURN(PxIsFinite(stiffness) && stiffness >= 0, "PxArticulationJoint::setTangentialStiffness: stiffness must be > 0"); + + NP_WRITE_CHECK(getOwnerScene()); + + mJoint.setTangentialStiffness(stiffness); +} + + +PxReal NpArticulationJoint::getTangentialStiffness() const +{ + NP_READ_CHECK(getOwnerScene()); + + return mJoint.getTangentialStiffness(); +} + + +void NpArticulationJoint::setTangentialDamping(PxReal damping) +{ + PX_CHECK_AND_RETURN(PxIsFinite(damping) && damping >= 0, "PxArticulationJoint::setTangentialDamping: damping must be > 0"); + NP_WRITE_CHECK(getOwnerScene()); + + mJoint.setTangentialDamping(damping); +} + + +PxReal NpArticulationJoint::getTangentialDamping() const +{ + NP_READ_CHECK(getOwnerScene()); + + return mJoint.getTangentialDamping(); +} + + + +void NpArticulationJoint::setSwingLimitEnabled(bool e) +{ + NP_WRITE_CHECK(getOwnerScene()); + + mJoint.setSwingLimitEnabled(e); +} + + +bool NpArticulationJoint::getSwingLimitEnabled() const +{ + NP_READ_CHECK(getOwnerScene()); + + return mJoint.getSwingLimitEnabled(); +} + + +void NpArticulationJoint::setTwistLimit(PxReal lower, PxReal upper) +{ + PX_CHECK_AND_RETURN(PxIsFinite(lower) && PxIsFinite(upper) && lower<upper && lower>-PxPi && upper < PxPi, "PxArticulationJoint::setTwistLimit: illegal parameters"); + + NP_WRITE_CHECK(getOwnerScene()); + + mJoint.setTwistLimit(lower, upper); +} + + +void NpArticulationJoint::getTwistLimit(PxReal &lower, PxReal &upper) const +{ + NP_READ_CHECK(getOwnerScene()); + + mJoint.getTwistLimit(lower, upper); +} + + +void NpArticulationJoint::setTwistLimitEnabled(bool e) +{ + NP_WRITE_CHECK(getOwnerScene()); + + mJoint.setTwistLimitEnabled(e); +} + + +bool NpArticulationJoint::getTwistLimitEnabled() const +{ + NP_READ_CHECK(getOwnerScene()); + + return mJoint.getTwistLimitEnabled(); +} + + +NpScene* NpArticulationJoint::getOwnerScene() const +{ + return mJoint.getScbScene() ? static_cast<NpScene *>(mJoint.getScbScene()->getPxScene()) : NULL; +} + + +void NpArticulationJointGetBodiesFromScb(Scb::ArticulationJoint&c, Scb::Body*&b0, Scb::Body*&b1) +{ + NpArticulationJoint* np = const_cast<NpArticulationJoint*>(getNpArticulationJoint(&c)); + + NpArticulationLink& a0 = np->getParent(), & a1 = np->getChild(); + b0 = &a0.getScbBodyFast(); + b1 = &a1.getScbBodyFast(); +} + + +} diff --git a/PhysX_3.4/Source/PhysX/src/NpArticulationJoint.h b/PhysX_3.4/Source/PhysX/src/NpArticulationJoint.h new file mode 100644 index 00000000..c1bf03a2 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpArticulationJoint.h @@ -0,0 +1,159 @@ +// 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_NP_ARTICULATION_JOINT +#define PX_PHYSICS_NP_ARTICULATION_JOINT + +#include "PxArticulationJoint.h" +#include "ScbArticulationJoint.h" + +#if PX_ENABLE_DEBUG_VISUALIZATION +#include "CmRenderOutput.h" +#endif + +namespace physx +{ + +class NpScene; +class NpArticulationLink; + +class NpArticulationJoint : public PxArticulationJoint, public Ps::UserAllocated +{ +//= ATTENTION! ===================================================================================== +// Changing the data layout of this class breaks the binary serialization format. See comments for +// PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData +// function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION +// accordingly. +//================================================================================================== +public: +// PX_SERIALIZATION + NpArticulationJoint(PxBaseFlags baseFlags) : PxArticulationJoint(baseFlags), mJoint(PxEmpty) {} + virtual void resolveReferences(PxDeserializationContext& context); + static NpArticulationJoint* createObject(PxU8*& address, PxDeserializationContext& context); + static void getBinaryMetaData(PxOutputStream& stream); + void exportExtraData(PxSerializationContext&) {} + void importExtraData(PxDeserializationContext&) {} + virtual void requires(PxProcessPxBaseCallback&){} + virtual bool isSubordinate() const { return true; } +//~PX_SERIALIZATION + NpArticulationJoint(NpArticulationLink& parent, + const PxTransform& parentFrame, + NpArticulationLink& child, + const PxTransform& childFrame); + + virtual ~NpArticulationJoint(); + + //--------------------------------------------------------------------------------- + // PxArticulationJoint implementation + //--------------------------------------------------------------------------------- + // Save + + virtual PxTransform getParentPose() const; + virtual void setParentPose(const PxTransform&); + + virtual PxTransform getChildPose() const; + virtual void setChildPose(const PxTransform&); + + virtual void setTargetOrientation(const PxQuat&); + virtual PxQuat getTargetOrientation() const; + + virtual void setTargetVelocity(const PxVec3&); + virtual PxVec3 getTargetVelocity() const; + + virtual void setDriveType(PxArticulationJointDriveType::Enum driveType); + virtual PxArticulationJointDriveType::Enum + getDriveType() const; + + + virtual void setStiffness(PxReal); + virtual PxReal getStiffness() const; + + virtual void setDamping(PxReal); + virtual PxReal getDamping() const; + + virtual void setInternalCompliance(PxReal); + virtual PxReal getInternalCompliance() const; + + virtual void setExternalCompliance(PxReal); + virtual PxReal getExternalCompliance() const; + + virtual void setSwingLimit(PxReal yLimit, PxReal zLimit); + virtual void getSwingLimit(PxReal &yLimit, PxReal &zLimit) const; + + virtual void setTangentialStiffness(PxReal spring); + virtual PxReal getTangentialStiffness() const; + + virtual void setTangentialDamping(PxReal damping); + virtual PxReal getTangentialDamping() const; + + virtual void setSwingLimitEnabled(bool); + virtual bool getSwingLimitEnabled() const; + + virtual void setSwingLimitContactDistance(PxReal contactDistance); + virtual PxReal getSwingLimitContactDistance() const; + + virtual void setTwistLimit(PxReal lower, PxReal upper); + virtual void getTwistLimit(PxReal &lower, PxReal &upper) const; + + virtual void setTwistLimitEnabled(bool); + virtual bool getTwistLimitEnabled() const; + + virtual void setTwistLimitContactDistance(PxReal contactDistance); + virtual PxReal getTwistLimitContactDistance() const; + + + //--------------------------------------------------------------------------------- + // Miscellaneous + //--------------------------------------------------------------------------------- +public: + void release(); + + PX_INLINE const Scb::ArticulationJoint& getScbArticulationJoint() const { return mJoint; } + PX_INLINE Scb::ArticulationJoint& getScbArticulationJoint() { return mJoint; } + + PX_INLINE const NpArticulationLink& getParent() const { return *mParent; } + PX_INLINE NpArticulationLink& getParent() { return *mParent; } + + PX_INLINE const NpArticulationLink& getChild() const { return *mChild; } + PX_INLINE NpArticulationLink& getChild() { return *mChild; } + +private: + NpScene* getOwnerScene() const; // the scene the user thinks the actor is in, or from which the actor is pending removal + + +private: + Scb::ArticulationJoint mJoint; + NpArticulationLink* mParent; + NpArticulationLink* mChild; +}; + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/NpArticulationLink.cpp b/PhysX_3.4/Source/PhysX/src/NpArticulationLink.cpp new file mode 100644 index 00000000..1843d7d1 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpArticulationLink.cpp @@ -0,0 +1,384 @@ +// 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 "NpArticulationLink.h" +#include "NpArticulationJoint.h" +#include "NpWriteCheck.h" +#include "NpReadCheck.h" +#include "ScbArticulation.h" +#include "CmVisualization.h" +#include "CmConeLimitHelper.h" +#include "CmUtils.h" +#include "NpArticulation.h" + +using namespace physx; + +// PX_SERIALIZATION +void NpArticulationLink::requires(PxProcessPxBaseCallback& c) +{ + NpArticulationLinkT::requires(c); + + if(mInboundJoint) + c.process(*mInboundJoint); +} + +void NpArticulationLink::exportExtraData(PxSerializationContext& stream) +{ + NpArticulationLinkT::exportExtraData(stream); + Cm::exportInlineArray(mChildLinks, stream); +} + +void NpArticulationLink::importExtraData(PxDeserializationContext& context) +{ + NpArticulationLinkT::importExtraData(context); + Cm::importInlineArray(mChildLinks, context); +} + +void NpArticulationLink::resolveReferences(PxDeserializationContext& context) +{ + context.translatePxBase(mRoot); + context.translatePxBase(mInboundJoint); + context.translatePxBase(mParent); + + NpArticulationLinkT::resolveReferences(context); + + const PxU32 nbLinks = mChildLinks.size(); + for(PxU32 i=0;i<nbLinks;i++) + context.translatePxBase(mChildLinks[i]); +} + +NpArticulationLink* NpArticulationLink::createObject(PxU8*& address, PxDeserializationContext& context) +{ + NpArticulationLink* obj = new (address) NpArticulationLink(PxBaseFlags(0)); + address += sizeof(NpArticulationLink); + obj->importExtraData(context); + obj->resolveReferences(context); + return obj; +} +//~PX_SERIALIZATION + +NpArticulationLink::NpArticulationLink(const PxTransform& bodyPose, NpArticulation& root, NpArticulationLink* parent) +: NpArticulationLinkT(PxConcreteType::eARTICULATION_LINK, PxBaseFlag::eOWNS_MEMORY, PxActorType::eARTICULATION_LINK, bodyPose) +, mRoot(&root) +, mInboundJoint(NULL) +, mParent(parent) +{ + PX_ASSERT(mBody.getScbType() == ScbType::BODY); + mBody.setScbType(ScbType::BODY_FROM_ARTICULATION_LINK); + + mRoot->addToLinkList(*this); + + if (parent) + parent->addToChildList(*this); +} + + +NpArticulationLink::~NpArticulationLink() +{ +} + +void NpArticulationLink::releaseInternal() +{ + NpPhysics::getInstance().notifyDeletionListenersUserRelease(this, userData); + + NpArticulationLinkT::release(); + + mRoot->removeLinkFromList(*this); + + if (mParent) + mParent->removeFromChildList(*this); + + if (mInboundJoint) + mInboundJoint->release(); + + NpScene* npScene = NpActor::getAPIScene(*this); + if (npScene) + npScene->getScene().removeActor(mBody, true, false); + + mBody.destroy(); +} + + +void NpArticulationLink::release() +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_AND_RETURN(mRoot->getRoot() != this || NpActor::getOwnerScene(*this) == NULL, "PxArticulationLink::release(): root link may not be released while articulation is in a scene"); + + //! this function doesn't get called when the articulation root is released + // therefore, put deregistration code etc. into dtor, not here + + if (mChildLinks.empty()) + { + releaseInternal(); + } + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxArticulationLink::release(): Only leaf articulation links can be released. Release call failed"); + } +} + + + +PxTransform NpArticulationLink::getGlobalPose() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + //!!!AL TODO: Need to start from root and compute along the branch to reflect double buffered state of root link + return getScbBodyFast().getBody2World() * getScbBodyFast().getBody2Actor().getInverse(); +} + + +PxArticulation& NpArticulationLink::getArticulation() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return *mRoot; +} + + +PxArticulationJoint* NpArticulationLink::getInboundJoint() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return mInboundJoint; +} + + +PxU32 NpArticulationLink::getNbChildren() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return mChildLinks.size(); +} + + +PxU32 NpArticulationLink::getChildren(PxArticulationLink** userBuffer, PxU32 bufferSize, PxU32 startIndex) const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return Cm::getArrayOfPointers(userBuffer, bufferSize, startIndex, mChildLinks.begin(), mChildLinks.size()); +} + + +void NpArticulationLink::setCMassLocalPose(const PxTransform& pose) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(pose.isSane(), "PxArticulationLink::setCMassLocalPose: invalid parameter"); + + PxTransform p = pose.getNormalized(); + PxTransform oldpose = getScbBodyFast().getBody2Actor(); + PxTransform comShift = p.transformInv(oldpose); + + NpArticulationLinkT::setCMassLocalPoseInternal(p); + + if(mInboundJoint) + { + Scb::ArticulationJoint &j = mInboundJoint->getScbArticulationJoint(); + j.setChildPose(comShift.transform(j.getChildPose())); + } + + for(PxU32 i=0; i<mChildLinks.size(); i++) + { + Scb::ArticulationJoint &j = static_cast<NpArticulationJoint*>(mChildLinks[i]->getInboundJoint())->getScbArticulationJoint(); + j.setParentPose(comShift.transform(j.getParentPose())); + } +} + + +void NpArticulationLink::addForce(const PxVec3& force, PxForceMode::Enum mode, bool autowake) +{ + NpScene* scene = NpActor::getOwnerScene(*this); + PX_UNUSED(scene); + + PX_CHECK_AND_RETURN(force.isFinite(), "NpArticulationLink::addForce: force is not valid."); + NP_WRITE_CHECK(scene); + PX_CHECK_AND_RETURN(scene, "NpArticulationLink::addForce: articulation link must be in a scene!"); + + addSpatialForce(&force, 0, mode); + + mRoot->wakeUpInternal((!force.isZero()), autowake); +} + + +void NpArticulationLink::addTorque(const PxVec3& torque, PxForceMode::Enum mode, bool autowake) +{ + NpScene* scene = NpActor::getOwnerScene(*this); + PX_UNUSED(scene); + + PX_CHECK_AND_RETURN(torque.isFinite(), "NpArticulationLink::addTorque: force is not valid."); + NP_WRITE_CHECK(scene); + PX_CHECK_AND_RETURN(scene, "NpArticulationLink::addTorque: articulation link must be in a scene!"); + + addSpatialForce(0, &torque, mode); + + mRoot->wakeUpInternal((!torque.isZero()), autowake); +} + +void NpArticulationLink::clearForce(PxForceMode::Enum mode) +{ + NpScene* scene = NpActor::getOwnerScene(*this); + PX_UNUSED(scene); + NP_WRITE_CHECK(scene); + PX_CHECK_AND_RETURN(scene, "NpArticulationLink::clearForce: articulation link must be in a scene!"); + + clearSpatialForce(mode, true, false); +} + +void NpArticulationLink::clearTorque(PxForceMode::Enum mode) +{ + NpScene* scene = NpActor::getOwnerScene(*this); + PX_UNUSED(scene); + NP_WRITE_CHECK(scene); + PX_CHECK_AND_RETURN(scene, "NpArticulationLink::clearTorque: articulation link must be in a scene!"); + + clearSpatialForce(mode, false, true); +} + +void NpArticulationLink::setGlobalPose(const PxTransform& pose) +{ + // clow: no need to test inputs here, it's done in the setGlobalPose function already + setGlobalPose(pose, true); +} + +void NpArticulationLink::setGlobalPose(const PxTransform& pose, bool autowake) +{ + NpScene* scene = NpActor::getOwnerScene(*this); + + PX_CHECK_AND_RETURN(pose.isValid(), "NpArticulationLink::setGlobalPose pose is not valid."); + + NP_WRITE_CHECK(scene); + +#if PX_CHECKED + if(scene) + scene->checkPositionSanity(*this, pose, "PxArticulationLink::setGlobalPose"); +#endif + + PxTransform body2World = pose * getScbBodyFast().getBody2Actor(); + getScbBodyFast().setBody2World(body2World, false); + + if (scene && autowake) + mRoot->wakeUpInternal(false, true); +} + + +void NpArticulationLink::setLinearVelocity(const PxVec3& velocity, bool autowake) +{ + NpScene* scene = NpActor::getOwnerScene(*this); + + PX_CHECK_AND_RETURN(velocity.isFinite(), "NpArticulationLink::setLinearVelocity velocity is not valid."); + + NP_WRITE_CHECK(scene); + + getScbBodyFast().setLinearVelocity(velocity); + + if (scene) + mRoot->wakeUpInternal((!velocity.isZero()), autowake); +} + + +void NpArticulationLink::setAngularVelocity(const PxVec3& velocity, bool autowake) +{ + NpScene* scene = NpActor::getOwnerScene(*this); + + PX_CHECK_AND_RETURN(velocity.isFinite(), "NpArticulationLink::setAngularVelocity velocity is not valid."); + + NP_WRITE_CHECK(scene); + + getScbBodyFast().setAngularVelocity(velocity); + + if (scene) + mRoot->wakeUpInternal((!velocity.isZero()), autowake); +} + + +#if PX_ENABLE_DEBUG_VISUALIZATION +void NpArticulationLink::visualize(Cm::RenderOutput& out, NpScene* scene) +{ + NpArticulationLinkT::visualize(out, scene); + + if (getScbBodyFast().getActorFlags() & PxActorFlag::eVISUALIZATION) + { + PX_ASSERT(getScene()); + PxReal scale = getScene()->getVisualizationParameter(PxVisualizationParameter::eSCALE); + + PxReal massAxes = scale * getScene()->getVisualizationParameter(PxVisualizationParameter::eBODY_MASS_AXES); + if (massAxes != 0) + { + PxU32 color = 0xff; + color = (color<<16 | color<<8 | color); + PxVec3 dims = invertDiagInertia(getScbBodyFast().getInverseInertia()); + dims = getDimsFromBodyInertia(dims, 1.0f / getScbBodyFast().getInverseMass()); + + out << color << getScbBodyFast().getBody2World() << Cm::DebugBox(dims * 0.5f); + } + PxReal frameScale = scale * getScene()->getVisualizationParameter(PxVisualizationParameter::eJOINT_LOCAL_FRAMES); + PxReal limitScale = scale * getScene()->getVisualizationParameter(PxVisualizationParameter::eJOINT_LIMITS); + if ( frameScale != 0.0f || limitScale != 0.0f ) + { + Cm::ConstraintImmediateVisualizer viz( frameScale, limitScale, out ); + visualizeJoint( viz ); + } + } +} + +void NpArticulationLink::visualizeJoint(PxConstraintVisualizer& jointViz) +{ + NpArticulationLink* parent = getParent(); + if(parent) + { + PxTransform cA2w = getGlobalPose().transform(mInboundJoint->getChildPose()); + PxTransform cB2w = parent->getGlobalPose().transform(mInboundJoint->getParentPose()); + + jointViz.visualizeJointFrames(cA2w, cB2w); + + PxTransform parentFrame = cB2w; + + if(cA2w.q.dot(cB2w.q)<0) + cB2w.q = -cB2w.q; + + PxTransform cB2cA = cA2w.transformInv(cB2w); + + PxQuat swing, twist; + Ps::separateSwingTwist(cB2cA.q,swing,twist); + + PxMat33 cA2w_m(cA2w.q), cB2w_m(cB2w.q); + + PxReal tqPhi = Ps::tanHalf(twist.x, twist.w); // always support (-pi, +pi) + + PxReal lower, upper, yLimit, zLimit; + + mInboundJoint->getTwistLimit(lower, upper); + mInboundJoint->getSwingLimit(yLimit, zLimit); + PxReal swingPad = mInboundJoint->getSwingLimitContactDistance(), twistPad = mInboundJoint->getTwistLimitContactDistance(); + jointViz.visualizeAngularLimit(parentFrame, lower, upper, PxAbs(tqPhi) > PxTan(upper-twistPad)); + + PxVec3 tanQSwing = PxVec3(0, Ps::tanHalf(swing.z,swing.w), -Ps::tanHalf(swing.y,swing.w)); + Cm::ConeLimitHelper coneHelper(PxTan(yLimit/4), PxTan(zLimit/4), PxTan(swingPad/4)); + jointViz.visualizeLimitCone(parentFrame, PxTan(yLimit/4), PxTan(zLimit/4), !coneHelper.contains(tanQSwing)); + } +} +#endif // PX_ENABLE_DEBUG_VISUALIZATION diff --git a/PhysX_3.4/Source/PhysX/src/NpArticulationLink.h b/PhysX_3.4/Source/PhysX/src/NpArticulationLink.h new file mode 100644 index 00000000..752fa0bc --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpArticulationLink.h @@ -0,0 +1,158 @@ +// 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_NP_ARTICULATION_LINK +#define PX_PHYSICS_NP_ARTICULATION_LINK + +#include "NpRigidBodyTemplate.h" +#include "PxArticulationLink.h" + +#if PX_ENABLE_DEBUG_VISUALIZATION +#include "CmRenderOutput.h" +#endif + +namespace physx +{ + +class NpArticulation; +class NpArticulationLink; +class NpArticulationJoint; +class PxConstraintVisualizer; + +class NpArticulationLink; +typedef NpRigidBodyTemplate<PxArticulationLink> NpArticulationLinkT; + +class NpArticulationLinkArray : public Ps::InlineArray<NpArticulationLink*, 4> //!!!AL TODO: check if default of 4 elements makes sense +{ +//= 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 + NpArticulationLinkArray(const PxEMPTY) : Ps::InlineArray<NpArticulationLink*, 4> (PxEmpty) {} + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + NpArticulationLinkArray() : Ps::InlineArray<NpArticulationLink*, 4>(PX_DEBUG_EXP("articulationLinkArray")) {} +}; + + + +class NpArticulationLink : public NpArticulationLinkT +{ +//= 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 + NpArticulationLink(PxBaseFlags baseFlags) : NpArticulationLinkT(baseFlags), mChildLinks(PxEmpty) {} + virtual void exportExtraData(PxSerializationContext& stream); + void importExtraData(PxDeserializationContext& context); + void registerReferences(PxSerializationContext& stream); + void resolveReferences(PxDeserializationContext& context); + virtual void requires(PxProcessPxBaseCallback& c); + virtual bool isSubordinate() const { return true; } + static NpArticulationLink* createObject(PxU8*& address, PxDeserializationContext& context); + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + virtual ~NpArticulationLink(); + + //--------------------------------------------------------------------------------- + // PxArticulationLink implementation + //--------------------------------------------------------------------------------- + virtual void release(); + + + virtual PxActorType::Enum getType() const { return PxActorType::eARTICULATION_LINK; } + + // Pose + virtual void setGlobalPose(const PxTransform& pose); + virtual void setGlobalPose(const PxTransform& pose, bool autowake); + virtual PxTransform getGlobalPose() const; + + // Velocity + virtual void setLinearVelocity(const PxVec3&, bool autowake = true); + virtual void setAngularVelocity(const PxVec3&, bool autowake = true); + + virtual PxArticulation& getArticulation() const; + + virtual PxArticulationJoint* getInboundJoint() const; + + virtual PxU32 getNbChildren() const; + virtual PxU32 getChildren(PxArticulationLink** userBuffer, PxU32 bufferSize, PxU32 startIndex) const; + + virtual void setCMassLocalPose(const PxTransform& pose); + + virtual void addForce(const PxVec3& force, PxForceMode::Enum mode = PxForceMode::eFORCE, bool autowake = true); + virtual void addTorque(const PxVec3& torque, PxForceMode::Enum mode = PxForceMode::eFORCE, bool autowake = true); + virtual void clearForce(PxForceMode::Enum mode = PxForceMode::eFORCE); + virtual void clearTorque(PxForceMode::Enum mode = PxForceMode::eFORCE); + + //--------------------------------------------------------------------------------- + // Miscellaneous + //--------------------------------------------------------------------------------- + NpArticulationLink(const PxTransform& bodyPose, NpArticulation& root, NpArticulationLink* parent); + + void releaseInternal(); + + PX_INLINE NpArticulation& getRoot() { return *mRoot; } + PX_INLINE NpArticulationLink* getParent() { return mParent; } + + PX_INLINE void setInboundJoint(NpArticulationJoint& joint) { mInboundJoint = &joint; } + +private: + PX_INLINE void addToChildList(NpArticulationLink& link) { mChildLinks.pushBack(&link); } + PX_INLINE void removeFromChildList(NpArticulationLink& link) { PX_ASSERT(mChildLinks.find(&link) != mChildLinks.end()); mChildLinks.findAndReplaceWithLast(&link); } + +public: + PX_INLINE NpArticulationLink* const* getChildren() { return mChildLinks.empty() ? NULL : &mChildLinks.front(); } + +#if PX_ENABLE_DEBUG_VISUALIZATION +public: + void visualize(Cm::RenderOutput& out, NpScene* scene); + void visualizeJoint(PxConstraintVisualizer& jointViz); +#endif + + +private: + NpArticulation* mRoot; //!!!AL TODO: Revisit: Could probably be avoided if registration and deregistration in root is handled differently + NpArticulationJoint* mInboundJoint; + NpArticulationLink* mParent; //!!!AL TODO: Revisit: Some memory waste but makes things faster + NpArticulationLinkArray mChildLinks; +}; + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/NpBatchQuery.cpp b/PhysX_3.4/Source/PhysX/src/NpBatchQuery.cpp new file mode 100644 index 00000000..f428e706 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpBatchQuery.cpp @@ -0,0 +1,602 @@ +// 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 "NpBatchQuery.h" +#include "NpReadCheck.h" +#include "NpActor.h" +#include "NpShapeManager.h" +#include "PsAtomic.h" +#include "PsFoundation.h" +#include "PsUtilities.h" +#include "NpScene.h" + +using namespace physx; +using namespace Sq; +using namespace Cm; + +#if !PX_P64_FAMILY +PX_COMPILE_TIME_ASSERT(0==(sizeof(PxRaycastHit)& 0x0f)); +PX_COMPILE_TIME_ASSERT(0==(sizeof(PxSweepHit)& 0x0f)); +PX_COMPILE_TIME_ASSERT(0==(sizeof(PxOverlapHit)& 0x0f)); +#endif + +#define CHECK_RUNNING(QueryMessage) \ + if(Ps::atomicCompareExchange(&mBatchQueryIsRunning, -1, 0) == 1)\ + {\ + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, QueryMessage); return;\ + } + +NpBatchQuery::NpBatchQuery(NpScene& owner, const PxBatchQueryDesc& d) + : mNpScene(&owner), mNbRaycasts(0), mNbOverlaps(0), mNbSweeps(0), mBatchQueryIsRunning(0), mDesc(d), mPrevOffset(PxU32(eTERMINAL)) +{ + mHasMtdSweep = false; +} + +NpBatchQuery::~NpBatchQuery() +{ +} + +void NpBatchQuery::setUserMemory(const PxBatchQueryMemory& userMem) +{ + if(Ps::atomicCompareExchange(&mBatchQueryIsRunning, 0, 0) != 0) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxBatchQuery::setUserMemory: This batch is still executing, skipping setUserMemory"); + return; + } + + PxBatchQueryDesc& desc = getDesc(); + + desc.queryMemory = userMem; +} + +const PxBatchQueryMemory& NpBatchQuery::getUserMemory() +{ + return getDesc().queryMemory; +} + +// ROS abbreviates Raycast/Overlap/Sweep +struct QTypeROS { enum Enum { eRAYCAST = 0, eOVERLAP = 1, eSWEEP = 2 }; }; // AP: perhaps can be shared with some other code + +namespace physx +{ +struct BatchStreamHeader +{ + BatchStreamHeader( + PxHitFlags aHitFlags, const PxQueryCache* aCache, const PxQueryFilterData& aFd, + void* aUserData, PxU16 aMaxTouchHits, QTypeROS::Enum aHitTypeId) : + hitFlags(aHitFlags), fd(aFd), userData(aUserData), cache(aCache), + maxTouchHits(aMaxTouchHits), hitTypeId(char(aHitTypeId)) + { + nextQueryOffset = PxU32(NpBatchQuery::eTERMINAL); + } + + BatchStreamHeader() {} + + // TODO: possibly maintain 3 separate offset lists in the same array for raycasts/overlaps/sweeps + // offset of a 4-byte ptr to offset in the previously stored batch query in the stream, this is not a ptr because of reallocs + PxU32 nextQueryOffset; + PxHitFlags hitFlags; + PxQueryFilterData fd; + void* userData; + const PxQueryCache* cache; + PxU16 maxTouchHits; + char hitTypeId; // Sq::QTypeROS +}; +} // namespace physx + +static void writeGeom(BatchQueryStream& stream, const PxGeometry& geom) +{ + PxGeometryType::Enum geomType = geom.getType(); + stream.write<PxU32>(PxU32(geomType)); + switch (geomType) + { + case PxGeometryType::eCAPSULE: + stream.write<PxCapsuleGeometry>(static_cast<const PxCapsuleGeometry&>(geom)); + break; + case PxGeometryType::eSPHERE: + stream.write<PxSphereGeometry>(static_cast<const PxSphereGeometry&>(geom)); + break; + case PxGeometryType::eCONVEXMESH: + stream.write<PxConvexMeshGeometry>(static_cast<const PxConvexMeshGeometry&>(geom)); + break; + case PxGeometryType::eBOX: + stream.write<PxBoxGeometry>(static_cast<const PxBoxGeometry&>(geom)); + break; + case PxGeometryType::ePLANE: + case PxGeometryType::eTRIANGLEMESH: + case PxGeometryType::eHEIGHTFIELD: + case PxGeometryType::eGEOMETRY_COUNT: + case PxGeometryType::eINVALID: + PX_ALWAYS_ASSERT_MESSAGE("Unsupported geometry type in writeGeom"); + } +} + +static PxGeometry* readGeom(BatchQueryStreamReader& reader) +{ + PxU32 geomType = *reader.read<PxU32>(); + PxGeometry* anyGeom = NULL; + switch (geomType) + { + case PxGeometryType::eCAPSULE: + anyGeom = reader.read<PxCapsuleGeometry>(); + break; + case PxGeometryType::eSPHERE: + anyGeom = reader.read<PxSphereGeometry>(); + break; + case PxGeometryType::eCONVEXMESH: + anyGeom = reader.read<PxConvexMeshGeometry>(); + break; + case PxGeometryType::eBOX: + anyGeom = reader.read<PxBoxGeometry>(); + break; + default: + PX_ALWAYS_ASSERT_MESSAGE("Unsupported geometry type in readGeom"); + } + + return anyGeom; +} + +static void writeQueryInput(BatchQueryStream& stream, const MultiQueryInput& input) +{ + stream.write<MultiQueryInput>(input); + if (input.rayOrigin) + stream.write<PxVec3>(input.rayOrigin); + if (input.unitDir) + stream.write<PxVec3>(input.unitDir); + if (input.pose) + stream.write<PxTransform>(input.pose); + if (input.geometry) + writeGeom(stream, *input.geometry); +} + +static MultiQueryInput* readQueryInput(BatchQueryStreamReader& stream) +{ + MultiQueryInput* input = stream.read<MultiQueryInput>(); + if (input->rayOrigin) + input->rayOrigin = stream.read<PxVec3>(); + if (input->unitDir) + input->unitDir = stream.read<PxVec3>(); + if (input->pose) + input->pose = stream.read<PxTransform>(); + if (input->geometry) + input->geometry = readGeom(stream); + + return input; +} + +template<typename ResultType, typename HitType> +void writeStatus(ResultType* aRes, const PxHitBuffer<HitType>& hits, void* userData, bool overflow) +{ + ResultType* res = aRes; + res->userData = userData; + res->block = hits.block; + res->hasBlock = hits.hasBlock; + res->nbTouches = hits.nbTouches; + res->queryStatus = PxU8(overflow ? PxBatchQueryStatus::eOVERFLOW : PxBatchQueryStatus::eSUCCESS); + res->touches = (overflow && res->nbTouches == 0) ? NULL : hits.touches; +} + +void NpBatchQuery::resetResultBuffers() +{ + for (PxU32 i = 0; i<mNbRaycasts; i++) + { + mDesc.queryMemory.userRaycastResultBuffer[i].queryStatus = PxBatchQueryStatus::ePENDING; + mDesc.queryMemory.userRaycastResultBuffer[i].hasBlock = false; + mDesc.queryMemory.userRaycastResultBuffer[i].nbTouches = 0; + mDesc.queryMemory.userRaycastResultBuffer[i].touches = NULL; + mDesc.queryMemory.userRaycastResultBuffer[i].userData = NULL; + } + for (PxU32 i = 0; i<mNbOverlaps; i++) + { + mDesc.queryMemory.userOverlapResultBuffer[i].queryStatus = PxBatchQueryStatus::ePENDING; + mDesc.queryMemory.userOverlapResultBuffer[i].hasBlock = false; + mDesc.queryMemory.userOverlapResultBuffer[i].nbTouches = 0; + mDesc.queryMemory.userOverlapResultBuffer[i].touches = NULL; + mDesc.queryMemory.userOverlapResultBuffer[i].userData = NULL; + } + for (PxU32 i = 0; i<mNbSweeps; i++) + { + mDesc.queryMemory.userSweepResultBuffer[i].queryStatus = PxBatchQueryStatus::ePENDING; + mDesc.queryMemory.userSweepResultBuffer[i].hasBlock = false; + mDesc.queryMemory.userSweepResultBuffer[i].nbTouches = 0; + mDesc.queryMemory.userSweepResultBuffer[i].touches = NULL; + mDesc.queryMemory.userSweepResultBuffer[i].userData = NULL; + } +} + +void NpBatchQuery::finalizeExecute() +{ + mPrevOffset = PxU32(eTERMINAL); // reset the first BatchStreamHeader offset + mStream.rewind(); // clear out the executed queries - rewind the data stream so that the query object can be reused + mNbRaycasts = mNbOverlaps = mNbSweeps = 0; // also reset the counts so the query object can be reused + mHasMtdSweep = false; // reset the mtd flag + + Ps::atomicExchange(&mBatchQueryIsRunning, 0); +} + +// fixed memory buffer with extra single hit for overflow detection +template<typename HitType> +struct PxOverflowBuffer : PxHitBuffer<HitType> +{ + bool overflow; + PxU32 saveNbTouches; + HitType extraHit; + HitType* saveTouches; + bool processCalled; + PxOverflowBuffer(HitType* hits, PxU32 count) : PxHitBuffer<HitType>(hits, count), overflow(false), processCalled(false) + { + } + + virtual PxAgain processTouches(const HitType* /*hits*/, PxU32 /*count*/) + { + if (processCalled) + return false; + saveTouches = this->touches; + saveNbTouches = this->nbTouches; + processCalled = true; + this->touches = &extraHit; + this->maxNbTouches = 1; + return true; + } + + virtual void finalizeQuery() + { + if (processCalled) + { + overflow = (this->nbTouches > 0); + this->nbTouches = saveNbTouches; + this->touches = saveTouches; + } + } +}; + +void NpBatchQuery::execute() +{ + NP_READ_CHECK(mNpScene); + + if(mNbRaycasts) + { + PX_CHECK_AND_RETURN(mDesc.queryMemory.userRaycastResultBuffer!=NULL, "PxBatchQuery execute: userRaycastResultBuffer is NULL"); + PX_CHECK_AND_RETURN(mDesc.queryMemory.raycastTouchBufferSize > 0 ? + (mDesc.queryMemory.userRaycastTouchBuffer != NULL) : true, "PxBatchQuery execute: userRaycastTouchBuffer is NULL"); + } + if(mNbOverlaps) + { + PX_CHECK_AND_RETURN(mDesc.queryMemory.userOverlapResultBuffer!=NULL, "PxBatchQuery execute: userOverlapResultBuffer is NULL"); + PX_CHECK_AND_RETURN(mDesc.queryMemory.overlapTouchBufferSize > 0 ? + (mDesc.queryMemory.userOverlapTouchBuffer != NULL) : true, "PxBatchQuery execute: userOverlapTouchBuffer is NULL"); + } + if(mNbSweeps) + { + PX_CHECK_AND_RETURN(mDesc.queryMemory.userSweepResultBuffer!=NULL, "PxBatchQuery execute: userSweepResultBuffer is NULL"); + PX_CHECK_AND_RETURN(mDesc.queryMemory.sweepTouchBufferSize > 0 ? + (mDesc.queryMemory.userSweepTouchBuffer != NULL) : true, "PxBatchQuery execute: userSweepTouchBuffer is NULL"); + } + + PX_SIMD_GUARD; + + PX_PROFILE_ZONE("BatchedSceneQuery.execute", mNpScene->getContextId()); + PxI32 ret = Ps::atomicCompareExchange(&mBatchQueryIsRunning, 1, 0); + if(ret == 1) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxBatchQuery::execute: This batch is already executing"); + return; + } + else if(ret == -1) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxBatchQuery::execute: Another thread is still adding queries to this batch"); + return; + } + + resetResultBuffers(); + + // If PVD is connected and IS_PVD_SQ_ENABLED, record the offsets for queries in pvd buffers and run the queries on PPU + bool isSqCollectorLocked = false; + PX_UNUSED(isSqCollectorLocked); + +#if PX_SUPPORT_PVD + PxU32 pvdRayQstartIdx = 0; + PxU32 pvdOverlapQstartIdx = 0; + PxU32 pvdSweepQstartIdx = 0; + + Vd::ScbScenePvdClient& pvdClient = mNpScene->mScene.getScenePvdClient(); + const bool needUpdatePvd = pvdClient.checkPvdDebugFlag() && (pvdClient.getScenePvdFlags() & PxPvdSceneFlag::eTRANSMIT_SCENEQUERIES); + + if(needUpdatePvd) + { + mNpScene->getBatchedSqCollector().getLock().lock(); + isSqCollectorLocked = true; + + pvdRayQstartIdx = mNpScene->getBatchedSqCollector().mAccumulatedRaycastQueries.size(); + pvdOverlapQstartIdx = mNpScene->getBatchedSqCollector().mAccumulatedOverlapQueries.size(); + pvdSweepQstartIdx = mNpScene->getBatchedSqCollector().mAccumulatedSweepQueries.size(); + } +#endif + + PxClientID clientId = mDesc.ownerClient; + + // setup local pointers to user provided output buffers + PxRaycastHit* raycastHits = mDesc.queryMemory.userRaycastTouchBuffer; PX_UNUSED(raycastHits); + PxRaycastQueryResult* raycastResults = mDesc.queryMemory.userRaycastResultBuffer; PX_UNUSED(raycastResults); + PxU32 raycastHitsSize = mDesc.queryMemory.raycastTouchBufferSize; PX_UNUSED(raycastHitsSize); + + PxOverlapHit* overlapHits = mDesc.queryMemory.userOverlapTouchBuffer; PX_UNUSED(overlapHits); + PxOverlapQueryResult* overlapResults = mDesc.queryMemory.userOverlapResultBuffer; PX_UNUSED(overlapResults); + PxU32 overlapHitsSize = mDesc.queryMemory.overlapTouchBufferSize; PX_UNUSED(overlapHitsSize); + + PxSweepHit* sweepHits = mDesc.queryMemory.userSweepTouchBuffer; PX_UNUSED(sweepHits); + PxSweepQueryResult* sweepResults = mDesc.queryMemory.userSweepResultBuffer; PX_UNUSED(sweepResults); + PxU32 sweepHitsSize = mDesc.queryMemory.sweepTouchBufferSize; PX_UNUSED(sweepHitsSize); + + BatchQueryFilterData bfd(mDesc.filterShaderData, mDesc.filterShaderDataSize, mDesc.preFilterShader, mDesc.postFilterShader); + + // data declarations for double buffering the input stream + PxU32 curQueryOffset = 0; // first query starts at 0 + if (mPrevOffset == eTERMINAL) // except if zero queries were queued + { + finalizeExecute(); + return; + } + + PxU32 hitsSpaceLeft; PX_UNUSED(hitsSpaceLeft); + + // ====================== parse and execute the batch query memory stream ====================== + PxU32 queryCount = 0; + do { + // parse a query from the input stream, create a stream reader at current double buffer + BatchQueryStreamReader reader(mStream.begin()+curQueryOffset); + BatchStreamHeader& h = *reader.read<BatchStreamHeader>(); + if (h.fd.clientId == 0) + h.fd.clientId = clientId; // override a zero clientId with PxBatchQueryDesc.ownerClient + + curQueryOffset = h.nextQueryOffset; + Ps::prefetchLine(mStream.begin() + curQueryOffset); + + MultiQueryInput& input = *readQueryInput(reader); + + // ====================== switch over query type - QTypeROS::eRAYCAST, eOVERLAP, eSWEEP ===================== + switch (h.hitTypeId) + { + // =============== Current query is a raycast ===================== + case QTypeROS::eRAYCAST: + { + PxU32 nbRaycastHits = PxU32(raycastHits - mDesc.queryMemory.userRaycastTouchBuffer); + PX_ASSERT(nbRaycastHits <= raycastHitsSize); + hitsSpaceLeft = raycastHitsSize - nbRaycastHits; + PxOverflowBuffer<PxRaycastHit> hits(raycastHits, PxMin<PxU32>(h.maxTouchHits, hitsSpaceLeft)); + mNpScene->NpScene::multiQuery<PxRaycastHit>(input, hits, h.hitFlags, h.cache, h.fd, NULL, &bfd); + hits.overflow |= (hitsSpaceLeft == 0 && h.maxTouchHits > 0); // report overflow if 0 space left and maxTouchHits>0 + writeStatus<PxRaycastQueryResult, PxRaycastHit>(raycastResults++, hits, h.userData, hits.overflow); + raycastHits += hits.nbTouches; + } break; + + // ================ Current query is an overlap ==================== + case QTypeROS::eOVERLAP: + { + PxU32 nbOverlapHits = PxU32(overlapHits - mDesc.queryMemory.userOverlapTouchBuffer); + PX_ASSERT(nbOverlapHits <= overlapHitsSize); + hitsSpaceLeft = overlapHitsSize - nbOverlapHits; + PxOverflowBuffer<PxOverlapHit> hits(overlapHits, PxMin<PxU32>(h.maxTouchHits, hitsSpaceLeft)); + mNpScene->NpScene::multiQuery<PxOverlapHit>(input, hits, h.hitFlags, h.cache, h.fd, NULL, &bfd); + hits.overflow |= (hitsSpaceLeft == 0 && h.maxTouchHits > 0); // report overflow if 0 space left and maxTouchHits>0 + writeStatus<PxOverlapQueryResult, PxOverlapHit>(overlapResults++, hits, h.userData, hits.overflow); + overlapHits += hits.nbTouches; + } break; + + // ================== Current query is a sweep ========================= + case QTypeROS::eSWEEP: + { + + PxU32 nbSweepHits = PxU32(sweepHits - mDesc.queryMemory.userSweepTouchBuffer); + PX_ASSERT(nbSweepHits <= sweepHitsSize); + hitsSpaceLeft = sweepHitsSize - nbSweepHits; + PxOverflowBuffer<PxSweepHit> hits(sweepHits, PxMin<PxU32>(h.maxTouchHits, hitsSpaceLeft)); + mNpScene->NpScene::multiQuery<PxSweepHit>(input, hits, h.hitFlags, h.cache, h.fd, NULL, &bfd); + hits.overflow |= (hitsSpaceLeft == 0 && h.maxTouchHits > 0); // report overflow if 0 space left and maxTouchHits>0 + writeStatus<PxSweepQueryResult, PxSweepHit>(sweepResults++, hits, h.userData, hits.overflow); + sweepHits += hits.nbTouches; + } break; + default: + PX_ALWAYS_ASSERT_MESSAGE("Unexpected batch query type (raycast/overlap/sweep)."); + } + + if (h.nextQueryOffset == eTERMINAL) // end of stream + // AP: previously also had a break on hitCount==-1 which is aborted due to out of space + // abort stream parsing if we ran into an aborted query (hitCount==-1).. but it was easier to just continue + // the perf implications for aborted queries are not a significant consideration and this allows to avoid + // writing special case code for filling the query buffers after aborted query + break; + #undef MULTIQ + queryCount++; + } while (queryCount < 1000000); + +#if PX_SUPPORT_PVD + if( isSqCollectorLocked && needUpdatePvd) + { + mNpScene->getBatchedSqCollector().collectAllBatchedHits( mDesc.queryMemory.userRaycastResultBuffer, mNbRaycasts, pvdRayQstartIdx, + mDesc.queryMemory.userOverlapResultBuffer, mNbOverlaps, pvdOverlapQstartIdx, + mDesc.queryMemory.userSweepResultBuffer, mNbSweeps, pvdSweepQstartIdx); + } + + // Maybe connection is disconnected after the lock + if( isSqCollectorLocked ) + { + mNpScene->getBatchedSqCollector().getLock().unlock(); + isSqCollectorLocked = false; + } +#endif + + finalizeExecute(); +} + +/////////////////////////////////////////////////////////////////////////////// +void NpBatchQuery::writeBatchHeader(const BatchStreamHeader& h) +{ + PxU32 streamPos = PxU32(mStream.getPos()); // save the stream pos before we write the header + mStream.write<BatchStreamHeader>(h); + // link into a list as offset + PxU32* prevPtr = (mPrevOffset == eTERMINAL) ? &mPrevOffset : reinterpret_cast<PxU32*>(mStream.begin()+mPrevOffset); + PxU32 headerPtr = streamPos+PX_OFFSET_OF(BatchStreamHeader, nextQueryOffset); + *prevPtr = headerPtr; + mPrevOffset = headerPtr; +} + +/////////////////////////////////////////////////////////////////////////////// +void NpBatchQuery::raycast( + const PxVec3& origin, const PxVec3& unitDir, PxReal distance, PxU16 maxTouchHits, + PxHitFlags hitFlags, const PxQueryFilterData& fd, void* userData, const PxQueryCache* cache) +{ + PX_CHECK_AND_RETURN(distance>0, "PxBatchQuery::raycast: The maximum distance must be greater than zero!"); + PX_CHECK_AND_RETURN(unitDir.isNormalized(), "PxBatchQuery::raycast: Direction must be normalized"); + PX_CHECK_AND_RETURN(origin.isFinite(), "PxBatchQuery::raycast: origin is not valid"); + if (mNbRaycasts >= mDesc.queryMemory.getMaxRaycastsPerExecute()) + { + PX_CHECK_AND_RETURN(mNbRaycasts < mDesc.queryMemory.getMaxRaycastsPerExecute(), + "PxBatchQuery: number of raycast() calls exceeds PxBatchQueryMemory::raycastResultBufferSize, query discarded"); + return; + } + CHECK_RUNNING("PxBatchQuery::raycast: This batch is still executing, skipping query."); + mNbRaycasts++; + + writeBatchHeader(BatchStreamHeader(hitFlags, cache, fd, userData, maxTouchHits, QTypeROS::eRAYCAST)); + writeQueryInput(mStream, MultiQueryInput(origin, unitDir, distance)); + + Ps::atomicExchange(&mBatchQueryIsRunning, 0); +} + +/////////////////////////////////////////////////////////////////////////////// +void NpBatchQuery::overlap( + const PxGeometry& geometry, const PxTransform& pose, PxU16 maxTouchHits, + const PxQueryFilterData& fd, void* userData, const PxQueryCache* cache) +{ + PX_CHECK_AND_RETURN(pose.isValid(), "NpBatchQuery::overlapMultiple pose is not valid."); + if (mNbOverlaps >= mDesc.queryMemory.getMaxOverlapsPerExecute()) + { + PX_CHECK_AND_RETURN(mNbOverlaps < mDesc.queryMemory.getMaxOverlapsPerExecute(), + "PxBatchQuery: number of overlap() calls exceeds PxBatchQueryMemory::overlapResultBufferSize, query discarded"); + return; + } + CHECK_RUNNING("PxBatchQuery::overlap: This batch is still executing, skipping query.") + mNbOverlaps++; + + writeBatchHeader(BatchStreamHeader(PxHitFlags(), cache, fd, userData, maxTouchHits, QTypeROS::eOVERLAP)); + writeQueryInput(mStream, MultiQueryInput(&geometry, &pose)); + + Ps::atomicExchange(&mBatchQueryIsRunning, 0); +} + +void NpBatchQuery::sweep( + const PxGeometry& geometry, const PxTransform& pose, const PxVec3& unitDir, const PxReal distance, PxU16 maxTouchHits, + PxHitFlags hitFlags, const PxQueryFilterData& fd, void* userData, const PxQueryCache* cache, const PxReal inflation) +{ + PX_CHECK_AND_RETURN(pose.isValid(), "Batch sweep input check: pose is not valid."); + PX_CHECK_AND_RETURN(unitDir.isFinite(), "Batch sweep input check: unitDir is not valid."); + PX_CHECK_AND_RETURN(unitDir.isNormalized(), "Batch sweep input check: direction must be normalized"); + PX_CHECK_AND_RETURN(distance >= 0.0f, "Batch sweep input check: distance cannot be negative"); + PX_CHECK_AND_RETURN(distance != 0.0f || !(hitFlags & PxHitFlag::eASSUME_NO_INITIAL_OVERLAP), + "Batch sweep input check: zero-length sweep only valid without the PxHitFlag::eASSUME_NO_INITIAL_OVERLAP flag"); + + if (mNbSweeps >= mDesc.queryMemory.getMaxSweepsPerExecute()) + { + PX_CHECK_AND_RETURN(mNbSweeps < mDesc.queryMemory.getMaxSweepsPerExecute(), + "PxBatchQuery: number of sweep() calls exceeds PxBatchQueryMemory::sweepResultBufferSize, query discarded"); + return; + } + + + CHECK_RUNNING("PxBatchQuery::sweep: This batch is still executing, skipping query.") + mNbSweeps++; + + writeBatchHeader(BatchStreamHeader(hitFlags, cache, fd, userData, maxTouchHits, QTypeROS::eSWEEP)); + + //set the MTD flag + mHasMtdSweep |= !!(hitFlags & PxHitFlag::eMTD); + + if((hitFlags & PxHitFlag::ePRECISE_SWEEP) && (hitFlags & PxHitFlag::eMTD)) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, " Precise sweep doesn't support MTD. Perform MTD with default sweep"); + hitFlags &= ~PxHitFlag::ePRECISE_SWEEP; + } + + if((hitFlags & PxHitFlag::eASSUME_NO_INITIAL_OVERLAP) && (hitFlags & PxHitFlag::eMTD)) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, " eMTD cannot be used in conjunction with eASSUME_NO_INITIAL_OVERLAP. eASSUME_NO_INITIAL_OVERLAP will be ignored"); + hitFlags &= ~PxHitFlag::eASSUME_NO_INITIAL_OVERLAP; + } + + PxReal realInflation = inflation; + if((hitFlags & PxHitFlag::ePRECISE_SWEEP)&& inflation > 0.f) + { + realInflation = 0.f; + Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, " Precise sweep doesn't support inflation, inflation will be overwritten to be zero"); + } + + writeQueryInput(mStream, MultiQueryInput(&geometry, &pose, unitDir, distance, realInflation)); + + Ps::atomicExchange(&mBatchQueryIsRunning, 0); +} + +void NpBatchQuery::release() +{ + if(Ps::atomicCompareExchange(&mBatchQueryIsRunning, 0, 0) != 0) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxBatchQuery::release: This batch is still executing, skipping release"); + return; + } + + mNpScene->releaseBatchQuery(this); +} + +PxBatchQueryPreFilterShader NpBatchQuery::getPreFilterShader() const +{ + return mDesc.preFilterShader; +} + +PxBatchQueryPostFilterShader NpBatchQuery::getPostFilterShader() const +{ + return mDesc.postFilterShader; +} + +const void* NpBatchQuery::getFilterShaderData() const +{ + return mDesc.filterShaderData; +} + +PxU32 NpBatchQuery::getFilterShaderDataSize() const +{ + return mDesc.filterShaderDataSize; +} + +PxClientID NpBatchQuery::getOwnerClient() const +{ + return mDesc.ownerClient; +} + + diff --git a/PhysX_3.4/Source/PhysX/src/NpBatchQuery.h b/PhysX_3.4/Source/PhysX/src/NpBatchQuery.h new file mode 100644 index 00000000..7fa45890 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpBatchQuery.h @@ -0,0 +1,167 @@ +// 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_NP_SCENEQUERY +#define PX_PHYSICS_NP_SCENEQUERY +/** \addtogroup physics +@{ */ + +#include "PxBatchQuery.h" +#include "PsArray.h" +#include "PsUserAllocated.h" +#include "CmPhysXCommon.h" +#include "PsSync.h" + +namespace physx +{ + +class NpSceneQueryManager; +struct BatchStreamHeader; +class NpScene; + +namespace Sq +{ +class SceneQueryManager; +} + +struct BatchQueryStream : Ps::Array<char> +{ + BatchQueryStream() { rewind(); } + + void rewind() { mPosition = 0; } + + PX_FORCE_INLINE PxI32 getPos() { return PxI32(mPosition); } // signed to avoid casts elsewhere + + // write an object of type T to the stream, copying by value + template<typename T> + PX_FORCE_INLINE void write(const T* val, PxU32 count = 1) + { + PX_COMPILE_TIME_ASSERT(sizeof(T) > 0); + PxU32 newPosition = mPosition + sizeof(T)*count; + if (newPosition > capacity()) + reserve(newPosition+(newPosition<<1)); + resizeUninitialized(newPosition); + T* dest = reinterpret_cast<T*>(begin() + mPosition); + for (PxU32 i = 0; i < count; i++) + { + *dest = *(val+i); + dest++; + } + mPosition = newPosition; + } + + template<typename T> + PX_FORCE_INLINE void write(const T& val) + { + write(&val, 1); + } + + PX_FORCE_INLINE bool atEnd() const { return mPosition >= size(); } + +protected: + mutable PxU32 mPosition; +}; + +struct BatchQueryStreamReader +{ + BatchQueryStreamReader(char* buffer) : mBuffer(buffer), mReadPos(0) {} + + // read an object of type T from the stream (simply returns a pointer without copying) + template<typename T> + PX_FORCE_INLINE T* read(PxU32 count = 1) + { + //PX_ASSERT(mPosition+sizeof(T)*count <= size()); + T* result = reinterpret_cast<T*>(mBuffer+mReadPos); + mReadPos += sizeof(T)*count; + return result; + } + + char* mBuffer; + PxU32 mReadPos; +}; + +class NpBatchQuery : public PxBatchQuery, public Ps::UserAllocated +{ +public: + NpBatchQuery(NpScene& owner, const PxBatchQueryDesc& d); + virtual ~NpBatchQuery(); + + // PxBatchQuery interface + virtual void execute(); + virtual void release(); + virtual PxBatchQueryPreFilterShader getPreFilterShader() const; + virtual PxBatchQueryPostFilterShader getPostFilterShader() const; + virtual const void* getFilterShaderData() const; + virtual PxU32 getFilterShaderDataSize() const; + virtual PxClientID getOwnerClient() const; + virtual void setUserMemory(const PxBatchQueryMemory& ); + virtual const PxBatchQueryMemory& getUserMemory(); + + virtual void raycast(const PxVec3& origin, const PxVec3& unitDir, PxReal distance, PxU16 maxTouchHits, + PxHitFlags hitFlags, const PxQueryFilterData& filterData, + void* userData, const PxQueryCache* cache); + + virtual void overlap(const PxGeometry& geometry, const PxTransform& pose, PxU16 maxTouchHits, + const PxQueryFilterData& filterData, void* userData, + const PxQueryCache* cache); + + virtual void sweep(const PxGeometry& geometry, const PxTransform& pose, + const PxVec3& unitDir, const PxReal distance, PxU16 maxTouchHits, + PxHitFlags hitFlags, const PxQueryFilterData& filterData, + void* userData, const PxQueryCache* cache, const PxReal inflation); + + PxBatchQueryDesc& getDesc() { return mDesc; } + virtual const PxBatchQueryDesc& getDesc() const { return mDesc; } + + enum { eTERMINAL = PxU32(-16) }; // -16 so it's aligned to avoid SPU checks + + // sync object for batch query completion wait + shdfnd::Sync mSync; +private: + void resetResultBuffers(); + void finalizeExecute(); + void writeBatchHeader(const BatchStreamHeader& h); + + NpScene* mNpScene; + BatchQueryStream mStream; + PxU32 mNbRaycasts, mNbOverlaps, mNbSweeps; + volatile PxI32 mBatchQueryIsRunning; + PxBatchQueryDesc mDesc; + // offset in mStream of the offset to the next query for the last header written by BQ query functions + PxU32 mPrevOffset; + bool mHasMtdSweep; + + friend class physx::Sq::SceneQueryManager; +}; + +} + +/** @} */ +#endif diff --git a/PhysX_3.4/Source/PhysX/src/NpCast.h b/PhysX_3.4/Source/PhysX/src/NpCast.h new file mode 100644 index 00000000..c67370ef --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpCast.h @@ -0,0 +1,124 @@ +// 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_NP_CAST +#define PX_PHYSICS_NP_CAST + +#include "PxPhysXConfig.h" +#include "NpScene.h" +#include "NpRigidDynamic.h" +#include "NpRigidStatic.h" +#include "NpArticulation.h" +#include "NpArticulationLink.h" +#include "NpArticulationJoint.h" +#include "NpAggregate.h" +#if PX_USE_PARTICLE_SYSTEM_API + #include "NpParticleFluid.h" +#endif +#if PX_USE_CLOTH_API + #include "NpCloth.h" +#endif + +namespace physx +{ + // PT: Scb-to-Np casts + + PX_FORCE_INLINE const NpScene* getNpScene(const Scb::Scene* scene) + { + const size_t scbOffset = reinterpret_cast<size_t>(&(reinterpret_cast<NpScene*>(0)->getScene())); + return reinterpret_cast<const NpScene*>(reinterpret_cast<const char*>(scene) - scbOffset); + } + + PX_FORCE_INLINE const NpRigidDynamic* getNpRigidDynamic(const Scb::Body* scbBody) + { + const size_t offset = reinterpret_cast<size_t>(&(reinterpret_cast<NpRigidDynamic*>(0)->getScbActorFast())); + return reinterpret_cast<const NpRigidDynamic*>(reinterpret_cast<const char*>(scbBody) - offset); + } + + PX_FORCE_INLINE const NpRigidStatic* getNpRigidStatic(const Scb::RigidStatic* scbRigidStatic) + { + const size_t offset = reinterpret_cast<size_t>(&(reinterpret_cast<NpRigidStatic*>(0)->getScbActorFast())); + return reinterpret_cast<const NpRigidStatic*>(reinterpret_cast<const char*>(scbRigidStatic) - offset); + } + + PX_FORCE_INLINE const NpShape* getNpShape(const Scb::Shape* scbShape) + { + const size_t offset = reinterpret_cast<size_t>(&(reinterpret_cast<NpShape*>(0)->getScbShape())); + return reinterpret_cast<const NpShape*>(reinterpret_cast<const char*>(scbShape) - offset); + } + + PX_FORCE_INLINE const NpArticulationLink* getNpArticulationLink(const Scb::Body* scbArticulationLink) + { + const size_t offset = reinterpret_cast<size_t>(&(reinterpret_cast<NpArticulationLink*>(0)->getScbActorFast())); + return reinterpret_cast<const NpArticulationLink*>(reinterpret_cast<const char*>(scbArticulationLink) - offset); + } + + PX_FORCE_INLINE const NpArticulation* getNpArticulation(const Scb::Articulation* scbArticulation) + { + const size_t offset = reinterpret_cast<size_t>(&(reinterpret_cast<NpArticulation*>(0)->getArticulation())); + return reinterpret_cast<const NpArticulation*>(reinterpret_cast<const char*>(scbArticulation) - offset); + } + + PX_FORCE_INLINE const NpArticulationJoint* getNpArticulationJoint(const Scb::ArticulationJoint* scbArticulationJoint) + { + const size_t offset = reinterpret_cast<size_t>(&(reinterpret_cast<NpArticulationJoint*>(0)->getScbArticulationJoint())); + return reinterpret_cast<const NpArticulationJoint*>(reinterpret_cast<const char*>(scbArticulationJoint) - offset); + } + + PX_FORCE_INLINE const NpAggregate* getNpAggregate(const Scb::Aggregate* aggregate) + { + const size_t offset = reinterpret_cast<size_t>(&(reinterpret_cast<NpAggregate*>(0)->getScbAggregate())); + return reinterpret_cast<const NpAggregate*>(reinterpret_cast<const char*>(aggregate) - offset); + } + +#if PX_USE_PARTICLE_SYSTEM_API + PX_FORCE_INLINE const NpParticleSystem* getNpParticleSystem(const Scb::ParticleSystem* scbParticleSystem) + { + const size_t offset = reinterpret_cast<size_t>(&(reinterpret_cast<NpParticleSystem*>(0)->getScbParticleSystem())); + return reinterpret_cast<const NpParticleSystem*>(reinterpret_cast<const char*>(scbParticleSystem) - offset); + } + + PX_FORCE_INLINE const NpParticleFluid* getNpParticleFluid(const Scb::ParticleSystem* scbParticleSystem) + { + const size_t offset = reinterpret_cast<size_t>(&(reinterpret_cast<NpParticleFluid*>(0)->getScbParticleSystem())); + return reinterpret_cast<const NpParticleFluid*>(reinterpret_cast<const char*>(scbParticleSystem) - offset); + } +#endif + +#if PX_USE_CLOTH_API + PX_FORCE_INLINE const NpCloth* getNpCloth(const Scb::Cloth* cloth) + { + const size_t offset = reinterpret_cast<size_t>(&(reinterpret_cast<NpCloth*>(0)->getScbCloth())); + return reinterpret_cast<const NpCloth*>(reinterpret_cast<const char*>(cloth) - offset); + } +#endif + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/NpConnector.h b/PhysX_3.4/Source/PhysX/src/NpConnector.h new file mode 100644 index 00000000..465b0967 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpConnector.h @@ -0,0 +1,135 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + + +#ifndef PX_PHYSICS_NP_CONNECTOR +#define PX_PHYSICS_NP_CONNECTOR + +#include "CmPhysXCommon.h" +#include "PsInlineArray.h" +#include "PxSerialFramework.h" +#include "CmUtils.h" +#include "PsUtilities.h" + +namespace physx +{ + +struct NpConnectorType +{ + enum Enum + { + eConstraint, + eAggregate, + eObserver, + eInvalid + }; +}; + + +class NpConnector +{ +//= 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: + NpConnector() : mType(NpConnectorType::eInvalid), mObject(NULL) {} + NpConnector(NpConnectorType::Enum type, PxBase* object) : mType(Ps::to8(type)), mObject(object) {} +// PX_SERIALIZATION + NpConnector(const NpConnector& c) + { + //special copy constructor that initializes padding bytes for meta data verification (PX_CHECKED only) + Cm::markSerializedMem(this, sizeof(NpConnector)); + mType = c.mType; + mObject = c.mObject; + } + + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + + PxU8 mType; // Revisit whether the type is really necessary or whether the serializable type is enough. + // Since joints might gonna inherit from observers to register for constraint release events, the type + // is necessary because a joint has its own serializable type and could not be detected as observer anymore. + PxU8 mPadding[3]; // PT: padding from prev byte + PxBase* mObject; // So far the serialization framework only supports ptr resolve for PxBase objects. + // However, so far the observers all are PxBase, hence this choice of type. +}; + + +class NpConnectorIterator +{ +public: + PX_FORCE_INLINE NpConnectorIterator(NpConnector* c, PxU32 size, NpConnectorType::Enum type) : mConnectors(c), mSize(size), mIndex(0), mType(type) {} + + PX_FORCE_INLINE PxBase* getNext() + { + PxBase* s = NULL; + while(mIndex < mSize) + { + NpConnector& c = mConnectors[mIndex]; + mIndex++; + if (c.mType == mType) + return c.mObject; + } + return s; + } + +private: + NpConnector* mConnectors; + PxU32 mSize; + PxU32 mIndex; + NpConnectorType::Enum mType; +}; + + +class NpConnectorArray: public Ps::InlineArray<NpConnector, 4> +{ +//= 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 + NpConnectorArray(const PxEMPTY) : Ps::InlineArray<NpConnector, 4> (PxEmpty) {} + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + NpConnectorArray() : Ps::InlineArray<NpConnector, 4>(PX_DEBUG_EXP("connectorArray")) + { + //special default constructor that initializes padding bytes for meta data verification (PX_CHECKED only) + Cm::markSerializedMem(this->mData, 4*sizeof(NpConnector)); + } +}; + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/NpConstraint.cpp b/PhysX_3.4/Source/PhysX/src/NpConstraint.cpp new file mode 100644 index 00000000..798d13b0 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpConstraint.cpp @@ -0,0 +1,408 @@ +// 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 "PxConstraint.h" +#include "NpConstraint.h" +#include "NpPhysics.h" +#include "NpRigidDynamic.h" +#include "NpRigidStatic.h" +#include "NpArticulationLink.h" +#include "ScbConstraint.h" +#include "ScbNpDeps.h" + +using namespace physx; + +void NpConstraint::setConstraintFunctions(PxConstraintConnector& n, const PxConstraintShaderTable& shaders) +{ + mConstraint.getScConstraint().setConstraintFunctions(n, shaders); + + //update mConnectorArray, since mActor0 or mActor1 should be in external reference + bool bNeedUpdate = false; + if(mActor0) + { + NpActor& npActor = NpActor::getFromPxActor(*mActor0); + if(npActor.findConnector(NpConnectorType::eConstraint, this) == 0xffffffff) + { + bNeedUpdate = true; + npActor.addConnector(NpConnectorType::eConstraint, this, "PxConstraint: Add to rigid actor 0: Constraint already added"); + } + } + + if(mActor1) + { + NpActor& npActor = NpActor::getFromPxActor(*mActor1); + if(npActor.findConnector(NpConnectorType::eConstraint, this) == 0xffffffff) + { + bNeedUpdate = true; + npActor.addConnector(NpConnectorType::eConstraint, this, "PxConstraint: Add to rigid actor 1: Constraint already added"); + } + } + + if(bNeedUpdate) + { + NpScene* newScene = getSceneFromActors(mActor0, mActor1); + NpScene* oldScene = getNpScene(); + + if (oldScene != newScene) + { + if (oldScene) + { + oldScene->removeFromConstraintList(*this); + oldScene->getScene().removeConstraint(getScbConstraint()); + } + if (newScene) + { + newScene->addToConstraintList(*this); + newScene->getScene().addConstraint(getScbConstraint()); + } + } + } +} + +NpConstraint::NpConstraint(PxRigidActor* actor0, PxRigidActor* actor1, PxConstraintConnector& connector, const PxConstraintShaderTable& shaders, PxU32 dataSize) +: PxConstraint(PxConcreteType::eCONSTRAINT, PxBaseFlag::eOWNS_MEMORY) +, mActor0 (actor0) +, mActor1 (actor1) +, mConstraint (connector, shaders, dataSize) +, mIsDirty (true) +{ + + mConstraint.setFlags(shaders.flag); + if(actor0) + NpActor::getFromPxActor(*actor0).addConnector(NpConnectorType::eConstraint, this, "PxConstraint: Add to rigid actor 0: Constraint already added"); + if(actor1) + NpActor::getFromPxActor(*actor1).addConnector(NpConnectorType::eConstraint, this, "PxConstraint: Add to rigid actor 1: Constraint already added"); + + NpScene* s = getSceneFromActors(actor0, actor1); + if (s) + { + s->addToConstraintList(*this); + s->getScene().addConstraint(mConstraint); + } +} + + +NpConstraint::~NpConstraint() +{ + if(getBaseFlags()&PxBaseFlag::eOWNS_MEMORY) + mConstraint.getPxConnector()->onConstraintRelease(); + + NpFactory::getInstance().onConstraintRelease(this); +} + +void NpConstraint::release() +{ + NpScene* npScene = getNpScene(); + NP_WRITE_CHECK(npScene); + + NpPhysics::getInstance().notifyDeletionListenersUserRelease(this, NULL); + + if(mActor0) + NpActor::getFromPxActor(*mActor0).removeConnector(*mActor0, NpConnectorType::eConstraint, this, "PxConstraint: Add to rigid actor 0: Constraint already added"); + if(mActor1) + NpActor::getFromPxActor(*mActor1).removeConnector(*mActor1, NpConnectorType::eConstraint, this, "PxConstraint: Add to rigid actor 1: Constraint already added"); + + if (npScene) + { + npScene->removeFromConstraintList(*this); + npScene->getScene().removeConstraint(getScbConstraint()); + } + + mConstraint.destroy(); +} + +// PX_SERIALIZATION +void NpConstraint::resolveReferences(PxDeserializationContext& context) +{ + context.translatePxBase(mActor0); + context.translatePxBase(mActor1); +} + +NpConstraint* NpConstraint::createObject(PxU8*& address, PxDeserializationContext& context) +{ + NpConstraint* obj = new (address) NpConstraint(PxBaseFlags(0)); + address += sizeof(NpConstraint); + obj->importExtraData(context); + obj->resolveReferences(context); + return obj; +} + +// ~PX_SERIALIZATION + +PxScene* NpConstraint::getScene() const +{ + return getNpScene(); +} + +void NpConstraint::getActors(PxRigidActor*& actor0, PxRigidActor*& actor1) const +{ + NP_READ_CHECK(getNpScene()); + actor0 = mActor0; + actor1 = mActor1; +} + +void NpConstraint::setActors(PxRigidActor* actor0, PxRigidActor* actor1) +{ + NP_WRITE_CHECK(getNpScene()); + + PX_CHECK_AND_RETURN((actor0 && !actor0->is<PxRigidStatic>()) || (actor1 && !actor1->is<PxRigidStatic>()), "PxConstraint: at least one actor must be non-static"); + PX_SIMD_GUARD; + + if(mActor0) + NpActor::getFromPxActor(*mActor0).removeConnector(*mActor0, NpConnectorType::eConstraint, this, "PxConstraint: Add to rigid actor 0: Constraint already added"); + if(mActor1) + NpActor::getFromPxActor(*mActor1).removeConnector(*mActor1, NpConnectorType::eConstraint, this, "PxConstraint: Add to rigid actor 1: Constraint already added"); + + if(actor0) + NpActor::getFromPxActor(*actor0).addConnector(NpConnectorType::eConstraint, this, "PxConstraint: Add to rigid actor 0: Constraint already added"); + if(actor1) + NpActor::getFromPxActor(*actor1).addConnector(NpConnectorType::eConstraint, this, "PxConstraint: Add to rigid actor 1: Constraint already added"); + + mActor0 = actor0; + mActor1 = actor1; + + NpScene* newScene = getSceneFromActors(actor0, actor1); + NpScene* oldScene = getNpScene(); + + if (oldScene != newScene) + { + if (oldScene) + { + oldScene->removeFromConstraintList(*this); + oldScene->getScene().removeConstraint(getScbConstraint()); + } + + getScbConstraint().setBodies(getScbRigidObject(actor0), getScbRigidObject(actor1)); + + if (newScene) + { + newScene->addToConstraintList(*this); + newScene->getScene().addConstraint(getScbConstraint()); + } + } + else + getScbConstraint().setBodies(getScbRigidObject(actor0), getScbRigidObject(actor1)); +} + +void NpConstraint::markDirty() +{ + mIsDirty = true; +} + +void NpConstraint::setFlags(PxConstraintFlags flags) +{ + NP_WRITE_CHECK(getNpScene()); + // check for eBROKEN which is a read only flag + PX_CHECK_AND_RETURN(!(flags & PxConstraintFlag::eBROKEN), "PxConstraintFlag::eBROKEN is a read only flag"); + + PX_CHECK_AND_RETURN(!(flags & PxConstraintFlag::eGPU_COMPATIBLE), "PxConstraintFlag::eGPU_COMPATIBLE is an internal flag and is illegal to set via the API"); + + PX_SIMD_GUARD; + + mConstraint.setFlags(flags); +} + +PxConstraintFlags NpConstraint::getFlags() const +{ + NP_READ_CHECK(getNpScene()); + return mConstraint.getFlags(); +} + + +void NpConstraint::setFlag(PxConstraintFlag::Enum flag, bool value) +{ + NP_WRITE_CHECK(getNpScene()); + + // check for eBROKEN which is a read only flag + PX_CHECK_AND_RETURN(flag != PxConstraintFlag::eBROKEN, "PxConstraintFlag::eBROKEN is a read only flag"); + + PX_CHECK_AND_RETURN(flag != PxConstraintFlag::eGPU_COMPATIBLE, "PxConstraintFlag::eGPU_COMPATIBLE is an internal flag and is illegal to set via the API"); + + PX_SIMD_GUARD; + + PxConstraintFlags f = mConstraint.getFlags(); + + mConstraint.setFlags(value ? f|flag : f&~flag); +} + + +void NpConstraint::getForce(PxVec3& linear, PxVec3& angular) const +{ + NP_READ_CHECK(getNpScene()); + mConstraint.getForce(linear, angular); +} + +void NpConstraint::updateConstants() +{ + if(!mIsDirty) + return; + + //ML - we can't just set dirty to false because this fails with constraints that were created while the scene was buffering! + if(mConstraint.updateConstants(mConstraint.getPxConnector()->prepareData())) + mIsDirty = false; +#if PX_SUPPORT_PVD + Scb::Scene* scbScene = mConstraint.getScbSceneForAPI(); + //Changed to use the visual scenes update system which respects + //the debugger's connection type flag. + if( scbScene && !scbScene->isPhysicsBuffering() ) + scbScene->getScenePvdClient().updatePvdProperties( &mConstraint ); +#endif +} + +void NpConstraint::setBreakForce(PxReal linear, PxReal angular) +{ + NP_WRITE_CHECK(getNpScene()); + PX_SIMD_GUARD; + mConstraint.setBreakForce(linear, angular); +} + +void NpConstraint::getBreakForce(PxReal& linear, PxReal& angular) const +{ + NP_READ_CHECK(getNpScene()); + PX_SIMD_GUARD; + mConstraint.getBreakForce(linear, angular); +} + + +void NpConstraint::setMinResponseThreshold(PxReal threshold) +{ + PX_CHECK_AND_RETURN(PxIsFinite(threshold) && threshold>=0, "PxConstraint::setMinResponseThreshold: threshold must be non-negative"); + NP_WRITE_CHECK(getNpScene()); + PX_SIMD_GUARD; + mConstraint.setMinResponseThreshold(threshold); +} + +PxReal NpConstraint::getMinResponseThreshold() const +{ + NP_READ_CHECK(getNpScene()); + PX_SIMD_GUARD; + return mConstraint.getMinResponseThreshold(); +} + + +bool NpConstraint::isValid() const +{ + NP_READ_CHECK(getNpScene()); + bool isValid0 = mActor0 && !mActor0->is<PxRigidStatic>(); + bool isValid1 = mActor1 && !mActor1->is<PxRigidStatic>(); + return isValid0 || isValid1; +} + +void* NpConstraint::getExternalReference(PxU32& typeID) +{ + NP_READ_CHECK(getNpScene()); + PxConstraintConnector* connector = mConstraint.getPxConnector(); + return connector->getExternalReference(typeID); +} + +void NpConstraint::comShift(PxRigidActor* actor) +{ + PX_ASSERT(actor == mActor0 || actor == mActor1); + PxConstraintConnector* connector = mConstraint.getPxConnector(); + if(actor == mActor0) + connector->onComShift(0); + if(actor == mActor1) + connector->onComShift(1); +} + +void NpConstraint::actorDeleted(PxRigidActor* actor) +{ + // the actor cannot be deleted without also removing it from the scene, + // which means that the joint will also have been removed from the scene, + // so we can just reset the actor here. + PX_ASSERT(actor == mActor0 || actor == mActor1); + + if(actor == mActor0) + mActor0 = 0; + else + mActor1 = 0; +} + + + +NpScene* NpConstraint::getNpScene() const +{ + return mConstraint.getScbSceneForAPI() ? static_cast<NpScene*>(mConstraint.getScbSceneForAPI()->getPxScene()) : NULL; +} + +Scb::RigidObject* NpConstraint::getScbRigidObject(PxRigidActor* a) +{ + if(!a) + return NULL; + + PxType type = a->getConcreteType(); + + if (type == PxConcreteType::eRIGID_DYNAMIC) + return &(static_cast<NpRigidDynamic*>(a)->getScbBodyFast()); + else if (type == PxConcreteType::eARTICULATION_LINK) + return &(static_cast<NpArticulationLink*>(a)->getScbBodyFast()); + else + { + PX_ASSERT(type == PxConcreteType::eRIGID_STATIC); + return &(static_cast<NpRigidStatic*>(a)->getScbRigidStaticFast()); + } +} + +void physx::NpConstraintGetRigidObjectsFromScb(const Scb::Constraint&c, Scb::RigidObject*&b0, Scb::RigidObject*&b1) +{ + const size_t offset = size_t(&(reinterpret_cast<NpConstraint*>(0)->getScbConstraint())); + const NpConstraint* np = reinterpret_cast<const NpConstraint*>(reinterpret_cast<const char*>(&c)-offset); + + PxRigidActor* a0, * a1; + np->getActors(a0, a1); + b0 = NpConstraint::getScbRigidObject(a0); + b1 = NpConstraint::getScbRigidObject(a1); +} + +NpScene* NpConstraint::getSceneFromActors() const +{ + return getSceneFromActors(mActor0, mActor1); +} + +PX_FORCE_INLINE NpScene* NpConstraint::getSceneFromActors(const PxRigidActor* actor0, const PxRigidActor* actor1) +{ + NpScene* s0 = NULL; + NpScene* s1 = NULL; + + if (actor0 && (!(actor0->getActorFlags() & PxActorFlag::eDISABLE_SIMULATION))) + s0 = static_cast<NpScene*>(actor0->getScene()); + if (actor1 && (!(actor1->getActorFlags() & PxActorFlag::eDISABLE_SIMULATION))) + s1 = static_cast<NpScene*>(actor1->getScene()); + +#if PX_CHECKED + if ((s0 && s1) && (s0 != s1)) + Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "Adding constraint to scene: Actors belong to different scenes, undefined behavior expected!"); +#endif + + if ((!actor0 || s0) && (!actor1 || s1)) + return s0 ? s0 : s1; + else + return NULL; +} diff --git a/PhysX_3.4/Source/PhysX/src/NpConstraint.h b/PhysX_3.4/Source/PhysX/src/NpConstraint.h new file mode 100644 index 00000000..b8680a77 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpConstraint.h @@ -0,0 +1,131 @@ +// 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_NP_CONSTRAINT +#define PX_PHYSICS_NP_CONSTRAINT + +#include "PsUserAllocated.h" +#include "PxConstraint.h" +#include "ScbConstraint.h" + +namespace physx +{ + +class NpScene; +class NpRigidDynamic; + +namespace Scb +{ + class RigidObject; +} + +class NpConstraint : public PxConstraint, public Ps::UserAllocated +{ +//= ATTENTION! ===================================================================================== +// Changing the data layout of this class breaks the binary serialization format. See comments for +// PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData +// function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION +// accordingly. +//================================================================================================== +public: +// PX_SERIALIZATION + NpConstraint(PxBaseFlags baseFlags) : PxConstraint(baseFlags), mConstraint(PxEmpty) {} + virtual void setConstraintFunctions(PxConstraintConnector& n, + const PxConstraintShaderTable &t); + static NpConstraint* createObject(PxU8*& address, PxDeserializationContext& context); + static void getBinaryMetaData(PxOutputStream& stream); + void exportExtraData(PxSerializationContext&) {} + void importExtraData(PxDeserializationContext&) { } + void resolveReferences(PxDeserializationContext& context); + virtual void requires(PxProcessPxBaseCallback&){} + virtual bool isSubordinate() const { return true; } +//~PX_SERIALIZATION + NpConstraint(PxRigidActor* actor0, PxRigidActor* actor1, PxConstraintConnector& connector, const PxConstraintShaderTable& shaders, PxU32 dataSize); + ~NpConstraint(); + + virtual void release(); + + virtual PxScene* getScene() const; + + virtual void getActors(PxRigidActor*& actor0, PxRigidActor*& actor1) const; + virtual void setActors(PxRigidActor* actor0, PxRigidActor* actor1); + + virtual PxConstraintFlags getFlags() const; + virtual void setFlags(PxConstraintFlags flags); + virtual void setFlag(PxConstraintFlag::Enum flag, bool value); + + virtual void getForce(PxVec3& linear, PxVec3& angular) const; + + virtual void markDirty(); + + virtual void setBreakForce(PxReal linear, PxReal angular); + virtual void getBreakForce(PxReal& linear, PxReal& angular) const; + + virtual void setMinResponseThreshold(PxReal threshold); + virtual PxReal getMinResponseThreshold() const; + + virtual bool isValid() const; + + virtual void* getExternalReference(PxU32& typeID); + + void initialize(const PxConstraintDesc&, Scb::Constraint*); + void updateConstants(); + void comShift(PxRigidActor*); + void actorDeleted(PxRigidActor*); + + + + NpScene* getNpScene() const; + + NpScene* getSceneFromActors() const; + PX_FORCE_INLINE Scb::Constraint& getScbConstraint() { return mConstraint; } + PX_FORCE_INLINE const Scb::Constraint& getScbConstraint() const { return mConstraint; } + PX_FORCE_INLINE bool isDirty() const { return mIsDirty; } + + + static Scb::RigidObject* getScbRigidObject(PxRigidActor*); +private: + PX_FORCE_INLINE static NpScene* getSceneFromActors(const PxRigidActor* actor0, const PxRigidActor* actor1); // Returns the scene if both actors are in the scene, else NULL + + PxRigidActor* mActor0; + PxRigidActor* mActor1; + Scb::Constraint mConstraint; + + // this used to be stored in Scb, but that doesn't really work since Scb::Constraint's + // flags all get cleared on fetchResults. In any case, in order to support O(1) + // insert/remove this really wants to be an index into NpScene's dirty joint array + + bool mIsDirty; + bool mPaddingFromBool[3]; // PT: because of mIsDirty +}; + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/NpFactory.cpp b/PhysX_3.4/Source/PhysX/src/NpFactory.cpp new file mode 100644 index 00000000..bd026191 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpFactory.cpp @@ -0,0 +1,1256 @@ +// 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 "NpFactory.h" +#include "NpPhysics.h" +#include "ScPhysics.h" +#include "ScbScene.h" +#include "ScbActor.h" +#include "GuHeightField.h" +#include "GuTriangleMesh.h" +#include "GuConvexMesh.h" + +#if PX_USE_PARTICLE_SYSTEM_API + #include "NpParticleSystem.h" +#endif + +#if PX_USE_CLOTH_API + #include "NpClothFabric.h" + #include "PxClothCollisionData.h" +#endif + +#include "NpConnector.h" +#include "NpPtrTableStorageManager.h" +#include "CmCollection.h" + +using namespace physx; + +NpFactory::NpFactory() +: GuMeshFactory() +, mConnectorArrayPool(PX_DEBUG_EXP("connectorArrayPool")) +, mPtrTableStorageManager(PX_NEW(NpPtrTableStorageManager)) +, mMaterialPool(PX_DEBUG_EXP("MaterialPool")) +#if PX_USE_CLOTH_API + , mClothFabricArray(PX_DEBUG_EXP("clothFabricArray")) +#endif +#if PX_SUPPORT_PVD + , mNpFactoryListener(NULL) +#endif +{ +} + +namespace +{ + template <typename T> void releaseAll(Ps::HashSet<T*>& container) + { + // a bit tricky: release will call the factory back to remove the object from + // the tracking array, immediately evaluating the iterator. Reconstructing the + // iterator per delete can be expensive. So, we use a temporary object. + // + // a coalesced hash would be efficient too, but we only ever iterate over it + // here so it's not worth the 2x remove penalty over the normal hash. + + Ps::Array<T*, Ps::ReflectionAllocator<T*> > tmp; + tmp.reserve(container.size()); + for(typename Ps::HashSet<T*>::Iterator iter = container.getIterator(); !iter.done(); ++iter) + tmp.pushBack(*iter); + + PX_ASSERT(tmp.size() == container.size()); + for(PxU32 i=0;i<tmp.size();i++) + tmp[i]->release(); + } +} + + + +NpFactory::~NpFactory() +{ + PX_DELETE(mPtrTableStorageManager); +} + + +void NpFactory::release() +{ + releaseAll(mAggregateTracking); + releaseAll(mConstraintTracking); + releaseAll(mArticulationTracking); + releaseAll(mActorTracking); + while(mShapeTracking.size()) + static_cast<NpShape*>(mShapeTracking.getEntries()[0])->releaseInternal(); + +#if PX_USE_CLOTH_API + while(mClothFabricArray.size()) + { + mClothFabricArray[0]->release(); + } +#endif + + GuMeshFactory::release(); // deletes the class +} + +void NpFactory::createInstance() +{ + PX_ASSERT(!mInstance); + mInstance = PX_NEW(NpFactory)(); +} + + +void NpFactory::destroyInstance() +{ + PX_ASSERT(mInstance); + mInstance->release(); + mInstance = NULL; +} + + +NpFactory* NpFactory::mInstance = NULL; + +/////////////////////////////////////////////////////////////////////////////// + +namespace +{ + template <typename T> void addToTracking(Ps::HashSet<T*>& set, T* element, Ps::Mutex& mutex, bool lock=true) + { + if(!element) + return; + + if(lock) + mutex.lock(); + + set.insert(element); + + if(lock) + mutex.unlock(); + } +} + +/////////////////////////////////////////////////////////////////////////////// Actors + +void NpFactory::addRigidStatic(PxRigidStatic* npActor, bool lock) +{ + addToTracking<PxActor>(mActorTracking, npActor, mTrackingMutex, lock); +} + +void NpFactory::addRigidDynamic(PxRigidDynamic* npBody, bool lock) +{ + addToTracking<PxActor>(mActorTracking, npBody, mTrackingMutex, lock); +} + +void NpFactory::addShape(PxShape* shape, bool lock) +{ + // this uses a coalesced hash set rather than a normal hash set so that we can iterate over it efficiently + if(!shape) + return; + + if(lock) + mTrackingMutex.lock(); + + mShapeTracking.insert(shape); + + if(lock) + mTrackingMutex.unlock(); +} + + +#if PX_USE_PARTICLE_SYSTEM_API + +namespace +{ + NpParticleSystem* createParticleSystem(PxU32 maxParticles, bool perParticleRestOffset) + { + return NpFactory::getInstance().createNpParticleSystem(maxParticles, perParticleRestOffset); + } + + NpParticleFluid* createParticleFluid(PxU32 maxParticles, bool perParticleRestOffset) + { + return NpFactory::getInstance().createNpParticleFluid(maxParticles, perParticleRestOffset); + } + + // pointers to function above, initialized during subsystem registration + NpParticleSystem* (*sCreateParticleSystemFn)(PxU32 maxParticles, bool perParticleRestOffset) = 0; + NpParticleFluid* (*sCreateParticleFluidFn)(PxU32 maxParticles, bool perParticleRestOffset) = 0; +} + +void NpFactory::registerParticles() +{ + sCreateParticleSystemFn = &::createParticleSystem; + sCreateParticleFluidFn = &::createParticleFluid; +} + +void NpFactory::addParticleSystem(PxParticleSystem* ps, bool lock) +{ + addToTracking<PxActor>(mActorTracking, ps, mTrackingMutex, lock); +} + +void NpFactory::addParticleFluid(PxParticleFluid* fluid, bool lock) +{ + addToTracking<PxActor>(mActorTracking, fluid, mTrackingMutex, lock); +} + +NpParticleSystem* NpFactory::createNpParticleSystem(PxU32 maxParticles, bool perParticleRestOffset) +{ + NpParticleSystem* npParticleSystem; + { + Ps::Mutex::ScopedLock lock(mParticleSystemPoolLock); + npParticleSystem = mParticleSystemPool.construct(maxParticles, perParticleRestOffset); + } + return npParticleSystem; +} + +void NpFactory::releaseParticleSystemToPool(NpParticleSystem& particleSystem) +{ + PX_ASSERT(particleSystem.getBaseFlags() & PxBaseFlag::eOWNS_MEMORY); + Ps::Mutex::ScopedLock lock(mParticleSystemPoolLock); + mParticleSystemPool.destroy(&particleSystem); +} + +NpParticleFluid* NpFactory::createNpParticleFluid(PxU32 maxParticles, bool perParticleRestOffset) +{ + NpParticleFluid* npParticleFluid; + { + Ps::Mutex::ScopedLock lock(mParticleFluidPoolLock); + npParticleFluid = mParticleFluidPool.construct(maxParticles, perParticleRestOffset); + } + return npParticleFluid; +} + +void NpFactory::releaseParticleFluidToPool(NpParticleFluid& particleFluid) +{ + PX_ASSERT(particleFluid.getBaseFlags() & PxBaseFlag::eOWNS_MEMORY); + Ps::Mutex::ScopedLock lock(mParticleFluidPoolLock); + mParticleFluidPool.destroy(&particleFluid); +} + +PxParticleFluid* NpFactory::createParticleFluid(PxU32 maxParticles, bool perParticleRestOffset) +{ + if (!sCreateParticleFluidFn) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, + "Particle fluid creation failed. Use PxRegisterParticles to register particle module: returned NULL."); + return NULL; + } + + PxParticleFluid* fluid = sCreateParticleFluidFn(maxParticles, perParticleRestOffset); + if (!fluid) + { + Ps::getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __LINE__, + "Particle fluid initialization failed: returned NULL."); + return NULL; + } + + addParticleFluid(fluid); + return fluid; +} + +PxParticleSystem* NpFactory::createParticleSystem(PxU32 maxParticles, bool perParticleRestOffset) +{ + if (!sCreateParticleSystemFn) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, + "Particle system creation failed. Use PxRegisterParticles to register particle module: returned NULL."); + return NULL; + } + + PxParticleSystem* ps = sCreateParticleSystemFn(maxParticles, perParticleRestOffset); + if (!ps) + { + Ps::getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __LINE__, + "Particle system initialization failed: returned NULL."); + return NULL; + } + + addParticleSystem(ps); + return ps; +} + +#endif + + +#if PX_USE_CLOTH_API + +namespace +{ + NpCloth* createCloth(const PxTransform& globalPose, PxClothFabric& fabric, const PxClothParticle* particles, PxClothFlags flags) + { + return NpFactory::getInstance().createNpCloth(globalPose, static_cast<NpClothFabric&>(fabric), particles, flags); + } + + NpClothFabric* createClothFabric(PxInputStream& stream) + { + NpClothFabric* fabric = NpFactory::getInstance().createNpClothFabric(); + if(fabric) + { + if(fabric->load(stream)) + return fabric; + fabric->decRefCount(); + } + return NULL; + } + + NpClothFabric* createClothFabric(const PxClothFabricDesc& desc) + { + NpClothFabric* fabric = NpFactory::getInstance().createNpClothFabric(); + if(fabric) + { + if(fabric->load(desc)) + return fabric; + fabric->decRefCount(); + } + return NULL; + } + + // pointers to functions above, initialized during subsystem registration + NpCloth* (*sCreateClothFn)(const PxTransform&, PxClothFabric&, const PxClothParticle*, PxClothFlags) = 0; + NpClothFabric* (*sCreateClothFabricFromStreamFn)(PxInputStream&) = 0; + NpClothFabric* (*sCreateClothFabricFromDescFn)(const PxClothFabricDesc&) = 0; +} + +void NpFactory::registerCloth() +{ + sCreateClothFn = &::createCloth; + sCreateClothFabricFromStreamFn = &::createClothFabric; + sCreateClothFabricFromDescFn = &::createClothFabric; + + Sc::Physics::getInstance().registerCloth(); +} + +void NpFactory::addCloth(PxCloth* cloth, bool lock) +{ + addToTracking<PxActor>(mActorTracking, cloth, mTrackingMutex, lock); +} + +NpCloth* NpFactory::createNpCloth(const PxTransform& globalPose, PxClothFabric& fabric, const PxClothParticle* particles, PxClothFlags flags) +{ + NpCloth* npCloth; + { + Ps::Mutex::ScopedLock lock(mClothPoolLock); + npCloth = mClothPool.construct(globalPose, static_cast<NpClothFabric&>(fabric), particles, flags); + } + return npCloth; +} + +void NpFactory::releaseClothToPool(NpCloth& cloth) +{ + PX_ASSERT(cloth.getBaseFlags() & PxBaseFlag::eOWNS_MEMORY); + Ps::Mutex::ScopedLock lock(mClothPoolLock); + mClothPool.destroy(&cloth); +} + +NpClothFabric* NpFactory::createNpClothFabric() +{ + NpClothFabric* npClothFabric; + { + Ps::Mutex::ScopedLock lock(mClothFabricPoolLock); + npClothFabric = mClothFabricPool.construct(); + } + return npClothFabric; +} + +void NpFactory::releaseClothFabricToPool(NpClothFabric& clothFabric) +{ + PX_ASSERT(clothFabric.getBaseFlags() & PxBaseFlag::eOWNS_MEMORY); + Ps::Mutex::ScopedLock lock(mClothFabricPoolLock); + mClothFabricPool.destroy(&clothFabric); +} + +void NpFactory::addClothFabric(NpClothFabric* cf, bool lock) +{ + if(lock) + { + Ps::Mutex::ScopedLock lock_(mTrackingMutex); + if(!mClothFabricArray.size()) + mClothFabricArray.reserve(64); + + mClothFabricArray.pushBack(cf); + } + else + { + if(!mClothFabricArray.size()) + mClothFabricArray.reserve(64); + + mClothFabricArray.pushBack(cf); + } +} + +PxClothFabric* NpFactory::createClothFabric(PxInputStream& stream) +{ + if(!sCreateClothFabricFromStreamFn) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, + "Cloth not registered: returned NULL."); + return NULL; + } + + NpClothFabric* result = (*sCreateClothFabricFromStreamFn)(stream); + + if(result) + addClothFabric(result); + + return result; +} + +PxClothFabric* NpFactory::createClothFabric(const PxClothFabricDesc& desc) +{ + if(!sCreateClothFabricFromDescFn) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, + "Cloth not registered: returned NULL."); + return NULL; + } + + NpClothFabric* result = (*sCreateClothFabricFromDescFn)(desc); + + if(result) + addClothFabric(result); + + return result; +} + +bool NpFactory::removeClothFabric(PxClothFabric& cf) +{ + NpClothFabric* npClothFabric = &static_cast<NpClothFabric&>(cf); + + Ps::Mutex::ScopedLock lock(mTrackingMutex); + + // remove the cloth fabric from the array + for(PxU32 i=0; i<mClothFabricArray.size(); i++) + { + if(mClothFabricArray[i]==npClothFabric) + { + mClothFabricArray.replaceWithLast(i); +#if PX_SUPPORT_PVD + if(mNpFactoryListener) + mNpFactoryListener->onNpFactoryBufferRelease(cf); +#endif + return true; + } + } + return false; +} + +PxU32 NpFactory::getNbClothFabrics() const +{ + return mClothFabricArray.size(); +} + +PxU32 NpFactory::getClothFabrics(PxClothFabric** userBuffer, PxU32 bufferSize) const +{ + const PxU32 size = mClothFabricArray.size(); + + const PxU32 writeCount = PxMin(size, bufferSize); + for(PxU32 i=0; i<writeCount; i++) + userBuffer[i] = mClothFabricArray[i]; + + return writeCount; +} + +PxCloth* NpFactory::createCloth(const PxTransform& globalPose, PxClothFabric& fabric, const PxClothParticle* particles, PxClothFlags flags) +{ + PX_CHECK_AND_RETURN_NULL(globalPose.isValid(),"globalPose is not valid. createCloth returns NULL."); + PX_CHECK_AND_RETURN_NULL((particles != NULL) && fabric.getNbParticles(), "No particles supplied. createCloth returns NULL."); + +#if PX_CHECKED + PX_CHECK_AND_RETURN_NULL(NpCloth::checkParticles(fabric.getNbParticles(), particles), "PxPhysics::createCloth: particle values must be finite and inverse weight must not be negative"); +#endif + + if(!sCreateClothFn) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, + "Cloth not registered: returned NULL."); + return NULL; + } + + // create the internal cloth object + NpCloth* npCloth = (*sCreateClothFn)(globalPose, fabric, particles, flags); + if (npCloth) + { + addToTracking<PxActor>(mActorTracking, npCloth, mTrackingMutex); + return npCloth; + } + else + { + Ps::getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __LINE__, + "Cloth initialization failed: returned NULL."); + return NULL; + } +} +#endif + +void NpFactory::onActorRelease(PxActor* a) +{ + Ps::Mutex::ScopedLock lock(mTrackingMutex); + mActorTracking.erase(a); +} + +void NpFactory::onShapeRelease(PxShape* a) +{ + Ps::Mutex::ScopedLock lock(mTrackingMutex); + mShapeTracking.erase(a); +} + + +void NpFactory::addArticulation(PxArticulation* npArticulation, bool lock) +{ + addToTracking<PxArticulation>(mArticulationTracking, npArticulation, mTrackingMutex, lock); +} + +namespace +{ + NpArticulation* createArticulation() + { + NpArticulation* npArticulation = NpFactory::getInstance().createNpArticulation(); + if (!npArticulation) + Ps::getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __LINE__, "Articulation initialization failed: returned NULL."); + + return npArticulation; + } + + NpArticulationLink* createArticulationLink(NpArticulation&root, NpArticulationLink* parent, const PxTransform& pose) + { + PX_CHECK_AND_RETURN_NULL(pose.isValid(),"Supplied PxArticulation pose is not valid. Articulation link creation method returns NULL."); + PX_CHECK_AND_RETURN_NULL((!parent || (&parent->getRoot() == &root)), "specified parent link is not part of the destination articulation. Articulation link creation method returns NULL."); + + NpArticulationLink* npArticulationLink = NpFactory::getInstance().createNpArticulationLink(root, parent, pose); + if (!npArticulationLink) + { + Ps::getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __LINE__, + "Articulation link initialization failed: returned NULL."); + return NULL; + } + + if (parent) + { + PxTransform parentPose = parent->getCMassLocalPose().transformInv(pose); + PxTransform childPose = PxTransform(PxIdentity); + + NpArticulationJoint* npArticulationJoint = NpFactory::getInstance().createNpArticulationJoint(*parent, parentPose, *npArticulationLink, childPose); + if (!npArticulationJoint) + { + PX_DELETE(npArticulationLink); + + Ps::getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __LINE__, + "Articulation link initialization failed due to joint creation failure: returned NULL."); + return NULL; + } + + npArticulationLink->setInboundJoint(*npArticulationJoint); + } + + return npArticulationLink; + } + + // pointers to functions above, initialized during subsystem registration + static NpArticulation* (*sCreateArticulationFn)() = 0; + static NpArticulationLink* (*sCreateArticulationLinkFn)(NpArticulation&, NpArticulationLink* parent, const PxTransform& pose) = 0; +} + +void NpFactory::registerArticulations() +{ + sCreateArticulationFn = &::createArticulation; + sCreateArticulationLinkFn = &::createArticulationLink; +} + +NpArticulation* NpFactory::createNpArticulation() +{ + NpArticulation* npArticulation; + { + Ps::Mutex::ScopedLock lock(mArticulationPoolLock); + npArticulation = mArticulationPool.construct(); + } + return npArticulation; +} + +void NpFactory::releaseArticulationToPool(NpArticulation& articulation) +{ + PX_ASSERT(articulation.getBaseFlags() & PxBaseFlag::eOWNS_MEMORY); + Ps::Mutex::ScopedLock lock(mArticulationPoolLock); + mArticulationPool.destroy(&articulation); +} + +PxArticulation* NpFactory::createArticulation() +{ + if(!sCreateArticulationFn) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, + "Articulations not registered: returned NULL."); + return NULL; + } + + NpArticulation* npArticulation = (*sCreateArticulationFn)(); + if(npArticulation) + addArticulation(npArticulation); + + return npArticulation; +} + +void NpFactory::onArticulationRelease(PxArticulation* a) +{ + Ps::Mutex::ScopedLock lock(mTrackingMutex); + mArticulationTracking.erase(a); +} + +NpArticulationLink* NpFactory::createNpArticulationLink(NpArticulation&root, NpArticulationLink* parent, const PxTransform& pose) +{ + NpArticulationLink* npArticulationLink; + { + Ps::Mutex::ScopedLock lock(mArticulationLinkPoolLock); + npArticulationLink = mArticulationLinkPool.construct(pose, root, parent); + } + return npArticulationLink; +} + +void NpFactory::releaseArticulationLinkToPool(NpArticulationLink& articulationLink) +{ + PX_ASSERT(articulationLink.getBaseFlags() & PxBaseFlag::eOWNS_MEMORY); + Ps::Mutex::ScopedLock lock(mArticulationLinkPoolLock); + mArticulationLinkPool.destroy(&articulationLink); +} + +PxArticulationLink* NpFactory::createArticulationLink(NpArticulation& root, NpArticulationLink* parent, const PxTransform& pose) +{ + if(!sCreateArticulationLinkFn) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, + "Articulations not registered: returned NULL."); + return NULL; + } + + return (*sCreateArticulationLinkFn)(root, parent, pose); +} + +NpArticulationJoint* NpFactory::createNpArticulationJoint(NpArticulationLink& parent, const PxTransform& parentFrame, NpArticulationLink& child, const PxTransform& childFrame) +{ + NpArticulationJoint* npArticulationJoint; + { + Ps::Mutex::ScopedLock lock(mArticulationJointPoolLock); + npArticulationJoint = mArticulationJointPool.construct(parent, parentFrame, child, childFrame); + } + return npArticulationJoint; +} + +void NpFactory::releaseArticulationJointToPool(NpArticulationJoint& articulationJoint) +{ + PX_ASSERT(articulationJoint.getBaseFlags() & PxBaseFlag::eOWNS_MEMORY); + Ps::Mutex::ScopedLock lock(mArticulationJointPoolLock); + mArticulationJointPool.destroy(&articulationJoint); +} + +/////////////////////////////////////////////////////////////////////////////// constraint + +void NpFactory::addConstraint(PxConstraint* npConstraint, bool lock) +{ + addToTracking<PxConstraint>(mConstraintTracking, npConstraint, mTrackingMutex, lock); +} + +PxConstraint* NpFactory::createConstraint(PxRigidActor* actor0, PxRigidActor* actor1, PxConstraintConnector& connector, const PxConstraintShaderTable& shaders, PxU32 dataSize) +{ + PX_CHECK_AND_RETURN_NULL((actor0 && !actor0->is<PxRigidStatic>()) || (actor1 && !actor1->is<PxRigidStatic>()), "createConstraint: At least one actor must be dynamic or an articulation link"); + + NpConstraint* npConstraint; + { + Ps::Mutex::ScopedLock lock(mConstraintPoolLock); + npConstraint = mConstraintPool.construct(actor0, actor1, connector, shaders, dataSize); + } + addConstraint(npConstraint); + return npConstraint; +} + +void NpFactory::releaseConstraintToPool(NpConstraint& constraint) +{ + PX_ASSERT(constraint.getBaseFlags() & PxBaseFlag::eOWNS_MEMORY); + Ps::Mutex::ScopedLock lock(mConstraintPoolLock); + mConstraintPool.destroy(&constraint); +} + +void NpFactory::onConstraintRelease(PxConstraint* c) +{ + Ps::Mutex::ScopedLock lock(mTrackingMutex); + mConstraintTracking.erase(c); +} + +/////////////////////////////////////////////////////////////////////////////// aggregate + +// PX_AGGREGATE +void NpFactory::addAggregate(PxAggregate* npAggregate, bool lock) +{ + addToTracking<PxAggregate>(mAggregateTracking, npAggregate, mTrackingMutex, lock); +} + +PxAggregate* NpFactory::createAggregate(PxU32 maxActors, bool selfCollisions) +{ + PX_CHECK_AND_RETURN_NULL(maxActors<=128, "maxActors limited to 128. createAggregate method returns NULL."); + + NpAggregate* npAggregate; + + { + Ps::Mutex::ScopedLock lock(mAggregatePoolLock); + npAggregate = mAggregatePool.construct(maxActors, selfCollisions); + } + + addAggregate(npAggregate); + return npAggregate; +} + +void NpFactory::releaseAggregateToPool(NpAggregate& aggregate) +{ + PX_ASSERT(aggregate.getBaseFlags() & PxBaseFlag::eOWNS_MEMORY); + Ps::Mutex::ScopedLock lock(mAggregatePoolLock); + mAggregatePool.destroy(&aggregate); +} + +void NpFactory::onAggregateRelease(PxAggregate* a) +{ + Ps::Mutex::ScopedLock lock(mTrackingMutex); + mAggregateTracking.erase(a); +} +//~PX_AGGREGATE + + +/////////////////////////////////////////////////////////////////////////////// + +PxMaterial* NpFactory::createMaterial(PxReal staticFriction, PxReal dynamicFriction, PxReal restitution) +{ + PX_CHECK_AND_RETURN_NULL(dynamicFriction >= 0.0f, "createMaterial: dynamicFriction must be >= 0."); + PX_CHECK_AND_RETURN_NULL(staticFriction >= 0.0f, "createMaterial: staticFriction must be >= 0."); + PX_CHECK_AND_RETURN_NULL(restitution >= 0.0f || restitution <= 1.0f, "createMaterial: restitution must be between 0 and 1."); + + Sc::MaterialData data; + data.staticFriction = staticFriction; + data.dynamicFriction = dynamicFriction; + data.restitution = restitution; + + NpMaterial* npMaterial; + { + Ps::Mutex::ScopedLock lock(mMaterialPoolLock); + npMaterial = mMaterialPool.construct(data); + } + return npMaterial; +} + +void NpFactory::releaseMaterialToPool(NpMaterial& material) +{ + PX_ASSERT(material.getBaseFlags() & PxBaseFlag::eOWNS_MEMORY); + Ps::Mutex::ScopedLock lock(mMaterialPoolLock); + mMaterialPool.destroy(&material); +} + +/////////////////////////////////////////////////////////////////////////////// + +NpConnectorArray* NpFactory::acquireConnectorArray() +{ + Ps::MutexT<>::ScopedLock l(mConnectorArrayPoolLock); + return mConnectorArrayPool.construct(); +} + +void NpFactory::releaseConnectorArray(NpConnectorArray* array) +{ + Ps::MutexT<>::ScopedLock l(mConnectorArrayPoolLock); + mConnectorArrayPool.destroy(array); +} + +/////////////////////////////////////////////////////////////////////////////// + + + +/////////////////////////////////////////////////////////////////////////////// + +NpShape* NpFactory::createShape(const PxGeometry& geometry, + PxShapeFlags shapeFlags, + PxMaterial*const* materials, + PxU16 materialCount, + bool isExclusive) +{ + switch(geometry.getType()) + { + case PxGeometryType::eBOX: + PX_CHECK_AND_RETURN_NULL(static_cast<const PxBoxGeometry&>(geometry).isValid(), "Supplied PxGeometry is not valid. Shape creation method returns NULL."); + break; + case PxGeometryType::eSPHERE: + PX_CHECK_AND_RETURN_NULL(static_cast<const PxSphereGeometry&>(geometry).isValid(), "Supplied PxGeometry is not valid. Shape creation method returns NULL."); + break; + case PxGeometryType::eCAPSULE: + PX_CHECK_AND_RETURN_NULL(static_cast<const PxCapsuleGeometry&>(geometry).isValid(), "Supplied PxGeometry is not valid. Shape creation method returns NULL."); + break; + case PxGeometryType::eCONVEXMESH: + PX_CHECK_AND_RETURN_NULL(static_cast<const PxConvexMeshGeometry&>(geometry).isValid(), "Supplied PxGeometry is not valid. Shape creation method returns NULL."); + break; + case PxGeometryType::ePLANE: + PX_CHECK_AND_RETURN_NULL(static_cast<const PxPlaneGeometry&>(geometry).isValid(), "Supplied PxGeometry is not valid. Shape creation method returns NULL."); + break; + case PxGeometryType::eHEIGHTFIELD: + PX_CHECK_AND_RETURN_NULL(static_cast<const PxHeightFieldGeometry&>(geometry).isValid(), "Supplied PxGeometry is not valid. Shape creation method returns NULL."); + break; + case PxGeometryType::eTRIANGLEMESH: + PX_CHECK_AND_RETURN_NULL(static_cast<const PxTriangleMeshGeometry&>(geometry).isValid(), "Supplied PxGeometry is not valid. Shape creation method returns NULL."); + break; + case PxGeometryType::eGEOMETRY_COUNT: + case PxGeometryType::eINVALID: + PX_ASSERT(0); + } + + // + // Check for invalid material table setups + // + +#if PX_CHECKED + if (!NpShape::checkMaterialSetup(geometry, "Shape creation", materials, materialCount)) + return NULL; +#endif + + Ps::InlineArray<PxU16, 4> materialIndices("NpFactory::TmpMaterialIndexBuffer"); + materialIndices.resize(materialCount); + if (materialCount == 1) + { + materialIndices[0] = Ps::to16((static_cast<NpMaterial*>(materials[0]))->getHandle()); + } + else + { + NpMaterial::getMaterialIndices(materials, materialIndices.begin(), materialCount); + } + + NpShape* npShape; + { + Ps::Mutex::ScopedLock lock(mShapePoolLock); + PxU16* mi = materialIndices.begin(); // required to placate pool constructor arg passing + npShape = mShapePool.construct(geometry, shapeFlags, mi, materialCount, isExclusive); + } + + if(!npShape) + return NULL; + + for (PxU32 i=0; i < materialCount; i++) + static_cast<NpMaterial*>(npShape->getMaterial(i))->incRefCount(); + + addShape(npShape); + + return npShape; +} + +void NpFactory::releaseShapeToPool(NpShape& shape) +{ + PX_ASSERT(shape.getBaseFlags() & PxBaseFlag::eOWNS_MEMORY); + Ps::Mutex::ScopedLock lock(mShapePoolLock); + mShapePool.destroy(&shape); +} + + + +PxU32 NpFactory::getNbShapes() const +{ + return mShapeTracking.size(); +} + +PxU32 NpFactory::getShapes(PxShape** userBuffer, PxU32 bufferSize, PxU32 startIndex) const +{ + if(mShapeTracking.size()<startIndex) + return 0; + PxU32 count = PxMax(bufferSize, mShapeTracking.size()-startIndex); + PxShape*const *shapes = mShapeTracking.getEntries(); + for(PxU32 i=0;i<count;i++) + userBuffer[i] = shapes[startIndex+i]; + return count; +} + + +PxRigidStatic* NpFactory::createRigidStatic(const PxTransform& pose) +{ + PX_CHECK_AND_RETURN_NULL(pose.isValid(), "pose is not valid. createRigidStatic returns NULL."); + + NpRigidStatic* npActor; + + { + Ps::Mutex::ScopedLock lock(mRigidStaticPoolLock); + npActor = mRigidStaticPool.construct(pose); + } + + addRigidStatic(npActor); + return npActor; +} + +void NpFactory::releaseRigidStaticToPool(NpRigidStatic& rigidStatic) +{ + PX_ASSERT(rigidStatic.getBaseFlags() & PxBaseFlag::eOWNS_MEMORY); + Ps::Mutex::ScopedLock lock(mRigidStaticPoolLock); + mRigidStaticPool.destroy(&rigidStatic); +} + +PxRigidDynamic* NpFactory::createRigidDynamic(const PxTransform& pose) +{ + PX_CHECK_AND_RETURN_NULL(pose.isValid(), "pose is not valid. createRigidDynamic returns NULL."); + + NpRigidDynamic* npBody; + { + Ps::Mutex::ScopedLock lock(mRigidDynamicPoolLock); + npBody = mRigidDynamicPool.construct(pose); + } + addRigidDynamic(npBody); + return npBody; +} + + +void NpFactory::releaseRigidDynamicToPool(NpRigidDynamic& rigidDynamic) +{ + PX_ASSERT(rigidDynamic.getBaseFlags() & PxBaseFlag::eOWNS_MEMORY); + Ps::Mutex::ScopedLock lock(mRigidDynamicPoolLock); + mRigidDynamicPool.destroy(&rigidDynamic); +} + +/////////////////////////////////////////////////////////////////////////////// + +// PT: this function is here to minimize the amount of locks when deserializing a collection +void NpFactory::addCollection(const Cm::Collection& collection) +{ + + PxU32 nb = collection.getNbObjects(); + const Ps::Pair<PxBase* const, PxSerialObjectId>* entries = collection.internalGetObjects(); + // PT: we take the lock only once, here + Ps::Mutex::ScopedLock lock(mTrackingMutex); + + for(PxU32 i=0;i<nb;i++) + { + PxBase* s = entries[i].first; + const PxType serialType = s->getConcreteType(); +////////////////////////// + if(serialType==PxConcreteType::eHEIGHTFIELD) + { + Gu::HeightField* gu = static_cast<Gu::HeightField*>(s); + gu->setMeshFactory(this); + addHeightField(gu, false); + } + else if(serialType==PxConcreteType::eCONVEX_MESH) + { + Gu::ConvexMesh* gu = static_cast<Gu::ConvexMesh*>(s); + gu->setMeshFactory(this); + addConvexMesh(gu, false); + } + else if(serialType==PxConcreteType::eTRIANGLE_MESH_BVH33 || serialType==PxConcreteType::eTRIANGLE_MESH_BVH34) + { + Gu::TriangleMesh* gu = static_cast<Gu::TriangleMesh*>(s); + gu->setMeshFactory(this); + addTriangleMesh(gu, false); + } +////////////////////////// +#if PX_USE_CLOTH_API + else if (serialType==PxConcreteType::eCLOTH_FABRIC) + { + NpClothFabric* np = static_cast<NpClothFabric*>(s); + // PT: TODO: investigate why cloth don't need a "setMeshFactory" call here + addClothFabric(np, false); + } +#endif + else if(serialType==PxConcreteType::eRIGID_DYNAMIC) + { + NpRigidDynamic* np = static_cast<NpRigidDynamic*>(s); + addRigidDynamic(np, false); + } + else if(serialType==PxConcreteType::eRIGID_STATIC) + { + NpRigidStatic* np = static_cast<NpRigidStatic*>(s); + addRigidStatic(np, false); + } + else if(serialType==PxConcreteType::eSHAPE) + { + NpShape* np = static_cast<NpShape*>(s); + addShape(np, false); + } + else if(serialType==PxConcreteType::eMATERIAL) + { + } + else if(serialType==PxConcreteType::eCONSTRAINT) + { + NpConstraint* np = static_cast<NpConstraint*>(s); + addConstraint(np, false); + } +#if PX_USE_CLOTH_API + else if (serialType==PxConcreteType::eCLOTH) + { + NpCloth* np = static_cast<NpCloth*>(s); + addCloth(np, false); + } +#endif +#if PX_USE_PARTICLE_SYSTEM_API + else if(serialType==PxConcreteType::ePARTICLE_SYSTEM) + { + NpParticleSystem* np = static_cast<NpParticleSystem*>(s); + addParticleSystem(np, false); + } + else if(serialType==PxConcreteType::ePARTICLE_FLUID) + { + NpParticleFluid* np = static_cast<NpParticleFluid*>(s); + addParticleFluid(np, false); + } +#endif + else if(serialType==PxConcreteType::eAGGREGATE) + { + NpAggregate* np = static_cast<NpAggregate*>(s); + addAggregate(np, false); + + // PT: TODO: double-check this.... is it correct? + for(PxU32 j=0;j<np->getCurrentSizeFast();j++) + { + PxBase* actor = np->getActorFast(j); + const PxType serialType1 = actor->getConcreteType(); + + if(serialType1==PxConcreteType::eRIGID_STATIC) + addRigidStatic(static_cast<NpRigidStatic*>(actor), false); + else if(serialType1==PxConcreteType::eRIGID_DYNAMIC) + addRigidDynamic(static_cast<NpRigidDynamic*>(actor), false); + else if(serialType1==PxConcreteType::ePARTICLE_SYSTEM) + {} + else if(serialType1==PxConcreteType::ePARTICLE_FLUID) + {} + else if(serialType1==PxConcreteType::eARTICULATION_LINK) + {} + else PX_ASSERT(0); + } + } + else if(serialType==PxConcreteType::eARTICULATION) + { + NpArticulation* np = static_cast<NpArticulation*>(s); + addArticulation(np, false); + } + else if(serialType==PxConcreteType::eARTICULATION_LINK) + { +// NpArticulationLink* np = static_cast<NpArticulationLink*>(s); + } + else if(serialType==PxConcreteType::eARTICULATION_JOINT) + { +// NpArticulationJoint* np = static_cast<NpArticulationJoint*>(s); + } + else + { +// assert(0); + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +#if PX_SUPPORT_GPU_PHYSX +void NpFactory::notifyReleaseTriangleMesh(const PxTriangleMesh& tm) +{ + NpPhysics::getInstance().getNpPhysicsGpu().releaseTriangleMeshMirror(tm); +} + +void NpFactory::notifyReleaseHeightField(const PxHeightField& hf) +{ + NpPhysics::getInstance().getNpPhysicsGpu().releaseHeightFieldMirror(hf); +} + +void NpFactory::notifyReleaseConvexMesh(const PxConvexMesh& cm) +{ + NpPhysics::getInstance().getNpPhysicsGpu().releaseConvexMeshMirror(cm); +} +#endif + +#if PX_SUPPORT_PVD +void NpFactory::setNpFactoryListener( NpFactoryListener& inListener) +{ + mNpFactoryListener = &inListener; + addFactoryListener(inListener); +} +#endif +/////////////////////////////////////////////////////////////////////////////// + +// these calls are issued from the Scb layer when buffered deletes are issued. +// TODO: we should really push these down as a virtual interface that is part of Scb's reqs +// to eliminate this link-time dep. + + +static void NpDestroyRigidActor(Scb::RigidStatic& scb) +{ + NpRigidStatic* np = const_cast<NpRigidStatic*>(getNpRigidStatic(&scb)); + + void* ud = np->userData; + + if(np->getBaseFlags() & PxBaseFlag::eOWNS_MEMORY) + NpFactory::getInstance().releaseRigidStaticToPool(*np); + else + np->~NpRigidStatic(); + + NpPhysics::getInstance().notifyDeletionListenersMemRelease(np, ud); +} + +static void NpDestroyRigidDynamic(Scb::Body& scb) +{ + NpRigidDynamic* np = const_cast<NpRigidDynamic*>(getNpRigidDynamic(&scb)); + + void* ud = np->userData; + if(np->getBaseFlags() & PxBaseFlag::eOWNS_MEMORY) + NpFactory::getInstance().releaseRigidDynamicToPool(*np); + else + np->~NpRigidDynamic(); + NpPhysics::getInstance().notifyDeletionListenersMemRelease(np, ud); +} + +#if PX_USE_PARTICLE_SYSTEM_API +static void NpDestroyParticleSystem(Scb::ParticleSystem& scb) +{ + if(scb.getActorType() == PxActorType::ePARTICLE_SYSTEM) + { + NpParticleSystem* np = const_cast<NpParticleSystem*>(getNpParticleSystem(&scb)); + + void* ud = np->userData; + if(np->getBaseFlags() & PxBaseFlag::eOWNS_MEMORY) + NpFactory::getInstance().releaseParticleSystemToPool(*np); + else + np->~NpParticleSystem(); + NpPhysics::getInstance().notifyDeletionListenersMemRelease(np, ud); + } + else + { + NpParticleFluid* np = const_cast<NpParticleFluid*>(getNpParticleFluid(&scb)); + + void* ud = np->userData; + if(np->getBaseFlags() & PxBaseFlag::eOWNS_MEMORY) + NpFactory::getInstance().releaseParticleFluidToPool(*np); + else + np->~NpParticleFluid(); + NpPhysics::getInstance().notifyDeletionListenersMemRelease(np, ud); + } +} +#endif + +static void NpDestroyArticulationLink(Scb::Body& scb) +{ + NpArticulationLink* np = const_cast<NpArticulationLink*>(getNpArticulationLink(&scb)); + + void* ud = np->userData; + if(np->getBaseFlags() & PxBaseFlag::eOWNS_MEMORY) + NpFactory::getInstance().releaseArticulationLinkToPool(*np); + else + np->~NpArticulationLink(); + NpPhysics::getInstance().notifyDeletionListenersMemRelease(np, ud); +} + +static void NpDestroyArticulationJoint(Scb::ArticulationJoint& scb) +{ + NpArticulationJoint* np = const_cast<NpArticulationJoint*>(getNpArticulationJoint(&scb)); + + if(np->getBaseFlags() & PxBaseFlag::eOWNS_MEMORY) + NpFactory::getInstance().releaseArticulationJointToPool(*np); + else + np->~NpArticulationJoint(); + NpPhysics::getInstance().notifyDeletionListenersMemRelease(np, NULL); +} + +static void NpDestroyArticulation(Scb::Articulation& scb) +{ + NpArticulation* np = const_cast<NpArticulation*>(getNpArticulation(&scb)); + + void* ud = np->userData; + if(np->getBaseFlags() & PxBaseFlag::eOWNS_MEMORY) + NpFactory::getInstance().releaseArticulationToPool(*np); + else + np->~NpArticulation(); + NpPhysics::getInstance().notifyDeletionListenersMemRelease(np, ud); +} + +static void NpDestroyAggregate(Scb::Aggregate& scb) +{ + NpAggregate* np = const_cast<NpAggregate*>(getNpAggregate(&scb)); + + if(np->getBaseFlags() & PxBaseFlag::eOWNS_MEMORY) + NpFactory::getInstance().releaseAggregateToPool(*np); + else + np->~NpAggregate(); + + NpPhysics::getInstance().notifyDeletionListenersMemRelease(np, NULL); +} + +static void NpDestroyShape(Scb::Shape& scb) +{ + NpShape* np = const_cast<NpShape*>(getNpShape(&scb)); + + void* ud = np->userData; + + if(np->getBaseFlags() & PxBaseFlag::eOWNS_MEMORY) + NpFactory::getInstance().releaseShapeToPool(*np); + else + np->~NpShape(); + + NpPhysics::getInstance().notifyDeletionListenersMemRelease(np, ud); +} + +static void NpDestroyConstraint(Scb::Constraint& scb) +{ + const size_t offset = size_t(&(reinterpret_cast<NpConstraint*>(0)->getScbConstraint())); + NpConstraint* np = reinterpret_cast<NpConstraint*>(reinterpret_cast<char*>(&scb)-offset); + if(np->getBaseFlags() & PxBaseFlag::eOWNS_MEMORY) + NpFactory::getInstance().releaseConstraintToPool(*np); + else + np->~NpConstraint(); + NpPhysics::getInstance().notifyDeletionListenersMemRelease(np, NULL); +} + +#if PX_USE_CLOTH_API +static void NpDestroyCloth(Scb::Cloth& scb) +{ + NpCloth* np = const_cast<NpCloth*>(getNpCloth(&scb)); + + void* ud = np->userData; + if(np->getBaseFlags() & PxBaseFlag::eOWNS_MEMORY) + NpFactory::getInstance().releaseClothToPool(*np); + else + np->~NpCloth(); + NpPhysics::getInstance().notifyDeletionListenersMemRelease(np, ud); +} +#endif + +namespace physx +{ + void NpDestroy(Scb::Base& base) + { + switch(base.getScbType()) + { + case ScbType::SHAPE_EXCLUSIVE: + case ScbType::SHAPE_SHARED: { NpDestroyShape(static_cast<Scb::Shape&>(base)); }break; + case ScbType::BODY: { NpDestroyRigidDynamic(static_cast<Scb::Body&>(base)); }break; + case ScbType::BODY_FROM_ARTICULATION_LINK: { NpDestroyArticulationLink(static_cast<Scb::Body&>(base)); }break; + case ScbType::RIGID_STATIC: { NpDestroyRigidActor(static_cast<Scb::RigidStatic&>(base)); }break; + case ScbType::CONSTRAINT: { NpDestroyConstraint(static_cast<Scb::Constraint&>(base)); }break; +#if PX_USE_PARTICLE_SYSTEM_API + case ScbType::PARTICLE_SYSTEM: { NpDestroyParticleSystem(static_cast<Scb::ParticleSystem&>(base)); }break; +#endif + case ScbType::ARTICULATION: { NpDestroyArticulation(static_cast<Scb::Articulation&>(base)); }break; + case ScbType::ARTICULATION_JOINT: { NpDestroyArticulationJoint(static_cast<Scb::ArticulationJoint&>(base)); }break; + case ScbType::AGGREGATE: { NpDestroyAggregate(static_cast<Scb::Aggregate&>(base)); }break; +#if PX_USE_CLOTH_API + case ScbType::CLOTH: { NpDestroyCloth(static_cast<Scb::Cloth&>(base)); }break; +#endif + case ScbType::UNDEFINED: + case ScbType::TYPE_COUNT: + PX_ALWAYS_ASSERT_MESSAGE("NpDestroy: missing type!"); + break; + } + } +} + diff --git a/PhysX_3.4/Source/PhysX/src/NpFactory.h b/PhysX_3.4/Source/PhysX/src/NpFactory.h new file mode 100644 index 00000000..ac8dc6fb --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpFactory.h @@ -0,0 +1,304 @@ +// 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_NP_FACTORY +#define PX_PHYSICS_NP_FACTORY + +#include "PsPool.h" +#include "PsMutex.h" +#include "PsHashSet.h" + +#include "GuMeshFactory.h" +#include "CmPhysXCommon.h" +#include "PxPhysXConfig.h" +#include "PxShape.h" + +#if PX_USE_CLOTH_API +#include "cloth/PxClothTypes.h" +#include "cloth/PxClothFabric.h" +#endif + +namespace physx +{ + +class PxActor; + +class PxRigidActor; + +class PxRigidStatic; +class NpRigidStatic; + +class PxRigidDynamic; +class NpRigidDynamic; + +class NpConnectorArray; + +struct PxConstraintShaderTable; +class PxConstraintConnector; +class PxConstraint; +class NpConstraint; + +class PxArticulation; +class NpArticulation; +class PxArticulationLink; +class NpArticulationLink; +class NpArticulationJoint; + +class PxParticleBase; +class PxParticleSystem; +class NpParticleSystem; +class PxParticleFluid; +class NpParticleFluid; + +class PxClothFabric; +class NpClothFabric; +class PxCloth; +class NpCloth; +class PxMaterial; +class NpMaterial; + +class PxGeometry; + +class NpShape; + +class NpScene; + +class PxAggregate; +class NpAggregate; + +class NpConnectorArray; +class NpPtrTableStorageManager; + +namespace Cm +{ + class Collection; +} + +namespace Scb +{ + class RigidObject; +} + +class NpFactoryListener : public GuMeshFactoryListener +{ +protected: + virtual ~NpFactoryListener(){} +public: +#if PX_USE_CLOTH_API + virtual void onNpFactoryBufferRelease(PxClothFabric& data) = 0; +#endif +}; + + + +class NpFactory : public GuMeshFactory +{ + PX_NOCOPY(NpFactory) +public: + NpFactory(); +private: + ~NpFactory(); + +public: + static void createInstance(); + static void destroyInstance(); + static void registerArticulations(); + static void registerCloth(); + static void registerParticles(); + + void release(); + + void addCollection(const Cm::Collection& collection); + + PX_INLINE static NpFactory& getInstance() { return *mInstance; } + + PxRigidDynamic* createRigidDynamic(const PxTransform& pose); + void addRigidDynamic(PxRigidDynamic*, bool lock=true); + void releaseRigidDynamicToPool(NpRigidDynamic&); + + PxRigidStatic* createRigidStatic(const PxTransform& pose); + void addRigidStatic(PxRigidStatic*, bool lock=true); + void releaseRigidStaticToPool(NpRigidStatic&); + + NpShape* createShape(const PxGeometry& geometry, + PxShapeFlags shapeFlags, + PxMaterial*const* materials, + PxU16 materialCount, + bool isExclusive); + + void addShape(PxShape*, bool lock=true); + void releaseShapeToPool(NpShape&); + + PxU32 getNbShapes() const; + PxU32 getShapes(PxShape** userBuffer, PxU32 bufferSize, PxU32 startIndex) const; + + void addConstraint(PxConstraint*, bool lock=true); + PxConstraint* createConstraint(PxRigidActor* actor0, PxRigidActor* actor1, PxConstraintConnector& connector, const PxConstraintShaderTable& shaders, PxU32 dataSize); + void releaseConstraintToPool(NpConstraint&); + + void addArticulation(PxArticulation*, bool lock=true); + PxArticulation* createArticulation(); + NpArticulation* createNpArticulation(); + void releaseArticulationToPool(NpArticulation& articulation); + + NpArticulationLink* createNpArticulationLink(NpArticulation&root, NpArticulationLink* parent, const PxTransform& pose); + void releaseArticulationLinkToPool(NpArticulationLink& articulation); + PxArticulationLink* createArticulationLink(NpArticulation&, NpArticulationLink* parent, const PxTransform& pose); + + NpArticulationJoint* createNpArticulationJoint(NpArticulationLink& parent, const PxTransform& parentFrame, NpArticulationLink& child, const PxTransform& childFrame); + void releaseArticulationJointToPool(NpArticulationJoint& articulationJoint); + + void addAggregate(PxAggregate*, bool lock=true); + PxAggregate* createAggregate(PxU32 maxActors, bool selfCollisions); + void releaseAggregateToPool(NpAggregate&); + + +#if PX_USE_PARTICLE_SYSTEM_API + NpParticleSystem* createNpParticleSystem(PxU32 maxParticles, bool perParticleRestOffset); + void releaseParticleSystemToPool(NpParticleSystem& ps); + NpParticleFluid* createNpParticleFluid(PxU32 maxParticles, bool perParticleRestOffset); + void releaseParticleFluidToPool(NpParticleFluid& pf); + void addParticleSystem(PxParticleSystem*, bool lock=true); + PxParticleSystem* createParticleSystem(PxU32 maxParticles, bool perParticleRestOffset); + void addParticleFluid(PxParticleFluid*, bool lock=true); + PxParticleFluid* createParticleFluid(PxU32 maxParticles, bool perParticleRestOffset); +#endif + +#if PX_USE_CLOTH_API + NpCloth* createNpCloth(const PxTransform& globalPose, PxClothFabric& fabric, const PxClothParticle* particles, PxClothFlags flags); + void releaseClothToPool(NpCloth& cloth); + void addCloth(PxCloth* cloth, bool lock=true); + void addClothFabric(NpClothFabric* cf, bool lock=true); + PxClothFabric* createClothFabric(PxInputStream&); + PxClothFabric* createClothFabric(const PxClothFabricDesc& desc); + NpClothFabric* createNpClothFabric(); + void releaseClothFabricToPool(NpClothFabric& clothFabric); + bool removeClothFabric(PxClothFabric&); + PxU32 getNbClothFabrics() const; + PxU32 getClothFabrics(PxClothFabric** userBuffer, PxU32 bufferSize) const; + + PxCloth* createCloth(const PxTransform& globalPose, PxClothFabric& fabric, const PxClothParticle* particles, PxClothFlags flags); +#endif + + PxMaterial* createMaterial(PxReal staticFriction, PxReal dynamicFriction, PxReal restitution); + void releaseMaterialToPool(NpMaterial& material); + + // It's easiest to track these uninvasively, so it's OK to use the Px pointers + + void onActorRelease(PxActor*); + void onConstraintRelease(PxConstraint*); + void onAggregateRelease(PxAggregate*); + void onArticulationRelease(PxArticulation*); + void onShapeRelease(PxShape*); + + NpConnectorArray* acquireConnectorArray(); + void releaseConnectorArray(NpConnectorArray*); + + NpPtrTableStorageManager& getPtrTableStorageManager() { return *mPtrTableStorageManager; } + +#if PX_SUPPORT_PVD + void setNpFactoryListener( NpFactoryListener& ); +#endif + + +private: + + void releaseExclusiveShapeUserReferences(); +#if PX_SUPPORT_GPU_PHYSX + virtual void notifyReleaseTriangleMesh(const PxTriangleMesh& tm); + virtual void notifyReleaseHeightField(const PxHeightField& hf); + virtual void notifyReleaseConvexMesh(const PxConvexMesh& cm); +#endif + + Ps::Pool<NpConnectorArray> mConnectorArrayPool; + Ps::Mutex mConnectorArrayPoolLock; + + NpPtrTableStorageManager* mPtrTableStorageManager; + + Ps::HashSet<PxAggregate*> mAggregateTracking; + Ps::HashSet<PxArticulation*> mArticulationTracking; + Ps::HashSet<PxConstraint*> mConstraintTracking; + Ps::HashSet<PxActor*> mActorTracking; + Ps::CoalescedHashSet<PxShape*> mShapeTracking; + + Ps::Pool2<NpRigidDynamic, 4096> mRigidDynamicPool; + Ps::Mutex mRigidDynamicPoolLock; + + Ps::Pool2<NpRigidStatic, 4096> mRigidStaticPool; + Ps::Mutex mRigidStaticPoolLock; + + Ps::Pool2<NpShape, 4096> mShapePool; + Ps::Mutex mShapePoolLock; + + Ps::Pool2<NpAggregate, 4096> mAggregatePool; + Ps::Mutex mAggregatePoolLock; + + Ps::Pool2<NpConstraint, 4096> mConstraintPool; + Ps::Mutex mConstraintPoolLock; + + Ps::Pool2<NpMaterial, 4096> mMaterialPool; + Ps::Mutex mMaterialPoolLock; + + Ps::Pool2<NpArticulation, 4096> mArticulationPool; + Ps::Mutex mArticulationPoolLock; + + Ps::Pool2<NpArticulationLink, 4096> mArticulationLinkPool; + Ps::Mutex mArticulationLinkPoolLock; + + Ps::Pool2<NpArticulationJoint, 4096> mArticulationJointPool; + Ps::Mutex mArticulationJointPoolLock; + +#if PX_USE_PARTICLE_SYSTEM_API + Ps::Pool2<NpParticleSystem, 4096> mParticleSystemPool; + Ps::Mutex mParticleSystemPoolLock; + Ps::Pool2<NpParticleFluid, 4096> mParticleFluidPool; + Ps::Mutex mParticleFluidPoolLock; +#endif + +#if PX_USE_CLOTH_API + Ps::Array<NpClothFabric*> mClothFabricArray; + Ps::Pool2<NpCloth, 4096> mClothPool; + Ps::Mutex mClothPoolLock; + Ps::Pool2<NpClothFabric, 4096> mClothFabricPool; + Ps::Mutex mClothFabricPoolLock; +#endif + + static NpFactory* mInstance; + +#if PX_SUPPORT_PVD + NpFactoryListener* mNpFactoryListener; +#endif + +}; + + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/NpMaterial.cpp b/PhysX_3.4/Source/PhysX/src/NpMaterial.cpp new file mode 100644 index 00000000..ab68eebc --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpMaterial.cpp @@ -0,0 +1,205 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + + +#include "NpMaterial.h" +#include "NpPhysics.h" +#include "CmUtils.h" + +using namespace physx; + +NpMaterial::NpMaterial(const Sc::MaterialCore& desc) +: PxMaterial(PxConcreteType::eMATERIAL, PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE) +, mMaterial(desc) +{ + mMaterial.setNxMaterial(this); // back-reference +} + +NpMaterial::~NpMaterial() +{ + NpPhysics::getInstance().removeMaterialFromTable(*this); +} + +// PX_SERIALIZATION +void NpMaterial::resolveReferences(PxDeserializationContext&) +{ + // ### this one could be automated if NpMaterial would inherit from MaterialCore + // ### well actually in that case the pointer would not even be needed.... + mMaterial.setNxMaterial(this); // Resolve MaterialCore::mNxMaterial + + // Maybe not the best place to do it but it has to be done before the shapes resolve material indices + // since the material index translation table is needed there. This requires that the materials have + // been added to the table already. + NpPhysics::getInstance().addMaterial(this); +} + +void NpMaterial::onRefCountZero() +{ + void* ud = userData; + + if(getBaseFlags() & PxBaseFlag::eOWNS_MEMORY) + NpFactory::getInstance().releaseMaterialToPool(*this); + else + this->~NpMaterial(); + + NpPhysics::getInstance().notifyDeletionListenersMemRelease(this, ud); +} + +NpMaterial* NpMaterial::createObject(PxU8*& address, PxDeserializationContext& context) +{ + NpMaterial* obj = new (address) NpMaterial(PxBaseFlag::eIS_RELEASABLE); + address += sizeof(NpMaterial); + obj->importExtraData(context); + obj->resolveReferences(context); + return obj; +} +//~PX_SERIALIZATION + +void NpMaterial::release() +{ + decRefCount(); +} + +void NpMaterial::acquireReference() +{ + incRefCount(); +} + +PxU32 NpMaterial::getReferenceCount() const +{ + return getRefCount(); +} + +PX_INLINE void NpMaterial::updateMaterial() +{ + NpPhysics::getInstance().updateMaterial(*this); +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpMaterial::setDynamicFriction(PxReal x) +{ + PX_CHECK_AND_RETURN(PxIsFinite(x), "PxMaterial::setDynamicFriction: invalid float"); + mMaterial.dynamicFriction = x; + + updateMaterial(); +} + +PxReal NpMaterial::getDynamicFriction() const +{ + return mMaterial.dynamicFriction; +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpMaterial::setStaticFriction(PxReal x) +{ + PX_CHECK_AND_RETURN(PxIsFinite(x), "PxMaterial::setStaticFriction: invalid float"); + mMaterial.staticFriction = x; + + updateMaterial(); +} + +PxReal NpMaterial::getStaticFriction() const +{ + return mMaterial.staticFriction; +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpMaterial::setRestitution(PxReal x) +{ + PX_CHECK_AND_RETURN(PxIsFinite(x), "PxMaterial::setRestitution: invalid float"); + PX_CHECK_MSG(((x >= 0.0f) && (x <= 1.0f)), "PxMaterial::setRestitution: Restitution value has to be in [0,1]!"); + if ((x < 0.0f) || (x > 1.0f)) + { + PxClamp(x, 0.0f, 1.0f); + Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "PxMaterial::setRestitution: Invalid value %f was clamped to [0,1]!", PxF64(x)); + } + mMaterial.restitution = x; + + updateMaterial(); +} + +PxReal NpMaterial::getRestitution() const +{ + return mMaterial.restitution; +} + +///////////////////////////////////////////////////////////////////////////////// + +void NpMaterial::setFlag(PxMaterialFlag::Enum flag, bool value) +{ + if (value) + mMaterial.flags |= flag; + else + mMaterial.flags &= ~PxMaterialFlags(flag); + + updateMaterial(); +} + +void NpMaterial::setFlags(PxMaterialFlags inFlags) +{ + mMaterial.flags = inFlags; + updateMaterial(); +} + +PxMaterialFlags NpMaterial::getFlags() const +{ + return mMaterial.flags; +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpMaterial::setFrictionCombineMode(PxCombineMode::Enum x) +{ + mMaterial.setFrictionCombineMode(x); + + updateMaterial(); +} + +PxCombineMode::Enum NpMaterial::getFrictionCombineMode() const +{ + return mMaterial.getFrictionCombineMode(); +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpMaterial::setRestitutionCombineMode(PxCombineMode::Enum x) +{ + mMaterial.setRestitutionCombineMode(x); + updateMaterial(); +} + +PxCombineMode::Enum NpMaterial::getRestitutionCombineMode() const +{ + return mMaterial.getRestitutionCombineMode(); +} + +/////////////////////////////////////////////////////////////////////////////// diff --git a/PhysX_3.4/Source/PhysX/src/NpMaterial.h b/PhysX_3.4/Source/PhysX/src/NpMaterial.h new file mode 100644 index 00000000..fd2665f9 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpMaterial.h @@ -0,0 +1,122 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + + +#ifndef PX_PHYSICS_NP_MATERIAL +#define PX_PHYSICS_NP_MATERIAL + +#include "PxMaterial.h" +#include "ScMaterialCore.h" +#include "PsUserAllocated.h" +#include "CmRefCountable.h" +#include "PsUtilities.h" + +// PX_SERIALIZATION +#include "PxSerialFramework.h" +//~PX_SERIALIZATION + +namespace physx +{ + +// Compared to other objects, materials are special since they belong to the SDK and not to scenes +// (similar to meshes). That's why the NpMaterial does have direct access to the core material instead +// of having a buffered interface for it. Scenes will have copies of the SDK material table and there +// the materials will be buffered. + + +class NpMaterial : public PxMaterial, public Ps::UserAllocated, public Cm::RefCountable +{ +//= 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 + NpMaterial(PxBaseFlags baseFlags) : PxMaterial(baseFlags), Cm::RefCountable(PxEmpty), mMaterial(PxEmpty) {} + virtual void onRefCountZero(); + virtual void resolveReferences(PxDeserializationContext& context); + static NpMaterial* createObject(PxU8*& address, PxDeserializationContext& context); + static void getBinaryMetaData(PxOutputStream& stream); + void exportExtraData(PxSerializationContext&) {} + void importExtraData(PxDeserializationContext&) {} + virtual void requires(PxProcessPxBaseCallback&){} +//~PX_SERIALIZATION + NpMaterial(const Sc::MaterialCore& desc); + ~NpMaterial(); + + virtual void release(); + + virtual void acquireReference(); + virtual PxU32 getReferenceCount() const; + + virtual void setDynamicFriction(PxReal); + virtual PxReal getDynamicFriction() const; + virtual void setStaticFriction(PxReal); + virtual PxReal getStaticFriction() const; + virtual void setRestitution(PxReal); + virtual PxReal getRestitution() const; + virtual void setFlag(PxMaterialFlag::Enum flag, bool value); + virtual void setFlags(PxMaterialFlags inFlags); + virtual PxMaterialFlags getFlags() const; + virtual void setFrictionCombineMode(PxCombineMode::Enum); + virtual PxCombineMode::Enum getFrictionCombineMode() const; + virtual void setRestitutionCombineMode(PxCombineMode::Enum); + virtual PxCombineMode::Enum getRestitutionCombineMode() const; + + PX_INLINE const Sc::MaterialCore& getScMaterial() const { return mMaterial; } + PX_INLINE Sc::MaterialCore& getScMaterial() { return mMaterial; } + PX_INLINE PxU32 getHandle() const { return mMaterial.getMaterialIndex();} + PX_INLINE void setHandle(PxU32 handle) { return mMaterial.setMaterialIndex(handle);} + + PX_FORCE_INLINE static void getMaterialIndices(PxMaterial*const* materials, PxU16* materialIndices, PxU32 materialCount); + +private: + PX_INLINE void updateMaterial(); + +// PX_SERIALIZATION +public: +//~PX_SERIALIZATION + Sc::MaterialCore mMaterial; +}; + + +PX_FORCE_INLINE void NpMaterial::getMaterialIndices(PxMaterial*const* materials, PxU16* materialIndices, PxU32 materialCount) +{ + for(PxU32 i=0; i < materialCount; i++) + { + materialIndices[i] = Ps::to16((static_cast<NpMaterial*>(materials[i]))->getHandle()); + } +} + + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/NpMaterialManager.h b/PhysX_3.4/Source/PhysX/src/NpMaterialManager.h new file mode 100644 index 00000000..1d509ba1 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpMaterialManager.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 NP_MATERIALMANAGER +#define NP_MATERIALMANAGER + +#include "foundation/PxMemory.h" +#include "NpMaterial.h" +#include "CmIDPool.h" + +namespace physx +{ + class NpMaterialManager + { + public: + NpMaterialManager() + { + const PxU32 matCount = 128; + mMaterials = reinterpret_cast<NpMaterial**>(PX_ALLOC(sizeof(NpMaterial*) * matCount, "NpMaterialManager::initialise")); + mMaxMaterials = matCount; + PxMemZero(mMaterials, sizeof(NpMaterial*)*mMaxMaterials); + } + + ~NpMaterialManager() {} + + void releaseMaterials() + { + for(PxU32 i=0; i<mMaxMaterials; ++i) + { + if(mMaterials[i]) + { + const PxU32 handle = mMaterials[i]->getHandle(); + mHandleManager.freeID(handle); + mMaterials[i]->release(); + mMaterials[i] = NULL; + } + } + PX_FREE(mMaterials); + } + + bool setMaterial(NpMaterial& mat) + { + const PxU32 materialIndex = mHandleManager.getNewID(); + + if(materialIndex >= mMaxMaterials) + resize(); + + mMaterials[materialIndex] = &mat; + mat.setHandle(materialIndex); + return true; + } + + void updateMaterial(NpMaterial& mat) + { + mMaterials[mat.getHandle()] = &mat; + } + + PX_FORCE_INLINE PxU32 getNumMaterials() const + { + return mHandleManager.getNumUsedID(); + } + + void removeMaterial(NpMaterial& mat) + { + const PxU32 handle = mat.getHandle(); + if(handle != MATERIAL_INVALID_HANDLE) + { + mMaterials[handle] = NULL; + mHandleManager.freeID(handle); + } + } + + PX_FORCE_INLINE NpMaterial* getMaterial(const PxU32 index) const + { + PX_ASSERT(index < mMaxMaterials); + return mMaterials[index]; + } + + PX_FORCE_INLINE PxU32 getMaxSize() const + { + return mMaxMaterials; + } + + PX_FORCE_INLINE NpMaterial** getMaterials() const + { + return mMaterials; + } + + private: + void resize() + { + const PxU32 numMaterials = mMaxMaterials; + mMaxMaterials = mMaxMaterials*2; + + NpMaterial** mat = reinterpret_cast<NpMaterial**>(PX_ALLOC(sizeof(NpMaterial*)*mMaxMaterials, "NpMaterialManager::resize")); + PxMemZero(mat, sizeof(NpMaterial*)*mMaxMaterials); + for(PxU32 i=0; i<numMaterials; ++i) + mat[i] = mMaterials[i]; + + PX_FREE(mMaterials); + + mMaterials = mat; + } + + Cm::IDPool mHandleManager; + NpMaterial** mMaterials; + PxU32 mMaxMaterials; + }; + + class NpMaterialManagerIterator + { + public: + NpMaterialManagerIterator(const NpMaterialManager& manager) : mManager(manager), mIndex(0) + { + } + + bool getNextMaterial(NpMaterial*& np) + { + const PxU32 maxSize = mManager.getMaxSize(); + PxU32 index = mIndex; + while(index < maxSize && mManager.getMaterial(index)==NULL) + index++; + np = NULL; + if(index < maxSize) + np = mManager.getMaterial(index++); + mIndex = index; + return np!=NULL; + } + + private: + NpMaterialManagerIterator& operator=(const NpMaterialManagerIterator&); + const NpMaterialManager& mManager; + PxU32 mIndex; + }; +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/NpMetaData.cpp b/PhysX_3.4/Source/PhysX/src/NpMetaData.cpp new file mode 100644 index 00000000..531467b3 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpMetaData.cpp @@ -0,0 +1,646 @@ +// 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 "PxPhysicsSerialization.h" +#include "NpShape.h" +#include "NpShapeManager.h" +#include "NpConstraint.h" +#include "NpRigidStatic.h" +#include "NpRigidDynamic.h" +#include "NpArticulation.h" +#include "NpArticulationLink.h" +#include "NpArticulationJoint.h" +#include "NpClothFabric.h" +#include "NpCloth.h" +#include "NpAggregate.h" +#include "NpParticleFluid.h" +#include "GuConvexMesh.h" +#include "GuTriangleMesh.h" +#include "GuTriangleMeshBV4.h" +#include "GuTriangleMeshRTree.h" +#include "GuHeightField.h" + +using namespace physx; +using namespace Cm; + +/////////////////////////////////////////////////////////////////////////////// + +// PT: the offsets can be different for different templated classes so I need macros here. + +#define DefineMetaData_PxActor(x) \ + PX_DEF_BIN_METADATA_ITEM(stream, x, void, userData, PxMetaDataFlag::ePTR) + +#define DefineMetaData_NpRigidActorTemplate(x) \ + PX_DEF_BIN_METADATA_ITEM(stream, x, NpShapeManager, mShapeManager, 0) \ + PX_DEF_BIN_METADATA_ITEM(stream, x, PxU32, mIndex, 0) \ + +#define DefineMetaData_NpRigidBodyTemplate(x) \ + PX_DEF_BIN_METADATA_ITEM(stream, x, Scb::Body, mBody, 0) + +/////////////////////////////////////////////////////////////////////////////// + +static void getBinaryMetaData_PxVec3(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_CLASS(stream, PxVec3) + PX_DEF_BIN_METADATA_ITEM(stream, PxVec3, PxReal, x, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxVec3, PxReal, y, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxVec3, PxReal, z, 0) +} + +static void getBinaryMetaData_PxVec4(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_CLASS(stream, PxVec4) + PX_DEF_BIN_METADATA_ITEM(stream, PxVec4, PxReal, x, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxVec4, PxReal, y, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxVec4, PxReal, z, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxVec4, PxReal, w, 0) +} + +static void getBinaryMetaData_PxQuat(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_CLASS(stream, PxQuat) + PX_DEF_BIN_METADATA_ITEM(stream, PxQuat, PxReal, x, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxQuat, PxReal, y, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxQuat, PxReal, z, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxQuat, PxReal, w, 0) +} + +static void getBinaryMetaData_PxBounds3(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_CLASS(stream, PxBounds3) + PX_DEF_BIN_METADATA_ITEM(stream, PxBounds3, PxVec3, minimum, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxBounds3, PxVec3, maximum, 0) +} + +static void getBinaryMetaData_PxTransform(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_CLASS(stream, PxTransform) + PX_DEF_BIN_METADATA_ITEM(stream, PxTransform, PxQuat, q, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxTransform, PxVec3, p, 0) +} + +static void getBinaryMetaData_PxMat33(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_CLASS(stream, PxMat33) + PX_DEF_BIN_METADATA_ITEM(stream, PxMat33, PxVec3, column0, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxMat33, PxVec3, column1, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxMat33, PxVec3, column2, 0) +} + +namespace +{ + class ShadowBitMap : public BitMap + { + public: + static void getBinaryMetaData(PxOutputStream& stream_) + { + PX_DEF_BIN_METADATA_CLASS(stream_, ShadowBitMap) + PX_DEF_BIN_METADATA_ITEM(stream_, ShadowBitMap, PxU32, mMap, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream_, ShadowBitMap, PxU32, mWordCount, 0) + PX_DEF_BIN_METADATA_ITEM(stream_, ShadowBitMap, Allocator, mAllocator, 0) + PX_DEF_BIN_METADATA_ITEMS_AUTO(stream_, ShadowBitMap, PxU8, mPadding, PxMetaDataFlag::ePADDING) + + //------ Extra-data ------ + + // mMap + PX_DEF_BIN_METADATA_EXTRA_ARRAY(stream_, ShadowBitMap, PxU32, mWordCount, PX_SERIAL_ALIGN, PxMetaDataFlag::eCOUNT_MASK_MSB) + } + }; +} + +static void getBinaryMetaData_BitMap(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_TYPEDEF(stream, Allocator, PxU8) + ShadowBitMap::getBinaryMetaData(stream); + PX_DEF_BIN_METADATA_TYPEDEF(stream, BitMap, ShadowBitMap) +} + +static void getBinaryMetaData_PxPlane(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_CLASS(stream, PxPlane) + PX_DEF_BIN_METADATA_ITEM(stream, PxPlane, PxVec3, n, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxPlane, PxReal, d, 0) +} + +static void getBinaryMetaData_PxConstraintInvMassScale(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_CLASS(stream, PxConstraintInvMassScale) + + PX_DEF_BIN_METADATA_ITEM(stream, PxConstraintInvMassScale, PxReal, linear0, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxConstraintInvMassScale, PxReal, angular0, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxConstraintInvMassScale, PxReal, linear1, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxConstraintInvMassScale, PxReal, angular1, 0) +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpActor::getBinaryMetaData(PxOutputStream& stream) +{ + // 12 bytes + PX_DEF_BIN_METADATA_CLASS(stream, NpActor) + + PX_DEF_BIN_METADATA_ITEM(stream, NpActor, char, mName, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, NpActor, NpConnectorArray, mConnectorArray, PxMetaDataFlag::ePTR) + +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpMaterial::getBinaryMetaData(PxOutputStream& stream) +{ +// 76 => 72 => 64 bytes + PX_DEF_BIN_METADATA_VCLASS(stream, NpMaterial) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, NpMaterial, PxBase) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, NpMaterial, RefCountable) + + PX_DEF_BIN_METADATA_ITEM(stream, NpMaterial, void, userData, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, NpMaterial, MaterialCore, mMaterial, 0) +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpConstraint::getBinaryMetaData(PxOutputStream& stream) +{ +// 136 => 140 => 144 => 128 bytes + PX_DEF_BIN_METADATA_VCLASS(stream, NpConstraint) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, NpConstraint, PxBase) + + PX_DEF_BIN_METADATA_ITEM(stream, NpConstraint, PxRigidActor, mActor0, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, NpConstraint, PxRigidActor, mActor1, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, NpConstraint, Scb::Constraint, mConstraint, 0) + PX_DEF_BIN_METADATA_ITEM(stream, NpConstraint, bool, mIsDirty, 0) + PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, NpConstraint, bool, mPaddingFromBool, PxMetaDataFlag::ePADDING) +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpShapeManager::getBinaryMetaData(PxOutputStream& stream) +{ +// 8 bytes + PX_DEF_BIN_METADATA_CLASS(stream, NpShapeManager) + PX_DEF_BIN_METADATA_ITEM(stream, NpShapeManager, PtrTable, mShapes, 0) + PX_DEF_BIN_METADATA_ITEM(stream, NpShapeManager, PtrTable, mSceneQueryData, 0) + PX_DEF_BIN_METADATA_ITEM(stream, NpShapeManager, Sq::PruningStructure, mPruningStructure, PxMetaDataFlag::ePTR) +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpShape::getBinaryMetaData(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_TYPEDEF(stream, NpInternalShapeFlags, PxU8) + +// 208 => 224 => 208 => 192 bytes + PX_DEF_BIN_METADATA_VCLASS(stream, NpShape) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, NpShape, PxBase) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, NpShape, RefCountable) + + // PxShape + PX_DEF_BIN_METADATA_ITEM(stream, NpShape, void, userData, PxMetaDataFlag::ePTR) + + // NpShape + PX_DEF_BIN_METADATA_ITEM(stream, NpShape, PxRigidActor, mActor, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, NpShape, Scb::Shape, mShape, 0) + PX_DEF_BIN_METADATA_ITEM(stream, NpShape, char, mName, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, NpShape, PxI32, mExclusiveAndActorCount, 0) + + + PX_DEF_BIN_METADATA_EXTRA_NAME(stream, NpShape, mName, 0) +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpRigidStatic::getBinaryMetaData(PxOutputStream& stream) +{ +// 124 => 128 => 124 => 108 => 96 bytes + PX_DEF_BIN_METADATA_VCLASS(stream, NpRigidStatic) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, NpRigidStatic, PxBase) +// PX_DEF_BIN_METADATA_BASE_CLASS(stream, NpRigidStatic, NpRigidStaticT) // ### ??? + PX_DEF_BIN_METADATA_BASE_CLASS(stream, NpRigidStatic, NpActor) + + DefineMetaData_PxActor(NpRigidStatic) + DefineMetaData_NpRigidActorTemplate(NpRigidStatic) + + // NpRigidStatic + PX_DEF_BIN_METADATA_ITEM(stream, NpRigidStatic, Scb::RigidStatic, mRigidStatic, 0) + + //------ Extra-data ------ + + PX_DEF_BIN_METADATA_EXTRA_ITEM(stream, NpRigidStatic, NpConnectorArray, mConnectorArray, PX_SERIAL_ALIGN) + PX_DEF_BIN_METADATA_EXTRA_NAME(stream, NpRigidStatic, mName, 0) +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpConnector::getBinaryMetaData(PxOutputStream& stream) +{ +// 8 bytes + PX_DEF_BIN_METADATA_CLASS(stream, NpConnector) + PX_DEF_BIN_METADATA_ITEM(stream, NpConnector, PxU8, mType, 0) + PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, NpConnector, PxU8, mPadding, PxMetaDataFlag::ePADDING) + PX_DEF_BIN_METADATA_ITEM(stream, NpConnector, PxBase, mObject, PxMetaDataFlag::ePTR) +} + +void NpConnectorArray::getBinaryMetaData(PxOutputStream& stream) +{ +// 48 bytes + PX_DEF_BIN_METADATA_CLASS(stream, NpConnectorArray) + PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, NpConnectorArray, NpConnector, mBuffer, 0) + PX_DEF_BIN_METADATA_ITEM(stream, NpConnectorArray, bool, mBufferUsed, 0) + // PT: OMG this is so painful... I can't put the padding explicitly in the template + { PxMetaDataEntry tmp = {"char", "mPadding", 1 + PxU32(PX_OFFSET_OF_RT(NpConnectorArray, mBufferUsed)), 3, 3, 0, PxMetaDataFlag::ePADDING, 0}; PX_STORE_METADATA(stream, tmp); } + PX_DEF_BIN_METADATA_ITEM(stream, NpConnectorArray, NpConnector, mData, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, NpConnectorArray, PxU32, mSize, 0) + PX_DEF_BIN_METADATA_ITEM(stream, NpConnectorArray, PxU32, mCapacity, 0) + + //------ Extra-data ------ + + PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, NpConnectorArray, NpConnector, mBufferUsed, mCapacity, PxMetaDataFlag::eCONTROL_FLIP|PxMetaDataFlag::eCOUNT_MASK_MSB, 0) +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpRigidDynamic::getBinaryMetaData(PxOutputStream& stream) +{ +// 368 => 352 => 304 => 288 bytes + PX_DEF_BIN_METADATA_VCLASS(stream, NpRigidDynamic) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, NpRigidDynamic, PxBase) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, NpRigidDynamic, NpActor) + + DefineMetaData_PxActor(NpRigidDynamic) + DefineMetaData_NpRigidActorTemplate(NpRigidDynamic) + DefineMetaData_NpRigidBodyTemplate(NpRigidDynamic) + + // NpRigidDynamic + + //------ Extra-data ------ + +// Extra data: +// - inline array from shape manager +// - optional constraint array + +// PX_DEF_BIN_METADATA_ITEM(stream,NpRigidDynamic, NpShapeManager, mShapeManager.mShapes, 0) + +/* + virtual void exportExtraData(PxOutputStream& stream) + { + mShapeManager.exportExtraData(stream); + ActorTemplateClass::exportExtraData(stream); + } +void NpActorTemplate<APIClass, LeafClass>::exportExtraData(PxOutputStream& stream) +{ + if(mConnectorArray) + { + stream.storeBuffer(mConnectorArray, sizeof(NpConnectorArray) + mConnectorArray->exportExtraData(stream); + } +} +*/ + PX_DEF_BIN_METADATA_EXTRA_ITEM(stream, NpRigidDynamic, NpConnectorArray, mConnectorArray, PX_SERIAL_ALIGN) +//### missing inline array data here... only works for "buffered" arrays so far +/* + Big issue: we can't output the "offset of" the inline array within the class, since the inline array itself is extra-data. But we need to read + the array itself to know if it's inline or not (the "is buffered" bool). So we need to read from the extra data! +*/ + +/* +[17:41:39] Gordon Yeoman nvidia: PxsBodyCore need to be 16-byte aligned for spu. If it is 128-byte aligned then that is a mistake. Feel free to change it to 16. +*/ + PX_DEF_BIN_METADATA_EXTRA_NAME(stream, NpRigidDynamic, mName, 0) +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpArticulationLinkArray::getBinaryMetaData(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_CLASS(stream, NpArticulationLinkArray) + PX_DEF_BIN_METADATA_ITEMS(stream, NpArticulationLinkArray, NpArticulationLink, mBuffer, PxMetaDataFlag::ePTR, 4) + PX_DEF_BIN_METADATA_ITEM(stream, NpArticulationLinkArray, bool, mBufferUsed, 0) + // PT: OMG this is so painful... I can't put the padding explicitely in the template + { PxMetaDataEntry tmp = {"char", "mPadding", 1 + PxU32(PX_OFFSET_OF_RT(NpArticulationLinkArray, mBufferUsed)), 3, 3, 0, PxMetaDataFlag::ePADDING, 0}; PX_STORE_METADATA(stream, tmp); } + PX_DEF_BIN_METADATA_ITEM(stream, NpArticulationLinkArray, NpArticulationLink, mData, PxMetaDataFlag::ePTR) // ### + PX_DEF_BIN_METADATA_ITEM(stream, NpArticulationLinkArray, PxU32, mSize, 0) + PX_DEF_BIN_METADATA_ITEM(stream, NpArticulationLinkArray, PxU32, mCapacity, 0) + + //------ Extra-data ------ + + PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, NpArticulationLinkArray, NpArticulationLink, mBufferUsed, mCapacity, PxMetaDataFlag::eCONTROL_FLIP|PxMetaDataFlag::eCOUNT_MASK_MSB|PxMetaDataFlag::ePTR, 0) +} + +void NpArticulation::getBinaryMetaData(PxOutputStream& stream) +{ +// 92 => 108 => 104 => 116 => 120 => 104 bytes + PX_DEF_BIN_METADATA_VCLASS(stream, NpArticulation) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, NpArticulation, PxBase) + + // PxArticulation + PX_DEF_BIN_METADATA_ITEM(stream, NpArticulation, void, userData, PxMetaDataFlag::ePTR) + + // NpArticulation + PX_DEF_BIN_METADATA_ITEM(stream, NpArticulation, Scb::Articulation, mArticulation, 0) + PX_DEF_BIN_METADATA_ITEM(stream, NpArticulation, NpArticulationLinkArray, mArticulationLinks, 0) + PX_DEF_BIN_METADATA_ITEM(stream, NpArticulation, NpAggregate, mAggregate, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, NpArticulation, char, mName, PxMetaDataFlag::ePTR) + + PX_DEF_BIN_METADATA_EXTRA_NAME(stream, NpArticulation, mName, 0) +} + +void NpArticulationLink::getBinaryMetaData(PxOutputStream& stream) +{ +// 400 (!) => 352 => 336 bytes + PX_DEF_BIN_METADATA_VCLASS(stream, NpArticulationLink) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, NpArticulationLink, PxBase) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, NpArticulationLink, NpActor) + + DefineMetaData_PxActor(NpArticulationLink) + DefineMetaData_NpRigidActorTemplate(NpArticulationLink) + DefineMetaData_NpRigidBodyTemplate(NpArticulationLink) + + // NpArticulationLink + PX_DEF_BIN_METADATA_ITEM(stream, NpArticulationLink, NpArticulation, mRoot, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, NpArticulationLink, NpArticulationJoint, mInboundJoint, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, NpArticulationLink, NpArticulationLink, mParent, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, NpArticulationLink, NpArticulationLinkArray, mChildLinks, 0) +#ifdef EXPLICIT_PADDING_METADATA + PX_DEF_BIN_METADATA_ITEM(stream, NpArticulationLink, PxU32, mPadding, PxMetaDataFlag::ePADDING) +#endif + + //------ Extra-data ------ + + PX_DEF_BIN_METADATA_EXTRA_ITEM(stream, NpArticulationLink, NpConnectorArray, mConnectorArray, PX_SERIAL_ALIGN) + PX_DEF_BIN_METADATA_EXTRA_NAME(stream, NpArticulationLink, mName, 0) +} + +void NpArticulationJoint::getBinaryMetaData(PxOutputStream& stream) +{ +// 184 => 200 => 192 => 224 => 208 bytes + PX_DEF_BIN_METADATA_VCLASS(stream, NpArticulationJoint) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, NpArticulationJoint, PxBase) + + PX_DEF_BIN_METADATA_ITEM(stream, NpArticulationJoint, Scb::ArticulationJoint, mJoint, 0) + PX_DEF_BIN_METADATA_ITEM(stream, NpArticulationJoint, NpArticulationLink, mParent, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, NpArticulationJoint, NpArticulationLink, mChild, PxMetaDataFlag::ePTR) + +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpAggregate::getBinaryMetaData(PxOutputStream& stream) +{ +// 36 => 56 => 40 bytes + PX_DEF_BIN_METADATA_VCLASS(stream, NpAggregate) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, NpAggregate, PxBase) + + PX_DEF_BIN_METADATA_ITEM(stream, NpAggregate, Scb::Aggregate, mAggregate, 0) + PX_DEF_BIN_METADATA_ITEM(stream, NpAggregate, PxU32, mNbActors, 0) + PX_DEF_BIN_METADATA_ITEM(stream, NpAggregate, PxActor, mActors, PxMetaDataFlag::ePTR) + + //------ Extra-data ------ + + // mActors + PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, NpAggregate, PxActor, mActors, mNbActors, PxMetaDataFlag::ePTR, PX_SERIAL_ALIGN) +} + +/////////////////////////////////////////////////////////////////////////////// +#if PX_USE_CLOTH_API +void NpClothFabric::getBinaryMetaData(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_VCLASS(stream, NpClothFabric) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, NpClothFabric, PxBase) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, NpClothFabric, RefCountable) + + PX_DEF_BIN_METADATA_ITEM(stream, NpClothFabric, Sc::ClothFabricCore, mFabric, 0) +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpCloth::getBinaryMetaData(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_VCLASS(stream, NpCloth) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, NpCloth, PxBase) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, NpCloth, NpActor) + + DefineMetaData_PxActor(NpCloth) + + PX_DEF_BIN_METADATA_ITEM(stream, NpCloth, Scb::Cloth, mCloth, 0) + PX_DEF_BIN_METADATA_ITEM(stream, NpCloth, NpClothFabric, mClothFabric, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEMS(stream, NpCloth, PxU8, mParticleData, PxMetaDataFlag::ePADDING, sizeof(NpClothParticleData)) +} + +#endif // PX_USE_CLOTH_API + +/////////////////////////////////////////// + +#if PX_USE_PARTICLE_SYSTEM_API + +void NpParticleSystem::getBinaryMetaData(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_VCLASS(stream, NpParticleSystem) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, NpParticleSystem, PxBase) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, NpParticleSystem, NpActor) + + DefineMetaData_PxActor(NpParticleSystem) + + PX_DEF_BIN_METADATA_ITEM(stream, NpParticleFluid, Scb::ParticleSystem, mParticleSystem, 0) +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpParticleFluid::getBinaryMetaData(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_VCLASS(stream, NpParticleFluid) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, NpParticleFluid, PxBase) + PX_DEF_BIN_METADATA_BASE_CLASS(stream, NpParticleFluid, NpActor) + + DefineMetaData_PxActor(NpParticleFluid) + + PX_DEF_BIN_METADATA_ITEM(stream, NpParticleFluid, Scb::ParticleSystem, mParticleSystem, 0) +} + +#endif // PX_USE_PARTICLE_SYSTEM_API + +/////////////////////////////////////////////////////////////////////////////// + +static void getBinaryMetaData_PxMeshScale(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_CLASS(stream, PxMeshScale) + PX_DEF_BIN_METADATA_ITEM(stream, PxMeshScale, PxVec3, scale, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxMeshScale, PxQuat, rotation, 0) +} + +#if PX_USE_PARTICLE_SYSTEM_API + +static void getBinaryMetaData_ParticleSystemParameter(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_CLASS(stream, Pt::ParticleSystemParameter) + + PX_DEF_BIN_METADATA_ITEM(stream, Pt::ParticleSystemParameter, PxReal, restParticleDistance, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Pt::ParticleSystemParameter, PxReal, kernelRadiusMultiplier, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Pt::ParticleSystemParameter, PxReal, viscosity, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Pt::ParticleSystemParameter, PxReal, surfaceTension, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Pt::ParticleSystemParameter, PxReal, fadeInTime, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Pt::ParticleSystemParameter, PxU32, flags, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Pt::ParticleSystemParameter, PxU32, packetSizeMultiplierLog2, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Pt::ParticleSystemParameter, PxReal, restitution, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Pt::ParticleSystemParameter, PxReal, dynamicFriction, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Pt::ParticleSystemParameter, PxReal, staticFriction, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Pt::ParticleSystemParameter, PxReal, restDensity, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Pt::ParticleSystemParameter, PxReal, damping, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Pt::ParticleSystemParameter, PxReal, stiffness, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Pt::ParticleSystemParameter, PxReal, maxMotionDistance, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Pt::ParticleSystemParameter, PxReal, restOffset, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Pt::ParticleSystemParameter, PxReal, contactOffset, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Pt::ParticleSystemParameter, PxPlane,projectionPlane, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Pt::ParticleSystemParameter, PxU16, particleReadDataFlags, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Pt::ParticleSystemParameter, PxU32, noiseCounter, 0) +} + +#endif // PX_USE_PARTICLE_SYSTEM_API + +/////////////////////////////////////////////////////////////////////////////// +namespace physx +{ +void getBinaryMetaData_PxBase(PxOutputStream& stream) +{ + // 8 bytes + PX_DEF_BIN_METADATA_TYPEDEF(stream, PxBaseFlags, PxU16) + PX_DEF_BIN_METADATA_TYPEDEF(stream, PxType, PxU16) + PX_DEF_BIN_METADATA_VCLASS(stream, PxBase) + PX_DEF_BIN_METADATA_ITEM(stream, PxBase, PxType, mConcreteType, 0) + PX_DEF_BIN_METADATA_ITEM(stream, PxBase, PxBaseFlags, mBaseFlags, 0) +} +} +void RefCountable::getBinaryMetaData(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_VCLASS(stream, RefCountable) + PX_DEF_BIN_METADATA_ITEM(stream, RefCountable, PxI32, mRefCount, 0) +} + +static void getFoundationMetaData(PxOutputStream& stream) +{ + PX_DEF_BIN_METADATA_TYPEDEF(stream, PxU8, char) + PX_DEF_BIN_METADATA_TYPEDEF(stream, PxI8, char) + PX_DEF_BIN_METADATA_TYPEDEF(stream, PxU16, short) + PX_DEF_BIN_METADATA_TYPEDEF(stream, PxI16, short) + PX_DEF_BIN_METADATA_TYPEDEF(stream, PxU32, int) + PX_DEF_BIN_METADATA_TYPEDEF(stream, PxI32, int) + PX_DEF_BIN_METADATA_TYPEDEF(stream, PxReal, float) + + getBinaryMetaData_PxVec3(stream); + getBinaryMetaData_PxVec4(stream); + getBinaryMetaData_PxQuat(stream); + getBinaryMetaData_PxBounds3(stream); + getBinaryMetaData_PxTransform(stream); + getBinaryMetaData_PxMat33(stream); + getBinaryMetaData_BitMap(stream); + Cm::PtrTable::getBinaryMetaData(stream); + getBinaryMetaData_PxPlane(stream); + getBinaryMetaData_PxConstraintInvMassScale(stream); + + getBinaryMetaData_PxBase(stream); + RefCountable::getBinaryMetaData(stream); +} + +/////////////////////////////////////////////////////////////////////////////// + +void PxGetPhysicsBinaryMetaData(PxOutputStream& stream) +{ + getFoundationMetaData(stream); + + getBinaryMetaData_PxMeshScale(stream); +#if PX_USE_PARTICLE_SYSTEM_API + getBinaryMetaData_ParticleSystemParameter(stream); +#endif + + MaterialIndicesStruct::getBinaryMetaData(stream); + Gu::GeometryUnion::getBinaryMetaData(stream); + Gu::ConvexMesh::getBinaryMetaData(stream); + Gu::TriangleMesh::getBinaryMetaData(stream); + Gu::RTreeTriangleMesh::getBinaryMetaData(stream); + Gu::BV4TriangleMesh::getBinaryMetaData(stream); + Gu::HeightField::getBinaryMetaData(stream); + + Sc::ActorCore::getBinaryMetaData(stream); + Sc::RigidCore::getBinaryMetaData(stream); + Sc::StaticCore::getBinaryMetaData(stream); + Sc::BodyCore::getBinaryMetaData(stream); + Sc::MaterialCore::getBinaryMetaData(stream); + Sc::ShapeCore::getBinaryMetaData(stream); + Sc::ConstraintCore::getBinaryMetaData(stream); + Sc::ArticulationCore::getBinaryMetaData(stream); + Sc::ArticulationJointCore::getBinaryMetaData(stream); +#if PX_USE_CLOTH_API + Sc::ClothFabricCore::getBinaryMetaData(stream); + Sc::ClothCore::getBinaryMetaData(stream); +#endif +#if PX_USE_PARTICLE_SYSTEM_API + Sc::ParticleSystemCore::getBinaryMetaData(stream); +#endif + + Scb::Base::getBinaryMetaData(stream); + Scb::Actor::getBinaryMetaData(stream); + Scb::RigidObject::getBinaryMetaData(stream); + Scb::RigidStatic::getBinaryMetaData(stream); + Scb::Body::getBinaryMetaData(stream); + Scb::Shape::getBinaryMetaData(stream); + Scb::Constraint::getBinaryMetaData(stream); + Scb::Articulation::getBinaryMetaData(stream); + Scb::ArticulationJoint::getBinaryMetaData(stream); + Scb::Aggregate::getBinaryMetaData(stream); +#if PX_USE_CLOTH_API + Scb::Cloth::getBinaryMetaData(stream); +#endif +#if PX_USE_PARTICLE_SYSTEM_API + Scb::ParticleSystem::getBinaryMetaData(stream); +#endif + + NpConnector::getBinaryMetaData(stream); + NpConnectorArray::getBinaryMetaData(stream); + NpActor::getBinaryMetaData(stream); + NpMaterial::getBinaryMetaData(stream); // NP_MATERIAL + NpRigidDynamic::getBinaryMetaData(stream); // NP_RIGID_DYNAMIC + NpRigidStatic::getBinaryMetaData(stream); // NP_RIGID_STATIC + NpShape::getBinaryMetaData(stream); // NP_SHAPE + NpConstraint::getBinaryMetaData(stream); // NP_CONSTRAINT + NpArticulation::getBinaryMetaData(stream); // NP_ARTICULATION + NpArticulationLink::getBinaryMetaData(stream); // NP_ARTICULATION_LINK + NpArticulationJoint::getBinaryMetaData(stream); // NP_ARTICULATION_JOINT + NpArticulationLinkArray::getBinaryMetaData(stream); + NpShapeManager::getBinaryMetaData(stream); + NpAggregate::getBinaryMetaData(stream); // NP_AGGREGATE +#if PX_USE_CLOTH_API + NpClothFabric::getBinaryMetaData(stream); + NpCloth::getBinaryMetaData(stream); +#endif + +#if PX_USE_PARTICLE_SYSTEM_API + NpParticleSystem::getBinaryMetaData(stream); + NpParticleFluid::getBinaryMetaData(stream); +#endif +} diff --git a/PhysX_3.4/Source/PhysX/src/NpPhysics.cpp b/PhysX_3.4/Source/PhysX/src/NpPhysics.cpp new file mode 100644 index 00000000..f2397d90 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpPhysics.cpp @@ -0,0 +1,893 @@ +// 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 "NpPhysics.h" + +// PX_SERIALIZATION +#include "foundation/PxProfiler.h" +#include "foundation/PxIO.h" +#include "foundation/PxErrorCallback.h" +#include "PxPhysicsVersion.h" +#include "CmCollection.h" +#include "CmUtils.h" +#include "NpClothFabric.h" +#include "NpCloth.h" +#include "NpParticleSystem.h" +#include "NpParticleFluid.h" +#include "NpRigidStatic.h" +#include "NpRigidDynamic.h" +#include "NpArticulation.h" +#include "NpArticulationLink.h" +#include "NpArticulationJoint.h" +#include "NpMaterial.h" +#include "GuHeightFieldData.h" +#include "GuHeightField.h" +#include "GuConvexMesh.h" +#include "GuTriangleMesh.h" +#include "PsIntrinsics.h" +#include "PxTolerancesScale.h" +#include "PxvGlobals.h" // dynamic registration of HFs & articulations in LL +#include "GuOverlapTests.h" // dynamic registration of HFs in Gu +#include "PxDeletionListener.h" +#include "PxPhysicsSerialization.h" +#include "PsString.h" +#include "PvdPhysicsClient.h" +#include "SqPruningStructure.h" + +//~PX_SERIALIZATION + +#if PX_USE_PARTICLE_SYSTEM_API +#include "PtContext.h" +#endif + +#include "NpFactory.h" + + +#if PX_USE_CLOTH_API +#include "NpCloth.h" +#endif + +using namespace physx; +using namespace Cm; + +bool NpPhysics::apiReentryLock = false; +NpPhysics* NpPhysics::mInstance = NULL; +PxU32 NpPhysics::mRefCount = 0; + +#if PX_CHECKED +bool NpPhysics::mHeightFieldsRegistered = false; //just for error checking +#endif + + + +NpPhysics::NpPhysics(const PxTolerancesScale& scale, const PxvOffsetTable& pxvOffsetTable, bool trackOutstandingAllocations, + physx::pvdsdk::PsPvd* pvd) : + mSceneArray(PX_DEBUG_EXP("physicsSceneArray")) + , mSceneRunning(NULL) + , mPhysics(scale, pxvOffsetTable) + , mDeletionListenersExist(false) +#if PX_SUPPORT_GPU_PHYSX + , mNbRegisteredGpuClients(0) + , mPhysicsGpu(*this) +#endif +{ + + PX_UNUSED(trackOutstandingAllocations); + + //mMasterMaterialTable.reserve(10); + +#if PX_SUPPORT_PVD + mPvd = pvd; + if(pvd) + { + mPvdPhysicsClient = PX_NEW(Vd::PvdPhysicsClient)(mPvd); + shdfnd::getFoundation().registerErrorCallback(*mPvdPhysicsClient); + shdfnd::getFoundation().registerAllocationListener(*mPvd); + } + else + { + mPvdPhysicsClient = NULL; + } +#else + PX_UNUSED(pvd); +#endif +} + +NpPhysics::~NpPhysics() +{ + // Release all scenes in case the user didn't do it + PxU32 nbScenes = mSceneArray.size(); + NpScene** scenes = mSceneArray.begin(); + for(PxU32 i=0;i<nbScenes;i++) + PX_DELETE_AND_RESET(scenes[i]); + mSceneArray.clear(); + + //PxU32 matCount = mMasterMaterialTable.size(); + //while (mMasterMaterialTable.size() > 0) + //{ + // // It's done this way since the material destructor removes the material from the table and adjusts indices + + // PX_ASSERT(mMasterMaterialTable[0]->getRefCount() == 1); + // mMasterMaterialTable[0]->decRefCount(); + //} + //mMasterMaterialTable.clear(); + + mMasterMaterialManager.releaseMaterials(); + +#if PX_SUPPORT_PVD + if(mPvd) + { + mPvdPhysicsClient->destroyPvdInstance(this); + mPvd->removeClient(mPvdPhysicsClient); + shdfnd::getFoundation().deregisterErrorCallback(*mPvdPhysicsClient); + PX_DELETE_AND_RESET(mPvdPhysicsClient); + shdfnd::getFoundation().deregisterAllocationListener(*mPvd); + } +#endif + + const DeletionListenerMap::Entry* delListenerEntries = mDeletionListenerMap.getEntries(); + const PxU32 delListenerEntryCount = mDeletionListenerMap.size(); + for(PxU32 i=0; i < delListenerEntryCount; i++) + { + PX_DELETE(delListenerEntries[i].second); + } + mDeletionListenerMap.clear(); +} + +void NpPhysics::initOffsetTables(PxvOffsetTable& pxvOffsetTable) +{ + // init offset tables for Pxs/Sc/Scb/Px conversions + { + Sc::OffsetTable& offsetTable = Sc::gOffsetTable; + offsetTable.scRigidStatic2PxActor = -reinterpret_cast<ptrdiff_t>(&(reinterpret_cast<NpRigidStatic*>(0)->getScbRigidStaticFast())) - static_cast<ptrdiff_t>(Scb::RigidStatic::getScOffset()); + offsetTable.scRigidDynamic2PxActor = -reinterpret_cast<ptrdiff_t>(&(reinterpret_cast<NpRigidDynamic*>(0)->getScbBodyFast())) - static_cast<ptrdiff_t>(Scb::Body::getScOffset()); + offsetTable.scArticulationLink2PxActor = -reinterpret_cast<ptrdiff_t>(&(reinterpret_cast<NpArticulationLink*>(0)->getScbBodyFast())) - static_cast<ptrdiff_t>(Scb::Body::getScOffset()); + offsetTable.scArticulation2Px = -reinterpret_cast<ptrdiff_t>(&(reinterpret_cast<NpArticulation*>(0)->getScbArticulation())) - static_cast<ptrdiff_t>(Scb::Articulation::getScOffset()); + offsetTable.scConstraint2Px = -reinterpret_cast<ptrdiff_t>(&(reinterpret_cast<NpConstraint*>(0)->getScbConstraint())) - static_cast<ptrdiff_t>(Scb::Constraint::getScOffset()); + offsetTable.scShape2Px = -reinterpret_cast<ptrdiff_t>(&(reinterpret_cast<NpShape*>(0)->getScbShape())) - static_cast<ptrdiff_t>(Scb::Shape::getScOffset()); +#if PX_USE_PARTICLE_SYSTEM_API + offsetTable.scParticleSystem2PxParticleFluid = -reinterpret_cast<ptrdiff_t>(&(reinterpret_cast<NpParticleFluid*>(0)->getScbParticleSystem())) - static_cast<ptrdiff_t>(Scb::ParticleSystem::getScOffset()); + offsetTable.scParticleSystem2Px = -reinterpret_cast<ptrdiff_t>(&(reinterpret_cast<NpParticleSystem*>(0)->getScbParticleSystem())) - static_cast<ptrdiff_t>(Scb::ParticleSystem::getScOffset()); +#endif +#if PX_USE_CLOTH_API + offsetTable.scCloth2Px = -reinterpret_cast<ptrdiff_t>(&(reinterpret_cast<NpCloth*>(0)->getScbCloth())) - static_cast<ptrdiff_t>(Scb::Cloth::getScOffset()); +#endif + for(PxU32 i=0;i<PxActorType::eACTOR_COUNT;i++) + offsetTable.scCore2PxActor[i] = 0; + offsetTable.scCore2PxActor[PxActorType::eRIGID_STATIC] = offsetTable.scRigidStatic2PxActor; + offsetTable.scCore2PxActor[PxActorType::eRIGID_DYNAMIC] = offsetTable.scRigidDynamic2PxActor; + offsetTable.scCore2PxActor[PxActorType::eARTICULATION_LINK] = offsetTable.scArticulationLink2PxActor; + } + { + Sq::OffsetTable& offsetTable = Sq::gOffsetTable; + // init pxActorToScbActor + for(PxU32 i=0;i<PxConcreteType::ePHYSX_CORE_COUNT;i++) + offsetTable.pxActorToScbActor[i] = 0; + ptrdiff_t addr = 0x100; // casting the null ptr takes a special-case code path, which we don't want + PxActor* n = reinterpret_cast<PxActor*>(addr); + offsetTable.pxActorToScbActor[PxConcreteType::eRIGID_STATIC] = reinterpret_cast<ptrdiff_t>(&static_cast<NpRigidStatic*>(n)->getScbActorFast()) - addr; + offsetTable.pxActorToScbActor[PxConcreteType::eRIGID_DYNAMIC] = reinterpret_cast<ptrdiff_t>(&static_cast<NpRigidDynamic*>(n)->getScbActorFast()) - addr; +#if PX_USE_PARTICLE_SYSTEM_API + offsetTable.pxActorToScbActor[PxConcreteType::ePARTICLE_SYSTEM] = reinterpret_cast<ptrdiff_t>(&static_cast<NpParticleSystem*>(n)->getScbActor()) - addr; + offsetTable.pxActorToScbActor[PxConcreteType::ePARTICLE_FLUID] = reinterpret_cast<ptrdiff_t>(&static_cast<NpParticleFluid*>(n)->getScbActor()) - addr; +#endif + offsetTable.pxActorToScbActor[PxConcreteType::eARTICULATION_LINK] = reinterpret_cast<ptrdiff_t>(&static_cast<NpArticulationLink*>(n)->getScbActorFast()) - addr; +#if PX_USE_CLOTH_API + offsetTable.pxActorToScbActor[PxConcreteType::eCLOTH] = reinterpret_cast<ptrdiff_t>(&static_cast<NpCloth*>(n)->getScbCloth()) - addr; +#endif + // init scb2sc + for(PxU32 i=0;i<ScbType::TYPE_COUNT;i++) + offsetTable.scbToSc[i] = 0; + ptrdiff_t staticOffset = static_cast<ptrdiff_t>(Scb::RigidStatic::getScOffset()); + ptrdiff_t bodyOffset = static_cast<ptrdiff_t>(Scb::Body::getScOffset()); + offsetTable.scbToSc[ScbType::RIGID_STATIC] = staticOffset; + offsetTable.scbToSc[ScbType::BODY] = bodyOffset; + offsetTable.scbToSc[ScbType::BODY_FROM_ARTICULATION_LINK] = bodyOffset; +#if PX_USE_PARTICLE_SYSTEM_API + offsetTable.scbToSc[ScbType::PARTICLE_SYSTEM] = static_cast<ptrdiff_t>(Scb::ParticleSystem::getScOffset()); +#endif +#if PX_USE_CLOTH_API + offsetTable.scbToSc[ScbType::CLOTH] = static_cast<ptrdiff_t>(Scb::Cloth::getScOffset()); +#endif + } + { + Sc::OffsetTable& scOffsetTable = Sc::gOffsetTable; + pxvOffsetTable.pxsShapeCore2PxShape = scOffsetTable.scShape2Px - reinterpret_cast<ptrdiff_t>(&static_cast<Sc::ShapeCore*>(0)->getCore()); + pxvOffsetTable.pxsRigidCore2PxRigidBody = scOffsetTable.scRigidDynamic2PxActor - reinterpret_cast<ptrdiff_t>(&static_cast<Sc::BodyCore*>(0)->getCore()); + pxvOffsetTable.pxsRigidCore2PxRigidStatic = scOffsetTable.scRigidStatic2PxActor - reinterpret_cast<ptrdiff_t>(&static_cast<Sc::StaticCore*>(0)->getCore()); + } +} + +NpPhysics* NpPhysics::createInstance(PxU32 version, PxFoundation& foundation, const PxTolerancesScale& scale, bool trackOutstandingAllocations, + physx::pvdsdk::PsPvd* pvd) +{ + PX_UNUSED(foundation); + + if (version!=PX_PHYSICS_VERSION) + { + char buffer[256]; + Ps::snprintf(buffer, 256, "Wrong version: PhysX version is 0x%08x, tried to create 0x%08x", PX_PHYSICS_VERSION, version); + foundation.getErrorCallback().reportError(PxErrorCode::eINVALID_PARAMETER, buffer, __FILE__, __LINE__); + return NULL; + } + + if (!scale.isValid()) + { + foundation.getErrorCallback().reportError(PxErrorCode::eINVALID_PARAMETER, "Scale invalid.\n", __FILE__, __LINE__); + return NULL; + } + + if(0 == mRefCount) + { + PX_ASSERT(static_cast<Ps::Foundation*>(&foundation) == &Ps::Foundation::getInstance()); + + Ps::Foundation::incRefCount(); + + // init offset tables for Pxs/Sc/Scb/Px conversions + PxvOffsetTable pxvOffsetTable; + initOffsetTables(pxvOffsetTable); + + //SerialFactory::createInstance(); + mInstance = PX_NEW (NpPhysics)(scale, pxvOffsetTable, trackOutstandingAllocations, pvd); + NpFactory::createInstance(); + +#if PX_SUPPORT_PVD + if(pvd) + { + NpFactory::getInstance().setNpFactoryListener( *mInstance->mPvdPhysicsClient ); + pvd->addClient(mInstance->mPvdPhysicsClient); + } +#endif + + NpFactory::getInstance().addFactoryListener(mInstance->mDeletionMeshListener); + } + ++mRefCount; + + return mInstance; +} + +PxU32 NpPhysics::releaseInstance() +{ + PX_ASSERT(mRefCount > 0); + if (--mRefCount) + return mRefCount; + +#if PX_SUPPORT_PVD + if(mInstance->mPvd) + { + NpFactory::getInstance().removeFactoryListener( *mInstance->mPvdPhysicsClient ); + } +#endif + + NpFactory::destroyInstance(); + + PX_ASSERT(mInstance); + PX_DELETE_AND_RESET(mInstance); + + Ps::Foundation::decRefCount(); + + return mRefCount; +} + +void NpPhysics::release() +{ + NpPhysics::releaseInstance(); +} + +PxScene* NpPhysics::createScene(const PxSceneDesc& desc) +{ + PX_CHECK_AND_RETURN_NULL(desc.isValid(), "Physics::createScene: desc.isValid() is false!"); + + const PxTolerancesScale& scale = mPhysics.getTolerancesScale(); + const PxTolerancesScale& descScale = desc.getTolerancesScale(); + PX_UNUSED(scale); + PX_UNUSED(descScale); + PX_CHECK_AND_RETURN_NULL((descScale.length == scale.length) && (descScale.mass == scale.mass) && (descScale.speed == scale.speed), "Physics::createScene: PxTolerancesScale must be the same as used for creation of PxPhysics!"); + + Ps::Mutex::ScopedLock lock(mSceneAndMaterialMutex); // done here because scene constructor accesses profiling manager of the SDK + + NpScene* npScene = PX_NEW (NpScene)(desc); + if(!npScene) + { + Ps::getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __LINE__, "Unable to create scene."); + return NULL; + } + if(!npScene->getTaskManager()) + { + Ps::getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __LINE__, "Unable to create scene. Task manager creation failed."); + return NULL; + } + + npScene->loadFromDesc(desc); + +#if PX_SUPPORT_PVD + if(mPvd) + { + npScene->mScene.getScenePvdClient().setPsPvd(mPvd); + mPvd->addClient(&npScene->mScene.getScenePvdClient()); + } +#endif + + if (!sendMaterialTable(*npScene) || !npScene->getScene().isValid()) + { + PX_DELETE(npScene); + Ps::getFoundation().error(PxErrorCode::eOUT_OF_MEMORY, __FILE__, __LINE__, "Unable to create scene."); + return NULL; + } + + mSceneArray.pushBack(npScene); + return npScene; +} + + +void NpPhysics::releaseSceneInternal(PxScene& scene) +{ + NpScene* pScene = static_cast<NpScene*>(&scene); + + Ps::Mutex::ScopedLock lock(mSceneAndMaterialMutex); + for(PxU32 i=0;i<mSceneArray.size();i++) + { + if(mSceneArray[i]==pScene) + { + mSceneArray.replaceWithLast(i); + PX_DELETE_AND_RESET(pScene); + return; + } + } +} + + +PxU32 NpPhysics::getNbScenes() const +{ + Ps::Mutex::ScopedLock lock(const_cast<Ps::Mutex&>(mSceneAndMaterialMutex)); + return mSceneArray.size(); +} + + +PxU32 NpPhysics::getScenes(PxScene** userBuffer, PxU32 bufferSize, PxU32 startIndex) const +{ + Ps::Mutex::ScopedLock lock(const_cast<Ps::Mutex&>(mSceneAndMaterialMutex)); + return Cm::getArrayOfPointers(userBuffer, bufferSize, startIndex, mSceneArray.begin(), mSceneArray.size()); +} + + +PxRigidStatic* NpPhysics::createRigidStatic(const PxTransform& globalPose) +{ + PX_CHECK_AND_RETURN_NULL(globalPose.isSane(), "PxPhysics::createRigidStatic: invalid transform"); + return NpFactory::getInstance().createRigidStatic(globalPose.getNormalized()); +} + +PxShape* NpPhysics::createShape(const PxGeometry& geometry, PxMaterial*const * materials, PxU16 materialCount, bool isExclusive, PxShapeFlags shapeFlags) +{ + PX_CHECK_AND_RETURN_NULL(materials, "createShape: material pointer is NULL"); + PX_CHECK_AND_RETURN_NULL(materialCount>0, "createShape: material count is zero"); + +#if PX_CHECKED + const bool isHeightfield = geometry.getType() == PxGeometryType::eHEIGHTFIELD; + if (isHeightfield) + { + PX_CHECK_AND_RETURN_NULL(mHeightFieldsRegistered, "NpPhysics::createShape: Creating Heightfield shape without having called PxRegister[Unified]HeightFields()!"); + } + const bool hasMeshTypeGeom = isHeightfield || (geometry.getType() == PxGeometryType::eTRIANGLEMESH); + PX_CHECK_AND_RETURN_NULL(!(hasMeshTypeGeom && (shapeFlags & PxShapeFlag::eTRIGGER_SHAPE)), "NpPhysics::createShape: triangle mesh and heightfield triggers are not supported!"); + PX_CHECK_AND_RETURN_NULL(!((shapeFlags & PxShapeFlag::eSIMULATION_SHAPE) && (shapeFlags & PxShapeFlag::eTRIGGER_SHAPE)), "NpPhysics::createShape: shapes cannot simultaneously be trigger shapes and simulation shapes."); +#endif + + return NpFactory::getInstance().createShape(geometry, shapeFlags, materials, materialCount, isExclusive); +} + +PxU32 NpPhysics::getNbShapes() const +{ + return NpFactory::getInstance().getNbShapes(); +} + +PxU32 NpPhysics::getShapes(PxShape** userBuffer, PxU32 bufferSize, PxU32 startIndex) const +{ + return NpFactory::getInstance().getShapes(userBuffer, bufferSize, startIndex); +} + + + + + +PxRigidDynamic* NpPhysics::createRigidDynamic(const PxTransform& globalPose) +{ + PX_CHECK_AND_RETURN_NULL(globalPose.isSane(), "PxPhysics::createRigidDynamic: invalid transform"); + return NpFactory::getInstance().createRigidDynamic(globalPose.getNormalized()); +} + + +PxConstraint* NpPhysics::createConstraint(PxRigidActor* actor0, PxRigidActor* actor1, PxConstraintConnector& connector, const PxConstraintShaderTable& shaders, PxU32 dataSize) +{ + return NpFactory::getInstance().createConstraint(actor0, actor1, connector, shaders, dataSize); +} + + +PxArticulation* NpPhysics::createArticulation() +{ + return NpFactory::getInstance().createArticulation(); +} + + +// PX_AGGREGATE + + +PxAggregate* NpPhysics::createAggregate(PxU32 maxSize, bool selfCollisionEnabled) +{ + return NpFactory::getInstance().createAggregate(maxSize, selfCollisionEnabled); +} +//~PX_AGGREGATE + + +#if PX_USE_PARTICLE_SYSTEM_API +PxParticleSystem* NpPhysics::createParticleSystem(PxU32 maxParticles, bool perParticleRestOffset) +{ + return NpFactory::getInstance().createParticleSystem(maxParticles, perParticleRestOffset); +} + + +PxParticleFluid* NpPhysics::createParticleFluid(PxU32 maxParticles, bool perParticleRestOffset) +{ + return NpFactory::getInstance().createParticleFluid(maxParticles, perParticleRestOffset); +} +#endif + +#if PX_USE_CLOTH_API +PxCloth* NpPhysics::createCloth(const PxTransform& globalPose, PxClothFabric& fabric, const PxClothParticle* particles, PxClothFlags flags) +{ + PX_CHECK_AND_RETURN_NULL(globalPose.isSane(), "PxPhysics::createCloth: invalid transform"); + return NpFactory::getInstance().createCloth(globalPose.getNormalized(), fabric, particles, flags); +} +#endif + + + + +/////////////////////////////////////////////////////////////////////////////// + +NpMaterial* NpPhysics::addMaterial(NpMaterial* m) +{ + if(!m) + return NULL; + + Ps::Mutex::ScopedLock lock(mSceneAndMaterialMutex); + + //the handle is set inside the setMaterial method + if(mMasterMaterialManager.setMaterial(*m)) + { + // Let all scenes know of the new material + for(PxU32 i=0; i < mSceneArray.size(); i++) + { + NpScene* s = getScene(i); + s->addMaterial(*m); + } + return m; + } + else + { + m->release(); + return NULL; + } +} + +PxMaterial* NpPhysics::createMaterial(PxReal staticFriction, PxReal dynamicFriction, PxReal restitution) +{ + PxMaterial* m = NpFactory::getInstance().createMaterial(staticFriction, dynamicFriction, restitution); + return addMaterial(static_cast<NpMaterial*>(m)); +} + +PxU32 NpPhysics::getNbMaterials() const +{ + Ps::Mutex::ScopedLock lock(const_cast<Ps::Mutex&>(mSceneAndMaterialMutex)); + return mMasterMaterialManager.getNumMaterials(); +} + +PxU32 NpPhysics::getMaterials(PxMaterial** userBuffer, PxU32 bufferSize, PxU32 startIndex) const +{ + Ps::Mutex::ScopedLock lock(const_cast<Ps::Mutex&>(mSceneAndMaterialMutex)); + NpMaterialManagerIterator iter(mMasterMaterialManager); + PxU32 writeCount =0; + PxU32 index = 0; + NpMaterial* mat; + while(iter.getNextMaterial(mat)) + { + if(index++ < startIndex) + continue; + if(writeCount == bufferSize) + break; + userBuffer[writeCount++] = mat; + } + return writeCount; +} + +void NpPhysics::removeMaterialFromTable(NpMaterial& m) +{ + Ps::Mutex::ScopedLock lock(mSceneAndMaterialMutex); + + // Let all scenes know of the deleted material + for(PxU32 i=0; i < mSceneArray.size(); i++) + { + NpScene* s = getScene(i); + s->removeMaterial(m); + } + + mMasterMaterialManager.removeMaterial(m); +} + +void NpPhysics::updateMaterial(NpMaterial& m) +{ + Ps::Mutex::ScopedLock lock(mSceneAndMaterialMutex); + + // Let all scenes know of the updated material + for(PxU32 i=0; i < mSceneArray.size(); i++) + { + NpScene* s = getScene(i); + s->updateMaterial(m); + } + mMasterMaterialManager.updateMaterial(m); +} + +bool NpPhysics::sendMaterialTable(NpScene& scene) +{ + // note: no lock here because this method gets only called at scene creation and there we do lock + + NpMaterialManagerIterator iter(mMasterMaterialManager); + NpMaterial* mat; + while(iter.getNextMaterial(mat)) + scene.addMaterial(*mat); + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +PxTriangleMesh* NpPhysics::createTriangleMesh(PxInputStream& stream) +{ + return NpFactory::getInstance().createTriangleMesh(stream); +} + +PxU32 NpPhysics::getNbTriangleMeshes() const +{ + return NpFactory::getInstance().getNbTriangleMeshes(); +} + +PxU32 NpPhysics::getTriangleMeshes(PxTriangleMesh** userBuffer, PxU32 bufferSize, PxU32 startIndex) const +{ + return NpFactory::getInstance().getTriangleMeshes(userBuffer, bufferSize, startIndex); +} + +PxHeightField* NpPhysics::createHeightField(PxInputStream& stream) +{ + return NpFactory::getInstance().createHeightField(stream); +} + +PxU32 NpPhysics::getNbHeightFields() const +{ + return NpFactory::getInstance().getNbHeightFields(); +} + +PxU32 NpPhysics::getHeightFields(PxHeightField** userBuffer, PxU32 bufferSize, PxU32 startIndex) const +{ + return NpFactory::getInstance().getHeightFields(userBuffer, bufferSize, startIndex); +} + +/////////////////////////////////////////////////////////////////////////////// +PxConvexMesh* NpPhysics::createConvexMesh(PxInputStream& stream) +{ + return NpFactory::getInstance().createConvexMesh(stream); +} + + +PxU32 NpPhysics::getNbConvexMeshes() const +{ + return NpFactory::getInstance().getNbConvexMeshes(); +} + +PxU32 NpPhysics::getConvexMeshes(PxConvexMesh** userBuffer, PxU32 bufferSize, PxU32 startIndex) const +{ + return NpFactory::getInstance().getConvexMeshes(userBuffer, bufferSize, startIndex); +} + +/////////////////////////////////////////////////////////////////////////////// + + +#if PX_USE_CLOTH_API +PxClothFabric* NpPhysics::createClothFabric(PxInputStream& stream) +{ + return NpFactory::getInstance().createClothFabric(stream); +} + +PxClothFabric* NpPhysics::createClothFabric(const PxClothFabricDesc& desc) +{ + return NpFactory::getInstance().createClothFabric(desc); +} + +PxU32 NpPhysics::getNbClothFabrics() const +{ + return NpFactory::getInstance().getNbClothFabrics(); +} + + +PxU32 NpPhysics::getClothFabrics(PxClothFabric** userBuffer, PxU32 bufferSize) const +{ + return NpFactory::getInstance().getClothFabrics(userBuffer, bufferSize); +} + +void NpPhysics::registerCloth() +{ + NpFactory::registerCloth(); + + Ps::Mutex::ScopedLock lock(mSceneAndMaterialMutex); + for(PxU32 i = 0; i < mSceneArray.size(); i++) + mSceneArray[i]->getScene().getScScene().createClothSolver(); +} +#endif + +PxPruningStructure* NpPhysics::createPruningStructure(PxRigidActor*const* actors, PxU32 nbActors) +{ + PX_SIMD_GUARD; + + PX_ASSERT(actors); + PX_ASSERT(nbActors > 0); + + Sq::PruningStructure* ps = PX_NEW(Sq::PruningStructure)(); + if(!ps->build(actors, nbActors)) + { + PX_DELETE_AND_RESET(ps); + } + return ps; +} + +#if PX_SUPPORT_GPU_PHYSX +void NpPhysics::registerPhysXIndicatorGpuClient() +{ + Ps::Mutex::ScopedLock lock(mPhysXIndicatorMutex); + + ++mNbRegisteredGpuClients; + + mPhysXIndicator.setIsGpu(mNbRegisteredGpuClients>0); +} + +void NpPhysics::unregisterPhysXIndicatorGpuClient() +{ + Ps::Mutex::ScopedLock lock(mPhysXIndicatorMutex); + + if (mNbRegisteredGpuClients) + --mNbRegisteredGpuClients; + + mPhysXIndicator.setIsGpu(mNbRegisteredGpuClients>0); +} +#endif + +/////////////////////////////////////////////////////////////////////////////// +void NpPhysics::registerDeletionListener(PxDeletionListener& observer, const PxDeletionEventFlags& deletionEvents, bool restrictedObjectSet) +{ + Ps::Mutex::ScopedLock lock(mDeletionListenerMutex); + + const DeletionListenerMap::Entry* entry = mDeletionListenerMap.find(&observer); + if(!entry) + { + NpDelListenerEntry* e = PX_NEW(NpDelListenerEntry)(deletionEvents, restrictedObjectSet); + if (e) + { + if (mDeletionListenerMap.insert(&observer, e)) + mDeletionListenersExist = true; + else + { + PX_DELETE(e); + PX_ALWAYS_ASSERT(); + } + } + } + else + PX_ASSERT(mDeletionListenersExist); +} + +void NpPhysics::unregisterDeletionListener(PxDeletionListener& observer) +{ + Ps::Mutex::ScopedLock lock(mDeletionListenerMutex); + + const DeletionListenerMap::Entry* entry = mDeletionListenerMap.find(&observer); + if(entry) + { + NpDelListenerEntry* e = entry->second; + mDeletionListenerMap.erase(&observer); + PX_DELETE(e); + } + mDeletionListenersExist = mDeletionListenerMap.size()>0; +} + + +void NpPhysics::registerDeletionListenerObjects(PxDeletionListener& observer, const PxBase* const* observables, PxU32 observableCount) +{ + Ps::Mutex::ScopedLock lock(mDeletionListenerMutex); + + const DeletionListenerMap::Entry* entry = mDeletionListenerMap.find(&observer); + if(entry) + { + NpDelListenerEntry* e = entry->second; + PX_CHECK_AND_RETURN(e->restrictedObjectSet, "PxPhysics::registerDeletionListenerObjects: deletion listener is not configured to receive events from specific objects."); + + e->registeredObjects.reserve(e->registeredObjects.size() + observableCount); + for(PxU32 i=0; i < observableCount; i++) + e->registeredObjects.insert(observables[i]); + } + else + { + PX_CHECK_AND_RETURN(false, "PxPhysics::registerDeletionListenerObjects: deletion listener has to be registered in PxPhysics first."); + } +} + + +void NpPhysics::unregisterDeletionListenerObjects(PxDeletionListener& observer, const PxBase* const* observables, PxU32 observableCount) +{ + Ps::Mutex::ScopedLock lock(mDeletionListenerMutex); + + const DeletionListenerMap::Entry* entry = mDeletionListenerMap.find(&observer); + if(entry) + { + NpDelListenerEntry* e = entry->second; + if (e->restrictedObjectSet) + { + for(PxU32 i=0; i < observableCount; i++) + e->registeredObjects.erase(observables[i]); + } + else + { + PX_CHECK_AND_RETURN(false, "PxPhysics::unregisterDeletionListenerObjects: deletion listener is not configured to receive events from specific objects."); + } + } + else + { + PX_CHECK_AND_RETURN(false, "PxPhysics::unregisterDeletionListenerObjects: deletion listener has to be registered in PxPhysics first."); + } +} + + +void NpPhysics::notifyDeletionListeners(const PxBase* base, void* userData, PxDeletionEventFlag::Enum deletionEvent) +{ + // we don't protect the check for whether there are any listeners, because we don't want to take a hit in the + // common case where there are no listeners. Note the API comments here, that users should not register or + // unregister deletion listeners while deletions are occurring + + if(mDeletionListenersExist) + { + Ps::Mutex::ScopedLock lock(mDeletionListenerMutex); + + const DeletionListenerMap::Entry* delListenerEntries = mDeletionListenerMap.getEntries(); + const PxU32 delListenerEntryCount = mDeletionListenerMap.size(); + for(PxU32 i=0; i < delListenerEntryCount; i++) + { + const NpDelListenerEntry* entry = delListenerEntries[i].second; + + if (entry->flags & deletionEvent) + { + if (entry->restrictedObjectSet) + { + if (entry->registeredObjects.contains(base)) + delListenerEntries[i].first->onRelease(base, userData, deletionEvent); + } + else + delListenerEntries[i].first->onRelease(base, userData, deletionEvent); + } + } + } +} + + +/////////////////////////////////////////////////////////////////////////////// +const PxTolerancesScale& NpPhysics::getTolerancesScale() const +{ + return mPhysics.getTolerancesScale(); +} + +PxFoundation& NpPhysics::getFoundation() +{ + return Ps::Foundation::getInstance(); +} + +PxPhysics& PxGetPhysics() +{ + return NpPhysics::getInstance(); +} + +PxPhysics* PxCreateBasePhysics(PxU32 version, PxFoundation& foundation, const PxTolerancesScale& scale, bool trackOutstandingAllocations, + physx::PxPvd* pvd) +{ + return NpPhysics::createInstance(version, foundation, scale, trackOutstandingAllocations, static_cast<physx::pvdsdk::PsPvd*>(pvd)); +} + +void PxRegisterArticulations(PxPhysics& physics) +{ + PX_UNUSED(&physics); // for the moment + Dy::PxvRegisterArticulations(); + NpFactory::registerArticulations(); +} + +void PxRegisterHeightFields(PxPhysics& physics) +{ + PX_UNUSED(&physics); // for the moment + PX_CHECK_AND_RETURN(NpPhysics::getInstance().getNumScenes() == 0, "PxRegisterHeightFields: it is illegal to call a heightfield registration function after you have a scene."); + + PxvRegisterHeightFields(); + Gu::registerHeightFields(); +#if PX_CHECKED + NpPhysics::heightfieldsAreRegistered(); +#endif +} + +void PxRegisterLegacyHeightFields(PxPhysics& physics) +{ + PX_CHECK_AND_RETURN(NpPhysics::getInstance().getNumScenes() == 0, "PxRegisterLegacyHeightFields: it is illegal to call a heightfield registration function after you have a scene."); + PX_UNUSED(&physics); // for the moment + PxvRegisterLegacyHeightFields(); + Gu::registerHeightFields(); +#if PX_CHECKED + NpPhysics::heightfieldsAreRegistered(); +#endif +} + +void PxRegisterCloth(PxPhysics& physics) +{ + PX_UNUSED(&physics); + +#if PX_USE_CLOTH_API + static_cast<NpPhysics&>(physics).registerCloth(); +#endif +} + +void PxRegisterParticles(PxPhysics& physics) +{ + PX_UNUSED(&physics); // for the moment + +#if PX_USE_PARTICLE_SYSTEM_API + Pt::registerParticles(); + NpFactory::registerParticles(); +#endif +} + +bool NpPhysics::lockScene() +{ + mSceneRunning.lock(); + + return true; +} + +bool NpPhysics::unlockScene() +{ + mSceneRunning.unlock(); + + return true; +} + +void PxAddCollectionToPhysics(const PxCollection& collection) +{ + NpFactory& factory = NpFactory::getInstance(); + const Cm::Collection& c = static_cast<const Cm::Collection&>(collection); + factory.addCollection(c); +} diff --git a/PhysX_3.4/Source/PhysX/src/NpPhysics.h b/PhysX_3.4/Source/PhysX/src/NpPhysics.h new file mode 100644 index 00000000..6aee41bc --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpPhysics.h @@ -0,0 +1,274 @@ +// 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_NP_PHYSICS +#define PX_PHYSICS_NP_PHYSICS + +#include "foundation/PxProfiler.h" +#include "PxPhysics.h" +#include "PsUserAllocated.h" +#include "GuMeshFactory.h" +#include "NpMaterial.h" +#include "NpPhysicsInsertionCallback.h" +#include "NpMaterialManager.h" +#include "ScPhysics.h" +#include "PsHashSet.h" +#include "PsHashMap.h" + +#if PX_SUPPORT_GPU_PHYSX +#include "gpu/NpPhysicsGpu.h" +#endif + +#ifdef LINUX +#include <string.h> +#endif + +#if PX_SUPPORT_GPU_PHYSX +#include "device/PhysXIndicator.h" +#endif + +#include "PsPvd.h" + +namespace physx +{ +#if PX_SUPPORT_PVD +namespace Vd +{ + class PvdPhysicsClient; +} +#endif + struct NpMaterialIndexTranslator + { + NpMaterialIndexTranslator() : indicesNeedTranslation(false) {} + + Ps::HashMap<PxU16, PxU16> map; + bool indicesNeedTranslation; + }; + + class NpScene; + struct PxvOffsetTable; + +#if PX_VC +#pragma warning(push) +#pragma warning(disable:4996) // We have to implement deprecated member functions, do not warn. +#endif + +class NpPhysics : public PxPhysics, public Ps::UserAllocated +{ + NpPhysics& operator=(const NpPhysics&); + NpPhysics(const NpPhysics &); + + struct NpDelListenerEntry : public UserAllocated + { + NpDelListenerEntry(const PxDeletionEventFlags& de, bool restrictedObjSet) + : flags(de) + , restrictedObjectSet(restrictedObjSet) + { + } + + Ps::HashSet<const PxBase*> registeredObjects; // specifically registered objects for deletion events + PxDeletionEventFlags flags; + bool restrictedObjectSet; + }; + + + NpPhysics( const PxTolerancesScale& scale, + const PxvOffsetTable& pxvOffsetTable, + bool trackOutstandingAllocations, + physx::pvdsdk::PsPvd* pvd); + virtual ~NpPhysics(); + +public: + + static NpPhysics* createInstance( PxU32 version, + PxFoundation& foundation, + const PxTolerancesScale& scale, + bool trackOutstandingAllocations, + physx::pvdsdk::PsPvd* pvd); + + static PxU32 releaseInstance(); + + static NpPhysics& getInstance() { return *mInstance; } + + virtual void release(); + + virtual PxScene* createScene(const PxSceneDesc&); + void releaseSceneInternal(PxScene&); + virtual PxU32 getNbScenes() const; + virtual PxU32 getScenes(PxScene** userBuffer, PxU32 bufferSize, PxU32 startIndex=0) const; + + virtual PxRigidStatic* createRigidStatic(const PxTransform&); + virtual PxRigidDynamic* createRigidDynamic(const PxTransform&); + virtual PxArticulation* createArticulation(); + virtual PxConstraint* createConstraint(PxRigidActor* actor0, PxRigidActor* actor1, PxConstraintConnector& connector, const PxConstraintShaderTable& shaders, PxU32 dataSize); + virtual PxAggregate* createAggregate(PxU32 maxSize, bool selfCollision); + + virtual PxShape* createShape(const PxGeometry&, PxMaterial*const *, PxU16, bool, PxShapeFlags shapeFlags); + virtual PxU32 getNbShapes() const; + virtual PxU32 getShapes(PxShape** userBuffer, PxU32 bufferSize, PxU32 startIndex) const; + +#if PX_USE_PARTICLE_SYSTEM_API + virtual PxParticleSystem* createParticleSystem(PxU32 maxParticles, bool perParticleRestOffset); + virtual PxParticleFluid* createParticleFluid(PxU32 maxParticles, bool perParticleRestOffset); +#endif + +#if PX_USE_CLOTH_API + virtual PxCloth* createCloth(const PxTransform& globalPose, PxClothFabric& fabric, const PxClothParticle* particles, PxClothFlags flags); +#endif + + virtual PxMaterial* createMaterial(PxReal staticFriction, PxReal dynamicFriction, PxReal restitution); + virtual PxU32 getNbMaterials() const; + virtual PxU32 getMaterials(PxMaterial** userBuffer, PxU32 bufferSize, PxU32 startIndex=0) const; + + virtual PxTriangleMesh* createTriangleMesh(PxInputStream&); + virtual PxU32 getNbTriangleMeshes() const; + virtual PxU32 getTriangleMeshes(PxTriangleMesh** userBuffer, PxU32 bufferSize, PxU32 startIndex=0) const; + + virtual PxHeightField* createHeightField(PxInputStream& stream); + virtual PxU32 getNbHeightFields() const; + virtual PxU32 getHeightFields(PxHeightField** userBuffer, PxU32 bufferSize, PxU32 startIndex=0) const; + + virtual PxConvexMesh* createConvexMesh(PxInputStream&); + virtual PxU32 getNbConvexMeshes() const; + virtual PxU32 getConvexMeshes(PxConvexMesh** userBuffer, PxU32 bufferSize, PxU32 startIndex=0) const; + +#if PX_USE_CLOTH_API + virtual PxClothFabric* createClothFabric(PxInputStream&); + virtual PxClothFabric* createClothFabric(const PxClothFabricDesc& desc); + virtual PxU32 getNbClothFabrics() const; + virtual PxU32 getClothFabrics(PxClothFabric** userBuffer, PxU32 bufferSize) const; + void registerCloth(); +#endif + +#if PX_SUPPORT_GPU_PHYSX + void registerPhysXIndicatorGpuClient(); + void unregisterPhysXIndicatorGpuClient(); +#else + PX_FORCE_INLINE void registerPhysXIndicatorGpuClient() {} + PX_FORCE_INLINE void unregisterPhysXIndicatorGpuClient() {} +#endif + + virtual PxPruningStructure* createPruningStructure(PxRigidActor*const* actors, PxU32 nbActors); + + virtual const PxTolerancesScale& getTolerancesScale() const; + + virtual PxFoundation& getFoundation(); + + bool lockScene(); + bool unlockScene(); + + PX_INLINE NpScene* getScene(PxU32 i) const { return mSceneArray[i]; } + PX_INLINE PxU32 getNumScenes() const { return mSceneArray.size(); } +#if PX_CHECKED + static PX_INLINE void heightfieldsAreRegistered() { mHeightFieldsRegistered = true; } +#endif + +#if PX_SUPPORT_GPU_PHYSX + virtual NpPhysicsGpu& getNpPhysicsGpu() { return mPhysicsGpu; } +#endif + + virtual void registerDeletionListener(PxDeletionListener& observer, const PxDeletionEventFlags& deletionEvents, bool restrictedObjectSet); + virtual void unregisterDeletionListener(PxDeletionListener& observer); + virtual void registerDeletionListenerObjects(PxDeletionListener& observer, const PxBase* const* observables, PxU32 observableCount); + virtual void unregisterDeletionListenerObjects(PxDeletionListener& observer, const PxBase* const* observables, PxU32 observableCount); + + void notifyDeletionListeners(const PxBase*, void* userData, PxDeletionEventFlag::Enum deletionEvent); + PX_FORCE_INLINE void notifyDeletionListenersUserRelease(const PxBase* b, void* userData) { notifyDeletionListeners(b, userData, PxDeletionEventFlag::eUSER_RELEASE); } + PX_FORCE_INLINE void notifyDeletionListenersMemRelease(const PxBase* b, void* userData) { notifyDeletionListeners(b, userData, PxDeletionEventFlag::eMEMORY_RELEASE); } + + virtual PxPhysicsInsertionCallback& getPhysicsInsertionCallback() { return mObjectInsertion; } + + void removeMaterialFromTable(NpMaterial&); + void updateMaterial(NpMaterial&); + bool sendMaterialTable(NpScene&); + + NpMaterialManager& getMaterialManager() { return mMasterMaterialManager; } + + NpMaterial* addMaterial(NpMaterial* np); + + static void initOffsetTables(PxvOffsetTable& pxvOffsetTable); + + static bool apiReentryLock; + +private: + typedef Ps::CoalescedHashMap<PxDeletionListener*, NpDelListenerEntry*> DeletionListenerMap; + + Ps::Array<NpScene*> mSceneArray; + + Ps::Mutex mSceneRunning; + + Sc::Physics mPhysics; + NpMaterialManager mMasterMaterialManager; + + NpPhysicsInsertionCallback mObjectInsertion; + + struct MeshDeletionListener: public GuMeshFactoryListener + { + void onGuMeshFactoryBufferRelease(const PxBase* object, PxType type) + { + PX_UNUSED(type); + NpPhysics::getInstance().notifyDeletionListeners(object, NULL, PxDeletionEventFlag::eMEMORY_RELEASE); + } + }; + + Ps::Mutex mDeletionListenerMutex; + DeletionListenerMap mDeletionListenerMap; + MeshDeletionListener mDeletionMeshListener; + bool mDeletionListenersExist; + + Ps::Mutex mSceneAndMaterialMutex; // guarantees thread safety for API calls related to scene and material containers + +#if PX_SUPPORT_GPU_PHYSX + PhysXIndicator mPhysXIndicator; + PxU32 mNbRegisteredGpuClients; + Ps::Mutex mPhysXIndicatorMutex; + NpPhysicsGpu mPhysicsGpu; +#endif +#if PX_SUPPORT_PVD + physx::pvdsdk::PsPvd* mPvd; + Vd::PvdPhysicsClient* mPvdPhysicsClient; +#endif + + static PxU32 mRefCount; + static NpPhysics* mInstance; + +#if PX_CHECKED + static bool mHeightFieldsRegistered; //just for error checking +#endif + + friend class NpCollection; +}; + +#if PX_VC +#pragma warning(pop) +#endif +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/NpPhysicsInsertionCallback.h b/PhysX_3.4/Source/PhysX/src/NpPhysicsInsertionCallback.h new file mode 100644 index 00000000..4bfd9b33 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpPhysicsInsertionCallback.h @@ -0,0 +1,69 @@ +// 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_NP_PHYSICS_INSERTION_CALLBACK +#define PX_PHYSICS_NP_PHYSICS_INSERTION_CALLBACK + +#include "common/PxPhysicsInsertionCallback.h" +#include "GuTriangleMesh.h" +#include "GuHeightField.h" +#include "GuConvexMesh.h" +#include "NpFactory.h" +#include "PsFoundation.h" + +namespace physx +{ + class NpPhysicsInsertionCallback: public PxPhysicsInsertionCallback + { + public: + NpPhysicsInsertionCallback() {} + + virtual PxBase* buildObjectFromData(PxConcreteType::Enum type, void* data) + { + if(type == PxConcreteType::eTRIANGLE_MESH_BVH33 || type == PxConcreteType::eTRIANGLE_MESH_BVH34) + return NpFactory::getInstance().createTriangleMesh(data); + + if (type == PxConcreteType::eCONVEX_MESH) + return NpFactory::getInstance().createConvexMesh(data); + + if (type == PxConcreteType::eHEIGHTFIELD) + return NpFactory::getInstance().createHeightField(data); + + Ps::getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __LINE__, "Inserting object failed: " + "Object type not supported for buildObjectFromData."); + + return NULL; + } + + }; + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/NpPtrTableStorageManager.h b/PhysX_3.4/Source/PhysX/src/NpPtrTableStorageManager.h new file mode 100644 index 00000000..17c74129 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpPtrTableStorageManager.h @@ -0,0 +1,105 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + + +#ifndef PX_PHYSICS_NP_PTRTABLESTORAGEMANAGER_H +#define PX_PHYSICS_NP_PTRTABLESTORAGEMANAGER_H + +#include "CmPhysXCommon.h" +#include "PsMutex.h" +#include "PsUserAllocated.h" +#include "CmPtrTable.h" +#include "PsBitUtils.h" + +namespace physx +{ +class NpPtrTableStorageManager : public Cm::PtrTableStorageManager, public Ps::UserAllocated +{ + PX_NOCOPY(NpPtrTableStorageManager) + +public: + + NpPtrTableStorageManager() {} + ~NpPtrTableStorageManager() {} + + void** allocate(PxU32 capacity) + { + PX_ASSERT(Ps::isPowerOfTwo(capacity)); + + Ps::Mutex::ScopedLock lock(mMutex); + + return capacity<=4*sizeof(void*) ? reinterpret_cast<void**>(mPool4.construct()) + : capacity<=16*sizeof(void*) ? reinterpret_cast<void**>(mPool16.construct()) + : capacity<=64*sizeof(void*) ? reinterpret_cast<void**>(mPool64.construct()) + : reinterpret_cast<void**>(PX_ALLOC(capacity*sizeof(void*), "CmPtrTable pointer array")); + } + + void deallocate(void** addr, PxU32 capacity) + { + PX_ASSERT(Ps::isPowerOfTwo(capacity)); + + Ps::Mutex::ScopedLock lock(mMutex); + + if(capacity<=4*sizeof(void*)) mPool4.destroy(reinterpret_cast< PtrBlock<4>*>(addr)); + else if(capacity<=16*sizeof(void*)) mPool16.destroy(reinterpret_cast< PtrBlock<16>*>(addr)); + else if(capacity<=64*sizeof(void*)) mPool64.destroy(reinterpret_cast< PtrBlock<64>*>(addr)); + else PX_FREE(addr); + } + + // originalCapacity is the only way we know which pool the alloc request belongs to, + // so if those are no longer going to match, we need to realloc. + + bool canReuse(PxU32 originalCapacity, PxU32 newCapacity) + { + PX_ASSERT(Ps::isPowerOfTwo(originalCapacity)); + PX_ASSERT(Ps::isPowerOfTwo(newCapacity)); + + return poolId(originalCapacity) == poolId(newCapacity) && newCapacity<=64; + } + +private: + Ps::Mutex mMutex; + + int poolId(PxU32 size) + { + return size<=4 ? 0 + : size<=16 ? 1 + : size<=64 ? 2 + : 3; + } + + template<int N> class PtrBlock { void* ptr[N]; }; + + Ps::Pool2<PtrBlock<4>, 4096 > mPool4; + Ps::Pool2<PtrBlock<16>, 4096 > mPool16; + Ps::Pool2<PtrBlock<64>, 4096 > mPool64; +}; + +} +#endif diff --git a/PhysX_3.4/Source/PhysX/src/NpPvdSceneQueryCollector.cpp b/PhysX_3.4/Source/PhysX/src/NpPvdSceneQueryCollector.cpp new file mode 100644 index 00000000..2756f1a1 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpPvdSceneQueryCollector.cpp @@ -0,0 +1,159 @@ +// 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 "NpScene.h" + +#if PX_SUPPORT_PVD +using namespace physx; +using namespace Sq; +using namespace Vd; + +void PvdSceneQueryCollector::release() +{ + physx::pvdsdk::PvdDataStream* stream = mScene.getScenePvdClient().getDataStream(); + if(stream && stream->isConnected()) + { + const Ps::Array<PxGeometryHolder>& geoms = getPrevFrameGeometries(); + for(PxU32 k=0; k<geoms.size(); ++k) + stream->destroyInstance(&geoms[k]); + + clearGeometryArrays(); + } +} + +template<class QueryResultT, class PvdHitType> +static void collectBatchedHits(const QueryResultT* results, Ps::Array<PvdHitType>& accumulated, Ps::Array<PvdSqHit>& pvdSqHits, PxU32 nb, PxU32 startIdx, const char* arrayName) +{ + for(PxU32 i=0; i<nb; i++) + { + const QueryResultT& result = results[i]; + if(result.queryStatus != PxBatchQueryStatus::eSUCCESS) + continue; + + PvdHitType& query = accumulated[startIdx + i]; + const PxU32 nbAnyHits = result.getNbAnyHits(); + if(query.mHits.mCount != nbAnyHits) + { + query.mHits = PvdReference(arrayName, pvdSqHits.size(), nbAnyHits); + + for(PxU32 j=0; j<nbAnyHits; j++) + pvdSqHits.pushBack(PvdSqHit(result.getAnyHit(j))); + } + } +} + +void PvdSceneQueryCollector::collectAllBatchedHits(const PxRaycastQueryResult* r, PxU32 nbR, PxU32 idxR, const PxOverlapQueryResult* o, PxU32 nbO, PxU32 idxO, const PxSweepQueryResult* s, PxU32 nbS, PxU32 idxS) +{ + collectBatchedHits(r, mAccumulatedRaycastQueries, mPvdSqHits, nbR, idxR, getArrayName(mPvdSqHits)); + collectBatchedHits(o, mAccumulatedOverlapQueries, mPvdSqHits, nbO, idxO, getArrayName(mPvdSqHits)); + collectBatchedHits(s, mAccumulatedSweepQueries, mPvdSqHits, nbS, idxS, getArrayName(mPvdSqHits)); +} + +template<class SDKHitType, class PvdHitType> +static void accumulate(PvdHitType& query, Ps::Array<PvdHitType>& accumulated, const char* arrayName, Ps::Array<PvdSqHit>& dst, const SDKHitType* src, PxU32 nb, const PxQueryFilterData& fd) +{ + query.mFilterFlags = fd.flags; + query.mHits = PvdReference(arrayName, dst.size(), nb); + + PX_ASSERT(PxU32(-1) != nb); + for(PxU32 i=0; i<nb; i++) + dst.pushBack(PvdSqHit(src[i])); + + accumulated.pushBack(query); +} + +static PX_FORCE_INLINE void clampNbHits(PxU32& hitsNum, const PxQueryFilterData& fd, bool multipleHits) +{ + if((fd.flags & PxQueryFlag::eANY_HIT) || !multipleHits) + hitsNum = hitsNum > 0 ? 1u : 0; +} + +template<class Type> static void pushBackT(Ps::Array<Type>& array, const Type& item, PvdReference& ref, const char* arrayName) +{ + ref = PvdReference(arrayName, array.size(), 1); + array.pushBack(item); +} + +void PvdSceneQueryCollector::raycast(const PxVec3& origin, const PxVec3& unitDir, PxReal distance, const PxRaycastHit* hit, PxU32 hitsNum, const PxQueryFilterData& fd, bool multipleHits) +{ + Ps::Mutex::ScopedLock lock(mMutex); + + PvdRaycast raycastQuery; + raycastQuery.mOrigin = origin; + raycastQuery.mUnitDir = unitDir; + raycastQuery.mDistance = distance; + raycastQuery.mFilterData = fd.data; + if(fd.flags & PxQueryFlag::eANY_HIT) raycastQuery.mType = QueryID::QUERY_RAYCAST_ANY_OBJECT; + else if(multipleHits) raycastQuery.mType = QueryID::QUERY_RAYCAST_ALL_OBJECTS; + else raycastQuery.mType = QueryID::QUERY_RAYCAST_CLOSEST_OBJECT; + clampNbHits(hitsNum, fd, multipleHits); + + accumulate(raycastQuery, mAccumulatedRaycastQueries, getArrayName(mPvdSqHits), mPvdSqHits, hit, hitsNum, fd); +} + +void PvdSceneQueryCollector::sweep(const PxGeometry& geometry, const PxTransform& pose, const PxVec3& unitDir, PxReal distance, const PxSweepHit* hit, PxU32 hitsNum, const PxQueryFilterData& fd, bool multipleHits) +{ + Ps::Mutex::ScopedLock lock(mMutex); + + PvdSweep sweepQuery; + pushBackT(mGeometries[mInUse], PxGeometryHolder(geometry), sweepQuery.mGeometries, getArrayName(mGeometries[mInUse])); // PT: TODO: optimize this. We memcopy once to the stack, then again to the array.... + pushBackT(mPoses, pose, sweepQuery.mPoses, getArrayName(mPoses)); + pushBackT(mFilterData, fd.data, sweepQuery.mFilterData, getArrayName(mFilterData)); + + const PxGeometryType::Enum type = geometry.getType(); // PT: TODO: QueryID::QUERY_LINEAR_xxx_SWEEP_ALL_OBJECTS are never used! + if(type==PxGeometryType::eBOX) sweepQuery.mType = QueryID::QUERY_LINEAR_OBB_SWEEP_CLOSEST_OBJECT; + else if(type==PxGeometryType::eSPHERE || type==PxGeometryType::eCAPSULE) sweepQuery.mType = QueryID::QUERY_LINEAR_CAPSULE_SWEEP_CLOSEST_OBJECT; + else if(type==PxGeometryType::eCONVEXMESH) sweepQuery.mType = QueryID::QUERY_LINEAR_CONVEX_SWEEP_CLOSEST_OBJECT; + else PX_ASSERT(0); + sweepQuery.mUnitDir = unitDir; + sweepQuery.mDistance = distance; + clampNbHits(hitsNum, fd, multipleHits); + + accumulate(sweepQuery, mAccumulatedSweepQueries, getArrayName(mPvdSqHits), mPvdSqHits, hit, hitsNum, fd); +} + +void PvdSceneQueryCollector::overlapMultiple(const PxGeometry& geometry, const PxTransform& pose, const PxOverlapHit* hit, PxU32 hitsNum, const PxQueryFilterData& fd) +{ + Ps::Mutex::ScopedLock lock(mMutex); + + PvdOverlap overlapQuery; + pushBackT(mGeometries[mInUse], PxGeometryHolder(geometry), overlapQuery.mGeometries, getArrayName(mGeometries[mInUse])); // PT: TODO: optimize this. We memcopy once to the stack, then again to the array.... + + const PxGeometryType::Enum type = geometry.getType(); + if(type==PxGeometryType::eBOX) overlapQuery.mType = pose.q.isIdentity() ? QueryID::QUERY_OVERLAP_AABB_ALL_OBJECTS : QueryID::QUERY_OVERLAP_OBB_ALL_OBJECTS; + else if(type==PxGeometryType::eSPHERE) overlapQuery.mType = QueryID::QUERY_OVERLAP_SPHERE_ALL_OBJECTS; + else if(type==PxGeometryType::eCAPSULE) overlapQuery.mType = QueryID::QUERY_OVERLAP_CAPSULE_ALL_OBJECTS; + else if(type==PxGeometryType::eCONVEXMESH) overlapQuery.mType = QueryID::QUERY_OVERLAP_CONVEX_ALL_OBJECTS; + else PX_ASSERT(0); + overlapQuery.mPose = pose; + overlapQuery.mFilterData = fd.data; + + accumulate(overlapQuery, mAccumulatedOverlapQueries, getArrayName(mPvdSqHits), mPvdSqHits, hit, hitsNum, fd); +} +#endif diff --git a/PhysX_3.4/Source/PhysX/src/NpPvdSceneQueryCollector.h b/PhysX_3.4/Source/PhysX/src/NpPvdSceneQueryCollector.h new file mode 100644 index 00000000..38fe3091 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpPvdSceneQueryCollector.h @@ -0,0 +1,305 @@ +// 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 NP_PVD_SCENEQUERYCOLLECTOR_H +#define NP_PVD_SCENEQUERYCOLLECTOR_H + +#include "CmPhysXCommon.h" +#include "PsArray.h" +#include "PxFiltering.h" +#include "PxGeometryHelpers.h" +#include "PxQueryReport.h" +#include "PxBatchQueryDesc.h" + +#if PX_SUPPORT_PVD + +namespace physx +{ +namespace Scb +{ +class Scene; +} + +namespace Vd +{ +struct PvdReference +{ + PX_FORCE_INLINE PvdReference() {} + PX_FORCE_INLINE PvdReference(const char* arrayName, PxU32 baseIndex, PxU32 count) : mArrayName(arrayName), mBaseIndex(baseIndex), mCount(count) {} + + const char* mArrayName; + PxU32 mBaseIndex; + PxU32 mCount; +}; + +struct PvdRaycast +{ + PxU32 mType; + PxFilterData mFilterData; + PxU32 mFilterFlags; + PxVec3 mOrigin; + PxVec3 mUnitDir; + PxReal mDistance; + PvdReference mHits; +}; + +struct PvdOverlap +{ + PxU32 mType; + PxFilterData mFilterData; + PxU32 mFilterFlags; + PxTransform mPose; + PvdReference mGeometries; + PvdReference mHits; +}; + +struct PvdSweep +{ + PxU32 mType; + PxU32 mFilterFlags; + PxVec3 mUnitDir; + PxReal mDistance; + PvdReference mGeometries; + PvdReference mPoses; + PvdReference mFilterData; + PvdReference mHits; +}; + +struct PvdSqHit +{ + const void* mShape; + const void* mActor; + PxU32 mFaceIndex; + PxU32 mFlags; + PxVec3 mImpact; + PxVec3 mNormal; + PxF32 mDistance; + PxF32 mU; + PxF32 mV; + + PvdSqHit() + { + setDefaults(PxQueryHit()); + } + + explicit PvdSqHit(const PxOverlapHit& hit) + { + setDefaults(hit); + } + + explicit PvdSqHit(const PxRaycastHit& hit) + { + setDefaults(hit); + + mImpact = hit.position; + mNormal = hit.normal; + mDistance = hit.distance; + mFlags = hit.flags; + mU = hit.u; + mV = hit.v; + } + + explicit PvdSqHit(const PxSweepHit& hit) + { + setDefaults(hit); + + mImpact = hit.position; + mNormal = hit.normal; + mDistance = hit.distance; + mFlags = hit.flags; + } + + private: + void setDefaults(const PxQueryHit& hit) + { + mShape = hit.shape; + mActor = hit.actor; + mFaceIndex = hit.faceIndex; + mFlags = 0; + mImpact = mNormal = PxVec3(0.0f); + mDistance = mU = mV = 0.0f; + } +}; + +template <typename T, bool isBatched> +inline const char* PvdGetArrayName() +{ + return T::template getArrayName<isBatched>(); +} +template <> +inline const char* PvdGetArrayName<PxGeometryHolder, false>() +{ + return "SceneQueries.GeometryList"; +} +template <> +inline const char* PvdGetArrayName<PxTransform, false>() +{ + return "SceneQueries.PoseList"; +} +template <> +inline const char* PvdGetArrayName<PxFilterData, false>() +{ + return "SceneQueries.FilterDataList"; +} +template <> +inline const char* PvdGetArrayName<PvdRaycast, false>() +{ + return "SceneQueries.Raycasts"; +} +template <> +inline const char* PvdGetArrayName<PvdOverlap, false>() +{ + return "SceneQueries.Overlaps"; +} +template <> +inline const char* PvdGetArrayName<PvdSweep, false>() +{ + return "SceneQueries.Sweeps"; +} +template <> +inline const char* PvdGetArrayName<PvdSqHit, false>() +{ + return "SceneQueries.Hits"; +} +template <> +inline const char* PvdGetArrayName<PxGeometryHolder, true>() +{ + return "BatchedQueries.GeometryList"; +} +template <> +inline const char* PvdGetArrayName<PxTransform, true>() +{ + return "BatchedQueries.PoseList"; +} +template <> +inline const char* PvdGetArrayName<PxFilterData, true>() +{ + return "BatchedQueries.FilterDataList"; +} +template <> +inline const char* PvdGetArrayName<PvdRaycast, true>() +{ + return "BatchedQueries.Raycasts"; +} +template <> +inline const char* PvdGetArrayName<PvdOverlap, true>() +{ + return "BatchedQueries.Overlaps"; +} +template <> +inline const char* PvdGetArrayName<PvdSweep, true>() +{ + return "BatchedQueries.Sweeps"; +} +template <> +inline const char* PvdGetArrayName<PvdSqHit, true>() +{ + return "BatchedQueries.Hits"; +} + +class PvdSceneQueryCollector +{ + PX_NOCOPY(PvdSceneQueryCollector) +public: + PvdSceneQueryCollector(Scb::Scene& scene, bool isBatched) : mScene(scene), mInUse(0), mIsBatched(isBatched) {} + ~PvdSceneQueryCollector() {} + + void clear() + { + Ps::Mutex::ScopedLock lock(mMutex); + + mAccumulatedRaycastQueries.clear(); + mAccumulatedOverlapQueries.clear(); + mAccumulatedSweepQueries.clear(); + mPvdSqHits.clear(); + mPoses.clear(); + mFilterData.clear(); + } + + void clearGeometryArrays() + { + mGeometries[0].clear(); + mGeometries[1].clear(); + } + + void release(); + + void raycast(const PxVec3& origin, const PxVec3& unitDir, PxReal distance, const PxRaycastHit* hit, PxU32 hitsNum, const PxQueryFilterData& filterData, bool multipleHits); + void sweep(const PxGeometry& geometry, const PxTransform& pose, const PxVec3& unitDir, PxReal distance, const PxSweepHit* hit, PxU32 hitsNum, const PxQueryFilterData& filterData, bool multipleHits); + void overlapMultiple(const PxGeometry& geometry, const PxTransform& pose, const PxOverlapHit* hit, PxU32 hitsNum, const PxQueryFilterData& filterData); + + void collectAllBatchedHits (const PxRaycastQueryResult* raycastResults, PxU32 nbRaycastResults, PxU32 batchedRayQstartIdx, + const PxOverlapQueryResult* overlapResults, PxU32 nbOverlapResults, PxU32 batchedOverlapQstartIdx, + const PxSweepQueryResult* sweepResults, PxU32 nbSweepResults, PxU32 batchedSweepQstartIdx); + + PX_FORCE_INLINE Ps::Mutex& getLock() + { + return mMutex; + } + + PX_FORCE_INLINE const Ps::Array<PxGeometryHolder>& getCurrentFrameGeometries() const + { + return mGeometries[mInUse]; + } + PX_FORCE_INLINE const Ps::Array<PxGeometryHolder>& getPrevFrameGeometries() const + { + return mGeometries[mInUse ^ 1]; + } + void prepareNextFrameGeometries() + { + mInUse ^= 1; + mGeometries[mInUse].clear(); + } + template <typename T> + const char* getArrayName(const Ps::Array<T>&) + { + return mIsBatched ? PvdGetArrayName<T, 1>() : PvdGetArrayName<T, 0>(); + } + + // Scene query and hits for pvd, collected in current frame + Ps::Array<PvdRaycast> mAccumulatedRaycastQueries; + Ps::Array<PvdSweep> mAccumulatedSweepQueries; + Ps::Array<PvdOverlap> mAccumulatedOverlapQueries; + Ps::Array<PvdSqHit> mPvdSqHits; + Ps::Array<PxTransform> mPoses; + Ps::Array<PxFilterData> mFilterData; + +private: + Scb::Scene& mScene; + Ps::Mutex mMutex; + Ps::Array<PxGeometryHolder> mGeometries[2]; + PxU32 mInUse; + const bool mIsBatched; +}; +} +} + +#endif // PX_SUPPORT_PVD + +#endif // NP_PVD_SCENEQUERYCOLLECTOR_H diff --git a/PhysX_3.4/Source/PhysX/src/NpQueryShared.h b/PhysX_3.4/Source/PhysX/src/NpQueryShared.h new file mode 100644 index 00000000..9bf79883 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpQueryShared.h @@ -0,0 +1,106 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + + +#ifndef PX_PHYSICS_NP_QUERYSHARED +#define PX_PHYSICS_NP_QUERYSHARED + +#include "foundation/PxMemory.h" + +namespace physx +{ + +using namespace Cm; + +template <class ActorT> +PX_FORCE_INLINE bool applyClientFilter(ActorT* actor, const PxQueryFilterData& filterData, const NpSceneQueries& scene) +{ + if(filterData.clientId != actor->getOwnerClient()) + { + const bool passForeignShapes = scene.getClientBehaviorFlags(filterData.clientId) & PxClientBehaviorFlag::eREPORT_FOREIGN_OBJECTS_TO_SCENE_QUERY; + const bool reportToForeignClients = actor->getClientBehaviorFlags() & PxActorClientBehaviorFlag::eREPORT_TO_FOREIGN_CLIENTS_SCENE_QUERY; + if(!(passForeignShapes && reportToForeignClients)) + return false; + } + return true; +} + +PX_FORCE_INLINE bool applyFilterEquation(const Scb::Shape& scbShape, const PxFilterData& queryFd) +{ + // if the filterData field is non-zero, and the bitwise-AND value of filterData AND the shape's + // queryFilterData is zero, the shape is skipped. + if(queryFd.word0 | queryFd.word1 | queryFd.word2 | queryFd.word3) + { + const PxFilterData& objFd = scbShape.getScShape().getQueryFilterData(); + const PxU32 keep = (queryFd.word0 & objFd.word0) | (queryFd.word1 & objFd.word1) | (queryFd.word2 & objFd.word2) | (queryFd.word3 & objFd.word3); + if(!keep) + return false; + } + return true; +} + +//======================================================================================================================== +// these partial template specializations are used to generalize the query code to be reused for all permutations of +// hit type=(raycast, overlap, sweep) x query type=(ANY, SINGLE, MULTIPLE) +template <typename HitType> struct HitTypeSupport { enum { IsRaycast = 0, IsSweep = 0, IsOverlap = 0 }; }; +template <> struct HitTypeSupport<PxRaycastHit> +{ + enum { IsRaycast = 1, IsSweep = 0, IsOverlap = 0 }; + static PX_FORCE_INLINE PxReal getDistance(const PxQueryHit& hit) { return static_cast<const PxRaycastHit&>(hit).distance; } +}; +template <> struct HitTypeSupport<PxSweepHit> +{ + enum { IsRaycast = 0, IsSweep = 1, IsOverlap = 0 }; + static PX_FORCE_INLINE PxReal getDistance(const PxQueryHit& hit) { return static_cast<const PxSweepHit&>(hit).distance; } +}; +template <> struct HitTypeSupport<PxOverlapHit> +{ + enum { IsRaycast = 0, IsSweep = 0, IsOverlap = 1 }; + static PX_FORCE_INLINE PxReal getDistance(const PxQueryHit&) { return -1.0f; } +}; + +#define HITDIST(hit) HitTypeSupport<HitType>::getDistance(hit) + +template<typename HitType> +static PxU32 clipHitsToNewMaxDist(HitType* ppuHits, PxU32 count, PxReal newMaxDist) +{ + PxU32 i=0; + while(i!=count) + { + if(HITDIST(ppuHits[i]) > newMaxDist) + ppuHits[i] = ppuHits[--count]; + else + i++; + } + return count; +} + +} // namespace physx + +#endif // PX_PHYSICS_NP_QUERYSHARED diff --git a/PhysX_3.4/Source/PhysX/src/NpReadCheck.cpp b/PhysX_3.4/Source/PhysX/src/NpReadCheck.cpp new file mode 100644 index 00000000..4738866f --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpReadCheck.cpp @@ -0,0 +1,83 @@ +// 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 "NpReadCheck.h" + +#include "NpScene.h" + +using namespace physx; + +NpReadCheck::NpReadCheck(const NpScene* scene, const char* functionName) + : mScene(scene), mName(functionName), mErrorCount(0) +{ + if (mScene) + { + if (!mScene->startRead()) + { + if (mScene->getScene().getFlags() & PxSceneFlag::eREQUIRE_RW_LOCK) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, + "An API read call (%s) was made from thread %d but PxScene::lockRead() was not called first, note that " + "when PxSceneFlag::eREQUIRE_RW_LOCK is enabled all API reads and writes must be " + "wrapped in the appropriate locks.", mName, PxU32(Ps::Thread::getId())); + } + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, + "Overlapping API read and write call detected during %s from thread %d! Note that read operations to " + "the SDK must not be overlapped with write calls, else the resulting behavior is undefined.", mName, PxU32(Ps::Thread::getId())); + } + } + + // Record the NpScene read/write error counter which is + // incremented any time a NpScene::startWrite/startRead fails + // (see destructor for additional error checking based on this count) + mErrorCount = mScene->getReadWriteErrorCount(); + } +} + + +NpReadCheck::~NpReadCheck() +{ + if (mScene) + { + // By checking if the NpScene::mConcurrentErrorCount has been incremented + // we can detect if an erroneous read/write was performed during + // this objects lifetime. In this case we also print this function's + // details so that the user can see which two API calls overlapped + if (mScene->getReadWriteErrorCount() != mErrorCount && !(mScene->getScene().getFlags() & PxSceneFlag::eREQUIRE_RW_LOCK)) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, + "Leaving %s on thread %d, an API overlapping write on another thread was detected.", mName, PxU32(Ps::Thread::getId())); + } + + mScene->stopRead(); + } +} diff --git a/PhysX_3.4/Source/PhysX/src/NpReadCheck.h b/PhysX_3.4/Source/PhysX/src/NpReadCheck.h new file mode 100644 index 00000000..a7bd67a9 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpReadCheck.h @@ -0,0 +1,69 @@ +// 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 NP_READ_CHECK_H +#define NP_READ_CHECK_H + +#include "foundation/PxSimpleTypes.h" + +namespace physx +{ + +class NpScene; + +// RAII wrapper around the PxScene::startRead() method, note that this +// object does not acquire any scene locks, it is an error checking only mechanism +class NpReadCheck +{ +public: + NpReadCheck(const NpScene* scene, const char* functionName); + ~NpReadCheck(); +private: + const NpScene* mScene; + const char* mName; + PxU32 mErrorCount; +}; + +#if (PX_DEBUG || PX_CHECKED) + // Creates a scoped read check object that detects whether appropriate scene locks + // have been acquired and checks if reads/writes overlap, this macro should typically + // be placed at the beginning of any const API methods that are not multi-thread safe, + // the error conditions checked can be summarized as: + + // 1. PxSceneFlag::eREQUIRE_RW_LOCK was specified but PxScene::lockRead() was not yet called + // 2. Other threads were already writing, or began writing during the object lifetime + #define NP_READ_CHECK(npScenePtr) NpReadCheck npReadCheck(static_cast<const NpScene*>(npScenePtr), __FUNCTION__); +#else + #define NP_READ_CHECK(npScenePtr) +#endif + +} + +#endif // NP_Read_CHECK_H diff --git a/PhysX_3.4/Source/PhysX/src/NpRigidActorTemplate.h b/PhysX_3.4/Source/PhysX/src/NpRigidActorTemplate.h new file mode 100644 index 00000000..6e3bbf5a --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpRigidActorTemplate.h @@ -0,0 +1,467 @@ +// 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_NP_RIGIDACTOR_TEMPLATE +#define PX_PHYSICS_NP_RIGIDACTOR_TEMPLATE + +#include "NpActorTemplate.h" +#include "NpShapeManager.h" +#include "NpConstraint.h" +#include "NpFactory.h" + +// PX_SERIALIZATION +#include "foundation/PxErrors.h" +//~PX_SERIALIZATION + +namespace physx +{ + +template<class APIClass> +class NpRigidActorTemplate : public NpActorTemplate<APIClass> +{ +private: + typedef NpActorTemplate<APIClass> ActorTemplateClass; + +public: +// PX_SERIALIZATION + NpRigidActorTemplate(PxBaseFlags baseFlags) : ActorTemplateClass(baseFlags), mShapeManager(PxEmpty), mIndex(0xFFFFFFFF) {} + virtual void requires(PxProcessPxBaseCallback& c); + virtual void exportExtraData(PxSerializationContext& stream); + void importExtraData(PxDeserializationContext& context); + void resolveReferences(PxDeserializationContext& context); +//~PX_SERIALIZATION + virtual ~NpRigidActorTemplate(); + + //--------------------------------------------------------------------------------- + // PxActor implementation + //--------------------------------------------------------------------------------- + virtual void release(); + + // The rule is: If an API method is used somewhere in here, it has to be redeclared, else GCC whines + virtual PxActorType::Enum getType() const = 0; + + virtual PxBounds3 getWorldBounds(float inflation=1.01f) const; + + virtual void setActorFlag(PxActorFlag::Enum flag, bool value); + virtual void setActorFlags(PxActorFlags inFlags); + + //--------------------------------------------------------------------------------- + // PxRigidActor implementation + //--------------------------------------------------------------------------------- + + // Shapes + virtual PxU32 getNbShapes() const; + virtual PxU32 getShapes(PxShape** buffer, PxU32 bufferSize, PxU32 startIndex=0) const; + + // Constraint shaders + virtual PxU32 getNbConstraints() const; + virtual PxU32 getConstraints(PxConstraint** userBuffer, PxU32 bufferSize, PxU32 startIndex=0) const; + + // Multiclient + virtual void setClientBehaviorFlags(PxActorClientBehaviorFlags); + + // shared shapes + virtual void attachShape(PxShape& s); + virtual void detachShape(PxShape& s, bool wakeOnLostTouch); + + + //--------------------------------------------------------------------------------- + // Miscellaneous + //--------------------------------------------------------------------------------- + NpRigidActorTemplate(PxType concreteType, PxBaseFlags baseFlags); + + // not optimal but the template alternative is hardly more readable and perf is not that critical here + virtual void switchToNoSim() { PX_ASSERT(false); } + virtual void switchFromNoSim() { PX_ASSERT(false); } + + void releaseShape(NpShape& s); + + PX_FORCE_INLINE NpShapeManager& getShapeManager() { return mShapeManager; } + PX_FORCE_INLINE const NpShapeManager& getShapeManager() const { return mShapeManager; } + + void updateShaderComs(); + + PX_FORCE_INLINE PxU32 getRigidActorArrayIndex() const { return mIndex; } + PX_FORCE_INLINE void setRigidActorArrayIndex(const PxU32& index) { mIndex = index; } + + bool resetFiltering(Scb::RigidObject& ro, PxShape*const* shapes, PxU32 shapeCount); + +#if PX_ENABLE_DEBUG_VISUALIZATION +public: + void visualize(Cm::RenderOutput& out, NpScene* scene); +#endif +protected: + PX_FORCE_INLINE void setActorSimFlag(bool value); + + NpShapeManager mShapeManager; + PxU32 mIndex; // index for the NpScene rigid actor array +}; + +// PX_SERIALIZATION + +template<class APIClass> +void NpRigidActorTemplate<APIClass>::requires(PxProcessPxBaseCallback& c) +{ + // export shapes + PxU32 nbShapes = mShapeManager.getNbShapes(); + for(PxU32 i=0;i<nbShapes;i++) + { + NpShape* np = mShapeManager.getShapes()[i]; + c.process(*np); + } +} + +template<class APIClass> +void NpRigidActorTemplate<APIClass>::exportExtraData(PxSerializationContext& stream) +{ + mShapeManager.exportExtraData(stream); + ActorTemplateClass::exportExtraData(stream); +} + +template<class APIClass> +void NpRigidActorTemplate<APIClass>::importExtraData(PxDeserializationContext& context) +{ + mShapeManager.importExtraData(context); + ActorTemplateClass::importExtraData(context); +} + +template<class APIClass> +void NpRigidActorTemplate<APIClass>::resolveReferences(PxDeserializationContext& context) +{ + const PxU32 nbShapes = mShapeManager.getNbShapes(); + NpShape** shapes = const_cast<NpShape**>(mShapeManager.getShapes()); + for(PxU32 j=0;j<nbShapes;j++) + { + context.translatePxBase(shapes[j]); + shapes[j]->onActorAttach(*this); + } + + ActorTemplateClass::resolveReferences(context); +} + +//~PX_SERIALIZATION + +template<class APIClass> +NpRigidActorTemplate<APIClass>::NpRigidActorTemplate(PxType concreteType, PxBaseFlags baseFlags) +: ActorTemplateClass(concreteType, baseFlags, NULL, NULL) +{ +} + +template<class APIClass> +NpRigidActorTemplate<APIClass>::~NpRigidActorTemplate() +{ + // TODO: no mechanism for notifying shaders of actor destruction yet +} + + +template<class APIClass> +void NpRigidActorTemplate<APIClass>::release() +{ + NpActor::releaseConstraints(*this); + NpScene* scene = NpActor::getAPIScene(*this); + if(mShapeManager.getPruningStructure()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxRigidActor::release: Actor is part of a pruning structure, pruning structure is now invalid!"); + mShapeManager.getPruningStructure()->invalidate(this); + } + + mShapeManager.detachAll(scene); + +// PX_AGGREGATE + ActorTemplateClass::release(); // PT: added for PxAggregate +//~PX_AGGREGATE +} + + +template<class APIClass> +void NpRigidActorTemplate<APIClass>::releaseShape(NpShape& s) +{ + // invalidate the pruning structure if the actor bounds changed + if (mShapeManager.getPruningStructure()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxRigidActor::releaseShape: Actor is part of a pruning structure, pruning structure is now invalid!"); + mShapeManager.getPruningStructure()->invalidate(this); + } + mShapeManager.detachShape(s, *this); +} + + +template<class APIClass> +void NpRigidActorTemplate<APIClass>::attachShape(PxShape& shape) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(!static_cast<NpShape&>(shape).isExclusive() || shape.getActor()==NULL, "PxRigidActor::attachShape: shape must be shared or unowned"); + PX_SIMD_GUARD + // invalidate the pruning structure if the actor bounds changed + if (mShapeManager.getPruningStructure()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxRigidActor::attachShape: Actor is part of a pruning structure, pruning structure is now invalid!"); + mShapeManager.getPruningStructure()->invalidate(this); + } + + mShapeManager.attachShape(static_cast<NpShape&>(shape), *this); +} + +template<class APIClass> +void NpRigidActorTemplate<APIClass>::detachShape(PxShape& shape, bool wakeOnLostTouch) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(mShapeManager.shapeIsAttached(static_cast<NpShape&>(shape)), "PxRigidActor::detachShape: shape is not attached!") + if (mShapeManager.getPruningStructure()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxRigidActor::detachShape: Actor is part of a pruning structure, pruning structure is now invalid!"); + mShapeManager.getPruningStructure()->invalidate(this); + } + + mShapeManager.detachShape(static_cast<NpShape&>(shape), *this, wakeOnLostTouch); +} + + +template<class APIClass> +PxU32 NpRigidActorTemplate<APIClass>::getNbShapes() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return mShapeManager.getNbShapes(); +} + + +template<class APIClass> +PxU32 NpRigidActorTemplate<APIClass>::getShapes(PxShape** buffer, PxU32 bufferSize, PxU32 startIndex) const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return mShapeManager.getShapes(buffer, bufferSize, startIndex); +} + + +template<class APIClass> +PxU32 NpRigidActorTemplate<APIClass>::getNbConstraints() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return ActorTemplateClass::getNbConnectors(NpConnectorType::eConstraint); +} + + +template<class APIClass> +PxU32 NpRigidActorTemplate<APIClass>::getConstraints(PxConstraint** buffer, PxU32 bufferSize, PxU32 startIndex) const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return ActorTemplateClass::template getConnectors<PxConstraint>(NpConnectorType::eConstraint, buffer, bufferSize, startIndex); // Some people will love me for this one... The syntax is to be standard compliant and + // picky gcc won't compile without it. It is needed if you call a templated member function + // of a templated class +} + +template<class APIClass> +void NpRigidActorTemplate<APIClass>::setClientBehaviorFlags(PxActorClientBehaviorFlags b) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + Scb::Actor& scbActor = NpActor::getScbFromPxActor(*this); + if (scbActor.getClientBehaviorFlags() == b) + return; + + scbActor.setClientBehaviorFlags(b); +} + +template<class APIClass> +PxBounds3 NpRigidActorTemplate<APIClass>::getWorldBounds(float inflation) const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + PX_SIMD_GUARD; + + const PxBounds3 bounds = mShapeManager.getWorldBounds(*this); + PX_ASSERT(bounds.isValid()); + + // PT: unfortunately we can't just scale the min/max vectors, we need to go through center/extents. + const PxVec3 center = bounds.getCenter(); + const PxVec3 inflatedExtents = bounds.getExtents() * inflation; + return PxBounds3::centerExtents(center, inflatedExtents); +} + + +template<class APIClass> +PX_FORCE_INLINE void NpRigidActorTemplate<APIClass>::setActorSimFlag(bool value) +{ + NpScene* scene = NpActor::getOwnerScene(*this); + + PxActorFlags oldFlags = ActorTemplateClass::getActorFlags(); + bool hadNoSimFlag = oldFlags.isSet(PxActorFlag::eDISABLE_SIMULATION); + + PX_CHECK_AND_RETURN((getType() != PxActorType::eARTICULATION_LINK) || (!value && !hadNoSimFlag), "PxActor::setActorFlag: PxActorFlag::eDISABLE_SIMULATION is only supported by PxRigidDynamic and PxRigidStatic objects."); + + if (hadNoSimFlag && (!value)) + { + switchFromNoSim(); + ActorTemplateClass::setActorFlagsInternal(oldFlags & (~PxActorFlag::eDISABLE_SIMULATION)); // needs to be done before the code below to make sure the latest flags get picked up + if (scene) + NpActor::addConstraintsToScene(); + } + else if ((!hadNoSimFlag) && value) + { + if (scene) + NpActor::removeConstraintsFromScene(); + ActorTemplateClass::setActorFlagsInternal(oldFlags | PxActorFlag::eDISABLE_SIMULATION); + switchToNoSim(); + } +} + + +template<class APIClass> +void NpRigidActorTemplate<APIClass>::setActorFlag(PxActorFlag::Enum flag, bool value) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + if (flag == PxActorFlag::eDISABLE_SIMULATION) + setActorSimFlag(value); + + ActorTemplateClass::setActorFlagInternal(flag, value); +} + + +template<class APIClass> +void NpRigidActorTemplate<APIClass>::setActorFlags(PxActorFlags inFlags) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + bool noSim = inFlags.isSet(PxActorFlag::eDISABLE_SIMULATION); + setActorSimFlag(noSim); + + ActorTemplateClass::setActorFlagsInternal(inFlags); +} + + +template<class APIClass> +void NpRigidActorTemplate<APIClass>::updateShaderComs() +{ + NpConnectorIterator iter = ActorTemplateClass::getConnectorIterator(NpConnectorType::eConstraint); + while (PxBase* ser = iter.getNext()) + { + NpConstraint* c = static_cast<NpConstraint*>(ser); + c->comShift(this); + } +} + + +PX_FORCE_INLINE static void fillResetFilteringShapeList(Scb::RigidObject& ro, Scb::Shape& scb, Scb::Shape** shapes, PxU32& shapeCount) +{ + // It is important to filter out shapes that have been added while the simulation was running because for those there is nothing to do. + + if (!ro.isBuffered(Scb::RigidObjectBuffer::BF_Shapes) || !ro.isAddedShape(scb)) + { + shapes[shapeCount] = &scb; + shapeCount++; + } +} + + +template<class APIClass> +bool NpRigidActorTemplate<APIClass>::resetFiltering(Scb::RigidObject& ro, PxShape*const* shapes, PxU32 shapeCount) +{ + PX_CHECK_AND_RETURN_VAL(!(ro.getActorFlags() & PxActorFlag::eDISABLE_SIMULATION), "PxScene::resetFiltering(): Not allowed if PxActorFlag::eDISABLE_SIMULATION is set!", false); + for(PxU32 i=0; i < shapeCount; i++) + { +#if PX_CHECKED + PxRigidActor* ra = shapes[i]->getActor(); + if (ra != this) + { + bool found = false; + if (ra == NULL) + { + NpShape*const* sh = mShapeManager.getShapes(); + for(PxU32 j=0; j < mShapeManager.getNbShapes(); j++) + { + if (sh[j] == shapes[i]) + { + found = true; + break; + } + } + } + + PX_CHECK_AND_RETURN_VAL(found, "PxScene::resetFiltering(): specified shape not in actor!", false); + } +#endif + PX_CHECK_AND_RETURN_VAL(static_cast<NpShape*>(shapes[i])->getScbShape().getFlags() & (PxShapeFlag::eSIMULATION_SHAPE | PxShapeFlag::eTRIGGER_SHAPE), "PxScene::resetFiltering(): specified shapes not of type eSIMULATION_SHAPE or eTRIGGER_SHAPE!", false); + } + + PxU32 sCount; + if (shapes) + sCount = shapeCount; + else + sCount = mShapeManager.getNbShapes(); + + PX_ALLOCA(scbShapes, Scb::Shape*, sCount); + if (scbShapes) + { + if (shapes) // the user specified the shapes + { + PxU32 sAccepted = 0; + for(PxU32 i=0; i < sCount; i++) + { + Scb::Shape& scb = static_cast<NpShape*>(shapes[i])->getScbShape(); + fillResetFilteringShapeList(ro, scb, scbShapes, sAccepted); + } + sCount = sAccepted; + } + else // the user just specified the actor and the shapes are taken from the actor + { + NpShape* const* sh = mShapeManager.getShapes(); + PxU32 sAccepted = 0; + for(PxU32 i=0; i < sCount; i++) + { + Scb::Shape& scb = sh[i]->getScbShape(); + if (scb.getFlags() & (PxShapeFlag::eSIMULATION_SHAPE | PxShapeFlag::eTRIGGER_SHAPE)) + { + fillResetFilteringShapeList(ro, scb, scbShapes, sAccepted); + } + } + sCount = sAccepted; + } + + if (sCount) + { + ro.resetFiltering(scbShapes, sCount); + } + } + + return true; +} + + +#if PX_ENABLE_DEBUG_VISUALIZATION +template<class APIClass> +void NpRigidActorTemplate<APIClass>::visualize(Cm::RenderOutput& out, NpScene* scene) +{ + mShapeManager.visualize(out, scene, *this); +} +#endif // PX_ENABLE_DEBUG_VISUALIZATION + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/NpRigidActorTemplateInternal.h b/PhysX_3.4/Source/PhysX/src/NpRigidActorTemplateInternal.h new file mode 100644 index 00000000..635e1a83 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpRigidActorTemplateInternal.h @@ -0,0 +1,69 @@ +// 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_NP_RIGIDACTOR_TEMPLATE_INTERNAL +#define PX_PHYSICS_NP_RIGIDACTOR_TEMPLATE_INTERNAL + +namespace physx +{ + +template<class T, class T2> +static PX_FORCE_INLINE void releaseActorT(NpRigidActorTemplate<T>* actor, T2& scbActor) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*actor)); + + NpPhysics::getInstance().notifyDeletionListenersUserRelease(actor, actor->userData); + + Scb::Scene* s = scbActor.getScbSceneForAPI(); + + const bool noSim = scbActor.isSimDisabledInternally(); + // important to check the non-buffered flag because it tells what the current internal state of the object is + // (someone might switch to non-simulation and release all while the sim is running). Reading is fine even if + // the sim is running because actor flags are read-only internally. + if(s && noSim) + { + // need to do it here because the Np-shape buffer will not be valid anymore after the release below + // and unlike simulation objects, there is no shape buffer in the simulation controller + actor->getShapeManager().clearShapesOnRelease(*s, *actor); + } + + actor->NpRigidActorTemplate<T>::release(); + + if(s) + { + s->removeActor(scbActor, true, noSim); + static_cast<NpScene*>(s->getPxScene())->removeFromRigidActorList(actor->getRigidActorArrayIndex()); + } + + scbActor.destroy(); +} + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/NpRigidBodyTemplate.h b/PhysX_3.4/Source/PhysX/src/NpRigidBodyTemplate.h new file mode 100644 index 00000000..82255cdc --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpRigidBodyTemplate.h @@ -0,0 +1,593 @@ +// 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_NP_RIGIDBODY_TEMPLATE +#define PX_PHYSICS_NP_RIGIDBODY_TEMPLATE + +#include "NpRigidActorTemplate.h" +#include "ScbBody.h" +#include "NpPhysics.h" +#include "NpShape.h" +#include "NpScene.h" + +namespace physx +{ + +PX_INLINE PxVec3 invertDiagInertia(const PxVec3& m) +{ + return PxVec3( m.x == 0.0f ? 0.0f : 1.0f/m.x, + m.y == 0.0f ? 0.0f : 1.0f/m.y, + m.z == 0.0f ? 0.0f : 1.0f/m.z); +} + + +#if PX_ENABLE_DEBUG_VISUALIZATION +/* +given the diagonal of the body space inertia tensor, and the total mass +this returns the body space AABB width, height and depth of an equivalent box +*/ +PX_INLINE PxVec3 getDimsFromBodyInertia(const PxVec3& inertiaMoments, PxReal mass) +{ + const PxVec3 inertia = inertiaMoments * (6.0f/mass); + return PxVec3( PxSqrt(PxAbs(- inertia.x + inertia.y + inertia.z)), + PxSqrt(PxAbs(+ inertia.x - inertia.y + inertia.z)), + PxSqrt(PxAbs(+ inertia.x + inertia.y - inertia.z))); +} +#endif + + +template<class APIClass> +class NpRigidBodyTemplate : public NpRigidActorTemplate<APIClass> +{ +private: + typedef NpRigidActorTemplate<APIClass> RigidActorTemplateClass; +public: +// PX_SERIALIZATION + NpRigidBodyTemplate(PxBaseFlags baseFlags) : RigidActorTemplateClass(baseFlags), mBody(PxEmpty) {} +//~PX_SERIALIZATION + virtual ~NpRigidBodyTemplate(); + + //--------------------------------------------------------------------------------- + // PxRigidActor implementation + //--------------------------------------------------------------------------------- + // The rule is: If an API method is used somewhere in here, it has to be redeclared, else GCC whines + virtual PxTransform getGlobalPose() const = 0; + + //--------------------------------------------------------------------------------- + // PxRigidBody implementation + //--------------------------------------------------------------------------------- + + // Center of mass pose + virtual PxTransform getCMassLocalPose() const; + + // Mass + virtual void setMass(PxReal mass); + virtual PxReal getMass() const; + virtual PxReal getInvMass() const; + + virtual void setMassSpaceInertiaTensor(const PxVec3& m); + virtual PxVec3 getMassSpaceInertiaTensor() const; + virtual PxVec3 getMassSpaceInvInertiaTensor() const; + + // Velocity + virtual PxVec3 getLinearVelocity() const; + virtual PxVec3 getAngularVelocity() const; + + virtual PxShape* createShape(const PxGeometry& geometry, PxMaterial*const* material, PxU16 materialCount, PxShapeFlags shapeFlags); + virtual void attachShape(PxShape& shape); + + //--------------------------------------------------------------------------------- + // Miscellaneous + //--------------------------------------------------------------------------------- + NpRigidBodyTemplate(PxType concreteType, PxBaseFlags baseFlags, const PxActorType::Enum type, const PxTransform& bodyPose); + + PX_FORCE_INLINE const Scb::Body& getScbBodyFast() const { return mBody; } // PT: important: keep returning an address here (else update prefetch in SceneQueryManager::addShapes) + PX_FORCE_INLINE Scb::Body& getScbBodyFast() { return mBody; } // PT: important: keep returning an address here (else update prefetch in SceneQueryManager::addShapes) + + PX_FORCE_INLINE Scb::Actor& getScbActorFast() { return mBody; } + PX_FORCE_INLINE const Scb::Actor& getScbActorFast() const { return mBody; } + + // Flags + virtual void setRigidBodyFlag(PxRigidBodyFlag::Enum, bool value); + virtual void setRigidBodyFlags(PxRigidBodyFlags inFlags); + PX_FORCE_INLINE PxRigidBodyFlags getRigidBodyFlagsFast() const + { + return getScbBodyFast().getFlags(); + } + virtual PxRigidBodyFlags getRigidBodyFlags() const + { + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return getRigidBodyFlagsFast(); + } + + virtual void setMinCCDAdvanceCoefficient(PxReal advanceCoefficient); + + virtual PxReal getMinCCDAdvanceCoefficient() const; + + virtual void setMaxDepenetrationVelocity(PxReal maxDepenVel); + + virtual PxReal getMaxDepenetrationVelocity() const; + + virtual void setMaxContactImpulse(PxReal maxDepenVel); + + virtual PxReal getMaxContactImpulse() const; + +protected: + void setCMassLocalPoseInternal(const PxTransform&); + + void addSpatialForce(const PxVec3* force, const PxVec3* torque, PxForceMode::Enum mode); + void clearSpatialForce(PxForceMode::Enum mode, bool force, bool torque); + + PX_INLINE void updateBody2Actor(const PxTransform& newBody2Actor); + + PX_FORCE_INLINE void setRigidBodyFlagsInternal(const PxRigidBodyFlags& currentFlags, const PxRigidBodyFlags& newFlags); + +#if PX_ENABLE_DEBUG_VISUALIZATION +public: + void visualize(Cm::RenderOutput& out, NpScene* scene); +#endif + + PX_FORCE_INLINE bool isKinematic() + { + return (APIClass::getConcreteType() == PxConcreteType::eRIGID_DYNAMIC) && (getScbBodyFast().getFlags() & PxRigidBodyFlag::eKINEMATIC); + } + +protected: + Scb::Body mBody; +}; + + +template<class APIClass> +NpRigidBodyTemplate<APIClass>::NpRigidBodyTemplate(PxType concreteType, PxBaseFlags baseFlags, PxActorType::Enum type, const PxTransform& bodyPose) +: RigidActorTemplateClass(concreteType, baseFlags) +, mBody(type, bodyPose) +{ +} + + +template<class APIClass> +NpRigidBodyTemplate<APIClass>::~NpRigidBodyTemplate() +{ +} + +namespace +{ + PX_FORCE_INLINE static bool isSimGeom(PxGeometryType::Enum t) + { + return t != PxGeometryType::eTRIANGLEMESH && t != PxGeometryType::ePLANE && t != PxGeometryType::eHEIGHTFIELD; + } +} + +template<class APIClass> +PxShape* NpRigidBodyTemplate<APIClass>::createShape(const PxGeometry& geometry, PxMaterial*const* materials, PxU16 materialCount, PxShapeFlags shapeFlags) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN_NULL(!(shapeFlags & PxShapeFlag::eSIMULATION_SHAPE) + || isSimGeom(geometry.getType()) + || isKinematic(), + "createShape: Triangle mesh, heightfield or plane geometry shapes configured as eSIMULATION_SHAPE are not supported for non-kinematic PxRigidDynamic instances."); + + NpShape* shape = static_cast<NpShape*>(NpPhysics::getInstance().createShape(geometry, materials, materialCount, true, shapeFlags)); + + if ( shape != NULL ) + { + RigidActorTemplateClass::mShapeManager.attachShape(*shape, *this); + shape->releaseInternal(); + } + return shape; +} + + +template<class APIClass> +void NpRigidBodyTemplate<APIClass>::attachShape(PxShape& shape) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(!(shape.getFlags() & PxShapeFlag::eSIMULATION_SHAPE) + || isSimGeom(shape.getGeometryType()) + || isKinematic(), + "attachShape: Triangle mesh, heightfield or plane geometry shapes configured as eSIMULATION_SHAPE are not supported for non-kinematic PxRigidDynamic instances."); + RigidActorTemplateClass::attachShape(shape); +} + + +template<class APIClass> +void NpRigidBodyTemplate<APIClass>::setCMassLocalPoseInternal(const PxTransform& body2Actor) +{ + //the point here is to change the mass distribution w/o changing the actors' pose in the world + + PxTransform newBody2World = getGlobalPose() * body2Actor; + + mBody.setBody2World(newBody2World, true); + mBody.setBody2Actor(body2Actor); + + RigidActorTemplateClass::updateShaderComs(); +} + + +template<class APIClass> +PxTransform NpRigidBodyTemplate<APIClass>::getCMassLocalPose() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return getScbBodyFast().getBody2Actor(); +} + + +template<class APIClass> +void NpRigidBodyTemplate<APIClass>::setMass(PxReal mass) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(PxIsFinite(mass), "PxRigidDynamic::setMass: invalid float"); + PX_CHECK_AND_RETURN(mass>=0, "PxRigidDynamic::setMass: mass must be non-negative!"); + PX_CHECK_AND_RETURN(this->getType() != PxActorType::eARTICULATION_LINK || mass > 0.0f, "PxRigidDynamic::setMassSpaceInertiaTensor: components must be > 0 for articualtions"); + + getScbBodyFast().setInverseMass(mass > 0.0f ? 1.0f/mass : 0.0f); +} + + +template<class APIClass> +PxReal NpRigidBodyTemplate<APIClass>::getMass() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + const PxReal invMass = mBody.getInverseMass(); + + return invMass > 0.0f ? 1.0f/invMass : 0.0f; +} + +template<class APIClass> +PxReal NpRigidBodyTemplate<APIClass>::getInvMass() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return mBody.getInverseMass(); +} + + +template<class APIClass> +void NpRigidBodyTemplate<APIClass>::setMassSpaceInertiaTensor(const PxVec3& m) +{ + PX_CHECK_AND_RETURN(m.isFinite(), "PxRigidDynamic::setMassSpaceInertiaTensor: invalid inertia"); + PX_CHECK_AND_RETURN(m.x>=0.0f && m.y>=0.0f && m.z>=0.0f, "PxRigidDynamic::setMassSpaceInertiaTensor: components must be non-negative"); + PX_CHECK_AND_RETURN(this->getType() != PxActorType::eARTICULATION_LINK || (m.x > 0.0f && m.y > 0.0f && m.z > 0.0f), "PxRigidDynamic::setMassSpaceInertiaTensor: components must be > 0 for articualtions"); + + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + mBody.setInverseInertia(invertDiagInertia(m)); +} + + +template<class APIClass> +PxVec3 NpRigidBodyTemplate<APIClass>::getMassSpaceInertiaTensor() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return invertDiagInertia(mBody.getInverseInertia()); +} + +template<class APIClass> +PxVec3 NpRigidBodyTemplate<APIClass>::getMassSpaceInvInertiaTensor() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return mBody.getInverseInertia(); +} + + +template<class APIClass> +PxVec3 NpRigidBodyTemplate<APIClass>::getLinearVelocity() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return mBody.getLinearVelocity(); +} + + +template<class APIClass> +PxVec3 NpRigidBodyTemplate<APIClass>::getAngularVelocity() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return mBody.getAngularVelocity(); +} + + +template<class APIClass> +void NpRigidBodyTemplate<APIClass>::addSpatialForce(const PxVec3* force, const PxVec3* torque, PxForceMode::Enum mode) +{ + PX_ASSERT(!(mBody.getFlags() & PxRigidBodyFlag::eKINEMATIC)); + + switch (mode) + { + case PxForceMode::eFORCE: + { + PxVec3 linAcc, angAcc; + if (force) + { + linAcc = (*force) * mBody.getInverseMass(); + force = &linAcc; + } + if (torque) + { + angAcc = mBody.getGlobalInertiaTensorInverse() * (*torque); + torque = &angAcc; + } + mBody.addSpatialAcceleration(force, torque); + } + break; + + case PxForceMode::eACCELERATION: + mBody.addSpatialAcceleration(force, torque); + break; + + case PxForceMode::eIMPULSE: + { + PxVec3 linVelDelta, angVelDelta; + if (force) + { + linVelDelta = ((*force) * mBody.getInverseMass()); + force = &linVelDelta; + } + if (torque) + { + angVelDelta = (mBody.getGlobalInertiaTensorInverse() * (*torque)); + torque = &angVelDelta; + } + mBody.addSpatialVelocity(force, torque); + } + break; + + case PxForceMode::eVELOCITY_CHANGE: + mBody.addSpatialVelocity(force, torque); + break; + } +} + +template<class APIClass> +void NpRigidBodyTemplate<APIClass>::clearSpatialForce(PxForceMode::Enum mode, bool force, bool torque) +{ + PX_ASSERT(!(mBody.getFlags() & PxRigidBodyFlag::eKINEMATIC)); + + switch (mode) + { + case PxForceMode::eFORCE: + case PxForceMode::eACCELERATION: + mBody.clearSpatialAcceleration(force, torque); + break; + case PxForceMode::eIMPULSE: + case PxForceMode::eVELOCITY_CHANGE: + mBody.clearSpatialVelocity(force, torque); + break; + } +} + + +#if PX_ENABLE_DEBUG_VISUALIZATION +template<class APIClass> +void NpRigidBodyTemplate<APIClass>::visualize(Cm::RenderOutput& out, NpScene* scene) +{ + RigidActorTemplateClass::visualize(out, scene); + + if (mBody.getActorFlags() & PxActorFlag::eVISUALIZATION) + { + Scb::Scene& scbScene = scene->getScene(); + const PxReal scale = scbScene.getVisualizationParameter(PxVisualizationParameter::eSCALE); + + //visualize actor frames + const PxReal actorAxes = scale * scbScene.getVisualizationParameter(PxVisualizationParameter::eACTOR_AXES); + if (actorAxes != 0.0f) + out << getGlobalPose() << Cm::DebugBasis(PxVec3(actorAxes)); + + const PxReal bodyAxes = scale * scbScene.getVisualizationParameter(PxVisualizationParameter::eBODY_AXES); + if (bodyAxes != 0.0f) + out << mBody.getBody2World() << Cm::DebugBasis(PxVec3(bodyAxes)); + + const PxReal linVelocity = scale * scbScene.getVisualizationParameter(PxVisualizationParameter::eBODY_LIN_VELOCITY); + if (linVelocity != 0.0f) + { + out << 0xffffff << PxMat44(PxIdentity) << Cm::DebugArrow(mBody.getBody2World().p, + mBody.getLinearVelocity() * linVelocity, 0.2f * linVelocity); + } + + const PxReal angVelocity = scale * scbScene.getVisualizationParameter(PxVisualizationParameter::eBODY_ANG_VELOCITY); + if (angVelocity != 0.0f) + { + out << 0x000000 << PxMat44(PxIdentity) << Cm::DebugArrow(mBody.getBody2World().p, + mBody.getAngularVelocity() * angVelocity, 0.2f * angVelocity); + } + } +} +#endif + + +PX_FORCE_INLINE void updateDynamicSceneQueryShapes(NpShapeManager& shapeManager, Sq::SceneQueryManager& sqManager) +{ + shapeManager.markAllSceneQueryForUpdate(sqManager); + sqManager.get(Sq::PruningIndex::eDYNAMIC).invalidateTimestamp(); +} + + +template<class APIClass> +PX_FORCE_INLINE void NpRigidBodyTemplate<APIClass>::setRigidBodyFlagsInternal(const PxRigidBodyFlags& currentFlags, const PxRigidBodyFlags& newFlags) +{ + PxRigidBodyFlags filteredNewFlags = newFlags; + //Test to ensure we are not enabling both CCD and kinematic state on a body. This is unsupported + if((filteredNewFlags & PxRigidBodyFlag::eENABLE_CCD) && (filteredNewFlags & PxRigidBodyFlag::eKINEMATIC)) + { + physx::shdfnd::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, + "RigidBody::setRigidBodyFlag: kinematic bodies with CCD enabled are not supported! CCD will be ignored."); + filteredNewFlags &= PxRigidBodyFlags(~PxRigidBodyFlag::eENABLE_CCD); + } + + if ((filteredNewFlags & PxRigidBodyFlag::eENABLE_CCD) && (filteredNewFlags & PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD)) + { + physx::shdfnd::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, + "RigidBody::setRigidBodyFlag: eENABLE_CCD can't be raised as the same time as eENABLE_SPECULATIVE_CCD! eENABLE_SPECULATIVE_CCD will be ignored."); + filteredNewFlags &= PxRigidBodyFlags(~PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD); + } + + Scb::Body& body = getScbBodyFast(); + NpScene* scene = NpActor::getAPIScene(*this); + + const bool isKinematic = currentFlags & PxRigidBodyFlag::eKINEMATIC; + const bool willBeKinematic = filteredNewFlags & PxRigidBodyFlag::eKINEMATIC; + const bool kinematicSwitchingToDynamic = isKinematic && (!willBeKinematic); + const bool dynamicSwitchingToKinematic = (!isKinematic) && willBeKinematic; + + if(kinematicSwitchingToDynamic) + { + NpShapeManager& shapeManager = this->getShapeManager(); + PxU32 nbShapes = shapeManager.getNbShapes(); + NpShape*const* shapes = shapeManager.getShapes(); + bool hasTriangleMesh = false; + for(PxU32 i=0;i<nbShapes;i++) + { + if((shapes[i]->getFlags() & PxShapeFlag::eSIMULATION_SHAPE) && (shapes[i]->getGeometryTypeFast()==PxGeometryType::eTRIANGLEMESH || shapes[i]->getGeometryTypeFast()==PxGeometryType::ePLANE || shapes[i]->getGeometryTypeFast()==PxGeometryType::eHEIGHTFIELD)) + { + hasTriangleMesh = true; + break; + } + } + if(hasTriangleMesh) + { + physx::shdfnd::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "RigidBody::setRigidBodyFlag: dynamic meshes/planes/heightfields are not supported!"); + return; + } + + PxTransform bodyTarget; + if ((currentFlags & PxRigidBodyFlag::eUSE_KINEMATIC_TARGET_FOR_SCENE_QUERIES) && body.getKinematicTarget(bodyTarget) && scene) + { + updateDynamicSceneQueryShapes(shapeManager, scene->getSceneQueryManagerFast()); + } + + body.clearSimStateDataForPendingInsert(); + } + else if (dynamicSwitchingToKinematic) + { + if (this->getType() != PxActorType::eARTICULATION_LINK) + { + body.transitionSimStateDataForPendingInsert(); + } + else + { + //We're an articulation, raise an issue + physx::shdfnd::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "RigidBody::setRigidBodyFlag: kinematic articulation links are not supported!"); + return; + } + } + + const bool kinematicSwitchingUseTargetForSceneQuery = isKinematic && willBeKinematic && + ((currentFlags & PxRigidBodyFlag::eUSE_KINEMATIC_TARGET_FOR_SCENE_QUERIES) != (filteredNewFlags & PxRigidBodyFlag::eUSE_KINEMATIC_TARGET_FOR_SCENE_QUERIES)); + if (kinematicSwitchingUseTargetForSceneQuery) + { + PxTransform bodyTarget; + if (body.getKinematicTarget(bodyTarget) && scene) + { + updateDynamicSceneQueryShapes(this->getShapeManager(), scene->getSceneQueryManagerFast()); + } + } + + body.setFlags(filteredNewFlags); +} + + +template<class APIClass> +void NpRigidBodyTemplate<APIClass>::setRigidBodyFlag(PxRigidBodyFlag::Enum flag, bool value) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + Scb::Body& body = getScbBodyFast(); + const PxRigidBodyFlags currentFlags = body.getFlags(); + const PxRigidBodyFlags newFlags = value ? currentFlags | flag : currentFlags & (~PxRigidBodyFlags(flag)); + + setRigidBodyFlagsInternal(currentFlags, newFlags); +} + + +template<class APIClass> +void NpRigidBodyTemplate<APIClass>::setRigidBodyFlags(PxRigidBodyFlags inFlags) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + Scb::Body& body = getScbBodyFast(); + const PxRigidBodyFlags currentFlags = body.getFlags(); + + setRigidBodyFlagsInternal(currentFlags, inFlags); +} + + +template<class APIClass> +void NpRigidBodyTemplate<APIClass>::setMinCCDAdvanceCoefficient(PxReal minCCDAdvanceCoefficient) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + mBody.setMinCCDAdvanceCoefficient(minCCDAdvanceCoefficient); +} + +template<class APIClass> +PxReal NpRigidBodyTemplate<APIClass>::getMinCCDAdvanceCoefficient() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return mBody.getMinCCDAdvanceCoefficient(); +} + +template<class APIClass> +void NpRigidBodyTemplate<APIClass>::setMaxDepenetrationVelocity(PxReal maxDepenVel) +{ + PX_CHECK_AND_RETURN(maxDepenVel > 0.0f, "PxRigidDynamic::setMaxDepenetrationVelocity: maxDepenVel must be greater than zero."); + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + mBody.setMaxPenetrationBias(-maxDepenVel); +} + +template<class APIClass> +PxReal NpRigidBodyTemplate<APIClass>::getMaxDepenetrationVelocity() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return -mBody.getMaxPenetrationBias(); +} + +template<class APIClass> +void NpRigidBodyTemplate<APIClass>::setMaxContactImpulse(const PxReal maxImpulse) +{ + PX_CHECK_AND_RETURN(maxImpulse >= 0.f, "NpRigidBody::setMaxImpulse: impulse limit must be greater than or equal to zero."); + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + mBody.setMaxContactImpulse(maxImpulse); +} + +template<class APIClass> +PxReal NpRigidBodyTemplate<APIClass>::getMaxContactImpulse() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return mBody.getMaxContactImpulse(); +} + + + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/NpRigidDynamic.cpp b/PhysX_3.4/Source/PhysX/src/NpRigidDynamic.cpp new file mode 100644 index 00000000..52ccccab --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpRigidDynamic.cpp @@ -0,0 +1,533 @@ +// 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 "NpRigidDynamic.h" +#include "NpRigidActorTemplateInternal.h" + +using namespace physx; + +NpRigidDynamic::NpRigidDynamic(const PxTransform& bodyPose) +: NpRigidDynamicT(PxConcreteType::eRIGID_DYNAMIC, PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE, PxActorType::eRIGID_DYNAMIC, bodyPose) +{} + +NpRigidDynamic::~NpRigidDynamic() +{ +} + +// PX_SERIALIZATION +void NpRigidDynamic::requires(PxProcessPxBaseCallback& c) +{ + NpRigidDynamicT::requires(c); +} + +NpRigidDynamic* NpRigidDynamic::createObject(PxU8*& address, PxDeserializationContext& context) +{ + NpRigidDynamic* obj = new (address) NpRigidDynamic(PxBaseFlag::eIS_RELEASABLE); + address += sizeof(NpRigidDynamic); + obj->importExtraData(context); + obj->resolveReferences(context); + return obj; +} +//~PX_SERIALIZATION + +void NpRigidDynamic::release() +{ + releaseActorT(this, mBody); +} + + +void NpRigidDynamic::setGlobalPose(const PxTransform& pose, bool autowake) +{ + NpScene* scene = NpActor::getAPIScene(*this); + +#if PX_CHECKED + if(scene) + scene->checkPositionSanity(*this, pose, "PxRigidDynamic::setGlobalPose"); +#endif + + PX_CHECK_AND_RETURN(pose.isSane(), "PxRigidDynamic::setGlobalPose: pose is not valid."); + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + if(scene) + updateDynamicSceneQueryShapes(mShapeManager, scene->getSceneQueryManagerFast()); + + const PxTransform newPose = pose.getNormalized(); //AM: added to fix 1461 where users read and write orientations for no reason. + + Scb::Body& b = getScbBodyFast(); + const PxTransform body2World = newPose * b.getBody2Actor(); + b.setBody2World(body2World, false); + + // invalidate the pruning structure if the actor bounds changed + if(mShapeManager.getPruningStructure()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxRigidDynamic::setGlobalPose: Actor is part of a pruning structure, pruning structure is now invalid!"); + mShapeManager.getPruningStructure()->invalidate(this); + } + + if(scene && autowake && !(b.getActorFlags() & PxActorFlag::eDISABLE_SIMULATION)) + wakeUpInternal(); +} + + +PX_FORCE_INLINE void NpRigidDynamic::setKinematicTargetInternal(const PxTransform& targetPose) +{ + Scb::Body& b = getScbBodyFast(); + + // The target is actor related. Transform to body related target + const PxTransform bodyTarget = targetPose * b.getBody2Actor(); + + b.setKinematicTarget(bodyTarget); + + NpScene* scene = NpActor::getAPIScene(*this); + if ((b.getFlags() & PxRigidBodyFlag::eUSE_KINEMATIC_TARGET_FOR_SCENE_QUERIES) && scene) + { + updateDynamicSceneQueryShapes(mShapeManager, scene->getSceneQueryManagerFast()); + } +} + + +void NpRigidDynamic::setKinematicTarget(const PxTransform& destination) +{ + PX_CHECK_AND_RETURN(destination.isSane(), "PxRigidDynamic::setKinematicTarget: destination is not valid."); + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + +#if PX_CHECKED + NpScene* scene = NpActor::getAPIScene(*this); + if(scene) + scene->checkPositionSanity(*this, destination, "PxRigidDynamic::setKinematicTarget"); + + Scb::Body& b = getScbBodyFast(); + PX_CHECK_AND_RETURN((b.getFlags() & PxRigidBodyFlag::eKINEMATIC), "PxRigidDynamic::setKinematicTarget: Body must be kinematic!"); + PX_CHECK_AND_RETURN(scene, "PxRigidDynamic::setKinematicTarget: Body must be in a scene!"); + PX_CHECK_AND_RETURN(!(b.getActorFlags() & PxActorFlag::eDISABLE_SIMULATION), "PxRigidDynamic::setKinematicTarget: Not allowed if PxActorFlag::eDISABLE_SIMULATION is set!"); +#endif + + setKinematicTargetInternal(destination.getNormalized()); +} + + +bool NpRigidDynamic::getKinematicTarget(PxTransform& target) +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + Scb::Body& b = getScbBodyFast(); + if(b.getFlags() & PxRigidBodyFlag::eKINEMATIC) + { + PxTransform bodyTarget; + if(b.getKinematicTarget(bodyTarget)) + { + // The internal target is body related. Transform to actor related target + target = bodyTarget * b.getBody2Actor().getInverse(); + return true; + } + } + return false; +} + + +void NpRigidDynamic::setCMassLocalPose(const PxTransform& pose) +{ + PX_CHECK_AND_RETURN(pose.isSane(), "PxRigidDynamic::setCMassLocalPose pose is not valid."); + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + const PxTransform p = pose.getNormalized(); + + const PxTransform oldBody2Actor = getScbBodyFast().getBody2Actor(); + + NpRigidDynamicT::setCMassLocalPoseInternal(p); + + Scb::Body& b = getScbBodyFast(); + if(b.getFlags() & PxRigidBodyFlag::eKINEMATIC) + { + PxTransform bodyTarget; + if(b.getKinematicTarget(bodyTarget)) + { + PxTransform actorTarget = bodyTarget * oldBody2Actor.getInverse(); // get old target pose for the actor from the body target + setKinematicTargetInternal(actorTarget); + } + } +} + + +void NpRigidDynamic::setLinearDamping(PxReal linearDamping) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(PxIsFinite(linearDamping), "PxRigidDynamic::setLinearDamping: invalid float"); + PX_CHECK_AND_RETURN(linearDamping >=0, "PxRigidDynamic::setLinearDamping: The linear damping must be nonnegative!"); + + getScbBodyFast().setLinearDamping(linearDamping); +} + + +PxReal NpRigidDynamic::getLinearDamping() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return getScbBodyFast().getLinearDamping(); +} + + +void NpRigidDynamic::setAngularDamping(PxReal angularDamping) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(PxIsFinite(angularDamping), "PxRigidDynamic::setAngularDamping: invalid float"); + PX_CHECK_AND_RETURN(angularDamping>=0, "PxRigidDynamic::setAngularDamping: The angular damping must be nonnegative!") + + getScbBodyFast().setAngularDamping(angularDamping); +} + + +PxReal NpRigidDynamic::getAngularDamping() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return getScbBodyFast().getAngularDamping(); +} + + +void NpRigidDynamic::setLinearVelocity(const PxVec3& velocity, bool autowake) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(velocity.isFinite(), "PxRigidDynamic::setLinearVelocity: velocity is not valid."); + PX_CHECK_AND_RETURN(!(getScbBodyFast().getFlags() & PxRigidBodyFlag::eKINEMATIC), "PxRigidDynamic::setLinearVelocity: Body must be non-kinematic!"); + PX_CHECK_AND_RETURN(!(getScbBodyFast().getActorFlags() & PxActorFlag::eDISABLE_SIMULATION), "PxRigidDynamic::setLinearVelocity: Not allowed if PxActorFlag::eDISABLE_SIMULATION is set!"); + + Scb::Body& b = getScbBodyFast(); + b.setLinearVelocity(velocity); + + NpScene* scene = NpActor::getAPIScene(*this); + if(scene) + wakeUpInternalNoKinematicTest(b, (!velocity.isZero()), autowake); +} + + +void NpRigidDynamic::setAngularVelocity(const PxVec3& velocity, bool autowake) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(velocity.isFinite(), "PxRigidDynamic::setAngularVelocity: velocity is not valid."); + PX_CHECK_AND_RETURN(!(getScbBodyFast().getFlags() & PxRigidBodyFlag::eKINEMATIC), "PxRigidDynamic::setAngularVelocity: Body must be non-kinematic!"); + PX_CHECK_AND_RETURN(!(getScbBodyFast().getActorFlags() & PxActorFlag::eDISABLE_SIMULATION), "PxRigidDynamic::setAngularVelocity: Not allowed if PxActorFlag::eDISABLE_SIMULATION is set!"); + + Scb::Body& b = getScbBodyFast(); + b.setAngularVelocity(velocity); + + NpScene* scene = NpActor::getAPIScene(*this); + if(scene) + wakeUpInternalNoKinematicTest(b, (!velocity.isZero()), autowake); +} + + +void NpRigidDynamic::setMaxAngularVelocity(PxReal maxAngularVelocity) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(PxIsFinite(maxAngularVelocity), "PxRigidDynamic::setMaxAngularVelocity: invalid float"); + PX_CHECK_AND_RETURN(maxAngularVelocity>=0.0f, "PxRigidDynamic::setMaxAngularVelocity: threshold must be non-negative!"); + + getScbBodyFast().setMaxAngVelSq(maxAngularVelocity * maxAngularVelocity); +} + + +PxReal NpRigidDynamic::getMaxAngularVelocity() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return PxSqrt(getScbBodyFast().getMaxAngVelSq()); +} + + +void NpRigidDynamic::addForce(const PxVec3& force, PxForceMode::Enum mode, bool autowake) +{ + Scb::Body& b = getScbBodyFast(); + + PX_CHECK_AND_RETURN(force.isFinite(), "PxRigidDynamic::addForce: force is not valid."); + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(NpActor::getAPIScene(*this), "PxRigidDynamic::addForce: Body must be in a scene!"); + PX_CHECK_AND_RETURN(!(b.getFlags() & PxRigidBodyFlag::eKINEMATIC), "PxRigidDynamic::addForce: Body must be non-kinematic!"); + PX_CHECK_AND_RETURN(!(b.getActorFlags() & PxActorFlag::eDISABLE_SIMULATION), "PxRigidDynamic::addForce: Not allowed if PxActorFlag::eDISABLE_SIMULATION is set!"); + + addSpatialForce(&force, NULL, mode); + + wakeUpInternalNoKinematicTest(b, (!force.isZero()), autowake); +} + + +void NpRigidDynamic::addTorque(const PxVec3& torque, PxForceMode::Enum mode, bool autowake) +{ + Scb::Body& b = getScbBodyFast(); + + PX_CHECK_AND_RETURN(torque.isFinite(), "PxRigidDynamic::addTorque: torque is not valid."); + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(NpActor::getAPIScene(*this), "PxRigidDynamic::addTorque: Body must be in a scene!"); + PX_CHECK_AND_RETURN(!(b.getFlags() & PxRigidBodyFlag::eKINEMATIC), "PxRigidDynamic::addTorque: Body must be non-kinematic!"); + PX_CHECK_AND_RETURN(!(b.getActorFlags() & PxActorFlag::eDISABLE_SIMULATION), "PxRigidDynamic::addTorque: Not allowed if PxActorFlag::eDISABLE_SIMULATION is set!"); + + addSpatialForce(NULL, &torque, mode); + + wakeUpInternalNoKinematicTest(b, (!torque.isZero()), autowake); +} + +void NpRigidDynamic::clearForce(PxForceMode::Enum mode) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(NpActor::getAPIScene(*this), "PxRigidDynamic::clearForce: Body must be in a scene!"); + PX_CHECK_AND_RETURN(!(getScbBodyFast().getFlags() & PxRigidBodyFlag::eKINEMATIC), "PxRigidDynamic::clearForce: Body must be non-kinematic!"); + PX_CHECK_AND_RETURN(!(getScbBodyFast().getActorFlags() & PxActorFlag::eDISABLE_SIMULATION), "PxRigidDynamic::clearForce: Not allowed if PxActorFlag::eDISABLE_SIMULATION is set!"); + + clearSpatialForce(mode, true, false); +} + + +void NpRigidDynamic::clearTorque(PxForceMode::Enum mode) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(NpActor::getAPIScene(*this), "PxRigidDynamic::clearTorque: Body must be in a scene!"); + PX_CHECK_AND_RETURN(!(getScbBodyFast().getFlags() & PxRigidBodyFlag::eKINEMATIC), "PxRigidDynamic::clearTorque: Body must be non-kinematic!"); + PX_CHECK_AND_RETURN(!(getScbBodyFast().getActorFlags() & PxActorFlag::eDISABLE_SIMULATION), "PxRigidDynamic::clearTorque: Not allowed if PxActorFlag::eDISABLE_SIMULATION is set!"); + + clearSpatialForce(mode, false, true); +} + + +bool NpRigidDynamic::isSleeping() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN_VAL(NpActor::getAPIScene(*this), "PxRigidDynamic::isSleeping: Body must be in a scene.", true); + + return getScbBodyFast().isSleeping(); +} + + +void NpRigidDynamic::setSleepThreshold(PxReal threshold) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(PxIsFinite(threshold), "PxRigidDynamic::setSleepThreshold: invalid float."); + PX_CHECK_AND_RETURN(threshold>=0.0f, "PxRigidDynamic::setSleepThreshold: threshold must be non-negative!"); + + getScbBodyFast().setSleepThreshold(threshold); +} + + +PxReal NpRigidDynamic::getSleepThreshold() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return getScbBodyFast().getSleepThreshold(); +} + +void NpRigidDynamic::setStabilizationThreshold(PxReal threshold) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(PxIsFinite(threshold), "PxRigidDynamic::setSleepThreshold: invalid float."); + PX_CHECK_AND_RETURN(threshold>=0.0f, "PxRigidDynamic::setSleepThreshold: threshold must be non-negative!"); + + getScbBodyFast().setFreezeThreshold(threshold); +} + + +PxReal NpRigidDynamic::getStabilizationThreshold() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return getScbBodyFast().getFreezeThreshold(); +} + + +void NpRigidDynamic::setWakeCounter(PxReal wakeCounterValue) +{ + Scb::Body& b = getScbBodyFast(); + + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(PxIsFinite(wakeCounterValue), "PxRigidDynamic::setWakeCounter: invalid float."); + PX_CHECK_AND_RETURN(wakeCounterValue>=0.0f, "PxRigidDynamic::setWakeCounter: wakeCounterValue must be non-negative!"); + PX_CHECK_AND_RETURN(!(b.getFlags() & PxRigidBodyFlag::eKINEMATIC), "PxRigidDynamic::setWakeCounter: Body must be non-kinematic!"); + PX_CHECK_AND_RETURN(!(b.getActorFlags() & PxActorFlag::eDISABLE_SIMULATION), "PxRigidDynamic::setWakeCounter: Not allowed if PxActorFlag::eDISABLE_SIMULATION is set!"); + + b.setWakeCounter(wakeCounterValue); +} + + +PxReal NpRigidDynamic::getWakeCounter() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return getScbBodyFast().getWakeCounter(); +} + + +void NpRigidDynamic::wakeUp() +{ + Scb::Body& b = getScbBodyFast(); + + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(NpActor::getAPIScene(*this), "PxRigidDynamic::wakeUp: Body must be in a scene."); + PX_CHECK_AND_RETURN(!(b.getFlags() & PxRigidBodyFlag::eKINEMATIC), "PxRigidDynamic::wakeUp: Body must be non-kinematic!"); + PX_CHECK_AND_RETURN(!(b.getActorFlags() & PxActorFlag::eDISABLE_SIMULATION), "PxRigidDynamic::wakeUp: Not allowed if PxActorFlag::eDISABLE_SIMULATION is set!"); + + b.wakeUp(); +} + + +void NpRigidDynamic::putToSleep() +{ + Scb::Body& b = getScbBodyFast(); + + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(NpActor::getAPIScene(*this), "PxRigidDynamic::putToSleep: Body must be in a scene."); + PX_CHECK_AND_RETURN(!(b.getFlags() & PxRigidBodyFlag::eKINEMATIC), "PxRigidDynamic::putToSleep: Body must be non-kinematic!"); + PX_CHECK_AND_RETURN(!(b.getActorFlags() & PxActorFlag::eDISABLE_SIMULATION), "PxRigidDynamic::putToSleep: Not allowed if PxActorFlag::eDISABLE_SIMULATION is set!"); + + b.putToSleep(); +} + + +void NpRigidDynamic::setSolverIterationCounts(PxU32 positionIters, PxU32 velocityIters) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(positionIters > 0, "PxRigidDynamic::setSolverIterationCount: positionIters must be more than zero!"); + PX_CHECK_AND_RETURN(positionIters <= 255, "PxRigidDynamic::setSolverIterationCount: positionIters must be no greater than 255!"); + PX_CHECK_AND_RETURN(velocityIters > 0, "PxRigidDynamic::setSolverIterationCount: velocityIters must be more than zero!"); + PX_CHECK_AND_RETURN(velocityIters <= 255, "PxRigidDynamic::setSolverIterationCount: velocityIters must be no greater than 255!"); + + getScbBodyFast().setSolverIterationCounts((velocityIters & 0xff) << 8 | (positionIters & 0xff)); +} + + +void NpRigidDynamic::getSolverIterationCounts(PxU32 & positionIters, PxU32 & velocityIters) const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + PxU16 x = getScbBodyFast().getSolverIterationCounts(); + velocityIters = PxU32(x >> 8); + positionIters = PxU32(x & 0xff); +} + + +void NpRigidDynamic::setContactReportThreshold(PxReal threshold) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(PxIsFinite(threshold), "PxRigidDynamic::setContactReportThreshold: invalid float."); + PX_CHECK_AND_RETURN(threshold >= 0.0f, "PxRigidDynamic::setContactReportThreshold: Force threshold must be greater than zero!"); + + getScbBodyFast().setContactReportThreshold(threshold<0 ? 0 : threshold); +} + + +PxReal NpRigidDynamic::getContactReportThreshold() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return getScbBodyFast().getContactReportThreshold(); +} + + +PxU32 physx::NpRigidDynamicGetShapes(Scb::Body& body, void* const*& shapes) +{ + NpRigidDynamic* a = static_cast<NpRigidDynamic*>(body.getScBody().getPxActor()); + NpShapeManager& sm = a->getShapeManager(); + shapes = reinterpret_cast<void *const *>(sm.getShapes()); + return sm.getNbShapes(); +} + + +void NpRigidDynamic::switchToNoSim() +{ + getScbBodyFast().switchBodyToNoSim(); +} + + +void NpRigidDynamic::switchFromNoSim() +{ + getScbBodyFast().switchFromNoSim(true); +} + + +void NpRigidDynamic::wakeUpInternalNoKinematicTest(Scb::Body& body, bool forceWakeUp, bool autowake) +{ + NpScene* scene = NpActor::getOwnerScene(*this); + PX_ASSERT(scene); + PxReal wakeCounterResetValue = scene->getWakeCounterResetValueInteral(); + + PxReal wakeCounter = body.getWakeCounter(); + + bool needsWakingUp = body.isSleeping() && (autowake || forceWakeUp); + if (autowake && (wakeCounter < wakeCounterResetValue)) + { + wakeCounter = wakeCounterResetValue; + needsWakingUp = true; + } + + if (needsWakingUp) + body.wakeUpInternal(wakeCounter); +} + +PxRigidDynamicLockFlags NpRigidDynamic::getRigidDynamicLockFlags() const +{ + return mBody.getLockFlags(); +} +void NpRigidDynamic::setRigidDynamicLockFlags(PxRigidDynamicLockFlags flags) +{ + mBody.setLockFlags(flags); +} +void NpRigidDynamic::setRigidDynamicLockFlag(PxRigidDynamicLockFlag::Enum flag, bool value) +{ + PxRigidDynamicLockFlags flags = mBody.getLockFlags(); + if (value) + flags = flags | flag; + else + flags = flags & (~flag); + + mBody.setLockFlags(flags); +} + + +#if PX_ENABLE_DEBUG_VISUALIZATION +void NpRigidDynamic::visualize(Cm::RenderOutput& out, NpScene* npScene) +{ + NpRigidDynamicT::visualize(out, npScene); + + if (getScbBodyFast().getActorFlags() & PxActorFlag::eVISUALIZATION) + { + PX_ASSERT(npScene); + const PxReal scale = npScene->getVisualizationParameter(PxVisualizationParameter::eSCALE); + + const PxReal massAxes = scale * npScene->getVisualizationParameter(PxVisualizationParameter::eBODY_MASS_AXES); + if (massAxes != 0.0f) + { + PxReal sleepTime = getScbBodyFast().getWakeCounter() / npScene->getWakeCounterResetValueInteral(); + PxU32 color = PxU32(0xff * (sleepTime>1.0f ? 1.0f : sleepTime)); + color = getScbBodyFast().isSleeping() ? 0xff0000 : (color<<16 | color<<8 | color); + PxVec3 dims = invertDiagInertia(getScbBodyFast().getInverseInertia()); + dims = getDimsFromBodyInertia(dims, 1.0f / getScbBodyFast().getInverseMass()); + + out << color << getScbBodyFast().getBody2World() << Cm::DebugBox(dims * 0.5f); + } + } +} +#endif diff --git a/PhysX_3.4/Source/PhysX/src/NpRigidDynamic.h b/PhysX_3.4/Source/PhysX/src/NpRigidDynamic.h new file mode 100644 index 00000000..1458f0fe --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpRigidDynamic.h @@ -0,0 +1,171 @@ +// 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_NP_RIGIDDYNAMIC +#define PX_PHYSICS_NP_RIGIDDYNAMIC + +#include "NpRigidBodyTemplate.h" +#include "PxRigidDynamic.h" +#include "ScbBody.h" +#include "PxMetaData.h" + +namespace physx +{ + +class NpRigidDynamic; +typedef NpRigidBodyTemplate<PxRigidDynamic> NpRigidDynamicT; + +class NpRigidDynamic : public NpRigidDynamicT +{ +//= 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 + NpRigidDynamic(PxBaseFlags baseFlags) : NpRigidDynamicT(baseFlags) {} + + virtual void requires(PxProcessPxBaseCallback& c); + + static NpRigidDynamic* createObject(PxU8*& address, PxDeserializationContext& context); + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + virtual ~NpRigidDynamic(); + + //--------------------------------------------------------------------------------- + // PxActor implementation + //--------------------------------------------------------------------------------- + + virtual void release(); + + //--------------------------------------------------------------------------------- + // PxRigidDynamic implementation + //--------------------------------------------------------------------------------- + + virtual PxActorType::Enum getType() const { return PxActorType::eRIGID_DYNAMIC; } + + // Pose + virtual void setGlobalPose(const PxTransform& pose, bool autowake); + PX_FORCE_INLINE PxTransform getGlobalPoseFast() const + { + const Scb::Body& body=getScbBodyFast(); + return body.getBody2World() * body.getBody2Actor().getInverse(); + } + virtual PxTransform getGlobalPose() const + { + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return getGlobalPoseFast(); + } + + virtual void setKinematicTarget(const PxTransform& destination); + virtual bool getKinematicTarget(PxTransform& target); + + // Center of mass pose + virtual void setCMassLocalPose(const PxTransform&); + + // Damping + virtual void setLinearDamping(PxReal); + virtual PxReal getLinearDamping() const; + virtual void setAngularDamping(PxReal); + virtual PxReal getAngularDamping() const; + + // Velocity + virtual void setLinearVelocity(const PxVec3&, bool autowake); + virtual void setAngularVelocity(const PxVec3&, bool autowake); + virtual void setMaxAngularVelocity(PxReal); + virtual PxReal getMaxAngularVelocity() const; + + // Force/Torque modifiers + virtual void addForce(const PxVec3&, PxForceMode::Enum mode, bool autowake); + virtual void clearForce(PxForceMode::Enum mode); + virtual void addTorque(const PxVec3&, PxForceMode::Enum mode, bool autowake); + virtual void clearTorque(PxForceMode::Enum mode); + + // Sleeping + virtual bool isSleeping() const; + virtual PxReal getSleepThreshold() const; + virtual void setSleepThreshold(PxReal threshold); + virtual PxReal getStabilizationThreshold() const; + virtual void setStabilizationThreshold(PxReal threshold); + virtual void setWakeCounter(PxReal wakeCounterValue); + virtual PxReal getWakeCounter() const; + virtual void wakeUp(); + virtual void putToSleep(); + + virtual void setSolverIterationCounts(PxU32 positionIters, PxU32 velocityIters); + virtual void getSolverIterationCounts(PxU32 & positionIters, PxU32 & velocityIters) const; + + virtual void setContactReportThreshold(PxReal threshold); + virtual PxReal getContactReportThreshold() const; + + virtual PxRigidDynamicLockFlags getRigidDynamicLockFlags() const; + virtual void setRigidDynamicLockFlags(PxRigidDynamicLockFlags flags); + virtual void setRigidDynamicLockFlag(PxRigidDynamicLockFlag::Enum flag, bool value); + + //--------------------------------------------------------------------------------- + // Miscellaneous + //--------------------------------------------------------------------------------- + NpRigidDynamic(const PxTransform& bodyPose); + + virtual void switchToNoSim(); + virtual void switchFromNoSim(); + + PX_FORCE_INLINE void wakeUpInternal(); + void wakeUpInternalNoKinematicTest(Scb::Body& body, bool forceWakeUp, bool autowake); + +private: + PX_FORCE_INLINE void setKinematicTargetInternal(const PxTransform& destination); + +#if PX_ENABLE_DEBUG_VISUALIZATION +public: + void visualize(Cm::RenderOutput& out, NpScene* scene); +#endif +}; + + + + +PX_FORCE_INLINE void NpRigidDynamic::wakeUpInternal() +{ + PX_ASSERT(NpActor::getOwnerScene(*this)); + + Scb::Body& body = getScbBodyFast(); + const PxRigidBodyFlags currentFlags = body.getFlags(); + + if (!(currentFlags & PxRigidBodyFlag::eKINEMATIC)) // kinematics are only awake when a target is set, else they are asleep + wakeUpInternalNoKinematicTest(body, false, true); +} + + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/NpRigidStatic.cpp b/PhysX_3.4/Source/PhysX/src/NpRigidStatic.cpp new file mode 100644 index 00000000..0f3f8a15 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpRigidStatic.cpp @@ -0,0 +1,180 @@ +// 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 "NpRigidStatic.h" +#include "NpPhysics.h" +#include "ScbNpDeps.h" +#include "NpScene.h" +#include "NpRigidActorTemplateInternal.h" + +using namespace physx; + +NpRigidStatic::NpRigidStatic(const PxTransform& pose) +: NpRigidStaticT(PxConcreteType::eRIGID_STATIC, PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE) +, mRigidStatic(pose) +{ +} + +NpRigidStatic::~NpRigidStatic() +{ +} + +// PX_SERIALIZATION +void NpRigidStatic::requires(PxProcessPxBaseCallback& c) +{ + NpRigidStaticT::requires(c); +} + +NpRigidStatic* NpRigidStatic::createObject(PxU8*& address, PxDeserializationContext& context) +{ + NpRigidStatic* obj = new (address) NpRigidStatic(PxBaseFlag::eIS_RELEASABLE); + address += sizeof(NpRigidStatic); + obj->importExtraData(context); + obj->resolveReferences(context); + return obj; +} +//~PX_SERIALIZATION + +void NpRigidStatic::release() +{ + releaseActorT(this, mRigidStatic); +} + +void NpRigidStatic::setGlobalPose(const PxTransform& pose, bool /*wake*/) +{ + PX_CHECK_AND_RETURN(pose.isSane(), "PxRigidStatic::setGlobalPose: pose is not valid."); + + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + NpScene* npScene = NpActor::getAPIScene(*this); +#if PX_CHECKED + if(npScene) + npScene->checkPositionSanity(*this, pose, "PxRigidStatic::setGlobalPose"); +#endif + + mRigidStatic.setActor2World(pose.getNormalized()); + + if(npScene) + { + mShapeManager.markAllSceneQueryForUpdate(npScene->getSceneQueryManagerFast()); + npScene->getSceneQueryManagerFast().get(Sq::PruningIndex::eSTATIC).invalidateTimestamp(); + } + +#if PX_SUPPORT_PVD + // have to do this here since this call gets not forwarded to Scb::RigidStatic + Scb::Scene* scbScene = NpActor::getScbFromPxActor(*this).getScbSceneForAPI(); + if(scbScene) + scbScene->getScenePvdClient().updatePvdProperties(&mRigidStatic); +#endif + + // invalidate the pruning structure if the actor bounds changed + if (mShapeManager.getPruningStructure()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxRigidStatic::setGlobalPose: Actor is part of a pruning structure, pruning structure is now invalid!"); + mShapeManager.getPruningStructure()->invalidate(this); + } + + updateShaderComs(); +} + +PxTransform NpRigidStatic::getGlobalPose() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return mRigidStatic.getActor2World(); +} + +PxShape* NpRigidStatic::createShape(const PxGeometry& geometry, PxMaterial*const* materials, PxU16 materialCount, PxShapeFlags shapeFlags) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_AND_RETURN_NULL(materials, "createShape: material pointer is NULL"); + PX_CHECK_AND_RETURN_NULL(materialCount>0, "createShape: material count is zero"); + + NpShape* shape = static_cast<NpShape*>(NpPhysics::getInstance().createShape(geometry, materials, materialCount, true, shapeFlags)); + + if ( shape != NULL ) + { + mShapeManager.attachShape(*shape, *this); + shape->releaseInternal(); + } + return shape; +} + +PxU32 physx::NpRigidStaticGetShapes(Scb::RigidStatic& rigid, void* const *&shapes) +{ + NpRigidStatic* a = static_cast<NpRigidStatic*>(rigid.getScRigidCore().getPxActor()); + NpShapeManager& sm = a->getShapeManager(); + shapes = reinterpret_cast<void *const *>(sm.getShapes()); + return sm.getNbShapes(); +} + +void NpRigidStatic::switchToNoSim() +{ + getScbRigidStaticFast().switchToNoSim(false); +} + +void NpRigidStatic::switchFromNoSim() +{ + getScbRigidStaticFast().switchFromNoSim(false); +} + +#if PX_CHECKED +bool NpRigidStatic::checkConstraintValidity() const +{ + // Perhaps NpConnectorConstIterator would be worth it... + NpConnectorIterator iter = (const_cast<NpRigidStatic*>(this))->getConnectorIterator(NpConnectorType::eConstraint); + while (PxBase* ser = iter.getNext()) + { + NpConstraint* c = static_cast<NpConstraint*>(ser); + if(!c->NpConstraint::isValid()) + return false; + } + return true; +} +#endif + +#if PX_ENABLE_DEBUG_VISUALIZATION +void NpRigidStatic::visualize(Cm::RenderOutput& out, NpScene* scene) +{ + NpRigidStaticT::visualize(out, scene); + + if (getScbRigidStaticFast().getActorFlags() & PxActorFlag::eVISUALIZATION) + { + Scb::Scene& scbScene = scene->getScene(); + PxReal scale = scbScene.getVisualizationParameter(PxVisualizationParameter::eSCALE); + + //visualize actor frames + PxReal actorAxes = scale * scbScene.getVisualizationParameter(PxVisualizationParameter::eACTOR_AXES); + if (actorAxes != 0) + out << getGlobalPose() << Cm::DebugBasis(PxVec3(actorAxes)); + } +} +#endif + diff --git a/PhysX_3.4/Source/PhysX/src/NpRigidStatic.h b/PhysX_3.4/Source/PhysX/src/NpRigidStatic.h new file mode 100644 index 00000000..fad1296c --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpRigidStatic.h @@ -0,0 +1,118 @@ +// 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_NP_RIGIDSTATIC +#define PX_PHYSICS_NP_RIGIDSTATIC + +#include "NpRigidActorTemplate.h" +#include "PxRigidStatic.h" +#include "ScbRigidStatic.h" + +#include "PxMetaData.h" + +namespace physx +{ + +namespace Scb +{ + class RigidObject; +} + +class NpRigidStatic; +typedef NpRigidActorTemplate<PxRigidStatic> NpRigidStaticT; + +class NpRigidStatic : public NpRigidStaticT +{ +//= 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 + NpRigidStatic(PxBaseFlags baseFlags) : NpRigidStaticT(baseFlags), mRigidStatic(PxEmpty) {} + virtual void requires(PxProcessPxBaseCallback& c); + static NpRigidStatic* createObject(PxU8*& address, PxDeserializationContext& context); + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + + virtual ~NpRigidStatic(); + + //--------------------------------------------------------------------------------- + // PxActor implementation + //--------------------------------------------------------------------------------- + virtual void release(); + + virtual PxActorType::Enum getType() const { return PxActorType::eRIGID_STATIC; } + + //--------------------------------------------------------------------------------- + // PxRigidActor implementation + //--------------------------------------------------------------------------------- + + virtual PxShape* createShape(const PxGeometry& geometry, PxMaterial*const* material, + PxU16 materialCount, PxShapeFlags shapeFlags); + + // Pose + virtual void setGlobalPose(const PxTransform& pose, bool wake); + virtual PxTransform getGlobalPose() const; + + //--------------------------------------------------------------------------------- + // Miscellaneous + //--------------------------------------------------------------------------------- + NpRigidStatic(const PxTransform& pose); + + virtual void switchToNoSim(); + virtual void switchFromNoSim(); + +#if PX_CHECKED + bool checkConstraintValidity() const; +#endif + + PX_FORCE_INLINE const Scb::Actor& getScbActorFast() const { return mRigidStatic; } + PX_FORCE_INLINE Scb::Actor& getScbActorFast() { return mRigidStatic; } + + PX_FORCE_INLINE const Scb::RigidStatic& getScbRigidStaticFast() const { return mRigidStatic; } + PX_FORCE_INLINE Scb::RigidStatic& getScbRigidStaticFast() { return mRigidStatic; } + + PX_FORCE_INLINE const PxTransform& getGlobalPoseFast() const { return mRigidStatic.getActor2World(); } + +#if PX_ENABLE_DEBUG_VISUALIZATION +public: + void visualize(Cm::RenderOutput& out, NpScene* scene); +#endif + +private: + Scb::RigidStatic mRigidStatic; +}; + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/NpScene.cpp b/PhysX_3.4/Source/PhysX/src/NpScene.cpp new file mode 100644 index 00000000..eb81cb66 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpScene.cpp @@ -0,0 +1,3185 @@ +// 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 "PxSimulationEventCallback.h" + +#include "NpScene.h" +#include "NpRigidStatic.h" +#include "NpRigidDynamic.h" +#include "NpArticulation.h" +#include "NpArticulationLink.h" +#include "NpArticulationJoint.h" +// PX_AGGREGATE +#include "NpAggregate.h" +//~PX_AGGREGATE +#include "NpVolumeCache.h" +#include "NpBatchQuery.h" +#include "SqPruner.h" +#include "SqPrunerMergeData.h" +#include "SqPruningStructure.h" +#include "SqSceneQueryManager.h" + +#if PX_USE_PARTICLE_SYSTEM_API +#include "particles/NpParticleSystem.h" +#include "particles/NpParticleFluid.h" +#include "ScbParticleSystem.h" +#endif + +#if PX_USE_CLOTH_API +#include "NpCloth.h" +#endif + +#include "ScbNpDeps.h" +#include "CmCollection.h" +#include "CmUtils.h" + +#if PX_SUPPORT_GPU_PHYSX +#include "task/PxGpuDispatcher.h" +#endif + +#include "PxsIslandSim.h" + +using namespace physx; + +// enable thread checks in all debug builds +#if PX_DEBUG || PX_CHECKED +#define NP_ENABLE_THREAD_CHECKS 1 +#else +#define NP_ENABLE_THREAD_CHECKS 0 +#endif + +using namespace shdfnd; +using namespace Sq; + +/////////////////////////////////////////////////////////////////////////////// + +static PX_FORCE_INLINE bool removeFromSceneCheck(NpScene* npScene, PxScene* scene, const char* name) +{ + if (scene == static_cast<PxScene*>(npScene)) + { + return true; + } + else + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "%s not assigned to scene or assigned to another scene. Call will be ignored!", name); + return false; + } +} + +/////////////////////////////////////////////////////////////////////////////// +NpSceneQueries::NpSceneQueries(const PxSceneDesc& desc) : + mScene (desc, getContextId()), + mSQManager (mScene, desc.staticStructure, desc.dynamicStructure, desc.dynamicTreeRebuildRateHint, desc.limits), + mCachedRaycastFuncs (Gu::getRaycastFuncTable()), + mCachedSweepFuncs (Gu::getSweepFuncTable()), + mCachedOverlapFuncs (Gu::getOverlapFuncTable()) +#if PX_SUPPORT_PVD + , mSingleSqCollector (mScene, false), + mBatchedSqCollector (mScene, true) +#endif +{ +} + +NpScene::NpScene(const PxSceneDesc& desc) : + NpSceneQueries (desc), + mConstraints (PX_DEBUG_EXP("sceneConstraints")), + mRigidActors (PX_DEBUG_EXP("sceneRigidActors")), + mArticulations (PX_DEBUG_EXP("sceneArticulations")), + mAggregates (PX_DEBUG_EXP("sceneAggregates")), +#if PX_USE_PARTICLE_SYSTEM_API + mPxParticleBaseSet (PX_DEBUG_EXP("sceneParticles")), +#endif +#if PX_USE_CLOTH_API + mPxCloths (PX_DEBUG_EXP("sceneCloths")), +#endif + mSanityBounds (desc.sanityBounds), + mNbClients (1), //we always have the default client. + mClientBehaviorFlags (PX_DEBUG_EXP("sceneBehaviorFlags")), + mSceneCompletion (mPhysicsDone), + mCollisionCompletion (mCollisionDone), + mSceneExecution (0, "NpScene.execution"), + mSceneCollide (0, "NpScene.collide"), + mSceneAdvance (0, "NpScene.solve"), + mControllingSimulation (false), + mSimThreadStackSize (0), + mConcurrentWriteCount (0), + mConcurrentReadCount (0), + mConcurrentErrorCount (0), + mCurrentWriter (0), + mHasSimulatedOnce (false), + mBetweenFetchResults (false) +{ + mSceneExecution.setObject(this); + mSceneCollide.setObject(this); + mSceneAdvance.setObject(this); + + mTaskManager = mScene.getScScene().getTaskManagerPtr(); + mThreadReadWriteDepth = Ps::TlsAlloc(); + +} + +NpSceneQueries::~NpSceneQueries() +{ +} + +NpScene::~NpScene() +{ + // PT: we need to do that one first, now that we don't release the objects anymore. Otherwise we end up with a sequence like: + // - actor is part of an aggregate, and part of a scene + // - actor gets removed from the scene. This does *not* remove it from the aggregate. + // - aggregate gets removed from the scene, sees that one contained actor ain't in the scene => we get a warning message + PxU32 aggregateCount = mAggregates.size(); + while(aggregateCount--) + removeAggregate(*mAggregates.getEntries()[aggregateCount], false); + +#if PX_USE_PARTICLE_SYSTEM_API + PxU32 partCount = mPxParticleBaseSet.size(); + while(partCount--) + removeActor(*mPxParticleBaseSet.getEntries()[partCount], false); +#endif + +#if PX_USE_CLOTH_API + PxU32 clothCount = mPxCloths.size(); + while(clothCount--) + removeActor(*mPxCloths.getEntries()[clothCount], false); +#endif + + PxU32 rigidActorCount = mRigidActors.size(); + while(rigidActorCount--) + removeActor(*mRigidActors[rigidActorCount], false); + + PxU32 articCount = mArticulations.size(); + while(articCount--) + removeArticulation(*mArticulations.getEntries()[articCount], false); + + // release volume caches + Array<NpVolumeCache*> caches; caches.reserve(mVolumeCaches.size()); + for(HashSet<NpVolumeCache*>::Iterator iter = mVolumeCaches.getIterator(); !iter.done(); ++iter) + caches.pushBack(*iter); + for(PxU32 i = 0; i < caches.size(); i++) + releaseVolumeCache(caches[i]); + + bool unlock = mScene.getFlags() & PxSceneFlag::eREQUIRE_RW_LOCK; + +#if PX_SUPPORT_PVD + getSingleSqCollector().release(); + getBatchedSqCollector().release(); +#endif + + // release batch queries + PxU32 numSq = mBatchQueries.size(); + while(numSq--) + PX_DELETE(mBatchQueries[numSq]); + mBatchQueries.clear(); + + mScene.release(); + + // unlock the lock taken in release(), must unlock before + // mRWLock is destroyed otherwise behavior is undefined + if (unlock) + unlockWrite(); + + TlsFree(mThreadReadWriteDepth); +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpScene::release() +{ + // need to acquire lock for release, note this is unlocked in the destructor + if (mScene.getFlags() & PxSceneFlag::eREQUIRE_RW_LOCK) + lockWrite(__FILE__, __LINE__); + + // It will be hard to do a write check here since all object release calls in the scene destructor do it and would mess + // up the test. If we really want it on scene destruction as well, we need to either have internal and external release + // calls or come up with a different approach (for example using thread ID as detector variable). + + if(getSimulationStage() != Sc::SimulationStage::eCOMPLETE) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxScene::release(): Scene is still being simulated! PxScene::fetchResults() is called implicitly."); + + if(getSimulationStage() == Sc::SimulationStage::eCOLLIDE) + { + fetchCollision(true); + } + + if(getSimulationStage() == Sc::SimulationStage::eFETCHCOLLIDE) // need to call getSimulationStage() again beacause fetchCollision() might change the value. + { + // this is for split sim + advance(NULL); + } + + fetchResults(true, NULL); + } + NpPhysics::getInstance().releaseSceneInternal(*this); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool NpScene::loadFromDesc(const PxSceneDesc& desc) +{ + { + if(desc.limits.maxNbActors) + mRigidActors.reserve(desc.limits.maxNbActors); + + //const PxU32 totalNbShapes = desc.limits.maxNbStaticShapes + desc.limits.maxNbDynamicShapes; + mScene.getScScene().preAllocate(desc.limits.maxNbActors, desc.limits.maxNbBodies, desc.limits.maxNbStaticShapes, desc.limits.maxNbDynamicShapes); + } + + userData = desc.userData; + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpScene::setGravity(const PxVec3& g) +{ + NP_WRITE_CHECK(this); + mScene.setGravity(g); +} + +PxVec3 NpScene::getGravity() const +{ + NP_READ_CHECK(this); + return mScene.getGravity(); +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpScene::setBounceThresholdVelocity(const PxReal t) +{ + NP_WRITE_CHECK(this); + mScene.setBounceThresholdVelocity(t); +} + +PxReal NpScene::getBounceThresholdVelocity() const +{ + NP_READ_CHECK(this) + return mScene.getBounceThresholdVelocity(); +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpScene::setLimits(const PxSceneLimits& limits) +{ + NP_WRITE_CHECK(this); + + if(limits.maxNbActors) + mRigidActors.reserve(limits.maxNbActors); + + mScene.getScScene().preAllocate(limits.maxNbActors, limits.maxNbBodies, limits.maxNbStaticShapes, limits.maxNbDynamicShapes); + mScene.setLimits(limits); + + mSQManager.preallocate(limits.maxNbStaticShapes, limits.maxNbDynamicShapes); +} + +////////////////////////////////////////////////////////////////////////// + +PxSceneLimits NpScene::getLimits() const +{ + NP_READ_CHECK(this); + + return mScene.getLimits(); +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpScene::setFlag(PxSceneFlag::Enum flag, bool value) +{ + NP_WRITE_CHECK(this); + + // this call supports mutable flags only + PX_CHECK_AND_RETURN(PxSceneFlags(flag) & PxSceneFlags(PxSceneFlag::eMUTABLE_FLAGS), + "PxScene::setFlag: This flag is not mutable - you can only set it once in PxSceneDesc at startup!"); + + PxSceneFlags currentFlags = mScene.getFlags(); + + if(value) + currentFlags |= flag; + else + currentFlags &= ~PxSceneFlags(flag); + + mScene.setFlags(currentFlags); +} + +PxSceneFlags NpScene::getFlags() const +{ + NP_READ_CHECK(this); + return mScene.getFlags(); +} + +/////////////////////////////////////////////////////////////////////////////// + +// PT: make sure we always add to array and set the array index properly / at the same time +template<class T> +static PX_FORCE_INLINE void addRigidActorToArray(T& a, Ps::Array<PxRigidActor*>& rigidActors) +{ + a.setRigidActorArrayIndex(rigidActors.size()); + rigidActors.pushBack(&a); +} + +void NpScene::addActor(PxActor& actor) +{ + PX_PROFILE_ZONE("API.addActor", getContextId()); + NP_WRITE_CHECK(this); + PX_SIMD_GUARD; + + PxRigidStatic* a = actor.is<PxRigidStatic>(); + if(a) + { +#if PX_CHECKED + if(!static_cast<NpRigidStatic*>(a)->checkConstraintValidity()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxScene::addActor(): actor has invalid constraint and may not be added to scene"); + return; + } +#endif + if(static_cast<NpRigidStatic*>(a)->getShapeManager().getPruningStructure()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxScene::addActor(): actor is in a pruning structure and cannot be added to a scene directly, use addActors(const PxPruningStructure& )"); + return; + } + } + + PxRigidDynamic* aD = actor.is<PxRigidDynamic>(); + if(aD && static_cast<NpRigidDynamic*>(aD)->getShapeManager().getPruningStructure()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxScene::addActor(): actor is in a pruning structure and cannot be added to a scene directly, use addActors(const PxPruningStructure& )"); + return; + } + + const Scb::ControlState::Enum cs = NpActor::getScbFromPxActor(actor).getControlState(); + if((cs == Scb::ControlState::eNOT_IN_SCENE) || ((cs == Scb::ControlState::eREMOVE_PENDING) && (NpActor::getOwnerScene(actor) == this))) + addActorInternal(actor); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxScene::addActor(): Actor already assigned to a scene. Call will be ignored!"); +} + +void NpScene::addActorInternal(PxActor& actor) +{ + switch(actor.getConcreteType()) + { + case PxConcreteType::eRIGID_STATIC: + { + NpRigidStatic& npStatic = static_cast<NpRigidStatic&>(actor); +#if PX_CHECKED + checkPositionSanity(npStatic, npStatic.getGlobalPose(), "PxScene::addActor or PxScene::addAggregate"); +#endif + addRigidStatic(npStatic); + } + break; + + case PxConcreteType::eRIGID_DYNAMIC: + { + NpRigidDynamic& npDynamic = static_cast<NpRigidDynamic&>(actor); +#if PX_CHECKED + checkPositionSanity(npDynamic, npDynamic.getGlobalPose(), "PxScene::addActor or PxScene::addAggregate"); +#endif + addRigidDynamic(npDynamic); + } + break; + +#if PX_USE_PARTICLE_SYSTEM_API + case PxConcreteType::ePARTICLE_SYSTEM: + { + NpParticleSystem& npSystem = static_cast<NpParticleSystem&>(actor); + addParticleSystem(npSystem); + } + break; + + case PxConcreteType::ePARTICLE_FLUID: + { + NpParticleFluid& npFluid = static_cast<NpParticleFluid&>(actor); + addParticleFluid(npFluid); + } + break; +#endif + +#if PX_USE_CLOTH_API + case PxConcreteType::eCLOTH: + { + NpCloth& npCloth = static_cast<NpCloth&>(actor); + addCloth(npCloth); + } + break; +#endif + case PxConcreteType::eARTICULATION_LINK: + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::addActor(): Individual articulation links can not be added to the scene"); + } + break; + + default: + PX_ASSERT(0); + } +} + +void NpScene::updateScbStateAndSetupSq(const PxRigidActor& rigidActor, Scb::Actor& scbActor, NpShapeManager& shapeManager, bool actorDynamic, const PxBounds3* bounds, bool hasPrunerStructure) +{ + // all the things Scb does in non-buffered insertion + SceneQueryManager& sqManager = getSceneQueryManagerFast(); + + scbActor.setScbScene(&mScene); + scbActor.setControlState(Scb::ControlState::eIN_SCENE); + NpShape*const * shapes = shapeManager.getShapes(); + PxU32 nbShapes = shapeManager.getNbShapes(); + + for(PxU32 i=0;i<nbShapes;i++) + { + NpShape& shape = *shapes[i]; + const PxShapeFlags shapeFlags = shape.getFlagsUnbuffered(); // PT: note that the regular code reads buffered flags + + shape.incRefCount(); + if(shape.isExclusiveFast()) + { + shape.getScbShape().setScbScene(&mScene); + shape.getScbShape().setControlState(Scb::ControlState::eIN_SCENE); + } + + // PT: this part is copied from 'NpShapeManager::setupAllSceneQuery' + if(shapeFlags & PxShapeFlag::eSCENE_QUERY_SHAPE) // PT: TODO: refactor with 'isSceneQuery' in shape manager? + { + const PrunerData data = sqManager.addPrunerShape(shape, rigidActor, actorDynamic, bounds ? bounds+i : NULL, hasPrunerStructure); + shapeManager.setPrunerData(i, data); + } + } +} + +PX_FORCE_INLINE void NpScene::updateScbStateAndSetupSq(const PxRigidActor& rigidActor, Scb::Body& body, NpShapeManager& shapeManager, bool actorDynamic, const PxBounds3* bounds, bool hasPrunerStructure) +{ + body.initBufferedState(); + updateScbStateAndSetupSq(rigidActor, static_cast<Scb::Actor&>(body), shapeManager, actorDynamic, bounds, hasPrunerStructure); +} + +void NpScene::addActors(PxActor*const* actors, PxU32 nbActors) +{ + addActorsInternal(actors, nbActors, NULL); +} + +void NpScene::addActors(const PxPruningStructure& ps) +{ + const Sq::PruningStructure& prunerStructure = static_cast<const Sq::PruningStructure&>(ps); + if(!prunerStructure.isValid()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, + "PxScene::addActors(): Provided pruning structure is not valid."); + return; + } + addActorsInternal(prunerStructure.getActors(), prunerStructure.getNbActors(), &prunerStructure); +} + +void NpScene::addActorsInternal(PxActor*const* PX_RESTRICT actors, PxU32 nbActors, const Sq::PruningStructure* pS) +{ + PX_PROFILE_ZONE("API.addActors", getContextId()); + NP_WRITE_CHECK(this); + PX_SIMD_GUARD; + + if(getSimulationStage() != Sc::SimulationStage::eCOMPLETE) + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, + "PxScene::addActors() not allowed while simulation is running."); + return; + } + + const bool hasPrunerStructure = pS ? true : false; + Sc::Scene& scScene = mScene.getScScene(); + PxU32 actorsDone; + + Sc::BatchInsertionState scState; + scScene.startBatchInsertion(scState); + + scState.staticActorOffset = ptrdiff_t(size_t(&(reinterpret_cast<NpRigidStatic*>(0)->getScbRigidStaticFast().getScStatic()))); + scState.staticShapeTableOffset = ptrdiff_t(size_t(&(reinterpret_cast<NpRigidStatic*>(0)->getShapeManager().getShapeTable()))); + scState.dynamicActorOffset = ptrdiff_t(size_t(&(reinterpret_cast<NpRigidDynamic*>(0)->getScbBodyFast().getScBody()))); + scState.dynamicShapeTableOffset = ptrdiff_t(size_t(&(reinterpret_cast<NpRigidDynamic*>(0)->getShapeManager().getShapeTable()))); + scState.shapeOffset = ptrdiff_t(NpShapeGetScPtrOffset()); + + Ps::InlineArray<PxBounds3, 8> shapeBounds; + for(actorsDone=0; actorsDone<nbActors; actorsDone++) + { + if(actorsDone+1<nbActors) + Ps::prefetch(actors[actorsDone+1], sizeof(NpRigidDynamic)); // worst case: PxRigidStatic is smaller + + const Scb::ControlState::Enum cs = NpActor::getScbFromPxActor(*actors[actorsDone]).getControlState(); + if (!((cs == Scb::ControlState::eNOT_IN_SCENE) || ((cs == Scb::ControlState::eREMOVE_PENDING) && (NpActor::getOwnerScene(*actors[actorsDone]) == this)))) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxScene::addActors(): Actor already assigned to a scene. Call will be ignored!"); + break; + } + + const PxType type = actors[actorsDone]->getConcreteType(); + if(type == PxConcreteType::eRIGID_STATIC) + { + NpRigidStatic& a = *static_cast<NpRigidStatic*>(actors[actorsDone]); +#if PX_CHECKED + if(!a.checkConstraintValidity()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxScene::addActors(): actor has invalid constraint and may not be added to scene"); + break; + } + checkPositionSanity(a, a.getGlobalPose(), "PxScene::addActors"); +#endif + if(!hasPrunerStructure && a.getShapeManager().getPruningStructure()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxScene::addActors(): actor is in a pruning structure and cannot be added to a scene directly, use addActors(const PxPruningStructure& )"); + break; + } + + if(!(a.getScbRigidStaticFast().getActorFlags() & PxActorFlag::eDISABLE_SIMULATION)) + { + shapeBounds.resizeUninitialized(a.NpRigidStatic::getNbShapes()+1); // PT: +1 for safe reads in addPrunerData/inflateBounds + scScene.addStatic(&a, scState, shapeBounds.begin()); + updateScbStateAndSetupSq(a, a.getScbActorFast(), a.getShapeManager(), false, shapeBounds.begin(), hasPrunerStructure); + addRigidActorToArray(a, mRigidActors); + a.addConstraintsToScene(); + } + else + addRigidStatic(a, hasPrunerStructure); + } + else if(type == PxConcreteType::eRIGID_DYNAMIC) + { + NpRigidDynamic& a = *static_cast<NpRigidDynamic*>(actors[actorsDone]); +#if PX_CHECKED + checkPositionSanity(a, a.getGlobalPose(), "PxScene::addActors"); +#endif + if(!hasPrunerStructure && a.getShapeManager().getPruningStructure()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxScene::addActors(): actor is in a pruning structure and cannot be added to a scene directly, use addActors(const PxPruningStructure& )"); + break; + } + + if(!(a.getScbBodyFast().getActorFlags() & PxActorFlag::eDISABLE_SIMULATION)) + { + shapeBounds.resizeUninitialized(a.NpRigidDynamic::getNbShapes()+1); // PT: +1 for safe reads in addPrunerData/inflateBounds + scScene.addBody(&a, scState, shapeBounds.begin()); + updateScbStateAndSetupSq(a, a.getScbBodyFast(), a.getShapeManager(), true, shapeBounds.begin(), hasPrunerStructure); + addRigidActorToArray(a, mRigidActors); + a.addConstraintsToScene(); + } + else + addRigidDynamic(a, hasPrunerStructure); + } + else if(type == PxConcreteType::eCLOTH || type == PxConcreteType::ePARTICLE_SYSTEM || type == PxConcreteType::ePARTICLE_FLUID) + { + addActorInternal(*actors[actorsDone]); + } + else + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::addRigidActors(): articulation link not permitted"); + break; + } + } + // merge sq PrunerStructure + if(pS) + { + if(pS->getTreeNodes(PruningIndex::eSTATIC)) + { + AABBPrunerMergeData params(pS->getTreeNbNodes(PruningIndex::eSTATIC), pS->getTreeNodes(PruningIndex::eSTATIC), + pS->getNbObjects(PruningIndex::eSTATIC), pS->getTreeIndices(PruningIndex::eSTATIC)); + mSQManager.get(PruningIndex::eSTATIC).pruner()->merge(¶ms); + } + if(pS->getTreeNodes(PruningIndex::eDYNAMIC)) + { + AABBPrunerMergeData params(pS->getTreeNbNodes(PruningIndex::eDYNAMIC), pS->getTreeNodes(PruningIndex::eDYNAMIC), + pS->getNbObjects(PruningIndex::eDYNAMIC), pS->getTreeIndices(PruningIndex::eDYNAMIC)); + mSQManager.get(PruningIndex::eDYNAMIC).pruner()->merge(¶ms); + } + } + scScene.finishBatchInsertion(scState); + + // if we failed, still complete everything for the successful inserted actors before backing out +#if PX_SUPPORT_PVD + for(PxU32 i=0;i<actorsDone;i++) + { + if ((actors[i]->getConcreteType()==PxConcreteType::eRIGID_STATIC) && (!(static_cast<NpRigidStatic*>(actors[i])->getScbRigidStaticFast().getActorFlags() & PxActorFlag::eDISABLE_SIMULATION))) + mScene.getScenePvdClient().addStaticAndShapesToPvd(static_cast<NpRigidStatic*>(actors[i])->getScbRigidStaticFast()); + else if ((actors[i]->getConcreteType() == PxConcreteType::eRIGID_DYNAMIC) && (!(static_cast<NpRigidDynamic*>(actors[i])->getScbBodyFast().getActorFlags() & PxActorFlag::eDISABLE_SIMULATION))) + mScene.getScenePvdClient().addBodyAndShapesToPvd(static_cast<NpRigidDynamic*>(actors[i])->getScbBodyFast()); + } +#endif + + if(actorsDone<nbActors) // Everything is consistent up to the failure point, so just use removeActor to back out gracefully if necessary + { + for(PxU32 j=0;j<actorsDone;j++) + removeActorInternal(*actors[j], false, true); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpScene::removeActors(PxActor*const* PX_RESTRICT actors, PxU32 nbActors, bool wakeOnLostTouch) +{ + PX_PROFILE_ZONE("API.removeActors", getContextId()); + NP_WRITE_CHECK(this); + + Sc::Scene& scScene = mScene.getScScene(); + // resize the bitmap so it does not allocate each remove actor call + scScene.resizeReleasedBodyIDMaps(mRigidActors.size(),nbActors); + Sc::BatchRemoveState removeState; + scScene.setBatchRemove(&removeState); + + for(PxU32 actorsDone=0; actorsDone<nbActors; actorsDone++) + { + if(actorsDone+1<nbActors) + Ps::prefetch(actors[actorsDone+1], sizeof(NpRigidDynamic)); // worst case: PxRigidStatic is smaller + + PxType type = actors[actorsDone]->getConcreteType(); + if (!removeFromSceneCheck(this, actors[actorsDone]->getScene(), "PxScene::removeActors(): Actor")) + { + break; + } + + removeState.bufferedShapes.clear(); + removeState.removedShapes.clear(); + + if(type == PxConcreteType::eRIGID_STATIC) + { + NpRigidStatic& actor = *static_cast<NpRigidStatic*>(actors[actorsDone]); + const PxActorFlags actorFlags = actor.getScbRigidStaticFast().getActorFlags(); + + if(actor.getShapeManager().getNbShapes()) + Ps::prefetch(actor.getShapeManager().getShapes()[0],sizeof(NpShape)); + scScene.prefetchForRemove(actor.getScbRigidStaticFast().getScStatic()); + Ps::prefetch(mRigidActors[mRigidActors.size()-1],sizeof(NpRigidDynamic)); + + const bool noSimBuffered = actorFlags.isSet(PxActorFlag::eDISABLE_SIMULATION); + if (!noSimBuffered) + actor.removeConstraintsFromScene(); + + actor.getShapeManager().teardownAllSceneQuery(getSceneQueryManagerFast()); + + Scb::RigidStatic& rs = actor.getScbRigidStaticFast(); + mScene.removeActor(rs, wakeOnLostTouch, rs.isSimDisabledInternally()); + removeFromRigidActorList(actor.getRigidActorArrayIndex()); + } + else if(type == PxConcreteType::eRIGID_DYNAMIC) + { + NpRigidDynamic& actor = *static_cast<NpRigidDynamic*>(actors[actorsDone]); + const PxActorFlags actorFlags = actor.getScbBodyFast().getActorFlags(); + + if(actor.getShapeManager().getNbShapes()) + Ps::prefetch(actor.getShapeManager().getShapes()[0],sizeof(NpShape)); + scScene.prefetchForRemove(actor.getScbBodyFast().getScBody()); + Ps::prefetch(mRigidActors[mRigidActors.size()-1],sizeof(NpRigidDynamic)); + + const bool noSimBuffered = actorFlags.isSet(PxActorFlag::eDISABLE_SIMULATION); + if (!noSimBuffered) + actor.removeConstraintsFromScene(); + + actor.getShapeManager().teardownAllSceneQuery(getSceneQueryManagerFast()); + + Scb::Body& b = actor.getScbBodyFast(); + mScene.removeActor(b, wakeOnLostTouch, b.isSimDisabledInternally()); + removeFromRigidActorList(actor.getRigidActorArrayIndex()); + } + else if(type == PxConcreteType::eCLOTH || type == PxConcreteType::ePARTICLE_SYSTEM || type == PxConcreteType::ePARTICLE_FLUID) + { + removeActorInternal(*actors[actorsDone],wakeOnLostTouch, true); + } + else + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::removeActor(): Individual articulation links can not be removed from the scene"); + break; + } + } + + scScene.setBatchRemove(NULL); +} + +void NpScene::removeActor(PxActor& actor, bool wakeOnLostTouch) +{ + PX_PROFILE_ZONE("API.removeActor", getContextId()); + NP_WRITE_CHECK(this); + if (removeFromSceneCheck(this, actor.getScene(), "PxScene::removeActor(): Actor")) + { + removeActorInternal(actor, wakeOnLostTouch, true); + } +} + +void NpScene::removeActorInternal(PxActor& actor, bool wakeOnLostTouch, bool removeFromAggregate) +{ + switch(actor.getType()) + { + case PxActorType::eRIGID_STATIC: + { + NpRigidStatic& npStatic = static_cast<NpRigidStatic&>(actor); + removeRigidStatic(npStatic, wakeOnLostTouch, removeFromAggregate); + } + break; + + case PxActorType::eRIGID_DYNAMIC: + { + NpRigidDynamic& npDynamic = static_cast<NpRigidDynamic&>(actor); + removeRigidDynamic(npDynamic, wakeOnLostTouch, removeFromAggregate); + } + break; +#if PX_USE_PARTICLE_SYSTEM_API + case PxActorType::ePARTICLE_SYSTEM: + { + NpParticleSystem& npSystem = static_cast<NpParticleSystem&>(actor); + removeParticleSystem(npSystem); + } + break; + + case PxActorType::ePARTICLE_FLUID: + { + NpParticleFluid& npFluid = static_cast<NpParticleFluid&>(actor); + removeParticleFluid(npFluid); + } + break; +#endif + +#if PX_USE_CLOTH_API + case PxActorType::eCLOTH: + { + NpCloth& npCloth = static_cast<NpCloth&>(actor); + removeCloth(npCloth); + } + break; +#endif + + case PxActorType::eARTICULATION_LINK: + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::removeActor(): Individual articulation links can not be removed from the scene"); + } + break; + + case PxActorType::eACTOR_COUNT: + case PxActorType::eACTOR_FORCE_DWORD: + PX_ASSERT(0); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +// PT: TODO: inline this one in the header for consistency +void NpScene::removeFromRigidActorList(const PxU32& index) +{ + PX_ASSERT(index != 0xFFFFFFFF); + PX_ASSERT(index < mRigidActors.size()); + + { + const PxU32 size = mRigidActors.size() - 1; + mRigidActors.replaceWithLast(index); + if(size && size != index) + { + PxRigidActor& rigidActor = *mRigidActors[index]; + switch(rigidActor.getType()) + { + case PxActorType::eRIGID_STATIC: + { + NpRigidStatic& npStatic = static_cast<NpRigidStatic&>(rigidActor); + npStatic.setRigidActorArrayIndex(index); + } + break; + case PxActorType::eRIGID_DYNAMIC: + { + NpRigidDynamic& npDynamic = static_cast<NpRigidDynamic&>(rigidActor); + npDynamic.setRigidActorArrayIndex(index); + } + break; + +#if PX_USE_CLOTH_API + case PxActorType::eCLOTH: +#endif +#if PX_USE_PARTICLE_SYSTEM_API + case PxActorType::ePARTICLE_FLUID: + case PxActorType::ePARTICLE_SYSTEM: +#endif + case PxActorType::eARTICULATION_LINK: + case PxActorType::eACTOR_COUNT: + case PxActorType::eACTOR_FORCE_DWORD: + PX_ASSERT(0); + break; + } + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +template<class T, class T2> +static PX_FORCE_INLINE void addActorT(T& actor, T2& scbActor, Ps::Array<PxRigidActor*>& actors, NpScene* scene, bool hasPrunerStructure) +{ + const bool noSimBuffered = scbActor.getActorFlags().isSet(PxActorFlag::eDISABLE_SIMULATION); + + PxBounds3 bounds[8+1]; // PT: +1 for safe reads in addPrunerData/inflateBounds + const bool canReuseBounds = !noSimBuffered && !scene->getScene().isPhysicsBuffering() && actor.getShapeManager().getNbShapes()<=8; + PxBounds3* uninflatedBounds = canReuseBounds ? bounds : NULL; + + scene->getScene().addActor(scbActor, noSimBuffered, uninflatedBounds); + + actor.getShapeManager().setupAllSceneQuery(scene, actor, hasPrunerStructure, uninflatedBounds); + if(!noSimBuffered) + actor.addConstraintsToScene(); + addRigidActorToArray(actor, actors); +} + +void NpScene::addRigidStatic(NpRigidStatic& actor, bool hasPrunerStructure) +{ + addActorT(actor, actor.getScbRigidStaticFast(), mRigidActors, this, hasPrunerStructure); +} + +void NpScene::addRigidDynamic(NpRigidDynamic& body, bool hasPrunerStructure) +{ + addActorT(body, body.getScbBodyFast(), mRigidActors, this, hasPrunerStructure); +} + +/////////////////////////////////////////////////////////////////////////////// + +template<class T, class T2> +static PX_FORCE_INLINE void removeActorT(T& actor, T2& scbActor, NpScene* scene, bool wakeOnLostTouch, bool removeFromAggregate) +{ + PX_ASSERT(NpActor::getAPIScene(actor) == scene); + const bool noSimBuffered = scbActor.getActorFlags().isSet(PxActorFlag::eDISABLE_SIMULATION); + + if(removeFromAggregate) + { + PxU32 index = 0xffffffff; + NpAggregate* aggregate = actor.getNpAggregate(index); + if(aggregate) + { + aggregate->removeActorAndReinsert(actor, false); + PX_ASSERT(!actor.getAggregate()); + } + } + + actor.getShapeManager().teardownAllSceneQuery(scene->getSceneQueryManagerFast()); + if(!noSimBuffered) + actor.removeConstraintsFromScene(); + + scene->getScene().removeActor(scbActor, wakeOnLostTouch, scbActor.isSimDisabledInternally()); + scene->removeFromRigidActorList(actor.getRigidActorArrayIndex()); +} + +void NpScene::removeRigidStatic(NpRigidStatic& actor, bool wakeOnLostTouch, bool removeFromAggregate) +{ + removeActorT(actor, actor.getScbRigidStaticFast(), this, wakeOnLostTouch, removeFromAggregate); +} + +void NpScene::removeRigidDynamic(NpRigidDynamic& body, bool wakeOnLostTouch, bool removeFromAggregate) +{ + removeActorT(body, body.getScbBodyFast(), this, wakeOnLostTouch, removeFromAggregate); +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpScene::addArticulation(PxArticulation& articulation) +{ + PX_PROFILE_ZONE("API.addArticulation", getContextId()); + NP_WRITE_CHECK(this); + + PX_CHECK_AND_RETURN(articulation.getNbLinks()>0, "PxScene::addArticulation: empty articulations may not be added to simulation."); + PX_SIMD_GUARD; + + if (this->getFlags() & PxSceneFlag::eENABLE_GPU_DYNAMICS) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxScene::addArticulation(): Articulations are not currently supported when PxSceneFlag::eENABLE_GPU_DYNAMICS is set!"); + return; + } + + Scb::Articulation& art = static_cast<NpArticulation&>(articulation).getArticulation(); + Scb::ControlState::Enum cs = art.getControlState(); + if ((cs == Scb::ControlState::eNOT_IN_SCENE) || ((cs == Scb::ControlState::eREMOVE_PENDING) && (art.getScbScene()->getPxScene() == this))) + addArticulationInternal(articulation); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxScene::addArticulation(): Articulation already assigned to a scene. Call will be ignored!"); +} + +void NpScene::addArticulationInternal(PxArticulation& articulation) +{ + NpArticulation& npa = static_cast<NpArticulation&>(articulation); + + // Add root link first + PxU32 nbLinks = npa.getNbLinks(); + PX_ASSERT(nbLinks > 0); + NpArticulationLink* rootLink = npa.getLinks()[0]; + +#if PX_CHECKED + checkPositionSanity(*rootLink, rootLink->getGlobalPose(), "PxScene::addArticulation or PxScene::addAggregate"); +#endif + if(rootLink->getMass()==0) + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::addArticulation(): Articulation link with zero mass added to scene; defaulting mass to 1"); + rootLink->setMass(1.0f); + } + + PxVec3 inertia0 = rootLink->getMassSpaceInertiaTensor(); + if(inertia0.x == 0.0f || inertia0.y == 0.0f || inertia0.z == 0.0f) + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::addArticulation(): Articulation link with zero moment of inertia added to scene; defaulting inertia to (1,1,1)"); + rootLink->setMassSpaceInertiaTensor(PxVec3(1.0f, 1.0f, 1.0f)); + } + + bool linkTriggersWakeUp = !rootLink->getScbBodyFast().checkSleepReadinessBesidesWakeCounter(); + + addArticulationLinkBody(*rootLink); + + // Add articulation + Scb::Articulation& scbArt = npa.getArticulation(); + mScene.addArticulation(scbArt); + + addArticulationLinkConstraint(*rootLink); + + // Add links & joints + PX_ALLOCA(linkStack, NpArticulationLink*, nbLinks); + linkStack[0] = rootLink; + PxU32 curLink = 0; + PxU32 stackSize = 1; + while(curLink < (nbLinks-1)) + { + PX_ASSERT(curLink < stackSize); + NpArticulationLink* l = linkStack[curLink]; + NpArticulationLink*const* children = l->getChildren(); + + for(PxU32 i=0; i < l->getNbChildren(); i++) + { + NpArticulationLink* child = children[i]; + +#if PX_CHECKED + checkPositionSanity(*child, child->getGlobalPose(), "PxScene::addArticulation"); +#endif + if(child->getMass()==0) + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::addArticulation(): Articulation link with zero mass added to scene; defaulting mass to 1"); + child->setMass(1.0f); + } + + PxVec3 inertia = child->getMassSpaceInertiaTensor(); + if(inertia.x == 0.0f || inertia.y == 0.0f || inertia.z == 0.0f) + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::addArticulation(): Articulation link with zero moment of inertia added to scene; defaulting inertia to (1,1,1)"); + child->setMassSpaceInertiaTensor(PxVec3(1.0f, 1.0f, 1.0f)); + } + + linkTriggersWakeUp = linkTriggersWakeUp || (!child->getScbBodyFast().checkSleepReadinessBesidesWakeCounter()); + + addArticulationLink(*child); // Adds joint too + + linkStack[stackSize] = child; + stackSize++; + } + + curLink++; + } + + if ((scbArt.getWakeCounter() == 0.0f) && linkTriggersWakeUp) + { + // this is for the buffered insert case, where the articulation needs to wake up, if one of the links triggers activation. + npa.wakeUpInternal(true, false); + } + + mArticulations.insert(&npa); +} + +void NpScene::removeArticulation(PxArticulation& articulation, bool wakeOnLostTouch) +{ + PX_PROFILE_ZONE("API.removeArticulation", getContextId()); + NP_WRITE_CHECK(this); + + if (removeFromSceneCheck(this, articulation.getScene(), "PxScene::removeArticulation(): Articulation")) + { + removeArticulationInternal(articulation, wakeOnLostTouch, true); + } +} + +void NpScene::removeArticulationInternal(PxArticulation& articulation, bool wakeOnLostTouch, bool removeFromAggregate) +{ + NpArticulation& npa = static_cast<NpArticulation&>(articulation); + + PxU32 nbLinks = npa.getNbLinks(); + PX_ASSERT(nbLinks > 0); + + if(removeFromAggregate && articulation.getAggregate()) + { + static_cast<NpAggregate*>(articulation.getAggregate())->removeArticulationAndReinsert(articulation, false); + PX_ASSERT(!articulation.getAggregate()); + } + + //!!!AL + // Inefficient. We might want to introduce a LL method to kill the whole LL articulation together with all joints in one go, then + // the order of removing the links/joints does not matter anymore. + + // Remove links & joints + PX_ALLOCA(linkStack, NpArticulationLink*, nbLinks); + linkStack[0] = npa.getLinks()[0]; + PxU32 curLink = 0, stackSize = 1; + + while(curLink < (nbLinks-1)) + { + PX_ASSERT(curLink < stackSize); + NpArticulationLink* l = linkStack[curLink]; + NpArticulationLink*const* children = l->getChildren(); + + for(PxU32 i=0; i < l->getNbChildren(); i++) + { + linkStack[stackSize] = children[i]; + stackSize++; + } + + curLink++; + } + + PxRigidBodyFlags flag; + for(PxI32 j=PxI32(nbLinks); j-- > 0; ) + { + flag |=linkStack[j]->getScbBodyFast().getScBody().getCore().mFlags; + removeArticulationLink(*linkStack[j], wakeOnLostTouch); + } + + if (flag & PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD) + { + IG::NodeIndex index = npa.getScbArticulation().getScArticulation().getIslandNodeIndex(); + if (index.isValid()) + mScene.getScScene().resetSpeculativeCCDArticulationLink(index.index()); + } + // Remove articulation + mScene.removeArticulation(npa.getArticulation()); + + + removeFromArticulationList(articulation); +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpScene::addArticulationLinkBody(NpArticulationLink& link) +{ + mScene.addActor(link.getScbBodyFast(), false, NULL); + link.getShapeManager().setupAllSceneQuery(this, link, false); +} + +void NpScene::addArticulationLinkConstraint(NpArticulationLink& link) +{ + NpArticulationJoint* j = static_cast<NpArticulationJoint*>(link.getInboundJoint()); + if (j) + mScene.addArticulationJoint(j->getScbArticulationJoint()); + + link.addConstraintsToScene(); +} + +void NpScene::addArticulationLink(NpArticulationLink& link) +{ + addArticulationLinkBody(link); + addArticulationLinkConstraint(link); +} + +void NpScene::removeArticulationLink(NpArticulationLink& link, bool wakeOnLostTouch) +{ + NpArticulationJoint* j = static_cast<NpArticulationJoint*>(link.getInboundJoint()); + + link.removeConstraintsFromScene(); + link.getShapeManager().teardownAllSceneQuery(getSceneQueryManagerFast()); + + if (j) + mScene.removeArticulationJoint(j->getScbArticulationJoint()); + + mScene.removeActor(link.getScbBodyFast(), wakeOnLostTouch, false); +} + +/////////////////////////////////////////////////////////////////////////////// + +// PX_AGGREGATE + +void NpScene::addAggregate(PxAggregate& aggregate) +{ + PX_PROFILE_ZONE("API.addAggregate", getContextId()); + NP_WRITE_CHECK(this); + PX_SIMD_GUARD; + + NpAggregate& np = static_cast<NpAggregate&>(aggregate); + + const PxU32 nb = np.getCurrentSizeFast(); +#if PX_CHECKED + for(PxU32 i=0;i<nb;i++) + { + PxRigidStatic* a = np.getActorFast(i)->is<PxRigidStatic>(); + if(a && !static_cast<NpRigidStatic*>(a)->checkConstraintValidity()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxScene::addAggregate(): Aggregate contains an actor with an invalid constraint!"); + return; + } + } +#endif + + Scb::Aggregate& agg = np.getScbAggregate(); + Scb::ControlState::Enum cs = agg.getControlState(); + if ((cs == Scb::ControlState::eNOT_IN_SCENE) || ((cs == Scb::ControlState::eREMOVE_PENDING) && (agg.getScbScene()->getPxScene() == this))) + { + mScene.addAggregate(agg); + + for(PxU32 i=0;i<nb;i++) + { + PX_ASSERT(np.getActorFast(i)); + np.addActorInternal(*np.getActorFast(i), *this); + } + + mAggregates.insert(&aggregate); + } + else + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxScene::addAggregate(): Aggregate already assigned to a scene. Call will be ignored!"); +} + +void NpScene::removeAggregate(PxAggregate& aggregate, bool wakeOnLostTouch) +{ + PX_PROFILE_ZONE("API.removeAggregate", getContextId()); + NP_WRITE_CHECK(this); + if(!removeFromSceneCheck(this, aggregate.getScene(), "PxScene::removeAggregate(): Aggregate")) + return; + + NpAggregate& np = static_cast<NpAggregate&>(aggregate); + if(np.getScene()!=this) + return; + + const PxU32 nb = np.getCurrentSizeFast(); + for(PxU32 j=0;j<nb;j++) + { + PxActor* a = np.getActorFast(j); + PX_ASSERT(a); + + if (a->getType() != PxActorType::eARTICULATION_LINK) + { + Scb::Actor& scb = NpActor::getScbFromPxActor(*a); + + np.getScbAggregate().removeActor(scb, false); // This is only here to make sure the aggregateID gets set to invalid on sync + + removeActorInternal(*a, wakeOnLostTouch, false); + } + else if (a->getScene()) + { + NpArticulationLink& al = static_cast<NpArticulationLink&>(*a); + NpArticulation& npArt = al.getRoot(); + NpArticulationLink* const* links = npArt.getLinks(); + for(PxU32 i=0; i < npArt.getNbLinks(); i++) + { + np.getScbAggregate().removeActor(links[i]->getScbActorFast(), false); // This is only here to make sure the aggregateID gets set to invalid on sync + } + + removeArticulationInternal(npArt, wakeOnLostTouch, false); + } + } + + mScene.removeAggregate(np.getScbAggregate()); + + removeFromAggregateList(aggregate); +} + +PxU32 NpScene::getNbAggregates() const +{ + NP_READ_CHECK(this); + return mAggregates.size(); +} + +PxU32 NpScene::getAggregates(PxAggregate** userBuffer, PxU32 bufferSize, PxU32 startIndex) const +{ + NP_READ_CHECK(this); + return Cm::getArrayOfPointers(userBuffer, bufferSize, startIndex, mAggregates.getEntries(), mAggregates.size()); +} + +//~PX_AGGREGATE + +void NpScene::addCollection(const PxCollection& collection) +{ + PX_PROFILE_ZONE("API.addCollection", getContextId()); + const Cm::Collection& col = static_cast<const Cm::Collection&>(collection); + + PxU32 nb = col.internalGetNbObjects(); +#if PX_CHECKED + for(PxU32 i=0;i<nb;i++) + { + PxRigidStatic* a = col.internalGetObject(i)->is<PxRigidStatic>(); + if(a && !static_cast<NpRigidStatic*>(a)->checkConstraintValidity()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxScene::addCollection(): collection contains an actor with an invalid constraint!"); + return; + } + } +#endif + + Ps::Array<PxActor*> actorsToInsert; + actorsToInsert.reserve(nb); + + struct Local + { + static void addActorIfNeeded(PxActor* actor, Ps::Array<PxActor*>& actorArray) + { + if(actor->getAggregate()) + return; // The actor will be added when the aggregate is added + actorArray.pushBack(actor); + } + }; + + for(PxU32 i=0;i<nb;i++) + { + PxBase* s = col.internalGetObject(i); + const PxType serialType = s->getConcreteType(); + + //NpArticulationLink, NpArticulationJoint are added with the NpArticulation + //Actors and Articulations that are members of an Aggregate are added with the NpAggregate + + if(serialType==PxConcreteType::eRIGID_DYNAMIC) + { + NpRigidDynamic* np = static_cast<NpRigidDynamic*>(s); + // if pruner structure exists for the actor, actor will be added with the pruner structure + if(!np->getShapeManager().getPruningStructure()) + Local::addActorIfNeeded(np, actorsToInsert); + } + else if(serialType==PxConcreteType::eRIGID_STATIC) + { + NpRigidStatic* np = static_cast<NpRigidStatic*>(s); + // if pruner structure exists for the actor, actor will be added with the pruner structure + if(!np->getShapeManager().getPruningStructure()) + Local::addActorIfNeeded(np, actorsToInsert); + } + else if(serialType==PxConcreteType::eSHAPE) + { + } +#if PX_USE_CLOTH_API + else if (serialType==PxConcreteType::eCLOTH) + { + NpCloth* np = static_cast<NpCloth*>(s); + Local::addActorIfNeeded(np, actorsToInsert); + } +#endif +#if PX_USE_PARTICLE_SYSTEM_API + else if(serialType==PxConcreteType::ePARTICLE_SYSTEM) + { + NpParticleSystem* np = static_cast<NpParticleSystem*>(s); + Local::addActorIfNeeded(np, actorsToInsert); + } + else if(serialType==PxConcreteType::ePARTICLE_FLUID) + { + NpParticleFluid* np = static_cast<NpParticleFluid*>(s); + Local::addActorIfNeeded(np, actorsToInsert); + } +#endif + else if(serialType==PxConcreteType::eARTICULATION) + { + NpArticulation* np = static_cast<NpArticulation*>(s); + if(!np->getAggregate()) // The actor will be added when the aggregate is added + addArticulation(*np); + } + else if(serialType==PxConcreteType::eAGGREGATE) + { + NpAggregate* np = static_cast<NpAggregate*>(s); + addAggregate(*np); + } + else if(serialType == PxConcreteType::ePRUNING_STRUCTURE) + { + PxPruningStructure* ps = static_cast<PxPruningStructure*>(s); + addActors(*ps); + } + } + + if(!actorsToInsert.empty()) + addActorsInternal(&actorsToInsert[0], actorsToInsert.size(), NULL); +} + +/////////////////////////////////////////////////////////////////////////////// + +PxU32 NpScene::getNbActors(PxActorTypeFlags types) const +{ + NP_READ_CHECK(this); + PxU32 nbActors = 0; + + if (types & PxActorTypeFlag::eRIGID_STATIC) + { + for(PxU32 i=mRigidActors.size(); i--;) + { + if (mRigidActors[i]->is<PxRigidStatic>()) + nbActors++; + } + } + + if (types & PxActorTypeFlag::eRIGID_DYNAMIC) + { + for(PxU32 i=mRigidActors.size(); i--;) + { + if (mRigidActors[i]->is<PxRigidDynamic>()) + nbActors++; + } + } + +#if PX_USE_PARTICLE_SYSTEM_API + if (types & PxActorTypeFlag::ePARTICLE_SYSTEM) + { + PxParticleBase*const* particles = mPxParticleBaseSet.getEntries(); + const PxU32 particleBaseCount = mPxParticleBaseSet.size(); + for(PxU32 i=0; i < particleBaseCount; i++) + { + if (particles[i]->is<PxParticleSystem>()) + nbActors++; + } + } + + if (types & PxActorTypeFlag::ePARTICLE_FLUID) + { + PxParticleBase*const* particles = mPxParticleBaseSet.getEntries(); + const PxU32 particleBaseCount = mPxParticleBaseSet.size(); + for(PxU32 i=0; i < particleBaseCount; i++) + { + if (particles[i]->is<PxParticleFluid>()) + nbActors++; + } + } +#endif + +#if PX_USE_CLOTH_API + if (types & PxActorTypeFlag::eCLOTH) + { + nbActors += mPxCloths.size(); + } +#endif + + return nbActors; +} + +PxU32 NpScene::getActors(PxActorTypeFlags types, PxActor** buffer, PxU32 bufferSize, PxU32 startIndex) const +{ + NP_READ_CHECK(this); + + PxU32 writeCount = 0; + PxU32 virtualIndex = 0; // PT: virtual index of actor, continuous across different actor containers. + + if(types & (PxActorTypeFlag::eRIGID_STATIC | PxActorTypeFlag::eRIGID_DYNAMIC)) + { + const PxU32 size = mRigidActors.size(); + for(PxU32 i=0; (i < size) && (writeCount < bufferSize); i++) + { + if ((types & PxActorTypeFlag::eRIGID_STATIC ) && mRigidActors[i]->is<PxRigidStatic>()) + { + if (virtualIndex >= startIndex) + buffer[writeCount++] = mRigidActors[i]; + virtualIndex++; + } + else if ((types & PxActorTypeFlag::eRIGID_DYNAMIC) && mRigidActors[i]->is<PxRigidDynamic>()) + { + if (virtualIndex >= startIndex) + buffer[writeCount++] = mRigidActors[i]; + virtualIndex++; + } + } + } + +#if PX_USE_PARTICLE_SYSTEM_API + if (types & (PxActorTypeFlag::ePARTICLE_SYSTEM | PxActorTypeFlag::ePARTICLE_FLUID)) + { + const PxU32 size = mPxParticleBaseSet.size(); + PxParticleBase*const* particles = mPxParticleBaseSet.getEntries(); + for(PxU32 i=0; (i < size) && (writeCount < bufferSize); i++) + { + if ((types & PxActorTypeFlag::ePARTICLE_SYSTEM ) && particles[i]->is<PxParticleSystem>()) + { + if (virtualIndex >= startIndex) + buffer[writeCount++] = particles[i]; + virtualIndex++; + } + else if ((types & PxActorTypeFlag::ePARTICLE_FLUID) && particles[i]->is<PxParticleFluid>()) + { + if (virtualIndex >= startIndex) + buffer[writeCount++] = particles[i]; + virtualIndex++; + } + } + } + +#endif + +#if PX_USE_CLOTH_API + if (types & PxActorTypeFlag::eCLOTH) + { + const PxU32 size = mPxCloths.size(); + PxCloth*const* clothList = mPxCloths.getEntries(); + for(PxU32 i=0; (i < size) && (writeCount < bufferSize); i++) + { + if(virtualIndex>=startIndex) + buffer[writeCount++] = clothList[i]; + virtualIndex++; + } + } +#endif + + return writeCount; +} + +/////////////////////////////////////////////////////////////////////////////// + +PX_DEPRECATED const PxActiveTransform* NpScene::getActiveTransforms(PxU32& nbTransformsOut, PxClientID client) +{ + NP_READ_CHECK(this); + return mScene.getActiveTransforms(nbTransformsOut, client); +} + +PxActor** NpScene::getActiveActors(PxU32& nbActorsOut, PxClientID client) +{ + NP_READ_CHECK(this); + return mScene.getActiveActors(nbActorsOut, client); +} + +/////////////////////////////////////////////////////////////////////////////// + +PxU32 NpScene::getNbArticulations() const +{ + NP_READ_CHECK(this); + return mArticulations.size(); +} + +PxU32 NpScene::getArticulations(PxArticulation** userBuffer, PxU32 bufferSize, PxU32 startIndex) const +{ + NP_READ_CHECK(this); + return Cm::getArrayOfPointers(userBuffer, bufferSize, startIndex, mArticulations.getEntries(), mArticulations.size()); +} + +/////////////////////////////////////////////////////////////////////////////// + +PxU32 NpScene::getNbConstraints() const +{ + NP_READ_CHECK(this); + return mConstraints.size(); +} + +PxU32 NpScene::getConstraints(PxConstraint** userBuffer, PxU32 bufferSize, PxU32 startIndex) const +{ + NP_READ_CHECK(this); + return Cm::getArrayOfPointers(userBuffer, bufferSize, startIndex, mConstraints.getEntries(), mConstraints.size()); +} + +/////////////////////////////////////////////////////////////////////////////// + +const PxRenderBuffer& NpScene::getRenderBuffer() +{ + if (getSimulationStage() != Sc::SimulationStage::eCOMPLETE) + { + // will be reading the Sc::Scene renderable which is getting written + // during the sim, hence, avoid call while simulation is running. + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, + "PxScene::getRenderBuffer() not allowed while simulation is running."); + } + + return mRenderBuffer; +} + +void NpScene::visualize() +{ + NP_READ_CHECK(this); + + mRenderBuffer.clear(); // clear last frame visualizations + +#if PX_ENABLE_DEBUG_VISUALIZATION + if(getVisualizationParameter(PxVisualizationParameter::eSCALE) == 0.0f) + return; + + Cm::RenderOutput out(mRenderBuffer); + + // Visualize scene axis + const PxReal worldAxes = getVisualizationParameter(PxVisualizationParameter::eWORLD_AXES); + if (worldAxes != 0) + out << Cm::DebugBasis(PxVec3(worldAxes)); + + // Visualize articulations + for(PxU32 i=0;i<mArticulations.size();i++) + static_cast<NpArticulation *>(mArticulations.getEntries()[i])->visualize(out, this); + + // Visualize rigid actors and rigid bodies + PxRigidActor*const* rigidActors = mRigidActors.begin(); + const PxU32 rigidActorCount = mRigidActors.size(); + +#if PX_USE_CLOTH_API + // Visualize cloths + for(PxU32 i=0;i<mPxCloths.size();i++) + static_cast<NpCloth*>(mPxCloths.getEntries()[i])->visualize(out, this); +#endif + + for(PxU32 i=0; i < rigidActorCount; i++) + { + PxRigidActor* a = rigidActors[i]; + if (a->getType() == PxActorType::eRIGID_DYNAMIC) + static_cast<NpRigidDynamic*>(a)->visualize(out, this); + else + static_cast<NpRigidStatic*>(a)->visualize(out, this); + } + + // Visualize pruning structures + const bool visStatic = getVisualizationParameter(PxVisualizationParameter::eCOLLISION_STATIC) != 0.0f; + const bool visDynamic = getVisualizationParameter(PxVisualizationParameter::eCOLLISION_DYNAMIC) != 0.0f; + //flushQueryUpdates(); // DE7834 + if(visStatic && mSQManager.get(PruningIndex::eSTATIC).pruner()) + mSQManager.get(PruningIndex::eSTATIC).pruner()->visualize(out, PxU32(PxDebugColor::eARGB_BLUE)); + if(visDynamic && mSQManager.get(PruningIndex::eDYNAMIC).pruner()) + mSQManager.get(PruningIndex::eDYNAMIC).pruner()->visualize(out, PxU32(PxDebugColor::eARGB_RED)); + + if(getVisualizationParameter(PxVisualizationParameter::eMBP_REGIONS) != 0.0f) + { + out << PxTransform(PxIdentity); + + const PxU32 nbRegions = mScene.getNbBroadPhaseRegions(); + for(PxU32 i=0;i<nbRegions;i++) + { + PxBroadPhaseRegionInfo info; + mScene.getBroadPhaseRegions(&info, 1, i); + + if(info.active) + out << PxU32(PxDebugColor::eARGB_YELLOW); + else + out << PxU32(PxDebugColor::eARGB_BLACK); + out << Cm::DebugBox(info.region.bounds); + } + } + +#if PX_SUPPORT_PVD + mScene.getScenePvdClient().visualize(mRenderBuffer); +#endif +#endif +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpScene::getSimulationStatistics(PxSimulationStatistics& s) const +{ + NP_READ_CHECK(this); + + if (getSimulationStage() == Sc::SimulationStage::eCOMPLETE) + { +#if PX_ENABLE_SIM_STATS + mScene.getStats(s); +#else + PX_UNUSED(s); +#endif + } + else + { + //will be reading data that is getting written during the sim, hence, avoid call while simulation is running. + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::getSimulationStatistics() not allowed while simulation is running. Call will be ignored."); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +//Multiclient + +PxClientID NpScene::createClient() +{ + NP_WRITE_CHECK(this); + + PX_CHECK_AND_RETURN_NULL(mNbClients < PX_MAX_CLIENTS, "PxScene::createClient: Maximum number of clients reached! No new client created."); + mNbClients++; //track this just for error checking + return mScene.createClient(); +} + +void NpScene::setClientBehaviorFlags(PxClientID client, PxClientBehaviorFlags clientBehaviorFlags) +{ + NP_WRITE_CHECK(this); + + PX_CHECK_AND_RETURN(client < mNbClients, "PxScene::setClientBehaviorFlags: bad clientID! Please create clientIDs with PxScene::createClient()."); + mScene.setClientBehaviorFlags(client, clientBehaviorFlags); +} + +PxClientBehaviorFlags NpScene::getClientBehaviorFlags(PxClientID client) const +{ + NP_READ_CHECK(this); + PX_CHECK_AND_RETURN_VAL(client < mNbClients, "PxScene::getClientBehaviorFlags: bad clientID! Please create clientIDs with PxScene::createClient().", PxClientBehaviorFlags()); + return mScene.getClientBehaviorFlags(client); +} + +/////////////////////////////////////////////////////////////////////////////// + +//FrictionModel + +void NpScene::setFrictionType(PxFrictionType::Enum frictionType) +{ + NP_WRITE_CHECK(this); + PX_CHECK_AND_RETURN(!mHasSimulatedOnce, "PxScene::setFrictionType: This flag can only be set before calling Simulate() or Collide() for the first time"); + mScene.setFrictionType(frictionType); +} + +PxFrictionType::Enum NpScene::getFrictionType() const +{ + NP_READ_CHECK(this); + return mScene.getFrictionType(); +} + +#if PX_USE_CLOTH_API + +/////////////////////////////////////////////////////////////////////////////// + +//Cloth + +void NpScene::setClothInterCollisionDistance(PxF32 distance) +{ + NP_WRITE_CHECK(this); + PX_CHECK_AND_RETURN(distance >= 0.0f, "PxScene::setClothInterCollisionDistance: distance must be non-negative."); + mScene.setClothInterCollisionDistance(distance); +} + +PxF32 NpScene::getClothInterCollisionDistance() const +{ + NP_READ_CHECK(this); + return mScene.getClothInterCollisionDistance(); +} + +void NpScene::setClothInterCollisionStiffness(PxF32 stiffness) +{ + NP_WRITE_CHECK(this); + PX_CHECK_AND_RETURN(stiffness >= 0.0f, "PxScene::setClothInterCollisionStiffness: stiffness must be non-negative."); + return mScene.setClothInterCollisionStiffness(stiffness); +} + +PxF32 NpScene::getClothInterCollisionStiffness() const +{ + NP_READ_CHECK(this); + return mScene.getClothInterCollisionStiffness(); +} + +void NpScene::setClothInterCollisionNbIterations(PxU32 nbIterations) +{ + NP_WRITE_CHECK(this); + mScene.setClothInterCollisionNbIterations(nbIterations); +} + +PxU32 NpScene::getClothInterCollisionNbIterations() const +{ + NP_READ_CHECK(this); + return mScene.getClothInterCollisionNbIterations(); +} + +#endif + +/////////////////////////////////////////////////////////////////////////////// + +// Callbacks + +void NpScene::setSimulationEventCallback(PxSimulationEventCallback* callback, PxClientID client) +{ + NP_WRITE_CHECK(this); + mScene.setSimulationEventCallback(callback, client); +} + +PxSimulationEventCallback* NpScene::getSimulationEventCallback(PxClientID client) const +{ + NP_READ_CHECK(this); + return mScene.getSimulationEventCallback(client); +} + +void NpScene::setContactModifyCallback(PxContactModifyCallback* callback) +{ + NP_WRITE_CHECK(this); + mScene.setContactModifyCallback(callback); +} + +PxContactModifyCallback* NpScene::getContactModifyCallback() const +{ + NP_READ_CHECK(this); + return mScene.getContactModifyCallback(); +} + +void NpScene::setCCDContactModifyCallback(PxCCDContactModifyCallback* callback) +{ + NP_WRITE_CHECK(this); + mScene.setCCDContactModifyCallback(callback); +} + +PxCCDContactModifyCallback* NpScene::getCCDContactModifyCallback() const +{ + NP_READ_CHECK(this); + return mScene.getCCDContactModifyCallback(); +} + +void NpScene::setBroadPhaseCallback(PxBroadPhaseCallback* callback, PxClientID client) +{ + NP_WRITE_CHECK(this); + mScene.setBroadPhaseCallback(callback, client); +} + +PxBroadPhaseCallback* NpScene::getBroadPhaseCallback(PxClientID client) const +{ + NP_READ_CHECK(this); + return mScene.getBroadPhaseCallback(client); +} + +void NpScene::setCCDMaxPasses(PxU32 ccdMaxPasses) +{ + NP_WRITE_CHECK(this); + mScene.setCCDMaxPasses(ccdMaxPasses); +} + +PxU32 NpScene::getCCDMaxPasses() const +{ + NP_READ_CHECK(this); + return mScene.getCCDMaxPasses(); +} + +PxBroadPhaseType::Enum NpScene::getBroadPhaseType() const +{ + NP_READ_CHECK(this); + return mScene.getBroadPhaseType(); +} + +bool NpScene::getBroadPhaseCaps(PxBroadPhaseCaps& caps) const +{ + NP_READ_CHECK(this); + return mScene.getBroadPhaseCaps(caps); +} + +PxU32 NpScene::getNbBroadPhaseRegions() const +{ + NP_READ_CHECK(this); + return mScene.getNbBroadPhaseRegions(); +} + +PxU32 NpScene::getBroadPhaseRegions(PxBroadPhaseRegionInfo* userBuffer, PxU32 bufferSize, PxU32 startIndex) const +{ + NP_READ_CHECK(this); + return mScene.getBroadPhaseRegions(userBuffer, bufferSize, startIndex); +} + +PxU32 NpScene::addBroadPhaseRegion(const PxBroadPhaseRegion& region, bool populateRegion) +{ + PX_PROFILE_ZONE("BroadPhase.addBroadPhaseRegion", getContextId()); + + NP_WRITE_CHECK(this); + + PX_CHECK_MSG(region.bounds.isValid(), "PxScene::addBroadPhaseRegion(): invalid bounds provided!"); + if(region.bounds.isEmpty()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "PxScene::addBroadPhaseRegion(): region bounds are empty. Call will be ignored."); + return 0xffffffff; + } + + return mScene.addBroadPhaseRegion(region, populateRegion); +} + +bool NpScene::removeBroadPhaseRegion(PxU32 handle) +{ + NP_WRITE_CHECK(this); + return mScene.removeBroadPhaseRegion(handle); +} + +/////////////////////////////////////////////////////////////////////////////// + +// Filtering +void NpScene::setFilterShaderData(const void* data, PxU32 dataSize) +{ + NP_WRITE_CHECK(this); + + PX_CHECK_AND_RETURN(( ((dataSize == 0) && (data == NULL)) || + ((dataSize > 0) && (data != NULL)) ), "PxScene::setFilterShaderData(): data pointer must not be NULL unless the specified data size is 0 too and vice versa."); + + mScene.setFilterShaderData(data, dataSize); +} + +const void* NpScene::getFilterShaderData() const +{ + NP_READ_CHECK(this); + return mScene.getFilterShaderData(); +} + +PxU32 NpScene::getFilterShaderDataSize() const +{ + NP_READ_CHECK(this); + return mScene.getFilterShaderDataSize(); +} + +PxSimulationFilterShader NpScene::getFilterShader() const +{ + NP_READ_CHECK(this); + return mScene.getFilterShader(); +} + +PxSimulationFilterCallback* NpScene::getFilterCallback() const +{ + NP_READ_CHECK(this); + return mScene.getFilterCallback(); +} + +void NpScene::resetFiltering(PxActor& actor) +{ + NP_WRITE_CHECK(this); + + PX_CHECK_AND_RETURN(NpActor::getAPIScene(actor) && (NpActor::getAPIScene(actor) == this), "PxScene::resetFiltering(): actor not in scene!"); + + switch(actor.getConcreteType()) + { + case PxConcreteType::eRIGID_STATIC: + { + NpRigidStatic& npStatic = static_cast<NpRigidStatic&>(actor); + npStatic.resetFiltering(npStatic.getScbRigidStaticFast(), NULL, 0); + } + break; + + case PxConcreteType::eRIGID_DYNAMIC: + { + NpRigidDynamic& npDynamic = static_cast<NpRigidDynamic&>(actor); + if (npDynamic.resetFiltering(npDynamic.getScbBodyFast(), NULL, 0)) + npDynamic.wakeUpInternal(); + } + break; + + case PxConcreteType::eARTICULATION_LINK: + { + NpArticulationLink& npLink = static_cast<NpArticulationLink&>(actor); + if (npLink.resetFiltering(npLink.getScbBodyFast(), NULL, 0)) + npLink.getRoot().wakeUpInternal(false, true); + } + break; + +#if PX_USE_PARTICLE_SYSTEM_API + case PxConcreteType::ePARTICLE_SYSTEM: + { + NpParticleSystem& npSystem = static_cast<NpParticleSystem&>(actor); + npSystem.getScbParticleSystem().resetFiltering(); + } + break; + + case PxConcreteType::ePARTICLE_FLUID: + { + NpParticleFluid& npFluid = static_cast<NpParticleFluid&>(actor); + npFluid.getScbParticleSystem().resetFiltering(); + } + break; +#endif + + default: + Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "PxScene::resetFiltering(): only PxParticleBase and PxRigidActor support this operation!"); + } +} + +void NpScene::resetFiltering(PxRigidActor& actor, PxShape*const* shapes, PxU32 shapeCount) +{ + NP_WRITE_CHECK(this); + PX_CHECK_AND_RETURN(NpActor::getAPIScene(actor) && (NpActor::getAPIScene(actor) == this), "PxScene::resetFiltering(): actor not in scene!"); + PX_SIMD_GUARD; + + switch(actor.getConcreteType()) + { + case PxConcreteType::eRIGID_STATIC: + { + NpRigidStatic& npStatic = static_cast<NpRigidStatic&>(actor); + npStatic.resetFiltering(npStatic.getScbRigidStaticFast(), shapes, shapeCount); + } + break; + + case PxConcreteType::eRIGID_DYNAMIC: + { + NpRigidDynamic& npDynamic = static_cast<NpRigidDynamic&>(actor); + if (npDynamic.resetFiltering(npDynamic.getScbBodyFast(), shapes, shapeCount)) + npDynamic.wakeUpInternal(); + } + break; + + case PxConcreteType::eARTICULATION_LINK: + { + NpArticulationLink& npLink = static_cast<NpArticulationLink&>(actor); + if (npLink.resetFiltering(npLink.getScbBodyFast(), shapes, shapeCount)) + npLink.getRoot().wakeUpInternal(false, true); + } + break; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +PxPhysics& NpScene::getPhysics() +{ + return NpPhysics::getInstance(); +} + +void NpScene::updateDirtyShaders() +{ + PX_PROFILE_ZONE("Sim.updateDirtyShaders", getContextId()); + // this should continue to be done in the Np layer even after SC has taken over + // all vital simulation functions, because it needs to complete before simulate() + // returns to the application + + // However, the implementation needs fixing so that it does work proportional to + // the number of dirty shaders + + PxConstraint*const* constraints = mConstraints.getEntries(); + for(PxU32 i=0;i<mConstraints.size();i++) + { + static_cast<NpConstraint*>(constraints[i])->updateConstants(); + } +} + +/////////////////////////////////////////////////////////////////////////////// +void NpScene::simulateOrCollide(PxReal elapsedTime, physx::PxBaseTask* completionTask, void* scratchBlock, PxU32 scratchBlockSize, bool controlSimulation, const char* invalidCallMsg, Sc::SimulationStage::Enum simStage) +{ + PX_SIMD_GUARD; + + { + // write guard must end before simulation kicks off worker threads + // otherwise the simulation callbacks could overlap with this function + // and perform API reads,triggering an error + NP_WRITE_CHECK(this); + + PX_PROFILE_START_CROSSTHREAD("Basic.simulate", getContextId()); + + if(getSimulationStage() != Sc::SimulationStage::eCOMPLETE) + { + //fetchResult doesn't get called + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, invalidCallMsg); + return; + } + + PX_CHECK_AND_RETURN(elapsedTime > 0, "PxScene::collide/simulate: The elapsed time must be positive!"); + + PX_CHECK_AND_RETURN((reinterpret_cast<size_t>(scratchBlock)&15) == 0, "PxScene::simulate: scratch block must be 16-byte aligned!"); + + PX_CHECK_AND_RETURN((scratchBlockSize&16383) == 0, "PxScene::simulate: scratch block size must be a multiple of 16K"); + +#if PX_SUPPORT_PVD + //signal the frame is starting. + mScene.getScenePvdClient().frameStart(elapsedTime); +#endif + +#if PX_ENABLE_DEBUG_VISUALIZATION + visualize(); +#endif + + updateDirtyShaders(); + +#if PX_SUPPORT_PVD + mScene.getScenePvdClient().updateJoints(); +#endif + + mScene.getScScene().setScratchBlock(scratchBlock, scratchBlockSize); + + mElapsedTime = elapsedTime; + if (simStage == Sc::SimulationStage::eCOLLIDE) + mScene.getScScene().setElapsedTime(elapsedTime); + + mControllingSimulation = controlSimulation; + + //sync all the material events + NpPhysics& physics = static_cast<NpPhysics&>(this->getPhysics()); + NpMaterialManager& manager = physics.getMaterialManager(); + NpMaterial** materials = manager.getMaterials(); + mScene.updateLowLevelMaterial(materials); + +#if PX_USE_PARTICLE_SYSTEM_API + mScene.preSimulateUpdateAppThread(elapsedTime); +#endif + + setSimulationStage(simStage); + mScene.setPhysicsBuffering(true); + mHasSimulatedOnce = true; + } + + { + PX_PROFILE_ZONE("Sim.taskFrameworkSetup", getContextId()); + + if (controlSimulation) + { + { + PX_PROFILE_ZONE("Sim.resetDependencies", getContextId()); + // Only reset dependencies, etc if we own the TaskManager. Will be false + // when an NpScene is controlled by an APEX scene. + mTaskManager->resetDependencies(); + } + mTaskManager->startSimulation(); + } + + if (simStage == Sc::SimulationStage::eCOLLIDE) + { + mCollisionCompletion.setContinuation(*mTaskManager, completionTask); + mSceneCollide.setContinuation(&mCollisionCompletion); + //Initialize scene completion task + mSceneCompletion.setContinuation(*mTaskManager, NULL); + } + else + { + mSceneCompletion.setContinuation(*mTaskManager, completionTask); + mSceneExecution.setContinuation(*mTaskManager, &mSceneCompletion); + } + +#if PX_SUPPORT_GPU_PHYSX + //workaround to prevent premature launching of gpu launch task + if (PxGpuDispatcher* gpuDispatcher = getGpuDispatcher()) + { + //GPU pre-launch task must complete before scene completion can run + gpuDispatcher->addPreLaunchDependent(mSceneCompletion); + } +#endif + + if (simStage == Sc::SimulationStage::eCOLLIDE) + { + mCollisionCompletion.removeReference(); + mSceneCollide.removeReference(); + } + else + { + mSceneCompletion.removeReference(); + mSceneExecution.removeReference(); + } + } +} + +void NpScene::simulate(PxReal elapsedTime, physx::PxBaseTask* completionTask, void* scratchBlock, PxU32 scratchBlockSize, bool controlSimulation) +{ + simulateOrCollide( elapsedTime, completionTask, scratchBlock, scratchBlockSize, controlSimulation, + "PxScene::simulate: Simulation is still processing last simulate call, you should call fetchResults()!", Sc::SimulationStage::eADVANCE); +} + +void NpScene::advance( physx::PxBaseTask* completionTask) +{ + NP_WRITE_CHECK(this); + //issue error if advance() doesn't get called between fetchCollision() and fetchResult() + if(getSimulationStage() != Sc::SimulationStage::eFETCHCOLLIDE) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxScene::advance: advance() called illegally! advance() needed to be called after fetchCollision() and before fetchResult()!!"); + return; + } + + //apply buffering for forces, velocities, kinematic targets and wake-up events + mScene.syncWriteThroughProperties(); + + //if mSimulateStage == eFETCHCOLLIDE, which means collide() has been kicked off and finished running, we can run advance() safely + { + //change the mSimulateStaget to eADVANCE to indicate the next stage to run is fetchResult() + setSimulationStage(Sc::SimulationStage::eADVANCE); + + { + PX_PROFILE_ZONE("Sim.taskFrameworkSetup", getContextId()); + + mSceneCompletion.setDependent(completionTask); + mSceneAdvance.setContinuation(*mTaskManager, &mSceneCompletion); + mSceneCompletion.removeReference(); + mSceneAdvance.removeReference(); + } + } +} + +void NpScene::collide(PxReal elapsedTime, physx::PxBaseTask* completionTask, void* scratchBlock, PxU32 scratchBlockSize, bool controlSimulation) +{ + simulateOrCollide( elapsedTime, + completionTask, + scratchBlock, + scratchBlockSize, + controlSimulation, + "PxScene::collide: collide() called illegally! If it isn't the first frame, collide() needed to be called between fetchResults() and fetchCollision(). Otherwise, collide() needed to be called before fetchCollision()", + Sc::SimulationStage::eCOLLIDE); +} + +bool NpScene::checkResultsInternal(bool block) +{ + PX_PROFILE_ZONE("Basic.checkResults", getContextId()); + return mPhysicsDone.wait(block ? Ps::Sync::waitForever : 0); +} + +bool NpScene::checkCollisionInternal(bool block) +{ + PX_PROFILE_ZONE("Basic.checkCollision", getContextId()); + return mCollisionDone.wait(block ? Ps::Sync::waitForever : 0); +} + +bool NpScene::checkResults(bool block) +{ + return checkResultsInternal(block); +} + +bool NpScene::checkCollision(bool block) +{ + return checkCollisionInternal(block); +} + +void NpScene::fireOutOfBoundsCallbacks() +{ + PX_PROFILE_ZONE("Sim.fireOutOfBoundsCallbacks", getContextId()); + + // Fire broad-phase callbacks + { + Sc::Scene& scene = mScene.getScScene(); + using namespace physx::Sc; + + bool outputWarning = scene.fireOutOfBoundsCallbacks(); + + // Aggregates + { + void** outAgg = scene.getOutOfBoundsAggregates(); + const PxU32 nbOut1 = scene.getNbOutOfBoundsAggregates(); + + for(PxU32 i=0;i<nbOut1;i++) + { + PxAggregate* px = reinterpret_cast<PxAggregate*>(outAgg[i]); + NpAggregate* np = static_cast<NpAggregate*>(px); + if(np->getScbAggregate().getControlState()==Scb::ControlState::eREMOVE_PENDING) + continue; + + // PT: used to avoid calling the callback twice for the same client + bool flags[PX_MAX_CLIENTS]; + PxMemZero(flags, PX_MAX_CLIENTS*sizeof(bool)); + + PxU32 nbActors = np->getCurrentSizeFast(); + for(PxU32 j=0;j<nbActors;j++) + { + PxActor* pxActor = np->getActorFast(j); + const PxClientID clientID = pxActor->getOwnerClient(); + if(!flags[clientID]) + { + flags[clientID] = true; + PxBroadPhaseCallback* cb = scene.getBroadPhaseCallback(clientID); + if(cb) + { + cb->onObjectOutOfBounds(*px); + } + else + { + outputWarning = true; + } + } + } + } + scene.clearOutOfBoundsAggregates(); + } + + if(outputWarning) + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "At least one object is out of the broadphase bounds. To manage those objects, define a PxBroadPhaseCallback for each used client."); + } +} + +bool NpScene::fetchCollision(bool block) +{ + if(getSimulationStage() != Sc::SimulationStage::eCOLLIDE) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxScene::fetchCollision: fetchCollision() should be called after collide() and before advance()!"); + return false; + } + + //if collision isn't finish running (and block is false), then return false + if(!checkCollisionInternal(block)) + return false; + + // take write check *after* collision() finished, otherwise + // we will block fetchCollision() from using the API + NP_WRITE_CHECK_NOREENTRY(this); + + setSimulationStage(Sc::SimulationStage::eFETCHCOLLIDE); + + return true; +} + +class SqRefFinder: public Sc::SqRefFinder +{ +public: + PxU32 find(const PxRigidBody * body, const PxShape* shape) + { + Sq::PrunerData prunerdata = NpActor::getShapeManager(*body)->findSceneQueryData(*static_cast<const NpShape*>(shape)); + return Sq::getPrunerHandle(prunerdata); + } +private: +}; + +// The order of the following operations is important! +// 1. Process object deletions which were carried out while the simulation was running (since these effect contact and trigger reports) +// 2. Write contact reports to global stream (taking pending deletions into account), clear some simulation buffers (deleted objects etc.), ... +// 3. Send reports which have to be done before the data is synced (contact & trigger reports etc.) such that the user gets the old state. +// 4. Mark the simulation as not running internally to allow reading data which should not be read otherwise +// 5. Synchronize the simulation and user state +// 6. Fire callbacks which need to reflect the synchronized object state + +void NpScene::fetchResultsPreContactCallbacks() +{ +#if PX_SUPPORT_PVD + mScene.getScenePvdClient().updateContacts(); +#endif + + mScene.prepareOutOfBoundsCallbacks(); + mScene.processPendingRemove(); + mScene.endSimulation(); + + { + PX_PROFILE_ZONE("Sim.fireCallbacksPreSync", getContextId()); + fireOutOfBoundsCallbacks(); // fire out-of-bounds callbacks + mScene.fireBrokenConstraintCallbacks(); + mScene.fireTriggerCallbacks(); + } +} + +void NpScene::fetchResultsPostContactCallbacks() +{ + mScene.postCallbacksPreSync(); + mScene.setPhysicsBuffering(false); // Clear the buffering flag to allow buffered writes to execute immediately. Once collision detection is running, buffering is automatically forced on + mScene.syncEntireScene(NULL); // double buffering + + SqRefFinder sqRefFinder; + mScene.getScScene().syncSceneQueryBounds(mSQManager.getDynamicBoundsSync(), sqRefFinder); + + mSQManager.afterSync(!(getFlagsFast()&PxSceneFlag::eSUPPRESS_EAGER_SCENE_QUERY_REFIT)); + +#if PX_DEBUG && 0 + mSQManager.validateSimUpdates(); +#endif + +#if PX_SUPPORT_PVD + mScene.getScenePvdClient().updateSceneQueries(); + + getSingleSqCollector().clear(); + getBatchedSqCollector().clear(); +#endif + + // fire sleep and wake-up events + // we do this after buffer-swapping so that the events have the new state + { + PX_PROFILE_ZONE("Sim.fireCallbacksPostSync", getContextId()); + mScene.fireCallBacksPostSync(); + } + + mScene.postReportsCleanup(); + + // build the list of active transforms + { + PX_PROFILE_ZONE("Sim.buildActiveTransforms", getContextId()); + if (mScene.getFlags() & PxSceneFlag::eENABLE_ACTIVETRANSFORMS) + mScene.buildActiveTransforms(); + if (mScene.getFlags() & PxSceneFlag::eENABLE_ACTIVE_ACTORS) + mScene.buildActiveActors(); + } + + mRenderBuffer.append(mScene.getScScene().getRenderBuffer()); + + PX_ASSERT(getSimulationStage() != Sc::SimulationStage::eCOMPLETE); + if (mControllingSimulation) + { + mTaskManager->stopSimulation(); + } + + setSimulationStage(Sc::SimulationStage::eCOMPLETE); + + mPhysicsDone.reset(); // allow Physics to run again + mCollisionDone.reset(); +} + +bool NpScene::fetchResults(bool block, PxU32* errorState) +{ + if(getSimulationStage() != Sc::SimulationStage::eADVANCE) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxScene::fetchResults: fetchResults() called illegally! It must be called after advance() or simulate()"); + return false; + } + + if(!checkResultsInternal(block)) + return false; + + { + PX_SIMD_GUARD; + + // take write check *after* simulation has finished, otherwise + // we will block simulation callbacks from using the API + // disallow re-entry to detect callbacks making write calls + NP_WRITE_CHECK_NOREENTRY(this); + + // we use cross thread profile here, to show the event in cross thread view + // PT: TODO: why do we want to show it in the cross thread view? + PX_PROFILE_START_CROSSTHREAD("Basic.fetchResults", getContextId()); + PX_PROFILE_ZONE("Sim.fetchResults", getContextId()); + + fetchResultsPreContactCallbacks(); + + { + // PT: TODO: why a cross-thread event here? + PX_PROFILE_START_CROSSTHREAD("Basic.processCallbacks", getContextId()); + mScene.fireQueuedContactCallbacks(); + PX_PROFILE_STOP_CROSSTHREAD("Basic.processCallbacks", getContextId()); + } + + fetchResultsPostContactCallbacks(); + + PX_PROFILE_STOP_CROSSTHREAD("Basic.fetchResults", getContextId()); + PX_PROFILE_STOP_CROSSTHREAD("Basic.simulate", getContextId()); + + if(errorState) + *errorState = mScene.getScScene().getErrorState(); + } + +#if PX_SUPPORT_PVD + mScene.getScenePvdClient().frameEnd(); +#endif + return true; +} + +bool NpScene::fetchResultsStart(const PxContactPairHeader*& contactPairs, PxU32& nbContactPairs, bool block) +{ + if (getSimulationStage() != Sc::SimulationStage::eADVANCE) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PXScene::fetchResultsStart: fetchResultsStart() called illegally! It must be called after advance() or simulate()"); + return false; + } + + if (!checkResultsInternal(block)) + return false; + + PX_SIMD_GUARD; + NP_WRITE_CHECK(this); + + // we use cross thread profile here, to show the event in cross thread view + PX_PROFILE_START_CROSSTHREAD("Basic.fetchResults", getContextId()); + PX_PROFILE_ZONE("Sim.fetchResultsStart", getContextId()); + + fetchResultsPreContactCallbacks(); + const Ps::Array<PxContactPairHeader>& pairs = mScene.getQueuedContactPairHeaders(); + nbContactPairs = pairs.size(); + contactPairs = pairs.begin(); + + mBetweenFetchResults = true; + return true; +} + +void NpContactCallbackTask::setData(NpScene* scene, const PxContactPairHeader* contactPairHeaders, const uint32_t nbContactPairHeaders) +{ + mScene = scene; + mContactPairHeaders = contactPairHeaders; + mNbContactPairHeaders = nbContactPairHeaders; +} + +void NpContactCallbackTask::run() +{ + mScene->lockRead(); + for (uint32_t i = 0; i < mNbContactPairHeaders; ++i) + { + const physx::PxContactPairHeader& pairHeader = mContactPairHeaders[i]; + physx::PxRigidActor* aActor = pairHeader.actors[0]; + physx::PxRigidActor* bActor = pairHeader.actors[1]; + + physx::PxClientID clientActor0 = aActor->getOwnerClient(); + physx::PxClientID clientActor1 = bActor->getOwnerClient(); + + physx::PxSimulationEventCallback* aCallback = mScene->getSimulationEventCallback(clientActor0); + physx::PxSimulationEventCallback* bCallback = mScene->getSimulationEventCallback(clientActor1); + + uint8_t actor0ClientBehaviorFlags = aActor->getClientBehaviorFlags();//aPair->getActorAClientBehavior(); + uint8_t actor1ClientBehaviorFlags = bActor->getClientBehaviorFlags(); + + if (aCallback && + ( + (clientActor0 == clientActor1) //easy common case: the same client owns both shapes + || ( //else actor1 has a different owner -- see if we can still send this pair to the client of actor0: + (actor0ClientBehaviorFlags & physx::PxClientBehaviorFlag::eREPORT_FOREIGN_OBJECTS_TO_CONTACT_NOTIFY)//this client accepts foreign objects + && (actor1ClientBehaviorFlags & physx::PxActorClientBehaviorFlag::eREPORT_TO_FOREIGN_CLIENTS_CONTACT_NOTIFY)//this actor can be sent to foreign client + ) + )) + aCallback->onContact(pairHeader, pairHeader.pairs, pairHeader.nbPairs); + + if ( + (clientActor0 != clientActor1) //don't call the same client twice + && bCallback + && (actor1ClientBehaviorFlags & physx::PxClientBehaviorFlag::eREPORT_FOREIGN_OBJECTS_TO_CONTACT_NOTIFY)//this client accepts foreign objects + && (actor0ClientBehaviorFlags & physx::PxActorClientBehaviorFlag::eREPORT_TO_FOREIGN_CLIENTS_CONTACT_NOTIFY)//this actor can be sent to foreign client + ) + bCallback->onContact(pairHeader, pairHeader.pairs, pairHeader.nbPairs); + } + mScene->unlockRead(); +} + +void NpScene::processCallbacks(physx::PxBaseTask* continuation) +{ + PX_PROFILE_START_CROSSTHREAD("Basic.processCallbacks", getContextId()); + PX_PROFILE_ZONE("Sim.processCallbacks", getContextId()); + //ML: because Apex destruction callback isn't thread safe so that we make this run single thread first + const Ps::Array<PxContactPairHeader>& pairs = mScene.getQueuedContactPairHeaders(); + const PxU32 nbPairs = pairs.size(); + const PxContactPairHeader* contactPairs = pairs.begin(); + const PxU32 nbToProcess = 256; + + Cm::FlushPool* flushPool = mScene.getScScene().getFlushPool(); + + for (PxU32 i = 0; i < nbPairs; i += nbToProcess) + { + NpContactCallbackTask* task = PX_PLACEMENT_NEW(flushPool->allocate(sizeof(NpContactCallbackTask)), NpContactCallbackTask)(); + task->setData(this, contactPairs+i, PxMin(nbToProcess, nbPairs - i)); + task->setContinuation(continuation); + task->removeReference(); + } +} + +void NpScene::fetchResultsFinish(PxU32* errorState) +{ + { + PX_SIMD_GUARD; + PX_PROFILE_STOP_CROSSTHREAD("Basic.processCallbacks", getContextId()); + PX_PROFILE_ZONE("Basic.fetchResultsFinish", getContextId()); + + mBetweenFetchResults = false; + NP_WRITE_CHECK(this); + + fetchResultsPostContactCallbacks(); + + if (errorState) + *errorState = mScene.getScScene().getErrorState(); + + PX_PROFILE_STOP_CROSSTHREAD("Basic.fetchResults", getContextId()); + PX_PROFILE_STOP_CROSSTHREAD("Basic.simulate", getContextId()); + } + +#if PX_SUPPORT_PVD + mScene.getScenePvdClient().frameEnd(); +#endif +} + +void NpScene::flushSimulation(bool sendPendingReports) +{ + PX_PROFILE_ZONE("API.flushSimulation", getContextId()); + NP_WRITE_CHECK_NOREENTRY(this); + PX_SIMD_GUARD; + + if (getSimulationStage() != Sc::SimulationStage::eCOMPLETE) + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, + "PxScene::flushSimulation(): This call is not allowed while the simulation is running. Call will be ignored"); + return; + } + + mScene.flush(sendPendingReports); + mSQManager.flushMemory(); + + //!!! TODO: Shrink all NpObject lists? +} + +void NpScene::flushQueryUpdates() +{ + // DS: how do we profile const methods?????? + PX_PROFILE_ZONE("API.flushQueryUpdates", getContextId()); + NP_READ_CHECK(this); + PX_SIMD_GUARD; + + if (getSimulationStage() != Sc::SimulationStage::eCOMPLETE) + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, + "PxScene::flushQueryUpdates(): This call is not allowed while the simulation is running. Call will be ignored"); + return; + } + + mSQManager.flushUpdates(); +} + +/* +Replaces finishRun() with the addition of appropriate thread sync(pulled out of PhysicsThread()) + +Note: this function can be called from the application thread or the physics thread, depending on the +scene flags. +*/ +void NpScene::executeScene(PxBaseTask* continuation) +{ + mScene.simulate(mElapsedTime, continuation); +} + +void NpScene::executeCollide(PxBaseTask* continuation) +{ + mScene.collide(mElapsedTime, continuation); +} + +void NpScene::executeAdvance(PxBaseTask* continuation) +{ + mScene.advance(mElapsedTime, continuation); +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpScene::addMaterial(const NpMaterial& mat) +{ + mScene.addMaterial(mat.getScMaterial()); +} + +void NpScene::updateMaterial(const NpMaterial& mat) +{ + //PxU32 index = mat.getTableIndex(); + mScene.updateMaterial(mat.getScMaterial()); +} + +void NpScene::removeMaterial(const NpMaterial& mat) +{ + //PxU32 index = mat.getTableIndex(); + mScene.removeMaterial(mat.getScMaterial()); +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpScene::setDominanceGroupPair(PxDominanceGroup group1, PxDominanceGroup group2, const PxDominanceGroupPair& dominance) +{ + NP_WRITE_CHECK(this); + PX_CHECK_AND_RETURN((group1 < PX_MAX_DOMINANCE_GROUP && group2 < PX_MAX_DOMINANCE_GROUP), + "PxScene::setDominanceGroupPair: invalid params! Groups must be <= 31!"); + //can't change matrix diagonal + PX_CHECK_AND_RETURN(group1 != group2, "PxScene::setDominanceGroupPair: invalid params! Groups must be unequal! Can't change matrix diagonal!"); + PX_CHECK_AND_RETURN( + ((dominance.dominance0) == 1.0f && (dominance.dominance1 == 1.0f)) + || ((dominance.dominance0) == 1.0f && (dominance.dominance1 == 0.0f)) + || ((dominance.dominance0) == 0.0f && (dominance.dominance1 == 1.0f)) + , "PxScene::setDominanceGroupPair: invalid params! dominance must be one of (1,1), (1,0), or (0,1)!"); + + mScene.setDominanceGroupPair(group1, group2, dominance); +} + +PxDominanceGroupPair NpScene::getDominanceGroupPair(PxDominanceGroup group1, PxDominanceGroup group2) const +{ + NP_READ_CHECK(this); + PX_CHECK_AND_RETURN_VAL((group1 < PX_MAX_DOMINANCE_GROUP && group2 < PX_MAX_DOMINANCE_GROUP), + "PxScene::getDominanceGroupPair: invalid params! Groups must be <= 31!", PxDominanceGroupPair(PxU8(1u), PxU8(1u))); + return mScene.getDominanceGroupPair(group1, group2); +} + +/////////////////////////////////////////////////////////////////////////////// + +#if PX_USE_PARTICLE_SYSTEM_API + +void NpScene::addParticleSystem(NpParticleSystem& system) +{ + PX_PROFILE_ZONE("API.addParticleSystem", getContextId()); + + PX_CHECK_AND_RETURN(mScene.getScScene().getParticleContext(), "PxRegisterParticles needs to be called before scene creation. PxParticleSystem not added to scene."); + mScene.addParticleSystem(system.getScbParticleSystem()); + mPxParticleBaseSet.insert(&system); + + updatePhysXIndicator(); +} + +void NpScene::removeParticleSystem(NpParticleSystem& system) +{ + PX_PROFILE_ZONE("API.removeParticleSystem", getContextId()); + PX_ASSERT(system.getNpScene() == this); + + PX_CHECK_AND_RETURN(mScene.getScScene().getParticleContext(), "PxRegisterParticles needs to be called before scene creation. PxParticleFluid not added to scene."); + mScene.removeParticleSystem(system.getScbParticleSystem(), false); + removeFromParticleBaseList(system); + + updatePhysXIndicator(); +} + +void NpScene::addParticleFluid(NpParticleFluid& fluid) +{ + PX_PROFILE_ZONE("API.addParticleFluid", getContextId()); + mScene.addParticleSystem(fluid.getScbParticleSystem()); + mPxParticleBaseSet.insert(&fluid); + + updatePhysXIndicator(); +} + +void NpScene::removeParticleFluid(NpParticleFluid& fluid) +{ + PX_PROFILE_ZONE("API.removeParticleFluid", getContextId()); + PX_ASSERT(fluid.getNpScene() == this); + + mScene.removeParticleSystem(fluid.getScbParticleSystem(), false); + removeFromParticleBaseList(fluid); + + updatePhysXIndicator(); +} + +#endif // PX_USE_PARTICLE_SYSTEM_API + +/////////////////////////////////////////////////////////////////////////////// + +#if PX_USE_CLOTH_API + +void NpScene::addCloth(NpCloth& cloth) +{ + PX_PROFILE_ZONE("API.addCloth", getContextId()); + mScene.addCloth(cloth.getScbCloth()); + mPxCloths.insert(&cloth); + + updatePhysXIndicator(); +} + +void NpScene::removeCloth(NpCloth& cloth) +{ + PX_PROFILE_ZONE("API.removeCloth", getContextId()); + PX_ASSERT(NpActor::getAPIScene(cloth) == this); + + mScene.removeCloth(cloth.getScbCloth()); + removeFromClothList(cloth); + + updatePhysXIndicator(); +} + +#endif // PX_USE_CLOTH_API + +/////////////////////////////////////////////////////////////////////////////// + +#if PX_SUPPORT_GPU_PHYSX + +void NpScene::updatePhysXIndicator() +{ + Ps::IntBool isGpu = 0; + +#if PX_USE_PARTICLE_SYSTEM_API + PxParticleBase*const* particleBaseList = mPxParticleBaseSet.getEntries(); + for (PxU32 i = 0; !isGpu && i < mPxParticleBaseSet.size(); i++) + { + NpParticleSystem* particles = (NpParticleSystem*)particleBaseList[i]->is<PxParticleSystem>(); + NpParticleFluid* fluid = (NpParticleFluid*)particleBaseList[i]->is<PxParticleFluid>(); + + isGpu |= particles && particles->getScbParticleSystem().getScParticleSystem().isGpu(); + isGpu |= fluid && fluid->getScbParticleSystem().getScParticleSystem().isGpu(); + } +#endif + +#if PX_USE_CLOTH_API + PxCloth*const* clothList = mPxCloths.getEntries(); + for (PxU32 i = 0; !isGpu && i < mPxCloths.size(); i++) + { + NpCloth* pCloth = (NpCloth*)clothList[i]->is<PxCloth>(); + isGpu = pCloth->getScbCloth().getScCloth().isGpu(); + } +#endif + + mPhysXIndicator.setIsGpu(isGpu != 0); +} +#endif //PX_SUPPORT_GPU_PHYSX + +/////////////////////////////////////////////////////////////////////////////// + +PxVolumeCache* NpScene::createVolumeCache(PxU32 maxStaticShapes, PxU32 maxDynamicShapes) +{ + NpVolumeCache* cache = PX_NEW(NpVolumeCache)(&mSQManager, maxStaticShapes, maxDynamicShapes); + mVolumeCaches.insert(cache); + return cache; +} + +void NpScene::releaseVolumeCache(NpVolumeCache* volumeCache) +{ + bool found = mVolumeCaches.erase(volumeCache); PX_UNUSED(found); + PX_ASSERT_WITH_MESSAGE(found, "volume cache not found in releaseVolumeCache"); + PX_DELETE(static_cast<NpVolumeCache*>(volumeCache)); +} + +void NpScene::setDynamicTreeRebuildRateHint(PxU32 dynamicTreeRebuildRateHint) +{ + PX_CHECK_AND_RETURN((dynamicTreeRebuildRateHint >= 4), "PxScene::setDynamicTreeRebuildRateHint(): Param has to be >= 4!"); + mSQManager.setDynamicTreeRebuildRateHint(dynamicTreeRebuildRateHint); +} + +PxU32 NpScene::getDynamicTreeRebuildRateHint() const +{ + NP_READ_CHECK(this); + return mSQManager.getDynamicTreeRebuildRateHint(); +} + +void NpScene::forceDynamicTreeRebuild(bool rebuildStaticStructure, bool rebuildDynamicStructure) +{ + PX_PROFILE_ZONE("API.forceDynamicTreeRebuild", getContextId()); + NP_WRITE_CHECK(this); + PX_SIMD_GUARD; + mSQManager.forceDynamicTreeRebuild(rebuildStaticStructure, rebuildDynamicStructure); +} + +void NpScene::setSolverBatchSize(PxU32 solverBatchSize) +{ + NP_WRITE_CHECK(this); + mScene.setSolverBatchSize(solverBatchSize); +} + +PxU32 NpScene::getSolverBatchSize(void) const +{ + NP_READ_CHECK(this); + // get from our local copy + return mScene.getSolverBatchSize(); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool NpScene::setVisualizationParameter(PxVisualizationParameter::Enum param, PxReal value) +{ + NP_WRITE_CHECK(this); + PX_CHECK_AND_RETURN_VAL(PxIsFinite(value), "PxScene::setVisualizationParameter: value is not valid.", false); + + if (param >= PxVisualizationParameter::eNUM_VALUES) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "setVisualizationParameter: parameter out of range."); + return false; + } + else if (value < 0.0f) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "setVisualizationParameter: value must be larger or equal to 0."); + return false; + } + else + { + mScene.setVisualizationParameter(param, value); + return true; + } +} + +PxReal NpScene::getVisualizationParameter(PxVisualizationParameter::Enum param) const +{ + if (param < PxVisualizationParameter::eNUM_VALUES) + return mScene.getVisualizationParameter(param); + else + Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "getVisualizationParameter: param is not an enum."); + + return 0.0f; +} + +void NpScene::setVisualizationCullingBox(const PxBounds3& box) +{ + NP_WRITE_CHECK(this); + PX_CHECK_MSG(box.isValid(), "PxScene::setVisualizationCullingBox(): invalid bounds provided!"); + mScene.setVisualizationCullingBox(box); +} + +const PxBounds3& NpScene::getVisualizationCullingBox() const +{ + NP_READ_CHECK(this); + const PxBounds3& bounds = mScene.getVisualizationCullingBox(); + PX_ASSERT(bounds.isValid()); + return bounds; +} + +void NpScene::setNbContactDataBlocks(PxU32 numBlocks) +{ + PX_CHECK_AND_RETURN((getSimulationStage() == Sc::SimulationStage::eCOMPLETE), + "PxScene::setNbContactDataBlock: This call is not allowed while the simulation is running. Call will be ignored!"); + + mScene.getScScene().setNbContactDataBlocks(numBlocks); +} + +PxU32 NpScene::getNbContactDataBlocksUsed() const +{ + PX_CHECK_AND_RETURN_VAL((getSimulationStage() == Sc::SimulationStage::eCOMPLETE), + "PxScene::getNbContactDataBlocksUsed: This call is not allowed while the simulation is running. Returning 0.", 0); + + return mScene.getScScene().getNbContactDataBlocksUsed(); +} + +PxU32 NpScene::getMaxNbContactDataBlocksUsed() const +{ + PX_CHECK_AND_RETURN_VAL((getSimulationStage() == Sc::SimulationStage::eCOMPLETE), + "PxScene::getMaxNbContactDataBlocksUsed: This call is not allowed while the simulation is running. Returning 0.", 0); + + return mScene.getScScene().getMaxNbContactDataBlocksUsed(); +} + +PxU32 NpScene::getTimestamp() const +{ + return mScene.getScScene().getTimeStamp(); +} + +PxU32 NpScene::getSceneQueryStaticTimestamp() const +{ + return mSQManager.get(PruningIndex::eSTATIC).timestamp(); +} + +PxCpuDispatcher* NpScene::getCpuDispatcher() const +{ + return getTaskManager()->getCpuDispatcher(); +} + +PxGpuDispatcher* NpScene::getGpuDispatcher() const +{ + return getTaskManager()->getGpuDispatcher(); +} + +PxPruningStructureType::Enum NpScene::getStaticStructure() const +{ + return mSQManager.get(PruningIndex::eSTATIC).type(); +} + +PxPruningStructureType::Enum NpScene::getDynamicStructure() const +{ + return mSQManager.get(PruningIndex::eDYNAMIC).type(); +} + +PxReal NpScene::getFrictionOffsetThreshold() const +{ + return mScene.getScScene().getFrictionOffsetThreshold(); +} + +PxU32 NpScene::getContactReportStreamBufferSize() const +{ + return mScene.getScScene().getDefaultContactReportStreamBufferSize(); +} + +#if PX_CHECKED +void NpScene::checkPositionSanity(const PxRigidActor& a, const PxTransform& pose, const char* fnName) const +{ + if(!mSanityBounds.contains(pose.p)) + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, + "%s: actor pose for %lp is outside sanity bounds\n", fnName, &a); +} +#endif + +namespace +{ + struct ThreadReadWriteCount + { + PxU8 readDepth; // depth of re-entrant reads + PxU8 writeDepth; // depth of re-entrant writes + + PxU8 readLockDepth; // depth of read-locks + PxU8 writeLockDepth; // depth of write-locks + }; +} + +#if NP_ENABLE_THREAD_CHECKS + +NpScene::StartWriteResult::Enum NpScene::startWrite(bool allowReentry) +{ + PX_COMPILE_TIME_ASSERT(sizeof(ThreadReadWriteCount) == 4); + + if (mScene.getFlags() & PxSceneFlag::eREQUIRE_RW_LOCK) + { + ThreadReadWriteCount localCounts = PxUnionCast<ThreadReadWriteCount>(TlsGet(mThreadReadWriteDepth)); + + if (mBetweenFetchResults) + return StartWriteResult::eIN_FETCHRESULTS; + + // ensure we already have the write lock + return localCounts.writeLockDepth > 0 ? StartWriteResult::eOK : StartWriteResult::eNO_LOCK; + } + + { + ThreadReadWriteCount localCounts = PxUnionCast<ThreadReadWriteCount>(TlsGet(mThreadReadWriteDepth)); + StartWriteResult::Enum result; + + if (mBetweenFetchResults) + result = StartWriteResult::eIN_FETCHRESULTS; + + // check we are the only thread reading (allows read->write order on a single thread) and no other threads are writing + else if (mConcurrentReadCount != localCounts.readDepth || mConcurrentWriteCount != localCounts.writeDepth) + result = StartWriteResult::eRACE_DETECTED; + + else + result = StartWriteResult::eOK; + + // increment shared write counter + Ps::atomicIncrement(&mConcurrentWriteCount); + + // in the normal case (re-entry is allowed) then we simply increment + // the writeDepth by 1, otherwise (re-entry is not allowed) increment + // by 2 to force subsequent writes to fail by creating a mismatch between + // the concurrent write counter and the local counter, any value > 1 will do + localCounts.writeDepth += allowReentry ? 1 : 2; + TlsSet(mThreadReadWriteDepth, PxUnionCast<void*>(localCounts)); + + if (result != StartWriteResult::eOK) + Ps::atomicIncrement(&mConcurrentErrorCount); + + return result; + } +} + +void NpScene::stopWrite(bool allowReentry) +{ + if (!(mScene.getFlags() & PxSceneFlag::eREQUIRE_RW_LOCK)) + { + Ps::atomicDecrement(&mConcurrentWriteCount); + + // decrement depth of writes for this thread + ThreadReadWriteCount localCounts = PxUnionCast<ThreadReadWriteCount>(TlsGet(mThreadReadWriteDepth)); + + // see comment in startWrite() + if (allowReentry) + localCounts.writeDepth--; + else + localCounts.writeDepth-=2; + + TlsSet(mThreadReadWriteDepth, PxUnionCast<void*>(localCounts)); + } +} + +bool NpScene::startRead() const +{ + if (mScene.getFlags() & PxSceneFlag::eREQUIRE_RW_LOCK) + { + ThreadReadWriteCount localCounts = PxUnionCast<ThreadReadWriteCount>(TlsGet(mThreadReadWriteDepth)); + + // ensure we already have the write or read lock + return localCounts.writeLockDepth > 0 || localCounts.readLockDepth > 0; + } + else + { + Ps::atomicIncrement(&mConcurrentReadCount); + + // update current threads read depth + ThreadReadWriteCount localCounts = PxUnionCast<ThreadReadWriteCount>(TlsGet(mThreadReadWriteDepth)); + localCounts.readDepth++; + TlsSet(mThreadReadWriteDepth, PxUnionCast<void*>(localCounts)); + + // success if the current thread is already performing a write (API re-entry) or no writes are in progress + bool success = (localCounts.writeDepth > 0 || mConcurrentWriteCount == 0); + + if (!success) + Ps::atomicIncrement(&mConcurrentErrorCount); + + return success; + } +} + +void NpScene::stopRead() const +{ + if (!(mScene.getFlags() & PxSceneFlag::eREQUIRE_RW_LOCK)) + { + Ps::atomicDecrement(&mConcurrentReadCount); + + // update local threads read depth + ThreadReadWriteCount localCounts = PxUnionCast<ThreadReadWriteCount>(TlsGet(mThreadReadWriteDepth)); + localCounts.readDepth--; + TlsSet(mThreadReadWriteDepth, PxUnionCast<void*>(localCounts)); + } +} + +#else + +NpScene::StartWriteResult::Enum NpScene::startWrite(bool) { PX_ASSERT(0); return NpScene::StartWriteResult::eOK; } +void NpScene::stopWrite(bool) {} + +bool NpScene::startRead() const { PX_ASSERT(0); return false; } +void NpScene::stopRead() const {} + +#endif // NP_ENABLE_THREAD_CHECKS + +void NpScene::lockRead(const char* /*file*/, PxU32 /*line*/) +{ + // increment this threads read depth + ThreadReadWriteCount localCounts = PxUnionCast<ThreadReadWriteCount>(TlsGet(mThreadReadWriteDepth)); + localCounts.readLockDepth++; + TlsSet(mThreadReadWriteDepth, PxUnionCast<void*>(localCounts)); + + // if we are the current writer then do nothing (allow reading from threads with write ownership) + if (mCurrentWriter == Thread::getId()) + return; + + // only lock on first read + if (localCounts.readLockDepth == 1) + mRWLock.lockReader(); +} + +void NpScene::unlockRead() +{ + // increment this threads read depth + ThreadReadWriteCount localCounts = PxUnionCast<ThreadReadWriteCount>(TlsGet(mThreadReadWriteDepth)); + if (localCounts.readLockDepth < 1) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxScene::unlockRead() called without matching call to PxScene::lockRead(), behaviour will be undefined."); + return; + } + localCounts.readLockDepth--; + TlsSet(mThreadReadWriteDepth, PxUnionCast<void*>(localCounts)); + + // if we are the current writer then do nothing (allow reading from threads with write ownership) + if (mCurrentWriter == Thread::getId()) + return; + + // only unlock on last read + if (localCounts.readLockDepth == 0) + mRWLock.unlockReader(); +} + +void NpScene::lockWrite(const char* file, PxU32 line) +{ + // increment this threads write depth + ThreadReadWriteCount localCounts = PxUnionCast<ThreadReadWriteCount>(TlsGet(mThreadReadWriteDepth)); + if (localCounts.writeLockDepth == 0 && localCounts.readLockDepth > 0) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, file?file:__FILE__, file?int(line):__LINE__, "PxScene::lockWrite() detected after a PxScene::lockRead(), lock upgrading is not supported, behaviour will be undefined."); + return; + } + localCounts.writeLockDepth++; + TlsSet(mThreadReadWriteDepth, PxUnionCast<void*>(localCounts)); + + // only lock on first call + if (localCounts.writeLockDepth == 1) + mRWLock.lockWriter(); + + PX_ASSERT(mCurrentWriter == 0 || mCurrentWriter == Thread::getId()); + + // set ourselves as the current writer + mCurrentWriter = Thread::getId(); +} + +void NpScene::unlockWrite() +{ + // increment this thread's write depth + ThreadReadWriteCount localCounts = PxUnionCast<ThreadReadWriteCount>(TlsGet(mThreadReadWriteDepth)); + if (localCounts.writeLockDepth < 1) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxScene::unlockWrite() called without matching call to PxScene::lockWrite(), behaviour will be undefined."); + return; + } + localCounts.writeLockDepth--; + TlsSet(mThreadReadWriteDepth, PxUnionCast<void*>(localCounts)); + + PX_ASSERT(mCurrentWriter == Thread::getId()); + + if (localCounts.writeLockDepth == 0) + { + mCurrentWriter = 0; + mRWLock.unlockWriter(); + } +} + +PxReal NpScene::getWakeCounterResetValue() const +{ + NP_READ_CHECK(this); + + return getWakeCounterResetValueInteral(); +} + +static PX_FORCE_INLINE void shiftRigidActor(PxRigidActor* a, const PxVec3& shift) +{ + PxActorType::Enum t = a->getType(); + if (t == PxActorType::eRIGID_DYNAMIC) + { + NpRigidDynamic* rd = static_cast<NpRigidDynamic*>(a); + rd->getScbBodyFast().onOriginShift(shift); + } + else if (t == PxActorType::eRIGID_STATIC) + { + NpRigidStatic* rs = static_cast<NpRigidStatic*>(a); + rs->getScbRigidStaticFast().onOriginShift(shift); + } + else + { + PX_ASSERT(t == PxActorType::eARTICULATION_LINK); + NpArticulationLink* al = static_cast<NpArticulationLink*>(a); + al->getScbBodyFast().onOriginShift(shift); + } +} + +void NpScene::shiftOrigin(const PxVec3& shift) +{ + PX_PROFILE_ZONE("API.shiftOrigin", getContextId()); + NP_WRITE_CHECK(this); + + if(mScene.isPhysicsBuffering()) + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::shiftOrigin() not allowed while simulation is running. Call will be ignored."); + return; + } + + PX_SIMD_GUARD; + + const PxU32 prefetchLookAhead = 4; + PxU32 rigidCount = mRigidActors.size(); + PxRigidActor*const* rigidActors = mRigidActors.begin(); + PxU32 batchIterCount = rigidCount / prefetchLookAhead; + + PxU32 idx = 0; + for(PxU32 i=0; i < batchIterCount; i++) + { + // prefetch elements for next batch + if (i < (batchIterCount-1)) + { + Ps::prefetchLine(rigidActors[idx + prefetchLookAhead]); + Ps::prefetchLine(reinterpret_cast<PxU8*>(rigidActors[idx + prefetchLookAhead]) + 128); // for the buffered pose + Ps::prefetchLine(rigidActors[idx + prefetchLookAhead + 1]); + Ps::prefetchLine(reinterpret_cast<PxU8*>(rigidActors[idx + prefetchLookAhead + 1]) + 128); + Ps::prefetchLine(rigidActors[idx + prefetchLookAhead + 2]); + Ps::prefetchLine(reinterpret_cast<PxU8*>(rigidActors[idx + prefetchLookAhead + 2]) + 128); + Ps::prefetchLine(rigidActors[idx + prefetchLookAhead + 3]); + Ps::prefetchLine(reinterpret_cast<PxU8*>(rigidActors[idx + prefetchLookAhead + 3]) + 128); + } + else + { + for(PxU32 k=(idx + prefetchLookAhead); k < rigidCount; k++) + { + Ps::prefetchLine(rigidActors[k]); + Ps::prefetchLine(reinterpret_cast<PxU8*>(rigidActors[k]) + 128); + } + } + + for(PxU32 j=idx; j < (idx + prefetchLookAhead); j++) + { + shiftRigidActor(rigidActors[j], shift); + } + + idx += prefetchLookAhead; + } + // process remaining objects + for(PxU32 i=idx; i < rigidCount; i++) + { + shiftRigidActor(rigidActors[i], shift); + } + + PxArticulation*const* articulations = mArticulations.getEntries(); + for(PxU32 i=0; i < mArticulations.size(); i++) + { + NpArticulation* np = static_cast<NpArticulation*>(articulations[i]); + NpArticulationLink*const* links = np->getLinks(); + + for(PxU32 j=0; j < np->getNbLinks(); j++) + { + shiftRigidActor(links[j], shift); + } + } + + + mScene.shiftOrigin(shift); + + + // + // shift scene query related data structures + // + mSQManager.shiftOrigin(shift); + + Ps::HashSet<NpVolumeCache*>::Iterator it = mVolumeCaches.getIterator(); + while (!it.done()) + { + NpVolumeCache* cache = (*it); + cache->onOriginShift(shift); + ++it; + } + + +#if PX_ENABLE_DEBUG_VISUALIZATION + // + // debug visualization + // + mRenderBuffer.shift(-shift); +#endif +} + +#if PX_SUPPORT_PVD +PxPvdSceneClient* NpScene::getScenePvdClient() +{ + return &mScene.getScenePvdClient(); +} +#else +PxPvdSceneClient* NpScene::getScenePvdClient() +{ + return NULL; +} +#endif + +PxBatchQuery* NpScene::createBatchQuery(const PxBatchQueryDesc& desc) +{ + PX_PROFILE_ZONE("API.createBatchQuery", getContextId()); + PX_CHECK_AND_RETURN_NULL(desc.isValid(),"Supplied PxBatchQueryDesc is not valid. createBatchQuery returns NULL."); + + NpBatchQuery* bq = PX_NEW(NpBatchQuery)(*this, desc); + mBatchQueries.pushBack(bq); + return bq; +} + +void NpScene::releaseBatchQuery(PxBatchQuery* sq) +{ + PX_PROFILE_ZONE("API.releaseBatchQuery", getContextId()); + NpBatchQuery* npsq = static_cast<NpBatchQuery*>(sq); + bool found = mBatchQueries.findAndReplaceWithLast(npsq); + PX_UNUSED(found); PX_ASSERT(found); + PX_DELETE_AND_RESET(npsq); +} diff --git a/PhysX_3.4/Source/PhysX/src/NpScene.h b/PhysX_3.4/Source/PhysX/src/NpScene.h new file mode 100644 index 00000000..892e0f99 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpScene.h @@ -0,0 +1,544 @@ +// 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_NP_SCENE +#define PX_PHYSICS_NP_SCENE + +#include "foundation/PxProfiler.h" +#include "PsUserAllocated.h" +#include "PsSync.h" +#include "PsArray.h" +#include "PsThread.h" +#include "PsHashSet.h" +#include "PxPhysXConfig.h" + +#if PX_SUPPORT_GPU_PHYSX +#include "device/PhysXIndicator.h" +#endif + +#include "NpSceneQueries.h" + +namespace physx +{ + +class PhysicsThread; +class PxBatchQueryDesc; +class NpMaterial; +class NpVolumeCache; +class NpScene; + +namespace Sc +{ + class Joint; + class ConstraintBreakEvent; +} + +namespace Sq +{ + class SceneQueryManager; +} + +class NpObjectFactory; +class NpRigidStatic; +class NpRigidDynamic; +class NpParticleSystem; +class NpParticleFluid; +class NpConstraint; +class NpArticulationLink; +class NpCloth; +class NpShapeManager; +class NpBatchQuery; + +class PxBatchQuery; + +enum NpProfileZones +{ + NpScene_checkResults, + NpScene_reportContacts, + NpScene_reportProfiling, + NpScene_reportTriggers, + NpScene_stats, + + NpPrNumZones +}; + + +class NpContactCallbackTask : public physx::PxLightCpuTask +{ + NpScene* mScene; + const PxContactPairHeader* mContactPairHeaders; + uint32_t mNbContactPairHeaders; + +public: + + void setData(NpScene* scene, const PxContactPairHeader* contactPairHeaders, const uint32_t nbContactPairHeaders); + + virtual void run(); + + virtual const char* getName() const + { + return "NpContactCallbackTask"; + } +}; + +class NpScene : public NpSceneQueries, public Ps::UserAllocated +{ + //virtual interfaces: + + PX_NOCOPY(NpScene) + public: + + virtual void release(); + + virtual void setFlag(PxSceneFlag::Enum flag, bool value); + virtual PxSceneFlags getFlags() const; + + // implement PxScene: + + virtual void setGravity(const PxVec3&); + virtual PxVec3 getGravity() const; + + virtual void setBounceThresholdVelocity(const PxReal t); + virtual PxReal getBounceThresholdVelocity() const; + + virtual PxReal getFrictionOffsetThreshold() const; + + virtual void setLimits(const PxSceneLimits& limits); + virtual PxSceneLimits getLimits() const; + + virtual void addActor(PxActor& actor); + virtual void removeActor(PxActor& actor, bool wakeOnLostTouch); + + virtual PxU32 getNbConstraints() const; + virtual PxU32 getConstraints(PxConstraint** buffer, PxU32 bufferSize, PxU32 startIndex=0) const; + + virtual void addArticulation(PxArticulation&); + virtual void removeArticulation(PxArticulation&, bool wakeOnLostTouch); + virtual PxU32 getNbArticulations() const; + virtual PxU32 getArticulations(PxArticulation** userBuffer, PxU32 bufferSize, PxU32 startIndex=0) const; + +// PX_AGGREGATE + virtual void addAggregate(PxAggregate&); + virtual void removeAggregate(PxAggregate&, bool wakeOnLostTouch); + virtual PxU32 getNbAggregates() const; + virtual PxU32 getAggregates(PxAggregate** userBuffer, PxU32 bufferSize, PxU32 startIndex=0) const; +//~PX_AGGREGATE + + virtual void addCollection(const PxCollection& collection); + + // Groups + virtual void setDominanceGroupPair(PxDominanceGroup group1, PxDominanceGroup group2, const PxDominanceGroupPair& dominance); + virtual PxDominanceGroupPair getDominanceGroupPair(PxDominanceGroup group1, PxDominanceGroup group2) const; + + // Actors + virtual PxU32 getNbActors(PxActorTypeFlags types) const; + virtual PxU32 getActors(PxActorTypeFlags types, PxActor** buffer, PxU32 bufferSize, PxU32 startIndex=0) const; + virtual const PxActiveTransform* getActiveTransforms(PxU32& nbTransformsOut, PxClientID client); + virtual PxActor** getActiveActors(PxU32& nbActorsOut, PxClientID client); + + // Run + virtual void getSimulationStatistics(PxSimulationStatistics& s) const; + + // Multiclient + virtual PxClientID createClient(); + virtual void setClientBehaviorFlags(PxClientID client, PxClientBehaviorFlags clientBehaviorFlags); + virtual PxClientBehaviorFlags getClientBehaviorFlags(PxClientID client) const; + + // FrictionModel + virtual void setFrictionType(PxFrictionType::Enum frictionType); + virtual PxFrictionType::Enum getFrictionType() const; + +#if PX_USE_CLOTH_API + // Cloth + virtual void setClothInterCollisionDistance(PxF32 distance); + virtual PxF32 getClothInterCollisionDistance() const; + virtual void setClothInterCollisionStiffness(PxF32 stiffness); + virtual PxF32 getClothInterCollisionStiffness() const; + virtual void setClothInterCollisionNbIterations(PxU32 nbIterations); + virtual PxU32 getClothInterCollisionNbIterations() const; +#endif + + // Callbacks + virtual void setSimulationEventCallback(PxSimulationEventCallback* callback, PxClientID client); + virtual PxSimulationEventCallback* getSimulationEventCallback(PxClientID client) const; + virtual void setContactModifyCallback(PxContactModifyCallback* callback); + virtual PxContactModifyCallback* getContactModifyCallback() const; + virtual void setCCDContactModifyCallback(PxCCDContactModifyCallback* callback); + virtual PxCCDContactModifyCallback* getCCDContactModifyCallback() const; + virtual void setBroadPhaseCallback(PxBroadPhaseCallback* callback, PxClientID client); + virtual PxBroadPhaseCallback* getBroadPhaseCallback(PxClientID client) const; + + //CCD passes + virtual void setCCDMaxPasses(PxU32 ccdMaxPasses); + virtual PxU32 getCCDMaxPasses() const; + + // Collision filtering + virtual void setFilterShaderData(const void* data, PxU32 dataSize); + virtual const void* getFilterShaderData() const; + virtual PxU32 getFilterShaderDataSize() const; + virtual PxSimulationFilterShader getFilterShader() const; + virtual PxSimulationFilterCallback* getFilterCallback() const; + virtual void resetFiltering(PxActor& actor); + virtual void resetFiltering(PxRigidActor& actor, PxShape*const* shapes, PxU32 shapeCount); + + // Get Physics SDK + virtual PxPhysics& getPhysics(); + + // new API methods + virtual void simulate(PxReal elapsedTime, physx::PxBaseTask* completionTask, void* scratchBlock, PxU32 scratchBlockSize, bool controlSimulation); + virtual void advance(physx::PxBaseTask* completionTask); + virtual void collide(PxReal elapsedTime, physx::PxBaseTask* completionTask, void* scratchBlock, PxU32 scratchBlockSize, bool controlSimulation = true); + virtual bool checkResults(bool block); + virtual bool checkCollision(bool block); + virtual bool fetchCollision(bool block); + virtual bool fetchResults(bool block, PxU32* errorState); + virtual bool fetchResultsStart(const PxContactPairHeader*& contactPairs, PxU32& nbContactPairs, bool block = false); + virtual void processCallbacks(physx::PxBaseTask* continuation); + virtual void fetchResultsFinish(PxU32* errorState = 0); + + + + virtual void flush(bool sendPendingReports) { flushSimulation(sendPendingReports); } + virtual void flushSimulation(bool sendPendingReports); + virtual void flushQueryUpdates(); + virtual const PxRenderBuffer& getRenderBuffer(); + + virtual PxBatchQuery* createBatchQuery(const PxBatchQueryDesc& desc); + void releaseBatchQuery(PxBatchQuery* bq); + virtual PxVolumeCache* createVolumeCache(PxU32 maxStaticShapes, PxU32 maxDynamicShapes); + void releaseVolumeCache(NpVolumeCache* cache); + virtual void setDynamicTreeRebuildRateHint(PxU32 dynamicTreeRebuildRateHint); + virtual PxU32 getDynamicTreeRebuildRateHint() const; + virtual void forceDynamicTreeRebuild(bool rebuildStaticStructure, bool rebuildDynamicStructure); + + virtual void setSolverBatchSize(PxU32 solverBatchSize); + virtual PxU32 getSolverBatchSize(void) const; + + virtual bool setVisualizationParameter(PxVisualizationParameter::Enum param, PxReal value); + virtual PxReal getVisualizationParameter(PxVisualizationParameter::Enum param) const; + + virtual void setVisualizationCullingBox(const PxBounds3& box); + virtual const PxBounds3& getVisualizationCullingBox() const; + + virtual PxTaskManager* getTaskManager() { return mTaskManager; } + void checkBeginWrite() const {} + + virtual void setNbContactDataBlocks(PxU32 numBlocks); + virtual PxU32 getNbContactDataBlocksUsed() const; + virtual PxU32 getMaxNbContactDataBlocksUsed() const; + + virtual PxU32 getContactReportStreamBufferSize() const; + + virtual PxU32 getTimestamp() const; + virtual PxU32 getSceneQueryStaticTimestamp() const; + + virtual PxCpuDispatcher* getCpuDispatcher() const; + virtual PxGpuDispatcher* getGpuDispatcher() const; + + virtual PxPruningStructureType::Enum getStaticStructure() const; + virtual PxPruningStructureType::Enum getDynamicStructure() const; + + virtual PxBroadPhaseType::Enum getBroadPhaseType() const; + virtual bool getBroadPhaseCaps(PxBroadPhaseCaps& caps) const; + virtual PxU32 getNbBroadPhaseRegions() const; + virtual PxU32 getBroadPhaseRegions(PxBroadPhaseRegionInfo* userBuffer, PxU32 bufferSize, PxU32 startIndex=0) const; + virtual PxU32 addBroadPhaseRegion(const PxBroadPhaseRegion& region, bool populateRegion); + virtual bool removeBroadPhaseRegion(PxU32 handle); + + virtual void addActors(PxActor*const* actors, PxU32 nbActors); + virtual void addActors(const PxPruningStructure& prunerStructure); + virtual void removeActors(PxActor*const* actors, PxU32 nbActors, bool wakeOnLostTouch); + + virtual void lockRead(const char* file=NULL, PxU32 line=0); + virtual void unlockRead(); + + virtual void lockWrite(const char* file=NULL, PxU32 line=0); + virtual void unlockWrite(); + + virtual PxReal getWakeCounterResetValue() const; + + virtual void shiftOrigin(const PxVec3& shift); + + virtual PxPvdSceneClient* getScenePvdClient(); + + //internal public methods: + public: + NpScene(const PxSceneDesc& desc); + ~NpScene(); + + PX_FORCE_INLINE PxTaskManager* getTaskManager() const { return mTaskManager; } + + PX_FORCE_INLINE Sc::SimulationStage::Enum getSimulationStage() const { return mScene.getSimulationStage(); } + PX_FORCE_INLINE void setSimulationStage(Sc::SimulationStage::Enum stage) { mScene.setSimulationStage(stage); } + + void addActorInternal(PxActor& actor); + void removeActorInternal(PxActor& actor, bool wakeOnLostTouch, bool removeFromAggregate); + void addActorsInternal(PxActor*const* PX_RESTRICT actors, PxU32 nbActors, const Sq::PruningStructure* ps = NULL); + + void addArticulationInternal(PxArticulation&); + void removeArticulationInternal(PxArticulation&, bool wakeOnLostTouch, bool removeFromAggregate); + // materials + void addMaterial(const NpMaterial& mat); + void updateMaterial(const NpMaterial& mat); + void removeMaterial(const NpMaterial& mat); + + void executeScene(PxBaseTask* continuation); + void executeCollide(PxBaseTask* continuation); + void executeAdvance(PxBaseTask* continuation); + void constraintBreakEventNotify(PxConstraint *const *constraints, PxU32 count); + + bool loadFromDesc(const PxSceneDesc&); + + void removeFromRigidActorList(const PxU32&); + PX_FORCE_INLINE void removeFromArticulationList(PxArticulation&); + PX_FORCE_INLINE void removeFromAggregateList(PxAggregate&); + + PX_FORCE_INLINE void addToConstraintList(PxConstraint&); + PX_FORCE_INLINE void removeFromConstraintList(PxConstraint&); + +#if PX_USE_PARTICLE_SYSTEM_API + PX_FORCE_INLINE void removeFromParticleBaseList(PxParticleBase&); +#endif + + void addArticulationLink(NpArticulationLink& link); + void addArticulationLinkBody(NpArticulationLink& link); + void addArticulationLinkConstraint(NpArticulationLink& link); + void removeArticulationLink(NpArticulationLink& link, bool wakeOnLostTouch); + + struct StartWriteResult + { + enum Enum { eOK, eNO_LOCK, eIN_FETCHRESULTS, eRACE_DETECTED }; + }; + + StartWriteResult::Enum startWrite(bool allowReentry); + void stopWrite(bool allowReentry); + + bool startRead() const; + void stopRead() const; + + PxU32 getReadWriteErrorCount() const { return PxU32(mConcurrentErrorCount); } + +#if PX_CHECKED + void checkPositionSanity(const PxRigidActor& a, const PxTransform& pose, const char* fnName) const; +#endif + +#if PX_USE_CLOTH_API + void addCloth(NpCloth&); + void removeCloth(NpCloth&); +#endif + +#if PX_SUPPORT_GPU_PHYSX + void updatePhysXIndicator(); +#else + PX_FORCE_INLINE void updatePhysXIndicator() {} +#endif + + PX_FORCE_INLINE PxReal getWakeCounterResetValueInteral() const { return mScene.getWakeCounterResetValue(); } + +private: + bool checkResultsInternal(bool block); + bool checkCollisionInternal(bool block); + void simulateOrCollide(PxReal elapsedTime, physx::PxBaseTask* completionTask, void* scratchBlock, PxU32 scratchBlockSize, bool controlSimulation, const char* invalidCallMsg, Sc::SimulationStage::Enum simStage); + + void addRigidStatic(NpRigidStatic& , bool hasPrunerStructure = false); + void removeRigidStatic(NpRigidStatic&, bool wakeOnLostTouch, bool removeFromAggregate); + void addRigidDynamic(NpRigidDynamic& , bool hasPrunerStructure = false); + void removeRigidDynamic(NpRigidDynamic&, bool wakeOnLostTouch, bool removeFromAggregate); + + bool addRigidActorsInternal(PxU32 nbActors, PxActor** PX_RESTRICT actors); + +#if PX_USE_PARTICLE_SYSTEM_API + void addParticleSystem(NpParticleSystem&); + void removeParticleSystem(NpParticleSystem&); + void addParticleFluid(NpParticleFluid&); + void removeParticleFluid(NpParticleFluid&); +#endif + +#if PX_USE_CLOTH_API + PX_FORCE_INLINE void removeFromClothList(PxCloth&); +#endif + + void visualize(); + + void updateDirtyShaders(); + + void fireOutOfBoundsCallbacks(); + void fetchResultsPreContactCallbacks(); + void fetchResultsPostContactCallbacks(); + + + + void updateScbStateAndSetupSq(const PxRigidActor& rigidActor, Scb::Actor& actor, NpShapeManager& shapeManager, bool actorDynamic, const PxBounds3* bounds, bool hasPrunerStructure); + PX_FORCE_INLINE void updateScbStateAndSetupSq(const PxRigidActor& rigidActor, Scb::Body& body, NpShapeManager& shapeManager, bool actorDynamic, const PxBounds3* bounds, bool hasPrunerStructure); + + Cm::RenderBuffer mRenderBuffer; + + Ps::CoalescedHashSet<PxConstraint*> mConstraints; + Ps::Array<PxRigidActor*> mRigidActors; // no hash set used because it would be quite a bit slower when adding a large number of actors + Ps::CoalescedHashSet<PxArticulation*> mArticulations; + Ps::CoalescedHashSet<PxAggregate*> mAggregates; + Ps::HashSet<NpVolumeCache*> mVolumeCaches; + Ps::Array<NpBatchQuery*> mBatchQueries; + +#if PX_USE_PARTICLE_SYSTEM_API + Ps::CoalescedHashSet<PxParticleBase*> mPxParticleBaseSet; +#endif + +#if PX_USE_CLOTH_API + Ps::CoalescedHashSet<PxCloth*> mPxCloths; +#endif + + PxBounds3 mSanityBounds; +#if PX_SUPPORT_GPU_PHYSX + PhysXIndicator mPhysXIndicator; +#endif + + Ps::Sync mPhysicsDone; // physics thread signals this when update ready + Ps::Sync mCollisionDone; // physics thread signals this when all collisions ready + + + //legacy timing settings: + PxReal mElapsedTime; //needed to transfer the elapsed time param from the user to the sim thread. + + PxU32 mNbClients; // Tracks reserved clients for multiclient support. + Ps::Array<PxU32> mClientBehaviorFlags;// Tracks behavior bits for clients. + + + struct SceneCompletion : public Cm::Task + { + SceneCompletion(Ps::Sync& sync) : mSync(sync){} + virtual void runInternal() {} + //ML: As soon as mSync.set is called, and the scene is shutting down, + //the scene may be deleted. That means this running task may also be deleted. + //As such, we call mSync.set() inside release() to avoid a crash because the v-table on this + //task might be deleted between the call to runInternal() and release() in the worker thread. + virtual void release() + { + //We cache the continuation pointer because this class may be deleted + //as soon as mSync.set() is called if the application releases the scene. + PxBaseTask* c = mCont; + //once mSync.set(), fetchResults() will be allowed to run. + mSync.set(); + //Call the continuation task that we cached above. If we use mCont or + //any other member variable of this class, there is a small chance + //that the variables might have become corrupted if the class + //was deleted. + if(c) c->removeReference(); + } + virtual const char* getName() const { return "NpScene.completion"; } + + // //This method just is called in the split sim approach as a way to set continuation after the task has been initialized + void setDependent(PxBaseTask* task){PX_ASSERT(mCont == NULL); mCont = task; if(task)task->addReference();} + Ps::Sync& mSync; + private: + SceneCompletion& operator=(const SceneCompletion&); + }; + + typedef Cm::DelegateTask<NpScene, &NpScene::executeScene> SceneExecution; + typedef Cm::DelegateTask<NpScene, &NpScene::executeCollide> SceneCollide; + typedef Cm::DelegateTask<NpScene, &NpScene::executeAdvance> SceneAdvance; + + + PxTaskManager* mTaskManager; + SceneCompletion mSceneCompletion; + SceneCompletion mCollisionCompletion; + SceneExecution mSceneExecution; + SceneCollide mSceneCollide; + SceneAdvance mSceneAdvance; + bool mControllingSimulation; + + PxU32 mSimThreadStackSize; + + volatile PxI32 mConcurrentWriteCount; + mutable volatile PxI32 mConcurrentReadCount; + mutable volatile PxI32 mConcurrentErrorCount; + + // TLS slot index, keeps track of re-entry depth for this thread + PxU32 mThreadReadWriteDepth; + Ps::Thread::Id mCurrentWriter; + Ps::ReadWriteLock mRWLock; + + bool mHasSimulatedOnce; + bool mBetweenFetchResults; +}; + + +PX_FORCE_INLINE void NpScene::addToConstraintList(PxConstraint& constraint) +{ + mConstraints.insert(&constraint); +} + + +PX_FORCE_INLINE void NpScene::removeFromConstraintList(PxConstraint& constraint) +{ + const bool exists = mConstraints.erase(&constraint); + PX_ASSERT(exists); + PX_UNUSED(exists); +} + + +PX_FORCE_INLINE void NpScene::removeFromArticulationList(PxArticulation& articulation) +{ + const bool exists = mArticulations.erase(&articulation); + PX_ASSERT(exists); + PX_UNUSED(exists); +} + + +PX_FORCE_INLINE void NpScene::removeFromAggregateList(PxAggregate& aggregate) +{ + const bool exists = mAggregates.erase(&aggregate); + PX_ASSERT(exists); + PX_UNUSED(exists); +} + + +#if PX_USE_PARTICLE_SYSTEM_API +PX_FORCE_INLINE void NpScene::removeFromParticleBaseList(PxParticleBase& p) +{ + const bool exists = mPxParticleBaseSet.erase(&p); + PX_ASSERT(exists); + PX_UNUSED(exists); +} +#endif + + +#if PX_USE_CLOTH_API +PX_FORCE_INLINE void NpScene::removeFromClothList(PxCloth& cloth) +{ + const bool exists = mPxCloths.erase(&cloth); + PX_ASSERT(exists); + PX_UNUSED(exists); +} +#endif // PX_USE_CLOTH_API + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/NpSceneQueries.cpp b/PhysX_3.4/Source/PhysX/src/NpSceneQueries.cpp new file mode 100644 index 00000000..afadf740 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpSceneQueries.cpp @@ -0,0 +1,836 @@ +// 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 "GuIntersectionRayBox.h" +#include "PxGeometryQuery.h" +#include "NpRigidDynamic.h" +#include "NpQueryShared.h" +#include "SqPruner.h" +#include "GuBounds.h" +#include "GuIntersectionRay.h" + +// Synchronous scene queries + +using namespace physx; +using namespace Sq; +using namespace Gu; + +#if PX_SUPPORT_PVD +#include "NpPvdSceneQueryCollector.h" +#endif + +namespace local +{ + // helper class to encapsulate Scb::Actor and Shape together with PxActorShape + struct ActorShape : PxActorShape + { + const Scb::Shape* scbShape; + const Scb::Actor* scbActor; + + ActorShape() : PxActorShape() {} + + ActorShape(PxRigidActor* eaActor, PxShape* eaShape, Scb::Shape* sShape, Scb::Actor* sActor) : PxActorShape(eaActor, eaShape) + { + scbShape = sShape; + scbActor = sActor; + } + }; + + // fill the helper actor shape + static PX_FORCE_INLINE void populate(const PrunerPayload& payload, ActorShape& as) + { + Scb::Shape* localShape = reinterpret_cast<Scb::Shape*>(payload.data[0]); + Scb::Actor* localActor = reinterpret_cast<Scb::Actor*>(payload.data[1]); + + as.scbShape = localShape; + as.scbActor = localActor; + + as.actor = static_cast<PxRigidActor*>(static_cast<const Sc::RigidCore&>(localActor->getActorCore()).getPxActor()); + as.shape = localShape->getScShape().getPxShape(); + } +} + +/////////////////////////////////////////////////////////////////////////////// +bool NpSceneQueries::raycast( + const PxVec3& origin, const PxVec3& unitDir, const PxReal distance, + PxHitCallback<PxRaycastHit>& hits, PxHitFlags hitFlags, const PxQueryFilterData& filterData, PxQueryFilterCallback* filterCall, + const PxQueryCache* cache) const +{ + PX_PROFILE_ZONE("SceneQuery.raycast", getContextId()); + NP_READ_CHECK(this); + PX_SIMD_GUARD; + + MultiQueryInput input(origin, unitDir, distance); + return multiQuery<PxRaycastHit>(input, hits, hitFlags, cache, filterData, filterCall, NULL); +} + +////////////////////////////////////////////////////////////////////////// +bool NpSceneQueries::overlap( + const PxGeometry& geometry, const PxTransform& pose, PxOverlapCallback& hits, + const PxQueryFilterData& filterData, PxQueryFilterCallback* filterCall) const +{ + PX_PROFILE_ZONE("SceneQuery.overlap", getContextId()); + NP_READ_CHECK(this); + PX_SIMD_GUARD; + + MultiQueryInput input(&geometry, &pose); + // we are not supporting cache for overlaps for some reason + return multiQuery<PxOverlapHit>(input, hits, PxHitFlags(), NULL, filterData, filterCall, NULL); +} + +/////////////////////////////////////////////////////////////////////////////// +bool NpSceneQueries::sweep( + const PxGeometry& geometry, const PxTransform& pose, const PxVec3& unitDir, const PxReal distance, + PxHitCallback<PxSweepHit>& hits, PxHitFlags hitFlags, const PxQueryFilterData& filterData, PxQueryFilterCallback* filterCall, + const PxQueryCache* cache, const PxReal inflation) const +{ + PX_PROFILE_ZONE("SceneQuery.sweep", getContextId()); + NP_READ_CHECK(this); + PX_SIMD_GUARD; + +#if PX_CHECKED + if(!PxGeometryQuery::isValid(geometry)) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "Provided geometry is not valid"); + return false; + } +#endif // PX_CHECKED + + + if((hitFlags & PxHitFlag::ePRECISE_SWEEP) && (hitFlags & PxHitFlag::eMTD)) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, " Precise sweep doesn't support MTD. Perform MTD with default sweep"); + hitFlags &= ~PxHitFlag::ePRECISE_SWEEP; + } + + if((hitFlags & PxHitFlag::eASSUME_NO_INITIAL_OVERLAP) && (hitFlags & PxHitFlag::eMTD)) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, " eMTD cannot be used in conjunction with eASSUME_NO_INITIAL_OVERLAP. eASSUME_NO_INITIAL_OVERLAP will be ignored"); + hitFlags &= ~PxHitFlag::eASSUME_NO_INITIAL_OVERLAP; + } + + PxReal realInflation = inflation; + if((hitFlags & PxHitFlag::ePRECISE_SWEEP)&& inflation > 0.f) + { + realInflation = 0.f; + Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, " Precise sweep doesn't support inflation, inflation will be overwritten to be zero"); + } + MultiQueryInput input(&geometry, &pose, unitDir, distance, realInflation); + return multiQuery<PxSweepHit>(input, hits, hitFlags, cache, filterData, filterCall, NULL); +} + +/////////////////////////////////////////////////////////////////////////////// +//======================================================================================================================== + +static PX_FORCE_INLINE bool applyAllPreFiltersSQ( + const local::ActorShape* as, PxQueryHitType::Enum& hitType, const PxQueryFlags& inFilterFlags, + const PxQueryFilterData& filterData, PxQueryFilterCallback* filterCall, + const NpSceneQueries& scene, BatchQueryFilterData* bfd, PxHitFlags& queryFlags, PxU32 /*maxNbTouches*/) +{ + if(!applyClientFilter(as->scbActor, filterData, scene)) + return false; + + // AP: the !bfd clause is here because there's no other way to pass data to BQ pre/post filter shaders + // For normal query the data can be passed with inherited callback instance + // So if for BQ SPU filter shader the user tries to pass data via FD, the equation will always cut it out + // AP scaffold TODO: once SPU is officially phased out we can remove the !bfd clause, fix broken UTs (that are wrong) + // and also remove support for filter shaders + if(!bfd && !applyFilterEquation(*as->scbShape, filterData.data)) + return false; + + if((inFilterFlags & PxQueryFlag::ePREFILTER) && (filterCall || bfd)) + { + PxHitFlags outQueryFlags = queryFlags; + + if(filterCall) + hitType = filterCall->preFilter(filterData.data, as->shape, as->actor, outQueryFlags); + else if(bfd->preFilterShader) + hitType = bfd->preFilterShader( + filterData.data, as->scbShape->getScShape().getQueryFilterData(), + bfd->filterShaderData, bfd->filterShaderDataSize, outQueryFlags); + + // AP: at this point the callback might return eTOUCH but the touch buffer can be empty, the hit will be discarded + //PX_CHECK_MSG(hitType == PxQueryHitType::eTOUCH ? maxNbTouches > 0 : true, + // "SceneQuery: preFilter returned eTOUCH but empty touch buffer was provided, hit discarded."); + + queryFlags = (queryFlags & ~PxHitFlag::eMODIFIABLE_FLAGS) | (outQueryFlags & PxHitFlag::eMODIFIABLE_FLAGS); + } + // test passed, continue to return as; + return true; +} + +//======================================================================================================================== +// performs a single geometry query for any HitType (PxSweepHit, PxOverlapHit, PxRaycastHit) +template<typename HitType> +struct GeomQueryAny +{ + static PX_FORCE_INLINE PxU32 geomHit( + const NpSceneQueries& sceneQueries, const MultiQueryInput& input, const ShapeData& sd, + const PxGeometry& sceneGeom, const PxTransform& pose, PxHitFlags hitFlags, + PxU32 maxHits, HitType* hits, const PxReal shrunkMaxDistance, PxBounds3* precomputedBounds) + { + const PxGeometry& geom0 = *input.geometry; + const PxTransform& pose0 = *input.pose; + const PxGeometry& geom1 = sceneGeom; + const PxTransform& pose1 = pose; + + // Handle raycasts + if(HitTypeSupport<HitType>::IsRaycast) + { + // the test for mesh AABB is archived in //sw/physx/dev/apokrovsky/graveyard/sqMeshAABBTest.cpp + // TODO: investigate performance impact (see US12801) + PX_CHECK_AND_RETURN_VAL(input.getDir().isFinite(), "PxScene::raycast(): rayDir is not valid.", 0); + PX_CHECK_AND_RETURN_VAL(input.getOrigin().isFinite(), "PxScene::raycast(): rayOrigin is not valid.", 0); + PX_CHECK_AND_RETURN_VAL(pose1.isValid(), "PxScene::raycast(): pose is not valid.", 0); + PX_CHECK_AND_RETURN_VAL(shrunkMaxDistance >= 0.0f, "PxScene::raycast(): maxDist is negative.", 0); + PX_CHECK_AND_RETURN_VAL(PxIsFinite(shrunkMaxDistance), "PxScene::raycast(): maxDist is not valid.", 0); + PX_CHECK_AND_RETURN_VAL(PxAbs(input.getDir().magnitudeSquared()-1)<1e-4f, + "PxScene::raycast(): ray direction must be unit vector.", 0); + + // PT: TODO: investigate perf difference + const RaycastFunc func = sceneQueries.mCachedRaycastFuncs[geom1.getType()]; + return func(geom1, pose1, input.getOrigin(), input.getDir(), shrunkMaxDistance, + hitFlags, maxHits, reinterpret_cast<PxRaycastHit*>(hits)); + } + // Handle sweeps + else if(HitTypeSupport<HitType>::IsSweep) + { + PX_ASSERT(precomputedBounds != NULL); + // b0 = query shape bounds + // b1 = scene shape bounds + // AP: Here we clip the sweep to bounds with sum of extents. This is needed for GJK stability. + // because sweep is equivalent to a raycast vs a scene shape with inflated bounds. + // This also may (or may not) provide an optimization for meshes because top level of rtree has multiple boxes + // and there is no bounds test for the whole mesh elsewhere + PxBounds3 b0 = *precomputedBounds, b1; + // compute the scene geometry bounds + Gu::computeBounds(b1, sceneGeom, pose, 0.0f, NULL, 1.0f, false); + const PxVec3 combExt = (b0.getExtents() + b1.getExtents())*1.01f; + + PxF32 tnear, tfar; + if(!intersectRayAABB2(-combExt, combExt, b0.getCenter() - b1.getCenter(), input.getDir(), shrunkMaxDistance, tnear, tfar)) // returns (tnear<tfar) + if(tnear>tfar) // this second test is needed because shrunkMaxDistance can be 0 for 0 length sweep + return 0; + PX_ASSERT(input.getDir().isNormalized()); + // tfar is now the t where the ray exits the AABB. input.getDir() is normalized + + const PxVec3& unitDir = input.getDir(); + PxSweepHit& sweepHit = reinterpret_cast<PxSweepHit&>(hits[0]); + + // if we don't start inside the AABB box, offset the start pos, because of precision issues with large maxDist + const bool offsetPos = (tnear > GU_RAY_SURFACE_OFFSET); + const PxReal offset = offsetPos ? (tnear - GU_RAY_SURFACE_OFFSET) : 0.0f; + const PxVec3 offsetVec(offsetPos ? (unitDir*offset) : PxVec3(0.0f)); + // we move the geometry we sweep against, so that we avoid the Gu::Capsule/Box recomputation + const PxTransform pose1Offset(pose1.p - offsetVec, pose1.q); + + const PxReal distance = PxMin(tfar, shrunkMaxDistance) - offset; + const PxReal inflation = input.inflation; + PX_CHECK_AND_RETURN_VAL(pose0.isValid(), "PxScene::sweep(): pose0 is not valid.", 0); + PX_CHECK_AND_RETURN_VAL(pose1Offset.isValid(), "PxScene::sweep(): pose1 is not valid.", 0); + PX_CHECK_AND_RETURN_VAL(unitDir.isFinite(), "PxScene::sweep(): unitDir is not valid.", 0); + PX_CHECK_AND_RETURN_VAL(PxIsFinite(distance), "PxScene::sweep(): distance is not valid.", 0); + PX_CHECK_AND_RETURN_VAL((distance >= 0.0f && !(hitFlags & PxHitFlag::eASSUME_NO_INITIAL_OVERLAP)) || distance > 0.0f, + "PxScene::sweep(): sweep distance must be >=0 or >0 with eASSUME_NO_INITIAL_OVERLAP.", 0); + + PxU32 retVal = 0; + const GeomSweepFuncs& sf = sceneQueries.mCachedSweepFuncs; + switch(geom0.getType()) + { + case PxGeometryType::eSPHERE: + { + const PxSphereGeometry& sphereGeom = static_cast<const PxSphereGeometry&>(geom0); + // PT: TODO: technically this capsule with 0.0 half-height is invalid ("isValid" returns false) + const PxCapsuleGeometry capsuleGeom(sphereGeom.radius, 0.0f); + const Capsule worldCapsule(pose0.p, pose0.p, sphereGeom.radius); // AP: precompute? + const bool precise = hitFlags & PxHitFlag::ePRECISE_SWEEP; + const SweepCapsuleFunc func = precise ? sf.preciseCapsuleMap[geom1.getType()] : sf.capsuleMap[geom1.getType()]; + retVal = PxU32(func(geom1, pose1Offset, capsuleGeom, pose0, worldCapsule, unitDir, distance, sweepHit, hitFlags, inflation)); + } + break; + + case PxGeometryType::eCAPSULE: + { + const bool precise = hitFlags & PxHitFlag::ePRECISE_SWEEP; + const SweepCapsuleFunc func = precise ? sf.preciseCapsuleMap[geom1.getType()] : sf.capsuleMap[geom1.getType()]; + retVal = PxU32(func(geom1, pose1Offset, static_cast<const PxCapsuleGeometry&>(geom0), pose0, sd.getGuCapsule(), unitDir, distance, sweepHit, hitFlags, inflation)); + } + break; + + case PxGeometryType::eBOX: + { + const bool precise = hitFlags & PxHitFlag::ePRECISE_SWEEP; + const SweepBoxFunc func = precise ? sf.preciseBoxMap[geom1.getType()] : sf.boxMap[geom1.getType()]; + retVal = PxU32(func(geom1, pose1Offset, static_cast<const PxBoxGeometry&>(geom0), pose0, sd.getGuBox(), unitDir, distance, sweepHit, hitFlags, inflation)); + } + break; + + case PxGeometryType::eCONVEXMESH: + { + const PxConvexMeshGeometry& convexGeom = static_cast<const PxConvexMeshGeometry&>(geom0); + const SweepConvexFunc func = sf.convexMap[geom1.getType()]; + retVal = PxU32(func(geom1, pose1Offset, convexGeom, pose0, unitDir, distance, sweepHit, hitFlags, inflation)); + } + break; + case PxGeometryType::ePLANE: + case PxGeometryType::eTRIANGLEMESH: + case PxGeometryType::eHEIGHTFIELD: + case PxGeometryType::eGEOMETRY_COUNT: + case PxGeometryType::eINVALID: + physx::shdfnd::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, + "PxScene::sweep(): first geometry object parameter must be sphere, capsule, box or convex geometry."); + break; + } + if (retVal) + { + // we need to offset the distance back + sweepHit.distance += offset; + // we need to offset the hit position back as we moved the geometry we sweep against + sweepHit.position += offsetVec; + } + return retVal; + } + // Handle overlaps + else if(HitTypeSupport<HitType>::IsOverlap) + { + const GeomOverlapTable* overlapFuncs = sceneQueries.mCachedOverlapFuncs; + return PxU32(Gu::overlap(geom0, pose0, geom1, pose1, overlapFuncs)); + } + else + { + PX_ALWAYS_ASSERT_MESSAGE("Unexpected template expansion in GeomQueryAny::geomHit"); + return 0; + } + } +}; + +// struct to access protected data members in the public PxHitCallback API +template<typename HitType> +struct MultiQueryCallback : public PrunerCallback +{ + const NpSceneQueries& mScene; + const MultiQueryInput& mInput; + PxHitCallback<HitType>& mHitCall; + const PxHitFlags mHitFlags; + const PxQueryFilterData& mFilterData; + PxQueryFilterCallback* mFilterCall; + PxReal mShrunkDistance; + BatchQueryFilterData* mBfd; // only not NULL for batch queries + const PxHitFlags mMeshAnyHitFlags; + bool mReportTouchesAgain; + bool mFarBlockFound; // this is to prevent repeated searches for far block + bool mNoBlock; + const bool mAnyHit; + bool mIsCached; // is this call coming as a callback from the pruner or a single item cached callback? + + // The reason we need these bounds is because we need to know combined(inflated shape) bounds to clip the sweep path + // to be tolerable by GJK precision issues. This test is done for (queryShape vs touchedShapes) + // So it makes sense to cache the bounds for sweep query shape, otherwise we'd have to recompute them every time + // Currently only used for sweeps. + PxBounds3 mQueryShapeBounds; + bool mQueryShapeBoundsValid; + const ShapeData* mShapeData; + + MultiQueryCallback( + const NpSceneQueries& scene, const MultiQueryInput& input, bool anyHit, PxHitCallback<HitType>& hitCall, PxHitFlags hitFlags, + const PxQueryFilterData& filterData, PxQueryFilterCallback* filterCall, PxReal shrunkDistance, BatchQueryFilterData* aBfd) : + mScene (scene), + mInput (input), + mHitCall (hitCall), + mHitFlags (hitFlags), + mFilterData (filterData), + mFilterCall (filterCall), + mShrunkDistance (shrunkDistance), + mBfd (aBfd), + mMeshAnyHitFlags ((hitFlags.isSet(PxHitFlag::eMESH_ANY) || anyHit) ? PxHitFlag::eMESH_ANY : PxHitFlag::eDISTANCE), + mReportTouchesAgain (true), + mFarBlockFound (filterData.flags & PxQueryFlag::eNO_BLOCK), + mNoBlock (filterData.flags & PxQueryFlag::eNO_BLOCK), + mAnyHit (anyHit), + mIsCached (false), + mQueryShapeBoundsValid (false), + mShapeData (NULL) + { + } + + virtual PxAgain invoke(PxReal& aDist, const PrunerPayload& aPayload) + { + const PxU32 tempCount = 1; + HitType tempBuf[tempCount]; + + // PT: TODO: do we need actorShape.actor/actorShape.shape immediately? + local::ActorShape actorShape; + local::populate(aPayload, actorShape); + + const PxQueryFlags filterFlags = mFilterData.flags; + + // for no filter callback, default to eTOUCH for MULTIPLE, eBLOCK otherwise + // also always treat as eBLOCK if currently tested shape is cached + // Using eRESERVED flag as a special condition to default to eTOUCH hits while only looking for a single blocking hit + // from a nested query (see other comments containing #LABEL1) + PxQueryHitType::Enum shapeHitType = + ((mHitCall.maxNbTouches || (mFilterData.flags & PxQueryFlag::eRESERVED)) && !mIsCached) + ? PxQueryHitType::eTOUCH + : PxQueryHitType::eBLOCK; + + // apply pre-filter + PxHitFlags filteredHitFlags = mHitFlags; + if(!mIsCached) // don't run filters on single item cache + if(!applyAllPreFiltersSQ(&actorShape, shapeHitType/*in&out*/, filterFlags, mFilterData, mFilterCall, + mScene, mBfd, filteredHitFlags, mHitCall.maxNbTouches)) + return true; // skip this shape from reporting if prefilter said to do so + if(shapeHitType == PxQueryHitType::eNONE) + return true; + + PX_ASSERT(actorShape.actor && actorShape.shape); + const Scb::Shape* shape = actorShape.scbShape; + const Scb::Actor* actor = actorShape.scbActor; + + // compute the global pose for the cached shape and actor + PX_ALIGN(16, PxTransform) globalPose; + NpActor::getGlobalPose(globalPose, *shape, *actor); + + const PxGeometry& shapeGeom = shape->getGeometry(); + + // Here we decide whether to use the user provided buffer in place or a local stack buffer + // see if we have more room left in the callback results buffer than in the parent stack buffer + // if so get subHits in-place in the hit buffer instead of the parent stack buffer + // nbTouches is the number of accumulated touch hits so far + // maxNbTouches is the size of the user buffer + PxU32 maxSubHits1 = mHitCall.maxNbTouches - mHitCall.nbTouches; // how much room is left in the user buffer + HitType* subHits1 = mHitCall.touches + mHitCall.nbTouches; // pointer to the first free hit in the user buffer + if(mHitCall.nbTouches >= mHitCall.maxNbTouches) + // if there's no room left in the user buffer, use a stack buffer + { + // tried using 64 here - causes check stack code to get generated on xbox, perhaps because of guard page + // need this buffer in case the input buffer is full but we still want to correctly merge results from later hits + maxSubHits1 = tempCount; + subHits1 = reinterpret_cast<HitType*>(tempBuf); + } + + // limit number of hits to 1 for meshes if eMESH_MULTIPLE wasn't specified. this tells geomQuery to only look for a closest hit + if(shapeGeom.getType() == PxGeometryType::eTRIANGLEMESH && !(filteredHitFlags & PxHitFlag::eMESH_MULTIPLE)) + maxSubHits1 = 1; // required to only receive 1 hit to pass UTs + // call the geometry specific intersection template + PxU32 nbSubHits = GeomQueryAny<HitType>::geomHit( + mScene, mInput, *mShapeData, shapeGeom, globalPose, + filteredHitFlags | mMeshAnyHitFlags, + maxSubHits1, subHits1, mShrunkDistance, mQueryShapeBoundsValid ? &mQueryShapeBounds : NULL); + + // ------------------------- iterate over geometry subhits ----------------------------------- + for (PxU32 iSubHit = 0; iSubHit < nbSubHits; iSubHit++) + { + HitType& hit = subHits1[iSubHit]; + hit.actor = actorShape.actor; + hit.shape = actorShape.shape; + + // some additional processing only for sweep hits with initial overlap + if(HitTypeSupport<HitType>::IsSweep && HITDIST(hit) == 0.0f && !(filteredHitFlags & PxHitFlag::eMTD)) + // PT: necessary as some leaf routines are called with reversed params, thus writing +unitDir there. + // AP: apparently still necessary to also do in Gu because Gu can be used standalone (without SQ) + reinterpret_cast<PxSweepHit&>(hit).normal = -mInput.getDir(); + + // start out with hitType for this cached shape set to a pre-filtered hit type + PxQueryHitType::Enum hitType = shapeHitType; + + // run the post-filter if specified in filterFlags and filterCall is non-NULL + if(!mIsCached && (mFilterCall || mBfd) && (filterFlags & PxQueryFlag::ePOSTFILTER)) + { + if(mFilterCall) + hitType = mFilterCall->postFilter(mFilterData.data, hit); + else if(mBfd->postFilterShader) + hitType = mBfd->postFilterShader( + mFilterData.data, actorShape.scbShape->getScShape().getQueryFilterData(), + mBfd->filterShaderData, mBfd->filterShaderDataSize, hit); + } + + // early out on any hit if eANY_HIT was specified, regardless of hit type + if(mAnyHit && hitType != PxQueryHitType::eNONE) + { + // block or touch qualifies for qType=ANY type hit => return it as blocking according to spec. Ignore eNONE. + mHitCall.block = hit; + mHitCall.hasBlock = true; + return false; // found a hit for ANY qType, can early exit now + } + + if(mNoBlock) + hitType = PxQueryHitType::eTOUCH; + + PX_WARN_ONCE_IF(HitTypeSupport<HitType>::IsOverlap && hitType == PxQueryHitType::eBLOCK, + "eBLOCK returned from user filter for overlap() query. This may cause undesired behavior. " + "Consider using PxQueryFlag::eNO_BLOCK for overlap queries."); + + if(hitType == PxQueryHitType::eTOUCH) + { + // -------------------------- handle eTOUCH hits --------------------------------- + // for qType=multiple, store the hit. For other qTypes ignore it. + // <= is important for initially overlapping sweeps + #if PX_CHECKED + if(mHitCall.maxNbTouches == 0 && !mBfd && !mFilterData.flags.isSet(PxQueryFlag::eRESERVED)) + // issue a warning if eTOUCH was returned by the prefilter, we have 0 touch buffer and not a batch query + // not doing for BQ because the touches buffer can be overflown and thats ok by spec + // eRESERVED to avoid a warning from nested callback (closest blocking hit recursive search) + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, + "User filter returned PxQueryHitType::eTOUCH but the touches buffer was empty. Hit was discarded."); + #endif + + if(mHitCall.maxNbTouches && mReportTouchesAgain && HITDIST(hit) <= mShrunkDistance) + { + // Buffer full: need to find the closest blocking hit, clip touch hits and flush the buffer + if(mHitCall.nbTouches == mHitCall.maxNbTouches) + { + // issue a second nested query just looking for the closest blocking hit + // could do better perf-wise by saving traversal state (start looking for blocking from this point) + // but this is not a perf critical case because users can provide a bigger buffer + // that covers non-degenerate cases + // far block search doesn't apply to overlaps because overlaps don't work with blocking hits + if(HitTypeSupport<HitType>::IsOverlap == 0) + { + // AP: the use of eRESERVED is a bit tricky, see other comments containing #LABEL1 + PxQueryFilterData fd1 = mFilterData; fd1.flags |= PxQueryFlag::eRESERVED; + PxHitBuffer<HitType> buf1; // create a temp callback buffer for a single blocking hit + if(!mFarBlockFound && mHitCall.maxNbTouches > 0 && mScene.NpSceneQueries::multiQuery<HitType>( + mInput, buf1, mHitFlags, NULL, fd1, mFilterCall, mBfd)) + { + mHitCall.block = buf1.block; + mHitCall.hasBlock = true; + mHitCall.nbTouches = + clipHitsToNewMaxDist<HitType>(mHitCall.touches, mHitCall.nbTouches, HITDIST(buf1.block)); + mShrunkDistance = HITDIST(buf1.block); + aDist = mShrunkDistance; + } + mFarBlockFound = true; + } + if(mHitCall.nbTouches == mHitCall.maxNbTouches) + { + mReportTouchesAgain = mHitCall.processTouches(mHitCall.touches, mHitCall.nbTouches); + if(!mReportTouchesAgain) + return false; // optimization - buffer is full + else + mHitCall.nbTouches = 0; // reset nbTouches so we can continue accumulating again + } + } + + //if(hitCall.nbTouches < hitCall.maxNbTouches) // can be true if maxNbTouches is 0 + mHitCall.touches[mHitCall.nbTouches++] = hit; + } // if(hitCall.maxNbTouches && reportTouchesAgain && HITDIST(hit) <= shrunkDistance) + } // if(hitType == PxQueryHitType::eTOUCH) + else if(hitType == PxQueryHitType::eBLOCK) + { + // -------------------------- handle eBLOCK hits ---------------------------------- + // only eBLOCK qualifies as a closest hit candidate => compare against best distance and store + // <= is needed for eTOUCH hits to be recorded correctly vs same eBLOCK distance for overlaps + if(HITDIST(hit) <= mShrunkDistance) + { + if(HitTypeSupport<HitType>::IsOverlap == 0) + { + mShrunkDistance = HITDIST(hit); + aDist = mShrunkDistance; + } + mHitCall.block = hit; + mHitCall.hasBlock = true; + } + } // if(hitType == eBLOCK) + else { + PX_ASSERT(hitType == PxQueryHitType::eNONE); + } + } // for iSubHit + return true; + } + +private: + MultiQueryCallback<HitType>& operator=(const MultiQueryCallback<HitType>&); +}; + +//======================================================================================================================== +#if PX_SUPPORT_PVD +template<typename HitType> +struct CapturePvdOnReturn : public PxHitCallback<HitType> +{ + // copy the arguments of multiQuery into a struct, this is strictly for PVD recording + const NpSceneQueries* mSQ; + const MultiQueryInput& mInput; + PxHitFlags mHitFlags; // PT: TODO: this is not used! + const PxQueryCache* mCache; // PT: TODO: this is not used! + const PxQueryFilterData& mFilterData; + PxQueryFilterCallback* mFilterCall; // PT: TODO: this is not used! + BatchQueryFilterData* mBFD; // PT: TODO: check if this is sometimes not NULL + Ps::Array<HitType> mAllHits; + PxHitCallback<HitType>& mParentCallback; + + CapturePvdOnReturn( + const NpSceneQueries* sq, const MultiQueryInput& input, PxHitFlags hitFlags, + const PxQueryCache* cache, const PxQueryFilterData& filterData, PxQueryFilterCallback* filterCall, + BatchQueryFilterData* bfd, PxHitCallback<HitType>& parentCallback) : + PxHitCallback<HitType> (parentCallback.touches, parentCallback.maxNbTouches), + mSQ (sq), + mInput (input), + mHitFlags (hitFlags), + mCache (cache), + mFilterData (filterData), + mFilterCall (filterCall), + mBFD (bfd), + mParentCallback (parentCallback) + {} + + virtual PxAgain processTouches(const HitType* hits, PxU32 nbHits) + { + const PxAgain again = mParentCallback.processTouches(hits, nbHits); + for(PxU32 i=0; i<nbHits; i++) + mAllHits.pushBack(hits[i]); + return again; + } + + ~CapturePvdOnReturn() + { + const physx::Vd::ScbScenePvdClient& pvdClient = mSQ->getScene().getScenePvdClient(); + if(!(pvdClient.isConnected() && (pvdClient.getScenePvdFlags() & PxPvdSceneFlag::eTRANSMIT_SCENEQUERIES))) + return; + + physx::Vd::PvdSceneQueryCollector& collector = mBFD ? mSQ->getBatchedSqCollector() : mSQ->getSingleSqCollector(); + + if(mParentCallback.nbTouches) + { + for(PxU32 i = 0; i < mParentCallback.nbTouches; i++) + mAllHits.pushBack(mParentCallback.touches[i]); + } + + if(mParentCallback.hasBlock) + mAllHits.pushBack(mParentCallback.block); + + // PT: TODO: why do we need reinterpret_casts below? + if(HitTypeSupport<HitType>::IsRaycast) + collector.raycast (mInput.getOrigin(), mInput.getDir(), mInput.maxDistance, reinterpret_cast<PxRaycastHit*>(mAllHits.begin()), mAllHits.size(), mFilterData, this->maxNbTouches!=0); + else if(HitTypeSupport<HitType>::IsOverlap) + collector.overlapMultiple (*mInput.geometry, *mInput.pose, reinterpret_cast<PxOverlapHit*>(mAllHits.begin()), mAllHits.size(), mFilterData); + else if(HitTypeSupport<HitType>::IsSweep) + collector.sweep (*mInput.geometry, *mInput.pose, mInput.getDir(), mInput.maxDistance, reinterpret_cast<PxSweepHit*>(mAllHits.begin()), mAllHits.size(), mFilterData, this->maxNbTouches!=0); + } + +private: + CapturePvdOnReturn<HitType>& operator=(const CapturePvdOnReturn<HitType>&); +}; +#endif // PX_SUPPORT_PVD + +//======================================================================================================================== +template<typename HitType> +struct IssueCallbacksOnReturn +{ + PxHitCallback<HitType>& hits; + PxAgain again; // query was stopped by previous processTouches. This means that nbTouches is still non-zero + // but we don't need to issue processTouches again + PX_FORCE_INLINE IssueCallbacksOnReturn(PxHitCallback<HitType>& aHits) : hits(aHits) + { + again = true; + } + + ~IssueCallbacksOnReturn() + { + if(again) + // only issue processTouches if query wasn't stopped + // this is because nbTouches doesn't get reset to 0 in this case (according to spec) + // and the touches in touches array were already processed by the callback + { + if(hits.hasBlock && hits.nbTouches) + hits.nbTouches = clipHitsToNewMaxDist<HitType>(hits.touches, hits.nbTouches, HITDIST(hits.block)); + if(hits.nbTouches) + { + bool again_ = hits.processTouches(hits.touches, hits.nbTouches); + if(again_) + hits.nbTouches = 0; + } + } + hits.finalizeQuery(); + } + +private: + IssueCallbacksOnReturn<HitType>& operator=(const IssueCallbacksOnReturn<HitType>&); +}; + +#undef HITDIST + +//======================================================================================================================== +template<typename HitType> +bool NpSceneQueries::multiQuery( + const MultiQueryInput& input, PxHitCallback<HitType>& hits, PxHitFlags hitFlags, const PxQueryCache* cache, + const PxQueryFilterData& filterData, PxQueryFilterCallback* filterCall, BatchQueryFilterData* bfd) const +{ + const bool anyHit = (filterData.flags & PxQueryFlag::eANY_HIT) == PxQueryFlag::eANY_HIT; + + PxI32 retval = 0; PX_UNUSED(retval); + + if(HitTypeSupport<HitType>::IsRaycast == 0) + { + PX_CHECK_AND_RETURN_VAL(input.pose != NULL, "NpSceneQueries::overlap/sweep pose is NULL.", 0); + PX_CHECK_AND_RETURN_VAL(input.pose->isValid(), "NpSceneQueries::overlap/sweep pose is not valid.", 0); + } + else + { + PX_CHECK_AND_RETURN_VAL(input.getOrigin().isFinite(), "NpSceneQueries::raycast pose is not valid.", 0); + } + + if(HitTypeSupport<HitType>::IsOverlap == 0) + { + PX_CHECK_AND_RETURN_VAL(input.getDir().isFinite(), "NpSceneQueries multiQuery input check: unitDir is not valid.", 0); + PX_CHECK_AND_RETURN_VAL(input.getDir().isNormalized(), "NpSceneQueries multiQuery input check: direction must be normalized", 0); + } + + if(HitTypeSupport<HitType>::IsRaycast) + { + PX_CHECK_AND_RETURN_VAL(input.maxDistance > 0.0f, "NpSceneQueries::multiQuery input check: distance cannot be negative or zero", 0); + } + + if(HitTypeSupport<HitType>::IsOverlap && !anyHit) + { + PX_CHECK_AND_RETURN_VAL(hits.maxNbTouches > 0, "PxScene::overlap() and PxBatchQuery::overlap() calls without eANY_HIT flag require a touch hit buffer for return results.", 0); + } + + if(HitTypeSupport<HitType>::IsSweep) + { + PX_CHECK_AND_RETURN_VAL(input.maxDistance >= 0.0f, "NpSceneQueries multiQuery input check: distance cannot be negative", 0); + PX_CHECK_AND_RETURN_VAL(input.maxDistance != 0.0f || !(hitFlags & PxHitFlag::eASSUME_NO_INITIAL_OVERLAP), + "NpSceneQueries multiQuery input check: zero-length sweep only valid without the PxHitFlag::eASSUME_NO_INITIAL_OVERLAP flag", 0); + } + + PX_CHECK_MSG(!cache || (cache && cache->shape && cache->actor), "Raycast cache specified but shape or actor pointer is NULL!"); + const PrunerData cacheData = cache ? NpActor::getShapeManager(*cache->actor)->findSceneQueryData(*static_cast<NpShape*>(cache->shape)) : SQ_INVALID_PRUNER_DATA; + + // this function is logically const for the SDK user, as flushUpdates() will not have an API-visible effect on this object + // internally however, flushUpdates() changes the states of the Pruners in mSQManager + // because here is the only place we need this, const_cast instead of making SQM mutable + const_cast<NpSceneQueries*>(this)->mSQManager.flushUpdates(); + +#if PX_SUPPORT_PVD + CapturePvdOnReturn<HitType> pvdCapture(this, input, hitFlags, cache, filterData, filterCall, bfd, hits); +#endif + + IssueCallbacksOnReturn<HitType> cbr(hits); // destructor will execute callbacks on return from this function + hits.hasBlock = false; + hits.nbTouches = 0; + + PxReal shrunkDistance = HitTypeSupport<HitType>::IsOverlap ? PX_MAX_REAL : input.maxDistance; // can be progressively shrunk as we go over the list of shapes + if(HitTypeSupport<HitType>::IsSweep) + shrunkDistance = PxMin(shrunkDistance, PX_MAX_SWEEP_DISTANCE); + MultiQueryCallback<HitType> pcb(*this, input, anyHit, hits, hitFlags, filterData, filterCall, shrunkDistance, bfd); + + if(cacheData!=SQ_INVALID_PRUNER_DATA && hits.maxNbTouches == 0) // don't use cache for queries that can return touch hits + { + // this block is only executed for single shape cache + const PrunerPayload& cachedPayload = mSQManager.getPayload(cacheData); + pcb.mIsCached = true; + PxReal dummyDist; + + PxAgain againAfterCache; + if(HitTypeSupport<HitType>::IsSweep) + { + // AP: for sweeps we cache the bounds because we need to know them for the test to clip the sweep to bounds + // otherwise GJK becomes unstable. The bounds can be used multiple times so this is an optimization. + const ShapeData sd(*input.geometry, *input.pose, input.inflation); + pcb.mQueryShapeBounds = sd.getPrunerInflatedWorldAABB(); + pcb.mQueryShapeBoundsValid = true; + pcb.mShapeData = &sd; + againAfterCache = pcb.invoke(dummyDist, cachedPayload); + pcb.mShapeData = NULL; + } else + againAfterCache = pcb.invoke(dummyDist, cachedPayload); + pcb.mIsCached = false; + if(!againAfterCache) // if PxAgain result for cached shape was false (abort query), return here + return hits.hasAnyHits(); + } + + const Pruner* staticPruner = mSQManager.get(PruningIndex::eSTATIC).pruner(); + const Pruner* dynamicPruner = mSQManager.get(PruningIndex::eDYNAMIC).pruner(); + + const PxU32 doStatics = filterData.flags & PxQueryFlag::eSTATIC; + const PxU32 doDynamics = filterData.flags & PxQueryFlag::eDYNAMIC; + + if(HitTypeSupport<HitType>::IsRaycast) + { + bool again = doStatics ? staticPruner->raycast(input.getOrigin(), input.getDir(), pcb.mShrunkDistance, pcb) : true; + if(!again) + return hits.hasAnyHits(); + + if(doDynamics) + again = dynamicPruner->raycast(input.getOrigin(), input.getDir(), pcb.mShrunkDistance, pcb); + + cbr.again = again; // update the status to avoid duplicate processTouches() + return hits.hasAnyHits(); + } + else if(HitTypeSupport<HitType>::IsOverlap) + { + PX_ASSERT(input.geometry); + + const ShapeData sd(*input.geometry, *input.pose, input.inflation); + pcb.mShapeData = &sd; + PxAgain again = doStatics ? staticPruner->overlap(sd, pcb) : true; + if(!again) // && (filterData.flags & PxQueryFlag::eANY_HIT)) + return hits.hasAnyHits(); + + if(doDynamics) + again = dynamicPruner->overlap(sd, pcb); + + cbr.again = again; // update the status to avoid duplicate processTouches() + return hits.hasAnyHits(); + } + else + { + PX_ASSERT(HitTypeSupport<HitType>::IsSweep); + PX_ASSERT(input.geometry); + + const ShapeData sd(*input.geometry, *input.pose, input.inflation); + pcb.mQueryShapeBounds = sd.getPrunerInflatedWorldAABB(); + pcb.mQueryShapeBoundsValid = true; + pcb.mShapeData = &sd; + PxAgain again = doStatics ? staticPruner->sweep(sd, input.getDir(), pcb.mShrunkDistance, pcb) : true; + if(!again) + return hits.hasAnyHits(); + + if(doDynamics) + again = dynamicPruner->sweep(sd, input.getDir(), pcb.mShrunkDistance, pcb); + + cbr.again = again; // update the status to avoid duplicate processTouches() + return hits.hasAnyHits(); + } +} + + +// explicit instantiations for multiQuery to fix link errors on android +#if !PX_WINDOWS_FAMILY +#define TMQ(hittype) \ + template bool NpSceneQueries::multiQuery<hittype>( \ + const MultiQueryInput& input, PxHitCallback<hittype>& hits, PxHitFlags hitFlags, \ + const PxQueryCache* cache, const PxQueryFilterData& filterData, PxQueryFilterCallback* filterCall, \ + BatchQueryFilterData* bfd) const; + +TMQ(PxRaycastHit) +TMQ(PxOverlapHit) +TMQ(PxSweepHit) + +#undef TMQ +#endif diff --git a/PhysX_3.4/Source/PhysX/src/NpSceneQueries.h b/PhysX_3.4/Source/PhysX/src/NpSceneQueries.h new file mode 100644 index 00000000..3071e43f --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpSceneQueries.h @@ -0,0 +1,211 @@ +// 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_NP_SCENEQUERIES +#define PX_PHYSICS_NP_SCENEQUERIES + +#include "PxScene.h" +#include "PxQueryReport.h" +#include "PsIntrinsics.h" +#include "CmPhysXCommon.h" +#include "SqSceneQueryManager.h" +#include "GuTriangleMesh.h" +#include "GuRaycastTests.h" +#include "GuSweepTests.h" +#include "GuOverlapTests.h" +#include "ScbScene.h" + +#if PX_SUPPORT_PVD +#include "NpPvdSceneQueryCollector.h" +#endif + +namespace physx { namespace Sq { + + struct QueryID { enum Enum { + QUERY_RAYCAST_ANY_OBJECT, + QUERY_RAYCAST_CLOSEST_OBJECT, + QUERY_RAYCAST_ALL_OBJECTS, + + QUERY_OVERLAP_SPHERE_ALL_OBJECTS, + QUERY_OVERLAP_AABB_ALL_OBJECTS, + QUERY_OVERLAP_OBB_ALL_OBJECTS, + QUERY_OVERLAP_CAPSULE_ALL_OBJECTS, + QUERY_OVERLAP_CONVEX_ALL_OBJECTS, + + QUERY_LINEAR_OBB_SWEEP_CLOSEST_OBJECT, + QUERY_LINEAR_CAPSULE_SWEEP_CLOSEST_OBJECT, + QUERY_LINEAR_CONVEX_SWEEP_CLOSEST_OBJECT + }; }; +} + +struct MultiQueryInput +{ + const PxVec3* rayOrigin; // only valid for raycasts + const PxVec3* unitDir; // only valid for raycasts and sweeps + PxReal maxDistance; // only valid for raycasts and sweeps + const PxGeometry* geometry; // only valid for overlaps and sweeps + const PxTransform* pose; // only valid for overlaps and sweeps + PxReal inflation; // only valid for sweeps + + // Raycast constructor + MultiQueryInput(const PxVec3& aRayOrigin, const PxVec3& aUnitDir, PxReal aMaxDist) + { + Ps::prefetchLine(&aRayOrigin); + Ps::prefetchLine(&aUnitDir); + rayOrigin = &aRayOrigin; + unitDir = &aUnitDir; + maxDistance = aMaxDist; + geometry = NULL; + pose = NULL; + inflation = 0.0f; + } + + // Overlap constructor + MultiQueryInput(const PxGeometry* aGeometry, const PxTransform* aPose) + { + Ps::prefetchLine(aGeometry); + Ps::prefetchLine(aPose); + geometry = aGeometry; + pose = aPose; + inflation = 0.0f; + rayOrigin = unitDir = NULL; + } + + // Sweep constructor + MultiQueryInput( + const PxGeometry* aGeometry, const PxTransform* aPose, + const PxVec3& aUnitDir, const PxReal aMaxDist, const PxReal aInflation) + { + Ps::prefetchLine(aGeometry); + Ps::prefetchLine(aPose); + Ps::prefetchLine(&aUnitDir); + rayOrigin = NULL; + maxDistance = aMaxDist; + unitDir = &aUnitDir; + geometry = aGeometry; + pose = aPose; + inflation = aInflation; + } + + PX_FORCE_INLINE const PxVec3& getDir() const { PX_ASSERT(unitDir); return *unitDir; } + PX_FORCE_INLINE const PxVec3& getOrigin() const { PX_ASSERT(rayOrigin); return *rayOrigin; } +}; + +struct BatchQueryFilterData +{ + void* filterShaderData; + PxU32 filterShaderDataSize; + PxBatchQueryPreFilterShader preFilterShader; + PxBatchQueryPostFilterShader postFilterShader; + #if PX_SUPPORT_PVD + Vd::PvdSceneQueryCollector* collector; // gets set to bq collector + #endif + BatchQueryFilterData(void* fsData, PxU32 fsSize, PxBatchQueryPreFilterShader preFs, PxBatchQueryPostFilterShader postFs) + : filterShaderData(fsData), filterShaderDataSize(fsSize), preFilterShader(preFs), postFilterShader(postFs) + { + #if PX_SUPPORT_PVD + collector = NULL; + #endif + } +}; + +class PxGeometry; + +class NpSceneQueries : public PxScene +{ + PX_NOCOPY(NpSceneQueries) + +public: + NpSceneQueries(const PxSceneDesc& desc); + ~NpSceneQueries(); + + template<typename QueryHit> + bool multiQuery( + const MultiQueryInput& in, + PxHitCallback<QueryHit>& hits, PxHitFlags hitFlags, const PxQueryCache* cache, + const PxQueryFilterData& filterData, PxQueryFilterCallback* filterCall, + BatchQueryFilterData* bqFd) const; + + // Synchronous scene queries + virtual bool raycast( + const PxVec3& origin, const PxVec3& unitDir, const PxReal distance, // Ray data + PxRaycastCallback& hitCall, PxHitFlags hitFlags, + const PxQueryFilterData& filterData, PxQueryFilterCallback* filterCall, + const PxQueryCache* cache) const; + + virtual bool sweep( + const PxGeometry& geometry, const PxTransform& pose, // GeomObject data + const PxVec3& unitDir, const PxReal distance, // Ray data + PxSweepCallback& hitCall, PxHitFlags hitFlags, + const PxQueryFilterData& filterData, PxQueryFilterCallback* filterCall, + const PxQueryCache* cache, const PxReal inflation) const; + + virtual bool overlap( + const PxGeometry& geometry, const PxTransform& transform, // GeomObject data + PxOverlapCallback& hitCall, + const PxQueryFilterData& filterData, PxQueryFilterCallback* filterCall) const; + + PX_FORCE_INLINE PxU64 getContextId() const { return PxU64(reinterpret_cast<size_t>(this)); } + PX_FORCE_INLINE Scb::Scene& getScene() { return mScene; } + PX_FORCE_INLINE const Scb::Scene& getScene() const { return mScene; } + PX_FORCE_INLINE PxU32 getFlagsFast() const { return mScene.getFlags(); } + PX_FORCE_INLINE Sq::SceneQueryManager& getSceneQueryManagerFast() { return mSQManager; } + + Scb::Scene mScene; + Sq::SceneQueryManager mSQManager; + + const Gu::GeomRaycastTable& mCachedRaycastFuncs; + const Gu::GeomSweepFuncs& mCachedSweepFuncs; + const Gu::GeomOverlapTable* mCachedOverlapFuncs; + +#if PX_SUPPORT_PVD +public: + //Scene query and hits for pvd, collected in current frame + mutable Vd::PvdSceneQueryCollector mSingleSqCollector; + mutable Vd::PvdSceneQueryCollector mBatchedSqCollector; + +PX_FORCE_INLINE Vd::PvdSceneQueryCollector& getSingleSqCollector() const {return mSingleSqCollector;} +PX_FORCE_INLINE Vd::PvdSceneQueryCollector& getBatchedSqCollector() const {return mBatchedSqCollector;} +#endif // PX_SUPPORT_PVD +}; + +namespace Sq { class AABBPruner; class AABBTreeRuntimeNode; class AABBTree; } + +#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 + +#if PX_VC + #pragma warning(pop) +#endif + +} // namespace physx, sq + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/NpSerializerAdapter.cpp b/PhysX_3.4/Source/PhysX/src/NpSerializerAdapter.cpp new file mode 100644 index 00000000..c8e2b2be --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpSerializerAdapter.cpp @@ -0,0 +1,207 @@ +// 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 "GuHeightField.h" +#include "GuConvexMesh.h" +#include "GuTriangleMesh.h" +#include "GuTriangleMeshBV4.h" +#include "GuTriangleMeshRTree.h" +#include "NpClothFabric.h" +#include "NpCloth.h" +#include "NpParticleSystem.h" +#include "NpParticleFluid.h" + +#include "NpRigidStatic.h" +#include "NpRigidDynamic.h" +#include "NpArticulation.h" +#include "NpArticulationLink.h" +#include "NpArticulationJoint.h" +#include "NpMaterial.h" +#include "NpAggregate.h" +#include "GuHeightFieldData.h" + +#include "SqPruningStructure.h" + +#include "PxBase.h" +#include "PxSerialFramework.h" +#include "PxSerializer.h" +#include "PxPhysicsSerialization.h" + +namespace physx +{ + using namespace physx::Gu; + + template<> + void PxSerializerDefaultAdapter<NpRigidDynamic>::exportData(PxBase& obj, PxSerializationContext& s) const + { + PxU32 classSize = sizeof(NpRigidDynamic); + NpRigidDynamic& dynamic = static_cast<NpRigidDynamic&>(obj); + + PxsBodyCore serialCore; + size_t address = dynamic.getScbBodyFast().getScBody().getSerialCore(serialCore); + PxU32 offset = PxU32(address - reinterpret_cast<size_t>(&dynamic)); + PX_ASSERT(offset + sizeof(serialCore) <= classSize); + s.writeData(&dynamic, offset); + s.writeData(&serialCore, sizeof(serialCore)); + void* tail = reinterpret_cast<PxU8*>(&dynamic) + offset + sizeof(serialCore); + s.writeData(tail, classSize - offset - sizeof(serialCore)); + } + + template<> + void PxSerializerDefaultAdapter<NpRigidDynamic>::registerReferences(PxBase& obj, PxSerializationContext& s) const + { + NpRigidDynamic& dynamic = static_cast<NpRigidDynamic&>(obj); + + s.registerReference(obj, PX_SERIAL_REF_KIND_PXBASE, size_t(&obj)); + + struct RequiresCallback : public PxProcessPxBaseCallback + { + RequiresCallback(physx::PxSerializationContext& c) : context(c) {} + RequiresCallback& operator=(const RequiresCallback&) { PX_ASSERT(0); return *this; } //PX_NOCOPY doesn't work for local classes + void process(PxBase& base) + { + context.registerReference(base, PX_SERIAL_REF_KIND_PXBASE, size_t(&base)); + } + PxSerializationContext& context; + }; + + RequiresCallback callback(s); + dynamic.requires(callback); + } + + template<> + void PxSerializerDefaultAdapter<NpShape>::registerReferences(PxBase& obj, PxSerializationContext& s) const + { + NpShape& shape = static_cast<NpShape&>(obj); + + s.registerReference(obj, PX_SERIAL_REF_KIND_PXBASE, size_t(&obj)); + + struct RequiresCallback : public PxProcessPxBaseCallback + { + RequiresCallback(physx::PxSerializationContext& c) : context(c) {} + RequiresCallback &operator=(const RequiresCallback&) { PX_ASSERT(0); return *this; } //PX_NOCOPY doesn't work for local classes + void process(PxBase& base) + { + PxMaterial* pxMaterial = base.is<PxMaterial>(); + if (!pxMaterial) + { + context.registerReference(base, PX_SERIAL_REF_KIND_PXBASE, size_t(&base)); + } + else + { + //ideally we would move this part to ScShapeCore but we don't yet have a MaterialManager available there. + PxU32 index = static_cast<NpMaterial*>(pxMaterial)->getHandle(); + context.registerReference(base, PX_SERIAL_REF_KIND_MATERIAL_IDX, size_t(index)); + } + } + PxSerializationContext& context; + }; + + RequiresCallback callback(s); + shape.requires(callback); + } + + template<> + bool PxSerializerDefaultAdapter<NpConstraint>::isSubordinate() const + { + return true; + } + + template<> + bool PxSerializerDefaultAdapter<NpArticulationJoint>::isSubordinate() const + { + return true; + } + + template<> + bool PxSerializerDefaultAdapter<NpArticulationLink>::isSubordinate() const + { + return true; + } +} + +using namespace physx; + +void PxRegisterPhysicsSerializers(PxSerializationRegistry& sr) +{ + sr.registerSerializer(PxConcreteType::eCONVEX_MESH, PX_NEW_SERIALIZER_ADAPTER(ConvexMesh)); + sr.registerSerializer(PxConcreteType::eTRIANGLE_MESH_BVH33, PX_NEW_SERIALIZER_ADAPTER(RTreeTriangleMesh)); + sr.registerSerializer(PxConcreteType::eTRIANGLE_MESH_BVH34, PX_NEW_SERIALIZER_ADAPTER(BV4TriangleMesh)); + sr.registerSerializer(PxConcreteType::eHEIGHTFIELD, PX_NEW_SERIALIZER_ADAPTER(HeightField)); + sr.registerSerializer(PxConcreteType::eRIGID_DYNAMIC, PX_NEW_SERIALIZER_ADAPTER(NpRigidDynamic)); + sr.registerSerializer(PxConcreteType::eRIGID_STATIC, PX_NEW_SERIALIZER_ADAPTER(NpRigidStatic)); + sr.registerSerializer(PxConcreteType::eSHAPE, PX_NEW_SERIALIZER_ADAPTER(NpShape)); + sr.registerSerializer(PxConcreteType::eMATERIAL, PX_NEW_SERIALIZER_ADAPTER(NpMaterial)); + sr.registerSerializer(PxConcreteType::eCONSTRAINT, PX_NEW_SERIALIZER_ADAPTER(NpConstraint)); + sr.registerSerializer(PxConcreteType::eAGGREGATE, PX_NEW_SERIALIZER_ADAPTER(NpAggregate)); + sr.registerSerializer(PxConcreteType::eARTICULATION, PX_NEW_SERIALIZER_ADAPTER(NpArticulation)); + sr.registerSerializer(PxConcreteType::eARTICULATION_LINK, PX_NEW_SERIALIZER_ADAPTER(NpArticulationLink)); + sr.registerSerializer(PxConcreteType::eARTICULATION_JOINT, PX_NEW_SERIALIZER_ADAPTER(NpArticulationJoint)); + sr.registerSerializer(PxConcreteType::ePRUNING_STRUCTURE, PX_NEW_SERIALIZER_ADAPTER(Sq::PruningStructure)); + +#if PX_USE_CLOTH_API + sr.registerSerializer(PxConcreteType::eCLOTH, PX_NEW_SERIALIZER_ADAPTER(NpCloth)); + sr.registerSerializer(PxConcreteType::eCLOTH_FABRIC, PX_NEW_SERIALIZER_ADAPTER(NpClothFabric)); +#endif + +#if PX_USE_PARTICLE_SYSTEM_API + sr.registerSerializer(PxConcreteType::ePARTICLE_SYSTEM, PX_NEW_SERIALIZER_ADAPTER(NpParticleSystem)); + sr.registerSerializer(PxConcreteType::ePARTICLE_FLUID, PX_NEW_SERIALIZER_ADAPTER(NpParticleFluid)); +#endif + +} + + +void PxUnregisterPhysicsSerializers(PxSerializationRegistry& sr) +{ + PX_DELETE_SERIALIZER_ADAPTER(sr.unregisterSerializer(PxConcreteType::eCONVEX_MESH)); + PX_DELETE_SERIALIZER_ADAPTER(sr.unregisterSerializer(PxConcreteType::eTRIANGLE_MESH_BVH33)); + PX_DELETE_SERIALIZER_ADAPTER(sr.unregisterSerializer(PxConcreteType::eTRIANGLE_MESH_BVH34)); + PX_DELETE_SERIALIZER_ADAPTER(sr.unregisterSerializer(PxConcreteType::eHEIGHTFIELD)); + PX_DELETE_SERIALIZER_ADAPTER(sr.unregisterSerializer(PxConcreteType::eRIGID_DYNAMIC)); + PX_DELETE_SERIALIZER_ADAPTER(sr.unregisterSerializer(PxConcreteType::eRIGID_STATIC)); + PX_DELETE_SERIALIZER_ADAPTER(sr.unregisterSerializer(PxConcreteType::eSHAPE)); + PX_DELETE_SERIALIZER_ADAPTER(sr.unregisterSerializer(PxConcreteType::eMATERIAL)); + PX_DELETE_SERIALIZER_ADAPTER(sr.unregisterSerializer(PxConcreteType::eCONSTRAINT)); + PX_DELETE_SERIALIZER_ADAPTER(sr.unregisterSerializer(PxConcreteType::eAGGREGATE)); + PX_DELETE_SERIALIZER_ADAPTER(sr.unregisterSerializer(PxConcreteType::eARTICULATION)); + PX_DELETE_SERIALIZER_ADAPTER(sr.unregisterSerializer(PxConcreteType::eARTICULATION_LINK)); + PX_DELETE_SERIALIZER_ADAPTER(sr.unregisterSerializer(PxConcreteType::eARTICULATION_JOINT)); + PX_DELETE_SERIALIZER_ADAPTER(sr.unregisterSerializer(PxConcreteType::ePRUNING_STRUCTURE)); + +#if PX_USE_CLOTH_API + PX_DELETE_SERIALIZER_ADAPTER(sr.unregisterSerializer(PxConcreteType::eCLOTH)); + PX_DELETE_SERIALIZER_ADAPTER(sr.unregisterSerializer(PxConcreteType::eCLOTH_FABRIC)); +#endif + +#if PX_USE_PARTICLE_SYSTEM_API + PX_DELETE_SERIALIZER_ADAPTER(sr.unregisterSerializer(PxConcreteType::ePARTICLE_SYSTEM)); + PX_DELETE_SERIALIZER_ADAPTER(sr.unregisterSerializer(PxConcreteType::ePARTICLE_FLUID)); +#endif +} diff --git a/PhysX_3.4/Source/PhysX/src/NpShape.cpp b/PhysX_3.4/Source/PhysX/src/NpShape.cpp new file mode 100644 index 00000000..eafbd852 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpShape.cpp @@ -0,0 +1,851 @@ +// 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 "GuConvexMesh.h" +#include "GuTriangleMesh.h" +#include "ScbNpDeps.h" +#include "GuBounds.h" + +using namespace physx; +using namespace Sq; + +namespace physx +{ + extern bool gUnifiedHeightfieldCollision; +} + +static PX_FORCE_INLINE void updatePvdProperties(const Scb::Shape& shape) +{ +#if PX_SUPPORT_PVD + Scb::Scene* scbScene = shape.getScbSceneForAPI(); + if(scbScene) + scbScene->getScenePvdClient().updatePvdProperties(&shape); +#else + PX_UNUSED(shape); +#endif +} + +NpShape::NpShape(const PxGeometry& geometry, PxShapeFlags shapeFlags, const PxU16* materialIndices, PxU16 materialCount, bool isExclusive) +: PxShape (PxConcreteType::eSHAPE, PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE) +, mActor (NULL) +, mShape (geometry, shapeFlags, materialIndices, materialCount, isExclusive) +, mName (NULL) +, mExclusiveAndActorCount (isExclusive ? EXCLUSIVE_MASK : 0) +{ + PX_ASSERT(mShape.getScShape().getPxShape() == static_cast<PxShape*>(this)); + + PxShape::userData = NULL; + + incMeshRefCount(); +} + +NpShape::~NpShape() +{ + decMeshRefCount(); + + PxU32 nbMaterials = mShape.getNbMaterials(); + for (PxU32 i=0; i < nbMaterials; i++) + { + NpMaterial* mat = static_cast<NpMaterial*>(mShape.getMaterial(i)); + mat->decRefCount(); + } +} + +void NpShape::onRefCountZero() +{ + NpFactory::getInstance().onShapeRelease(this); + // see NpShape.h for ref counting semantics for shapes + NpDestroy(getScbShape()); +} + +// PX_SERIALIZATION + +NpShape::NpShape(PxBaseFlags baseFlags) : PxShape(baseFlags), mShape(PxEmpty) +{ + mExclusiveAndActorCount &= EXCLUSIVE_MASK; +} + +void NpShape::exportExtraData(PxSerializationContext& stream) +{ + getScbShape().getScShape().exportExtraData(stream); + stream.writeName(mName); +} + +void NpShape::importExtraData(PxDeserializationContext& context) +{ + getScbShape().getScShape().importExtraData(context); + context.readName(mName); +} + +void NpShape::requires(PxProcessPxBaseCallback& c) +{ + //meshes + PxBase* mesh = NULL; + switch(mShape.getGeometryType()) + { + case PxGeometryType::eCONVEXMESH: + mesh = static_cast<const PxConvexMeshGeometry&>(mShape.getGeometry()).convexMesh; + break; + case PxGeometryType::eHEIGHTFIELD: + mesh = static_cast<const PxHeightFieldGeometry&>(mShape.getGeometry()).heightField; + break; + case PxGeometryType::eTRIANGLEMESH: + mesh = static_cast<const PxTriangleMeshGeometry&>(mShape.getGeometry()).triangleMesh; + break; + case PxGeometryType::eSPHERE: + case PxGeometryType::ePLANE: + case PxGeometryType::eCAPSULE: + case PxGeometryType::eBOX: + case PxGeometryType::eGEOMETRY_COUNT: + case PxGeometryType::eINVALID: + break; + } + + if(mesh) + c.process(*mesh); + + //material + PxU32 nbMaterials = mShape.getNbMaterials(); + for (PxU32 i=0; i < nbMaterials; i++) + { + NpMaterial* mat = static_cast<NpMaterial*>(mShape.getMaterial(i)); + c.process(*mat); + } +} + +void NpShape::resolveReferences(PxDeserializationContext& context) +{ + // getMaterials() only works after material indices have been patched. + // in order to get to the new material indices, we need access to the new materials. + // this only leaves us with the option of acquiring the material through the context given an old material index (we do have the mapping) + { + PxU32 nbIndices = mShape.getScShape().getNbMaterialIndices(); + const PxU16* indices = mShape.getScShape().getMaterialIndices(); + + for (PxU32 i=0; i < nbIndices; i++) + { + PxBase* base = context.resolveReference(PX_SERIAL_REF_KIND_MATERIAL_IDX, size_t(indices[i])); + PX_ASSERT(base && base->is<PxMaterial>()); + + NpMaterial& material = *static_cast<NpMaterial*>(base); + getScbShape().getScShape().resolveMaterialReference(i, PxU16(material.getHandle())); + } + } + + context.translatePxBase(mActor); + + getScbShape().getScShape().resolveReferences(context); + + + incMeshRefCount(); + + // Increment materials' refcounts in a second pass. Works better in case of failure above. + PxU32 nbMaterials = mShape.getNbMaterials(); + for (PxU32 i=0; i < nbMaterials; i++) + { + NpMaterial* mat = static_cast<NpMaterial*>(mShape.getMaterial(i)); + mat->incRefCount(); + } +} + +NpShape* NpShape::createObject(PxU8*& address, PxDeserializationContext& context) +{ + NpShape* obj = new (address) NpShape(PxBaseFlag::eIS_RELEASABLE); + address += sizeof(NpShape); + obj->importExtraData(context); + obj->resolveReferences(context); + return obj; +} +//~PX_SERIALIZATION + +void NpShape::acquireReference() +{ + incRefCount(); +} + +void NpShape::release() +{ + PX_CHECK_AND_RETURN(getRefCount() > 1 || getActorCount() == 0, "PxShape::release: last reference to a shape released while still attached to an actor!"); + NP_WRITE_CHECK(getOwnerScene()); + releaseInternal(); +} + +void NpShape::releaseInternal() +{ + decRefCount(); +} + +Sc::RigidCore& NpShape::getScRigidObjectExclusive() const +{ + const PxType actorType = mActor->getConcreteType(); + + if (actorType == PxConcreteType::eRIGID_DYNAMIC) + return static_cast<NpRigidDynamic&>(*mActor).getScbBodyFast().getScBody(); + else if (actorType == PxConcreteType::eARTICULATION_LINK) + return static_cast<NpArticulationLink&>(*mActor).getScbBodyFast().getScBody(); + else + return static_cast<NpRigidStatic&>(*mActor).getScbRigidStaticFast().getScStatic(); +} + +PxGeometryType::Enum NpShape::getGeometryType() const +{ + NP_READ_CHECK(getOwnerScene()); + + return mShape.getGeometryType(); +} + +void NpShape::setGeometry(const PxGeometry& g) +{ + NP_WRITE_CHECK(getOwnerScene()); + PX_CHECK_AND_RETURN(isWritable(), "PxShape::setGeometry: shared shapes attached to actors are not writable."); + PX_SIMD_GUARD; + + // PT: fixes US2117 + if(g.getType() != getGeometryTypeFast()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "PxShape::setGeometry(): Invalid geometry type. Changing the type of the shape is not supported."); + return; + } + +#if PX_CHECKED + bool isValid = false; + switch(g.getType()) + { + case PxGeometryType::eSPHERE: + isValid = static_cast<const PxSphereGeometry&>(g).isValid(); + break; + + case PxGeometryType::ePLANE: + isValid = static_cast<const PxPlaneGeometry&>(g).isValid(); + break; + + case PxGeometryType::eCAPSULE: + isValid = static_cast<const PxCapsuleGeometry&>(g).isValid(); + break; + + case PxGeometryType::eBOX: + isValid = static_cast<const PxBoxGeometry&>(g).isValid(); + break; + + case PxGeometryType::eCONVEXMESH: + isValid = static_cast<const PxConvexMeshGeometry&>(g).isValid(); + break; + + case PxGeometryType::eTRIANGLEMESH: + isValid = static_cast<const PxTriangleMeshGeometry&>(g).isValid(); + break; + + case PxGeometryType::eHEIGHTFIELD: + isValid = static_cast<const PxHeightFieldGeometry&>(g).isValid(); + break; + + case PxGeometryType::eGEOMETRY_COUNT: + case PxGeometryType::eINVALID: + break; + } + + if(!isValid) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "PxShape::setGeometry(): Invalid geometry!"); + return; + } +#endif + + decMeshRefCount(); + + mShape.setGeometry(g); + + incMeshRefCount(); + + if((mShape.getFlags() & PxShapeFlag::eSCENE_QUERY_SHAPE) && mActor) + { + PX_ASSERT(mActor); + + NpScene* scene = NpActor::getOwnerScene(*mActor); + NpShapeManager* shapeManager = NpActor::getShapeManager(*mActor); + if(scene) + { + const PrunerData sqData = shapeManager->findSceneQueryData(*this); + scene->getSceneQueryManagerFast().markForUpdate(sqData); + } + + // invalidate the pruning structure if the actor bounds changed + if (shapeManager->getPruningStructure()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxShape::setGeometry: Shape is a part of pruning structure, pruning structure is now invalid!"); + shapeManager->getPruningStructure()->invalidate(mActor); + } + } +} + +PxGeometryHolder NpShape::getGeometry() const +{ + PX_COMPILE_TIME_ASSERT(sizeof(Gu::GeometryUnion)>=sizeof(PxGeometryHolder)); + return reinterpret_cast<const PxGeometryHolder&>(mShape.getGeometry()); +} + +template<class T> +static PX_FORCE_INLINE bool getGeometryT(const NpShape* npShape, PxGeometryType::Enum type, T& geom) +{ + NP_READ_CHECK(npShape->getOwnerScene()); + + if(npShape->getGeometryTypeFast() != type) + return false; + + geom = static_cast<const T&>(npShape->getScbShape().getGeometry()); + return true; +} + +bool NpShape::getBoxGeometry(PxBoxGeometry& g) const { return getGeometryT(this, PxGeometryType::eBOX, g); } +bool NpShape::getSphereGeometry(PxSphereGeometry& g) const { return getGeometryT(this, PxGeometryType::eSPHERE, g); } +bool NpShape::getCapsuleGeometry(PxCapsuleGeometry& g) const { return getGeometryT(this, PxGeometryType::eCAPSULE, g); } +bool NpShape::getPlaneGeometry(PxPlaneGeometry& g) const { return getGeometryT(this, PxGeometryType::ePLANE, g); } +bool NpShape::getConvexMeshGeometry(PxConvexMeshGeometry& g) const { return getGeometryT(this, PxGeometryType::eCONVEXMESH, g); } +bool NpShape::getTriangleMeshGeometry(PxTriangleMeshGeometry& g) const { return getGeometryT(this, PxGeometryType::eTRIANGLEMESH, g); } +bool NpShape::getHeightFieldGeometry(PxHeightFieldGeometry& g) const { return getGeometryT(this, PxGeometryType::eHEIGHTFIELD, g); } + +PxRigidActor* NpShape::getActor() const +{ + NP_READ_CHECK(getOwnerScene()); + return mActor; +} + +void NpShape::setLocalPose(const PxTransform& newShape2Actor) +{ + PX_CHECK_AND_RETURN(newShape2Actor.isSane(), "PxShape::setLocalPose: pose is not valid."); + PX_CHECK_AND_RETURN(isWritable(), "PxShape::setLocalPose: shared shapes attached to actors are not writable."); + NP_WRITE_CHECK(getOwnerScene()); + + mShape.setShape2Actor(newShape2Actor.getNormalized()); + + if(mShape.getFlags() & PxShapeFlag::eSCENE_QUERY_SHAPE && mActor) + { + NpScene* scene = NpActor::getAPIScene(*mActor); + NpShapeManager* shapeManager = NpActor::getShapeManager(*mActor); + if(scene) + { + const PrunerData sqData = shapeManager->findSceneQueryData(*this); + scene->getSceneQueryManagerFast().markForUpdate(sqData); + } + + // invalidate the pruning structure if the actor bounds changed + if (shapeManager->getPruningStructure()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxShape::setLocalPose: Shape is a part of pruning structure, pruning structure is now invalid!"); + shapeManager->getPruningStructure()->invalidate(mActor); + } + } +} + +PxTransform NpShape::getLocalPose() const +{ + NP_READ_CHECK(getOwnerScene()); + + return mShape.getShape2Actor(); +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpShape::setSimulationFilterData(const PxFilterData& data) +{ + NP_WRITE_CHECK(getOwnerScene()); + PX_CHECK_AND_RETURN(isWritable(), "PxShape::setSimulationFilterData: shared shapes attached to actors are not writable."); + mShape.setSimulationFilterData(data); +} + +PxFilterData NpShape::getSimulationFilterData() const +{ + NP_READ_CHECK(getOwnerScene()); + return mShape.getSimulationFilterData(); +} + +void NpShape::setQueryFilterData(const PxFilterData& data) +{ + NP_WRITE_CHECK(getOwnerScene()); + PX_CHECK_AND_RETURN(isWritable(), "PxShape::setQueryFilterData: shared shapes attached to actors are not writable."); + + mShape.getScShape().setQueryFilterData(data); // PT: this one doesn't need double-buffering + + updatePvdProperties(mShape); +} + +PxFilterData NpShape::getQueryFilterData() const +{ + NP_READ_CHECK(getOwnerScene()); + + return getQueryFilterDataFast(); +} + +/////////////////////////////////////////////////////////////////////////////// + +void NpShape::setMaterials(PxMaterial*const* materials, PxU16 materialCount) +{ + NP_WRITE_CHECK(getOwnerScene()); + PX_CHECK_AND_RETURN(isWritable(), "PxShape::setMaterials: shared shapes attached to actors are not writable."); + +#if PX_CHECKED + if (!NpShape::checkMaterialSetup(mShape.getGeometry(), "PxShape::setMaterials()", materials, materialCount)) + return; +#endif + + PxU32 oldMaterialCount = mShape.getNbMaterials(); + PX_ALLOCA(oldMaterials, PxMaterial*, oldMaterialCount); + PxU32 tmp = mShape.getMaterials(oldMaterials, oldMaterialCount); + PX_ASSERT(tmp == oldMaterialCount); + PX_UNUSED(tmp); + + if (mShape.setMaterials(materials, materialCount)) + { + for(PxU32 i=0; i < materialCount; i++) + static_cast<NpMaterial*>(materials[i])->incRefCount(); + + for(PxU32 i=0; i < oldMaterialCount; i++) + static_cast<NpMaterial*>(oldMaterials[i])->decRefCount(); + } +} + +PxU16 NpShape::getNbMaterials() const +{ + NP_READ_CHECK(getOwnerScene()); + + return mShape.getNbMaterials(); +} + +PxU32 NpShape::getMaterials(PxMaterial** userBuffer, PxU32 bufferSize, PxU32 startIndex) const +{ + NP_READ_CHECK(getOwnerScene()); + + return mShape.getMaterials(userBuffer, bufferSize, startIndex); +} + +PxMaterial* NpShape::getMaterialFromInternalFaceIndex(PxU32 faceIndex) const +{ + NP_READ_CHECK(getOwnerScene()); + + bool isHf = (getGeometryType() == PxGeometryType::eHEIGHTFIELD); + bool isMesh = (getGeometryType() == PxGeometryType::eTRIANGLEMESH); + if( faceIndex == 0xFFFFffff && (isHf || isMesh) ) + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, + "PxShape::getMaterialFromInternalFaceIndex received 0xFFFFffff as input - returning NULL."); + return NULL; + } + + PxMaterialTableIndex hitMatTableId = 0; + + if(isHf) + { + PxHeightFieldGeometry hfGeom; + getHeightFieldGeometry(hfGeom); + + hitMatTableId = hfGeom.heightField->getTriangleMaterialIndex(faceIndex); + } + else if(isMesh) + { + PxTriangleMeshGeometry triGeo; + getTriangleMeshGeometry(triGeo); + + Gu::TriangleMesh* tm = static_cast<Gu::TriangleMesh*>(triGeo.triangleMesh); + if(tm->hasPerTriangleMaterials()) + hitMatTableId = triGeo.triangleMesh->getTriangleMaterialIndex(faceIndex); + } + + return getMaterial(hitMatTableId); +} + +void NpShape::setContactOffset(PxReal contactOffset) +{ + NP_WRITE_CHECK(getOwnerScene()); + + PX_CHECK_AND_RETURN(PxIsFinite(contactOffset), "PxShape::setContactOffset: invalid float"); + PX_CHECK_AND_RETURN((contactOffset >= 0.0f && contactOffset > mShape.getRestOffset()), "PxShape::setContactOffset: contactOffset should be positive, and greater than restOffset!"); + PX_CHECK_AND_RETURN(isWritable(), "PxShape::setContactOffset: shared shapes attached to actors are not writable."); + + mShape.setContactOffset(contactOffset); +} + +PxReal NpShape::getContactOffset() const +{ + NP_READ_CHECK(getOwnerScene()); + + return mShape.getContactOffset(); +} + +void NpShape::setRestOffset(PxReal restOffset) +{ + NP_WRITE_CHECK(getOwnerScene()); + PX_CHECK_AND_RETURN(PxIsFinite(restOffset), "PxShape::setRestOffset: invalid float"); + PX_CHECK_AND_RETURN((restOffset < mShape.getContactOffset()), "PxShape::setRestOffset: restOffset should be less than contactOffset!"); + PX_CHECK_AND_RETURN(isWritable(), "PxShape::setRestOffset: shared shapes attached to actors are not writable."); + + mShape.setRestOffset(restOffset); +} + +PxReal NpShape::getRestOffset() const +{ + NP_READ_CHECK(getOwnerScene()); + + return mShape.getRestOffset(); +} + +void NpShape::setFlagsInternal(PxShapeFlags inFlags) +{ + const bool hasMeshTypeGeom = mShape.getGeometryType() == PxGeometryType::eTRIANGLEMESH || mShape.getGeometryType() == PxGeometryType::eHEIGHTFIELD; + + if(hasMeshTypeGeom && (inFlags & PxShapeFlag::eTRIGGER_SHAPE)) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, + "PxShape::setFlag(s): triangle mesh and heightfield triggers are not supported!"); + return; + } + + if((inFlags & PxShapeFlag::eSIMULATION_SHAPE) && (inFlags & PxShapeFlag::eTRIGGER_SHAPE)) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, + "PxShape::setFlag(s): shapes cannot simultaneously be trigger shapes and simulation shapes."); + return; + } + + const PxShapeFlags oldFlags = mShape.getFlags(); + + const bool oldIsSimShape = oldFlags & PxShapeFlag::eSIMULATION_SHAPE; + const bool isSimShape = inFlags & PxShapeFlag::eSIMULATION_SHAPE; + + if(mActor) + { + const PxType type = mActor->getConcreteType(); + + // PT: US5732 - support kinematic meshes + bool isKinematic = false; + if(type==PxConcreteType::eRIGID_DYNAMIC) + { + PxRigidDynamic* rigidDynamic = static_cast<PxRigidDynamic*>(mActor); + isKinematic = rigidDynamic->getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC; + } + + if((type != PxConcreteType::eRIGID_STATIC) && !isKinematic && isSimShape && !oldIsSimShape && (hasMeshTypeGeom || mShape.getGeometryType() == PxGeometryType::ePLANE)) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, + "PxShape::setFlag(s): triangle mesh, heightfield and plane shapes can only be simulation shapes if part of a PxRigidStatic!"); + return; + } + } + + const bool oldHasSceneQuery = oldFlags & PxShapeFlag::eSCENE_QUERY_SHAPE; + const bool hasSceneQuery = inFlags & PxShapeFlag::eSCENE_QUERY_SHAPE; + + mShape.setFlags(inFlags); + + if(oldHasSceneQuery != hasSceneQuery && mActor) + { + NpScene* npScene = getAPIScene(); + NpShapeManager* shapeManager = NpActor::getShapeManager(*mActor); + if(npScene) + { + if(hasSceneQuery) + shapeManager->setupSceneQuery(npScene->getSceneQueryManagerFast(), *mActor, *this); + else + shapeManager->teardownSceneQuery(npScene->getSceneQueryManagerFast(), *this); + } + + // invalidate the pruning structure if the actor bounds changed + if(shapeManager->getPruningStructure()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxShape::setFlag: Shape is a part of pruning structure, pruning structure is now invalid!"); + shapeManager->getPruningStructure()->invalidate(mActor); + } + } +} + +void NpShape::setFlag(PxShapeFlag::Enum flag, bool value) +{ + NP_WRITE_CHECK(getOwnerScene()); + PX_CHECK_AND_RETURN(isWritable(), "PxShape::setFlag: shared shapes attached to actors are not writable."); + PX_SIMD_GUARD; + + PxShapeFlags shapeFlags = mShape.getFlags(); + shapeFlags = value ? shapeFlags | flag : shapeFlags & ~flag; + + setFlagsInternal(shapeFlags); +} + +void NpShape::setFlags( PxShapeFlags inFlags ) +{ + NP_WRITE_CHECK(getOwnerScene()); + PX_SIMD_GUARD; + + setFlagsInternal(inFlags); +} + +PxShapeFlags NpShape::getFlags() const +{ + NP_READ_CHECK(getOwnerScene()); + return mShape.getFlags(); +} + +bool NpShape::isExclusive() const +{ + NP_READ_CHECK(getOwnerScene()); + return (mExclusiveAndActorCount & EXCLUSIVE_MASK) != 0; +} + +void NpShape::onActorAttach(PxRigidActor& actor) +{ + incRefCount(); + if(isExclusiveFast()) + mActor = &actor; + Ps::atomicIncrement(&mExclusiveAndActorCount); +} + +void NpShape::onActorDetach() +{ + PX_ASSERT(getActorCount() > 0); + Ps::atomicDecrement(&mExclusiveAndActorCount); + if(isExclusiveFast()) + mActor = NULL; + decRefCount(); +} + +void NpShape::setName(const char* debugName) +{ + NP_WRITE_CHECK(getOwnerScene()); + PX_CHECK_AND_RETURN(isWritable(), "PxShape::setName: shared shapes attached to actors are not writable."); + + mName = debugName; + + updatePvdProperties(mShape); +} + +const char* NpShape::getName() const +{ + NP_READ_CHECK(getOwnerScene()); + + return mName; +} + +NpScene* NpShape::getOwnerScene() const +{ + return mActor ? NpActor::getOwnerScene(*mActor) : NULL; +} + +NpScene* NpShape::getAPIScene() const +{ + // gets called when we update SQ structures due to a write - in which case there must be an actor + PX_ASSERT(mActor); + return NpActor::getAPIScene(*mActor); +} + +/////////////////////////////////////////////////////////////////////////////// + +namespace physx +{ +Sc::RigidCore* NpShapeGetScRigidObjectFromScbSLOW(const Scb::Shape &scb) +{ + const NpShape* np = getNpShape(&scb); + return np->NpShape::getActor() ? &np->getScRigidObjectExclusive() : NULL; +} + +size_t NpShapeGetScPtrOffset() +{ + const size_t offset = size_t(&(reinterpret_cast<NpShape*>(0)->getScbShape().getScShape())); + return offset; +} + +void NpShapeIncRefCount(Scb::Shape& scb) +{ + NpShape* np = const_cast<NpShape*>(getNpShape(&scb)); + np->incRefCount(); +} + +void NpShapeDecRefCount(Scb::Shape& scb) +{ + NpShape* np = const_cast<NpShape*>(getNpShape(&scb)); + np->decRefCount(); +} +} + +// see NpConvexMesh.h, NpHeightField.h, NpTriangleMesh.h for details on how ref counting works +// for meshes +Cm::RefCountable* NpShape::getMeshRefCountable() +{ + switch(mShape.getGeometryType()) + { + case PxGeometryType::eCONVEXMESH: + return static_cast<Gu::ConvexMesh*>( + static_cast<const PxConvexMeshGeometry&>(mShape.getGeometry()).convexMesh); + + case PxGeometryType::eHEIGHTFIELD: + return static_cast<Gu::HeightField*>( + static_cast<const PxHeightFieldGeometry&>(mShape.getGeometry()).heightField); + + case PxGeometryType::eTRIANGLEMESH: + return static_cast<Gu::TriangleMesh*>( + static_cast<const PxTriangleMeshGeometry&>(mShape.getGeometry()).triangleMesh); + + case PxGeometryType::eSPHERE: + case PxGeometryType::ePLANE: + case PxGeometryType::eCAPSULE: + case PxGeometryType::eBOX: + case PxGeometryType::eGEOMETRY_COUNT: + case PxGeometryType::eINVALID: + break; + } + return NULL; +} + +bool NpShape::isWritable() +{ + // a shape is writable if it's exclusive, or it's not connected to any actors (which is true if the ref count is 1 and the user ref is not released.) + return isExclusiveFast() || (getRefCount()==1 && (mBaseFlags & PxBaseFlag::eIS_RELEASABLE)); +} + +void NpShape::incMeshRefCount() +{ + Cm::RefCountable* npMesh = getMeshRefCountable(); + if(npMesh) + npMesh->incRefCount(); +} + +void NpShape::decMeshRefCount() +{ + Cm::RefCountable* npMesh = getMeshRefCountable(); + if(npMesh) + npMesh->decRefCount(); +} + +bool NpShape::checkMaterialSetup(const PxGeometry& geom, const char* errorMsgPrefix, PxMaterial*const* materials, PxU16 materialCount) +{ + for(PxU32 i=0; i<materialCount; ++i) + { + if(!materials[i]) + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, + "material pointer %d is NULL!", i); + return false; + } + } + + // check that simple shapes don't get assigned multiple materials + if (materialCount > 1 && (geom.getType() != PxGeometryType::eHEIGHTFIELD) && (geom.getType() != PxGeometryType::eTRIANGLEMESH)) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, + "%s: multiple materials defined for single material geometry!", errorMsgPrefix); + return false; + } + + // verify we provide all materials required + if (materialCount > 1 && (geom.getType() == PxGeometryType::eTRIANGLEMESH)) + { + const PxTriangleMeshGeometry& meshGeom = static_cast<const PxTriangleMeshGeometry&>(geom); + const PxTriangleMesh& mesh = *meshGeom.triangleMesh; + if(mesh.getTriangleMaterialIndex(0) != 0xffff) + { + for(PxU32 i = 0; i < mesh.getNbTriangles(); i++) + { + const PxMaterialTableIndex meshMaterialIndex = mesh.getTriangleMaterialIndex(i); + if(meshMaterialIndex >= materialCount) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, + "%s: PxTriangleMesh material indices reference more materials than provided!", errorMsgPrefix); + break; + } + } + } + } + if (materialCount > 1 && (geom.getType() == PxGeometryType::eHEIGHTFIELD)) + { + const PxHeightFieldGeometry& meshGeom = static_cast<const PxHeightFieldGeometry&>(geom); + const PxHeightField& mesh = *meshGeom.heightField; + if(mesh.getTriangleMaterialIndex(0) != 0xffff) + { + const PxU32 nbTris = (mesh.getNbColumns() - 1)*(mesh.getNbColumns() - 1)*2; + for(PxU32 i = 0; i < nbTris; i++) + { + const PxMaterialTableIndex meshMaterialIndex = mesh.getTriangleMaterialIndex(i); + if(meshMaterialIndex >= materialCount) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, + "%s: PxHeightField material indices reference more materials than provided!", errorMsgPrefix); + break; + } + } + } + } + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +#if PX_ENABLE_DEBUG_VISUALIZATION +#include "GuDebug.h" + +void NpShape::visualize(Cm::RenderOutput& out, const PxRigidActor& actor) +{ + NpScene* npScene = NpActor::getOwnerScene(actor); + PX_ASSERT(npScene); + + const PxReal scale = npScene->getVisualizationParameter(PxVisualizationParameter::eSCALE); + if(!scale) return; + + const PxTransform absPose = actor.getGlobalPose() * mShape.getShape2Actor(); + + if(npScene->getVisualizationParameter(PxVisualizationParameter::eCOLLISION_AABBS)) + out << PxU32(PxDebugColor::eARGB_YELLOW) << PxMat44(PxIdentity) << Cm::DebugBox(Gu::computeBounds(mShape.getGeometry(), absPose, !gUnifiedHeightfieldCollision)); + + const PxReal collisionAxes = scale * npScene->getVisualizationParameter(PxVisualizationParameter::eCOLLISION_AXES); + if(collisionAxes != 0.0f) + out << PxMat44(absPose) << Cm::DebugBasis(PxVec3(collisionAxes), 0xcf0000, 0x00cf00, 0x0000cf); + + if( npScene->getVisualizationParameter(PxVisualizationParameter::eCOLLISION_SHAPES) || + npScene->getVisualizationParameter(PxVisualizationParameter::eCOLLISION_FNORMALS) || + npScene->getVisualizationParameter(PxVisualizationParameter::eCOLLISION_EDGES)) + { + const PxBounds3& cullbox = npScene->getVisualizationCullingBox(); + + const PxReal fscale = scale * npScene->getVisualizationParameter(PxVisualizationParameter::eCOLLISION_FNORMALS); + + // Pack bool params into bit mask. + PxU64 mask = 0; + + #define SET_MASK(mask, param) (mask |= (PxU64(!!npScene->getVisualizationParameter(param))) << param) + + SET_MASK(mask, PxVisualizationParameter::eCULL_BOX); + SET_MASK(mask, PxVisualizationParameter::eCOLLISION_FNORMALS); + SET_MASK(mask, PxVisualizationParameter::eCOLLISION_EDGES); + SET_MASK(mask, PxVisualizationParameter::eCOLLISION_SHAPES); + + Sc::ShapeCore& shape = mShape.getScShape(); + const PxU32 numMaterials = shape.getNbMaterialIndices(); + Gu::Debug::visualize(getGeometryFast().getGeometry(), out, absPose, cullbox, mask, fscale, numMaterials); + } +} + +#endif // PX_ENABLE_DEBUG_VISUALIZATION diff --git a/PhysX_3.4/Source/PhysX/src/NpShape.h b/PhysX_3.4/Source/PhysX/src/NpShape.h new file mode 100644 index 00000000..fb2b4e2a --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpShape.h @@ -0,0 +1,216 @@ +// 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_NP_SHAPE +#define PX_PHYSICS_NP_SHAPE + +#include "PxShape.h" +#include "buffering/ScbShape.h" +#include "PxMetaData.h" + +namespace physx +{ + +struct NpInternalShapeFlag +{ + enum Enum + { + eEXCLUSIVE = (1<<0) + }; +}; + +/** +\brief collection of set bits defined in PxShapeFlag. + +@see PxShapeFlag +*/ +typedef PxFlags<NpInternalShapeFlag::Enum,PxU8> NpInternalShapeFlags; +PX_FLAGS_OPERATORS(NpInternalShapeFlag::Enum,PxU8) + + +class NpScene; +class NpShapeManager; + +namespace Scb +{ + class Scene; + class RigidObject; +} + +namespace Sc +{ + class MaterialCore; +} + +class NpShape : public PxShape, public Ps::UserAllocated, public Cm::RefCountable +{ +//= 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 + NpShape(PxBaseFlags baseFlags); + virtual void exportExtraData(PxSerializationContext& stream); + void importExtraData(PxDeserializationContext& context); + virtual void requires(PxProcessPxBaseCallback& c); + void resolveReferences(PxDeserializationContext& context); + static NpShape* createObject(PxU8*& address, PxDeserializationContext& context); + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + NpShape(const PxGeometry& geometry, + PxShapeFlags shapeFlags, + const PxU16* materialIndices, + PxU16 materialCount, + bool isExclusive); + + virtual ~NpShape(); + + //--------------------------------------------------------------------------------- + // PxShape implementation + //--------------------------------------------------------------------------------- + virtual void release(); //!< call to release from actor + virtual void acquireReference(); + + virtual PxGeometryType::Enum getGeometryType() const; + + virtual void setGeometry(const PxGeometry&); + virtual PxGeometryHolder getGeometry() const; + virtual bool getBoxGeometry(PxBoxGeometry&) const; + virtual bool getSphereGeometry(PxSphereGeometry&) const; + virtual bool getCapsuleGeometry(PxCapsuleGeometry&) const; + virtual bool getPlaneGeometry(PxPlaneGeometry&) const; + virtual bool getConvexMeshGeometry(PxConvexMeshGeometry& g) const; + virtual bool getTriangleMeshGeometry(PxTriangleMeshGeometry& g) const; + virtual bool getHeightFieldGeometry(PxHeightFieldGeometry& g) const; + + virtual PxRigidActor* getActor() const; + + virtual void setLocalPose(const PxTransform& pose); + virtual PxTransform getLocalPose() const; + + virtual void setSimulationFilterData(const PxFilterData& data); + virtual PxFilterData getSimulationFilterData() const; + virtual void setQueryFilterData(const PxFilterData& data); + virtual PxFilterData getQueryFilterData() const; + + virtual void setMaterials(PxMaterial*const* materials, PxU16 materialCount); + virtual PxU16 getNbMaterials() const; + virtual PxU32 getMaterials(PxMaterial** userBuffer, PxU32 bufferSize, PxU32 startIndex=0) const; + virtual PxMaterial* getMaterialFromInternalFaceIndex(PxU32 faceIndex) const; + + virtual void setContactOffset(PxReal); + virtual PxReal getContactOffset() const; + + virtual void setRestOffset(PxReal); + virtual PxReal getRestOffset() const; + + virtual void setFlag(PxShapeFlag::Enum flag, bool value); + virtual void setFlags( PxShapeFlags inFlags ); + virtual PxShapeFlags getFlags() const; + + virtual bool isExclusive() const; + + virtual void setName(const char* debugName); + virtual const char* getName() const; + + //--------------------------------------------------------------------------------- + // RefCountable implementation + //--------------------------------------------------------------------------------- + + // Ref counting for shapes works like this: + // * for exclusive shapes the actor has a counted reference + // * for shared shapes, each actor has a counted reference, and the user has a counted reference + // * for either kind, each instance of the shape in a scene (i.e. each shapeSim) causes the reference count to be incremented by 1. + // Because these semantics aren't clear to users, this reference count should not be exposed in the API + + virtual void onRefCountZero(); + + //--------------------------------------------------------------------------------- + // Miscellaneous + //--------------------------------------------------------------------------------- + + void setFlagsInternal( PxShapeFlags inFlags ); + + PX_FORCE_INLINE PxShapeFlags getFlagsFast() const { return mShape.getFlags(); } + PX_FORCE_INLINE PxShapeFlags getFlagsUnbuffered() const { return mShape.getScShape().getFlags(); } + PX_FORCE_INLINE PxGeometryType::Enum getGeometryTypeFast() const { return mShape.getGeometryType(); } + PX_FORCE_INLINE const Gu::GeometryUnion& getGeometryFast() const { return mShape.getGeometryUnion(); } + PX_FORCE_INLINE const PxTransform& getLocalPoseFast() const { return mShape.getShape2Actor(); } + PX_FORCE_INLINE PxU32 getActorCount() const { return PxU32(mExclusiveAndActorCount & ACTOR_COUNT_MASK); } + PX_FORCE_INLINE PxI32 isExclusiveFast() const { return mExclusiveAndActorCount & EXCLUSIVE_MASK; } + + PX_FORCE_INLINE const PxFilterData& getQueryFilterDataFast() const + { + return mShape.getScShape().getQueryFilterData(); // PT: this one doesn't need double-buffering + } + + PX_FORCE_INLINE const Scb::Shape& getScbShape() const { return mShape; } + PX_FORCE_INLINE Scb::Shape& getScbShape() { return mShape; } + + PX_INLINE PxMaterial* getMaterial(PxU32 index) const { return mShape.getMaterial(index); } + static bool checkMaterialSetup(const PxGeometry& geom, const char* errorMsgPrefix, PxMaterial*const* materials, PxU16 materialCount); + + void onActorAttach(PxRigidActor& actor); + void onActorDetach(); + +#if PX_ENABLE_DEBUG_VISUALIZATION +public: + virtual void visualize(Cm::RenderOutput& out, const PxRigidActor& owner); +#endif + + // These methods are used only for sync'ing, and may only be called on exclusive shapes since only exclusive shapes have buffering + Sc::RigidCore& getScRigidObjectExclusive() const; + void releaseInternal(); + + NpScene* getOwnerScene() const; // same distinctions as for NpActor +private: + NpScene* getAPIScene() const; + + void incMeshRefCount(); + void decMeshRefCount(); + Cm::RefCountable* getMeshRefCountable(); + bool isWritable(); + + PxRigidActor* mActor; // Auto-resolving refs breaks DLL loading for some reason + Scb::Shape mShape; + const char* mName; + + static const PxI32 EXCLUSIVE_MASK = 0x80000000; + static const PxI32 ACTOR_COUNT_MASK = 0x7fffffff; + + volatile PxI32 mExclusiveAndActorCount; +}; + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/NpShapeManager.cpp b/PhysX_3.4/Source/PhysX/src/NpShapeManager.cpp new file mode 100644 index 00000000..ab2d6d8b --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpShapeManager.cpp @@ -0,0 +1,309 @@ +// 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 "NpShapeManager.h" +#include "NpFactory.h" +#include "ScbRigidObject.h" +#include "NpActor.h" +#include "SqSceneQueryManager.h" +#include "SqPruningStructure.h" +#include "NpScene.h" +#include "NpPtrTableStorageManager.h" +#include "GuBounds.h" +#include "CmUtils.h" + +using namespace physx; +using namespace Sq; + +namespace physx +{ + extern bool gUnifiedHeightfieldCollision; +} + +static PX_FORCE_INLINE bool isSceneQuery(const NpShape& shape) { return shape.getFlagsFast() & PxShapeFlag::eSCENE_QUERY_SHAPE; } + +NpShapeManager::NpShapeManager() + : mPruningStructure(NULL) +{ +} + +// PX_SERIALIZATION +NpShapeManager::NpShapeManager(const PxEMPTY) : + mShapes (PxEmpty), + mSceneQueryData (PxEmpty) +{ +} + +NpShapeManager::~NpShapeManager() +{ + PX_ASSERT(!mPruningStructure); + Cm::PtrTableStorageManager& sm = NpFactory::getInstance().getPtrTableStorageManager(); + mShapes.clear(sm); + mSceneQueryData.clear(sm); +} + +void NpShapeManager::exportExtraData(PxSerializationContext& stream) +{ + mShapes.exportExtraData(stream); + mSceneQueryData.exportExtraData(stream); +} + +void NpShapeManager::importExtraData(PxDeserializationContext& context) +{ + mShapes.importExtraData(context); + mSceneQueryData.importExtraData(context); +} +//~PX_SERIALIZATION + +void NpShapeManager::attachShape(NpShape& shape, PxRigidActor& actor) +{ + PX_ASSERT(!mPruningStructure); + + Cm::PtrTableStorageManager& sm = NpFactory::getInstance().getPtrTableStorageManager(); + + const PxU32 index = getNbShapes(); + mShapes.add(&shape, sm); + mSceneQueryData.add(reinterpret_cast<void*>(size_t(SQ_INVALID_PRUNER_DATA)), sm); + + NpScene* scene = NpActor::getAPIScene(actor); + if(scene && isSceneQuery(shape)) + setupSceneQuery(scene->getSceneQueryManagerFast(), actor, index); + + Scb::RigidObject& ro = static_cast<Scb::RigidObject&>(NpActor::getScbFromPxActor(actor)); + ro.onShapeAttach(shape.getScbShape()); + + PX_ASSERT(!shape.isExclusive() || shape.getActor()==NULL); + shape.onActorAttach(actor); +} + +void NpShapeManager::detachShape(NpShape& s, PxRigidActor& actor, bool wakeOnLostTouch) +{ + PX_ASSERT(!mPruningStructure); + + Cm::PtrTableStorageManager& sm = NpFactory::getInstance().getPtrTableStorageManager(); + + const PxU32 index = mShapes.find(&s); + PX_ASSERT(index!=0xffffffff); + + Scb::RigidObject& ro = static_cast<Scb::RigidObject&>(NpActor::getScbFromPxActor(actor)); + + NpScene* scene = NpActor::getAPIScene(actor); + if(scene && isSceneQuery(s)) + scene->getSceneQueryManagerFast().removePrunerShape(getPrunerData(index)); + + Scb::Shape& scbShape = s.getScbShape(); + ro.onShapeDetach(scbShape, wakeOnLostTouch, (s.getRefCount() == 1)); + mShapes.replaceWithLast(index, sm); + mSceneQueryData.replaceWithLast(index, sm); + + s.onActorDetach(); +} + +bool NpShapeManager::shapeIsAttached(NpShape& s) const +{ + return mShapes.find(&s)!=0xffffffff; +} + +void NpShapeManager::detachAll(NpScene* scene) +{ + // assumes all SQ data has been released, which is currently the responsbility of the owning actor + const PxU32 nbShapes = getNbShapes(); + NpShape*const *shapes = getShapes(); + + if(scene) + teardownAllSceneQuery(scene->getSceneQueryManagerFast()); + + // actor cleanup in Scb/Sc will remove any outstanding references corresponding to sim objects, so we don't need to do that here. + for(PxU32 i=0;i<nbShapes;i++) + shapes[i]->onActorDetach(); + + Cm::PtrTableStorageManager& sm = NpFactory::getInstance().getPtrTableStorageManager(); + + mShapes.clear(sm); + mSceneQueryData.clear(sm); +} + +PxU32 NpShapeManager::getShapes(PxShape** buffer, PxU32 bufferSize, PxU32 startIndex) const +{ + return Cm::getArrayOfPointers(buffer, bufferSize, startIndex, getShapes(), getNbShapes()); +} + +PxBounds3 NpShapeManager::getWorldBounds(const PxRigidActor& actor) const +{ + PxBounds3 bounds(PxBounds3::empty()); + + const PxU32 nbShapes = getNbShapes(); + PxTransform actorPose = actor.getGlobalPose(); + NpShape*const* PX_RESTRICT shapes = getShapes(); + + for(PxU32 i=0;i<nbShapes;i++) + bounds.include(Gu::computeBounds(shapes[i]->getScbShape().getGeometry(), actorPose * shapes[i]->getLocalPoseFast(), !physx::gUnifiedHeightfieldCollision)); + + return bounds; +} + +void NpShapeManager::clearShapesOnRelease(Scb::Scene& s, PxRigidActor& r) +{ + PX_ASSERT(static_cast<Scb::RigidObject&>(NpActor::getScbFromPxActor(r)).isSimDisabledInternally()); + + const PxU32 nbShapes = getNbShapes(); + NpShape*const* PX_RESTRICT shapes = getShapes(); + + for(PxU32 i=0;i<nbShapes;i++) + { + Scb::Shape& scbShape = shapes[i]->getScbShape(); + scbShape.checkUpdateOnRemove<false>(&s); +#if PX_SUPPORT_PVD + s.getScenePvdClient().releasePvdInstance(&scbShape, r); +#else + PX_UNUSED(r); +#endif + } +} + +void NpShapeManager::releaseExclusiveUserReferences() +{ + // when the factory is torn down, release any shape owner refs that are still outstanding + const PxU32 nbShapes = getNbShapes(); + NpShape*const* PX_RESTRICT shapes = getShapes(); + for(PxU32 i=0;i<nbShapes;i++) + { + if(shapes[i]->isExclusiveFast() && shapes[i]->getRefCount()>1) + shapes[i]->release(); + } +} + +void NpShapeManager::setupSceneQuery(SceneQueryManager& sqManager, const PxRigidActor& actor, const NpShape& shape) +{ + PX_ASSERT(shape.getFlags() & PxShapeFlag::eSCENE_QUERY_SHAPE); + const PxU32 index = mShapes.find(&shape); + PX_ASSERT(index!=0xffffffff); + setupSceneQuery(sqManager, actor, index); +} + +void NpShapeManager::teardownSceneQuery(SceneQueryManager& sqManager, const NpShape& shape) +{ + const PxU32 index = mShapes.find(&shape); + PX_ASSERT(index!=0xffffffff); + teardownSceneQuery(sqManager, index); +} + +void NpShapeManager::setupAllSceneQuery(NpScene* scene, const PxRigidActor& actor, bool hasPrunerStructure, const PxBounds3* bounds) +{ + PX_ASSERT(scene); // shouldn't get here unless we're in a scene + SceneQueryManager& sqManager = scene->getSceneQueryManagerFast(); + + const PxU32 nbShapes = getNbShapes(); + NpShape*const *shapes = getShapes(); + + const PxType actorType = actor.getConcreteType(); + const bool isDynamic = actorType == PxConcreteType::eRIGID_DYNAMIC || actorType == PxConcreteType::eARTICULATION_LINK; + + for(PxU32 i=0;i<nbShapes;i++) + { + if(isSceneQuery(*shapes[i])) + setPrunerData(i, sqManager.addPrunerShape(*shapes[i], actor, isDynamic, bounds ? bounds + i : NULL, hasPrunerStructure)); + } +} + +void NpShapeManager::teardownAllSceneQuery(SceneQueryManager& sqManager) +{ + NpShape*const *shapes = getShapes(); + const PxU32 nbShapes = getNbShapes(); + + for(PxU32 i=0;i<nbShapes;i++) + { + if(isSceneQuery(*shapes[i])) + sqManager.removePrunerShape(getPrunerData(i)); + + setPrunerData(i, SQ_INVALID_PRUNER_DATA); + } +} + +void NpShapeManager::markAllSceneQueryForUpdate(SceneQueryManager& sqManager) +{ + const PxU32 nbShapes = getNbShapes(); + + for(PxU32 i=0;i<nbShapes;i++) + { + const PrunerData data = getPrunerData(i); + if(data!=SQ_INVALID_PRUNER_DATA) + sqManager.markForUpdate(data); + } +} + +Sq::PrunerData NpShapeManager::findSceneQueryData(const NpShape& shape) const +{ + const PxU32 index = mShapes.find(&shape); + PX_ASSERT(index!=0xffffffff); + + return getPrunerData(index); +} + +// +// internal methods +// + +void NpShapeManager::setupSceneQuery(SceneQueryManager& sqManager, const PxRigidActor& actor, PxU32 index) +{ + const PxType actorType = actor.getConcreteType(); + const bool isDynamic = actorType == PxConcreteType::eRIGID_DYNAMIC || actorType == PxConcreteType::eARTICULATION_LINK; + setPrunerData(index, sqManager.addPrunerShape(*(getShapes()[index]), actor, isDynamic)); +} + +void NpShapeManager::teardownSceneQuery(SceneQueryManager& sqManager, PxU32 index) +{ + sqManager.removePrunerShape(getPrunerData(index)); + setPrunerData(index, SQ_INVALID_PRUNER_DATA); +} + +#if PX_ENABLE_DEBUG_VISUALIZATION +void NpShapeManager::visualize(Cm::RenderOutput& out, NpScene* scene, const PxRigidActor& actor) +{ + const PxU32 nbShapes = getNbShapes(); + NpShape*const* PX_RESTRICT shapes = getShapes(); + PxTransform actorPose = actor.getGlobalPose(); + + const bool visualizeCompounds = (nbShapes>1) && scene->getVisualizationParameter(PxVisualizationParameter::eCOLLISION_COMPOUNDS)!=0.0f; + + PxBounds3 compoundBounds(PxBounds3::empty()); + for(PxU32 i=0;i<nbShapes;i++) + { + Scb::Shape& shape = shapes[i]->getScbShape(); + if(shape.getFlags() & PxShapeFlag::eVISUALIZATION) + { + shapes[i]->visualize(out, actor); + if(visualizeCompounds) + compoundBounds.include(Gu::computeBounds(shape.getGeometry(), actorPose*shapes[i]->getLocalPose(), !physx::gUnifiedHeightfieldCollision)); + } + } + if(visualizeCompounds && !compoundBounds.isEmpty()) + out << PxU32(PxDebugColor::eARGB_MAGENTA) << PxMat44(PxIdentity) << Cm::DebugBox(compoundBounds); +} +#endif // PX_ENABLE_DEBUG_VISUALIZATION diff --git a/PhysX_3.4/Source/PhysX/src/NpShapeManager.h b/PhysX_3.4/Source/PhysX/src/NpShapeManager.h new file mode 100644 index 00000000..d7d22ea6 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpShapeManager.h @@ -0,0 +1,126 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + + +#ifndef PX_PHYSICS_NP_SHAPE_MANAGER +#define PX_PHYSICS_NP_SHAPE_MANAGER + +#include "NpShape.h" +#include "CmPtrTable.h" + +#if PX_ENABLE_DEBUG_VISUALIZATION +#include "CmRenderOutput.h" +#endif + +namespace physx +{ + +namespace Sq +{ + typedef size_t PrunerData; + class SceneQueryManager; + class PruningStructure; +} + +class NpScene; + +class NpShapeManager : public Ps::UserAllocated +{ +//= ATTENTION! ===================================================================================== +// Changing the data layout of this class breaks the binary serialization format. See comments for +// PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData +// function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION +// accordingly. +//================================================================================================== +public: +// PX_SERIALIZATION + static void getBinaryMetaData(PxOutputStream& stream); + NpShapeManager(const PxEMPTY); + void exportExtraData(PxSerializationContext& stream); + void importExtraData(PxDeserializationContext& context); +//~PX_SERIALIZATION + NpShapeManager(); + ~NpShapeManager(); + + PX_FORCE_INLINE PxU32 getNbShapes() const { return mShapes.getCount(); } + PX_FORCE_INLINE NpShape* const* getShapes() const { return reinterpret_cast<NpShape*const*>(mShapes.getPtrs()); } + PxU32 getShapes(PxShape** buffer, PxU32 bufferSize, PxU32 startIndex=0) const; + + void attachShape(NpShape& shape, PxRigidActor& actor); + void detachShape(NpShape& s, PxRigidActor &actor, bool wakeOnLostTouch); + bool shapeIsAttached(NpShape& s) const; + void detachAll(NpScene *scene); + + void teardownSceneQuery(Sq::SceneQueryManager& sqManager, const NpShape& shape); + void setupSceneQuery(Sq::SceneQueryManager& sqManager, const PxRigidActor& actor, const NpShape& shape); + + PX_FORCE_INLINE void setPrunerData(PxU32 index, Sq::PrunerData data) + { + PX_ASSERT(index<getNbShapes()); + mSceneQueryData.getPtrs()[index] = reinterpret_cast<void*>(data); + } + + PX_FORCE_INLINE Sq::PrunerData getPrunerData(PxU32 index) const + { + PX_ASSERT(index<getNbShapes()); + return Sq::PrunerData(mSceneQueryData.getPtrs()[index]); + } + + void setupAllSceneQuery(NpScene* scene, const PxRigidActor& actor, bool hasPrunerStructure, const PxBounds3* bounds=NULL); + void teardownAllSceneQuery(Sq::SceneQueryManager& sqManager); + void markAllSceneQueryForUpdate(Sq::SceneQueryManager& shapeManager); + + Sq::PrunerData findSceneQueryData(const NpShape& shape) const; + + PxBounds3 getWorldBounds(const PxRigidActor&) const; + + PX_FORCE_INLINE void setPruningStructure(Sq::PruningStructure* ps) { mPruningStructure = ps; } + PX_FORCE_INLINE Sq::PruningStructure* getPruningStructure() const { return mPruningStructure; } + + void clearShapesOnRelease(Scb::Scene& s, PxRigidActor&); + void releaseExclusiveUserReferences(); + +#if PX_ENABLE_DEBUG_VISUALIZATION + void visualize(Cm::RenderOutput& out, NpScene* scene, const PxRigidActor& actor); +#endif + // for batching + PX_FORCE_INLINE const Cm::PtrTable& getShapeTable() const { return mShapes; } +protected: + void setupSceneQuery(Sq::SceneQueryManager& sqManager, const PxRigidActor& actor, PxU32 index); + void teardownSceneQuery(Sq::SceneQueryManager& sqManager, PxU32 index); + + // PT: TODO: revisit this. We don't need two arrays. + Cm::PtrTable mShapes; + Cm::PtrTable mSceneQueryData; // 1-1 correspondence with shapes - TODO: allocate on scene insertion or combine with the shape array for better caching + Sq::PruningStructure* mPruningStructure; // Shape scene query data are pre-build in pruning structure +}; + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/NpSpatialIndex.cpp b/PhysX_3.4/Source/PhysX/src/NpSpatialIndex.cpp new file mode 100644 index 00000000..bda0b2ff --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpSpatialIndex.cpp @@ -0,0 +1,221 @@ +// 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 "NpSpatialIndex.h" +#include "PsFPU.h" +#include "SqPruner.h" +#include "PxBoxGeometry.h" +#include "PsFoundation.h" +#include "GuBounds.h" + +using namespace physx; +using namespace Sq; +using namespace Gu; + +NpSpatialIndex::NpSpatialIndex() +: mPendingUpdates(false) +{ + mPruner = createAABBPruner(true); +} + +NpSpatialIndex::~NpSpatialIndex() +{ + PX_DELETE(mPruner); +} + +PxSpatialIndexItemId NpSpatialIndex::insert(PxSpatialIndexItem& item, + const PxBounds3& bounds) +{ + PX_SIMD_GUARD; + PX_CHECK_AND_RETURN_VAL(bounds.isValid(), "PxSpatialIndex::insert: bounds are not valid.", PX_SPATIAL_INDEX_INVALID_ITEM_ID); + + PrunerHandle output; + PrunerPayload payload; + payload.data[0] = reinterpret_cast<size_t>(&item); + mPruner->addObjects(&output, &bounds, &payload); + mPendingUpdates = true; + return output; +} + +void NpSpatialIndex::update(PxSpatialIndexItemId id, + const PxBounds3& bounds) +{ + PX_SIMD_GUARD; + PX_CHECK_AND_RETURN(bounds.isValid(), "PxSpatialIndex::update: bounds are not valid."); + + mPruner->updateObjects(&id, &bounds); + mPendingUpdates = true; +} + +void NpSpatialIndex::remove(PxSpatialIndexItemId id) +{ + PX_SIMD_GUARD; + + mPruner->removeObjects(&id); + mPendingUpdates = true; +} + +PxBounds3 NpSpatialIndex::getBounds(PxSpatialIndexItemId /*id*/) const +{ + return PxBounds3(); +} + +namespace +{ + struct OverlapCallback: public PrunerCallback + { + OverlapCallback(PxSpatialOverlapCallback& callback) : mUserCallback(callback) {} + + virtual PxAgain invoke(PxReal& /*distance*/, const PrunerPayload& userData) + { + PxSpatialIndexItem& item = *reinterpret_cast<PxSpatialIndexItem*>(userData.data[0]); + return mUserCallback.onHit(item); + } + + PxSpatialOverlapCallback &mUserCallback; + private: + OverlapCallback& operator=(const OverlapCallback&); + }; + + struct LocationCallback: public PrunerCallback + { + LocationCallback(PxSpatialLocationCallback& callback) : mUserCallback(callback) {} + + virtual PxAgain invoke(PxReal& distance, const PrunerPayload& userData) + { + PxReal oldDistance = distance, shrunkDistance = distance; + PxSpatialIndexItem& item = *reinterpret_cast<PxSpatialIndexItem*>(userData.data[0]); + PxAgain result = mUserCallback.onHit(item, distance, shrunkDistance); + + if(shrunkDistance>distance) + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxSpatialLocationCallback: distance may not be extended."); + + if(!result) + return false; + + distance = PxMin(oldDistance, distance); + return true; + } + + PxSpatialLocationCallback& mUserCallback; + + private: + LocationCallback& operator=(const LocationCallback&); + }; +} + +void NpSpatialIndex::flushUpdates() const +{ + if(mPendingUpdates) + mPruner->commit(); + mPendingUpdates = false; +} + +void NpSpatialIndex::overlap(const PxBounds3& aabb, + PxSpatialOverlapCallback& callback) const +{ + PX_SIMD_GUARD; + PX_CHECK_AND_RETURN(aabb.isValid(), "PxSpatialIndex::overlap: aabb is not valid."); + + flushUpdates(); + OverlapCallback cb(callback); + PxBoxGeometry boxGeom(aabb.getExtents()); + PxTransform xf(aabb.getCenter()); + ShapeData shapeData(boxGeom, xf, 0.0f); // temporary rvalue not compatible with PX_NOCOPY + mPruner->overlap(shapeData, cb); +} + +void NpSpatialIndex::raycast(const PxVec3& origin, + const PxVec3& unitDir, + PxReal maxDist, + PxSpatialLocationCallback& callback) const +{ + PX_SIMD_GUARD; + + PX_CHECK_AND_RETURN(origin.isFinite(), "PxSpatialIndex::raycast: origin is not valid."); + PX_CHECK_AND_RETURN(unitDir.isFinite() && unitDir.isNormalized(), "PxSpatialIndex::raycast: unitDir is not valid."); + PX_CHECK_AND_RETURN(maxDist > 0.0f, "PxSpatialIndex::raycast: distance must be positive"); + + flushUpdates(); + LocationCallback cb(callback); + mPruner->raycast(origin, unitDir, maxDist, cb); +} + +void NpSpatialIndex::sweep(const PxBounds3& aabb, + const PxVec3& unitDir, + PxReal maxDist, + PxSpatialLocationCallback& callback) const +{ + PX_SIMD_GUARD; + + PX_CHECK_AND_RETURN(aabb.isValid(), "PxSpatialIndex::sweep: aabb is not valid."); + PX_CHECK_AND_RETURN(unitDir.isFinite() && unitDir.isNormalized(), "PxSpatialIndex::sweep: unitDir is not valid."); + PX_CHECK_AND_RETURN(maxDist > 0.0f, "PxSpatialIndex::sweep: distance must be positive"); + + flushUpdates(); + LocationCallback cb(callback); + PxBoxGeometry boxGeom(aabb.getExtents()); + PxTransform xf(aabb.getCenter()); + ShapeData shapeData(boxGeom, xf, 0.0f); // temporary rvalue not compatible with PX_NOCOPY + mPruner->sweep(shapeData, unitDir, maxDist, cb); +} + + +void NpSpatialIndex::rebuildFull() +{ + PX_SIMD_GUARD; + + mPruner->purge(); + mPruner->commit(); + mPendingUpdates = false; +} + +void NpSpatialIndex::setIncrementalRebuildRate(PxU32 rate) +{ + mPruner->setRebuildRateHint(rate); +} + +void NpSpatialIndex::rebuildStep() +{ + PX_SIMD_GUARD; + mPruner->buildStep(); + mPendingUpdates = true; +} + +void NpSpatialIndex::release() +{ + delete this; +} + + +PxSpatialIndex* physx::PxCreateSpatialIndex() +{ + return PX_NEW(NpSpatialIndex)(); +} + diff --git a/PhysX_3.4/Source/PhysX/src/NpSpatialIndex.h b/PhysX_3.4/Source/PhysX/src/NpSpatialIndex.h new file mode 100644 index 00000000..4d46f006 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpSpatialIndex.h @@ -0,0 +1,92 @@ +// 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 NP_SPATIALINDEX +#define NP_SPATIALINDEX + +#include "PxSpatialIndex.h" +#include "PsUserAllocated.h" +#include "CmPhysXCommon.h" + +namespace physx +{ +namespace Sq +{ + class IncrementalPruner; +} + +class NpSpatialIndex: public PxSpatialIndex, public Ps::UserAllocated +{ +public: + NpSpatialIndex(); + ~NpSpatialIndex(); + + virtual PxSpatialIndexItemId insert(PxSpatialIndexItem& item, + const PxBounds3& bounds); + + virtual void update(PxSpatialIndexItemId id, + const PxBounds3& bounds); + + virtual void remove(PxSpatialIndexItemId id); + + virtual PxBounds3 getBounds(PxSpatialIndexItemId id) const; + + virtual void overlap(const PxBounds3& aabb, + PxSpatialOverlapCallback& callback) const; + + virtual void raycast(const PxVec3& origin, + const PxVec3& unitDir, + PxReal maxDist, + PxSpatialLocationCallback& callback) const; + + virtual void sweep(const PxBounds3& aabb, + const PxVec3& unitDir, + PxReal maxDist, + PxSpatialLocationCallback& callback) const; + + virtual void flush() { flushUpdates(); } + virtual void rebuildFull(); + virtual void setIncrementalRebuildRate(PxU32 rate); + virtual void rebuildStep(); + virtual void release(); +private: + + // const so that we can call it from const methods + void flushUpdates() const; + + mutable bool mPendingUpdates; + Sq::IncrementalPruner* mPruner; +}; + + +} +#endif + + diff --git a/PhysX_3.4/Source/PhysX/src/NpVolumeCache.cpp b/PhysX_3.4/Source/PhysX/src/NpVolumeCache.cpp new file mode 100644 index 00000000..35b7e5d9 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpVolumeCache.cpp @@ -0,0 +1,806 @@ +// 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 "NpVolumeCache.h" +#include "SqSceneQueryManager.h" +#include "GuBounds.h" +#include "PxRigidActor.h" +#include "GuRaycastTests.h" +#include "PxGeometryQuery.h" +#include "GuIntersectionRayBox.h" +#include "NpQueryShared.h" +#include "NpSceneQueries.h" +#include "PsFoundation.h" + +namespace physx { + +using namespace Sq; +using namespace Gu; + +static PX_FORCE_INLINE NpScene* getNpScene(SceneQueryManager* sqm) +{ + return const_cast<NpScene*>(getNpScene(&sqm->getScene())); +} + +//======================================================================================================================== +NpVolumeCache::NpVolumeCache(Sq::SceneQueryManager* sqm, PxU32 maxStaticShapes, PxU32 maxDynamicShapes) + : mSQManager(sqm) +{ + mCacheVolume.any() = InvalidGeometry(); + mMaxShapeCount[0] = maxStaticShapes; + mMaxShapeCount[1] = maxDynamicShapes; + mIsInvalid[0] = mIsInvalid[1] = true; + mCache[0].reserve(maxStaticShapes); + mCache[1].reserve(maxDynamicShapes); +} + +//======================================================================================================================== +NpVolumeCache::~NpVolumeCache() +{ +} + +//======================================================================================================================== +void NpVolumeCache::invalidate() +{ + mCacheVolume.any() = InvalidGeometry(); + mCache[0].clear(); + mCache[1].clear(); + mIsInvalid[0] = mIsInvalid[1] = true; +} + +//======================================================================================================================== +void NpVolumeCache::release() +{ + getNpScene(mSQManager)->releaseVolumeCache(this); +} + +//======================================================================================================================== +PxI32 NpVolumeCache::getNbCachedShapes() +{ + if(!isValid()) + return -1; + return PxI32(mCache[0].size()+mCache[1].size()); +} + +//======================================================================================================================== +bool NpVolumeCache::isValid() const +{ + if(mIsInvalid[0] || mIsInvalid[1]) + return false; + + return mSQManager->get(PruningIndex::eSTATIC).timestamp() == mStaticTimestamp && mSQManager->get(PruningIndex::eDYNAMIC).timestamp() == mDynamicTimestamp; +} + +//======================================================================================================================== +bool NpVolumeCache::isValid(PxU32 isDynamic) const +{ + if(mIsInvalid[isDynamic]) + return false; + + return isDynamic ? + (mSQManager->get(PruningIndex::eDYNAMIC).timestamp() == mDynamicTimestamp) : (mSQManager->get(PruningIndex::eSTATIC).timestamp() == mStaticTimestamp); +} + +//======================================================================================================================== +// PT: TODO: replace this with just holder.storeAny() when/if we can support convexes +static PX_INLINE bool geometryToHolder(const PxGeometry& geometry, PxGeometryHolder& holder) +{ + holder.any() = geometry; // this just copies the type, so that later holder.box() etc don't assert. Awkward but works. + switch ( geometry.getType() ) + { + case PxGeometryType::eBOX: + holder.box() = static_cast<const PxBoxGeometry&>( geometry ); + break; + case PxGeometryType::eSPHERE: + holder.sphere() = static_cast<const PxSphereGeometry&>( geometry ); + break; + case PxGeometryType::eCAPSULE: + holder.capsule() = static_cast<const PxCapsuleGeometry&>( geometry ); + break; + // convexes are not supported for now. The rationale is unknown utility + // and we need to correctly handle refcounts on a convex mesh (and write unit tests for that) + //case PxGeometryType::eCONVEXMESH: + // holder.convexMesh() = static_cast<const PxConvexMeshGeometry&>( geometry ); + // break; + case PxGeometryType::ePLANE: + case PxGeometryType::eCONVEXMESH: + case PxGeometryType::eTRIANGLEMESH: + case PxGeometryType::eHEIGHTFIELD: + case PxGeometryType::eGEOMETRY_COUNT: + case PxGeometryType::eINVALID: + holder.any() = InvalidGeometry(); + return false; + } + + return true; +} + +//======================================================================================================================== +PxVolumeCache::FillStatus NpVolumeCache::fill(const PxGeometry& cacheVolume, const PxTransform& pose) +{ + PX_CHECK_AND_RETURN_VAL(pose.isSane(), "Invalid pose in PxVolumeCache::fill()", FILL_UNSUPPORTED_GEOMETRY_TYPE); + + // save the cache volume pose into a cache pose + mCachePose = pose; + + // save the provided geometry arg in mCacheVolume + // try to convert geometry to holder, if fails mark the cache as invalid and notify the user about unsupported geometry type + if(!geometryToHolder(cacheVolume, mCacheVolume)) + { + physx::shdfnd::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, + "PxVolumeCache::fill(): unsupported cache volume geometry type."); + mIsInvalid[0] = mIsInvalid[1] = true; + return FILL_UNSUPPORTED_GEOMETRY_TYPE; + } + + mIsInvalid[0] = mIsInvalid[1] = true; // invalidate the cache due to volume change + + FillStatus status0 = fillInternal(0); + FillStatus status1 = fillInternal(1); + + PX_COMPILE_TIME_ASSERT(FILL_OK < FILL_OVER_MAX_COUNT && FILL_OVER_MAX_COUNT < FILL_UNSUPPORTED_GEOMETRY_TYPE); + PX_COMPILE_TIME_ASSERT(FILL_UNSUPPORTED_GEOMETRY_TYPE < FILL_OUT_OF_MEMORY); + return PxMax(status0, status1); +} + +//======================================================================================================================== +PxVolumeCache::FillStatus NpVolumeCache::fillInternal(PxU32 isDynamic, const PxOverlapHit* prefilledBuffer, PxI32 prefilledCount) +{ + PX_ASSERT(isDynamic == 0 || isDynamic == 1); + PX_CHECK_AND_RETURN_VAL(mCachePose.isValid(), "PxVolumeCache::fillInternal: pose is not valid.", FILL_UNSUPPORTED_GEOMETRY_TYPE); + + // allocate a buffer for temp results from SQ overlap call (or use prefilledBuffer) + const PxU32 maxStackHits = 64; + PxOverlapHit* hitBuffer = const_cast<PxOverlapHit*>(prefilledBuffer); + bool hitBufferAlloca = false; + if(prefilledBuffer == NULL) + { + if(mMaxShapeCount[isDynamic]+1 <= maxStackHits) // try allocating on the stack first if we can + { + hitBuffer = reinterpret_cast<PxOverlapHit*>(PxAlloca((mMaxShapeCount[isDynamic]+1) * sizeof(PxOverlapHit))); + hitBufferAlloca = true; + } + else + { + hitBuffer = reinterpret_cast<PxOverlapHit*>(physx::shdfnd::TempAllocator().allocate( + sizeof(PxOverlapHit) * (mMaxShapeCount[isDynamic]+1), __FILE__, __LINE__)); + if(hitBuffer == NULL) + { + mIsInvalid[isDynamic] = true; + physx::shdfnd::getFoundation().error(physx::PxErrorCode::eOUT_OF_MEMORY, __FILE__, __LINE__, + "PxVolumeCache::fill(): Fallback memory allocation failed, mMaxShapeCount = %d. Try reducing the cache size.", + mMaxShapeCount[isDynamic]); + return FILL_OUT_OF_MEMORY; + } + } + } + + // clear current cache + mCache[isDynamic].resize(0); + + // query the scene + PxI32 resultCount = prefilledCount; + PxQueryFilterData fd(isDynamic ? PxQueryFlag::eDYNAMIC : PxQueryFlag::eSTATIC); + PxOverlapBuffer sqBuffer(hitBuffer, mMaxShapeCount[isDynamic]+1); // one extra element so we can detect overflow in a single callback + if(!prefilledBuffer) + { + getNpScene(mSQManager)->overlap(mCacheVolume.any(), mCachePose, sqBuffer, fd, NULL); + resultCount = PxI32(sqBuffer.getNbAnyHits()); + } + + if(resultCount > PxI32(mMaxShapeCount[isDynamic])) + { + // cache overflow - deallocate the temp buffer + if(!hitBufferAlloca && hitBuffer != prefilledBuffer) + physx::shdfnd::TempAllocator().deallocate(hitBuffer); + mIsInvalid[isDynamic] = true; + return FILL_OVER_MAX_COUNT; + } + + // fill the cache + PX_ASSERT(resultCount <= PxI32(mMaxShapeCount[isDynamic])); + for (PxI32 iHit = 0; iHit < resultCount; iHit++) + { + PxActorShape as; + as.actor = hitBuffer[iHit].actor; + as.shape = hitBuffer[iHit].shape; + PX_ASSERT(as.actor && as.shape); + mCache[isDynamic].pushBack(as); + } + + // timestamp the cache + if(isDynamic) + mDynamicTimestamp = mSQManager->get(PruningIndex::eDYNAMIC).timestamp(); + else + mStaticTimestamp = mSQManager->get(PruningIndex::eSTATIC).timestamp(); + + // clear the invalid flag + mIsInvalid[isDynamic] = false; + + if(!hitBufferAlloca && hitBuffer != prefilledBuffer) + physx::shdfnd::TempAllocator().deallocate(hitBuffer); + + return FILL_OK; +} + +//======================================================================================================================== +bool NpVolumeCache::getCacheVolume(PxGeometryHolder& resultVolume, PxTransform& resultPose) +{ + resultVolume = mCacheVolume; + resultPose = mCachePose; + + return isValid(); +} + +//======================================================================================================================== +struct NpVolumeCacheSqCallback : PxOverlapCallback +{ + NpVolumeCache* cache; + NpVolumeCache::Iterator& iter; + PxU32 isDynamic; + PxActorShape* reportBuf; + bool reportedOverMaxCount; + + NpVolumeCacheSqCallback( + NpVolumeCache* cache_, NpVolumeCache::Iterator& iter_, + PxU32 isDynamic_, PxOverlapHit* hits, PxActorShape* reportBuf_, PxU32 maxHits) + : PxOverlapCallback(hits, maxHits), cache(cache_), iter(iter_), isDynamic(isDynamic_), + reportBuf(reportBuf_), reportedOverMaxCount(false) + {} + + virtual PxAgain processTouches(const PxOverlapHit* buffer, PxU32 nbHits) + { + // at this point we know that the callback's buffer capacity exceeds the cache max shape count by 1 + // so if nbHits is within shape count it means there will be no more callbacks. + + if(!reportedOverMaxCount && nbHits <= cache->mMaxShapeCount[isDynamic]) + { + // if actual overlapCount is under cache capacity, fill the cache + if(const_cast<NpVolumeCache*>(cache)->fillInternal(isDynamic, buffer, PxI32(nbHits)) != PxVolumeCache::FILL_OK) + // we shouldn't really end up here because we already checked all possible bad conditions fill() could return + // so the only way to end up here is if this is an error condition that should already be logged from inside fillInternal + return false; + // At this point the cache should be valid and within the user specified capacity + PX_ASSERT(cache->isValid(isDynamic)); + // break out of the loop, this will fall through to return the results from cache via iterator + + return false; + } else + { + // reroute to the user + // copy into a temp buffer for iterator reporting + for (PxU32 j = 0; j < PxU32(nbHits); j++) + { + reportBuf[j].actor = buffer[j].actor; + reportBuf[j].shape = buffer[j].shape; + } + + // invoke the iterator + iter.processShapes(nbHits, reportBuf); + reportedOverMaxCount = true; + return true; + } + } + +private: + NpVolumeCacheSqCallback& operator=(const NpVolumeCacheSqCallback&); +}; + +void NpVolumeCache::forEach(Iterator& iter) +{ + if(mCacheVolume.getType() == PxGeometryType::eINVALID) + return; // The volume wasn't set, do nothing. No results fed to the iterator. + + // keep track of whether we reported over max count shapes via callback to the user, per static/dynamic type + bool reportedOverMaxCount[2] = { false, false }; + // will be set to true if cache was overflown inside of callback + // if this flag stays at false, it means the cache was be filled and validated/timestamped + + for (PxU32 isDynamic = 0; isDynamic <= 1; isDynamic++) + { + if(isValid(isDynamic)) + continue; + + const PxU32 maxShapeCount = mMaxShapeCount[isDynamic]; + + // retrieve all the shapes overlapping with the current cache volume from the scene + // using currentTryShapeCount size temp buffer + PxQueryFilterData fd(isDynamic ? PxQueryFlag::eDYNAMIC : PxQueryFlag::eSTATIC); + + // allocate a local hit buffer, either on the stack or from temp allocator, just big enough to hold #hits=max cached shapes + PxOverlapHit* localBuffer; + PxActorShape* reportBuffer; + const PxU32 maxStackShapes = 65; + if(maxShapeCount+1 <= maxStackShapes) + { + localBuffer = reinterpret_cast<PxOverlapHit*>(PxAlloca(maxStackShapes * (sizeof(PxOverlapHit) + sizeof(PxActorShape)))); + reportBuffer = static_cast<PxActorShape*>(localBuffer + maxStackShapes); + } else + { + localBuffer = reinterpret_cast<PxOverlapHit*>(physx::shdfnd::TempAllocator().allocate( + (sizeof(PxOverlapHit) + sizeof(PxActorShape)) * (maxShapeCount+1), __FILE__, __LINE__)); + reportBuffer = static_cast<PxActorShape*>(localBuffer + maxShapeCount+1); + } + + // +1 shape so we can tell inside of single callback if we blew the buffer + NpVolumeCacheSqCallback cacheSqCallback(this, iter, isDynamic, localBuffer, reportBuffer, maxShapeCount+1); + + // execute the overlap query to get all touching shapes. will be processed in cb.processTouches() + getNpScene(mSQManager)->overlap(mCacheVolume.any(), mCachePose, cacheSqCallback, fd, NULL); + reportedOverMaxCount[isDynamic] = cacheSqCallback.reportedOverMaxCount; + + if(maxShapeCount >= maxStackShapes) // release the local hit buffer if not on the stack + physx::shdfnd::TempAllocator().deallocate(localBuffer); + + } // for (isDynamic) + + // report all cached shapes via the iterator callback, any shapes previously over capacity were already reported + // if so reportedOverMaxCount is set to true at this point for statics and/or dynamics correspondingly + if(!reportedOverMaxCount[0] && mCache[0].size() > 0) + iter.processShapes(mCache[0].size(), mCache[0].begin()); + if(!reportedOverMaxCount[1] && mCache[1].size() > 0) + iter.processShapes(mCache[1].size(), mCache[1].begin()); + iter.finalizeQuery(); +} + +//======================================================================================================================== +void NpVolumeCache::setMaxNbStaticShapes(PxU32 maxCount) +{ + if(maxCount < mCache[0].size()) + { + mIsInvalid[0] = true; + mCache[0].clear(); + } + mMaxShapeCount[0] = maxCount; + mCache[0].reserve(maxCount); +} + +//======================================================================================================================== +PxU32 NpVolumeCache::getMaxNbStaticShapes() +{ + return mMaxShapeCount[0]; +} + +//======================================================================================================================== +void NpVolumeCache::setMaxNbDynamicShapes(PxU32 maxCount) +{ + if(maxCount < mCache[1].size()) + { + mIsInvalid[1] = true; + mCache[1].clear(); + } + mMaxShapeCount[1] = maxCount; + mCache[1].reserve(maxCount); +} + +//======================================================================================================================== +PxU32 NpVolumeCache::getMaxNbDynamicShapes() +{ + return mMaxShapeCount[1]; +} + +//======================================================================================================================== + static PX_FORCE_INLINE PxActorShape* applyAllPreFiltersVC( + PxActorShape* as, PxQueryHitType::Enum& hitType, const PxQueryFlags& inFilterFlags, + const PxQueryFilterData& filterData, PxQueryFilterCallback* filterCall, const NpScene& scene, PxHitFlags& hitFlags) +{ + if(!applyClientFilter(as->actor, filterData, scene)) + return NULL; + + if(!applyFilterEquation(static_cast<NpShape*>(as->shape)->getScbShape(), filterData.data)) + return NULL; + + if(filterCall && (inFilterFlags & PxQueryFlag::ePREFILTER)) + { + PxHitFlags outHitFlags = hitFlags; + + hitType = filterCall->preFilter(filterData.data, as->shape, as->actor, outHitFlags); + + hitFlags = (hitFlags & ~PxHitFlag::eMODIFIABLE_FLAGS) | (outHitFlags & PxHitFlag::eMODIFIABLE_FLAGS); + } + return as; +} + +// performs a single geometry query for any HitType (PxSweepHit, PxOverlapHit, PxRaycastHit) +template<typename HitType> +struct GeomQueryAny +{ + static PX_INLINE PxU32 geomHit( + const MultiQueryInput& input, + const PxGeometry& geom, const PxTransform& pose, PxHitFlags outputFlags, + PxU32 maxHits, HitType* hits, PxReal& shrunkMaxDistance) + { + if(HitTypeSupport<HitType>::IsRaycast) + { + // for meshes test against the mesh AABB + if(0 && geom.getType() == PxGeometryType::eTRIANGLEMESH) + { + PxBounds3 bounds; + computeBounds(bounds, geom, pose, 0.0f, NULL, 1.0f, false); + PxF32 tnear, tfar; + if(!intersectRayAABB2( + bounds.minimum, bounds.maximum, *input.rayOrigin, *input.unitDir, shrunkMaxDistance, tnear, tfar)) + return 0; + } + // perform a raycast against the cached shape + return PxGeometryQuery::raycast( + input.getOrigin(), input.getDir(), geom, pose, shrunkMaxDistance, outputFlags, + maxHits, reinterpret_cast<PxRaycastHit*>(hits)); + } + else if(HitTypeSupport<HitType>::IsSweep) + { + PxU32 result = PxU32(PxGeometryQuery::sweep( + input.getDir(), input.maxDistance, *input.geometry, *input.pose, geom, pose, reinterpret_cast<PxSweepHit&>(hits[0]), outputFlags)); + return result; + } + else if(HitTypeSupport<HitType>::IsOverlap) + { + PxU32 result = PxU32(PxGeometryQuery::overlap(*input.geometry, *input.pose, geom, pose)); + return result; + } + else + { + PX_ALWAYS_ASSERT_MESSAGE("Unexpected template expansion in GeomQueryAny::geomHit"); + return 0; + } + } +}; + +// performs a cache volume query for any HitType (PxSweepHit, PxOverlapHit, PxRaycastHit) +template<typename HitType> +struct SceneQueryAny +{ + static PX_INLINE bool doQuery( + PxScene* scene, const MultiQueryInput& input, PxHitCallback<HitType>& hitCall, PxHitFlags hitFlags, + const PxQueryFilterData& filterData, PxQueryFilterCallback* filterCall) + { + if(HitTypeSupport<HitType>::IsRaycast) + { + PX_ASSERT(sizeof(HitType) == sizeof(PxRaycastHit)); + scene->raycast(input.getOrigin(), input.getDir(), input.maxDistance, + reinterpret_cast<PxRaycastCallback&>(hitCall), hitFlags, filterData, filterCall, NULL); + return hitCall.hasAnyHits(); + } + else if(HitTypeSupport<HitType>::IsSweep) + { + PX_ASSERT(sizeof(HitType) == sizeof(PxSweepHit)); + scene->sweep(*input.geometry, *input.pose, input.getDir(), input.maxDistance, + reinterpret_cast<PxSweepCallback&>(hitCall), hitFlags, filterData, filterCall, NULL); + return hitCall.hasAnyHits(); + } + else if(HitTypeSupport<HitType>::IsOverlap) + { + PX_ASSERT(sizeof(HitType) == sizeof(PxOverlapHit)); + scene->overlap(*input.geometry, *input.pose, reinterpret_cast<PxOverlapCallback&>(hitCall), filterData, filterCall); + return hitCall.hasAnyHits(); + } + else + { + PX_ALWAYS_ASSERT_MESSAGE("Unexpected template expansion in SceneQueryAny::doQuery"); + return false; + } + } +}; + +//======================================================================================================================== +template<typename HitType> +PX_FORCE_INLINE void makeHitSafe(HitType& hit) // hit can contain NaNs (due to uninitialized mem allocation) which cannot be copied +{ + if(HitTypeSupport<HitType>::IsRaycast == 1 || HitTypeSupport<HitType>::IsSweep == 1) + { +#if PX_VC +#pragma warning(push) +#pragma warning(disable : 4946) // reinterpret_cast used between related classes + // happens if the template param inherits from PxLocationHit +#endif + PxLocationHit& hit1 = reinterpret_cast<PxLocationHit&>(hit); +#if PX_VC +#pragma warning(pop) +#endif + if(!(hit1.flags & PxHitFlag::eDISTANCE)) + hit1.distance = 0.0f; + if(!(hit1.flags & PxHitFlag::ePOSITION)) + hit1.position = PxVec3(0.0f); + if(!(hit1.flags & PxHitFlag::eNORMAL)) + hit1.normal = PxVec3(0.0f); + } + if(HitTypeSupport<HitType>::IsRaycast == 1 && !(reinterpret_cast<PxRaycastHit&>(hit).flags & PxHitFlag::eUV) ) + { + reinterpret_cast<PxRaycastHit&>(hit).u = 0.0f; + reinterpret_cast<PxRaycastHit&>(hit).v = 0.0f; + } +} + +//======================================================================================================================== +template<typename HitType> +bool NpVolumeCache::multiQuery( + const MultiQueryInput& input, PxHitCallback<HitType>& hitCall, PxHitFlags hitFlags, + const PxQueryFilterData& filterData, PxQueryFilterCallback* filterCall, PxF32 inflation) const +{ + + if(HitTypeSupport<HitType>::IsRaycast == 0) + { + PX_CHECK_AND_RETURN_VAL(input.pose->isValid(), "sweepInputCheck: pose is not valid.", 0); + } + if(HitTypeSupport<HitType>::IsOverlap == 0) + { + PX_CHECK_AND_RETURN_VAL(input.getDir().isFinite(), "PxVolumeCache multiQuery input check: unitDir is not valid.", 0); + PX_CHECK_AND_RETURN_VAL(input.getDir().isNormalized(), "PxVolumeCache multiQuery input check: direction must be normalized", 0); + } + if(HitTypeSupport<HitType>::IsRaycast) + { + PX_CHECK_AND_RETURN_VAL(input.maxDistance > 0.0f, "PxVolumeCache multiQuery input check: distance cannot be negative or zero", 0); + } + if(HitTypeSupport<HitType>::IsSweep) + { + PX_CHECK_AND_RETURN_VAL(input.maxDistance >= 0.0f, "NpSceneQueries multiQuery input check: distance cannot be negative", 0); + PX_CHECK_AND_RETURN_VAL(input.maxDistance != 0.0f || !(hitFlags & PxHitFlag::eASSUME_NO_INITIAL_OVERLAP), + "PxVolumeCache multiQuery input check: zero-length sweep only valid without the PxHitFlag::eASSUME_NO_INITIAL_OVERLAP flag", 0); + } + + hitCall.hasBlock = false; + hitCall.nbTouches = 0; + + const PxQueryFlags filterFlags = filterData.flags; + + // refill the cache if invalid + for(PxU32 isDynamic = 0; isDynamic <= 1; isDynamic++) + { + if(!isValid(isDynamic) && ((isDynamic+1) & PxU32(filterFlags)) != 0) // isDynamic+1 = 1 for static, 2 for dynamic + // check for overflow or unspecified cache volume&transform, fall back to scene query on overflow (or invalid voltype) + if(const_cast<NpVolumeCache*>(this)->fillInternal(isDynamic) == FILL_OVER_MAX_COUNT + || mCacheVolume.getType() == PxGeometryType::eINVALID) + { + // fall back to full scene query with input flags if we blow the cache on either static or dynamic for now + if(mCacheVolume.getType() == PxGeometryType::eINVALID) + Ps::getFoundation().error(PxErrorCode::ePERF_WARNING, __FILE__, __LINE__, + "PxVolumeCache: unspecified volume geometry. Reverting to uncached scene query."); + return SceneQueryAny<HitType>::doQuery( + getNpScene(mSQManager), input, hitCall, hitFlags, filterData, filterCall); + } + } + + // cache is now valid and there was no overflow + PX_ASSERT_WITH_MESSAGE(isValid() ,"PxVolumeCache became invalid inside of a scene read call."); + + const PxU32 cacheSize[2] = { mCache[0].size(), mCache[1].size() }; + + // early out if the cache is empty and valid + if(cacheSize[0] == 0 && cacheSize[1] == 0) + return 0; + + PxReal shrunkDistance = HitTypeSupport<HitType>::IsOverlap ? PX_MAX_REAL : input.maxDistance; // can be progressively shrunk as we go over the list of shapes + const NpScene& scene = *getNpScene(mSQManager); + HitType* subHits = NULL; + + // make sure to deallocate the temp buffer when we return + struct FreeSubhits + { + HitType* toFree; + PX_FORCE_INLINE FreeSubhits() { toFree = NULL; } + PX_FORCE_INLINE ~FreeSubhits() { if (toFree) physx::shdfnd::TempAllocator().deallocate(toFree); } + } ds; + + // allocate from temp storage rather than from the stack if we are over some shape count + PxU32 maxMaxShapeCount = PxMax(mMaxShapeCount[0], mMaxShapeCount[1]); // max size buffer for statics and dynamics + if(maxMaxShapeCount < 128) // somewhat arbitrary + subHits = reinterpret_cast<HitType*>(PxAlloca(sizeof(HitType)*maxMaxShapeCount)); + else + ds.toFree = subHits = reinterpret_cast<HitType*>(physx::shdfnd::TempAllocator().allocate(sizeof(HitType)*maxMaxShapeCount, __FILE__, __LINE__)); + + const bool noBlock = (filterFlags & PxQueryFlag::eNO_BLOCK); + + // for statics & dynamics + for(PxU32 isDynamic = 0; isDynamic <= 1; isDynamic++) + // iterate over all the cached shapes + for(PxU32 iCachedShape = 0; iCachedShape < cacheSize[isDynamic]; iCachedShape++) + { + PxActorShape* as = &mCache[isDynamic][iCachedShape]; + + const PxU32 actorFlag = (PxU32(as->actor->is<PxRigidDynamic>() != NULL) + 1); // 1 for static, 2 for dynamic + PX_COMPILE_TIME_ASSERT(PxQueryFlag::eSTATIC == 1); + PX_COMPILE_TIME_ASSERT(PxQueryFlag::eDYNAMIC == 2); + if((actorFlag & PxU32(filterFlags)) == 0) // filter the actor according to the input static/dynamic filter + continue; + + // for no filter callback, default to eTOUCH for MULTIPLE, eBLOCK otherwise + PxQueryHitType::Enum shapeHitType = hitCall.maxNbTouches ? PxQueryHitType::eTOUCH : PxQueryHitType::eBLOCK; + + // apply pre-filter + PxHitFlags queryFlags = hitFlags; + as = applyAllPreFiltersVC(as, shapeHitType, filterFlags, filterData, filterCall, scene, hitFlags); + if(!as || shapeHitType == PxQueryHitType::eNONE) + continue; + PX_ASSERT(as->actor && as->shape); + + NpShape* shape = static_cast<NpShape*>(as->shape); + + // compute the global pose for the cached shape and actor + PX_ALIGN(16, PxTransform) globalPose; + NpActor::getGlobalPose(globalPose, *shape, *as->actor); + + const GeometryUnion& cachedShapeGeom = shape->getGeometryFast(); + + // call the geometry specific intersection template + PxU32 nbSubHits = GeomQueryAny<HitType>::geomHit( + input, cachedShapeGeom.getGeometry(), globalPose, queryFlags, + // limit number of hits to 1 for meshes if eMESH_MULTIPLE wasn't specified. + //this tells geomQuery to only look for a closest hit + (cachedShapeGeom.getType() == PxGeometryType::eTRIANGLEMESH && !(hitFlags & PxHitFlag::eMESH_MULTIPLE)) ? 1 : maxMaxShapeCount, + subHits, shrunkDistance); + + // iterate over geometry subhits + for(PxU32 iSubHit = 0; iSubHit < nbSubHits; iSubHit++) + { + HitType& hit = subHits[iSubHit]; + hit.actor = as->actor; + hit.shape = as->shape; + makeHitSafe<HitType>(hit); + + // some additional processing only for sweep hits with initial overlap + if(HitTypeSupport<HitType>::IsSweep && HITDIST(hit) == 0.0f) + // PT: necessary as some leaf routines are called with reversed params, thus writing +unitDir there. + reinterpret_cast<PxSweepHit&>(hit).normal = -input.getDir(); + + // start out with hitType for this cached shape set to a pre-filtered hit type + PxQueryHitType::Enum hitType = shapeHitType; + + // run the post-filter if specified in filterFlags and filterCall is non-NULL + if(filterCall && (filterFlags & PxQueryFlag::ePOSTFILTER)) + hitType = filterCall->postFilter(filterData.data, hit); + + // -------------------------- handle eANY_HIT hits --------------------------------- + if(filterFlags & PxQueryFlag::eANY_HIT && hitType != PxQueryHitType::eNONE) + { + hitCall.block = hit; + hitCall.finalizeQuery(); + return (hitCall.hasBlock = true); + } + + if(noBlock) + hitType = PxQueryHitType::eTOUCH; + + if(hitType == PxQueryHitType::eTOUCH) + { + // -------------------------- handle eTOUCH hits --------------------------------- + // for MULTIPLE hits (hitCall.touches != NULL), store the hit. For other qTypes ignore it. + if(hitCall.maxNbTouches && HITDIST(hit) <= shrunkDistance) + { + // Buffer full: need to find the closest blocking hit, clip touch hits and flush the buffer + if(hitCall.nbTouches == hitCall.maxNbTouches) + { + // issue a second nested query just looking for the closest blocking hit + // could do better perf-wise by saving traversal state (start looking for blocking from this point) + // but this is not a perf critical case because users can provide a bigger buffer + // that covers non-degenerate cases + PxHitBuffer<HitType> buf1; + if(multiQuery<HitType>(input, buf1, hitFlags, filterData, filterCall, inflation)) + { + hitCall.block = buf1.block; + hitCall.hasBlock = true; + hitCall.nbTouches = + clipHitsToNewMaxDist<HitType>(hitCall.touches, hitCall.nbTouches, HITDIST(buf1.block)); + } + + if(hitCall.nbTouches == hitCall.maxNbTouches) + { + PxAgain again = hitCall.processTouches(hitCall.touches, hitCall.maxNbTouches); + if(!again) // early exit opportunity + { + hitCall.finalizeQuery(); + return hitCall.hasBlock; + } else + hitCall.nbTouches = 0; // reset nbTouches so we can continue accumulating again + } + + } // if(hitCall.nbTouches == hitCall.maxNbTouches) + + hitCall.touches[hitCall.nbTouches++] = hit; + } // if(hitCall.maxNbTouches && hit.dist <= shrunkDist) + } + else if(hitType == PxQueryHitType::eBLOCK) + { + // -------------------------- handle eBLOCK hits --------------------------------- + // former SINGLE and MULTIPLE cases => update blocking hit distance + // only eBLOCK qualifies as a closest hit candidate for "single" query + // => compare against the best distance and store + if(HITDIST(hit) <= shrunkDistance) + { + shrunkDistance = HITDIST(hit); + hitCall.block = hit; + hitCall.hasBlock = true; + } + } else + { + PX_ASSERT(hitType == PxQueryHitType::eNONE); + } + } // for iSubHit + } // for isDynamic, for iCachedShape + + // clip any unreported touch hits to block.distance and report via callback + if(hitCall.hasBlock && hitCall.nbTouches) + hitCall.nbTouches = clipHitsToNewMaxDist(hitCall.touches, hitCall.nbTouches, HITDIST(hitCall.block)); + if(hitCall.nbTouches) + { + bool again = hitCall.processTouches(hitCall.touches, hitCall.nbTouches); + if(again) + hitCall.nbTouches = 0; + } + hitCall.finalizeQuery(); + + return hitCall.hasBlock; +} + +#undef HITDIST + +//======================================================================================================================== +bool NpVolumeCache::raycast( + const PxVec3& origin, const PxVec3& unitDir, const PxReal distance, PxRaycastCallback& hitCall, PxHitFlags hitFlags, + const PxQueryFilterData& filterData, PxQueryFilterCallback* filterCall) const +{ + PX_SIMD_GUARD; + + MultiQueryInput input(origin, unitDir, distance); + bool result = multiQuery<PxRaycastHit>(input, hitCall, hitFlags, filterData, filterCall); + return result; +} + +//======================================================================================================================= +bool NpVolumeCache::sweep( + const PxGeometry& geometry, const PxTransform& pose, const PxVec3& unitDir, const PxReal distance, + PxSweepCallback& hitCall, PxHitFlags hitFlags, + const PxQueryFilterData& filterData, PxQueryFilterCallback* filterCall, const PxReal inflation) const +{ + PX_SIMD_GUARD; + + MultiQueryInput input(&geometry, &pose, unitDir, distance, 0.0f); + bool result = multiQuery<PxSweepHit>(input, hitCall, hitFlags, filterData, filterCall, inflation); + return result; +} + +//======================================================================================================================== +bool NpVolumeCache::overlap( + const PxGeometry& geometry, const PxTransform& transform, + PxOverlapCallback& hitCall, const PxQueryFilterData& filterData, PxQueryFilterCallback* filterCall) const +{ + PX_SIMD_GUARD; + + MultiQueryInput input(&geometry, &transform); + bool result = multiQuery<PxOverlapHit>(input, hitCall, PxHitFlags(), filterData, filterCall); + return result; +} + +//======================================================================================================================== +void NpVolumeCache::onOriginShift(const PxVec3& shift) +{ + mCachePose.p -= shift; +} + +} // namespace physx diff --git a/PhysX_3.4/Source/PhysX/src/NpVolumeCache.h b/PhysX_3.4/Source/PhysX/src/NpVolumeCache.h new file mode 100644 index 00000000..a7038c21 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpVolumeCache.h @@ -0,0 +1,111 @@ +// 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_NP_VOLUMECACHE +#define PX_PHYSICS_NP_VOLUMECACHE + +#include "PxVolumeCache.h" +#include "PsUserAllocated.h" +#include "CmPhysXCommon.h" +#include "PsArray.h" + +namespace physx +{ + + struct MultiQueryInput; + +namespace Sq { class SceneQueryManager; } + + +// internal implementation for PxVolumeCache +class NpVolumeCache : public PxVolumeCache, public Ps::UserAllocated +{ +public: + NpVolumeCache(Sq::SceneQueryManager* sqm, PxU32 maxNbStatic, PxU32 maxNbDynamic); + virtual ~NpVolumeCache(); + virtual bool isValid() const; + bool isValid(PxU32 isDynamic) const; + + virtual FillStatus fill(const PxGeometry& cacheVolume, const PxTransform& pose); + FillStatus fillInternal(PxU32 isDynamic, const PxOverlapHit* buffer = NULL, PxI32 count = 0); + + virtual bool getCacheVolume(PxGeometryHolder& resultVolume, PxTransform& resultPose); + virtual PxI32 getNbCachedShapes(); + + virtual void invalidate(); + virtual void release(); + + virtual void forEach(Iterator& iter); + + virtual void setMaxNbStaticShapes(PxU32 maxCount); + virtual PxU32 getMaxNbStaticShapes(); + virtual void setMaxNbDynamicShapes(PxU32 maxCount); + virtual PxU32 getMaxNbDynamicShapes(); + + template<typename HitType> + bool multiQuery( + const MultiQueryInput& multiInput, // type specific input data + PxHitCallback<HitType>& hitCall, PxHitFlags hitFlags, + const PxQueryFilterData& filterData, PxQueryFilterCallback* filterCall, + PxF32 inflation = 0.0f) const; + + virtual bool raycast( + const PxVec3& origin, const PxVec3& unitDir, const PxReal distance, + PxRaycastCallback& hitCall, PxHitFlags hitFlags, + const PxQueryFilterData& filterData, PxQueryFilterCallback* filterCall) const; + + virtual bool sweep( + const PxGeometry& geometry, const PxTransform& pose, const PxVec3& unitDir, const PxReal distance, + PxSweepCallback& hitCall, PxHitFlags hitFlags, + const PxQueryFilterData& filterData, PxQueryFilterCallback* filterCall, + const PxReal inflation) const; + + virtual bool overlap( + const PxGeometry& geometry, const PxTransform& pose, + PxOverlapCallback& hitCall, const PxQueryFilterData& filterData, + PxQueryFilterCallback* filterCall) const; + + + void onOriginShift(const PxVec3& shift); + + + PxGeometryHolder mCacheVolume; + PxTransform mCachePose; + PxU32 mMaxShapeCount[2]; + Sq::SceneQueryManager* mSQManager; + mutable Ps::Array<PxActorShape> mCache[2]; // AP todo: improve memory management, could we have one allocation for both? + PxU32 mStaticTimestamp; + PxU32 mDynamicTimestamp; + bool mIsInvalid[2]; // invalid for reasons other than timestamp, such as overflow on previous fill +}; + +} + +#endif // PX_PHYSICS_NP_SCENE diff --git a/PhysX_3.4/Source/PhysX/src/NpWriteCheck.cpp b/PhysX_3.4/Source/PhysX/src/NpWriteCheck.cpp new file mode 100644 index 00000000..6c132150 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpWriteCheck.cpp @@ -0,0 +1,92 @@ +// 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 "NpWriteCheck.h" + +#include "NpScene.h" + +using namespace physx; + +NpWriteCheck::NpWriteCheck(NpScene* scene, const char* functionName, bool allowReentry) +: mScene(scene), mName(functionName), mAllowReentry(allowReentry), mErrorCount(0) +{ + if (mScene) + { + switch (mScene->startWrite(mAllowReentry)) + { + case NpScene::StartWriteResult::eOK: + break; + case NpScene::StartWriteResult::eNO_LOCK: + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, + "An API write call (%s) was made from thread %d but PxScene::lockWrite() was not called first, note that " + "when PxSceneFlag::eREQUIRE_RW_LOCK is enabled all API reads and writes must be " + "wrapped in the appropriate locks.", mName, PxU32(Ps::Thread::getId())); + break; + case NpScene::StartWriteResult::eRACE_DETECTED: + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, + "Concurrent API write call or overlapping API read and write call detected during %s from thread %d! " + "Note that write operations to the SDK must be sequential, i.e., no overlap with " + "other write or read calls, else the resulting behavior is undefined. " + "Also note that API writes during a callback function are not permitted.", mName, PxU32(Ps::Thread::getId())); + break; + + case NpScene::StartWriteResult::eIN_FETCHRESULTS: + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, + "Illegal write call detected in %s from thread %d during split fetchResults! " + "Note that write operations to the SDK are not permitted between the start of fetchResultsStart() and end of fetchResultsFinish(). " + "Behavior will be undefined. ", mName, PxU32(Ps::Thread::getId())); + break; + } + + // Record the NpScene read/write error counter which is + // incremented any time a NpScene::startWrite/startRead fails + // (see destructor for additional error checking based on this count) + mErrorCount = mScene->getReadWriteErrorCount(); + } +} + + +NpWriteCheck::~NpWriteCheck() +{ + if (mScene) + { + // By checking if the NpScene::mConcurrentErrorCount has been incremented + // we can detect if an erroneous read/write was performed during + // this objects lifetime. In this case we also print this function's + // details so that the user can see which two API calls overlapped + if (mScene->getReadWriteErrorCount() != mErrorCount && !(mScene->getScene().getFlags() & PxSceneFlag::eREQUIRE_RW_LOCK)) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, + "Leaving %s on thread %d, an overlapping API read or write by another thread was detected.", mName, PxU32(Ps::Thread::getId())); + } + + mScene->stopWrite(mAllowReentry); + } +} diff --git a/PhysX_3.4/Source/PhysX/src/NpWriteCheck.h b/PhysX_3.4/Source/PhysX/src/NpWriteCheck.h new file mode 100644 index 00000000..937209bd --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/NpWriteCheck.h @@ -0,0 +1,79 @@ +// 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 NP_WRITE_CHECK_H +#define NP_WRITE_CHECK_H + +#include "foundation/PxSimpleTypes.h" + +namespace physx +{ + +class NpScene; + +// RAII wrapper around the PxScene::startWrite() method, note that this +// object does not acquire any scene locks, it is an error checking only mechanism +class NpWriteCheck +{ +public: + NpWriteCheck(NpScene* scene, const char* functionName, bool allowReentry=true); + ~NpWriteCheck(); + +private: + + NpScene* mScene; + const char* mName; + bool mAllowReentry; + PxU32 mErrorCount; +}; + +#if PX_DEBUG || PX_CHECKED + // Creates a scoped write check object that detects whether appropriate scene locks + // have been acquired and checks if reads/writes overlap, this macro should typically + // be placed at the beginning of any non-const API methods that are not multi-thread safe. + // By default re-entrant write calls by the same thread are allowed, the error conditions + // checked can be summarized as: + + // 1. PxSceneFlag::eREQUIRE_RW_LOCK was specified but PxScene::lockWrite() was not yet called + // 2. Other threads were already reading, or began reading during the object lifetime + // 3. Other threads were already writing, or began writing during the object lifetime + #define NP_WRITE_CHECK(npScenePtr) NpWriteCheck npWriteCheck(npScenePtr, __FUNCTION__); + + // Creates a scoped write check object that disallows re-entrant writes, this is used by + // the NpScene::simulate method to detect when callbacks make write calls to the API + #define NP_WRITE_CHECK_NOREENTRY(npScenePtr) NpWriteCheck npWriteCheck(npScenePtr, __FUNCTION__, false); +#else + #define NP_WRITE_CHECK(npScenePtr) + #define NP_WRITE_CHECK_NOREENTRY(npScenePtr) +#endif + +} + +#endif // NP_WRITE_CHECK_H diff --git a/PhysX_3.4/Source/PhysX/src/PvdMetaDataBindingData.h b/PhysX_3.4/Source/PhysX/src/PvdMetaDataBindingData.h new file mode 100644 index 00000000..add3fcfe --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/PvdMetaDataBindingData.h @@ -0,0 +1,82 @@ +// 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_META_DATA_PVD_BINDING_DATA_H +#define PX_META_DATA_PVD_BINDING_DATA_H +#if PX_SUPPORT_PVD +#include "foundation/PxSimpleTypes.h" +#include "PsArray.h" +#include "PsHashSet.h" +#include "PsHashMap.h" + +namespace physx +{ +namespace Vd +{ +using namespace physx::shdfnd; + +typedef HashSet<const PxRigidActor*> OwnerActorsValueType; +typedef HashMap<const PxShape*, OwnerActorsValueType*> OwnerActorsMap; + +struct PvdMetaDataBindingData : public UserAllocated +{ + Array<PxU8> mTempU8Array; + Array<PxActor*> mActors; + Array<PxArticulation*> mArticulations; + Array<PxArticulationLink*> mArticulationLinks; + HashSet<PxActor*> mSleepingActors; + OwnerActorsMap mOwnerActorsMap; + + PvdMetaDataBindingData() + : mTempU8Array(PX_DEBUG_EXP("TempU8Array")) + , mActors(PX_DEBUG_EXP("PxActor")) + , mArticulations(PX_DEBUG_EXP("Articulations")) + , mArticulationLinks(PX_DEBUG_EXP("ArticulationLinks")) + , mSleepingActors(PX_DEBUG_EXP("SleepingActors")) + { + } + + template <typename TDataType> + TDataType* allocateTemp(PxU32 numItems) + { + mTempU8Array.resize(numItems * sizeof(TDataType)); + if(numItems) + return reinterpret_cast<TDataType*>(mTempU8Array.begin()); + else + return NULL; + } + + DataRef<const PxU8> tempToRef() + { + return DataRef<const PxU8>(mTempU8Array.begin(), mTempU8Array.size()); + } +}; +} +} +#endif // PX_SUPPORT_PVD +#endif diff --git a/PhysX_3.4/Source/PhysX/src/PvdMetaDataPvdBinding.cpp b/PhysX_3.4/Source/PhysX/src/PvdMetaDataPvdBinding.cpp new file mode 100644 index 00000000..33951453 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/PvdMetaDataPvdBinding.cpp @@ -0,0 +1,2416 @@ +// 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. + +// suppress LNK4221 +#include "foundation/PxPreprocessor.h" +PX_DUMMY_SYMBOL + +#if PX_SUPPORT_PVD + +#include "foundation/PxSimpleTypes.h" +#include "foundation/Px.h" + +#include "PxMetaDataObjects.h" +#include "PxPvdDataStream.h" +#include "PxScene.h" +#include "ScBodyCore.h" +#include "PvdMetaDataExtensions.h" +#include "PvdMetaDataPropertyVisitor.h" +#include "PvdMetaDataDefineProperties.h" +#include "PvdMetaDataBindingData.h" +#include "PxRigidDynamic.h" +#include "PxArticulation.h" +#include "PxArticulationLink.h" +#include "NpScene.h" +#include "NpPhysics.h" + +#include "gpu/PxParticleGpu.h" +#include "PvdTypeNames.h" +#include "PvdMetaDataPvdBinding.h" + +using namespace physx; +using namespace Sc; +using namespace Vd; +using namespace Sq; + +namespace physx +{ +namespace Vd +{ + +struct NameValuePair +{ + const char* mName; + PxU32 mValue; +}; + +static const NameValuePair g_physx_Sq_SceneQueryID__EnumConversion[] = { + { "QUERY_RAYCAST_ANY_OBJECT", PxU32(QueryID::QUERY_RAYCAST_ANY_OBJECT) }, + { "QUERY_RAYCAST_CLOSEST_OBJECT", PxU32(QueryID::QUERY_RAYCAST_CLOSEST_OBJECT) }, + { "QUERY_RAYCAST_ALL_OBJECTS", PxU32(QueryID::QUERY_RAYCAST_ALL_OBJECTS) }, + { "QUERY_OVERLAP_SPHERE_ALL_OBJECTS", PxU32(QueryID::QUERY_OVERLAP_SPHERE_ALL_OBJECTS) }, + { "QUERY_OVERLAP_AABB_ALL_OBJECTS", PxU32(QueryID::QUERY_OVERLAP_AABB_ALL_OBJECTS) }, + { "QUERY_OVERLAP_OBB_ALL_OBJECTS", PxU32(QueryID::QUERY_OVERLAP_OBB_ALL_OBJECTS) }, + { "QUERY_OVERLAP_CAPSULE_ALL_OBJECTS", PxU32(QueryID::QUERY_OVERLAP_CAPSULE_ALL_OBJECTS) }, + { "QUERY_OVERLAP_CONVEX_ALL_OBJECTS", PxU32(QueryID::QUERY_OVERLAP_CONVEX_ALL_OBJECTS) }, + { "QUERY_LINEAR_OBB_SWEEP_CLOSEST_OBJECT", PxU32(QueryID::QUERY_LINEAR_OBB_SWEEP_CLOSEST_OBJECT) }, + { "QUERY_LINEAR_CAPSULE_SWEEP_CLOSEST_OBJECT", PxU32(QueryID::QUERY_LINEAR_CAPSULE_SWEEP_CLOSEST_OBJECT) }, + { "QUERY_LINEAR_CONVEX_SWEEP_CLOSEST_OBJECT", PxU32(QueryID::QUERY_LINEAR_CONVEX_SWEEP_CLOSEST_OBJECT) }, + { NULL, 0 } +}; + +struct SceneQueryIDConvertor +{ + const NameValuePair* NameConversion; + SceneQueryIDConvertor() : NameConversion(g_physx_Sq_SceneQueryID__EnumConversion) + { + } +}; + +PvdMetaDataBinding::PvdMetaDataBinding() : mBindingData(PX_NEW(PvdMetaDataBindingData)()) +{ +} + +PvdMetaDataBinding::~PvdMetaDataBinding() +{ + for(OwnerActorsMap::Iterator iter = mBindingData->mOwnerActorsMap.getIterator(); !iter.done(); iter++) + { + iter->second->~OwnerActorsValueType(); + PX_FREE(iter->second); + } + + PX_DELETE(mBindingData); + mBindingData = NULL; +} + +template <typename TDataType, typename TValueType, typename TClassType> +inline void definePropertyStruct(PvdDataStream& inStream, const char* pushName = NULL) +{ + PvdPropertyDefinitionHelper& helper(inStream.getPropertyDefinitionHelper()); + PvdClassInfoValueStructDefine definitionObj(helper); + bool doPush = pushName && *pushName; + if(doPush) + definitionObj.pushName(pushName); + visitAllPvdProperties<TDataType>(definitionObj); + if(doPush) + definitionObj.popName(); + helper.addPropertyMessage(getPvdNamespacedNameForType<TClassType>(), getPvdNamespacedNameForType<TValueType>(), sizeof(TValueType)); +} + +template <typename TDataType> +inline void createClassAndDefineProperties(PvdDataStream& inStream) +{ + inStream.createClass<TDataType>(); + PvdPropertyDefinitionHelper& helper(inStream.getPropertyDefinitionHelper()); + PvdClassInfoDefine definitionObj(helper, getPvdNamespacedNameForType<TDataType>()); + visitAllPvdProperties<TDataType>(definitionObj); +} + +template <typename TDataType, typename TParentType> +inline void createClassDeriveAndDefineProperties(PvdDataStream& inStream) +{ + inStream.createClass<TDataType>(); + inStream.deriveClass<TParentType, TDataType>(); + PvdPropertyDefinitionHelper& helper(inStream.getPropertyDefinitionHelper()); + PvdClassInfoDefine definitionObj(helper, getPvdNamespacedNameForType<TDataType>()); + visitInstancePvdProperties<TDataType>(definitionObj); +} + +template <typename TDataType, typename TConvertSrc, typename TConvertData> +inline void defineProperty(PvdDataStream& inStream, const char* inPropertyName, const char* semantic) +{ + PvdPropertyDefinitionHelper& helper(inStream.getPropertyDefinitionHelper()); + // PxEnumTraits< TValueType > filterFlagsEnum; + TConvertSrc filterFlagsEnum; + const TConvertData* convertor = filterFlagsEnum.NameConversion; + + for(; convertor->mName != NULL; ++convertor) + helper.addNamedValue(convertor->mName, convertor->mValue); + + inStream.createProperty<TDataType, PxU32>(inPropertyName, semantic, PropertyType::Scalar, helper.getNamedValues()); + helper.clearNamedValues(); +} + +template <typename TDataType, typename TConvertSrc, typename TConvertData> +inline void definePropertyFlags(PvdDataStream& inStream, const char* inPropertyName) +{ + defineProperty<TDataType, TConvertSrc, TConvertData>(inStream, inPropertyName, "Bitflag"); +} +template <typename TDataType, typename TConvertSrc, typename TConvertData> +inline void definePropertyEnums(PvdDataStream& inStream, const char* inPropertyName) +{ + defineProperty<TDataType, TConvertSrc, TConvertData>(inStream, inPropertyName, "Enumeration Value"); +} + +static PX_FORCE_INLINE void registerPvdRaycast(PvdDataStream& inStream) +{ + inStream.createClass<PvdRaycast>(); + definePropertyEnums<PvdRaycast, SceneQueryIDConvertor, NameValuePair>(inStream, "type"); + inStream.createProperty<PvdRaycast, PxFilterData>("filterData"); + definePropertyFlags<PvdRaycast, PxEnumTraits<physx::PxQueryFlag::Enum>, PxU32ToName>(inStream, "filterFlags"); + inStream.createProperty<PvdRaycast, PxVec3>("origin"); + inStream.createProperty<PvdRaycast, PxVec3>("unitDir"); + inStream.createProperty<PvdRaycast, PxF32>("distance"); + inStream.createProperty<PvdRaycast, String>("hits_arrayName"); + inStream.createProperty<PvdRaycast, PxU32>("hits_baseIndex"); + inStream.createProperty<PvdRaycast, PxU32>("hits_count"); +} + +static PX_FORCE_INLINE void registerPvdSweep(PvdDataStream& inStream) +{ + inStream.createClass<PvdSweep>(); + definePropertyEnums<PvdSweep, SceneQueryIDConvertor, NameValuePair>(inStream, "type"); + definePropertyFlags<PvdSweep, PxEnumTraits<physx::PxQueryFlag::Enum>, PxU32ToName>(inStream, "filterFlags"); + inStream.createProperty<PvdSweep, PxVec3>("unitDir"); + inStream.createProperty<PvdSweep, PxF32>("distance"); + inStream.createProperty<PvdSweep, String>("geom_arrayName"); + inStream.createProperty<PvdSweep, PxU32>("geom_baseIndex"); + inStream.createProperty<PvdSweep, PxU32>("geom_count"); + inStream.createProperty<PvdSweep, String>("pose_arrayName"); + inStream.createProperty<PvdSweep, PxU32>("pose_baseIndex"); + inStream.createProperty<PvdSweep, PxU32>("pose_count"); + inStream.createProperty<PvdSweep, String>("filterData_arrayName"); + inStream.createProperty<PvdSweep, PxU32>("filterData_baseIndex"); + inStream.createProperty<PvdSweep, PxU32>("filterData_count"); + inStream.createProperty<PvdSweep, String>("hits_arrayName"); + inStream.createProperty<PvdSweep, PxU32>("hits_baseIndex"); + inStream.createProperty<PvdSweep, PxU32>("hits_count"); +} + +static PX_FORCE_INLINE void registerPvdOverlap(PvdDataStream& inStream) +{ + inStream.createClass<PvdOverlap>(); + definePropertyEnums<PvdOverlap, SceneQueryIDConvertor, NameValuePair>(inStream, "type"); + inStream.createProperty<PvdOverlap, PxFilterData>("filterData"); + definePropertyFlags<PvdOverlap, PxEnumTraits<physx::PxQueryFlag::Enum>, PxU32ToName>(inStream, "filterFlags"); + inStream.createProperty<PvdOverlap, PxTransform>("pose"); + inStream.createProperty<PvdOverlap, String>("geom_arrayName"); + inStream.createProperty<PvdOverlap, PxU32>("geom_baseIndex"); + inStream.createProperty<PvdOverlap, PxU32>("geom_count"); + inStream.createProperty<PvdOverlap, String>("hits_arrayName"); + inStream.createProperty<PvdOverlap, PxU32>("hits_baseIndex"); + inStream.createProperty<PvdOverlap, PxU32>("hits_count"); +} + +static PX_FORCE_INLINE void registerPvdSqHit(PvdDataStream& inStream) +{ + inStream.createClass<PvdSqHit>(); + inStream.createProperty<PvdSqHit, ObjectRef>("Shape"); + inStream.createProperty<PvdSqHit, ObjectRef>("Actor"); + inStream.createProperty<PvdSqHit, PxU32>("FaceIndex"); + definePropertyFlags<PvdSqHit, PxEnumTraits<physx::PxHitFlag::Enum>, PxU32ToName>(inStream, "Flags"); + inStream.createProperty<PvdSqHit, PxVec3>("Impact"); + inStream.createProperty<PvdSqHit, PxVec3>("Normal"); + inStream.createProperty<PvdSqHit, PxF32>("Distance"); + inStream.createProperty<PvdSqHit, PxF32>("U"); + inStream.createProperty<PvdSqHit, PxF32>("V"); +} + +void PvdMetaDataBinding::registerSDKProperties(PvdDataStream& inStream) +{ + if (inStream.isClassExist<PxPhysics>()) + return; + // PxPhysics + { + inStream.createClass<PxPhysics>(); + PvdPropertyDefinitionHelper& helper(inStream.getPropertyDefinitionHelper()); + PvdClassInfoDefine definitionObj(helper, getPvdNamespacedNameForType<PxPhysics>()); + helper.pushName("TolerancesScale"); + visitAllPvdProperties<PxTolerancesScale>(definitionObj); + helper.popName(); + inStream.createProperty<PxPhysics, ObjectRef>("Scenes", "children", PropertyType::Array); + inStream.createProperty<PxPhysics, ObjectRef>("SharedShapes", "children", PropertyType::Array); + inStream.createProperty<PxPhysics, ObjectRef>("Materials", "children", PropertyType::Array); + inStream.createProperty<PxPhysics, ObjectRef>("HeightFields", "children", PropertyType::Array); + inStream.createProperty<PxPhysics, ObjectRef>("ConvexMeshes", "children", PropertyType::Array); + inStream.createProperty<PxPhysics, ObjectRef>("TriangleMeshes", "children", PropertyType::Array); + inStream.createProperty<PxPhysics, ObjectRef>("ClothFabrics", "children", PropertyType::Array); + inStream.createProperty<PxPhysics, PxU32>("Version.Major"); + inStream.createProperty<PxPhysics, PxU32>("Version.Minor"); + inStream.createProperty<PxPhysics, PxU32>("Version.Bugfix"); + inStream.createProperty<PxPhysics, String>("Version.Build"); + definePropertyStruct<PxTolerancesScale, PxTolerancesScaleGeneratedValues, PxPhysics>(inStream, "TolerancesScale"); + } + { // PxGeometry + inStream.createClass<PxGeometry>(); + inStream.createProperty<PxGeometry, ObjectRef>("Shape", "parents", PropertyType::Scalar); + } + { // PxBoxGeometry + createClassDeriveAndDefineProperties<PxBoxGeometry, PxGeometry>(inStream); + definePropertyStruct<PxBoxGeometry, PxBoxGeometryGeneratedValues, PxBoxGeometry>(inStream); + } + { // PxSphereGeometry + createClassDeriveAndDefineProperties<PxSphereGeometry, PxGeometry>(inStream); + definePropertyStruct<PxSphereGeometry, PxSphereGeometryGeneratedValues, PxSphereGeometry>(inStream); + } + { // PxCapsuleGeometry + createClassDeriveAndDefineProperties<PxCapsuleGeometry, PxGeometry>(inStream); + definePropertyStruct<PxCapsuleGeometry, PxCapsuleGeometryGeneratedValues, PxCapsuleGeometry>(inStream); + } + { // PxPlaneGeometry + createClassDeriveAndDefineProperties<PxPlaneGeometry, PxGeometry>(inStream); + } + { // PxConvexMeshGeometry + createClassDeriveAndDefineProperties<PxConvexMeshGeometry, PxGeometry>(inStream); + definePropertyStruct<PxConvexMeshGeometry, PxConvexMeshGeometryGeneratedValues, PxConvexMeshGeometry>(inStream); + } + { // PxTriangleMeshGeometry + createClassDeriveAndDefineProperties<PxTriangleMeshGeometry, PxGeometry>(inStream); + definePropertyStruct<PxTriangleMeshGeometry, PxTriangleMeshGeometryGeneratedValues, PxTriangleMeshGeometry>(inStream); + } + { // PxHeightFieldGeometry + createClassDeriveAndDefineProperties<PxHeightFieldGeometry, PxGeometry>(inStream); + definePropertyStruct<PxHeightFieldGeometry, PxHeightFieldGeometryGeneratedValues, PxHeightFieldGeometry>(inStream); + } + + // PxScene + { + // PT: TODO: why inline this for PvdContact but do PvdRaycast/etc in separate functions? + { // contact information + inStream.createClass<PvdContact>(); + inStream.createProperty<PvdContact, PxVec3>("Point"); + inStream.createProperty<PvdContact, PxVec3>("Axis"); + inStream.createProperty<PvdContact, ObjectRef>("Shapes[0]"); + inStream.createProperty<PvdContact, ObjectRef>("Shapes[1]"); + inStream.createProperty<PvdContact, PxF32>("Separation"); + inStream.createProperty<PvdContact, PxF32>("NormalForce"); + inStream.createProperty<PvdContact, PxU32>("InternalFaceIndex[0]"); + inStream.createProperty<PvdContact, PxU32>("InternalFaceIndex[1]"); + inStream.createProperty<PvdContact, bool>("NormalForceValid"); + } + + registerPvdSqHit(inStream); + registerPvdRaycast(inStream); + registerPvdSweep(inStream); + registerPvdOverlap(inStream); + + inStream.createClass<PxScene>(); + PvdPropertyDefinitionHelper& helper(inStream.getPropertyDefinitionHelper()); + PvdClassInfoDefine definitionObj(helper, getPvdNamespacedNameForType<PxScene>()); + visitAllPvdProperties<PxSceneDesc>(definitionObj); + helper.pushName("SimulationStatistics"); + visitAllPvdProperties<PxSimulationStatistics>(definitionObj); + helper.popName(); + inStream.createProperty<PxScene, ObjectRef>("Physics", "parents", PropertyType::Scalar); + inStream.createProperty<PxScene, PxU32>("Timestamp"); + inStream.createProperty<PxScene, PxReal>("SimulateElapsedTime"); + definePropertyStruct<PxSceneDesc, PxSceneDescGeneratedValues, PxScene>(inStream); + definePropertyStruct<PxSimulationStatistics, PxSimulationStatisticsGeneratedValues, PxScene>(inStream, "SimulationStatistics"); + inStream.createProperty<PxScene, PvdContact>("Contacts", "", PropertyType::Array); + + inStream.createProperty<PxScene, PvdOverlap>("SceneQueries.Overlaps", "", PropertyType::Array); + inStream.createProperty<PxScene, PvdSweep>("SceneQueries.Sweeps", "", PropertyType::Array); + inStream.createProperty<PxScene, PvdSqHit>("SceneQueries.Hits", "", PropertyType::Array); + inStream.createProperty<PxScene, PvdRaycast>("SceneQueries.Raycasts", "", PropertyType::Array); + inStream.createProperty<PxScene, PxTransform>("SceneQueries.PoseList", "", PropertyType::Array); + inStream.createProperty<PxScene, PxFilterData>("SceneQueries.FilterDataList", "", PropertyType::Array); + inStream.createProperty<PxScene, ObjectRef>("SceneQueries.GeometryList", "", PropertyType::Array); + + inStream.createProperty<PxScene, PvdOverlap>("BatchedQueries.Overlaps", "", PropertyType::Array); + inStream.createProperty<PxScene, PvdSweep>("BatchedQueries.Sweeps", "", PropertyType::Array); + inStream.createProperty<PxScene, PvdSqHit>("BatchedQueries.Hits", "", PropertyType::Array); + inStream.createProperty<PxScene, PvdRaycast>("BatchedQueries.Raycasts", "", PropertyType::Array); + inStream.createProperty<PxScene, PxTransform>("BatchedQueries.PoseList", "", PropertyType::Array); + inStream.createProperty<PxScene, PxFilterData>("BatchedQueries.FilterDataList", "", PropertyType::Array); + inStream.createProperty<PxScene, ObjectRef>("BatchedQueries.GeometryList", "", PropertyType::Array); + + inStream.createProperty<PxScene, ObjectRef>("RigidStatics", "children", PropertyType::Array); + inStream.createProperty<PxScene, ObjectRef>("RigidDynamics", "children", PropertyType::Array); + inStream.createProperty<PxScene, ObjectRef>("Articulations", "children", PropertyType::Array); + inStream.createProperty<PxScene, ObjectRef>("ParticleSystems", "children", PropertyType::Array); + inStream.createProperty<PxScene, ObjectRef>("ParticleFluids", "children", PropertyType::Array); + inStream.createProperty<PxScene, ObjectRef>("Cloths", "children", PropertyType::Array); + inStream.createProperty<PxScene, ObjectRef>("Joints", "children", PropertyType::Array); + inStream.createProperty<PxScene, ObjectRef>("Aggregates", "children", PropertyType::Array); + } + // PxMaterial + { + createClassAndDefineProperties<PxMaterial>(inStream); + definePropertyStruct<PxMaterial, PxMaterialGeneratedValues, PxMaterial>(inStream); + inStream.createProperty<PxMaterial, ObjectRef>("Physics", "parents", PropertyType::Scalar); + } + // PxHeightField + { + { + inStream.createClass<PxHeightFieldSample>(); + inStream.createProperty<PxHeightFieldSample, PxU16>("Height"); + inStream.createProperty<PxHeightFieldSample, PxU8>("MaterialIndex[0]"); + inStream.createProperty<PxHeightFieldSample, PxU8>("MaterialIndex[1]"); + } + + inStream.createClass<PxHeightField>(); + // It is important the PVD fields match the RepX fields, so this has + // to be hand coded. + PvdPropertyDefinitionHelper& helper(inStream.getPropertyDefinitionHelper()); + PvdClassInfoDefine definitionObj(helper, getPvdNamespacedNameForType<PxHeightField>()); + visitAllPvdProperties<PxHeightFieldDesc>(definitionObj); + inStream.createProperty<PxHeightField, PxHeightFieldSample>("Samples", "", PropertyType::Array); + inStream.createProperty<PxHeightField, ObjectRef>("Physics", "parents", PropertyType::Scalar); + definePropertyStruct<PxHeightFieldDesc, PxHeightFieldDescGeneratedValues, PxHeightField>(inStream); + } + // PxConvexMesh + { + { // hull polygon data. + inStream.createClass<PvdHullPolygonData>(); + inStream.createProperty<PvdHullPolygonData, PxU16>("NumVertices"); + inStream.createProperty<PvdHullPolygonData, PxU16>("IndexBase"); + } + inStream.createClass<PxConvexMesh>(); + inStream.createProperty<PxConvexMesh, PxF32>("Mass"); + inStream.createProperty<PxConvexMesh, PxMat33>("LocalInertia"); + inStream.createProperty<PxConvexMesh, PxVec3>("LocalCenterOfMass"); + inStream.createProperty<PxConvexMesh, PxVec3>("Points", "", PropertyType::Array); + inStream.createProperty<PxConvexMesh, PvdHullPolygonData>("HullPolygons", "", PropertyType::Array); + inStream.createProperty<PxConvexMesh, PxU8>("PolygonIndexes", "", PropertyType::Array); + inStream.createProperty<PxConvexMesh, ObjectRef>("Physics", "parents", PropertyType::Scalar); + } + // PxTriangleMesh + { + inStream.createClass<PxTriangleMesh>(); + inStream.createProperty<PxTriangleMesh, PxVec3>("Points", "", PropertyType::Array); + inStream.createProperty<PxTriangleMesh, PxU32>("NbTriangles", "", PropertyType::Scalar); + inStream.createProperty<PxTriangleMesh, PxU32>("Triangles", "", PropertyType::Array); + inStream.createProperty<PxTriangleMesh, PxU16>("MaterialIndices", "", PropertyType::Array); + inStream.createProperty<PxTriangleMesh, ObjectRef>("Physics", "parents", PropertyType::Scalar); + } + { // PxShape + createClassAndDefineProperties<PxShape>(inStream); + definePropertyStruct<PxShape, PxShapeGeneratedValues, PxShape>(inStream); + inStream.createProperty<PxShape, ObjectRef>("Geometry", "children"); + inStream.createProperty<PxShape, ObjectRef>("Materials", "children", PropertyType::Array); + inStream.createProperty<PxShape, ObjectRef>("Actor", "parents"); + } + // PxActor + { + createClassAndDefineProperties<PxActor>(inStream); + inStream.createProperty<PxActor, ObjectRef>("Scene", "parents"); + } + // PxRigidActor + { + createClassDeriveAndDefineProperties<PxRigidActor, PxActor>(inStream); + inStream.createProperty<PxRigidActor, ObjectRef>("Shapes", "children", PropertyType::Array); + inStream.createProperty<PxRigidActor, ObjectRef>("Joints", "children", PropertyType::Array); + } + // PxRigidStatic + { + createClassDeriveAndDefineProperties<PxRigidStatic, PxRigidActor>(inStream); + definePropertyStruct<PxRigidStatic, PxRigidStaticGeneratedValues, PxRigidStatic>(inStream); + } + { // PxRigidBody + createClassDeriveAndDefineProperties<PxRigidBody, PxRigidActor>(inStream); + } + // PxRigidDynamic + { + createClassDeriveAndDefineProperties<PxRigidDynamic, PxRigidBody>(inStream); + // If anyone adds a 'getKinematicTarget' to PxRigidDynamic you can remove the line + // below (after the code generator has run). + inStream.createProperty<PxRigidDynamic, PxTransform>("KinematicTarget"); + definePropertyStruct<PxRigidDynamic, PxRigidDynamicGeneratedValues, PxRigidDynamic>(inStream); + // Manually define the update struct. + PvdPropertyDefinitionHelper& helper(inStream.getPropertyDefinitionHelper()); + /*struct PxRigidDynamicUpdateBlock + { + Transform GlobalPose; + Float3 LinearVelocity; + Float3 AngularVelocity; + PxU8 IsSleeping; + PxU8 padding[3]; + }; + */ + helper.pushName("GlobalPose"); + helper.addPropertyMessageArg<PxTransform>(PX_OFFSET_OF_RT(PxRigidDynamicUpdateBlock, GlobalPose)); + helper.popName(); + helper.pushName("LinearVelocity"); + helper.addPropertyMessageArg<PxVec3>(PX_OFFSET_OF_RT(PxRigidDynamicUpdateBlock, LinearVelocity)); + helper.popName(); + helper.pushName("AngularVelocity"); + helper.addPropertyMessageArg<PxVec3>(PX_OFFSET_OF_RT(PxRigidDynamicUpdateBlock, AngularVelocity)); + helper.popName(); + helper.pushName("IsSleeping"); + helper.addPropertyMessageArg<bool>(PX_OFFSET_OF_RT(PxRigidDynamicUpdateBlock, IsSleeping)); + helper.popName(); + helper.addPropertyMessage<PxRigidDynamic, PxRigidDynamicUpdateBlock>(); + } + { // PxArticulation + createClassAndDefineProperties<PxArticulation>(inStream); + inStream.createProperty<PxArticulation, ObjectRef>("Scene", "parents"); + inStream.createProperty<PxArticulation, ObjectRef>("Links", "children", PropertyType::Array); + definePropertyStruct<PxArticulation, PxArticulationGeneratedValues, PxArticulation>(inStream); + } + { // PxArticulationLink + createClassDeriveAndDefineProperties<PxArticulationLink, PxRigidBody>(inStream); + inStream.createProperty<PxArticulationLink, ObjectRef>("Parent", "parents"); + inStream.createProperty<PxArticulationLink, ObjectRef>("Links", "children", PropertyType::Array); + inStream.createProperty<PxArticulationLink, ObjectRef>("InboundJoint", "children"); + definePropertyStruct<PxArticulationLink, PxArticulationLinkGeneratedValues, PxArticulationLink>(inStream); + + PvdPropertyDefinitionHelper& helper(inStream.getPropertyDefinitionHelper()); + /*struct PxArticulationLinkUpdateBlock + { + Transform GlobalPose; + Float3 LinearVelocity; + Float3 AngularVelocity; + }; + */ + helper.pushName("GlobalPose"); + helper.addPropertyMessageArg<PxTransform>(PX_OFFSET_OF(PxArticulationLinkUpdateBlock, GlobalPose)); + helper.popName(); + helper.pushName("LinearVelocity"); + helper.addPropertyMessageArg<PxVec3>(PX_OFFSET_OF(PxArticulationLinkUpdateBlock, LinearVelocity)); + helper.popName(); + helper.pushName("AngularVelocity"); + helper.addPropertyMessageArg<PxVec3>(PX_OFFSET_OF(PxArticulationLinkUpdateBlock, AngularVelocity)); + helper.popName(); + helper.addPropertyMessage<PxArticulationLink, PxArticulationLinkUpdateBlock>(); + } + { // PxArticulationJoint + createClassAndDefineProperties<PxArticulationJoint>(inStream); + inStream.createProperty<PxArticulationJoint, ObjectRef>("Link", "parents"); + definePropertyStruct<PxArticulationJoint, PxArticulationJointGeneratedValues, PxArticulationJoint>(inStream); + } + { // PxConstraint + createClassAndDefineProperties<PxConstraint>(inStream); + definePropertyStruct<PxConstraint, PxConstraintGeneratedValues, PxConstraint>(inStream); + } +#if PX_USE_PARTICLE_SYSTEM_API + { // PxParticleBase + createClassDeriveAndDefineProperties<PxParticleBase, PxActor>(inStream); + PvdPropertyDefinitionHelper& helper(inStream.getPropertyDefinitionHelper()); + PvdClassInfoDefine definitionObj(helper, getPvdNamespacedNameForType<PxParticleBase>()); + visitParticleSystemBufferProperties(makePvdPropertyFilter(definitionObj)); + } + { // PxParticleSystem + createClassDeriveAndDefineProperties<PxParticleSystem, PxParticleBase>(inStream); + inStream.createProperty<PxParticleSystem, PxU32>("NbParticles"); + inStream.createProperty<PxParticleSystem, PxU32>("ValidParticleRange"); + inStream.createProperty<PxParticleSystem, PxU32>("ValidParticleBitmap", "", PropertyType::Array); + definePropertyStruct<PxParticleSystem, PxParticleSystemGeneratedValues, PxParticleSystem>(inStream); + } + { // PxParticleFluid + createClassDeriveAndDefineProperties<PxParticleFluid, PxParticleBase>(inStream); + inStream.createProperty<PxParticleFluid, PxU32>("NbParticles"); + inStream.createProperty<PxParticleFluid, PxU32>("ValidParticleRange"); + inStream.createProperty<PxParticleFluid, PxU32>("ValidParticleBitmap", "", PropertyType::Array); + PvdPropertyDefinitionHelper& helper(inStream.getPropertyDefinitionHelper()); + PvdClassInfoDefine definitionObj(helper, getPvdNamespacedNameForType<PxParticleFluid>()); + visitParticleFluidBufferProperties(makePvdPropertyFilter(definitionObj)); + definePropertyStruct<PxParticleFluid, PxParticleFluidGeneratedValues, PxParticleFluid>(inStream); + } +#endif +#if PX_USE_CLOTH_API + { // PxClothFabricPhase + createClassAndDefineProperties<PxClothFabricPhase>(inStream); + } + { // PxClothFabric + createClassAndDefineProperties<PxClothFabric>(inStream); + definePropertyStruct<PxClothFabric, PxClothFabricGeneratedValues, PxClothFabric>(inStream); + inStream.createProperty<PxClothFabric, ObjectRef>("Physics", "parents"); + inStream.createProperty<PxClothFabric, ObjectRef>("Cloths", "children", PropertyType::Array); + inStream.createProperty<PxClothFabric, PxClothFabricPhase>("Phases", "", PropertyType::Array); + } + { // PxCloth + { // PxClothParticle + createClassAndDefineProperties<PxClothParticle>(inStream); + } + { // PxClothStretchConfig + createClassAndDefineProperties<PxClothStretchConfig>(inStream); + } + { // PxClothTetherConstraintConfig + createClassAndDefineProperties<PxClothTetherConfig>(inStream); + } + { // PvdPositionAndRadius + inStream.createClass<PvdPositionAndRadius>(); + inStream.createProperty<PvdPositionAndRadius, PxVec3>("Position"); + inStream.createProperty<PvdPositionAndRadius, PxF32>("Radius"); + } + createClassDeriveAndDefineProperties<PxCloth, PxActor>(inStream); + definePropertyStruct<PxCloth, PxClothGeneratedValues, PxCloth>(inStream); + inStream.createProperty<PxCloth, ObjectRef>("Fabric"); + inStream.createProperty<PxCloth, PxClothParticle>("ParticleBuffer", "", PropertyType::Array); + inStream.createProperty<PxCloth, PxClothParticle>("ParticleAccelerations", "", PropertyType::Array); + inStream.createProperty<PxCloth, PvdPositionAndRadius>("MotionConstraints", "", PropertyType::Array); + inStream.createProperty<PxCloth, PvdPositionAndRadius>("CollisionSpheres", "", PropertyType::Array); + inStream.createProperty<PxCloth, PvdPositionAndRadius>("SeparationConstraints", "", PropertyType::Array); + inStream.createProperty<PxCloth, PxU32>("CollisionSpherePairs", "", PropertyType::Array); + inStream.createProperty<PxCloth, PvdPositionAndRadius>("CollisionPlanes", "", PropertyType::Array); + inStream.createProperty<PxCloth, PxU32>("CollisionConvexMasks", "", PropertyType::Array); + inStream.createProperty<PxCloth, PxVec3>("CollisionTriangles", "", PropertyType::Array); + inStream.createProperty<PxCloth, PxU32>("VirtualParticles", "", PropertyType::Array); + inStream.createProperty<PxCloth, PxVec3>("VirtualParticleWeights", "", PropertyType::Array); + inStream.createProperty<PxCloth, PxU32>("SelfCollisionIndices", "", PropertyType::Array); + inStream.createProperty<PxCloth, PxVec4>("RestPositions", "", PropertyType::Array); + } +#endif + { + // PxAggregate + createClassAndDefineProperties<PxAggregate>(inStream); + inStream.createProperty<PxAggregate, ObjectRef>("Scene", "parents"); + definePropertyStruct<PxAggregate, PxAggregateGeneratedValues, PxAggregate>(inStream); + inStream.createProperty<PxAggregate, ObjectRef>("Actors", "children", PropertyType::Array); + inStream.createProperty<PxAggregate, ObjectRef>("Articulations", "children", PropertyType::Array); + } +} + +template <typename TClassType, typename TValueType, typename TDataType> +static void doSendAllProperties(PvdDataStream& inStream, const TDataType* inDatatype, const void* instanceId) +{ + TValueType theValues(inDatatype); + inStream.setPropertyMessage(instanceId, theValues); +} + +void PvdMetaDataBinding::sendAllProperties(PvdDataStream& inStream, const PxPhysics& inPhysics) +{ + PxTolerancesScale theScale(inPhysics.getTolerancesScale()); + doSendAllProperties<PxPhysics, PxTolerancesScaleGeneratedValues>(inStream, &theScale, &inPhysics); + inStream.setPropertyValue(&inPhysics, "Version.Major", PxU32(PX_PHYSICS_VERSION_MAJOR)); + inStream.setPropertyValue(&inPhysics, "Version.Minor", PxU32(PX_PHYSICS_VERSION_MINOR)); + inStream.setPropertyValue(&inPhysics, "Version.Bugfix", PxU32(PX_PHYSICS_VERSION_BUGFIX)); + +#if PX_CHECKED +#if defined(NDEBUG) + // This is a checked build + String buildType = "Checked"; +#elif defined(_DEBUG) + // This is a debug build + String buildType = "Debug"; +#endif +#elif PX_PROFILE + String buildType = "Profile"; +#elif defined(NDEBUG) + // This is a release build + String buildType = "Release"; +#endif + inStream.setPropertyValue(&inPhysics, "Version.Build", buildType); +} + +void PvdMetaDataBinding::sendAllProperties(PvdDataStream& inStream, const PxScene& inScene) +{ + PxPhysics& physics(const_cast<PxScene&>(inScene).getPhysics()); + PxTolerancesScale theScale; + PxSceneDesc theDesc(theScale); + + { + theDesc.gravity = inScene.getGravity(); + + theDesc.simulationEventCallback = inScene.getSimulationEventCallback(PX_DEFAULT_CLIENT); + theDesc.contactModifyCallback = inScene.getContactModifyCallback(); + theDesc.ccdContactModifyCallback = inScene.getCCDContactModifyCallback(); + + theDesc.filterShaderData = inScene.getFilterShaderData(); + theDesc.filterShaderDataSize = inScene.getFilterShaderDataSize(); + theDesc.filterShader = inScene.getFilterShader(); + theDesc.filterCallback = inScene.getFilterCallback(); + + theDesc.broadPhaseType = inScene.getBroadPhaseType(); + theDesc.broadPhaseCallback = inScene.getBroadPhaseCallback(); + + theDesc.limits = inScene.getLimits(); + + theDesc.frictionType = inScene.getFrictionType(); + + theDesc.bounceThresholdVelocity = inScene.getBounceThresholdVelocity(); + + theDesc.frictionOffsetThreshold = inScene.getFrictionOffsetThreshold(); + + theDesc.flags = inScene.getFlags(); + + theDesc.cpuDispatcher = inScene.getCpuDispatcher(); + theDesc.gpuDispatcher = inScene.getGpuDispatcher(); + + theDesc.staticStructure = inScene.getStaticStructure(); + theDesc.dynamicStructure = inScene.getDynamicStructure(); + theDesc.dynamicTreeRebuildRateHint = inScene.getDynamicTreeRebuildRateHint(); + + theDesc.userData = inScene.userData; + + theDesc.solverBatchSize = inScene.getSolverBatchSize(); + + // theDesc.nbContactDataBlocks = inScene.getNbContactDataBlocksUsed(); + // theDesc.maxNbContactDataBlocks = inScene.getMaxNbContactDataBlocksUsed(); + + theDesc.contactReportStreamBufferSize = inScene.getContactReportStreamBufferSize(); + + theDesc.ccdMaxPasses = inScene.getCCDMaxPasses(); + + // theDesc.simulationOrder = inScene.getSimulationOrder(); + + theDesc.wakeCounterResetValue = inScene.getWakeCounterResetValue(); + } + + PxSceneDescGeneratedValues theValues(&theDesc); + inStream.setPropertyMessage(&inScene, theValues); + // Create parent/child relationship. + inStream.setPropertyValue(&inScene, "Physics", reinterpret_cast<const void*>(&physics)); + inStream.pushBackObjectRef(&physics, "Scenes", &inScene); +} + +void PvdMetaDataBinding::sendBeginFrame(PvdDataStream& inStream, const PxScene* inScene, PxReal simulateElapsedTime) +{ + inStream.beginSection(inScene, "frame"); + inStream.setPropertyValue(inScene, "Timestamp", inScene->getTimestamp()); + inStream.setPropertyValue(inScene, "SimulateElapsedTime", simulateElapsedTime); +} + +template <typename TDataType> +struct NullConverter +{ + void operator()(TDataType& data, const TDataType& src) + { + data = src; + } +}; + +template <typename TTargetType, PxU32 T_NUM_ITEMS, typename TSourceType = TTargetType, + typename Converter = NullConverter<TTargetType> > +class ScopedPropertyValueSender +{ + TTargetType mStack[T_NUM_ITEMS]; + TTargetType* mCur; + const TTargetType* mEnd; + PvdDataStream& mStream; + + public: + ScopedPropertyValueSender(PvdDataStream& inStream, const void* inObj, String name) + : mCur(mStack), mEnd(&mStack[T_NUM_ITEMS]), mStream(inStream) + { + mStream.beginSetPropertyValue(inObj, name, getPvdNamespacedNameForType<TTargetType>()); + } + + ~ScopedPropertyValueSender() + { + if(mStack != mCur) + { + PxU32 size = sizeof(TTargetType) * PxU32(mCur - mStack); + mStream.appendPropertyValueData(DataRef<const PxU8>(reinterpret_cast<PxU8*>(mStack), size)); + } + mStream.endSetPropertyValue(); + } + + void append(const TSourceType& data) + { + Converter()(*mCur, data); + if(mCur < mEnd - 1) + ++mCur; + else + { + mStream.appendPropertyValueData(DataRef<const PxU8>(reinterpret_cast<PxU8*>(mStack), sizeof mStack)); + mCur = mStack; + } + } + + private: + ScopedPropertyValueSender& operator=(const ScopedPropertyValueSender&); +}; + +void PvdMetaDataBinding::sendContacts(PvdDataStream& inStream, const PxScene& inScene) +{ + inStream.setPropertyValue(&inScene, "Contacts", DataRef<const PxU8>(), getPvdNamespacedNameForType<PvdContact>()); +} + +struct PvdContactConverter +{ + void operator()(PvdContact& data, const Sc::Contact& src) + { + data.point = src.point; + data.axis = src.normal; + data.shape0 = src.shape0; + data.shape1 = src.shape1; + data.separation = src.separation; + data.normalForce = src.normalForce; + data.internalFaceIndex0 = src.faceIndex0; + data.internalFaceIndex1 = src.faceIndex1; + data.normalForceAvailable = src.normalForceAvailable; + } +}; + +void PvdMetaDataBinding::sendContacts(PvdDataStream& inStream, const PxScene& inScene, Array<Contact>& inContacts) +{ + ScopedPropertyValueSender<PvdContact, 32, Sc::Contact, PvdContactConverter> sender(inStream, &inScene, "Contacts"); + + for(PxU32 i = 0; i < inContacts.size(); i++) + { + sender.append(inContacts[i]); + } +} + +void PvdMetaDataBinding::sendStats(PvdDataStream& inStream, const PxScene* inScene, void* triMeshCacheStats) +{ + PxSimulationStatistics theStats; + inScene->getSimulationStatistics(theStats); + + PX_UNUSED(triMeshCacheStats); +#if PX_SUPPORT_GPU_PHYSX + if(triMeshCacheStats) + { + // gpu triangle mesh cache stats + PxTriangleMeshCacheStatistics* tmp = static_cast<PxTriangleMeshCacheStatistics*>(triMeshCacheStats); + theStats.particlesGpuMeshCacheSize = tmp->bytesTotal; + theStats.particlesGpuMeshCacheUsed = tmp->bytesUsed; + theStats.particlesGpuMeshCacheHitrate = tmp->percentageHitrate; + } +#endif + + PxSimulationStatisticsGeneratedValues values(&theStats); + inStream.setPropertyMessage(inScene, values); +} + +void PvdMetaDataBinding::sendEndFrame(PvdDataStream& inStream, const PxScene* inScene) +{ + //flush other client + inStream.endSection(inScene, "frame"); +} + +template <typename TDataType> +void addPhysicsGroupProperty(PvdDataStream& inStream, const char* groupName, const TDataType& inData, const PxPhysics& ownerPhysics) +{ + inStream.setPropertyValue(&inData, "Physics", reinterpret_cast<const void*>(&ownerPhysics)); + inStream.pushBackObjectRef(&ownerPhysics, groupName, &inData); + // Buffer type objects *have* to be flushed directly out once created else scene creation doesn't work. +} + +template <typename TDataType> +void removePhysicsGroupProperty(PvdDataStream& inStream, const char* groupName, const TDataType& inData, const PxPhysics& ownerPhysics) +{ + inStream.removeObjectRef(&ownerPhysics, groupName, &inData); + inStream.destroyInstance(&inData); +} + +void PvdMetaDataBinding::createInstance(PvdDataStream& inStream, const PxMaterial& inMaterial, const PxPhysics& ownerPhysics) +{ + inStream.createInstance(&inMaterial); + sendAllProperties(inStream, inMaterial); + addPhysicsGroupProperty(inStream, "Materials", inMaterial, ownerPhysics); +} + +void PvdMetaDataBinding::sendAllProperties(PvdDataStream& inStream, const PxMaterial& inMaterial) +{ + PxMaterialGeneratedValues values(&inMaterial); + inStream.setPropertyMessage(&inMaterial, values); +} + +void PvdMetaDataBinding::destroyInstance(PvdDataStream& inStream, const PxMaterial& inMaterial, const PxPhysics& ownerPhysics) +{ + removePhysicsGroupProperty(inStream, "Materials", inMaterial, ownerPhysics); +} + +void PvdMetaDataBinding::sendAllProperties(PvdDataStream& inStream, const PxHeightField& inData) +{ + PxHeightFieldDesc theDesc; + // Save the height field to desc. + theDesc.nbRows = inData.getNbRows(); + theDesc.nbColumns = inData.getNbColumns(); + theDesc.format = inData.getFormat(); + theDesc.samples.stride = inData.getSampleStride(); + theDesc.samples.data = NULL; + theDesc.thickness = inData.getThickness(); + theDesc.convexEdgeThreshold = inData.getConvexEdgeThreshold(); + theDesc.flags = inData.getFlags(); + + PxU32 theCellCount = inData.getNbRows() * inData.getNbColumns(); + PxU32 theSampleStride = sizeof(PxHeightFieldSample); + PxU32 theSampleBufSize = theCellCount * theSampleStride; + mBindingData->mTempU8Array.resize(theSampleBufSize); + PxHeightFieldSample* theSamples = reinterpret_cast<PxHeightFieldSample*>(mBindingData->mTempU8Array.begin()); + inData.saveCells(theSamples, theSampleBufSize); + theDesc.samples.data = theSamples; + PxHeightFieldDescGeneratedValues values(&theDesc); + inStream.setPropertyMessage(&inData, values); + PxHeightFieldSample* theSampleData = reinterpret_cast<PxHeightFieldSample*>(mBindingData->mTempU8Array.begin()); + inStream.setPropertyValue(&inData, "Samples", theSampleData, theCellCount); +} + +void PvdMetaDataBinding::createInstance(PvdDataStream& inStream, const PxHeightField& inData, const PxPhysics& ownerPhysics) +{ + inStream.createInstance(&inData); + sendAllProperties(inStream, inData); + addPhysicsGroupProperty(inStream, "HeightFields", inData, ownerPhysics); +} + +void PvdMetaDataBinding::destroyInstance(PvdDataStream& inStream, const PxHeightField& inData, const PxPhysics& ownerPhysics) +{ + removePhysicsGroupProperty(inStream, "HeightFields", inData, ownerPhysics); +} + +void PvdMetaDataBinding::createInstance(PvdDataStream& inStream, const PxConvexMesh& inData, const PxPhysics& ownerPhysics) +{ + inStream.createInstance(&inData); + PxReal mass; + PxMat33 localInertia; + PxVec3 localCom; + inData.getMassInformation(mass, reinterpret_cast<PxMat33&>(localInertia), localCom); + inStream.setPropertyValue(&inData, "Mass", mass); + inStream.setPropertyValue(&inData, "LocalInertia", localInertia); + inStream.setPropertyValue(&inData, "LocalCenterOfMass", localCom); + + // update arrays: + // vertex Array: + { + const PxVec3* vertexPtr = inData.getVertices(); + const PxU32 numVertices = inData.getNbVertices(); + inStream.setPropertyValue(&inData, "Points", vertexPtr, numVertices); + } + + // HullPolyArray: + PxU16 maxIndices = 0; + { + + PxU32 numPolygons = inData.getNbPolygons(); + PvdHullPolygonData* tempData = mBindingData->allocateTemp<PvdHullPolygonData>(numPolygons); + // Get the polygon data stripping the plane equations + for(PxU32 index = 0; index < numPolygons; index++) + { + PxHullPolygon curOut; + inData.getPolygonData(index, curOut); + maxIndices = PxMax(maxIndices, PxU16(curOut.mIndexBase + curOut.mNbVerts)); + tempData[index].mIndexBase = curOut.mIndexBase; + tempData[index].mNumVertices = curOut.mNbVerts; + } + inStream.setPropertyValue(&inData, "HullPolygons", tempData, numPolygons); + } + + // poly index Array: + { + const PxU8* indices = inData.getIndexBuffer(); + inStream.setPropertyValue(&inData, "PolygonIndexes", indices, maxIndices); + } + addPhysicsGroupProperty(inStream, "ConvexMeshes", inData, ownerPhysics); +} + +void PvdMetaDataBinding::destroyInstance(PvdDataStream& inStream, const PxConvexMesh& inData, const PxPhysics& ownerPhysics) +{ + removePhysicsGroupProperty(inStream, "ConvexMeshes", inData, ownerPhysics); +} + +void PvdMetaDataBinding::createInstance(PvdDataStream& inStream, const PxTriangleMesh& inData, const PxPhysics& ownerPhysics) +{ + inStream.createInstance(&inData); + bool hasMatIndex = inData.getTriangleMaterialIndex(0) != 0xffff; + // update arrays: + // vertex Array: + { + const PxVec3* vertexPtr = inData.getVertices(); + const PxU32 numVertices = inData.getNbVertices(); + inStream.setPropertyValue(&inData, "Points", vertexPtr, numVertices); + } + + // index Array: + { + const bool has16BitIndices = inData.getTriangleMeshFlags() & PxTriangleMeshFlag::e16_BIT_INDICES ? true : false; + const PxU32 numTriangles = inData.getNbTriangles(); + + inStream.setPropertyValue(&inData, "NbTriangles", numTriangles); + + const PxU32 numIndexes = numTriangles * 3; + const PxU8* trianglePtr = reinterpret_cast<const PxU8*>(inData.getTriangles()); + // We declared this type as a 32 bit integer above. + // PVD will automatically unsigned-extend data that is smaller than the target type. + if(has16BitIndices) + inStream.setPropertyValue(&inData, "Triangles", reinterpret_cast<const PxU16*>(trianglePtr), numIndexes); + else + inStream.setPropertyValue(&inData, "Triangles", reinterpret_cast<const PxU32*>(trianglePtr), numIndexes); + } + + // material Array: + if(hasMatIndex) + { + PxU32 numMaterials = inData.getNbTriangles(); + PxU16* matIndexData = mBindingData->allocateTemp<PxU16>(numMaterials); + for(PxU32 m = 0; m < numMaterials; m++) + matIndexData[m] = inData.getTriangleMaterialIndex(m); + inStream.setPropertyValue(&inData, "MaterialIndices", matIndexData, numMaterials); + } + addPhysicsGroupProperty(inStream, "TriangleMeshes", inData, ownerPhysics); +} + +void PvdMetaDataBinding::destroyInstance(PvdDataStream& inStream, const PxTriangleMesh& inData, const PxPhysics& ownerPhysics) +{ + removePhysicsGroupProperty(inStream, "TriangleMeshes", inData, ownerPhysics); +} + +template <typename TDataType> +void PvdMetaDataBinding::registrarPhysicsObject(PvdDataStream&, const TDataType&, PsPvd*) +{ +} + +template <> +void PvdMetaDataBinding::registrarPhysicsObject<PxConvexMeshGeometry>(PvdDataStream& inStream, const PxConvexMeshGeometry& geom, PsPvd* pvd) +{ + if(pvd->registerObject(geom.convexMesh)) + createInstance(inStream, *geom.convexMesh, PxGetPhysics()); +} + +template <> +void PvdMetaDataBinding::registrarPhysicsObject<PxTriangleMeshGeometry>(PvdDataStream& inStream, const PxTriangleMeshGeometry& geom, PsPvd* pvd) +{ + if(pvd->registerObject(geom.triangleMesh)) + createInstance(inStream, *geom.triangleMesh, PxGetPhysics()); +} + +template <> +void PvdMetaDataBinding::registrarPhysicsObject<PxHeightFieldGeometry>(PvdDataStream& inStream, const PxHeightFieldGeometry& geom, PsPvd* pvd) +{ + if(pvd->registerObject(geom.heightField)) + createInstance(inStream, *geom.heightField, PxGetPhysics()); +} + +template <typename TGeneratedValuesType, typename TGeomType> +void sendGeometry(PvdMetaDataBinding& metaBind, PvdDataStream& inStream, const PxShape& inShape, const TGeomType& geom, PsPvd* pvd) +{ + const void* geomInst = (reinterpret_cast<const PxU8*>(&inShape)) + 4; + inStream.createInstance(getPvdNamespacedNameForType<TGeomType>(), geomInst); + metaBind.registrarPhysicsObject<TGeomType>(inStream, geom, pvd); + TGeneratedValuesType values(&geom); + inStream.setPropertyMessage(geomInst, values); + inStream.setPropertyValue(&inShape, "Geometry", geomInst); + inStream.setPropertyValue(geomInst, "Shape", reinterpret_cast<const void*>(&inShape)); +} + +void setGeometry(PvdMetaDataBinding& metaBind, PvdDataStream& inStream, const PxShape& inObj, PsPvd* pvd) +{ + switch(inObj.getGeometryType()) + { +#define SEND_PVD_GEOM_TYPE(enumType, geomType, valueType) \ + case PxGeometryType::enumType: \ + { \ + Px##geomType geom; \ + inObj.get##geomType(geom); \ + sendGeometry<valueType>(metaBind, inStream, inObj, geom, pvd); \ + } \ + break; + SEND_PVD_GEOM_TYPE(eSPHERE, SphereGeometry, PxSphereGeometryGeneratedValues); + // Plane geometries don't have any properties, so this avoids using a property + // struct for them. + case PxGeometryType::ePLANE: + { + PxPlaneGeometry geom; + inObj.getPlaneGeometry(geom); + const void* geomInst = (reinterpret_cast<const PxU8*>(&inObj)) + 4; + inStream.createInstance(getPvdNamespacedNameForType<PxPlaneGeometry>(), geomInst); + inStream.setPropertyValue(&inObj, "Geometry", geomInst); + inStream.setPropertyValue(geomInst, "Shape", reinterpret_cast<const void*>(&inObj)); + } + break; + SEND_PVD_GEOM_TYPE(eCAPSULE, CapsuleGeometry, PxCapsuleGeometryGeneratedValues); + SEND_PVD_GEOM_TYPE(eBOX, BoxGeometry, PxBoxGeometryGeneratedValues); + SEND_PVD_GEOM_TYPE(eCONVEXMESH, ConvexMeshGeometry, PxConvexMeshGeometryGeneratedValues); + SEND_PVD_GEOM_TYPE(eTRIANGLEMESH, TriangleMeshGeometry, PxTriangleMeshGeometryGeneratedValues); + SEND_PVD_GEOM_TYPE(eHEIGHTFIELD, HeightFieldGeometry, PxHeightFieldGeometryGeneratedValues); +#undef SEND_PVD_GEOM_TYPE + case PxGeometryType::eGEOMETRY_COUNT: + case PxGeometryType::eINVALID: + PX_ASSERT(false); + break; + } +} + +void setMaterials(PvdMetaDataBinding& metaBing, PvdDataStream& inStream, const PxShape& inObj, PsPvd* pvd, PvdMetaDataBindingData* mBindingData) +{ + PxU32 numMaterials = inObj.getNbMaterials(); + PxMaterial** materialPtr = mBindingData->allocateTemp<PxMaterial*>(numMaterials); + inObj.getMaterials(materialPtr, numMaterials); + for(PxU32 idx = 0; idx < numMaterials; ++idx) + { + if(pvd->registerObject(materialPtr[idx])) + metaBing.createInstance(inStream, *materialPtr[idx], PxGetPhysics()); + inStream.pushBackObjectRef(&inObj, "Materials", materialPtr[idx]); + } +} + +void PvdMetaDataBinding::createInstance(PvdDataStream& inStream, const PxShape& inObj, const PxRigidActor& owner, PsPvd* pvd) +{ + if(!inStream.isInstanceValid(&owner)) + return; + + const OwnerActorsMap::Entry* entry = mBindingData->mOwnerActorsMap.find(&inObj); + if(entry != NULL) + { + if(!mBindingData->mOwnerActorsMap[&inObj]->contains(&owner)) + mBindingData->mOwnerActorsMap[&inObj]->insert(&owner); + } + else + { + OwnerActorsValueType* data = reinterpret_cast<OwnerActorsValueType*>( + PX_ALLOC(sizeof(OwnerActorsValueType), "mOwnerActorsMapValue")); //( 1 ); + OwnerActorsValueType* actors = PX_PLACEMENT_NEW(data, OwnerActorsValueType); + actors->insert(&owner); + + mBindingData->mOwnerActorsMap.insert(&inObj, actors); + } + + if(inStream.isInstanceValid(&inObj)) + { + inStream.pushBackObjectRef(&owner, "Shapes", &inObj); + return; + } + + inStream.createInstance(&inObj); + inStream.pushBackObjectRef(&owner, "Shapes", &inObj); + inStream.setPropertyValue(&inObj, "Actor", reinterpret_cast<const void*>(&owner)); + sendAllProperties(inStream, inObj); + setGeometry(*this, inStream, inObj, pvd); + setMaterials(*this, inStream, inObj, pvd, mBindingData); + if(!inObj.isExclusive()) + inStream.pushBackObjectRef(&owner.getScene()->getPhysics(), "SharedShapes", &inObj); +} + +void PvdMetaDataBinding::sendAllProperties(PvdDataStream& inStream, const PxShape& inObj) +{ + PxShapeGeneratedValues values(&inObj); + inStream.setPropertyMessage(&inObj, values); +} + +void PvdMetaDataBinding::releaseAndRecreateGeometry(PvdDataStream& inStream, const PxShape& inObj, PxPhysics& /*ownerPhysics*/, PsPvd* pvd) +{ + const void* geomInst = (reinterpret_cast<const PxU8*>(&inObj)) + 4; + inStream.destroyInstance(geomInst); + // Quick fix for HF modify, PxConvexMesh and PxTriangleMesh need recook, they should always be new if modified + if(inObj.getGeometryType() == PxGeometryType::eHEIGHTFIELD) + { + PxHeightFieldGeometry hfGeom; + inObj.getHeightFieldGeometry(hfGeom); + if(inStream.isInstanceValid(hfGeom.heightField)) + sendAllProperties(inStream, *hfGeom.heightField); + } + + setGeometry(*this, inStream, inObj, pvd); + + // Need update actor cause PVD takes actor-shape as a pair. + { + PxRigidActor* actor = inObj.getActor(); + if(actor != NULL) + { + + if(const PxRigidStatic* rgS = actor->is<PxRigidStatic>()) + sendAllProperties(inStream, *rgS); + else if(const PxRigidDynamic* rgD = actor->is<PxRigidDynamic>()) + sendAllProperties(inStream, *rgD); + } + } +} + +void PvdMetaDataBinding::updateMaterials(PvdDataStream& inStream, const PxShape& inObj, PsPvd* pvd) +{ + // Clear the shape's materials array. + inStream.setPropertyValue(&inObj, "Materials", DataRef<const PxU8>(), getPvdNamespacedNameForType<ObjectRef>()); + setMaterials(*this, inStream, inObj, pvd, mBindingData); +} + +void PvdMetaDataBinding::destroyInstance(PvdDataStream& inStream, const PxShape& inObj, const PxRigidActor& owner) +{ + if(inStream.isInstanceValid(&inObj)) + { + inStream.removeObjectRef(&owner, "Shapes", &inObj); + + bool bDestroy = true; + const OwnerActorsMap::Entry* entry0 = mBindingData->mOwnerActorsMap.find(&inObj); + if(entry0 != NULL) + { + entry0->second->erase(&owner); + if(entry0->second->size() > 0) + bDestroy = false; + else + { + mBindingData->mOwnerActorsMap[&inObj]->~OwnerActorsValueType(); + PX_FREE(mBindingData->mOwnerActorsMap[&inObj]); + mBindingData->mOwnerActorsMap.erase(&inObj); + } + } + + if(bDestroy) + { + if(!inObj.isExclusive()) + inStream.removeObjectRef(&PxGetPhysics(), "SharedShapes", &inObj); + + const void* geomInst = (reinterpret_cast<const PxU8*>(&inObj)) + 4; + inStream.destroyInstance(geomInst); + inStream.destroyInstance(&inObj); + + const OwnerActorsMap::Entry* entry = mBindingData->mOwnerActorsMap.find(&inObj); + if(entry != NULL) + { + entry->second->~OwnerActorsValueType(); + PX_FREE(entry->second); + mBindingData->mOwnerActorsMap.erase(&inObj); + } + } + } +} + +template <typename TDataType> +void addSceneGroupProperty(PvdDataStream& inStream, const char* groupName, const TDataType& inObj, const PxScene& inScene) +{ + inStream.createInstance(&inObj); + inStream.pushBackObjectRef(&inScene, groupName, &inObj); + inStream.setPropertyValue(&inObj, "Scene", reinterpret_cast<const void*>(&inScene)); +} + +template <typename TDataType> +void removeSceneGroupProperty(PvdDataStream& inStream, const char* groupName, const TDataType& inObj, const PxScene& inScene) +{ + inStream.removeObjectRef(&inScene, groupName, &inObj); + inStream.destroyInstance(&inObj); +} + +void sendShapes(PvdMetaDataBinding& binding, PvdDataStream& inStream, const PxRigidActor& inObj, PsPvd* pvd) +{ + InlineArray<PxShape*, 5> shapeData; + PxU32 nbShapes = inObj.getNbShapes(); + shapeData.resize(nbShapes); + inObj.getShapes(shapeData.begin(), nbShapes); + for(PxU32 idx = 0; idx < nbShapes; ++idx) + binding.createInstance(inStream, *shapeData[idx], inObj, pvd); +} + +void releaseShapes(PvdMetaDataBinding& binding, PvdDataStream& inStream, const PxRigidActor& inObj) +{ + InlineArray<PxShape*, 5> shapeData; + PxU32 nbShapes = inObj.getNbShapes(); + shapeData.resize(nbShapes); + inObj.getShapes(shapeData.begin(), nbShapes); + for(PxU32 idx = 0; idx < nbShapes; ++idx) + binding.destroyInstance(inStream, *shapeData[idx], inObj); +} + +void PvdMetaDataBinding::createInstance(PvdDataStream& inStream, const PxRigidStatic& inObj, const PxScene& ownerScene, PsPvd* pvd) +{ + addSceneGroupProperty(inStream, "RigidStatics", inObj, ownerScene); + sendAllProperties(inStream, inObj); + sendShapes(*this, inStream, inObj, pvd); +} +void PvdMetaDataBinding::sendAllProperties(PvdDataStream& inStream, const PxRigidStatic& inObj) +{ + PxRigidStaticGeneratedValues values(&inObj); + inStream.setPropertyMessage(&inObj, values); +} +void PvdMetaDataBinding::destroyInstance(PvdDataStream& inStream, const PxRigidStatic& inObj, const PxScene& ownerScene) +{ + releaseShapes(*this, inStream, inObj); + removeSceneGroupProperty(inStream, "RigidStatics", inObj, ownerScene); +} +void PvdMetaDataBinding::createInstance(PvdDataStream& inStream, const PxRigidDynamic& inObj, const PxScene& ownerScene, PsPvd* pvd) +{ + addSceneGroupProperty(inStream, "RigidDynamics", inObj, ownerScene); + sendAllProperties(inStream, inObj); + sendShapes(*this, inStream, inObj, pvd); +} +void PvdMetaDataBinding::sendAllProperties(PvdDataStream& inStream, const PxRigidDynamic& inObj) +{ + PxRigidDynamicGeneratedValues values(&inObj); + inStream.setPropertyMessage(&inObj, values); +} +void PvdMetaDataBinding::destroyInstance(PvdDataStream& inStream, const PxRigidDynamic& inObj, const PxScene& ownerScene) +{ + releaseShapes(*this, inStream, inObj); + removeSceneGroupProperty(inStream, "RigidDynamics", inObj, ownerScene); +} + +void addChild(PvdDataStream& inStream, const void* inParent, const PxArticulationLink& inChild) +{ + inStream.pushBackObjectRef(inParent, "Links", &inChild); + inStream.setPropertyValue(&inChild, "Parent", inParent); +} + +void PvdMetaDataBinding::createInstance(PvdDataStream& inStream, const PxArticulation& inObj, const PxScene& ownerScene, PsPvd* pvd) +{ + addSceneGroupProperty(inStream, "Articulations", inObj, ownerScene); + sendAllProperties(inStream, inObj); + PxU32 numLinks = inObj.getNbLinks(); + mBindingData->mArticulationLinks.resize(numLinks); + inObj.getLinks(mBindingData->mArticulationLinks.begin(), numLinks); + // From Dilip Sequiera: + /* + No, there can only be one root, and in all the code I wrote (which is not 100% of the HL code for + articulations), the index of a child is always > the index of the parent. + */ + + // Create all the links + for(PxU32 idx = 0; idx < numLinks; ++idx) + { + if(!inStream.isInstanceValid(mBindingData->mArticulationLinks[idx])) + createInstance(inStream, *mBindingData->mArticulationLinks[idx], pvd); + } + + // Setup the link graph + for(PxU32 idx = 0; idx < numLinks; ++idx) + { + PxArticulationLink* link = mBindingData->mArticulationLinks[idx]; + if(idx == 0) + addChild(inStream, &inObj, *link); + + PxU32 numChildren = link->getNbChildren(); + PxArticulationLink** children = mBindingData->allocateTemp<PxArticulationLink*>(numChildren); + link->getChildren(children, numChildren); + for(PxU32 i = 0; i < numChildren; ++i) + addChild(inStream, link, *children[i]); + } +} + +void PvdMetaDataBinding::sendAllProperties(PvdDataStream& inStream, const PxArticulation& inObj) +{ + PxArticulationGeneratedValues values(&inObj); + inStream.setPropertyMessage(&inObj, values); +} + +void PvdMetaDataBinding::destroyInstance(PvdDataStream& inStream, const PxArticulation& inObj, const PxScene& ownerScene) +{ + removeSceneGroupProperty(inStream, "Articulations", inObj, ownerScene); +} + +void PvdMetaDataBinding::createInstance(PvdDataStream& inStream, const PxArticulationLink& inObj, PsPvd* pvd) +{ + inStream.createInstance(&inObj); + PxArticulationJoint* joint(inObj.getInboundJoint()); + if(joint) + { + inStream.createInstance(joint); + inStream.setPropertyValue(&inObj, "InboundJoint", reinterpret_cast<const void*>(joint)); + inStream.setPropertyValue(joint, "Link", reinterpret_cast<const void*>(&inObj)); + sendAllProperties(inStream, *joint); + } + sendAllProperties(inStream, inObj); + sendShapes(*this, inStream, inObj, pvd); +} + +void PvdMetaDataBinding::sendAllProperties(PvdDataStream& inStream, const PxArticulationLink& inObj) +{ + PxArticulationLinkGeneratedValues values(&inObj); + inStream.setPropertyMessage(&inObj, values); +} + +void PvdMetaDataBinding::destroyInstance(PvdDataStream& inStream, const PxArticulationLink& inObj) +{ + PxArticulationJoint* joint(inObj.getInboundJoint()); + if(joint) + inStream.destroyInstance(joint); + releaseShapes(*this, inStream, inObj); + inStream.destroyInstance(&inObj); +} +// These are created as part of the articulation link's creation process, so outside entities don't need to +// create them. +void PvdMetaDataBinding::sendAllProperties(PvdDataStream& inStream, const PxArticulationJoint& inObj) +{ + PxArticulationJointGeneratedValues values(&inObj); + inStream.setPropertyMessage(&inObj, values); +} + +void PvdMetaDataBinding::originShift(PvdDataStream& inStream, const PxScene* inScene, PxVec3 shift) +{ + inStream.originShift(inScene, shift); +} + +template <typename TReadDataType> +struct ParticleFluidUpdater +{ + TReadDataType& mData; + Array<PxU8>& mTempU8Array; + PvdDataStream& mStream; + const void* mInstanceId; + PxU32 mRdFlags; + ParticleFluidUpdater(TReadDataType& d, PvdDataStream& s, const void* id, PxU32 flags, Array<PxU8>& tempArray) + : mData(d), mTempU8Array(tempArray), mStream(s), mInstanceId(id), mRdFlags(flags) + { + } + + template <PxU32 TKey, typename TObjectType, typename TPropertyType, PxU32 TEnableFlag> + void handleBuffer(const PxBufferPropertyInfo<TKey, TObjectType, PxStrideIterator<const TPropertyType>, TEnableFlag>& inProp, NamespacedName datatype) + { + PxU32 nbValidParticles = mData.nbValidParticles; + PxU32 validParticleRange = mData.validParticleRange; + PxStrideIterator<const TPropertyType> iterator(inProp.get(&mData)); + const PxU32* validParticleBitmap = mData.validParticleBitmap; + + if(nbValidParticles == 0 || iterator.ptr() == NULL || inProp.isEnabled(mRdFlags) == false) + return; + + // setup the pvd array + DataRef<const PxU8> propData; + mTempU8Array.resize(nbValidParticles * sizeof(TPropertyType)); + TPropertyType* tmpArray = reinterpret_cast<TPropertyType*>(mTempU8Array.begin()); + propData = DataRef<const PxU8>(mTempU8Array.begin(), mTempU8Array.size()); + if(nbValidParticles == validParticleRange) + { + for(PxU32 idx = 0; idx < nbValidParticles; ++idx) + tmpArray[idx] = iterator[idx]; + } + else + { + PxU32 tIdx = 0; + // iterate over bitmap and send all valid particles + for(PxU32 w = 0; w <= (validParticleRange - 1) >> 5; w++) + { + for(PxU32 b = validParticleBitmap[w]; b; b &= b - 1) + { + tmpArray[tIdx++] = iterator[w << 5 | Ps::lowestSetBit(b)]; + } + } + PX_ASSERT(tIdx == nbValidParticles); + } + mStream.setPropertyValue(mInstanceId, inProp.mName, propData, datatype); + } + template <PxU32 TKey, typename TObjectType, typename TPropertyType, PxU32 TEnableFlag> + void handleBuffer(const PxBufferPropertyInfo<TKey, TObjectType, PxStrideIterator<const TPropertyType>, TEnableFlag>& inProp) + { + handleBuffer(inProp, getPvdNamespacedNameForType<TPropertyType>()); + } + + template <PxU32 TKey, typename TObjectType, typename TEnumType, typename TStorageType, PxU32 TEnableFlag> + void handleFlagsBuffer(const PxBufferPropertyInfo<TKey, TObjectType, PxStrideIterator<const PxFlags<TEnumType, TStorageType> >, TEnableFlag>& inProp, const PxU32ToName*) + { + handleBuffer(inProp, getPvdNamespacedNameForType<TStorageType>()); + } + + private: + ParticleFluidUpdater& operator=(const ParticleFluidUpdater&); +}; + +#if PX_USE_PARTICLE_SYSTEM_API +void PvdMetaDataBinding::createInstance(PvdDataStream& inStream, const PxParticleSystem& inObj, const PxScene& ownerScene) +{ + addSceneGroupProperty(inStream, "ParticleSystems", inObj, ownerScene); + sendAllProperties(inStream, inObj); + PxParticleReadData* readData(const_cast<PxParticleSystem&>(inObj).lockParticleReadData()); + if(readData) + { + PxU32 readFlags = inObj.getParticleReadDataFlags(); + sendArrays(inStream, inObj, *readData, readFlags); + readData->unlock(); + } +} +void PvdMetaDataBinding::sendAllProperties(PvdDataStream& inStream, const PxParticleSystem& inObj) +{ + PxParticleSystemGeneratedValues values(&inObj); + inStream.setPropertyMessage(&inObj, values); +} + +void PvdMetaDataBinding::sendArrays(PvdDataStream& inStream, const PxParticleSystem& inObj, PxParticleReadData& inData, PxU32 inFlags) +{ + inStream.setPropertyValue(&inObj, "NbParticles", inData.nbValidParticles); + inStream.setPropertyValue(&inObj, "ValidParticleRange", inData.validParticleRange); + if(inData.validParticleRange > 0) + inStream.setPropertyValue(&inObj, "ValidParticleBitmap", inData.validParticleBitmap, (inData.validParticleRange >> 5) + 1); + + ParticleFluidUpdater<PxParticleReadData> theUpdater(inData, inStream, static_cast<const PxActor*>(&inObj), inFlags, mBindingData->mTempU8Array); + visitParticleSystemBufferProperties(makePvdPropertyFilter(theUpdater)); +} + +void PvdMetaDataBinding::destroyInstance(PvdDataStream& inStream, const PxParticleSystem& inObj, const PxScene& ownerScene) +{ + removeSceneGroupProperty(inStream, "ParticleSystems", inObj, ownerScene); +} + +void PvdMetaDataBinding::createInstance(PvdDataStream& inStream, const PxParticleFluid& inObj, const PxScene& ownerScene) +{ + addSceneGroupProperty(inStream, "ParticleFluids", inObj, ownerScene); + sendAllProperties(inStream, inObj); + PxParticleFluidReadData* readData(const_cast<PxParticleFluid&>(inObj).lockParticleFluidReadData()); + if(readData) + { + PxU32 readFlags = inObj.getParticleReadDataFlags(); + sendArrays(inStream, inObj, *readData, readFlags); + readData->unlock(); + } +} +void PvdMetaDataBinding::sendAllProperties(PvdDataStream& inStream, const PxParticleFluid& inObj) +{ + PxParticleFluidGeneratedValues values(&inObj); + inStream.setPropertyMessage(&inObj, values); +} + +void PvdMetaDataBinding::sendArrays(PvdDataStream& inStream, const PxParticleFluid& inObj, PxParticleFluidReadData& inData, PxU32 inFlags) +{ + inStream.setPropertyValue(&inObj, "NbParticles", inData.nbValidParticles); + inStream.setPropertyValue(&inObj, "ValidParticleRange", inData.validParticleRange); + if(inData.validParticleRange > 0) + inStream.setPropertyValue(&inObj, "ValidParticleBitmap", inData.validParticleBitmap, (inData.validParticleRange >> 5) + 1); + + ParticleFluidUpdater<PxParticleFluidReadData> theUpdater(inData, inStream, static_cast<const PxActor*>(&inObj), inFlags, mBindingData->mTempU8Array); + visitParticleSystemBufferProperties(makePvdPropertyFilter(theUpdater)); + visitParticleFluidBufferProperties(makePvdPropertyFilter(theUpdater)); +} + +void PvdMetaDataBinding::destroyInstance(PvdDataStream& inStream, const PxParticleFluid& inObj, const PxScene& ownerScene) +{ + removeSceneGroupProperty(inStream, "ParticleFluids", inObj, ownerScene); +} +#endif // PX_USE_PARTICLE_SYSTEM_API + +template <typename TBlockType, typename TActorType, typename TOperator> +void updateActor(PvdDataStream& inStream, TActorType** actorGroup, PxU32 numActors, TOperator sleepingOp, PvdMetaDataBindingData& bindingData) +{ + TBlockType theBlock; + if(numActors == 0) + return; + for(PxU32 idx = 0; idx < numActors; ++idx) + { + TActorType* theActor(actorGroup[idx]); + bool sleeping = sleepingOp(theActor, theBlock); + bool wasSleeping = bindingData.mSleepingActors.contains(theActor); + + if(sleeping == false || sleeping != wasSleeping) + { + theBlock.GlobalPose = theActor->getGlobalPose(); + theBlock.AngularVelocity = theActor->getAngularVelocity(); + theBlock.LinearVelocity = theActor->getLinearVelocity(); + inStream.sendPropertyMessageFromGroup(theActor, theBlock); + if(sleeping != wasSleeping) + { + if(sleeping) + bindingData.mSleepingActors.insert(theActor); + else + bindingData.mSleepingActors.erase(theActor); + } + } + } +} + +struct RigidDynamicUpdateOp +{ + bool operator()(PxRigidDynamic* actor, PxRigidDynamicUpdateBlock& block) + { + bool sleeping = actor->isSleeping(); + block.IsSleeping = sleeping; + return sleeping; + } +}; + +struct ArticulationLinkUpdateOp +{ + bool sleeping; + ArticulationLinkUpdateOp(bool s) : sleeping(s) + { + } + bool operator()(PxArticulationLink*, PxArticulationLinkUpdateBlock&) + { + return sleeping; + } +}; + +void PvdMetaDataBinding::updateDynamicActorsAndArticulations(PvdDataStream& inStream, const PxScene* inScene, PvdVisualizer* linkJointViz) +{ + PX_COMPILE_TIME_ASSERT(sizeof(PxRigidDynamicUpdateBlock) == 14 * 4); + { + PxU32 actorCount = inScene->getNbActors(PxActorTypeFlag::eRIGID_DYNAMIC); + if(actorCount) + { + inStream.beginPropertyMessageGroup<PxRigidDynamicUpdateBlock>(); + mBindingData->mActors.resize(actorCount); + PxActor** theActors = mBindingData->mActors.begin(); + inScene->getActors(PxActorTypeFlag::eRIGID_DYNAMIC, theActors, actorCount); + updateActor<PxRigidDynamicUpdateBlock>(inStream, reinterpret_cast<PxRigidDynamic**>(theActors), actorCount, RigidDynamicUpdateOp(), *mBindingData); + inStream.endPropertyMessageGroup(); + } + } + { + PxU32 articulationCount = inScene->getNbArticulations(); + if(articulationCount) + { + mBindingData->mArticulations.resize(articulationCount); + PxArticulation** firstArticulation = mBindingData->mArticulations.begin(); + PxArticulation** lastArticulation = firstArticulation + articulationCount; + inScene->getArticulations(firstArticulation, articulationCount); + inStream.beginPropertyMessageGroup<PxArticulationLinkUpdateBlock>(); + for(; firstArticulation < lastArticulation; ++firstArticulation) + { + PxU32 linkCount = (*firstArticulation)->getNbLinks(); + bool sleeping = (*firstArticulation)->isSleeping(); + if(linkCount) + { + mBindingData->mArticulationLinks.resize(linkCount); + PxArticulationLink** theLink = mBindingData->mArticulationLinks.begin(); + (*firstArticulation)->getLinks(theLink, linkCount); + updateActor<PxArticulationLinkUpdateBlock>(inStream, theLink, linkCount, ArticulationLinkUpdateOp(sleeping), *mBindingData); + if(linkJointViz) + { + for(PxU32 idx = 0; idx < linkCount; ++idx) + linkJointViz->visualize(*theLink[idx]); + } + } + } + inStream.endPropertyMessageGroup(); + firstArticulation = mBindingData->mArticulations.begin(); + for(; firstArticulation < lastArticulation; ++firstArticulation) + inStream.setPropertyValue(*firstArticulation, "IsSleeping", (*firstArticulation)->isSleeping()); + } + } +} + +template <typename TObjType> +struct CollectionOperator +{ + Array<PxU8>& mTempArray; + const TObjType& mObject; + PvdDataStream& mStream; + + CollectionOperator(Array<PxU8>& ary, const TObjType& obj, PvdDataStream& stream) + : mTempArray(ary), mObject(obj), mStream(stream) + { + } + void pushName(const char*) + { + } + void popName() + { + } + template <typename TAccessor> + void simpleProperty(PxU32 /*key*/, const TAccessor&) + { + } + template <typename TAccessor> + void flagsProperty(PxU32 /*key*/, const TAccessor&, const PxU32ToName*) + { + } + + template <typename TColType, typename TDataType, typename TCollectionProp> + void handleCollection(const TCollectionProp& prop, NamespacedName dtype, PxU32 countMultiplier = 1) + { + PxU32 count = prop.size(&mObject); + mTempArray.resize(count * sizeof(TDataType)); + TColType* start = reinterpret_cast<TColType*>(mTempArray.begin()); + prop.get(&mObject, start, count * countMultiplier); + mStream.setPropertyValue(&mObject, prop.mName, DataRef<const PxU8>(mTempArray.begin(), mTempArray.size()), dtype); + } + template <PxU32 TKey, typename TObject, typename TColType> + void handleCollection(const PxReadOnlyCollectionPropertyInfo<TKey, TObject, TColType>& prop) + { + handleCollection<TColType, TColType>(prop, getPvdNamespacedNameForType<TColType>()); + } + // Enumerations or bitflags. + template <PxU32 TKey, typename TObject, typename TColType> + void handleCollection(const PxReadOnlyCollectionPropertyInfo<TKey, TObject, TColType>& prop, const PxU32ToName*) + { + PX_COMPILE_TIME_ASSERT(sizeof(TColType) == sizeof(PxU32)); + handleCollection<TColType, PxU32>(prop, getPvdNamespacedNameForType<PxU32>()); + } + + private: + CollectionOperator& operator=(const CollectionOperator&); +}; + +#if PX_USE_CLOTH_API +struct PxClothFabricCollectionOperator : CollectionOperator<PxClothFabric> +{ + PxClothFabricCollectionOperator(Array<PxU8>& ary, const PxClothFabric& obj, PvdDataStream& stream) + : CollectionOperator<PxClothFabric>(ary, obj, stream) + { + } + + template <PxU32 TKey, typename TObject, typename TColType> + void handleCollection(const PxReadOnlyCollectionPropertyInfo<TKey, TObject, TColType>& prop) + { + // CollectionOperator<PxClothFabric>::handleCollection<TColType,TColType>( prop, + // getPvdNamespacedNameForType<TColType>(), sizeof( TColType ) ); + + // have to duplicate here because the cloth api expects buffer sizes + // in the number of elements, not the number of bytes + PxU32 count = prop.size(&mObject); + mTempArray.resize(count * sizeof(TColType)); + TColType* start = reinterpret_cast<TColType*>(mTempArray.begin()); + prop.get(&mObject, start, count); + mStream.setPropertyValue(&mObject, prop.mName, DataRef<const PxU8>(mTempArray.begin(), mTempArray.size()), getPvdNamespacedNameForType<TColType>()); + } + + // Enumerations or bitflags. + template <PxU32 TKey, typename TObject, typename TColType> + void handleCollection(const PxReadOnlyCollectionPropertyInfo<TKey, TObject, TColType>& prop, const PxU32ToName*) + { + PX_COMPILE_TIME_ASSERT(sizeof(TColType) == sizeof(PxU32)); + CollectionOperator<PxClothFabric>::handleCollection<TColType, PxU32>(prop, getPvdNamespacedNameForType<PxU32>()); + } + + private: + PxClothFabricCollectionOperator& operator=(const PxClothFabricCollectionOperator&); +}; + +void PvdMetaDataBinding::createInstance(PvdDataStream& inStream, const PxClothFabric& fabric, const PxPhysics& ownerPhysics) +{ + inStream.createInstance(&fabric); + addPhysicsGroupProperty(inStream, "ClothFabrics", fabric, ownerPhysics); + sendAllProperties(inStream, fabric); +} + +void PvdMetaDataBinding::sendAllProperties(PvdDataStream& inStream, const PxClothFabric& fabric) +{ + PxClothFabricCollectionOperator op(mBindingData->mTempU8Array, fabric, inStream); + visitInstancePvdProperties<PxClothFabric>(op); + + PxClothFabricGeneratedValues values(&fabric); + inStream.setPropertyMessage(&fabric, values); + + PxU32 count = fabric.getNbPhases(); + PxClothFabricPhase* phases = mBindingData->allocateTemp<PxClothFabricPhase>(count); + if(count) + fabric.getPhases(phases, count); + inStream.setPropertyValue(&fabric, "Phases", DataRef<const PxU8>(reinterpret_cast<PxU8*>(phases), sizeof(PxClothFabricPhase) * count), getPvdNamespacedNameForType<PxClothFabricPhase>()); +} + +void PvdMetaDataBinding::destroyInstance(PvdDataStream& inStream, const PxClothFabric& fabric, const PxPhysics& ownerPhysics) +{ + removePhysicsGroupProperty(inStream, "ClothFabrics", fabric, ownerPhysics); +} + +void PvdMetaDataBinding::createInstance(PvdDataStream& inStream, const PxCloth& cloth, const PxScene& ownerScene, PsPvd* pvd) +{ + addSceneGroupProperty(inStream, "Cloths", cloth, ownerScene); + PxClothFabric* fabric = cloth.getFabric(); + if(fabric != NULL) + { + if(pvd->registerObject(fabric)) + createInstance(inStream, *fabric, PxGetPhysics()); + inStream.setPropertyValue(&cloth, "Fabric", reinterpret_cast<const void*>(fabric)); + inStream.pushBackObjectRef(fabric, "Cloths", &cloth); + } + sendAllProperties(inStream, cloth); +} +void PvdMetaDataBinding::sendAllProperties(PvdDataStream& inStream, const PxCloth& cloth) +{ + sendSimpleProperties(inStream, cloth); + sendParticleAccelerations(inStream, cloth); + sendMotionConstraints(inStream, cloth); + sendCollisionSpheres(inStream, cloth); + sendCollisionSpheres(inStream, cloth, true); + sendCollisionTriangles(inStream, cloth); + sendVirtualParticles(inStream, cloth); + sendSeparationConstraints(inStream, cloth); + sendSelfCollisionIndices(inStream, cloth); + sendRestPositions(inStream, cloth); +} +void PvdMetaDataBinding::sendSimpleProperties(PvdDataStream& inStream, const PxCloth& cloth) +{ + PxClothGeneratedValues values(&cloth); + inStream.setPropertyMessage(&cloth, values); +} +void PvdMetaDataBinding::sendMotionConstraints(PvdDataStream& inStream, const PxCloth& cloth) +{ + PxU32 count = cloth.getNbMotionConstraints(); + PxClothParticleMotionConstraint* constraints = mBindingData->allocateTemp<PxClothParticleMotionConstraint>(count); + if(count) + cloth.getMotionConstraints(constraints); + inStream.setPropertyValue(&cloth, "MotionConstraints", mBindingData->tempToRef(), getPvdNamespacedNameForType<PvdPositionAndRadius>()); +} + +void PvdMetaDataBinding::sendRestPositions(PvdDataStream& inStream, const PxCloth& cloth) +{ + PxU32 count = cloth.getNbRestPositions(); + PxVec4* positions = mBindingData->allocateTemp<PxVec4>(count); + if(count) + cloth.getRestPositions(positions); + inStream.setPropertyValue(&cloth, "RestPositions", mBindingData->tempToRef(), getPvdNamespacedNameForType<PxVec4>()); +} + +void PvdMetaDataBinding::sendParticleAccelerations(PvdDataStream& inStream, const PxCloth& cloth) +{ + PxU32 count = cloth.getNbParticleAccelerations(); + PxVec4* accelerations = mBindingData->allocateTemp<PxVec4>(count); + if(count) + cloth.getParticleAccelerations(accelerations); + inStream.setPropertyValue(&cloth, "ParticleAccelerations", mBindingData->tempToRef(), getPvdNamespacedNameForType<PxVec4>()); +} + +void PvdMetaDataBinding::sendSelfCollisionIndices(PvdDataStream& inStream, const PxCloth& cloth) +{ + PxU32 count = cloth.getNbSelfCollisionIndices(); + PxU32* selfCollisionIndices = mBindingData->allocateTemp<PxU32>(count); + if(count) + cloth.getSelfCollisionIndices(selfCollisionIndices); + inStream.setPropertyValue(&cloth, "SelfCollisionIndices", mBindingData->tempToRef(), getPvdNamespacedNameForType<PxU32>()); +} + +void PvdMetaDataBinding::sendCollisionSpheres(PvdDataStream& inStream, const PxCloth& cloth, bool sendPairs) +{ + PxU32 numSpheres = cloth.getNbCollisionSpheres(); + PxU32 numIndices = 2 * cloth.getNbCollisionCapsules(); + PxU32 numPlanes = cloth.getNbCollisionPlanes(); + PxU32 numConvexes = cloth.getNbCollisionConvexes(); + PxU32 numTriangles = cloth.getNbCollisionTriangles(); + + PxU32 sphereBytes = numSpheres * sizeof(PxClothCollisionSphere); + PxU32 pairBytes = numIndices * sizeof(PxU32); + PxU32 planesBytes = numPlanes * sizeof(PxClothCollisionPlane); + PxU32 convexBytes = numConvexes * sizeof(PxU32); + PxU32 triangleBytes = numTriangles * sizeof(PxClothCollisionTriangle); + + mBindingData->mTempU8Array.resize(sphereBytes + pairBytes + planesBytes + convexBytes + triangleBytes); + PxU8* bufferStart = mBindingData->mTempU8Array.begin(); + PxClothCollisionSphere* spheresBuffer = reinterpret_cast<PxClothCollisionSphere*>(mBindingData->mTempU8Array.begin()); + PxU32* indexBuffer = reinterpret_cast<PxU32*>(spheresBuffer + numSpheres); + PxClothCollisionPlane* planeBuffer = reinterpret_cast<PxClothCollisionPlane*>(indexBuffer + numIndices); + PxU32* convexBuffer = reinterpret_cast<PxU32*>(planeBuffer + numPlanes); + PxClothCollisionTriangle* trianglesBuffer = reinterpret_cast<PxClothCollisionTriangle*>(convexBuffer + numConvexes); + + cloth.getCollisionData(spheresBuffer, indexBuffer, planeBuffer, convexBuffer, trianglesBuffer); + inStream.setPropertyValue(&cloth, "CollisionSpheres", DataRef<const PxU8>(bufferStart, sphereBytes), getPvdNamespacedNameForType<PvdPositionAndRadius>()); + if(sendPairs) + inStream.setPropertyValue(&cloth, "CollisionSpherePairs", DataRef<const PxU8>(bufferStart + sphereBytes, pairBytes), getPvdNamespacedNameForType<PxU32>()); +} + +// begin code to generate triangle mesh from cloth convex planes + +namespace +{ +PxReal det(PxVec4 v0, PxVec4 v1, PxVec4 v2, PxVec4 v3) +{ + const PxVec3& d0 = reinterpret_cast<const PxVec3&>(v0); + const PxVec3& d1 = reinterpret_cast<const PxVec3&>(v1); + const PxVec3& d2 = reinterpret_cast<const PxVec3&>(v2); + const PxVec3& d3 = reinterpret_cast<const PxVec3&>(v3); + + return v0.w * d1.cross(d2).dot(d3) - v1.w * d0.cross(d2).dot(d3) + v2.w * d0.cross(d1).dot(d3) - + v3.w * d0.cross(d1).dot(d2); +} + +PxVec3 intersect(PxVec4 p0, PxVec4 p1, PxVec4 p2) +{ + const PxVec3& d0 = reinterpret_cast<const PxVec3&>(p0); + const PxVec3& d1 = reinterpret_cast<const PxVec3&>(p1); + const PxVec3& d2 = reinterpret_cast<const PxVec3&>(p2); + + return (p0.w * d1.cross(d2) + p1.w * d2.cross(d0) + p2.w * d0.cross(d1)) / d0.dot(d2.cross(d1)); +} + +const PxU16 sInvalid = PxU16(-1); + +// restriction: only supports a single patch per vertex. +struct HalfedgeMesh +{ + struct Halfedge + { + Halfedge(PxU16 vertex = sInvalid, PxU16 face = sInvalid, PxU16 next = sInvalid, PxU16 prev = sInvalid) + : mVertex(vertex), mFace(face), mNext(next), mPrev(prev) + { + } + + PxU16 mVertex; // to + PxU16 mFace; // left + PxU16 mNext; // ccw + PxU16 mPrev; // cw + }; + + PxU16 findHalfedge(PxU16 v0, PxU16 v1) + { + PxU16 h = mVertices[v0], start = h; + while(h != sInvalid && mHalfedges[h].mVertex != v1) + { + h = mHalfedges[PxU32(h ^ 1)].mNext; + if(h == start) + return sInvalid; + } + return h; + } + + void connect(PxU16 h0, PxU16 h1) + { + mHalfedges[h0].mNext = h1; + mHalfedges[h1].mPrev = h0; + } + + void addTriangle(PxU16 v0, PxU16 v1, PxU16 v2) + { + // add new vertices + PxU16 n = PxU16(PxMax(v0, PxMax(v1, v2)) + 1); + if(mVertices.size() < n) + mVertices.resize(n, sInvalid); + + // collect halfedges, prev and next of triangle + PxU16 verts[] = { v0, v1, v2 }; + PxU16 handles[3], prev[3], next[3]; + for(PxU16 i = 0; i < 3; ++i) + { + PxU16 j = PxU16((i + 1) % 3); + PxU16 h = findHalfedge(verts[i], verts[j]); + if(h == sInvalid) + { + // add new edge + h = Ps::to16(mHalfedges.size()); + mHalfedges.pushBack(Halfedge(verts[j])); + mHalfedges.pushBack(Halfedge(verts[i])); + } + handles[i] = h; + prev[i] = mHalfedges[h].mPrev; + next[i] = mHalfedges[h].mNext; + } + + // patch connectivity + for(PxU16 i = 0; i < 3; ++i) + { + PxU16 j = PxU16((i + 1) % 3); + + mHalfedges[handles[i]].mFace = Ps::to16(mFaces.size()); + + // connect prev and next + connect(handles[i], handles[j]); + + if(next[j] == sInvalid) // new next edge, connect opposite + connect(PxU16(handles[j] ^ 1), next[i] != sInvalid ? next[i] : PxU16(handles[i] ^ 1)); + + if(prev[i] == sInvalid) // new prev edge, connect opposite + connect(prev[j] != sInvalid ? prev[j] : PxU16(handles[j] ^ 1), PxU16(handles[i] ^ 1)); + + // prev is boundary, update middle vertex + if(mHalfedges[PxU32(handles[i] ^ 1)].mFace == sInvalid) + mVertices[verts[j]] = PxU16(handles[i] ^ 1); + } + + mFaces.pushBack(handles[2]); + } + + PxU16 removeTriangle(PxU16 f) + { + PxU16 result = sInvalid; + + for(PxU16 i = 0, h = mFaces[f]; i < 3; ++i) + { + PxU16 v0 = mHalfedges[PxU32(h ^ 1)].mVertex; + PxU16 v1 = mHalfedges[PxU32(h)].mVertex; + + mHalfedges[h].mFace = sInvalid; + + if(mHalfedges[PxU32(h ^ 1)].mFace == sInvalid) // was boundary edge, remove + { + // update halfedge connectivity + connect(mHalfedges[h].mPrev, mHalfedges[PxU32(h ^ 1)].mNext); + connect(mHalfedges[PxU32(h ^ 1)].mPrev, mHalfedges[h].mNext); + + // update vertex boundary or delete + mVertices[v0] = mVertices[v0] == h ? sInvalid : mHalfedges[PxU32(h ^ 1)].mNext; + mVertices[v1] = mVertices[v1] == (h ^ 1) ? sInvalid : mHalfedges[h].mNext; + } + else + { + mVertices[v0] = h; // update vertex boundary + result = v1; + } + + h = mHalfedges[h].mNext; + } + + mFaces[f] = sInvalid; + return result; + } + + // true if vertex v is in front of face f + bool visible(PxU16 v, PxU16 f) + { + PxU16 h = mFaces[f]; + if(h == sInvalid) + return false; + + PxU16 v0 = mHalfedges[h].mVertex; + h = mHalfedges[h].mNext; + PxU16 v1 = mHalfedges[h].mVertex; + h = mHalfedges[h].mNext; + PxU16 v2 = mHalfedges[h].mVertex; + h = mHalfedges[h].mNext; + + return det(mPoints[v], mPoints[v0], mPoints[v1], mPoints[v2]) < 0.0f; + } + + shdfnd::Array<Halfedge> mHalfedges; + shdfnd::Array<PxU16> mVertices; // vertex -> (boundary) halfedge + shdfnd::Array<PxU16> mFaces; // face -> halfedge + shdfnd::Array<PxVec4> mPoints; +}; +} + +struct ConvexMeshBuilder +{ + ConvexMeshBuilder(const PxVec4* planes) : mPlanes(planes) + { + } + + void operator()(PxU32 mask, float scale = 1.0f); + + const PxVec4* mPlanes; + shdfnd::Array<PxVec3> mVertices; + shdfnd::Array<PxU16> mIndices; +}; + +void ConvexMeshBuilder::operator()(PxU32 planeMask, float scale) +{ + PxU16 numPlanes = Ps::to16(shdfnd::bitCount(planeMask)); + + if(numPlanes == 1) + { + PxTransform t = PxTransformFromPlaneEquation(reinterpret_cast<const PxPlane&>(mPlanes[lowestSetBit(planeMask)])); + + if(!t.isValid()) + return; + + const PxU16 indices[] = { 0, 1, 2, 0, 2, 3 }; + const PxVec3 vertices[] = { PxVec3(0.0f, scale, scale), PxVec3(0.0f, -scale, scale), + PxVec3(0.0f, -scale, -scale), PxVec3(0.0f, scale, -scale) }; + + PxU16 baseIndex = Ps::to16(mVertices.size()); + + for(PxU32 i = 0; i < 4; ++i) + mVertices.pushBack(t.transform(vertices[i])); + + for(PxU32 i = 0; i < 6; ++i) + mIndices.pushBack(PxU16(indices[i] + baseIndex)); + + return; + } + + if(numPlanes < 4) + return; // todo: handle degenerate cases + + HalfedgeMesh mesh; + + // gather points (planes, that is) + mesh.mPoints.reserve(numPlanes); + for(; planeMask; planeMask &= planeMask - 1) + mesh.mPoints.pushBack(mPlanes[shdfnd::lowestSetBit(planeMask)]); + + // initialize to tetrahedron + mesh.addTriangle(0, 1, 2); + mesh.addTriangle(0, 3, 1); + mesh.addTriangle(1, 3, 2); + mesh.addTriangle(2, 3, 0); + + // flip if inside-out + if(mesh.visible(3, 0)) + shdfnd::swap(mesh.mPoints[0], mesh.mPoints[1]); + + // iterate through remaining points + for(PxU16 i = 4; i < mesh.mPoints.size(); ++i) + { + // remove any visible triangle + PxU16 v0 = sInvalid; + for(PxU16 j = 0; j < mesh.mFaces.size(); ++j) + { + if(mesh.visible(i, j)) + v0 = PxMin(v0, mesh.removeTriangle(j)); + } + + if(v0 == sInvalid) + continue; + + // tesselate hole + PxU16 start = v0; + do + { + PxU16 h = mesh.mVertices[v0]; + PxU16 v1 = mesh.mHalfedges[h].mVertex; + mesh.addTriangle(v0, v1, i); + v0 = v1; + } while(v0 != start); + } + + // convert triangles to vertices (intersection of 3 planes) + shdfnd::Array<PxU32> face2Vertex(mesh.mFaces.size()); + for(PxU32 i = 0; i < mesh.mFaces.size(); ++i) + { + face2Vertex[i] = mVertices.size(); + + PxU16 h = mesh.mFaces[i]; + if(h == sInvalid) + continue; + + PxU16 v0 = mesh.mHalfedges[h].mVertex; + h = mesh.mHalfedges[h].mNext; + PxU16 v1 = mesh.mHalfedges[h].mVertex; + h = mesh.mHalfedges[h].mNext; + PxU16 v2 = mesh.mHalfedges[h].mVertex; + + mVertices.pushBack(intersect(mesh.mPoints[v0], mesh.mPoints[v1], mesh.mPoints[v2])); + } + + // convert vertices to polygons (face one-ring) + for(PxU32 i = 0; i < mesh.mVertices.size(); ++i) + { + PxU16 h = mesh.mVertices[i]; + if(h == sInvalid) + continue; + + PxU16 v0 = Ps::to16(face2Vertex[mesh.mHalfedges[h].mFace]); + h = PxU16(mesh.mHalfedges[h].mPrev ^ 1); + PxU16 v1 = Ps::to16(face2Vertex[mesh.mHalfedges[h].mFace]); + + while(true) + { + h = PxU16(mesh.mHalfedges[h].mPrev ^ 1); + PxU16 v2 = Ps::to16(face2Vertex[mesh.mHalfedges[h].mFace]); + + if(v0 == v2) + break; + + mIndices.pushBack(v0); + mIndices.pushBack(v2); + mIndices.pushBack(v1); + + v1 = v2; + } + } +} + +void PvdMetaDataBinding::sendCollisionTriangles(PvdDataStream& inStream, const PxCloth& cloth) +{ + PxU32 numSpheres = cloth.getNbCollisionSpheres(); + PxU32 numIndices = 2 * cloth.getNbCollisionCapsules(); + PxU32 numPlanes = cloth.getNbCollisionPlanes(); + PxU32 numConvexes = cloth.getNbCollisionConvexes(); + PxU32 numTriangles = cloth.getNbCollisionTriangles(); + + PxU32 sphereBytes = numSpheres * sizeof(PxClothCollisionSphere); + PxU32 pairBytes = numIndices * sizeof(PxU32); + PxU32 planesBytes = numPlanes * sizeof(PxClothCollisionPlane); + PxU32 convexBytes = numConvexes * sizeof(PxU32); + PxU32 triangleBytes = numTriangles * sizeof(PxClothCollisionTriangle); + + mBindingData->mTempU8Array.resize(sphereBytes + pairBytes + planesBytes + convexBytes + triangleBytes); + PxU8* bufferStart = mBindingData->mTempU8Array.begin(); + PxClothCollisionSphere* spheresBuffer = reinterpret_cast<PxClothCollisionSphere*>(mBindingData->mTempU8Array.begin()); + PxU32* indexBuffer = reinterpret_cast<PxU32*>(spheresBuffer + numSpheres); + PxClothCollisionPlane* planeBuffer = reinterpret_cast<PxClothCollisionPlane*>(indexBuffer + numIndices); + PxU32* convexBuffer = reinterpret_cast<PxU32*>(planeBuffer + numPlanes); + PxClothCollisionTriangle* trianglesBuffer = reinterpret_cast<PxClothCollisionTriangle*>(convexBuffer + numConvexes); + + cloth.getCollisionData(spheresBuffer, indexBuffer, planeBuffer, convexBuffer, trianglesBuffer); + + inStream.setPropertyValue(&cloth, "CollisionPlanes", DataRef<const PxU8>(bufferStart + sphereBytes + pairBytes, planesBytes), getPvdNamespacedNameForType<PvdPositionAndRadius>()); + inStream.setPropertyValue(&cloth, "CollisionConvexMasks", DataRef<const PxU8>(bufferStart + sphereBytes + pairBytes + planesBytes, convexBytes), getPvdNamespacedNameForType<PxU32>()); + inStream.setPropertyValue(&cloth, "CollisionTriangles", DataRef<const PxU8>(bufferStart + sphereBytes + pairBytes + planesBytes + convexBytes, triangleBytes), getPvdNamespacedNameForType<PxVec3>()); +} + +void PvdMetaDataBinding::sendVirtualParticles(PvdDataStream& inStream, const PxCloth& cloth) +{ + PxU32 numParticles = cloth.getNbVirtualParticles(); + PxU32 numWeights = cloth.getNbVirtualParticleWeights(); + PxU32 numIndexes = numParticles * 4; + PxU32 numIndexBytes = numIndexes * sizeof(PxU32); + PxU32 numWeightBytes = numWeights * sizeof(PxVec3); + + mBindingData->mTempU8Array.resize(PxMax(numIndexBytes, numWeightBytes)); + PxU8* dataStart = mBindingData->mTempU8Array.begin(); + + PxU32* indexStart = reinterpret_cast<PxU32*>(dataStart); + if(numIndexes) + cloth.getVirtualParticles(indexStart); + inStream.setPropertyValue(&cloth, "VirtualParticles", DataRef<const PxU8>(dataStart, numIndexBytes), getPvdNamespacedNameForType<PxU32>()); + + PxVec3* weightStart = reinterpret_cast<PxVec3*>(dataStart); + if(numWeights) + cloth.getVirtualParticleWeights(weightStart); + inStream.setPropertyValue(&cloth, "VirtualParticleWeights", DataRef<const PxU8>(dataStart, numWeightBytes), getPvdNamespacedNameForType<PxVec3>()); +} +void PvdMetaDataBinding::sendSeparationConstraints(PvdDataStream& inStream, const PxCloth& cloth) +{ + PxU32 count = cloth.getNbSeparationConstraints(); + PxU32 byteSize = count * sizeof(PxClothParticleSeparationConstraint); + mBindingData->mTempU8Array.resize(byteSize); + if(count) + cloth.getSeparationConstraints(reinterpret_cast<PxClothParticleSeparationConstraint*>(mBindingData->mTempU8Array.begin())); + inStream.setPropertyValue(&cloth, "SeparationConstraints", mBindingData->tempToRef(), getPvdNamespacedNameForType<PvdPositionAndRadius>()); +} +#endif // PX_USE_CLOTH_API + +// per frame update + +#if PX_USE_CLOTH_API + +void PvdMetaDataBinding::updateCloths(PvdDataStream& inStream, const PxScene& inScene) +{ + PxU32 actorCount = inScene.getNbActors(PxActorTypeFlag::eCLOTH); + if(actorCount == 0) + return; + mBindingData->mActors.resize(actorCount); + PxActor** theActors = mBindingData->mActors.begin(); + inScene.getActors(PxActorTypeFlag::eCLOTH, theActors, actorCount); + PX_COMPILE_TIME_ASSERT(sizeof(PxClothParticle) == sizeof(PxVec3) + sizeof(PxF32)); + for(PxU32 idx = 0; idx < actorCount; ++idx) + { + PxCloth* theCloth = static_cast<PxCloth*>(theActors[idx]); + bool isSleeping = theCloth->isSleeping(); + bool wasSleeping = mBindingData->mSleepingActors.contains(theCloth); + if(isSleeping == false || isSleeping != wasSleeping) + { + PxClothParticleData* theData = theCloth->lockParticleData(); + if(theData != NULL) + { + PxU32 numBytes = sizeof(PxClothParticle) * theCloth->getNbParticles(); + inStream.setPropertyValue(theCloth, "ParticleBuffer", DataRef<const PxU8>(reinterpret_cast<const PxU8*>(theData->particles), numBytes), getPvdNamespacedNameForType<PxClothParticle>()); + theData->unlock(); + } + } + if(isSleeping != wasSleeping) + { + inStream.setPropertyValue(theCloth, "IsSleeping", isSleeping); + if(isSleeping) + mBindingData->mSleepingActors.insert(theActors[idx]); + else + mBindingData->mSleepingActors.erase(theActors[idx]); + } + } +} + +void PvdMetaDataBinding::destroyInstance(PvdDataStream& inStream, const PxCloth& cloth, const PxScene& ownerScene) +{ + PxClothFabric* fabric = cloth.getFabric(); + if(fabric) + inStream.removeObjectRef(fabric, "Cloths", &cloth); + removeSceneGroupProperty(inStream, "Cloths", cloth, ownerScene); +} + +#endif // PX_USE_CLOTH_API + +#define ENABLE_AGGREGATE_PVD_SUPPORT 1 +#ifdef ENABLE_AGGREGATE_PVD_SUPPORT + +void PvdMetaDataBinding::createInstance(PvdDataStream& inStream, const PxAggregate& inObj, const PxScene& ownerScene) +{ + addSceneGroupProperty(inStream, "Aggregates", inObj, ownerScene); + sendAllProperties(inStream, inObj); +} + +void PvdMetaDataBinding::sendAllProperties(PvdDataStream& inStream, const PxAggregate& inObj) +{ + PxAggregateGeneratedValues values(&inObj); + inStream.setPropertyMessage(&inObj, values); +} + +void PvdMetaDataBinding::destroyInstance(PvdDataStream& inStream, const PxAggregate& inObj, const PxScene& ownerScene) +{ + removeSceneGroupProperty(inStream, "Aggregates", inObj, ownerScene); +} + +template <bool bPushBack> +class ChangeOjectRefCmd : public PvdDataStream::PvdCommand +{ + ChangeOjectRefCmd& operator=(const ChangeOjectRefCmd&) + { + PX_ASSERT(0); + return *this; + } // PX_NOCOPY doesn't work for local classes + public: + const void* instance; + String propName; + const void* propObj; + + ChangeOjectRefCmd(const void* inInst, String inName, const void* inObj) + : instance(inInst), propName(inName), propObj(inObj) + { + } + + // Assigned is needed for copying + ChangeOjectRefCmd(const ChangeOjectRefCmd& other) + : instance(other.instance), propName(other.propName), propObj(other.propObj) + { + } + + virtual bool canRun(PvdInstanceDataStream& inStream) + { + PX_ASSERT(inStream.isInstanceValid(instance)); + return inStream.isInstanceValid(propObj); + } + virtual void run(PvdInstanceDataStream& inStream) + { + if(!inStream.isInstanceValid(instance)) + return; + + if(bPushBack) + { + if(inStream.isInstanceValid(propObj)) + inStream.pushBackObjectRef(instance, propName, propObj); + } + else + { + // the called function will assert if propobj is already removed + inStream.removeObjectRef(instance, propName, propObj); + } + } +}; + +template <class Command> +void changeAggregateSubActors(PvdDataStream& inStream, const PxAggregate& inObj, const PxActor& inActor) +{ + const PxArticulationLink* link = inActor.is<PxArticulationLink>(); + String propName = NULL; + const void* object = NULL; + if(link == NULL) + { + propName = "Actors"; + object = &inActor; + } + else if(link->getInboundJoint() == NULL) + { + propName = "Articulations"; + object = &link->getArticulation(); + } + else + return; + + Command* cmd = PX_PLACEMENT_NEW(inStream.allocateMemForCmd(sizeof(Command)), Command)(&inObj, propName, object); + + if(cmd->canRun(inStream)) + cmd->run(inStream); + else + inStream.pushPvdCommand(*cmd); +} +void PvdMetaDataBinding::detachAggregateActor(PvdDataStream& inStream, const PxAggregate& inObj, const PxActor& inActor) +{ + typedef ChangeOjectRefCmd<false> RemoveOjectRefCmd; + changeAggregateSubActors<RemoveOjectRefCmd>(inStream, inObj, inActor); +} + +void PvdMetaDataBinding::attachAggregateActor(PvdDataStream& inStream, const PxAggregate& inObj, const PxActor& inActor) +{ + typedef ChangeOjectRefCmd<true> PushbackOjectRefCmd; + changeAggregateSubActors<PushbackOjectRefCmd>(inStream, inObj, inActor); +} +#else +void PvdMetaDataBinding::createInstance(PvdDataStream&, const PxAggregate&, const PxScene&, ObjectRegistrar&) +{ +} + +void PvdMetaDataBinding::sendAllProperties(PvdDataStream&, const PxAggregate&) +{ +} + +void PvdMetaDataBinding::destroyInstance(PvdDataStream&, const PxAggregate&, const PxScene&) +{ +} + +void PvdMetaDataBinding::detachAggregateActor(PvdDataStream&, const PxAggregate&, const PxActor&) +{ +} + +void PvdMetaDataBinding::attachAggregateActor(PvdDataStream&, const PxAggregate&, const PxActor&) +{ +} +#endif + +template <typename TDataType> +void sendSceneArray(PvdDataStream& inStream, const PxScene& inScene, const Ps::Array<TDataType>& inArray, const char* propName) +{ + if(0 == inArray.size()) + inStream.setPropertyValue(&inScene, propName, DataRef<const PxU8>(), getPvdNamespacedNameForType<TDataType>()); + else + { + ScopedPropertyValueSender<TDataType, 32> sender(inStream, &inScene, propName); + for(PxU32 i = 0; i < inArray.size(); ++i) + sender.append(inArray[i]); + } +} + +void sendSceneArray(PvdDataStream& inStream, const PxScene& inScene, const Ps::Array<PvdSqHit>& inArray, const char* propName) +{ + if(0 == inArray.size()) + inStream.setPropertyValue(&inScene, propName, DataRef<const PxU8>(), getPvdNamespacedNameForType<PvdSqHit>()); + else + { + ScopedPropertyValueSender<PvdSqHit, 32> sender(inStream, &inScene, propName); + for(PxU32 i = 0; i < inArray.size(); ++i) + { + if(!inStream.isInstanceValid(inArray[i].mShape) || !inStream.isInstanceValid(inArray[i].mActor)) + { + PvdSqHit hit = inArray[i]; + hit.mShape = NULL; + hit.mActor = NULL; + sender.append(hit); + } + else + sender.append(inArray[i]); + } + } +} +void PvdMetaDataBinding::sendSceneQueries(PvdDataStream& inStream, const PxScene& inScene, PsPvd* pvd) +{ + if(!inStream.isConnected()) + return; + + const physx::NpScene& scene = static_cast<const NpScene&>(inScene); + + for(PxU32 i = 0; i < 2; i++) + { + PvdSceneQueryCollector& collector = ((i == 0) ? scene.getSingleSqCollector() : scene.getBatchedSqCollector()); + Ps::Mutex::ScopedLock lock(collector.getLock()); + + String propName = collector.getArrayName(collector.mPvdSqHits); + sendSceneArray(inStream, inScene, collector.mPvdSqHits, propName); + + propName = collector.getArrayName(collector.mPoses); + sendSceneArray(inStream, inScene, collector.mPoses, propName); + + propName = collector.getArrayName(collector.mFilterData); + sendSceneArray(inStream, inScene, collector.mFilterData, propName); + + const Ps::Array<PxGeometryHolder>& geometriesToDestroy = collector.getPrevFrameGeometries(); + propName = collector.getArrayName(geometriesToDestroy); + for(PxU32 k = 0; k < geometriesToDestroy.size(); ++k) + { + const PxGeometryHolder& inObj = geometriesToDestroy[k]; + inStream.removeObjectRef(&inScene, propName, &inObj); + inStream.destroyInstance(&inObj); + } + const Ps::Array<PxGeometryHolder>& geometriesToCreate = collector.getCurrentFrameGeometries(); + for(PxU32 k = 0; k < geometriesToCreate.size(); ++k) + { + const PxGeometry& geometry = geometriesToCreate[k].any(); + switch(geometry.getType()) + { +#define SEND_PVD_GEOM_TYPE(enumType, TGeomType, TValueType) \ + case enumType: \ + { \ + const TGeomType& inObj = static_cast<const TGeomType&>(geometry); \ + inStream.createInstance(getPvdNamespacedNameForType<TGeomType>(), &inObj); \ + registrarPhysicsObject<TGeomType>(inStream, inObj, pvd); \ + TValueType values(&inObj); \ + inStream.setPropertyMessage(&inObj, values); \ + inStream.pushBackObjectRef(&inScene, propName, &inObj); \ + } \ + break; + SEND_PVD_GEOM_TYPE(PxGeometryType::eBOX, PxBoxGeometry, PxBoxGeometryGeneratedValues) + SEND_PVD_GEOM_TYPE(PxGeometryType::eSPHERE, PxSphereGeometry, PxSphereGeometryGeneratedValues) + SEND_PVD_GEOM_TYPE(PxGeometryType::eCAPSULE, PxCapsuleGeometry, PxCapsuleGeometryGeneratedValues) + SEND_PVD_GEOM_TYPE(PxGeometryType::eCONVEXMESH, PxConvexMeshGeometry, PxConvexMeshGeometryGeneratedValues) +#undef SEND_PVD_GEOM_TYPE + case PxGeometryType::ePLANE: + case PxGeometryType::eTRIANGLEMESH: + case PxGeometryType::eHEIGHTFIELD: + case PxGeometryType::eGEOMETRY_COUNT: + case PxGeometryType::eINVALID: + PX_ALWAYS_ASSERT_MESSAGE("unsupported scene query geometry type"); + break; + } + } + collector.prepareNextFrameGeometries(); + + propName = collector.getArrayName(collector.mAccumulatedRaycastQueries); + sendSceneArray(inStream, inScene, collector.mAccumulatedRaycastQueries, propName); + + propName = collector.getArrayName(collector.mAccumulatedOverlapQueries); + sendSceneArray(inStream, inScene, collector.mAccumulatedOverlapQueries, propName); + + propName = collector.getArrayName(collector.mAccumulatedSweepQueries); + sendSceneArray(inStream, inScene, collector.mAccumulatedSweepQueries, propName); + } +} +} +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/PvdMetaDataPvdBinding.h b/PhysX_3.4/Source/PhysX/src/PvdMetaDataPvdBinding.h new file mode 100644 index 00000000..f76cb2f9 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/PvdMetaDataPvdBinding.h @@ -0,0 +1,188 @@ +// 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_META_DATA_PVD_BINDING_H +#define PX_META_DATA_PVD_BINDING_H + +#if PX_SUPPORT_PVD + +#include "PxPhysXConfig.h" +#include "PsArray.h" + +namespace physx +{ + namespace pvdsdk + { + class PsPvd; + class PvdDataStream; + struct PvdMetaDataBindingData; + } +} + +namespace physx +{ + +namespace Sc +{ +struct Contact; +struct ClothBulkData; +} + +namespace Vd +{ + +using namespace physx::pvdsdk; + +class PvdVisualizer +{ + protected: + virtual ~PvdVisualizer() + { + } + + public: + virtual void visualize(PxArticulationLink& link) = 0; +}; + +class PvdMetaDataBinding +{ + PvdMetaDataBindingData* mBindingData; + + public: + PvdMetaDataBinding(); + ~PvdMetaDataBinding(); + void registerSDKProperties(PvdDataStream& inStream); + + void sendAllProperties(PvdDataStream& inStream, const PxPhysics& inPhysics); + + void sendAllProperties(PvdDataStream& inStream, const PxScene& inScene); + // per frame update + void sendBeginFrame(PvdDataStream& inStream, const PxScene* inScene, PxReal simulateElapsedTime); + void sendContacts(PvdDataStream& inStream, const PxScene& inScene, shdfnd::Array<Sc::Contact>& inContacts); + void sendContacts(PvdDataStream& inStream, const PxScene& inScene); + void sendSceneQueries(PvdDataStream& inStream, const PxScene& inScene, PsPvd* pvd); + void sendStats(PvdDataStream& inStream, const PxScene* inScene, void* triMeshCacheStats); + void sendEndFrame(PvdDataStream& inStream, const PxScene* inScene); + + void createInstance(PvdDataStream& inStream, const PxMaterial& inMaterial, const PxPhysics& ownerPhysics); + void sendAllProperties(PvdDataStream& inStream, const PxMaterial& inMaterial); + void destroyInstance(PvdDataStream& inStream, const PxMaterial& inMaterial, const PxPhysics& ownerPhysics); + + void createInstance(PvdDataStream& inStream, const PxHeightField& inData, const PxPhysics& ownerPhysics); + void sendAllProperties(PvdDataStream& inStream, const PxHeightField& inData); + void destroyInstance(PvdDataStream& inStream, const PxHeightField& inData, const PxPhysics& ownerPhysics); + + void createInstance(PvdDataStream& inStream, const PxConvexMesh& inData, const PxPhysics& ownerPhysics); + void destroyInstance(PvdDataStream& inStream, const PxConvexMesh& inData, const PxPhysics& ownerPhysics); + + void createInstance(PvdDataStream& inStream, const PxTriangleMesh& inData, const PxPhysics& ownerPhysics); + void destroyInstance(PvdDataStream& inStream, const PxTriangleMesh& inData, const PxPhysics& ownerPhysics); + + void createInstance(PvdDataStream& inStream, const PxRigidStatic& inObj, const PxScene& ownerScene, PsPvd* pvd); + void sendAllProperties(PvdDataStream& inStream, const PxRigidStatic& inObj); + void destroyInstance(PvdDataStream& inStream, const PxRigidStatic& inObj, const PxScene& ownerScene); + + void createInstance(PvdDataStream& inStream, const PxRigidDynamic& inObj, const PxScene& ownerScene, PsPvd* pvd); + void sendAllProperties(PvdDataStream& inStream, const PxRigidDynamic& inObj); + void destroyInstance(PvdDataStream& inStream, const PxRigidDynamic& inObj, const PxScene& ownerScene); + + void createInstance(PvdDataStream& inStream, const PxArticulation& inObj, const PxScene& ownerScene, PsPvd* pvd); + void sendAllProperties(PvdDataStream& inStream, const PxArticulation& inObj); + void destroyInstance(PvdDataStream& inStream, const PxArticulation& inObj, const PxScene& ownerScene); + + void createInstance(PvdDataStream& inStream, const PxArticulationLink& inObj, PsPvd* pvd); + void sendAllProperties(PvdDataStream& inStream, const PxArticulationLink& inObj); + void destroyInstance(PvdDataStream& inStream, const PxArticulationLink& inObj); + + void createInstance(PvdDataStream& inStream, const PxShape& inObj, const PxRigidActor& owner, PsPvd* pvd); + void sendAllProperties(PvdDataStream& inStream, const PxShape& inObj); + void releaseAndRecreateGeometry(PvdDataStream& inStream, const PxShape& inObj, PxPhysics& ownerPhysics, PsPvd* pvd); + void updateMaterials(PvdDataStream& inStream, const PxShape& inObj, PsPvd* pvd); + void destroyInstance(PvdDataStream& inStream, const PxShape& inObj, const PxRigidActor& owner); + + // These are created as part of the articulation link's creation process, so outside entities don't need to + // create them. + void sendAllProperties(PvdDataStream& inStream, const PxArticulationJoint& inObj); + + // per frame update + void updateDynamicActorsAndArticulations(PvdDataStream& inStream, const PxScene* inScene, PvdVisualizer* linkJointViz); + + // Origin Shift + void originShift(PvdDataStream& inStream, const PxScene* inScene, PxVec3 shift); + +#if PX_USE_PARTICLE_SYSTEM_API + void createInstance(PvdDataStream& inStream, const PxParticleSystem& inObj, const PxScene& ownerScene); + void sendAllProperties(PvdDataStream& inStream, const PxParticleSystem& inObj); + // per frame update + void sendArrays(PvdDataStream& inStream, const PxParticleSystem& inObj, PxParticleReadData& inData, PxU32 inFlags); + void destroyInstance(PvdDataStream& inStream, const PxParticleSystem& inObj, const PxScene& ownerScene); + + void createInstance(PvdDataStream& inStream, const PxParticleFluid& inObj, const PxScene& ownerScene); + void sendAllProperties(PvdDataStream& inStream, const PxParticleFluid& inObj); + // per frame update + void sendArrays(PvdDataStream& inStream, const PxParticleFluid& inObj, PxParticleFluidReadData& inData, + PxU32 inFlags); + void destroyInstance(PvdDataStream& inStream, const PxParticleFluid& inObj, const PxScene& ownerScene); +#endif + +#if PX_USE_CLOTH_API + void createInstance(PvdDataStream& inStream, const PxClothFabric& fabric, const PxPhysics& ownerPhysics); + void sendAllProperties(PvdDataStream& inStream, const PxClothFabric& fabric); + void destroyInstance(PvdDataStream& inStream, const PxClothFabric& fabric, const PxPhysics& ownerPhysics); + + void createInstance(PvdDataStream& inStream, const PxCloth& cloth, const PxScene& ownerScene, PsPvd* pvd); + void sendAllProperties(PvdDataStream& inStream, const PxCloth& cloth); + void sendSimpleProperties(PvdDataStream& inStream, const PxCloth& cloth); + void sendMotionConstraints(PvdDataStream& inStream, const PxCloth& cloth); + void sendCollisionSpheres(PvdDataStream& inStream, const PxCloth& cloth, bool sendPairs = true); + void sendCollisionTriangles(PvdDataStream& inStream, const PxCloth& cloth); + void sendVirtualParticles(PvdDataStream& inStream, const PxCloth& cloth); + void sendSeparationConstraints(PvdDataStream& inStream, const PxCloth& cloth); + void sendRestPositions(PvdDataStream& inStream, const PxCloth& cloth); + void sendSelfCollisionIndices(PvdDataStream& inStream, const PxCloth& cloth); + void sendParticleAccelerations(PvdDataStream& inStream, const PxCloth& cloth); + // per frame update + void updateCloths(PvdDataStream& inStream, const PxScene& inScene); + void destroyInstance(PvdDataStream& inStream, const PxCloth& cloth, const PxScene& ownerScene); +#endif + + void createInstance(PvdDataStream& inStream, const PxAggregate& inObj, const PxScene& ownerScene); + void sendAllProperties(PvdDataStream& inStream, const PxAggregate& inObj); + void destroyInstance(PvdDataStream& inStream, const PxAggregate& inObj, const PxScene& ownerScene); + void detachAggregateActor(PvdDataStream& inStream, const PxAggregate& inObj, const PxActor& inActor); + void attachAggregateActor(PvdDataStream& inStream, const PxAggregate& inObj, const PxActor& inActor); + + template <typename TDataType> + void registrarPhysicsObject(PvdDataStream&, const TDataType&, PsPvd*); +}; +} +} + +#endif +#endif diff --git a/PhysX_3.4/Source/PhysX/src/PvdPhysicsClient.cpp b/PhysX_3.4/Source/PhysX/src/PvdPhysicsClient.cpp new file mode 100644 index 00000000..cd73cf60 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/PvdPhysicsClient.cpp @@ -0,0 +1,243 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +// PX_DUMMY_SYMBOL + +#if PX_SUPPORT_PVD + +#include "pvd/PxPvdTransport.h" +#include "PxPhysics.h" +#include "PxPvdClient.h" +#include "PxPvdDataStream.h" +#include "PxPvdObjectModelBaseTypes.h" +#include "PvdPhysicsClient.h" +#include "PvdTypeNames.h" + +using namespace physx; +using namespace physx::Vd; + +PvdPhysicsClient::PvdPhysicsClient(PsPvd* pvd) +: mPvd(pvd), mPvdDataStream(NULL), mIsConnected(false) +{ +} + +PvdPhysicsClient::~PvdPhysicsClient() +{ + mPvd->removeClient(this); +} + +PvdDataStream* PvdPhysicsClient::getDataStream() +{ + return mPvdDataStream; +} + +PvdMetaDataBinding* PvdPhysicsClient::getMetaDataBinding() +{ + return &mMetaDataBinding; +} + +PvdUserRenderer* PvdPhysicsClient::getUserRender() +{ + PX_ASSERT(0); + return NULL; +} + +bool PvdPhysicsClient::isConnected() const +{ + return mIsConnected; +} + +void PvdPhysicsClient::onPvdConnected() +{ + if(mIsConnected || !mPvd) + return; + + mIsConnected = true; + mPvdDataStream = PvdDataStream::create(mPvd); + sendEntireSDK(); +} + +void PvdPhysicsClient::onPvdDisconnected() +{ + if(!mIsConnected) + return; + mIsConnected = false; + + mPvdDataStream->release(); + mPvdDataStream = NULL; +} + +void PvdPhysicsClient::flush() +{ +} + +void PvdPhysicsClient::sendEntireSDK() +{ + PxPhysics& physics = PxGetPhysics(); + + mMetaDataBinding.registerSDKProperties(*mPvdDataStream); + mPvdDataStream->createInstance(&physics); + + mPvdDataStream->setIsTopLevelUIElement(&physics, true); + mMetaDataBinding.sendAllProperties(*mPvdDataStream, physics); + +#define SEND_BUFFER_GROUP(type, name) \ + { \ + physx::shdfnd::Array<type*> buffers; \ + PxU32 numBuffers = physics.getNb##name(); \ + buffers.resize(numBuffers); \ + physics.get##name(buffers.begin(), numBuffers); \ + for(PxU32 i = 0; i < numBuffers; i++) \ + { \ + if(mPvd->registerObject(buffers[i])) \ + createPvdInstance(buffers[i]); \ + } \ + } + + SEND_BUFFER_GROUP(PxMaterial, Materials); + SEND_BUFFER_GROUP(PxTriangleMesh, TriangleMeshes); + SEND_BUFFER_GROUP(PxConvexMesh, ConvexMeshes); + SEND_BUFFER_GROUP(PxHeightField, HeightFields); + +#if PX_USE_CLOTH_API + SEND_BUFFER_GROUP(PxClothFabric, ClothFabrics); +#endif +} + +void PvdPhysicsClient::destroyPvdInstance(const PxPhysics* physics) +{ + if(mPvdDataStream) + mPvdDataStream->destroyInstance(physics); +} + +void PvdPhysicsClient::createPvdInstance(const PxTriangleMesh* triMesh) +{ + mMetaDataBinding.createInstance(*mPvdDataStream, *triMesh, PxGetPhysics()); +} + +void PvdPhysicsClient::destroyPvdInstance(const PxTriangleMesh* triMesh) +{ + mMetaDataBinding.destroyInstance(*mPvdDataStream, *triMesh, PxGetPhysics()); +} + +void PvdPhysicsClient::createPvdInstance(const PxConvexMesh* convexMesh) +{ + mMetaDataBinding.createInstance(*mPvdDataStream, *convexMesh, PxGetPhysics()); +} + +void PvdPhysicsClient::destroyPvdInstance(const PxConvexMesh* convexMesh) +{ + mMetaDataBinding.destroyInstance(*mPvdDataStream, *convexMesh, PxGetPhysics()); +} + +void PvdPhysicsClient::createPvdInstance(const PxHeightField* heightField) +{ + mMetaDataBinding.createInstance(*mPvdDataStream, *heightField, PxGetPhysics()); +} + +void PvdPhysicsClient::destroyPvdInstance(const PxHeightField* heightField) +{ + mMetaDataBinding.destroyInstance(*mPvdDataStream, *heightField, PxGetPhysics()); +} + +void PvdPhysicsClient::createPvdInstance(const PxMaterial* mat) +{ + mMetaDataBinding.createInstance(*mPvdDataStream, *mat, PxGetPhysics()); +} + +void PvdPhysicsClient::updatePvdProperties(const PxMaterial* mat) +{ + mMetaDataBinding.sendAllProperties(*mPvdDataStream, *mat); +} + +void PvdPhysicsClient::destroyPvdInstance(const PxMaterial* mat) +{ + mMetaDataBinding.destroyInstance(*mPvdDataStream, *mat, PxGetPhysics()); +} + +#if PX_USE_CLOTH_API +void PvdPhysicsClient::createPvdInstance(const PxClothFabric* fabric) +{ + mMetaDataBinding.createInstance(*mPvdDataStream, *fabric, PxGetPhysics()); + // Physics level buffer object update, must be flushed immediatedly. +} + +void PvdPhysicsClient::destroyPvdInstance(const PxClothFabric* fabric) +{ + mMetaDataBinding.destroyInstance(*mPvdDataStream, *fabric, PxGetPhysics()); + // Physics level buffer object update, must be flushed immediatedly. +} +#endif + +void PvdPhysicsClient::onGuMeshFactoryBufferRelease(const PxBase* object, PxType typeID) +{ + if(!mIsConnected || !mPvd) + return; + + if(mPvd->unRegisterObject(object)) + { + switch(typeID) + { + case PxConcreteType::eHEIGHTFIELD: + destroyPvdInstance(static_cast<const PxHeightField*>(object)); + break; + + case PxConcreteType::eCONVEX_MESH: + destroyPvdInstance(static_cast<const PxConvexMesh*>(object)); + break; + + case PxConcreteType::eTRIANGLE_MESH_BVH33: + case PxConcreteType::eTRIANGLE_MESH_BVH34: + destroyPvdInstance(static_cast<const PxTriangleMesh*>(object)); + break; + + default: + break; + } + } +} +#if PX_USE_CLOTH_API +void PvdPhysicsClient::onNpFactoryBufferRelease(PxClothFabric& data) +{ + if(!mIsConnected || !mPvd) + return; + if(mPvd->unRegisterObject(&data)) + destroyPvdInstance(&data); +} +#endif + +void PvdPhysicsClient::reportError(PxErrorCode::Enum code, const char* message, const char* file, int line) +{ + if(mIsConnected) + { + mPvdDataStream->sendErrorMessage(code, message, file, PxU32(line)); + } +} + +#endif // PX_SUPPORT_PVD diff --git a/PhysX_3.4/Source/PhysX/src/PvdPhysicsClient.h b/PhysX_3.4/Source/PhysX/src/PvdPhysicsClient.h new file mode 100644 index 00000000..36ac4b81 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/PvdPhysicsClient.h @@ -0,0 +1,103 @@ +// 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 PVD_PHYSICS_CLIENT_H +#define PVD_PHYSICS_CLIENT_H +#if PX_SUPPORT_PVD +#include "foundation/PxErrorCallback.h" +#include "PxPvdClient.h" +#include "PvdMetaDataPvdBinding.h" +#include "NpFactory.h" +#include "PsHashMap.h" +#include "PsMutex.h" +#include "PsPvd.h" + +namespace physx +{ +class PxProfileMemoryEventBuffer; + +namespace Vd +{ + +class PvdPhysicsClient : public PvdClient, public PxErrorCallback, public NpFactoryListener, public shdfnd::UserAllocated +{ + PX_NOCOPY(PvdPhysicsClient) + public: + PvdPhysicsClient(PsPvd* pvd); + virtual ~PvdPhysicsClient(); + + bool isConnected() const; + void onPvdConnected(); + void onPvdDisconnected(); + void flush(); + + PsPvd* getPsPvd(); + physx::pvdsdk::PvdDataStream* getDataStream(); + PvdMetaDataBinding* getMetaDataBinding(); + PvdUserRenderer* getUserRender(); + + void sendEntireSDK(); + void destroyPvdInstance(const PxPhysics* physics); + + // NpFactoryListener + virtual void onGuMeshFactoryBufferRelease(const PxBase* object, PxType typeID); +#if PX_USE_CLOTH_API + virtual void onNpFactoryBufferRelease(PxClothFabric& data); +#endif + /// NpFactoryListener + + // PxErrorCallback + void reportError(PxErrorCode::Enum code, const char* message, const char* file, int line); + + private: + void createPvdInstance(const PxTriangleMesh* triMesh); + void destroyPvdInstance(const PxTriangleMesh* triMesh); + void createPvdInstance(const PxConvexMesh* convexMesh); + void destroyPvdInstance(const PxConvexMesh* convexMesh); + void createPvdInstance(const PxHeightField* heightField); + void destroyPvdInstance(const PxHeightField* heightField); + void createPvdInstance(const PxMaterial* mat); + void destroyPvdInstance(const PxMaterial* mat); + void updatePvdProperties(const PxMaterial* mat); +#if PX_USE_CLOTH_API + void createPvdInstance(const PxClothFabric* fabric); + void destroyPvdInstance(const PxClothFabric* fabric); +#endif + + PsPvd* mPvd; + PvdDataStream* mPvdDataStream; + PvdMetaDataBinding mMetaDataBinding; + bool mIsConnected; +}; + +} // namespace Vd +} // namespace physx + +#endif // PX_SUPPORT_PVD +#endif // PVD_PHYSICS_CLIENT_H diff --git a/PhysX_3.4/Source/PhysX/src/PvdTypeNames.h b/PhysX_3.4/Source/PhysX/src/PvdTypeNames.h new file mode 100644 index 00000000..0b5abe17 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/PvdTypeNames.h @@ -0,0 +1,189 @@ +// 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 PVD_TYPE_NAMES_H +#define PVD_TYPE_NAMES_H +#if PX_SUPPORT_PVD +#include "PxPhysicsAPI.h" +#include "PxPvdObjectModelBaseTypes.h" +#include "PxMetaDataObjects.h" +#include "PxHeightFieldSample.h" + +namespace physx +{ +namespace Vd +{ +struct PvdSqHit; +struct PvdRaycast; +struct PvdOverlap; +struct PvdSweep; + +struct PvdHullPolygonData +{ + PxU16 mNumVertices; + PxU16 mIndexBase; + PvdHullPolygonData(PxU16 numVert, PxU16 idxBase) : mNumVertices(numVert), mIndexBase(idxBase) + { + } +}; + + +struct PxArticulationLinkUpdateBlock +{ + PxTransform GlobalPose; + PxVec3 LinearVelocity; + PxVec3 AngularVelocity; +}; +struct PxRigidDynamicUpdateBlock : public PxArticulationLinkUpdateBlock +{ + bool IsSleeping; +}; + +struct PvdContact +{ + PxVec3 point; + PxVec3 axis; + const void* shape0; + const void* shape1; + PxF32 separation; + PxF32 normalForce; + PxU32 internalFaceIndex0; + PxU32 internalFaceIndex1; + bool normalForceAvailable; +}; + +struct PvdPositionAndRadius +{ + PxVec3 position; + PxF32 radius; +}; + +} //Vd +} //physx + +namespace physx +{ +namespace pvdsdk +{ + +#define DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(type) DEFINE_PVD_TYPE_NAME_MAP(physx::type, "physx3", #type) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxPhysics) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxScene) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxTolerancesScale) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxTolerancesScaleGeneratedValues) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxSceneDescGeneratedValues) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxSceneDesc) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxSimulationStatistics) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxSimulationStatisticsGeneratedValues) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxMaterial) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxMaterialGeneratedValues) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxHeightField) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxHeightFieldDesc) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxHeightFieldDescGeneratedValues) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxTriangleMesh) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxConvexMesh) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxActor) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxRigidActor) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxRigidBody) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxRigidDynamic) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxRigidDynamicGeneratedValues) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxRigidStatic) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxRigidStaticGeneratedValues) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxShape) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxShapeGeneratedValues) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxGeometry) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxBoxGeometry) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxPlaneGeometry) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxCapsuleGeometry) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxSphereGeometry) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxHeightFieldGeometry) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxTriangleMeshGeometry) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxConvexMeshGeometry) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxBoxGeometryGeneratedValues) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxPlaneGeometryGeneratedValues) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxCapsuleGeometryGeneratedValues) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxSphereGeometryGeneratedValues) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxHeightFieldGeometryGeneratedValues) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxTriangleMeshGeometryGeneratedValues) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxConvexMeshGeometryGeneratedValues) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxHeightFieldSample) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxConstraint) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxConstraintGeneratedValues) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxArticulation) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxArticulationGeneratedValues) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxArticulationLink) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxArticulationLinkGeneratedValues) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxArticulationJoint) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxArticulationJointGeneratedValues) +#if PX_USE_PARTICLE_SYSTEM_API +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxParticleBase) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxParticleSystem) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxParticleSystemGeneratedValues) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxParticleFluid) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxParticleFluidGeneratedValues) +#endif + +#if PX_USE_CLOTH_API +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxClothFabric) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxClothFabricPhase) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxClothFabricPhaseGeneratedValues) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxClothFabricGeneratedValues) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxCloth) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxClothGeneratedValues) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxClothParticle) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxClothStretchConfig) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxClothTetherConfig) +#endif +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxAggregate) +DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP(PxAggregateGeneratedValues) + +#undef DEFINE_NATIVE_PVD_PHYSX3_TYPE_MAP + +#define DEFINE_NATIVE_PVD_TYPE_MAP(type) DEFINE_PVD_TYPE_NAME_MAP(physx::Vd::type, "physx3", #type) +DEFINE_NATIVE_PVD_TYPE_MAP(PvdHullPolygonData) +DEFINE_NATIVE_PVD_TYPE_MAP(PxRigidDynamicUpdateBlock) +DEFINE_NATIVE_PVD_TYPE_MAP(PxArticulationLinkUpdateBlock) +DEFINE_NATIVE_PVD_TYPE_MAP(PvdContact) +DEFINE_NATIVE_PVD_TYPE_MAP(PvdRaycast) +DEFINE_NATIVE_PVD_TYPE_MAP(PvdSweep) +DEFINE_NATIVE_PVD_TYPE_MAP(PvdOverlap) +DEFINE_NATIVE_PVD_TYPE_MAP(PvdSqHit) +DEFINE_NATIVE_PVD_TYPE_MAP(PvdPositionAndRadius) + +#undef DEFINE_NATIVE_PVD_TYPE_MAP + + +DEFINE_PVD_TYPE_ALIAS(physx::PxFilterData, U32Array4) + + +} +} + +#endif + +#endif 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 diff --git a/PhysX_3.4/Source/PhysX/src/cloth/NpCloth.cpp b/PhysX_3.4/Source/PhysX/src/cloth/NpCloth.cpp new file mode 100644 index 00000000..45b6beed --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/cloth/NpCloth.cpp @@ -0,0 +1,1342 @@ +// 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 "NpCloth.h" +#include "NpClothFabric.h" +#include "NpScene.h" +#include "NpPhysics.h" + +using namespace physx; + +// PX_SERIALIZATION +NpCloth::NpCloth(PxBaseFlags baseFlags) : NpClothT(baseFlags), mCloth(PxEmpty), mParticleData(*this) +{ +} +//~PX_SERIALIZATION + +NpCloth::NpCloth(const PxTransform& globalPose, NpClothFabric& fabric, const PxClothParticle* particles, PxClothFlags flags) : + NpClothT(PxConcreteType::eCLOTH, PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE, NULL, NULL), + mCloth(globalPose, fabric.getScClothFabric(), particles, flags), + mClothFabric(&fabric), + mParticleData(*this) +{ + fabric.incRefCount(); +} + +NpCloth::~NpCloth() +{ + // ScClothCore deletion is buffered, but ScClothFabricCore is not + // make sure we don't have a dangling pointer in ScClothCore. + if(1 == mClothFabric->getRefCount()) + mCloth.resetFabric(); + + mClothFabric->decRefCount(); +} + +// PX_SERIALIZATION +void NpCloth::resolveReferences(PxDeserializationContext& context) +{ + context.translatePxBase(mClothFabric); + mClothFabric->incRefCount(); + + // pass fabric down to Scb + mCloth.resolveReferences(mClothFabric->getScClothFabric()); +} + +void NpCloth::requires(PxProcessPxBaseCallback& c) +{ + c.process(*mClothFabric); +} + +NpCloth* NpCloth::createObject(PxU8*& address, PxDeserializationContext& context) +{ + NpCloth* obj = new (address) NpCloth(PxBaseFlag::eIS_RELEASABLE); + address += sizeof(NpCloth); + obj->importExtraData(context); + obj->resolveReferences(context); + return obj; +} +//~PX_SERIALIZATION + +void NpCloth::release() +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + NpPhysics::getInstance().notifyDeletionListenersUserRelease(this, userData); + +// PX_AGGREGATE + // initially no support for aggregates + //NpClothT::release(); // PT: added for PxAggregate +//~PX_AGGREGATE + + NpScene* npScene = NpActor::getAPIScene(*this); + if(npScene) // scene is 0 after scheduling for remove + npScene->removeCloth(*this); + + mCloth.destroy(); +} + + +PxActorType::Enum NpCloth::getType() const +{ + return PxActorType::eCLOTH; +} + + +PxClothFabric* NpCloth::getFabric() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + Sc::ClothFabricCore* scFabric = mCloth.getFabric(); + + size_t scOffset = reinterpret_cast<size_t>(&(reinterpret_cast<NpClothFabric*>(0)->getScClothFabric())); + return reinterpret_cast<NpClothFabric*>(reinterpret_cast<char*>(scFabric)-scOffset); +} + + +void NpCloth::setParticles(const PxClothParticle* currentParticles, const PxClothParticle* previousParticles) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + +#if PX_CHECKED + if (currentParticles) + PX_CHECK_AND_RETURN(checkParticles(mCloth.getNbParticles(), currentParticles), "PxCloth::setParticles: values must be finite and inverse weight must not be negative"); + if (previousParticles) + PX_CHECK_AND_RETURN(checkParticles(mCloth.getNbParticles(), previousParticles), "PxCloth::setParticles: values must be finite and inverse weight must not be negative"); +#endif + + mCloth.setParticles(currentParticles, previousParticles); +} + +PxU32 NpCloth::getNbParticles() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return mCloth.getNbParticles(); +} + +void NpCloth::setMotionConstraints(const PxClothParticleMotionConstraint* motionConstraints) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + +#if PX_CHECKED + PX_CHECK_AND_RETURN(checkMotionConstraints(mCloth.getNbParticles(), motionConstraints), "PxCloth::setMotionConstraints: values must be finite and radius must not be negative"); +#endif + + mCloth.setMotionConstraints(motionConstraints); + sendPvdMotionConstraints(); +} + + +bool NpCloth::getMotionConstraints(PxClothParticleMotionConstraint* motionConstraintsBuffer) const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_MSG(motionConstraintsBuffer || !getNbMotionConstraints(), "PxCloth::getMotionConstraints: no motion constraint buffer provided!"); + + return mCloth.getMotionConstraints(motionConstraintsBuffer); +} + +PxU32 NpCloth::getNbMotionConstraints() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return mCloth.getNbMotionConstraints(); +} + +void NpCloth::setMotionConstraintConfig(const PxClothMotionConstraintConfig& config) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN((config.scale >= 0.0f), "PxCloth::setMotionConstraintConfig: scale must not be negative!"); + + mCloth.setMotionConstraintConfig(config); + sendPvdSimpleProperties(); +} + + +PxClothMotionConstraintConfig NpCloth::getMotionConstraintConfig() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return mCloth.getMotionConstraintConfig(); +} + +void NpCloth::setSeparationConstraints(const PxClothParticleSeparationConstraint* separationConstraints) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + +#if PX_CHECKED + PX_CHECK_AND_RETURN(checkSeparationConstraints(mCloth.getNbParticles(), separationConstraints), "PxCloth::setSeparationConstraints: values must be finite and radius must not be negative"); +#endif + + mCloth.setSeparationConstraints(separationConstraints); + sendPvdSeparationConstraints(); +} + + +bool NpCloth::getSeparationConstraints(PxClothParticleSeparationConstraint* separationConstraintsBuffer) const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_MSG(separationConstraintsBuffer || !getNbSeparationConstraints(), "PxCloth::getSeparationConstraints: no separation constraint buffer provided!"); + + return mCloth.getSeparationConstraints(separationConstraintsBuffer); +} + +PxU32 NpCloth::getNbSeparationConstraints() const +{ + return mCloth.getNbSeparationConstraints(); +} + +void NpCloth::clearInterpolation() +{ + return mCloth.clearInterpolation(); +} + +void NpCloth::setParticleAccelerations(const PxVec4* particleAccelerations) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + +#if PX_CHECKED + PX_CHECK_AND_RETURN(checkParticleAccelerations(mCloth.getNbParticles(), particleAccelerations), "PxCloth::setParticleAccelerations: values must be finite"); +#endif + + mCloth.setParticleAccelerations(particleAccelerations); + + //TODO: PVD support for particle accelerations + //sendPvdParticleAccelerations(); +} + + +bool NpCloth::getParticleAccelerations(PxVec4* particleAccelerationsBuffer) const +{ + PX_CHECK_MSG(particleAccelerationsBuffer, "PxCloth::getParticleAccelerations: no particle accelerations buffer provided!"); + + return mCloth.getParticleAccelerations(particleAccelerationsBuffer); +} + +PxU32 NpCloth::getNbParticleAccelerations() const +{ + return mCloth.getNbParticleAccelerations(); +} + + +void NpCloth::addCollisionSphere(const PxClothCollisionSphere& sphere) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_AND_RETURN(mCloth.getNbCollisionSpheres() < 32, "PxCloth::addCollisionSphere: more than 32 spheres is not supported"); + PX_CHECK_AND_RETURN(checkCollisionSpheres(1, &sphere), "PxCloth::addCollisionSphere: position must be finite and radius must not be negative"); + + mCloth.addCollisionSphere(sphere); +} +void NpCloth::removeCollisionSphere(PxU32 index) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + mCloth.removeCollisionSphere(index); +} +void NpCloth::setCollisionSpheres(const PxClothCollisionSphere* spheresBuffer, PxU32 count) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + +#if PX_CHECKED + PX_CHECK_AND_RETURN(count <= 32, "PxCloth::setCollisionSpheres: more than 32 spheres is not supported"); + PX_CHECK_AND_RETURN(checkCollisionSpheres(count, spheresBuffer), "PxCloth::setCollisionSpheres: positions must be finite and radius must not be negative"); +#endif + + mCloth.setCollisionSpheres(spheresBuffer, count); + sendPvdCollisionSpheres(); +} +PxU32 NpCloth::getNbCollisionSpheres() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return mCloth.getNbCollisionSpheres(); +} + +void NpCloth::getCollisionData(PxClothCollisionSphere* spheresBuffer, PxU32* capsulesBuffer, + PxClothCollisionPlane* planesBuffer, PxU32* convexesBuffer, PxClothCollisionTriangle* trianglesBuffer) const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + mCloth.getCollisionData(spheresBuffer, capsulesBuffer, planesBuffer, convexesBuffer, trianglesBuffer); +} + + +void NpCloth::addCollisionCapsule(PxU32 first, PxU32 second) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_AND_RETURN(mCloth.getNbCollisionCapsules() < 32, "PxCloth::addCollisionCapsule: more than 32 capsules is not supported"); + + mCloth.addCollisionCapsule(first, second); + + sendPvdCollisionCapsules(); +} +void NpCloth::removeCollisionCapsule(PxU32 index) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + mCloth.removeCollisionCapsule(index); + + sendPvdCollisionCapsules(); +} +PxU32 NpCloth::getNbCollisionCapsules() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return mCloth.getNbCollisionCapsules(); +} + +void NpCloth::addCollisionTriangle(const PxClothCollisionTriangle& triangle) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + mCloth.addCollisionTriangle(triangle); + sendPvdCollisionTriangles(); +} +void NpCloth::removeCollisionTriangle(PxU32 index) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + mCloth.removeCollisionTriangle(index); + sendPvdCollisionTriangles(); +} +void NpCloth::setCollisionTriangles(const PxClothCollisionTriangle* trianglesBuffer, PxU32 count) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + mCloth.setCollisionTriangles(trianglesBuffer, count); + sendPvdCollisionTriangles(); +} +PxU32 NpCloth::getNbCollisionTriangles() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return mCloth.getNbCollisionTriangles(); +} + +void NpCloth::addCollisionPlane(const PxClothCollisionPlane& plane) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_AND_RETURN(mCloth.getNbCollisionPlanes() < 32, "PxCloth::addCollisionPlane: more than 32 planes is not supported"); + + mCloth.addCollisionPlane(plane); + sendPvdCollisionTriangles(); +} +void NpCloth::removeCollisionPlane(PxU32 index) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + mCloth.removeCollisionPlane(index); + sendPvdCollisionTriangles(); +} +void NpCloth::setCollisionPlanes(const PxClothCollisionPlane* planesBuffer, PxU32 count) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_AND_RETURN(count <= 32, "PxCloth::setCollisionPlanes: more than 32 planes is not supported"); + + mCloth.setCollisionPlanes(planesBuffer, count); + sendPvdCollisionTriangles(); +} +PxU32 NpCloth::getNbCollisionPlanes() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return mCloth.getNbCollisionPlanes(); +} + +void NpCloth::addCollisionConvex(PxU32 mask) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + mCloth.addCollisionConvex(mask); + sendPvdCollisionTriangles(); +} +void NpCloth::removeCollisionConvex(PxU32 index) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + mCloth.removeCollisionConvex(index); + sendPvdCollisionTriangles(); +} +PxU32 NpCloth::getNbCollisionConvexes() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return mCloth.getNbCollisionConvexes(); +} + +void NpCloth::setVirtualParticles(PxU32 numParticles, const PxU32* indices, PxU32 numWeights, const PxVec3* weights) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_MSG(indices, "PxCloth::setVirtualParticles: no triangle vertex and weight index buffer provided!"); + PX_CHECK_MSG(weights, "PxCloth::setVirtualParticles: no triangle vertex weight buffer provided!"); + +#if PX_CHECKED + PX_CHECK_AND_RETURN(checkVirtualParticles(mCloth.getNbParticles(), numParticles, indices, numWeights, weights), + "PxCloth::setVirtualParticles: out of range value detected"); +#endif + + mCloth.setVirtualParticles(numParticles, indices, numWeights, weights); + sendPvdVirtualParticles(); +} + + +PxU32 NpCloth::getNbVirtualParticles() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return mCloth.getNbVirtualParticles(); +} + + +void NpCloth::getVirtualParticles(PxU32* indicesBuffer) const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_MSG(indicesBuffer, "PxCloth::getVirtualParticles: no triangle vertex and weight index buffer provided!"); + + mCloth.getVirtualParticles(indicesBuffer); +} + + +PxU32 NpCloth::getNbVirtualParticleWeights() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return mCloth.getNbVirtualParticleWeights(); +} + + +void NpCloth::getVirtualParticleWeights(PxVec3* weightsBuffer) const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_MSG(weightsBuffer, "PxCloth::getVirtualParticleWeights: no triangle vertex weight buffer provided!"); + + mCloth.getVirtualParticleWeights(weightsBuffer); +} + + +void NpCloth::setGlobalPose(const PxTransform& pose) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_AND_RETURN(pose.isSane(), "PxCloth::setGlobalPose: invalid transform!"); + + mCloth.setGlobalPose(pose.getNormalized()); + sendPvdSimpleProperties(); +} + + +PxTransform NpCloth::getGlobalPose() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return mCloth.getGlobalPose(); +} + + +void NpCloth::setTargetPose(const PxTransform& pose) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_AND_RETURN(pose.isSane(), "PxCloth::setTargetPose: invalid transform!"); + + mCloth.setTargetPose(pose.getNormalized()); + sendPvdSimpleProperties(); +} + + +void NpCloth::setExternalAcceleration(PxVec3 acceleration) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_AND_RETURN(acceleration.isFinite(), "PxCloth::setExternalAcceleration: invalid values!"); + + mCloth.setExternalAcceleration(acceleration); + sendPvdSimpleProperties(); +} + + +PxVec3 NpCloth::getExternalAcceleration() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return mCloth.getExternalAcceleration(); +} + +namespace +{ +#if PX_CHECKED + bool isInRange(const PxVec3 vec, float low, float high) + { + return vec.x >= low && vec.x <= high + && vec.y >= low && vec.y <= high + && vec.z >= low && vec.z <= high; + } +#endif +} + +void NpCloth::setLinearInertiaScale(PxVec3 scale) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_AND_RETURN(isInRange(scale, 0.0f, 1.0f), "PxCloth::setLinearInertiaScale: scale value has to be between 0 and 1!"); + + mCloth.setLinearInertiaScale(scale); + sendPvdSimpleProperties(); +} + + +PxVec3 NpCloth::getLinearInertiaScale() const +{ + return mCloth.getLinearInertiaScale(); +} + +void NpCloth::setAngularInertiaScale(PxVec3 scale) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_AND_RETURN(isInRange(scale, 0.0f, 1.0f), "PxCloth::setAngularInertiaScale: scale value has to be between 0 and 1!"); + + mCloth.setAngularInertiaScale(scale); + sendPvdSimpleProperties(); +} + + +PxVec3 NpCloth::getAngularInertiaScale() const +{ + return mCloth.getAngularInertiaScale(); +} + +void NpCloth::setCentrifugalInertiaScale(PxVec3 scale) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_AND_RETURN(isInRange(scale, 0.0f, 1.0f), "PxCloth::setCentrifugalInertiaScale: scale value has to be between 0 and 1!"); + + mCloth.setCentrifugalInertiaScale(scale); + sendPvdSimpleProperties(); +} + + +PxVec3 NpCloth::getCentrifugalInertiaScale() const +{ + return mCloth.getCentrifugalInertiaScale(); +} + +void NpCloth::setInertiaScale(float scale) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_AND_RETURN(scale >= 0.0f && scale <= 1.0f, "PxCloth::setInertiaScale: scale value has to be between 0 and 1!"); + + mCloth.setLinearInertiaScale(PxVec3(scale)); + mCloth.setAngularInertiaScale(PxVec3(scale)); + sendPvdSimpleProperties(); +} + +void NpCloth::setDampingCoefficient(PxVec3 dampingCoefficient) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_AND_RETURN(isInRange(dampingCoefficient, 0.0f, 1.0f), "PxCloth::setDampingCoefficient: damping coefficient has to be between 0 and 1!"); + + mCloth.setDampingCoefficient(dampingCoefficient); + sendPvdSimpleProperties(); +} + + +PxVec3 NpCloth::getDampingCoefficient() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return mCloth.getDampingCoefficient(); +} + + +void NpCloth::setFrictionCoefficient(PxReal frictionCoefficient) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_AND_RETURN(frictionCoefficient >= 0.0f || frictionCoefficient <= 1.0f, "PxCloth::setFrictionCoefficient: friction coefficient has to be between 0 and 1!"); + + mCloth.setFrictionCoefficient(frictionCoefficient); + sendPvdSimpleProperties(); +} + +PxReal NpCloth::getFrictionCoefficient() const +{ + return mCloth.getFrictionCoefficient(); +} + +void NpCloth::setLinearDragCoefficient(PxVec3 dragCoefficient) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_AND_RETURN(isInRange(dragCoefficient, 0.0f, 1.0f), "PxCloth::setLinearDragCoefficient: damping coefficient has to be between 0 and 1!"); + + mCloth.setLinearDragCoefficient(dragCoefficient); + sendPvdSimpleProperties(); +} + + +PxVec3 NpCloth::getLinearDragCoefficient() const +{ + return mCloth.getLinearDragCoefficient(); +} + +void NpCloth::setAngularDragCoefficient(PxVec3 dragCoefficient) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_AND_RETURN(isInRange(dragCoefficient, 0.0f, 1.0f), "PxCloth::setAngularDragCoefficient: damping coefficient has to be between 0 and 1!"); + + mCloth.setAngularDragCoefficient(dragCoefficient); + sendPvdSimpleProperties(); +} + + +PxVec3 NpCloth::getAngularDragCoefficient() const +{ + return mCloth.getAngularDragCoefficient(); +} + +void NpCloth::setDragCoefficient(float coefficient) +{ + setLinearDragCoefficient(PxVec3(coefficient)); + setAngularDragCoefficient(PxVec3(coefficient)); +} + +void NpCloth::setCollisionMassScale(PxReal scalingCoefficient) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_AND_RETURN(scalingCoefficient >= 0.0f, "PxCloth::setCollisionMassScale: scaling coefficient has to be greater or equal than 0!"); + + mCloth.setCollisionMassScale(scalingCoefficient); +} + + +PxReal NpCloth::getCollisionMassScale() const +{ + return mCloth.getCollisionMassScale(); +} + +void NpCloth::setSelfCollisionDistance(PxReal distance) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_AND_RETURN(distance >= 0.0f, "PxCloth::setSelfCollisionDistance: distance has to be greater or equal than 0!"); + + mCloth.setSelfCollisionDistance(distance); +} +PxReal NpCloth::getSelfCollisionDistance() const +{ + return mCloth.getSelfCollisionDistance(); +} +void NpCloth::setSelfCollisionStiffness(PxReal stiffness) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_AND_RETURN(stiffness >= 0.0f, "PxCloth::setSelfCollisionStiffness: stiffness has to be greater or equal than 0!"); + + mCloth.setSelfCollisionStiffness(stiffness); +} +PxReal NpCloth::getSelfCollisionStiffness() const +{ + return mCloth.getSelfCollisionStiffness(); +} + +void NpCloth::setSelfCollisionIndices(const PxU32* indices, PxU32 nbIndices) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + mCloth.setSelfCollisionIndices(indices, nbIndices); + + sendPvdSelfCollisionIndices(); +} + +bool NpCloth::getSelfCollisionIndices(PxU32* indices) const +{ + return mCloth.getSelfCollisionIndices(indices); +} + +PxU32 NpCloth::getNbSelfCollisionIndices() const +{ + return mCloth.getNbSelfCollisionIndices(); +} + +void NpCloth::setRestPositions(const PxVec4* restPositions) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + mCloth.setRestPositions(restPositions); + + sendPvdRestPositions(); +} + +bool NpCloth::getRestPositions(PxVec4* restPositions) const +{ + return mCloth.getRestPositions(restPositions); +} + +PxU32 NpCloth::getNbRestPositions() const +{ + return mCloth.getNbRestPositions(); +} + +void NpCloth::setSolverFrequency(PxReal frequency) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_AND_RETURN(frequency > 0.0f, "PxCloth::setSolverFrequency: solver fequency has to be positive!"); + + mCloth.setSolverFrequency(frequency); + sendPvdSimpleProperties(); +} + + +PxReal NpCloth::getSolverFrequency() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return mCloth.getSolverFrequency(); +} + +void NpCloth::setStiffnessFrequency(PxReal frequency) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_AND_RETURN(frequency > 0.0f, "PxCloth::setStiffnessFrequency: solver fequency has to be positive!"); + + mCloth.setStiffnessFrequency(frequency); + sendPvdSimpleProperties(); +} + + +PxReal NpCloth::getStiffnessFrequency() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return mCloth.getStiffnessFrequency(); +} + +void NpCloth::setStretchConfig(PxClothFabricPhaseType::Enum type, const PxClothStretchConfig& config) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_MSG(config.stiffness >= 0.0f, "PxCloth::setStretchConfig: stiffness must not be negative!"); + PX_CHECK_MSG(config.stiffnessMultiplier >= 0.0f, "PxCloth::setStretchConfig: stiffnessMultiplier must not be negative!"); + PX_CHECK_MSG(config.compressionLimit >= 0.0f, "PxCloth::setStretchConfig: compressionLimit must not be negative!"); + PX_CHECK_MSG(config.compressionLimit <= 1.0f, "PxCloth::setStretchConfig: compressionLimit must not be larger than 1!"); + PX_CHECK_MSG(config.stretchLimit >= 1.0f, "PxCloth::setStretchConfig: stretchLimit must not be smaller than 1!"); + + mCloth.setStretchConfig(type, config); + sendPvdSimpleProperties(); +} + +void NpCloth::setTetherConfig(const PxClothTetherConfig& config) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_MSG(config.stiffness >= 0.0f, "PxCloth::setTetherConfig: stiffness must not be negative!"); + + mCloth.setTetherConfig(config); + sendPvdSimpleProperties(); +} + +PxClothStretchConfig NpCloth::getStretchConfig(PxClothFabricPhaseType::Enum type) const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return mCloth.getStretchConfig(type); +} + +PxClothTetherConfig NpCloth::getTetherConfig() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return mCloth.getTetherConfig(); +} + +void NpCloth::setClothFlags(PxClothFlags flags) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + mCloth.setClothFlags(flags); + sendPvdSimpleProperties(); + + NpScene* scene = NpActor::getAPIScene(*this); + if (scene) + scene->updatePhysXIndicator(); +} + +void NpCloth::setClothFlag(PxClothFlag::Enum flag, bool val) +{ + PxClothFlags flags = mCloth.getClothFlags(); + setClothFlags(val ? flags | flag : flags & ~flag); +} + + +PxClothFlags NpCloth::getClothFlags() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return mCloth.getClothFlags(); +} + +void NpCloth::setWindVelocity(PxVec3 value) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + mCloth.setWindVelocity(value); + sendPvdSimpleProperties(); +} + +PxVec3 NpCloth::getWindVelocity() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return mCloth.getWindVelocity(); +} + +void NpCloth::setWindDrag(PxReal value) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_AND_RETURN(value >= 0.0f, "PxCloth::setWindDrag: value has to be non-negative!"); + + mCloth.setDragCoefficient(value); + sendPvdSimpleProperties(); +} + +PxReal NpCloth::getWindDrag() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return mCloth.getDragCoefficient(); +} + +void NpCloth::setWindLift(PxReal value) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_AND_RETURN(value >= 0.0f, "PxCloth::setWindLift: value has to be non-negative!"); + + mCloth.setLiftCoefficient(value); + sendPvdSimpleProperties(); +} + +PxReal NpCloth::getWindLift() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return mCloth.getLiftCoefficient(); +} + + +bool NpCloth::isSleeping() const +{ + NpScene* scene = NpActor::getOwnerScene(*this); + PX_UNUSED(scene); + + NP_READ_CHECK(scene); + PX_CHECK_AND_RETURN_VAL(scene, "PxCloth::isSleeping: cloth must be in a scene.", true); + + return mCloth.isSleeping(); +} + + +PxReal NpCloth::getSleepLinearVelocity() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return mCloth.getSleepLinearVelocity(); +} + + +void NpCloth::setSleepLinearVelocity(PxReal threshold) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_MSG(threshold >= 0.0f, "PxCloth::setSleepLinearVelocity: threshold must not be negative!"); + + mCloth.setSleepLinearVelocity(threshold); + sendPvdSimpleProperties(); +} + + +void NpCloth::setWakeCounter(PxReal wakeCounterValue) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(PxIsFinite(wakeCounterValue), "PxCloth::setWakeCounter: invalid float."); + PX_CHECK_AND_RETURN(wakeCounterValue>=0.0f, "PxCloth::setWakeCounter: wakeCounterValue must be non-negative!"); + + mCloth.setWakeCounter(wakeCounterValue); +} + + +PxReal NpCloth::getWakeCounter() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return mCloth.getWakeCounter(); +} + + +void NpCloth::wakeUp() +{ + NpScene* scene = NpActor::getOwnerScene(*this); + PX_UNUSED(scene); + + NP_WRITE_CHECK(scene); + PX_CHECK_AND_RETURN(scene, "PxCloth::wakeUp: cloth must be in a scene."); + + mCloth.wakeUp(); +} + + +void NpCloth::putToSleep() +{ + NpScene* scene = NpActor::getOwnerScene(*this); + PX_UNUSED(scene); + + NP_WRITE_CHECK(scene); + PX_CHECK_AND_RETURN(scene, "PxCloth::putToSleep: cloth must be in a scene."); + + mCloth.putToSleep(); +} + + +PxClothParticleData* NpCloth::lockParticleData(PxDataAccessFlags flags) +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + if(!mParticleData.tryLock(flags)) + { + shdfnd::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, + "PxClothParticleData access through PxCloth::lockParticleData() while its still locked by last call."); + return 0; + } + + mCloth.getParticleData(mParticleData); + return &mParticleData; +} + +PxClothParticleData* NpCloth::lockParticleData() const +{ + return const_cast<NpCloth*>(this)->lockParticleData(PxDataAccessFlag::eREADABLE); +} + +void NpCloth::unlockParticleData() +{ + mCloth.getScCloth().unlockParticleData(); +} + +PxReal NpCloth::getPreviousTimeStep() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + return mCloth.getPreviousTimeStep(); +} + + +PxBounds3 NpCloth::getWorldBounds(float inflation) const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + const PxBounds3 bounds = mCloth.getWorldBounds(); + PX_ASSERT(bounds.isValid()); + + // PT: unfortunately we can't just scale the min/max vectors, we need to go through center/extents. + const PxVec3 center = bounds.getCenter(); + const PxVec3 inflatedExtents = bounds.getExtents() * inflation; + return PxBounds3::centerExtents(center, inflatedExtents); +} + +void NpCloth::setSimulationFilterData(const PxFilterData& data) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + mCloth.setSimulationFilterData(data); +} + +PxFilterData NpCloth::getSimulationFilterData() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return mCloth.getSimulationFilterData(); +} + +void NpCloth::setContactOffset(PxReal offset) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + mCloth.setContactOffset(offset); +} + +PxReal NpCloth::getContactOffset() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return mCloth.getContactOffset(); +} + +void NpCloth::setRestOffset(PxReal offset) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + mCloth.setRestOffset(offset); +} + +PxReal NpCloth::getRestOffset() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return mCloth.getRestOffset(); +} + +#if PX_CHECKED +bool NpCloth::checkParticles(PxU32 numParticles, const PxClothParticle* particles) +{ + for (PxU32 i = 0; i < numParticles; ++i) + { + if(!particles[i].pos.isFinite()) + return false; + if(!PxIsFinite(particles[i].invWeight) || (particles[i].invWeight < 0.0f)) + return false; + } + return true; +} + +bool NpCloth::checkMotionConstraints(PxU32 numConstraints, const PxClothParticleMotionConstraint* constraints) +{ + if(!constraints) + return true; + + for (PxU32 i = 0; i < numConstraints; ++i) + { + if(!constraints[i].pos.isFinite()) + return false; + if(!PxIsFinite(constraints[i].radius) || (constraints[i].radius < 0.0f)) + return false; + } + return true; +} + + +bool NpCloth::checkSeparationConstraints(PxU32 numConstraints, const PxClothParticleSeparationConstraint* constraints) +{ + if(!constraints) + return true; + + for (PxU32 i = 0; i < numConstraints; ++i) + { + if(!constraints[i].pos.isFinite()) + return false; + if(!PxIsFinite(constraints[i].radius) || (constraints[i].radius < 0.0f)) + return false; + } + return true; +} + +bool NpCloth::checkParticleAccelerations(PxU32 numParticles, const PxVec4* accelerations) +{ + if(!accelerations) + return true; + + for (PxU32 i = 0; i < numParticles; ++i) + { + if(!accelerations[i].isFinite()) + return false; + } + return true; +} + +bool NpCloth::checkCollisionSpheres(PxU32 numSpheres, const PxClothCollisionSphere* spheres) +{ + for (PxU32 i = 0; i < numSpheres; ++i) + { + if(!spheres[i].pos.isFinite()) + return false; + if(!PxIsFinite(spheres[i].radius) || (spheres[i].radius < 0.0f)) + return false; + } + return true; +} + +bool NpCloth::checkCollisionSpherePairs(PxU32 numSpheres, PxU32 numPairs, const PxU32* pairIndices) +{ + for (PxU32 i = 0; i < numPairs; ++i) + { + if ((pairIndices[2*i] >= numSpheres) || (pairIndices[2*i + 1] >= numSpheres)) + return false; + } + return true; +} + +bool NpCloth::checkVirtualParticles(PxU32 numParticles, PxU32 numVParticles, const PxU32* indices, PxU32 numWeights, const PxVec3* weights) +{ + for (PxU32 i = 0; i < numVParticles; ++i) + { + if ((indices[4*i] >= numParticles) || + (indices[4*i + 1] >= numParticles) || + (indices[4*i + 2] >= numParticles) || + (indices[4*i + 3] >= numWeights)) + return false; + } + for (PxU32 i = 0; i < numWeights; ++i) + { + if(!weights[i].isFinite()) + return false; + } + return true; +} +#endif + +#if PX_ENABLE_DEBUG_VISUALIZATION +void NpCloth::visualize(Cm::RenderOutput& out, NpScene* scene) +{ + PxClothParticleData* readData = lockParticleData(); + if (!readData) + return; + + NpClothFabric* fabric = static_cast<NpClothFabric*> (getFabric()); + + PxU32 nbSets = fabric->getNbSets(); + PxU32 nbPhases = fabric->getNbPhases(); + PxU32 nbIndices = fabric->getNbParticleIndices(); + + shdfnd::Array<PxU32> sets(nbSets); + shdfnd::Array<PxClothFabricPhase> phases(nbPhases); + shdfnd::Array<PxU32> indices(nbIndices); + + fabric->getSets(&sets[0], nbSets); + fabric->getPhases(&phases[0], nbPhases); + fabric->getParticleIndices(&indices[0], nbIndices); + + const PxU32 lineColor[] = + { + PxU32(PxDebugColor::eARGB_RED), + PxU32(PxDebugColor::eARGB_GREEN), + PxU32(PxDebugColor::eARGB_BLUE), + PxU32(PxDebugColor::eARGB_YELLOW), + PxU32(PxDebugColor::eARGB_MAGENTA) + }; + + PxU32 colorIndex = 0; + + const PxClothParticle* particles = readData->particles; + const PxTransform xform = getGlobalPose(); + + out << Cm::RenderOutput::LINES; + + for (PxU32 p=0; p < nbPhases; ++p) + { + PxClothFabricPhaseType::Enum phaseType = fabric->getPhaseType(p); + + float scale = 0.0f; + + // check if visualization requested + switch(phaseType) + { + case PxClothFabricPhaseType::eVERTICAL: + scale = scene->getVisualizationParameter(PxVisualizationParameter::eCLOTH_VERTICAL); + break; + case PxClothFabricPhaseType::eHORIZONTAL: + scale = scene->getVisualizationParameter(PxVisualizationParameter::eCLOTH_HORIZONTAL); + break; + case PxClothFabricPhaseType::eBENDING: + scale = scene->getVisualizationParameter(PxVisualizationParameter::eCLOTH_BENDING); + break; + case PxClothFabricPhaseType::eSHEARING: + scale = scene->getVisualizationParameter(PxVisualizationParameter::eCLOTH_SHEARING); + break; + case PxClothFabricPhaseType::eINVALID: + case PxClothFabricPhaseType::eCOUNT: + break; + } + + if (scale == 0.0f) + continue; + + out << lineColor[colorIndex]; + + PxU32 set = phases[p].setIndex; + + // draw one set at a time + PxU32 iIt = set ? 2*sets[set-1] : 0; + PxU32 iEnd = 2*sets[set]; + + // iterate over constraints + while (iIt < iEnd) + { + PxU32 i0 = indices[iIt++]; + PxU32 i1 = indices[iIt++]; + + // ideally we would know the mesh normals here and bias off + // the surface slightly but scaling slightly around the center helps + out << xform.transform(particles[i0].pos); + out << xform.transform(particles[i1].pos); + } + + colorIndex = (colorIndex+1)%5; + } + + // draw virtual particles + if (scene->getVisualizationParameter(PxVisualizationParameter::eCLOTH_VIRTUAL_PARTICLES) > 0.0f) + { + PxU32 nbVirtualParticles = getNbVirtualParticles(); + + if (nbVirtualParticles) + { + out << Cm::RenderOutput::POINTS; + out << PxU32(PxDebugColor::eARGB_WHITE); + + shdfnd::Array<PxU32> vpIndices(nbVirtualParticles*4); + getVirtualParticles(&vpIndices[0]); + + // get weights table + PxU32 nbVirtualParticleWeights = getNbVirtualParticleWeights(); + shdfnd::Array<PxVec3> vpWeights(nbVirtualParticleWeights); + getVirtualParticleWeights(&vpWeights[0]); + + for (PxU32 i=0; i < nbVirtualParticles; ++i) + { + PxU32 i0 = vpIndices[i*4+0]; + PxU32 i1 = vpIndices[i*4+1]; + PxU32 i2 = vpIndices[i*4+2]; + + PxVec3 v0 = xform.transform(readData->particles[i0].pos); + PxVec3 v1 = xform.transform(readData->particles[i1].pos); + PxVec3 v2 = xform.transform(readData->particles[i2].pos); + + PxVec3 weights = vpWeights[vpIndices[i*4+3]]; + + out << (v0*weights.x + v1*weights.y + v2*weights.z); + } + } + } + + readData->unlock(); +} + +#endif + +#if PX_SUPPORT_PVD +namespace +{ + Vd::ScbScenePvdClient* getScenePvdClient( Scb::Scene* scene ) + { + if(scene ) + { + Vd::ScbScenePvdClient& pvdClient = scene->getScenePvdClient(); + if(pvdClient.checkPvdDebugFlag()) + return &pvdClient; + } + return NULL; + } +} +#endif + +void NpCloth::sendPvdSimpleProperties() +{ +#if PX_SUPPORT_PVD + Vd::ScbScenePvdClient* pvdClient = getScenePvdClient( mCloth.getScbSceneForAPI() ); + if ( pvdClient ) pvdClient->sendSimpleProperties( &mCloth ); +#endif +} + +void NpCloth::sendPvdMotionConstraints() +{ +#if PX_SUPPORT_PVD + Vd::ScbScenePvdClient* pvdClient = getScenePvdClient( mCloth.getScbSceneForAPI() ); + if ( pvdClient ) pvdClient->sendMotionConstraints( &mCloth ); +#endif +} + +void NpCloth::sendPvdSelfCollisionIndices() +{ +#if PX_SUPPORT_PVD + Vd::ScbScenePvdClient* pvdClient = getScenePvdClient( mCloth.getScbSceneForAPI() ); + if ( pvdClient ) pvdClient->sendSelfCollisionIndices( &mCloth ); +#endif +} + +void NpCloth::sendPvdRestPositions() +{ +#if PX_SUPPORT_PVD + Vd::ScbScenePvdClient* pvdClient = getScenePvdClient( mCloth.getScbSceneForAPI() ); + if ( pvdClient ) pvdClient->sendRestPositions( &mCloth ); +#endif +} + +void NpCloth::sendPvdSeparationConstraints() +{ +#if PX_SUPPORT_PVD + Vd::ScbScenePvdClient* pvdClient = getScenePvdClient( mCloth.getScbSceneForAPI() ); + if ( pvdClient ) pvdClient->sendSeparationConstraints( &mCloth ); +#endif +} + +void NpCloth::sendPvdCollisionSpheres() +{ +#if PX_SUPPORT_PVD + Vd::ScbScenePvdClient* pvdClient = getScenePvdClient( mCloth.getScbSceneForAPI() ); + if ( pvdClient ) pvdClient->sendCollisionSpheres( &mCloth ); +#endif +} + +void NpCloth::sendPvdCollisionCapsules() +{ +#if PX_SUPPORT_PVD + Vd::ScbScenePvdClient* pvdClient = getScenePvdClient( mCloth.getScbSceneForAPI() ); + if ( pvdClient ) pvdClient->sendCollisionCapsules( &mCloth ); +#endif +} + +void NpCloth::sendPvdCollisionTriangles() +{ +#if PX_SUPPORT_PVD + Vd::ScbScenePvdClient* pvdClient = getScenePvdClient( mCloth.getScbSceneForAPI() ); + if ( pvdClient ) pvdClient->sendCollisionTriangles( &mCloth ); +#endif +} + +void NpCloth::sendPvdVirtualParticles() +{ +#if PX_SUPPORT_PVD + Vd::ScbScenePvdClient* pvdClient = getScenePvdClient( mCloth.getScbSceneForAPI() ); + if ( pvdClient ) pvdClient->sendVirtualParticles( &mCloth ); +#endif +} + +#endif // PX_USE_CLOTH_API diff --git a/PhysX_3.4/Source/PhysX/src/cloth/NpCloth.h b/PhysX_3.4/Source/PhysX/src/cloth/NpCloth.h new file mode 100644 index 00000000..14a98b93 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/cloth/NpCloth.h @@ -0,0 +1,269 @@ +// 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_NP_CLOTH +#define PX_PHYSICS_NP_CLOTH + +#include "PxPhysXConfig.h" + +#if PX_USE_CLOTH_API + +#include "PxCloth.h" +#include "NpActorTemplate.h" +#include "ScbCloth.h" + + +namespace physx +{ +class NpClothFabric; + +typedef NpActorTemplate<PxCloth> NpClothT; + +class NpCloth : public NpClothT +{ +//= 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 + NpCloth(PxBaseFlags baseFlags); + virtual void requires(PxProcessPxBaseCallback& c); + virtual void exportExtraData(PxSerializationContext& stream) { mCloth.exportExtraData(stream); } + void importExtraData(PxDeserializationContext& context) { mCloth.importExtraData(context); } + void resolveReferences(PxDeserializationContext& context); + static NpCloth* createObject(PxU8*& address, PxDeserializationContext& context); + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + NpCloth(const PxTransform& globalPose, NpClothFabric& fabric, const PxClothParticle* particles, PxClothFlags flags); + virtual ~NpCloth(); + NpCloth &operator=(const NpCloth &); + + //--------------------------------------------------------------------------------- + // PxCloth implementation + //--------------------------------------------------------------------------------- + virtual void release(); + + virtual PxActorType::Enum getType() const; + + virtual PxClothFabric* getFabric() const; + + virtual void setParticles(const PxClothParticle* currentParticles, const PxClothParticle* previousParticles); + virtual PxU32 getNbParticles() const; + + virtual void setMotionConstraints(const PxClothParticleMotionConstraint* motionConstraints); + virtual bool getMotionConstraints(PxClothParticleMotionConstraint* motionConstraintsBuffer) const; + virtual PxU32 getNbMotionConstraints() const; + + virtual void setMotionConstraintConfig(const PxClothMotionConstraintConfig& config); + virtual PxClothMotionConstraintConfig getMotionConstraintConfig() const; + + virtual void setSeparationConstraints(const PxClothParticleSeparationConstraint* separationConstraints); + virtual bool getSeparationConstraints(PxClothParticleSeparationConstraint* separationConstraintsBuffer) const; + virtual PxU32 getNbSeparationConstraints() const; + + virtual void clearInterpolation(); + + virtual void setParticleAccelerations(const PxVec4* particleAccelerations); + virtual bool getParticleAccelerations(PxVec4* particleAccelerationsBuffer) const; + virtual PxU32 getNbParticleAccelerations() const; + + virtual void addCollisionSphere(const PxClothCollisionSphere& sphere); + virtual void removeCollisionSphere(PxU32 index); + virtual void setCollisionSpheres(const PxClothCollisionSphere* spheresBuffer, PxU32 count); + virtual PxU32 getNbCollisionSpheres() const; + + virtual void getCollisionData(PxClothCollisionSphere* spheresBuffer, PxU32* capsulesBuffer, + PxClothCollisionPlane* planesBuffer, PxU32* convexesBuffer, PxClothCollisionTriangle* trianglesBuffer) const; + + virtual void addCollisionCapsule(PxU32 first, PxU32 second); + virtual void removeCollisionCapsule(PxU32 index); + virtual PxU32 getNbCollisionCapsules() const; + + virtual void addCollisionTriangle(const PxClothCollisionTriangle& triangle); + virtual void removeCollisionTriangle(PxU32 index); + virtual void setCollisionTriangles(const PxClothCollisionTriangle* trianglesBuffer, PxU32 count); + virtual PxU32 getNbCollisionTriangles() const; + + virtual void addCollisionPlane(const PxClothCollisionPlane& plane); + virtual void removeCollisionPlane(PxU32 index); + virtual void setCollisionPlanes(const PxClothCollisionPlane* planesBuffer, PxU32 count); + virtual PxU32 getNbCollisionPlanes() const; + + virtual void addCollisionConvex(PxU32 mask); + virtual void removeCollisionConvex(PxU32 index); + virtual PxU32 getNbCollisionConvexes() const; + + virtual void setVirtualParticles(PxU32 numParticles, const PxU32* indices, PxU32 numWeights, const PxVec3* weights); + + virtual PxU32 getNbVirtualParticles() const; + virtual void getVirtualParticles(PxU32* indicesBuffer) const; + + virtual PxU32 getNbVirtualParticleWeights() const; + virtual void getVirtualParticleWeights(PxVec3* weightsBuffer) const; + + virtual void setGlobalPose(const PxTransform& pose); + virtual PxTransform getGlobalPose() const; + + virtual void setTargetPose(const PxTransform& pose); + + virtual void setExternalAcceleration(PxVec3 acceleration); + virtual PxVec3 getExternalAcceleration() const; + + virtual void setLinearInertiaScale(PxVec3 scale); + virtual PxVec3 getLinearInertiaScale() const; + virtual void setAngularInertiaScale(PxVec3 scale); + virtual PxVec3 getAngularInertiaScale() const; + virtual void setCentrifugalInertiaScale(PxVec3 scale); + virtual PxVec3 getCentrifugalInertiaScale() const; + virtual void setInertiaScale(float); + + virtual void setDampingCoefficient(PxVec3 dampingCoefficient); + virtual PxVec3 getDampingCoefficient() const; + + virtual void setFrictionCoefficient(PxReal frictionCoefficient); + virtual PxReal getFrictionCoefficient() const; + + virtual void setLinearDragCoefficient(PxVec3 dampingCoefficient); + virtual PxVec3 getLinearDragCoefficient() const; + virtual void setAngularDragCoefficient(PxVec3 dampingCoefficient); + virtual PxVec3 getAngularDragCoefficient() const; + virtual void setDragCoefficient(float); + + virtual void setCollisionMassScale(PxReal scalingCoefficient); + virtual PxReal getCollisionMassScale() const; + + virtual void setSelfCollisionDistance(PxReal distance); + virtual PxReal getSelfCollisionDistance() const; + virtual void setSelfCollisionStiffness(PxReal stiffness); + virtual PxReal getSelfCollisionStiffness() const; + + virtual void setSelfCollisionIndices(const PxU32* indices, PxU32 nbIndices); + virtual bool getSelfCollisionIndices(PxU32* indices) const; + virtual PxU32 getNbSelfCollisionIndices() const; + + virtual void setRestPositions(const PxVec4* restPositions); + virtual bool getRestPositions(PxVec4* restPositions) const; + virtual PxU32 getNbRestPositions() const; + + virtual void setSolverFrequency(PxReal); + virtual PxReal getSolverFrequency() const; + + virtual void setStiffnessFrequency(PxReal); + virtual PxReal getStiffnessFrequency() const; + + virtual void setStretchConfig(PxClothFabricPhaseType::Enum type, const PxClothStretchConfig& config); + virtual PxClothStretchConfig getStretchConfig(PxClothFabricPhaseType::Enum type) const; + + virtual void setTetherConfig(const PxClothTetherConfig& config); + virtual PxClothTetherConfig getTetherConfig() const; + + virtual void setClothFlags(PxClothFlags flags); + virtual void setClothFlag(PxClothFlag::Enum flag, bool val); + virtual PxClothFlags getClothFlags() const; + + virtual PxVec3 getWindVelocity() const; + virtual void setWindVelocity(PxVec3); + virtual PxReal getWindDrag() const; + virtual void setWindDrag(PxReal); + virtual PxReal getWindLift() const; + virtual void setWindLift(PxReal); + + virtual bool isSleeping() const; + virtual PxReal getSleepLinearVelocity() const; + virtual void setSleepLinearVelocity(PxReal threshold); + virtual void setWakeCounter(PxReal wakeCounterValue); + virtual PxReal getWakeCounter() const; + virtual void wakeUp(); + virtual void putToSleep(); + + virtual PxClothParticleData* lockParticleData(PxDataAccessFlags); + virtual PxClothParticleData* lockParticleData() const; + + + virtual PxReal getPreviousTimeStep() const; + + virtual PxBounds3 getWorldBounds(float inflation=1.01f) const; + + virtual void setSimulationFilterData(const PxFilterData& data); + virtual PxFilterData getSimulationFilterData() const; + + virtual void setContactOffset(PxReal); + virtual PxReal getContactOffset() const; + virtual void setRestOffset(PxReal); + virtual PxReal getRestOffset() const; + + //--------------------------------------------------------------------------------- + // Miscellaneous + //--------------------------------------------------------------------------------- +public: + + PX_FORCE_INLINE Scb::Cloth& getScbCloth() { return mCloth; } + PX_FORCE_INLINE const Scb::Cloth& getScbCloth() const { return mCloth; } + +#if PX_CHECKED + static bool checkParticles(PxU32 numParticles, const PxClothParticle* particles); + static bool checkMotionConstraints(PxU32 numConstraints, const PxClothParticleMotionConstraint* constraints); + static bool checkSeparationConstraints(PxU32 numConstraints, const PxClothParticleSeparationConstraint* constraints); + static bool checkParticleAccelerations(PxU32 numParticles, const PxVec4* accelerations); + static bool checkCollisionSpheres(PxU32 numSpheres, const PxClothCollisionSphere* spheres); + static bool checkCollisionSpherePairs(PxU32 numSpheres, PxU32 numPairs, const PxU32* pairIndices); + static bool checkVirtualParticles(PxU32 numParticles, PxU32 numVParticles, const PxU32* indices, PxU32 numWeights, const PxVec3* weights); +#endif + +#if PX_ENABLE_DEBUG_VISUALIZATION + virtual void visualize(Cm::RenderOutput& out, NpScene* scene); +#endif + + void unlockParticleData(); + + +private: + + void sendPvdSimpleProperties(); + void sendPvdMotionConstraints(); + void sendPvdSeparationConstraints(); + void sendPvdCollisionSpheres(); + void sendPvdCollisionCapsules(); + void sendPvdCollisionTriangles(); + void sendPvdVirtualParticles(); + void sendPvdSelfCollisionIndices(); + void sendPvdRestPositions(); + Scb::Cloth mCloth; + NpClothFabric* mClothFabric; + NpClothParticleData mParticleData; +}; + +} + +#endif // PX_USE_CLOTH_API +#endif diff --git a/PhysX_3.4/Source/PhysX/src/cloth/NpClothFabric.cpp b/PhysX_3.4/Source/PhysX/src/cloth/NpClothFabric.cpp new file mode 100644 index 00000000..49e33ca2 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/cloth/NpClothFabric.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 "PxPhysXConfig.h" + +#if PX_USE_CLOTH_API + +#include "foundation/PxAssert.h" + +#include "NpClothFabric.h" +#include "NpFactory.h" +#include "NpPhysics.h" + +#include "GuSerialize.h" +#include "CmPhysXCommon.h" +#include "CmUtils.h" + +using namespace physx; + +void NpClothFabric::exportExtraData(PxSerializationContext& stream) +{ + mFabric.exportExtraData(stream); +} + + +void NpClothFabric::importExtraData(PxDeserializationContext& context) +{ + mFabric.importExtraData(context); +} + +NpClothFabric* NpClothFabric::createObject(PxU8*& address, PxDeserializationContext& context) +{ + NpClothFabric* obj = new (address) NpClothFabric(PxBaseFlag::eIS_RELEASABLE); + address += sizeof(NpClothFabric); + obj->importExtraData(context); + obj->resolveReferences(context); + return obj; +} +//~PX_SERIALIZATION + + +NpClothFabric::NpClothFabric() +: PxClothFabric(PxConcreteType::eCLOTH_FABRIC, PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE) +{ +} + + +NpClothFabric::~NpClothFabric() +{ +} + + +void NpClothFabric::release() +{ + decRefCount(); +} + + +void NpClothFabric::onRefCountZero() +{ + if(NpFactory::getInstance().removeClothFabric(*this)) + { + if(getBaseFlags() & PxBaseFlag::eOWNS_MEMORY) + NpFactory::getInstance().releaseClothFabricToPool(*this); + else + this->~NpClothFabric(); + NpPhysics::getInstance().notifyDeletionListenersMemRelease(this, NULL); + return; + } + + // PT: if we reach this point, we didn't find the cloth fabric in the Physics object => don't delete! + // This prevents deleting the object twice. + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "NpClothFabric: double deletion detected!"); +} + + +PxU32 NpClothFabric::getReferenceCount() const +{ + return getRefCount(); +} + + +void NpClothFabric::acquireReference() +{ + incRefCount(); +} + +/** + Load cloth fabric data from the given stream. + + @param[in] stream input stream to load fabric data from + @return true if loading was successful + + @sa For cooker implementation, see ClothFabricBuilder.cpp in PhysXCooking/src + */ +bool NpClothFabric::load(PxInputStream& stream) +{ + return mFabric.load(stream); +} + +bool NpClothFabric::load(const PxClothFabricDesc& desc) +{ + return mFabric.load(desc); +} + +PxU32 NpClothFabric::getNbParticles() const +{ + return getScClothFabric().getNbParticles(); +} + +PxU32 NpClothFabric::getNbPhases() const +{ + return getScClothFabric().getNbPhases(); +} + +PxU32 NpClothFabric::getNbSets() const +{ + return getScClothFabric().getNbSets(); +} + +PxU32 NpClothFabric::getNbParticleIndices() const +{ + return getScClothFabric().getNbParticleIndices(); +} + +PxU32 NpClothFabric::getNbRestvalues() const +{ + return getScClothFabric().getNbRestvalues(); +} + +PxU32 NpClothFabric::getNbTethers() const +{ + return getScClothFabric().getNbTethers(); +} + +PxU32 NpClothFabric::getPhases(PxClothFabricPhase* userPhaseIndexBuffer, PxU32 bufferSize) const +{ + return getScClothFabric().getPhases(userPhaseIndexBuffer, bufferSize); +} + +PxU32 NpClothFabric::getSets(PxU32* userSetBuffer, PxU32 bufferSize) const +{ + return getScClothFabric().getSets(userSetBuffer, bufferSize); +} + +PxU32 NpClothFabric::getParticleIndices(PxU32* userParticleIndexBuffer, PxU32 bufferSize) const +{ + return getScClothFabric().getParticleIndices(userParticleIndexBuffer, bufferSize); +} + +PxU32 NpClothFabric::getRestvalues(PxReal* userRestvalueBuffer, PxU32 bufferSize) const +{ + return getScClothFabric().getRestvalues(userRestvalueBuffer, bufferSize); +} + +PxU32 NpClothFabric::getTetherAnchors(PxU32* userAnchorBuffer, PxU32 bufferSize) const +{ + return getScClothFabric().getTetherAnchors(userAnchorBuffer, bufferSize); +} + +PxU32 NpClothFabric::getTetherLengths(PxReal* userLengthBuffer, PxU32 bufferSize) const +{ + return getScClothFabric().getTetherLengths(userLengthBuffer, bufferSize); +} + +PxClothFabricPhaseType::Enum NpClothFabric::getPhaseType(PxU32 phaseIndex) const +{ + return getScClothFabric().getPhaseType(phaseIndex); +} + +void NpClothFabric::scaleRestlengths(PxReal scale) +{ + mFabric.scaleRestlengths(scale); +} + +#endif // PX_USE_CLOTH_API + diff --git a/PhysX_3.4/Source/PhysX/src/cloth/NpClothFabric.h b/PhysX_3.4/Source/PhysX/src/cloth/NpClothFabric.h new file mode 100644 index 00000000..7c8d06d0 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/cloth/NpClothFabric.h @@ -0,0 +1,112 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + + +#ifndef PX_PHYSICS_NP_CLOTH_FABRIC +#define PX_PHYSICS_NP_CLOTH_FABRIC + +#include "PxPhysXConfig.h" + +#if PX_USE_CLOTH_API + +#include "PsUserAllocated.h" +#include "CmPhysXCommon.h" +#include "CmRefCountable.h" +#include "PxClothFabric.h" +#include "PsArray.h" +#include "ScClothFabricCore.h" // for the people asking: Why is it ok to use Sc directly here? Because there is no double buffering for fabrics (they are like meshes) +#include "PxSerialFramework.h" + +namespace physx +{ + +class NpClothFabric : public PxClothFabric, public Ps::UserAllocated, public Cm::RefCountable +{ +//= 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 + NpClothFabric(PxBaseFlags baseFlags) : PxClothFabric(baseFlags), Cm::RefCountable(PxEmpty), mFabric(PxEmpty) {} + virtual void onRefCountZero(); + virtual void exportExtraData(PxSerializationContext&); + void importExtraData(PxDeserializationContext&); + static NpClothFabric* createObject(PxU8*& address, PxDeserializationContext&); + static void getBinaryMetaData(PxOutputStream& stream); + void resolveReferences(PxDeserializationContext&) {} + virtual void requires(PxProcessPxBaseCallback&){} +//~PX_SERIALIZATION + NpClothFabric(); + + bool load(PxInputStream& stream); + bool load(const PxClothFabricDesc& desc); + +// PxClothFabric + virtual void release(); + + virtual PxU32 getNbParticles() const; + virtual PxU32 getNbPhases() const; + virtual PxU32 getNbSets() const; + virtual PxU32 getNbParticleIndices() const; + virtual PxU32 getNbRestvalues() const; + virtual PxU32 getNbTethers() const; + + virtual PxU32 getPhases(PxClothFabricPhase* userPhaseIndexBuffer, PxU32 bufferSize) const; + virtual PxU32 getSets(PxU32* userSetBuffer, PxU32 bufferSize) const; + virtual PxU32 getParticleIndices(PxU32* userParticleIndexBuffer, PxU32 bufferSize) const; + virtual PxU32 getRestvalues(PxReal* userRestvalueBuffer, PxU32 bufferSize) const; + + virtual PxU32 getTetherAnchors(PxU32* userAnchorBuffer, PxU32 bufferSize) const; + virtual PxU32 getTetherLengths(PxReal* userLengthBuffer, PxU32 bufferSize) const; + + PxClothFabricPhaseType::Enum getPhaseType(PxU32 phaseIndex) const; + + virtual void scaleRestlengths(PxReal scale); + + virtual PxU32 getReferenceCount() const; + virtual void acquireReference(); + //~PxClothFabric + + PX_FORCE_INLINE Sc::ClothFabricCore& getScClothFabric() { return mFabric; } + PX_FORCE_INLINE const Sc::ClothFabricCore& getScClothFabric() const { return mFabric; } + + virtual ~NpClothFabric(); + +protected: + + Sc::ClothFabricCore mFabric; // Internal layer object +}; + +} + +#endif // PX_USE_CLOTH_API +#endif diff --git a/PhysX_3.4/Source/PhysX/src/cloth/NpClothParticleData.cpp b/PhysX_3.4/Source/PhysX/src/cloth/NpClothParticleData.cpp new file mode 100644 index 00000000..78f51680 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/cloth/NpClothParticleData.cpp @@ -0,0 +1,65 @@ +// 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 "NpClothParticleData.h" +#include "NpCloth.h" + +using namespace physx; + +void NpClothParticleData::unlock() +{ + PX_ASSERT(mNbLocks); + + if(!mFlags.isSet(PxDataAccessFlag::eDEVICE)) + { + if (mFlags.isSet(PxDataAccessFlag::eWRITABLE)) + mCloth.setParticles(particles, previousParticles); + mCloth.unlockParticleData(); + } + mFlags.clear(PxDataAccessFlag::eWRITABLE); + mFlags.clear(PxDataAccessFlag::eDEVICE); + + --mNbLocks; +} + +bool NpClothParticleData::tryLock( PxDataAccessFlags flags ) +{ + flags |= mFlags; + if((flags.isSet(PxDataAccessFlag::eWRITABLE) || flags.isSet(PxDataAccessFlag::eDEVICE)) && mNbLocks) + return false; + + mFlags = flags; + ++mNbLocks; + return true; +} + +#endif // PX_USE_CLOTH_API diff --git a/PhysX_3.4/Source/PhysX/src/cloth/NpClothParticleData.h b/PhysX_3.4/Source/PhysX/src/cloth/NpClothParticleData.h new file mode 100644 index 00000000..1668fb35 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/cloth/NpClothParticleData.h @@ -0,0 +1,74 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + + +#ifndef PX_PHYSICS_NP_CLOTH_READ_DATA +#define PX_PHYSICS_NP_CLOTH_READ_DATA + +#include "PxPhysXConfig.h" + +#if PX_USE_CLOTH_API + +#include "PxClothParticleData.h" +#include "PsUserAllocated.h" + +namespace physx +{ + +class NpCloth; + +class NpClothParticleData : public PxClothParticleData, public shdfnd::UserAllocated +{ +public: + + NpClothParticleData(NpCloth& cloth) + : mCloth(cloth), mNbLocks(0), mFlags(PxDataAccessFlag::eREADABLE) + {} + + virtual ~NpClothParticleData() + {} + + // implementation for PxLockedData + virtual PxDataAccessFlags getDataAccessFlags() { return mFlags; } + virtual void unlock(); + + bool tryLock(PxDataAccessFlags); + +private: + NpClothParticleData& operator=(const NpClothParticleData&); + NpCloth& mCloth; + PxU32 mNbLocks; + PxDataAccessFlags mFlags; +}; + +} + +#endif // PX_USE_CLOTH_API + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/device/PhysXIndicator.h b/PhysX_3.4/Source/PhysX/src/device/PhysXIndicator.h new file mode 100644 index 00000000..2f6777ff --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/device/PhysXIndicator.h @@ -0,0 +1,56 @@ +// 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 __PHYSXINDICATOR_H__ +#define __PHYSXINDICATOR_H__ + +#include "foundation/PxPreprocessor.h" + +namespace physx +{ + struct NvPhysXToDrv_Data_V1_; + + class PhysXIndicator + { + public: + PhysXIndicator(bool isGpu = false); + ~PhysXIndicator(); + + void setIsGpu(bool isGpu); + + private: + void updateCounter(int delta); + + NvPhysXToDrv_Data_V1_* mPhysXDataPtr; + void* mFileHandle; + bool mIsGpu; + }; +} + +#endif // __PHYSXINDICATOR_H__ diff --git a/PhysX_3.4/Source/PhysX/src/device/linux/PhysXIndicatorLinux.cpp b/PhysX_3.4/Source/PhysX/src/device/linux/PhysXIndicatorLinux.cpp new file mode 100644 index 00000000..e60569f9 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/device/linux/PhysXIndicatorLinux.cpp @@ -0,0 +1,51 @@ +// 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 "PhysXIndicator.h" +#include "nvPhysXtoDrv.h" + +physx::PhysXIndicator::PhysXIndicator(bool isGpu) +: mPhysXDataPtr(0), mFileHandle(0), mIsGpu(isGpu) +{ + +} + +physx::PhysXIndicator::~PhysXIndicator() +{ +} + +void physx::PhysXIndicator::setIsGpu(bool isGpu) +{ + PX_UNUSED(isGpu); +} + +PX_INLINE void physx::PhysXIndicator::updateCounter(int delta) +{ + PX_UNUSED(delta); +} diff --git a/PhysX_3.4/Source/PhysX/src/device/nvPhysXtoDrv.h b/PhysX_3.4/Source/PhysX/src/device/nvPhysXtoDrv.h new file mode 100644 index 00000000..830193c5 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/device/nvPhysXtoDrv.h @@ -0,0 +1,93 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +#ifndef __NVPHYSXTODRV_H__ +#define __NVPHYSXTODRV_H__ + +// The puprose of this interface is to provide graphics drivers with information +// about PhysX state to draw PhysX visual indicator + +// We share information between modules using a memory section object. PhysX creates +// such object, graphics drivers try to open it. The name of the object has +// fixed part (NvPhysXToDrv_SectionName) followed by the process id. This allows +// each process to have its own communication channel. + +namespace physx +{ + +#define NvPhysXToDrv_SectionName "PH71828182845_" + +// Vista apps cannot create stuff in Global\\ namespace when NOT elevated, so use local scope +#define NvPhysXToDrv_Build_SectionName(PID, buf) sprintf(buf, NvPhysXToDrv_SectionName "%x", static_cast<unsigned int>(PID)) +#define NvPhysXToDrv_Build_SectionNameXP(PID, buf) sprintf(buf, "Global\\" NvPhysXToDrv_SectionName "%x", static_cast<unsigned int>(PID)) + +typedef struct NvPhysXToDrv_Header_ +{ + int signature; // header interface signature + int version; // version of the interface + int size; // size of the structure + int reserved; // reserved, must be zero +} NvPhysXToDrv_Header; + +// this structure describes layout of data in the shared memory section +typedef struct NvPhysXToDrv_Data_V1_ +{ + NvPhysXToDrv_Header header; // keep this member first in all versions of the interface. + + int bCpuPhysicsPresent; // nonzero if cpu physics is initialized + int bGpuPhysicsPresent; // nonzero if gpu physics is initialized + +} NvPhysXToDrv_Data_V1; + +// some random magic number as our interface signature +#define NvPhysXToDrv_Header_Signature 0xA7AB + +// use the macro to setup the header to the latest version of the interface +// update the macro when a new verson of the interface is added +#define NvPhysXToDrv_Header_Init(header) \ +{ \ + header.signature = NvPhysXToDrv_Header_Signature; \ + header.version = 1; \ + header.size = sizeof(NvPhysXToDrv_Data_V1); \ + header.reserved = 0; \ +} + +// validate the header against all known interface versions +// add validation checks when new interfaces are added +#define NvPhysXToDrv_Header_Validate(header, curVersion) \ + ( \ + (header.signature == NvPhysXToDrv_Header_Signature) && \ + (header.version == curVersion) && \ + (curVersion == 1) && \ + (header.size == sizeof(NvPhysXToDrv_Data_V1)) \ + ) + +} + +#endif // __NVPHYSXTODRV_H__ diff --git a/PhysX_3.4/Source/PhysX/src/device/windows/PhysXIndicatorWindows.cpp b/PhysX_3.4/Source/PhysX/src/device/windows/PhysXIndicatorWindows.cpp new file mode 100644 index 00000000..92d43f5a --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/device/windows/PhysXIndicatorWindows.cpp @@ -0,0 +1,131 @@ +// 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 "PhysXIndicator.h" +#include "nvPhysXtoDrv.h" + +#pragma warning (push) +#pragma warning (disable : 4668) //'symbol' is not defined as a preprocessor macro, replacing with '0' for 'directives' +#include <windows.h> +#pragma warning (pop) + +#include <stdio.h> + +#if _MSC_VER >= 1800 +#include <VersionHelpers.h> +#endif + +// Scope-based to indicate to NV driver that CPU PhysX is happening +physx::PhysXIndicator::PhysXIndicator(bool isGpu) +: mPhysXDataPtr(0), mFileHandle(0), mIsGpu(isGpu) +{ + // Get the windows version (we can only create Global\\ namespace objects in XP) + /** + Operating system Version number + ---------------- -------------- + Windows 7 6.1 + Windows Server 2008 R2 6.1 + Windows Server 2008 6.0 + Windows Vista 6.0 + Windows Server 2003 R2 5.2 + Windows Server 2003 5.2 + Windows XP 5.1 + Windows 2000 5.0 + **/ + + char configName[128]; + +#if _MSC_VER >= 1800 + if (!IsWindowsVistaOrGreater()) +#else + OSVERSIONINFOEX windowsVersionInfo; + windowsVersionInfo.dwOSVersionInfoSize = sizeof (windowsVersionInfo); + GetVersionEx((LPOSVERSIONINFO)&windowsVersionInfo); + + if (windowsVersionInfo.dwMajorVersion < 6) +#endif + NvPhysXToDrv_Build_SectionNameXP(GetCurrentProcessId(), configName); + else + NvPhysXToDrv_Build_SectionName(GetCurrentProcessId(), configName); + + mFileHandle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, + PAGE_READWRITE, 0, sizeof(NvPhysXToDrv_Data_V1), configName); + + if (!mFileHandle || mFileHandle == INVALID_HANDLE_VALUE) + return; + + bool alreadyExists = ERROR_ALREADY_EXISTS == GetLastError(); + + mPhysXDataPtr = (physx::NvPhysXToDrv_Data_V1*)MapViewOfFile(mFileHandle, + FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(NvPhysXToDrv_Data_V1)); + + if(!mPhysXDataPtr) + return; + + if (!alreadyExists) + { + mPhysXDataPtr->bCpuPhysicsPresent = 0; + mPhysXDataPtr->bGpuPhysicsPresent = 0; + } + + updateCounter(1); + + // init header last to prevent race conditions + // this must be done because the driver may have already created the shared memory block, + // thus alreadyExists may be true, even if PhysX hasn't been initialized + NvPhysXToDrv_Header_Init(mPhysXDataPtr->header); +} + +physx::PhysXIndicator::~PhysXIndicator() +{ + if(mPhysXDataPtr) + { + updateCounter(-1); + UnmapViewOfFile(mPhysXDataPtr); + } + + if(mFileHandle && mFileHandle != INVALID_HANDLE_VALUE) + CloseHandle(mFileHandle); +} + +void physx::PhysXIndicator::setIsGpu(bool isGpu) +{ + if(!mPhysXDataPtr) + return; + + updateCounter(-1); + mIsGpu = isGpu; + updateCounter(1); +} + +PX_INLINE void physx::PhysXIndicator::updateCounter(int delta) +{ + (mIsGpu ? mPhysXDataPtr->bGpuPhysicsPresent + : mPhysXDataPtr->bCpuPhysicsPresent) += delta; +} diff --git a/PhysX_3.4/Source/PhysX/src/gpu/NpPhysicsGpu.cpp b/PhysX_3.4/Source/PhysX/src/gpu/NpPhysicsGpu.cpp new file mode 100644 index 00000000..2ed19c55 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/gpu/NpPhysicsGpu.cpp @@ -0,0 +1,291 @@ +// 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 "NpPhysicsGpu.h" + +#if PX_SUPPORT_GPU_PHYSX + +#include "NpPhysics.h" +#include "PxvGlobals.h" +#include "PxPhysXGpu.h" +#include "PxParticleGpu.h" +#include "NpScene.h" + +using namespace physx; + +//-------------------------------------------------------------------------------------------------------------------// + +Ps::Array<NpPhysicsGpu::MeshMirror>::Iterator NpPhysicsGpu::findMeshMirror(const void* meshAddress) +{ + Ps::Array<MeshMirror>::Iterator i = mMeshMirrors.begin(); + while (i != mMeshMirrors.end() && i->meshAddress != meshAddress) + i++; + + return i; +} + +Ps::Array<NpPhysicsGpu::MeshMirror>::Iterator NpPhysicsGpu::findMeshMirror(const void* meshAddress, PxCudaContextManager& ctx) +{ + Ps::Array<MeshMirror>::Iterator i = mMeshMirrors.begin(); + while (i != mMeshMirrors.end() && (i->meshAddress != meshAddress || i->ctx != &ctx)) + i++; + + return i; +} + +PxPhysXGpu* NpPhysicsGpu::getPhysXGpu(bool createIfNeeded, const char* functionName, bool doWarn) +{ + PxPhysXGpu* physXGpu = PxvGetPhysXGpu(createIfNeeded); + + if (!physXGpu && doWarn) + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "%s, GPU implementation not available.", functionName); + + return physXGpu; +} + +bool NpPhysicsGpu::checkNewMirror(const void* meshPtr, PxCudaContextManager& ctx, const char* functionName) +{ + Ps::Array<MeshMirror>::Iterator it = findMeshMirror(meshPtr, ctx); + if (it == mMeshMirrors.end()) + return true; + + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "%s has no effect. Mirror already exists.", functionName); + return false; +} + +bool NpPhysicsGpu::checkMirrorExists(Ps::Array<MeshMirror>::Iterator it, const char* functionName) +{ + if (it != mMeshMirrors.end()) + return true; + + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "%s has no effect. Mirror doesn't exist.", functionName); + return false; +} + +bool NpPhysicsGpu::checkMirrorHandle(PxU32 mirrorHandle, const char* functionName) +{ + if (mirrorHandle != PX_INVALID_U32) + return true; + + Ps::getFoundation().error(PxErrorCode::eOUT_OF_MEMORY, __FILE__, __LINE__, "%s failed.", functionName); + return false; +} + +void NpPhysicsGpu::addMeshMirror(const void* meshPtr, PxU32 mirrorHandle, PxCudaContextManager& ctx) +{ + MeshMirror& meshMirror = mMeshMirrors.insert(); + meshMirror.meshAddress = meshPtr; + meshMirror.ctx = &ctx; + meshMirror.mirrorHandle = mirrorHandle; +} + +void NpPhysicsGpu::releaseMeshMirror(const void* meshPtr, const char* functionName, PxCudaContextManager* ctx) +{ + PxPhysXGpu* physXGpu = getPhysXGpu(false, functionName, ctx != NULL); + if (!physXGpu) + return; + + if (ctx) + { + Ps::Array<MeshMirror>::Iterator mirrorIt = findMeshMirror(meshPtr, *ctx); + if (!checkMirrorExists(mirrorIt, functionName)) + return; + + physXGpu->releaseMirror(mirrorIt->mirrorHandle); + mMeshMirrors.replaceWithLast(mirrorIt); + } + else + { + //remove all mesh mirrors for all contexts. + Ps::Array<MeshMirror>::Iterator mirrorIt; + while ((mirrorIt = findMeshMirror(meshPtr)) != mMeshMirrors.end()) + { + physXGpu->releaseMirror(mirrorIt->mirrorHandle); + mMeshMirrors.replaceWithLast(mirrorIt); + } + } +} + +//-------------------------------------------------------------------------------------------------------------------// + + +bool NpPhysicsGpu::createTriangleMeshMirror(const PxTriangleMesh& triangleMesh, PxCudaContextManager& contextManager) +{ + const char* functionName = "PxParticleGpu::createTriangleMeshMirror()"; + PxPhysXGpu* physXGpu = getPhysXGpu(true, functionName); + if (!physXGpu) + return false; + + const void* meshPtr = (const void*)&triangleMesh; + if (!checkNewMirror(meshPtr, contextManager, functionName)) + return true; + + PxU32 mirrorHandle = physXGpu->createTriangleMeshMirror(triangleMesh, contextManager); + if (!checkMirrorHandle(mirrorHandle, functionName)) + return false; + + addMeshMirror(meshPtr, mirrorHandle, contextManager); + return true; +} + +//-------------------------------------------------------------------------------------------------------------------// + +void NpPhysicsGpu::releaseTriangleMeshMirror(const PxTriangleMesh& triangleMesh, PxCudaContextManager* contextManager) +{ + releaseMeshMirror((const void*)&triangleMesh, "PxParticleGpu::releaseTriangleMeshMirror()", contextManager); +} + +//-------------------------------------------------------------------------------------------------------------------// + +bool NpPhysicsGpu::createHeightFieldMirror(const PxHeightField& heightField, PxCudaContextManager& contextManager) +{ + const char* functionName = "PxParticleGpu::createHeightFieldMirror()"; + PxPhysXGpu* physXGpu = getPhysXGpu(true, functionName); + if (!physXGpu) + return false; + + const void* meshPtr = (const void*)&heightField; + if (!checkNewMirror(meshPtr, contextManager, functionName)) + return true; + + PxU32 mirrorHandle = physXGpu->createHeightFieldMirror(heightField, contextManager); + if (!checkMirrorHandle(mirrorHandle, functionName)) + return false; + + addMeshMirror(meshPtr, mirrorHandle, contextManager); + return true; +} + +//-------------------------------------------------------------------------------------------------------------------// + +void NpPhysicsGpu::releaseHeightFieldMirror(const PxHeightField& heightField, PxCudaContextManager* contextManager) +{ + releaseMeshMirror((const void*)&heightField, "PxParticleGpu::releaseHeightFieldMirror()", contextManager); +} + +//-------------------------------------------------------------------------------------------------------------------// + +bool NpPhysicsGpu::createConvexMeshMirror(const PxConvexMesh& convexMesh, PxCudaContextManager& contextManager) +{ + const char* functionName = "PxParticleGpu::createConvexMeshMirror()"; + PxPhysXGpu* physXGpu = getPhysXGpu(true, functionName); + if (!physXGpu) + return false; + + const void* meshPtr = (const void*)&convexMesh; + if (!checkNewMirror(meshPtr, contextManager, functionName)) + return true; + + PxU32 mirrorHandle = physXGpu->createConvexMeshMirror(convexMesh, contextManager); + if (!checkMirrorHandle(mirrorHandle, functionName)) + return false; + + addMeshMirror(meshPtr, mirrorHandle, contextManager); + return true; +} + +//-------------------------------------------------------------------------------------------------------------------// + +void NpPhysicsGpu::releaseConvexMeshMirror(const PxConvexMesh& convexMesh, PxCudaContextManager* contextManager) +{ + releaseMeshMirror((const void*)&convexMesh, "PxParticleGpu::releaseConvexMeshMirror()", contextManager); +} + +//-------------------------------------------------------------------------------------------------------------------// + +namespace +{ + PxSceneGpu* getSceneGpu(const PxScene& scene) + { +#if PX_SUPPORT_GPU_PHYSX + return ((NpScene*)&scene)->mScene.getScScene().getSceneGpu(true); +#else + return NULL; +#endif + } +} + +void NpPhysicsGpu::setExplicitCudaFlushCountHint(const class PxScene& scene, PxU32 cudaFlushCount) +{ + const char* functionName = "PxParticleGpu::setExplicitCudaFlushCountHint()"; + PxPhysXGpu* physXGpu = getPhysXGpu(true, functionName); + if (physXGpu) + { + PxSceneGpu* gpuScene = getSceneGpu(scene); + PX_ASSERT(gpuScene); + physXGpu->setExplicitCudaFlushCountHint((PxgSceneGpu&)(*gpuScene), cudaFlushCount); + } +} + +//-------------------------------------------------------------------------------------------------------------------// + +bool NpPhysicsGpu::setTriangleMeshCacheSizeHint(const class PxScene& scene, PxU32 size) +{ + const char* functionName = "PxParticleGpu::setTriangleMeshCacheSizeHint()"; + PxPhysXGpu* physXGpu = getPhysXGpu(true, functionName); + if (physXGpu) + { + PxSceneGpu* gpuScene = getSceneGpu(scene); + PX_ASSERT(gpuScene); + return physXGpu->setTriangleMeshCacheSizeHint((PxgSceneGpu&)(*gpuScene), size); + } + return false; +} + +//-------------------------------------------------------------------------------------------------------------------// + +PxTriangleMeshCacheStatistics NpPhysicsGpu::getTriangleMeshCacheStatistics(const class PxScene& scene) +{ + PxTriangleMeshCacheStatistics stats; + + const char* functionName = "PxParticleGpu::getTriangleMeshCacheStatistics()"; + PxPhysXGpu* physXGpu = getPhysXGpu(true, functionName); + if (physXGpu) + { + PxSceneGpu* gpuScene = getSceneGpu(scene); + PX_ASSERT(gpuScene); + stats = physXGpu->getTriangleMeshCacheStatistics((PxgSceneGpu&)(*gpuScene)); + } + return stats; +} + +//-------------------------------------------------------------------------------------------------------------------// + +NpPhysicsGpu::NpPhysicsGpu(NpPhysics& npPhysics) : mMeshMirrors(PX_DEBUG_EXP("NpPhysicsGpu:mMeshMirrors")), mNpPhysics(npPhysics) +{} + +//-------------------------------------------------------------------------------------------------------------------// + +NpPhysicsGpu::~NpPhysicsGpu() +{} + +//-------------------------------------------------------------------------------------------------------------------// + +#endif // PX_SUPPORT_GPU_PHYSX diff --git a/PhysX_3.4/Source/PhysX/src/gpu/NpPhysicsGpu.h b/PhysX_3.4/Source/PhysX/src/gpu/NpPhysicsGpu.h new file mode 100644 index 00000000..5f3ceb6e --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/gpu/NpPhysicsGpu.h @@ -0,0 +1,101 @@ +// 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_NP_PHYSICS_GPU +#define PX_PHYSICS_NP_PHYSICS_GPU + +#include "PxPhysXCommonConfig.h" +#include "PxPhysXConfig.h" + +#if PX_SUPPORT_GPU_PHYSX + +#include "CmPhysXCommon.h" +#include "PsArray.h" + +namespace physx +{ + class PxCudaContextManager; +} + +namespace physx +{ + + struct PxTriangleMeshCacheStatistics; + + class NpPhysicsGpu + { + public: + + bool createTriangleMeshMirror(const class PxTriangleMesh& triangleMesh, physx::PxCudaContextManager& contextManager); + void releaseTriangleMeshMirror(const class PxTriangleMesh& triangleMesh, physx::PxCudaContextManager* contextManager = NULL); + + bool createHeightFieldMirror(const class PxHeightField& heightField, physx::PxCudaContextManager& contextManager); + void releaseHeightFieldMirror(const class PxHeightField& heightField, physx::PxCudaContextManager* contextManager = NULL); + + bool createConvexMeshMirror(const class PxConvexMesh& convexMesh, physx::PxCudaContextManager& contextManager); + void releaseConvexMeshMirror(const class PxConvexMesh& convexMesh, physx::PxCudaContextManager* contextManager = NULL); + + void setExplicitCudaFlushCountHint(const class PxScene& scene, PxU32 cudaFlushCount); + bool setTriangleMeshCacheSizeHint(const class PxScene& scene, PxU32 size); + PxTriangleMeshCacheStatistics getTriangleMeshCacheStatistics(const class PxScene& scene); + + NpPhysicsGpu(class NpPhysics& npPhysics); + virtual ~NpPhysicsGpu(); + + private: + + NpPhysicsGpu& operator=(const NpPhysicsGpu&); + + struct MeshMirror + { + PxU32 mirrorHandle; + physx::PxCudaContextManager* ctx; + const void* meshAddress; + }; + + Ps::Array<MeshMirror>::Iterator findMeshMirror(const void* meshAddress); + Ps::Array<MeshMirror>::Iterator findMeshMirror(const void* meshAddress, physx::PxCudaContextManager& ctx); + class PxPhysXGpu* getPhysXGpu(bool createIfNeeded, const char* functionName, bool doWarn = true); + bool checkNewMirror(const void* meshPtr, physx::PxCudaContextManager& ctx, const char* functionName); + bool checkMirrorExists(Ps::Array<MeshMirror>::Iterator it, const char* functionName); + bool checkMirrorHandle(PxU32 mirrorHandle, const char* functionName); + void addMeshMirror(const void* meshPtr, PxU32 mirrorHandle, physx::PxCudaContextManager& ctx); + void removeMeshMirror(const void* meshPtr, PxU32 mirrorHandle); + void releaseMeshMirror(const void* meshPtr, const char* functionName, physx::PxCudaContextManager* ctx); + + Ps::Array<MeshMirror> mMeshMirrors; + class NpPhysics& mNpPhysics; + }; + +} + +#endif +#endif + diff --git a/PhysX_3.4/Source/PhysX/src/gpu/PxGpu.cpp b/PhysX_3.4/Source/PhysX/src/gpu/PxGpu.cpp new file mode 100644 index 00000000..7b8611b9 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/gpu/PxGpu.cpp @@ -0,0 +1,68 @@ +// 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. + +#include "PxPhysXConfig.h" + +#if PX_SUPPORT_GPU_PHYSX + +#include "PxGpu.h" + +namespace physx +{ + //forward declare stuff from PxPhysXGpuModuleLoader.cpp + void PxLoadPhysxGPUModule(const char* appGUID); + typedef physx::PxCudaContextManager* (PxCreateCudaContextManager_FUNC)(physx::PxFoundation& foundation, const physx::PxCudaContextManagerDesc& desc); + typedef int (PxGetSuggestedCudaDeviceOrdinal_FUNC)(physx::PxErrorCallback& errc); + extern PxCreateCudaContextManager_FUNC* g_PxCreateCudaContextManager_Func; + extern PxGetSuggestedCudaDeviceOrdinal_FUNC* g_PxGetSuggestedCudaDeviceOrdinal_Func; + +} // end physx namespace + +physx::PxCudaContextManager* PxCreateCudaContextManager(physx::PxFoundation& foundation, const physx::PxCudaContextManagerDesc& desc) +{ + if (!physx::g_PxCreateCudaContextManager_Func) + physx::PxLoadPhysxGPUModule(desc.appGUID); + + if (physx::g_PxCreateCudaContextManager_Func) + return physx::g_PxCreateCudaContextManager_Func(foundation, desc); + else + return NULL; +} + +int PxGetSuggestedCudaDeviceOrdinal(physx::PxErrorCallback& errc) +{ + if (!physx::g_PxGetSuggestedCudaDeviceOrdinal_Func) + physx::PxLoadPhysxGPUModule(NULL); + + if (physx::g_PxGetSuggestedCudaDeviceOrdinal_Func) + return physx::g_PxGetSuggestedCudaDeviceOrdinal_Func(errc); + else + return -1; +} + +#endif // PX_SUPPORT_GPU_PHYSX + diff --git a/PhysX_3.4/Source/PhysX/src/gpu/PxParticleDeviceExclusive.cpp b/PhysX_3.4/Source/PhysX/src/gpu/PxParticleDeviceExclusive.cpp new file mode 100644 index 00000000..69ae7456 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/gpu/PxParticleDeviceExclusive.cpp @@ -0,0 +1,130 @@ +// 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 +#if PX_SUPPORT_GPU_PHYSX + +#include "PxParticleDeviceExclusive.h" +#include "NpParticleSystem.h" +#include "NpParticleFluid.h" + +using namespace physx; + +//-------------------------------------------------------------------------------------------------------------------// + +void PxParticleDeviceExclusive::enable(PxParticleBase& particleBase) +{ + if (particleBase.is<PxParticleSystem>()) + static_cast<NpParticleSystem*>(particleBase.is<PxParticleSystem>())->enableDeviceExclusiveModeGpu(); + else if (particleBase.is<PxParticleFluid>()) + static_cast<NpParticleFluid*>(particleBase.is<PxParticleFluid>())->enableDeviceExclusiveModeGpu(); +} + +//-------------------------------------------------------------------------------------------------------------------// + +bool PxParticleDeviceExclusive::isEnabled(PxParticleBase& particleBase) +{ + if (particleBase.is<PxParticleSystem>()) + return static_cast<NpParticleSystem*>(particleBase.is<PxParticleSystem>())->isDeviceExclusiveModeEnabledGpu(); + else if (particleBase.is<PxParticleFluid>()) + return static_cast<NpParticleFluid*>(particleBase.is<PxParticleFluid>())->isDeviceExclusiveModeEnabledGpu(); + + return false; +} + +//-------------------------------------------------------------------------------------------------------------------// + +void PxParticleDeviceExclusive::getReadWriteCudaBuffers(PxParticleBase& particleBase, PxCudaReadWriteParticleBuffers& buffers) +{ + if (particleBase.is<PxParticleSystem>()) + static_cast<NpParticleSystem*>(particleBase.is<PxParticleSystem>())->getReadWriteCudaBuffersGpu(buffers); + else if (particleBase.is<PxParticleFluid>()) + static_cast<NpParticleFluid*>(particleBase.is<PxParticleFluid>())->getReadWriteCudaBuffersGpu(buffers); +} + +//-------------------------------------------------------------------------------------------------------------------// + +void PxParticleDeviceExclusive::setValidParticleRange(PxParticleBase& particleBase, PxU32 validParticleRange) +{ + if (particleBase.is<PxParticleSystem>()) + static_cast<NpParticleSystem*>(particleBase.is<PxParticleSystem>())->setValidParticleRangeGpu(validParticleRange); + else if (particleBase.is<PxParticleFluid>()) + static_cast<NpParticleFluid*>(particleBase.is<PxParticleFluid>())->setValidParticleRangeGpu(validParticleRange); +} + +//-------------------------------------------------------------------------------------------------------------------// + +void PxParticleDeviceExclusive::setFlags(PxParticleBase& particleBase, PxParticleDeviceExclusiveFlags flags) +{ + if (particleBase.is<PxParticleSystem>()) + static_cast<NpParticleSystem*>(particleBase.is<PxParticleSystem>())->setDeviceExclusiveModeFlagsGpu(reinterpret_cast<PxU32&>(flags)); + else if (particleBase.is<PxParticleFluid>()) + static_cast<NpParticleFluid*>(particleBase.is<PxParticleFluid>())->setDeviceExclusiveModeFlagsGpu(reinterpret_cast<PxU32&>(flags)); +} + +//-------------------------------------------------------------------------------------------------------------------// + +class physx::PxBaseTask* PxParticleDeviceExclusive::getLaunchTask(class PxParticleBase& particleBase) +{ + if (particleBase.is<PxParticleSystem>()) + return static_cast<NpParticleSystem*>(particleBase.is<PxParticleSystem>())->getLaunchTaskGpu(); + else if (particleBase.is<PxParticleFluid>()) + return static_cast<NpParticleFluid*>(particleBase.is<PxParticleFluid>())->getLaunchTaskGpu(); + + return NULL; +} + +//-------------------------------------------------------------------------------------------------------------------// + +void PxParticleDeviceExclusive::addLaunchTaskDependent(class PxParticleBase& particleBase, class physx::PxBaseTask& dependent) +{ + if (particleBase.is<PxParticleSystem>()) + static_cast<NpParticleSystem*>(particleBase.is<PxParticleSystem>())->addLaunchTaskDependentGpu(dependent); + else if (particleBase.is<PxParticleFluid>()) + static_cast<NpParticleFluid*>(particleBase.is<PxParticleFluid>())->addLaunchTaskDependentGpu(dependent); +} + +//-------------------------------------------------------------------------------------------------------------------// + +CUstream PxParticleDeviceExclusive::getCudaStream(class PxParticleBase& particleBase) +{ + if (particleBase.is<PxParticleSystem>()) + return (CUstream)static_cast<NpParticleSystem*>(particleBase.is<PxParticleSystem>())->getCudaStreamGpu(); + else if (particleBase.is<PxParticleFluid>()) + return (CUstream)static_cast<NpParticleFluid*>(particleBase.is<PxParticleFluid>())->getCudaStreamGpu(); + + return NULL; +} + +//-------------------------------------------------------------------------------------------------------------------// + +#endif // PX_SUPPORT_GPU_PHYSX +#endif // PX_USE_PARTICLE_SYSTEM_API diff --git a/PhysX_3.4/Source/PhysX/src/gpu/PxParticleGpu.cpp b/PhysX_3.4/Source/PhysX/src/gpu/PxParticleGpu.cpp new file mode 100644 index 00000000..a2793b95 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/gpu/PxParticleGpu.cpp @@ -0,0 +1,89 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + + +#include "PxParticleGpu.h" + +#if PX_SUPPORT_GPU_PHYSX + +#include "NpPhysics.h" +#include "NpPhysicsGpu.h" + +using namespace physx; + +//-------------------------------------------------------------------------------------------------------------------// + +bool PxParticleGpu::createTriangleMeshMirror(const class PxTriangleMesh& triangleMesh, PxCudaContextManager& contextManager) +{ + return NpPhysics::getInstance().getNpPhysicsGpu().createTriangleMeshMirror(triangleMesh, contextManager); +} + +void PxParticleGpu::releaseTriangleMeshMirror(const class PxTriangleMesh& triangleMesh, PxCudaContextManager* contextManager) +{ + NpPhysics::getInstance().getNpPhysicsGpu().releaseTriangleMeshMirror(triangleMesh, contextManager); +} + +bool PxParticleGpu::createHeightFieldMirror(const class PxHeightField& heightField, PxCudaContextManager& contextManager) +{ + return NpPhysics::getInstance().getNpPhysicsGpu().createHeightFieldMirror(heightField, contextManager); +} + +void PxParticleGpu::releaseHeightFieldMirror(const class PxHeightField& heightField, PxCudaContextManager* contextManager) +{ + NpPhysics::getInstance().getNpPhysicsGpu().releaseHeightFieldMirror(heightField, contextManager); +} + +bool PxParticleGpu::createConvexMeshMirror(const class PxConvexMesh& convexMesh, PxCudaContextManager& contextManager) +{ + return NpPhysics::getInstance().getNpPhysicsGpu().createConvexMeshMirror(convexMesh, contextManager); +} + +void PxParticleGpu::releaseConvexMeshMirror(const class PxConvexMesh& convexMesh, PxCudaContextManager* contextManager) +{ + NpPhysics::getInstance().getNpPhysicsGpu().releaseConvexMeshMirror(convexMesh, contextManager); +} + +void PxParticleGpu::setExplicitCudaFlushCountHint(const class PxScene& scene, PxU32 cudaFlushCount) +{ + NpPhysics::getInstance().getNpPhysicsGpu().setExplicitCudaFlushCountHint(scene, cudaFlushCount); +} + +bool PxParticleGpu::setTriangleMeshCacheSizeHint(const class PxScene& scene, PxU32 size) +{ + return NpPhysics::getInstance().getNpPhysicsGpu().setTriangleMeshCacheSizeHint(scene, size); +} + +PxTriangleMeshCacheStatistics PxParticleGpu::getTriangleMeshCacheStatistics(const class PxScene& scene) +{ + return NpPhysics::getInstance().getNpPhysicsGpu().getTriangleMeshCacheStatistics(scene); +} + +//-------------------------------------------------------------------------------------------------------------------// + +#endif // PX_SUPPORT_GPU_PHYSX diff --git a/PhysX_3.4/Source/PhysX/src/gpu/PxPhysXGpuModuleLoader.cpp b/PhysX_3.4/Source/PhysX/src/gpu/PxPhysXGpuModuleLoader.cpp new file mode 100644 index 00000000..1d5f7388 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/gpu/PxPhysXGpuModuleLoader.cpp @@ -0,0 +1,141 @@ +// 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. + +#include "PxPhysXConfig.h" + +#if PX_SUPPORT_GPU_PHYSX + +#include "foundation/Px.h" +#include "PsFoundation.h" +#include "PxPhysics.h" + +#include "cudamanager/PxCudaContextManager.h" + +#define STRINGIFY(x) #x +#define GETSTRING(x) STRINGIFY(x) + +#if PX_X86 +#define PLATFORM_SUB_STR "x86" +#elif PX_X64 +#define PLATFORM_SUB_STR "x64" +#endif + +#if defined(PX_PHYSX_DLL_NAME_POSTFIX) +#define CONFIG_SUB_STR GETSTRING(PX_PHYSX_DLL_NAME_POSTFIX) +#else +#define CONFIG_SUB_STR +#endif + +#if PX_WINDOWS + +#include "windows/PsWindowsInclude.h" +#include "windows/CmWindowsModuleUpdateLoader.h" +static const char* gPhysXGpuLibraryName = "PhysX3Gpu" CONFIG_SUB_STR "_" PLATFORM_SUB_STR ".dll"; + +#elif PX_LINUX + +#include <dlfcn.h> +static const char* gPhysXGpuLibraryName = "./libPhysX3Gpu" CONFIG_SUB_STR "_" PLATFORM_SUB_STR ".so"; + +#endif // PX_LINUX + +#undef GETSTRING +#undef STRINGIFY + +namespace physx +{ +#if PX_VC +#pragma warning(disable: 4191) //'operator/operation' : unsafe conversion from 'type of expression' to 'type required' +#endif + + class PxFoundation; + class PxPhysXGpu; + + typedef physx::PxPhysXGpu* (PxCreatePhysXGpu_FUNC)(); + typedef physx::PxCudaContextManager* (PxCreateCudaContextManager_FUNC)(physx::PxFoundation& foundation, const physx::PxCudaContextManagerDesc& desc); + typedef int (PxGetSuggestedCudaDeviceOrdinal_FUNC)(physx::PxErrorCallback& errc); + + PxCreatePhysXGpu_FUNC* g_PxCreatePhysXGpu_Func = NULL; + PxCreateCudaContextManager_FUNC* g_PxCreateCudaContextManager_Func = NULL; + PxGetSuggestedCudaDeviceOrdinal_FUNC* g_PxGetSuggestedCudaDeviceOrdinal_Func = NULL; + +#if PX_WINDOWS + +#define DEFAULT_PHYSX_GPU_GUID "D79FA4BF-177C-4841-8091-4375D311D6A3" + + void PxLoadPhysxGPUModule(const char* appGUID) + { + static HMODULE s_library; + + if (s_library == NULL) + s_library = GetModuleHandle(gPhysXGpuLibraryName); + + if (s_library == NULL) + { + Cm::CmModuleUpdateLoader moduleLoader(UPDATE_LOADER_DLL_NAME); + s_library = moduleLoader.LoadModule(gPhysXGpuLibraryName, appGUID == NULL ? DEFAULT_PHYSX_GPU_GUID : appGUID); + } + + if (s_library) + { + g_PxCreatePhysXGpu_Func = (PxCreatePhysXGpu_FUNC*)GetProcAddress(s_library, "PxCreatePhysXGpu"); + g_PxCreateCudaContextManager_Func = (PxCreateCudaContextManager_FUNC*)GetProcAddress(s_library, "PxCreateCudaContextManager"); + g_PxGetSuggestedCudaDeviceOrdinal_Func = (PxGetSuggestedCudaDeviceOrdinal_FUNC*)GetProcAddress(s_library, "PxGetSuggestedCudaDeviceOrdinal"); + } + } + +#elif PX_LINUX + + void PxLoadPhysxGPUModule(const char*) + { + static void* s_library; + + if (s_library == NULL) + { + // load libcuda.so here since gcc configured with --as-needed won't link to it + // if there is no call from the binary to it. + void* hLibCuda = dlopen("libcuda.so", RTLD_NOW | RTLD_GLOBAL); + if (hLibCuda) + { + s_library = dlopen(gPhysXGpuLibraryName, RTLD_NOW); + } + } + + // no UpdateLoader + if (s_library) + { + *reinterpret_cast<void**>(&g_PxCreatePhysXGpu_Func) = dlsym(s_library, "PxCreatePhysXGpu"); + *reinterpret_cast<void**>(&g_PxCreateCudaContextManager_Func) = dlsym(s_library, "PxCreateCudaContextManager"); + *reinterpret_cast<void**>(&g_PxGetSuggestedCudaDeviceOrdinal_Func) = dlsym(s_library, "PxGetSuggestedCudaDeviceOrdinal"); + } + } + +#endif // PX_LINUX + +} // end physx namespace + +#endif // PX_SUPPORT_GPU_PHYSX
\ No newline at end of file diff --git a/PhysX_3.4/Source/PhysX/src/gpu/PxPhysXIndicatorDeviceExclusive.cpp b/PhysX_3.4/Source/PhysX/src/gpu/PxPhysXIndicatorDeviceExclusive.cpp new file mode 100644 index 00000000..4c32a1dc --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/gpu/PxPhysXIndicatorDeviceExclusive.cpp @@ -0,0 +1,50 @@ +// 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" +#include "PxPhysXIndicatorDeviceExclusive.h" +#include "NpPhysics.h" + +using namespace physx; + +//-------------------------------------------------------------------------------------------------------------------// + +void PxPhysXIndicatorDeviceExclusive::registerPhysXIndicatorGpuClient(class PxPhysics& physics) +{ + static_cast<NpPhysics*>(&physics)->registerPhysXIndicatorGpuClient(); +} + +//-------------------------------------------------------------------------------------------------------------------// + +void PxPhysXIndicatorDeviceExclusive::unregisterPhysXIndicatorGpuClient(class PxPhysics& physics) +{ + static_cast<NpPhysics*>(&physics)->unregisterPhysXIndicatorGpuClient(); +} + +//-------------------------------------------------------------------------------------------------------------------// diff --git a/PhysX_3.4/Source/PhysX/src/particles/NpParticleBaseTemplate.h b/PhysX_3.4/Source/PhysX/src/particles/NpParticleBaseTemplate.h new file mode 100644 index 00000000..001d3cbd --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/particles/NpParticleBaseTemplate.h @@ -0,0 +1,925 @@ +// 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_NP_PARTICLESYSTEM_TEMPLATE +#define PX_PHYSICS_NP_PARTICLESYSTEM_TEMPLATE + +#include "PxPhysXConfig.h" + +#if PX_USE_PARTICLE_SYSTEM_API + +#include "NpActorTemplate.h" +#include "PxParticleSystem.h" +#include "ScbParticleSystem.h" +#include "NpWriteCheck.h" +#include "NpReadCheck.h" +#include "PtParticleData.h" +#include "NpScene.h" + +#if PX_SUPPORT_GPU_PHYSX +#include "PxParticleDeviceExclusive.h" +#endif + +namespace physx +{ + +template<class APIClass, class LeafClass> +class NpParticleBaseTemplate : public NpActorTemplate<APIClass> +{ +public: +// PX_SERIALIZATION + NpParticleBaseTemplate(PxBaseFlags baseFlags) : NpActorTemplate<APIClass>(baseFlags), mParticleSystem(PxEmpty) {} +//~PX_SERIALIZATION + NpParticleBaseTemplate<APIClass, LeafClass>(PxType, PxBaseFlags, const PxActorType::Enum&, PxU32, bool); + virtual ~NpParticleBaseTemplate(); + + //--------------------------------------------------------------------------------- + // PxParticleSystemActor implementation + //--------------------------------------------------------------------------------- + virtual void release(); + + virtual PxActorType::Enum getType() const { return PxActorType::ePARTICLE_SYSTEM; } + + virtual bool createParticles(const PxParticleCreationData& creationData); + virtual void releaseParticles(PxU32 numParticles, const PxStrideIterator<const PxU32>& indexBuffer); + virtual void releaseParticles(); + virtual void setPositions(PxU32 numParticles, const PxStrideIterator<const PxU32>& indexBuffer, + const PxStrideIterator<const PxVec3>& positionBuffer); + virtual void setVelocities(PxU32 numParticles, const PxStrideIterator<const PxU32>& indexBuffer, + const PxStrideIterator<const PxVec3>& velocityBuffer); + virtual void setRestOffsets(PxU32 numParticles, const PxStrideIterator<const PxU32>& indexBuffer, + const PxStrideIterator<const PxF32>& restOffsetBuffer); + virtual void addForces(PxU32 numParticles, const PxStrideIterator<const PxU32>& indexBuffer, + const PxStrideIterator<const PxVec3>& forceBuffer, PxForceMode::Enum forceMode); + virtual PxParticleReadData* lockParticleReadData(PxDataAccessFlags flags); + virtual PxParticleReadData* lockParticleReadData(); + + virtual PxReal getDamping() const; + virtual void setDamping(PxReal); + virtual PxVec3 getExternalAcceleration() const; + virtual void setExternalAcceleration(const PxVec3&); + + virtual PxReal getParticleMass() const; + virtual void setParticleMass(PxReal); + virtual PxReal getRestitution() const; + virtual void setRestitution(PxReal); + virtual PxReal getDynamicFriction() const; + virtual void setDynamicFriction(PxReal); + virtual PxReal getStaticFriction() const; + virtual void setStaticFriction(PxReal); + + virtual void setSimulationFilterData(const PxFilterData& data); + virtual PxFilterData getSimulationFilterData() const; + virtual void resetFiltering(); + + virtual void setParticleBaseFlag(PxParticleBaseFlag::Enum flag, bool value); + virtual PxParticleBaseFlags getParticleBaseFlags() const; + + virtual PxParticleReadDataFlags getParticleReadDataFlags() const; + virtual void setParticleReadDataFlag(PxParticleReadDataFlag::Enum, bool); + + virtual PxU32 getMaxParticles() const; + + virtual PxReal getMaxMotionDistance() const; + virtual void setMaxMotionDistance(PxReal); + virtual PxReal getRestOffset() const; + virtual void setRestOffset(PxReal); + virtual PxReal getContactOffset() const; + virtual void setContactOffset(PxReal); + virtual PxReal getGridSize() const; + virtual void setGridSize(PxReal); + + virtual void getProjectionPlane(PxVec3& normal, PxReal& d) const; + virtual void setProjectionPlane(const PxVec3& normal, PxReal d); + + virtual PxBounds3 getWorldBounds(float inflation=1.01f) const; + + typedef NpActorTemplate<APIClass> ActorTemplateClass; + + //--------------------------------------------------------------------------------- + // Miscellaneous + //--------------------------------------------------------------------------------- + PX_INLINE Scb::Actor& getScbActor() const { return const_cast<Scb::ParticleSystem&>(mParticleSystem); } + + PX_INLINE const Scb::ParticleSystem& getScbParticleSystem() const { return mParticleSystem; } + PX_INLINE Scb::ParticleSystem& getScbParticleSystem() { return mParticleSystem; } + PX_INLINE NpScene* getNpScene() const { return NpActor::getAPIScene(*this); } + +#if PX_SUPPORT_GPU_PHYSX + // Helper for reporting error conditions. + class PxParticleDeviceExclusiveAccess* getDeviceExclusiveAccessGpu(const char* callerName) const; + + void enableDeviceExclusiveModeGpu(); + bool isDeviceExclusiveModeEnabledGpu() const; + void getReadWriteCudaBuffersGpu(struct PxCudaReadWriteParticleBuffers& buffers) const; + void setValidParticleRangeGpu(PxU32 validParticleRange); + void setDeviceExclusiveModeFlagsGpu(PxU32 flags); + PxBaseTask* getLaunchTaskGpu() const; + void addLaunchTaskDependentGpu(class physx::PxBaseTask& dependent); + size_t getCudaStreamGpu() const; +#endif + +private: + bool checkAllocatedIndices(PxU32 numIndices, const PxStrideIterator<const PxU32>& indices); + bool checkFreeIndices(PxU32 numIndices, const PxStrideIterator<const PxU32>& indices); + +//private: +public: // PT: sorry, needs to be accessible to serialization macro + Scb::ParticleSystem mParticleSystem; +}; + + +template<class APIClass, class LeafClass> +NpParticleBaseTemplate<APIClass, LeafClass>::NpParticleBaseTemplate(PxType concreteType, PxBaseFlags baseFlags, const PxActorType::Enum& actorType, PxU32 maxParticles, bool perParticleRestOffset) +: ActorTemplateClass(concreteType, baseFlags, NULL, NULL) +, mParticleSystem(actorType, maxParticles, perParticleRestOffset) +{ + // don't ref Scb actor here, it hasn't been assigned yet +} + + +template<class APIClass, class LeafClass> +NpParticleBaseTemplate<APIClass, LeafClass>::~NpParticleBaseTemplate() +{ +} + + +template<class APIClass, class LeafClass> +void NpParticleBaseTemplate<APIClass, LeafClass>::release() +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + NpPhysics::getInstance().notifyDeletionListenersUserRelease(this, this->userData); + +// PX_AGGREGATE + ActorTemplateClass::release(); // PT: added for PxAggregate +//~PX_AGGREGATE + + NpScene* npScene = NpActor::getAPIScene(*this); + if (npScene) + { + npScene->removeFromParticleBaseList(*this); + npScene->getScene().removeParticleSystem(static_cast<LeafClass&>(*this).getScbParticleSystem(), true); + } + mParticleSystem.destroy(); +} + +#if PX_CHECKED +namespace +{ + bool checkUniqueIndices(PxU32 numIndices, const PxStrideIterator<const PxU32>& indices) + { + Cm::BitMap bitmap; + PxU32 i = 0; + for (; i != numIndices; ++i) + { + PxU32 index = indices[i]; + if (bitmap.boundedTest(index)) + break; + bitmap.growAndSet(index); + } + + if (i != numIndices) + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, + "PxParticleBase::releaseParticles(): indexBuffer contains duplicate particle index %d.", indices[i]); + return false; + } + return true; + } + + bool checkVectors(PxU32 numVectors, const PxStrideIterator<const PxVec3>& vectors) + { + for (PxU32 i = 0; i < numVectors; ++i) + { + if(!vectors[i].isFinite()) + return false; + } + return true; + } + + bool checkRestOffsets(PxU32 numParticles, const PxStrideIterator<const PxF32>& restOffsetBuffer, PxF32 restOffset) + { + for (PxU32 i = 0; i < numParticles; ++i) + { + if (restOffsetBuffer[i] < 0.0f || restOffsetBuffer[i] > restOffset) + return false; + } + return true; + } + + bool checkRestOffset(Pt::ParticleData& standaloneData, PxF32 restOffset) + { + const PxF32* restOffsetBuffer = standaloneData.getRestOffsetBuffer(); + PxU32 numParticles = standaloneData.getMaxParticles(); + for (PxU32 i = 0; i < numParticles; ++i) + { + if (restOffsetBuffer[i] > restOffset) + return false; + } + return true; + } +} +#endif // PX_CHECKED + +//----------------------------------------------------------------------------// + +template<class APIClass, class LeafClass> +bool NpParticleBaseTemplate<APIClass, LeafClass>::checkAllocatedIndices(PxU32 numIndices, const PxStrideIterator<const PxU32>& indices) +{ + const Cm::BitMap& map = mParticleSystem.getParticleMap(); + PxU32 maxParticles = getMaxParticles(); + + for (PxU32 i = 0; i < numIndices; ++i) + { + PxU32 index = indices[i]; + + if (index >= maxParticles) + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, + "Operation on particle index %d not in valid range [0, %d]", index, getMaxParticles() - 1); + return false; + } + + if (!map.boundedTest(index)) + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, + "Operation on invalid particle with index %d", index); + return false; + } + } + return true; +} + +//----------------------------------------------------------------------------// + +template<class APIClass, class LeafClass> +bool NpParticleBaseTemplate<APIClass, LeafClass>::checkFreeIndices(PxU32 numIndices, const PxStrideIterator<const PxU32>& indices) +{ + const Cm::BitMap& map = mParticleSystem.getParticleMap(); + PxU32 maxParticles = getMaxParticles(); + + for (PxU32 i = 0; i < numIndices; ++i) + { + PxU32 index = indices[i]; + + if (index >= maxParticles) + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, + "Provided particle index %d is not in valid range [0, %d]", index, getMaxParticles() - 1); + return false; + } + + if (map.boundedTest(index)) + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, + "Provided particle index %d is already in use", index); + return false; + } + } + return true; +} + +//----------------------------------------------------------------------------// + +template<class APIClass, class LeafClass> +bool NpParticleBaseTemplate<APIClass, LeafClass>::createParticles(const PxParticleCreationData& creationData) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PX_CHECK_AND_RETURN_NULL(creationData.isValid(), "PxParticleCreationData submitted with PxParticleBase::createParticles() invalid."); + if (creationData.numParticles == 0) + return true; + + bool supportsPerParticleRestOffset = getScbParticleSystem().getFlags() & PxParticleBaseFlag::ePER_PARTICLE_REST_OFFSET; + bool perParticleRestOffset = creationData.restOffsetBuffer.ptr() != NULL; + + PX_UNUSED(supportsPerParticleRestOffset); + PX_UNUSED(perParticleRestOffset); + + PX_CHECK_AND_RETURN_NULL(!perParticleRestOffset || supportsPerParticleRestOffset, "PxParticleCreationData.restOffsetBuffer set but PxParticleBaseFlag::ePER_PARTICLE_REST_OFFSET not set.") + PX_CHECK_AND_RETURN_NULL(!supportsPerParticleRestOffset || perParticleRestOffset, "PxParticleBaseFlag::ePER_PARTICLE_REST_OFFSET set, but PxParticleCreationData.restOffsetBuffer not set.") + +#if PX_CHECKED + PX_CHECK_AND_RETURN_NULL(checkFreeIndices(creationData.numParticles, creationData.indexBuffer), "PxParticleBase::createParticles: failed"); + PX_CHECK_AND_RETURN_NULL(checkUniqueIndices(creationData.numParticles, creationData.indexBuffer), "PxParticleBase::createParticles: failed"); + + if (perParticleRestOffset) + PX_CHECK_AND_RETURN_NULL(checkRestOffsets(creationData.numParticles, creationData.restOffsetBuffer, getScbParticleSystem().getRestOffset()), + "PxParticleCreationData.restOffsetBuffer: offsets must be in range [0.0f, restOffset]."); + + PX_CHECK_AND_RETURN_NULL(checkVectors(creationData.numParticles, creationData.positionBuffer), "PxParticleBase::createParticles: position vectors shoule be finite"); + + bool perParticleVelocity = creationData.velocityBuffer.ptr() != NULL; + if(perParticleVelocity) + { + PX_CHECK_AND_RETURN_NULL(checkVectors(creationData.numParticles, creationData.velocityBuffer), "PxParticleBase::createParticles: velocity vectors shoule be finite"); + } +#endif + + return getScbParticleSystem().createParticles(creationData); +} + + +template<class APIClass, class LeafClass> +void NpParticleBaseTemplate<APIClass, LeafClass>::releaseParticles(PxU32 numParticles, const PxStrideIterator<const PxU32>& indices) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + if (numParticles == 0) + return; + +#if PX_CHECKED + PX_CHECK_AND_RETURN(indices.ptr() && indices.stride() != 0, "PxParticleBase::releaseParticles: invalid index buffer"); + PX_CHECK_AND_RETURN(checkAllocatedIndices(numParticles, indices), "PxParticleBase::releaseParticles: failed"); + PX_CHECK_AND_RETURN(checkUniqueIndices(numParticles, indices), "PxParticleBase::releaseParticles: failed"); +#endif + + getScbParticleSystem().releaseParticles(numParticles, indices); +} + + +template<class APIClass, class LeafClass> +void NpParticleBaseTemplate<APIClass, LeafClass>::releaseParticles() +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + getScbParticleSystem().releaseParticles(); +} + + +template<class APIClass, class LeafClass> +void NpParticleBaseTemplate<APIClass, LeafClass>::setPositions(PxU32 numParticles, const PxStrideIterator<const PxU32>& indexBuffer, + const PxStrideIterator<const PxVec3>& positionBuffer) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + if (numParticles == 0) + return; + + PX_CHECK_AND_RETURN(indexBuffer.ptr() && indexBuffer.stride() != 0, "PxParticleBase::setPositions: invalid index buffer"); + PX_CHECK_AND_RETURN(positionBuffer.ptr(), "PxParticleBase::setPositions: invalid position buffer"); + +#if PX_CHECKED + PX_CHECK_AND_RETURN(checkAllocatedIndices(numParticles, indexBuffer), "PxParticleBase::setPositions: failed"); + PX_CHECK_AND_RETURN(checkVectors(numParticles, positionBuffer), "PxParticleBase::setPositions: position vectors shoule be finite"); +#endif + + getScbParticleSystem().setPositions(numParticles, indexBuffer, positionBuffer); +} + + +template<class APIClass, class LeafClass> +void NpParticleBaseTemplate<APIClass, LeafClass>::setVelocities(PxU32 numParticles, const PxStrideIterator<const PxU32>& indexBuffer, + const PxStrideIterator<const PxVec3>& velocityBuffer) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + if (numParticles == 0) + return; + + PX_CHECK_AND_RETURN(indexBuffer.ptr() && indexBuffer.stride() != 0, "PxParticleBase::setVelocities: invalid index buffer"); + PX_CHECK_AND_RETURN(velocityBuffer.ptr(), "PxParticleBase::setVelocities: invalid velocity buffer"); + +#if PX_CHECKED + PX_CHECK_AND_RETURN(checkAllocatedIndices(numParticles, indexBuffer), "PxParticleBase::setVelocities: failed"); + PX_CHECK_AND_RETURN(checkVectors(numParticles, velocityBuffer), "PxParticleBase::setVelocities: velocity vectors shoule be finite"); +#endif + getScbParticleSystem().setVelocities(numParticles, indexBuffer, velocityBuffer); +} + + +template<class APIClass, class LeafClass> +void NpParticleBaseTemplate<APIClass, LeafClass>::setRestOffsets(PxU32 numParticles, const PxStrideIterator<const PxU32>& indexBuffer, + const PxStrideIterator<const PxF32>& restOffsetBuffer) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + if (numParticles == 0) + return; + + PX_CHECK_AND_RETURN(indexBuffer.ptr() && indexBuffer.stride() != 0, "PxParticleBase::setRestOffsets: invalid index buffer"); + PX_CHECK_AND_RETURN(restOffsetBuffer.ptr(), "PxParticleBase::restOffsets: invalid restOffset buffer"); + + PX_CHECK_AND_RETURN(getScbParticleSystem().getFlags() & PxParticleBaseFlag::ePER_PARTICLE_REST_OFFSET, "PxParticleBase::setRestOffsets: PxParticleBaseFlag::ePER_PARTICLE_REST_OFFSET not set"); + +#if PX_CHECKED + PX_CHECK_AND_RETURN(checkAllocatedIndices(numParticles, indexBuffer), "PxParticleBase::setRestOffsets: failed"); + PX_CHECK_AND_RETURN(checkRestOffsets(numParticles, restOffsetBuffer, getScbParticleSystem().getRestOffset()), + "PxParticleBase::restOffsets: offsets must be in range [0.0f, restOffset]."); +#endif + getScbParticleSystem().setRestOffsets(numParticles, indexBuffer, restOffsetBuffer); +} + + +template<class APIClass, class LeafClass> +void NpParticleBaseTemplate<APIClass, LeafClass>::addForces(PxU32 numParticles, const PxStrideIterator<const PxU32>& indexBuffer, + const PxStrideIterator<const PxVec3>& forceBuffer, PxForceMode::Enum forceMode) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + if (!getNpScene()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, + "Attempt to add forces on particle system which isn't assigned to any scene."); + return; + } + + if (numParticles == 0) + return; + + PX_CHECK_AND_RETURN(indexBuffer.ptr() && indexBuffer.stride() != 0, "PxParticleBase::addForces: invalid index buffer"); + PX_CHECK_AND_RETURN(forceBuffer.ptr(), "PxParticleBase::addForces: invalid force buffer"); + +#if PX_CHECKED + PX_CHECK_AND_RETURN(checkAllocatedIndices(numParticles, indexBuffer), "PxParticleBase::addForces: failed"); + PX_CHECK_AND_RETURN(checkVectors(numParticles, forceBuffer), "PxParticleBase::addForces: force vectors shoule be finite"); +#endif + + getScbParticleSystem().addForces(numParticles, indexBuffer, forceBuffer, forceMode); +} + +template<class APIClass, class LeafClass> +PxParticleReadData* NpParticleBaseTemplate<APIClass, LeafClass>::lockParticleReadData(PxDataAccessFlags flags) +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return getScbParticleSystem().lockParticleReadData(flags); +} + +template<class APIClass, class LeafClass> +PxParticleReadData* NpParticleBaseTemplate<APIClass, LeafClass>::lockParticleReadData() +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return getScbParticleSystem().lockParticleReadData(PxDataAccessFlag::eREADABLE); +} + + +template<class APIClass, class LeafClass> +PxReal NpParticleBaseTemplate<APIClass, LeafClass>::getDamping() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return getScbParticleSystem().getDamping(); +} + + +template<class APIClass, class LeafClass> +void NpParticleBaseTemplate<APIClass, LeafClass>::setDamping(PxReal d) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(d >= 0.0f,"Damping is not allowed to be negative, PxParticleBase::setDamping() ignored."); + getScbParticleSystem().setDamping(d); +} + + +template<class APIClass, class LeafClass> +PxVec3 NpParticleBaseTemplate<APIClass, LeafClass>::getExternalAcceleration() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return getScbParticleSystem().getExternalAcceleration(); +} + + +template<class APIClass, class LeafClass> +void NpParticleBaseTemplate<APIClass, LeafClass>::setExternalAcceleration(const PxVec3& a) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + getScbParticleSystem().setExternalAcceleration(a); +} + + +template<class APIClass, class LeafClass> +void NpParticleBaseTemplate<APIClass, LeafClass>::getProjectionPlane(PxVec3& normal, PxReal& d) const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + PxPlane p = getScbParticleSystem().getProjectionPlane(); + normal = p.n; + d = p.d; +} + + +template<class APIClass, class LeafClass> +void NpParticleBaseTemplate<APIClass, LeafClass>::setProjectionPlane(const PxVec3& normal, PxReal d) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(!normal.isZero(),"Plane normal needs to be non zero, PxParticleBase::setProjectionPlane() ignored."); + + PxPlane p(normal, d); + getScbParticleSystem().setProjectionPlane(p); +} + + +template<class APIClass, class LeafClass> +PxReal NpParticleBaseTemplate<APIClass, LeafClass>::getParticleMass() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return getScbParticleSystem().getParticleMass(); +} + + +template<class APIClass, class LeafClass> +void NpParticleBaseTemplate<APIClass, LeafClass>::setParticleMass(PxReal m) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(m > 0.0f, "ParticleMass needs to be positive, PxParticleBase::setParticleMass() ignored."); + getScbParticleSystem().setParticleMass(m); +} + + +template<class APIClass, class LeafClass> +PxReal NpParticleBaseTemplate<APIClass, LeafClass>::getRestitution() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return getScbParticleSystem().getRestitution(); +} + + +template<class APIClass, class LeafClass> +void NpParticleBaseTemplate<APIClass, LeafClass>::setRestitution(PxReal r) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(r >= 0.0f && r <= 1.0f,"Restitution needs to be in [0,1], PxParticleBase::setRestitution() ignored."); + getScbParticleSystem().setRestitution(r); +} + + +template<class APIClass, class LeafClass> +PxReal NpParticleBaseTemplate<APIClass, LeafClass>::getDynamicFriction() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return getScbParticleSystem().getDynamicFriction(); +} + + +template<class APIClass, class LeafClass> +void NpParticleBaseTemplate<APIClass, LeafClass>::setDynamicFriction(PxReal a) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(a >= 0.0f && a <= 1.0f,"Dynamic Friction needs to be in [0,1], PxParticleBase::setDynamicFriction() ignored."); + getScbParticleSystem().setDynamicFriction(a); +} + + +template<class APIClass, class LeafClass> +PxReal NpParticleBaseTemplate<APIClass, LeafClass>::getStaticFriction() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return getScbParticleSystem().getStaticFriction(); +} + + +template<class APIClass, class LeafClass> +void NpParticleBaseTemplate<APIClass, LeafClass>::setStaticFriction(PxReal a) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(a >= 0.0f,"Static Friction needs to be positive, PxParticleBase::setStaticFriction() ignored."); + getScbParticleSystem().setStaticFriction(a); +} + + +template<class APIClass, class LeafClass> +void NpParticleBaseTemplate<APIClass, LeafClass>::setSimulationFilterData(const PxFilterData& data) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + getScbParticleSystem().setSimulationFilterData(data); +} + + +template<class APIClass, class LeafClass> +PxFilterData NpParticleBaseTemplate<APIClass, LeafClass>::getSimulationFilterData() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return getScbParticleSystem().getSimulationFilterData(); +} + + +template<class APIClass, class LeafClass> +void NpParticleBaseTemplate<APIClass, LeafClass>::resetFiltering() +{ + physx::shdfnd::getFoundation().error(physx::PxErrorCode::eDEBUG_INFO, __FILE__, __LINE__, "PxParticleBase::resetFiltering: This method has been deprecated!"); + + NpScene* scene = NpActor::getOwnerScene(*this); + if (scene) + scene->resetFiltering(*this); +} + + +template<class APIClass, class LeafClass> +void NpParticleBaseTemplate<APIClass, LeafClass>::setParticleBaseFlag(PxParticleBaseFlag::Enum flag, bool value) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + // flags that are generally immutable + if (flag == PxParticleBaseFlag::ePER_PARTICLE_REST_OFFSET) + { + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxParticleBaseFlag::ePER_PARTICLE_REST_OFFSET flag is not modifiable. Operation ignored."); + return; + } + + PxParticleBaseFlags flags = getScbParticleSystem().getFlags(); + if(value) + flags |= flag; + else + flags &= ~flag; + + getScbParticleSystem().setFlags(flags); + + if (getNpScene()) + getNpScene()->updatePhysXIndicator(); +} + + +template<class APIClass, class LeafClass> +PxParticleBaseFlags NpParticleBaseTemplate<APIClass, LeafClass>::getParticleBaseFlags() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return getScbParticleSystem().getFlags(); +} + +template<class APIClass, class LeafClass> +PxParticleReadDataFlags NpParticleBaseTemplate<APIClass, LeafClass>::getParticleReadDataFlags() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return getScbParticleSystem().getParticleReadDataFlags(); +} + +template<class APIClass, class LeafClass> +void NpParticleBaseTemplate<APIClass, LeafClass>::setParticleReadDataFlag(PxParticleReadDataFlag::Enum flag, bool value) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(!getScbParticleSystem().getScParticleSystem().getSim(),"PxParticleReadDataFlag immutable when the particle system is part of a scene."); + PxParticleReadDataFlags flags = getScbParticleSystem().getParticleReadDataFlags(); + + PX_CHECK_AND_RETURN(!(flag == PxParticleReadDataFlag::eREST_OFFSET_BUFFER && value) + || (getScbParticleSystem().getFlags() & PxParticleBaseFlag::ePER_PARTICLE_REST_OFFSET), + "PxParticleReadDataFlag::eREST_OFFSET_BUFFER not supported without specifying per particle rest offsets on calling " + "PxPhysics::createParticleSystem or PxPhysics::createParticleFluid."); + + if(value) + flags |= flag; + else + flags &= ~flag; + + getScbParticleSystem().setParticleReadDataFlags(flags); +} + +template<class APIClass, class LeafClass> +PxU32 NpParticleBaseTemplate<APIClass, LeafClass>::getMaxParticles() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return getScbParticleSystem().getMaxParticles(); +} + + +template<class APIClass, class LeafClass> +PxReal NpParticleBaseTemplate<APIClass, LeafClass>::getMaxMotionDistance() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return getScbParticleSystem().getMaxMotionDistance(); +} + +template<class APIClass, class LeafClass> +void NpParticleBaseTemplate<APIClass, LeafClass>::setMaxMotionDistance(PxReal d) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(d >= 0.0f,"MaxMotionDistance needs to be positive, PxParticleBase::setMaxMotionDistance() ignored."); + PX_CHECK_AND_RETURN(!getScbParticleSystem().getScParticleSystem().getSim(),"MaxMotionDistance immutable when the particle system is part of a scene."); + getScbParticleSystem().setMaxMotionDistance(d); +} + +template<class APIClass, class LeafClass> +PxReal NpParticleBaseTemplate<APIClass, LeafClass>::getRestOffset() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return getScbParticleSystem().getRestOffset(); +} + +template<class APIClass, class LeafClass> +void NpParticleBaseTemplate<APIClass, LeafClass>::setRestOffset(PxReal r) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(r >= 0.0f,"RestOffset needs to be positive, PxParticleBase::setRestOffset() ignored."); + PX_CHECK_AND_RETURN(!getScbParticleSystem().getScParticleSystem().getSim(),"RestOffset immutable when the particle system is part of a scene."); +#if PX_CHECKED + if(getParticleBaseFlags() & PxParticleBaseFlag::ePER_PARTICLE_REST_OFFSET) + { + Pt::ParticleData* standaloneData = getScbParticleSystem().getScParticleSystem().obtainStandaloneData(); + PX_ASSERT(standaloneData); + bool pass = checkRestOffset(*standaloneData, r); + getScbParticleSystem().getScParticleSystem().returnStandaloneData(standaloneData); + PX_CHECK_AND_RETURN(pass, "PxParticleBase::restOffset: offset must be larger than each perParticle restOffset."); + } +#endif + getScbParticleSystem().setRestOffset(r); +} + +template<class APIClass, class LeafClass> +PxReal NpParticleBaseTemplate<APIClass, LeafClass>::getContactOffset() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return getScbParticleSystem().getContactOffset(); +} + +template<class APIClass, class LeafClass> +void NpParticleBaseTemplate<APIClass, LeafClass>::setContactOffset(PxReal c) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(c >= 0.0f,"ContactOffset needs to be positive, PxParticleBase::setContactOffset() ignored."); + PX_CHECK_AND_RETURN(!getScbParticleSystem().getScParticleSystem().getSim(),"ContactOffset immutable when the particle system is part of a scene."); + getScbParticleSystem().setContactOffset(c); +} + +template<class APIClass, class LeafClass> +PxReal NpParticleBaseTemplate<APIClass, LeafClass>::getGridSize() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + return getScbParticleSystem().getGridSize(); +} + +template<class APIClass, class LeafClass> +void NpParticleBaseTemplate<APIClass, LeafClass>::setGridSize(PxReal g) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + PX_CHECK_AND_RETURN(g >= 0.0f,"GridSize needs to be positive, PxParticleBase::setGridSize() ignored."); + PX_CHECK_AND_RETURN(!getScbParticleSystem().getScParticleSystem().getSim(),"GridSize immutable when the particle system is part of a scene."); + getScbParticleSystem().setGridSize(g); +} + +template<class APIClass, class LeafClass> +PxBounds3 NpParticleBaseTemplate<APIClass, LeafClass>::getWorldBounds(float inflation) const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + const PxBounds3 bounds = getScbParticleSystem().getWorldBounds(); + PX_ASSERT(bounds.isValid()); + + // PT: unfortunately we can't just scale the min/max vectors, we need to go through center/extents. + const PxVec3 center = bounds.getCenter(); + const PxVec3 inflatedExtents = bounds.getExtents() * inflation; + return PxBounds3::centerExtents(center, inflatedExtents); +} + + +#if PX_SUPPORT_GPU_PHYSX + +template<class APIClass, class LeafClass> +PxParticleDeviceExclusiveAccess* NpParticleBaseTemplate<APIClass, LeafClass>::getDeviceExclusiveAccessGpu(const char* callerName) const +{ + PxParticleDeviceExclusiveAccess* access = NULL; + if (getNpScene() && (getParticleBaseFlags() & PxParticleBaseFlag::eGPU)) + { + access = getScbParticleSystem().getDeviceExclusiveAccessGpu(); + } + + if (!access) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, + "%s is only allowed to be called if the particle system is in device exclusive mode. " + "Please refer to PxParticleDeviceExclusive::enable and PxParticleDeviceExclusive::isEnabled.", callerName); + } + + return access; +} + + +template<class APIClass, class LeafClass> +void NpParticleBaseTemplate<APIClass, LeafClass>::enableDeviceExclusiveModeGpu() +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + if (!getNpScene()) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxParticleDeviceExclusive::enable is not allowed to be called if the particle system is not in a scene."); + return; + } + + if (!(getParticleBaseFlags() & PxParticleBaseFlag::eGPU)) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxParticleDeviceExclusive::enable is not allowed for non PxParticleBaseFlag::eGPU particle systems."); + return; + } + + getScbParticleSystem().enableDeviceExclusiveModeGpu(); +} + + +template<class APIClass, class LeafClass> +bool NpParticleBaseTemplate<APIClass, LeafClass>::isDeviceExclusiveModeEnabledGpu() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + if (!getNpScene() || !(getParticleBaseFlags() & PxParticleBaseFlag::eGPU)) + { + return false; + } + + return getScbParticleSystem().getDeviceExclusiveAccessGpu() != NULL; +} + + +template<class APIClass, class LeafClass> +void NpParticleBaseTemplate<APIClass, LeafClass>::getReadWriteCudaBuffersGpu(PxCudaReadWriteParticleBuffers& buffers) const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + PxParticleDeviceExclusiveAccess* access = getDeviceExclusiveAccessGpu("PxParticleDeviceExclusive::getReadWriteCudaBuffers"); + if (access) + { + access->getReadWriteCudaBuffers(buffers); + } +} + + +template<class APIClass, class LeafClass> +void NpParticleBaseTemplate<APIClass, LeafClass>::setValidParticleRangeGpu(PxU32 validParticleRange) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PxParticleDeviceExclusiveAccess* access = getDeviceExclusiveAccessGpu("PxParticleDeviceExclusive::setValidParticleRange"); + if (access) + { + access->setValidParticleRange(validParticleRange); + } +} + + +template<class APIClass, class LeafClass> +void NpParticleBaseTemplate<APIClass, LeafClass>::setDeviceExclusiveModeFlagsGpu(PxU32 flags) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PxParticleDeviceExclusiveAccess* access = getDeviceExclusiveAccessGpu("PxParticleDeviceExclusive::setFlags"); + if (access) + { + access->setFlags(flags); + } +} + + +template<class APIClass, class LeafClass> +physx::PxBaseTask* NpParticleBaseTemplate<APIClass, LeafClass>::getLaunchTaskGpu() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + PxParticleDeviceExclusiveAccess* access = getDeviceExclusiveAccessGpu("PxParticleDeviceExclusive::getLaunchTask"); + if (access) + { + return access->getLaunchTask(); + } + return NULL; +} + + +template<class APIClass, class LeafClass> +void NpParticleBaseTemplate<APIClass, LeafClass>::addLaunchTaskDependentGpu(class physx::PxBaseTask& dependent) +{ + NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); + + PxParticleDeviceExclusiveAccess* access = getDeviceExclusiveAccessGpu("PxParticleDeviceExclusive::addLaunchTaskDependent"); + if (access) + { + access->addLaunchTaskDependent(dependent); + } +} + + +template<class APIClass, class LeafClass> +size_t NpParticleBaseTemplate<APIClass, LeafClass>::getCudaStreamGpu() const +{ + NP_READ_CHECK(NpActor::getOwnerScene(*this)); + + PxParticleDeviceExclusiveAccess* access = getDeviceExclusiveAccessGpu("PxParticleDeviceExclusive::getCudaStream"); + if (access) + { + return access->getCudaStream(); + } + return 0; +} + + +#endif +} + +#endif // PX_USE_PARTICLE_SYSTEM_API + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/particles/NpParticleFluid.cpp b/PhysX_3.4/Source/PhysX/src/particles/NpParticleFluid.cpp new file mode 100644 index 00000000..2e68e1b2 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/particles/NpParticleFluid.cpp @@ -0,0 +1,132 @@ +// 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 "NpParticleFluid.h" +#include "ScbParticleSystem.h" +#include "NpWriteCheck.h" +#include "NpReadCheck.h" + +using namespace physx; + +NpParticleFluid::NpParticleFluid(PxU32 maxParticles, bool perParticleRestOffset) +: ParticleSystemTemplateClass(PxConcreteType::ePARTICLE_FLUID, PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE, PxActorType::ePARTICLE_FLUID, maxParticles, perParticleRestOffset) +{} + +NpParticleFluid::~NpParticleFluid() +{ +} + +// PX_SERIALIZATION +NpParticleFluid* NpParticleFluid::createObject(PxU8*& address, PxDeserializationContext& context) +{ + NpParticleFluid* obj = new (address) NpParticleFluid(PxBaseFlag::eIS_RELEASABLE); + address += sizeof(NpParticleFluid); + obj->importExtraData(context); + obj->resolveReferences(context); + return obj; +} +//~PX_SERIALIZATION + +PxParticleFluidReadData* NpParticleFluid::lockParticleFluidReadData(PxDataAccessFlags flags) +{ + return static_cast<PxParticleFluidReadData*>(lockParticleReadData(flags)); +} + +PxParticleFluidReadData* NpParticleFluid::lockParticleFluidReadData() +{ + return static_cast<PxParticleFluidReadData*>(lockParticleReadData()); +} + +void* NpParticleFluid::is(PxActorType::Enum type) +{ + if (type == PxActorType::ePARTICLE_FLUID) + return reinterpret_cast<void*>(static_cast<PxParticleFluid*>(this)); + else + return NULL; +} + + +const void* NpParticleFluid::is(PxActorType::Enum type) const +{ + if (type == PxActorType::ePARTICLE_FLUID) + return reinterpret_cast<const void*>(static_cast<const PxParticleFluid*>(this)); + else + return NULL; +} + + +PxReal NpParticleFluid::getStiffness() const +{ + NP_READ_CHECK(getNpScene()); + return getScbParticleSystem().getStiffness(); +} + + +void NpParticleFluid::setStiffness(PxReal s) +{ + NP_WRITE_CHECK(getNpScene()); + PX_CHECK_AND_RETURN(s > 0.0f,"Stiffness needs to be positive, PxParticleFluid::setStiffness() ignored."); + getScbParticleSystem().setStiffness(s); +} + + +PxReal NpParticleFluid::getViscosity() const +{ + NP_READ_CHECK(getNpScene()); + return getScbParticleSystem().getViscosity(); +} + + +void NpParticleFluid::setViscosity(PxReal v) +{ + NP_WRITE_CHECK(getNpScene()); + PX_CHECK_AND_RETURN(v > 0.0f,"Viscosity needs to be positive, PxParticleFluid::setViscosity() ignored."); + getScbParticleSystem().setViscosity(v); +} + + +PxReal NpParticleFluid::getRestParticleDistance() const +{ + NP_READ_CHECK(getNpScene()); + return getScbParticleSystem().getRestParticleDistance(); +} + +void NpParticleFluid::setRestParticleDistance(PxReal r) +{ + NP_WRITE_CHECK(getNpScene()); + PX_CHECK_AND_RETURN(r > 0.0f,"RestParticleDistance needs to be positive, PxParticleFluid::setRestParticleDistance() ignored."); + PX_CHECK_AND_RETURN(!getScbParticleSystem().getScParticleSystem().getSim(),"RestParticleDistance immutable when the particle system is part of a scene."); + getScbParticleSystem().setRestParticleDistance(r); +} + +#endif // PX_USE_PARTICLE_SYSTEM_API diff --git a/PhysX_3.4/Source/PhysX/src/particles/NpParticleFluid.h b/PhysX_3.4/Source/PhysX/src/particles/NpParticleFluid.h new file mode 100644 index 00000000..da2f8234 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/particles/NpParticleFluid.h @@ -0,0 +1,94 @@ +// 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_NP_PARTICLEFLUID +#define PX_PHYSICS_NP_PARTICLEFLUID + +#include "PxPhysXConfig.h" + +#if PX_USE_PARTICLE_SYSTEM_API + +#include "NpParticleSystem.h" + +namespace physx +{ + +class NpParticleFluid; + +typedef NpParticleBaseTemplate<PxParticleFluid, NpParticleFluid> NpParticleFluidT; +class NpParticleFluid : public NpParticleFluidT +{ +//= 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 + NpParticleFluid(PxBaseFlags baseFlags) : NpParticleFluidT(baseFlags) {} + virtual void requires(PxProcessPxBaseCallback&){} + virtual void exportExtraData(PxSerializationContext& stream) { mParticleSystem.exportExtraData(stream); } + void importExtraData(PxDeserializationContext& context) { mParticleSystem.importExtraData(context); } + static NpParticleFluid* createObject(PxU8*& address, PxDeserializationContext& context); + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + NpParticleFluid(PxU32 maxParticles, bool perParticleRestOffset); + virtual ~NpParticleFluid(); + + //--------------------------------------------------------------------------------- + // PxParticleFluid implementation + //--------------------------------------------------------------------------------- + virtual PxActorType::Enum getType() const { return PxActorType::ePARTICLE_FLUID; } + + virtual void* is(PxActorType::Enum type); + virtual const void* is(PxActorType::Enum type) const; + + virtual PxParticleFluidReadData* lockParticleFluidReadData(PxDataAccessFlags flags); + virtual PxParticleFluidReadData* lockParticleFluidReadData(); + + virtual PxReal getStiffness() const; + virtual void setStiffness(PxReal); + virtual PxReal getViscosity() const; + virtual void setViscosity(PxReal); + + virtual PxReal getRestParticleDistance() const; + virtual void setRestParticleDistance(PxReal); + +private: + typedef NpParticleBaseTemplate<PxParticleFluid, NpParticleFluid> ParticleSystemTemplateClass; + +}; + +} + +#endif // PX_USE_PARTICLE_SYSTEM_API + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/particles/NpParticleFluidReadData.h b/PhysX_3.4/Source/PhysX/src/particles/NpParticleFluidReadData.h new file mode 100644 index 00000000..a9cec5d5 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/particles/NpParticleFluidReadData.h @@ -0,0 +1,85 @@ +// 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_NP_PARTICLE_FLUID_READ_DATA +#define PX_PHYSICS_NP_PARTICLE_FLUID_READ_DATA + +#include "PxParticleFluidReadData.h" +#include "PsFoundation.h" + +namespace physx +{ + +class NpParticleFluidReadData : public PxParticleFluidReadData, public Ps::UserAllocated +{ +public: + + NpParticleFluidReadData() : + mIsLocked(false), + mFlags(PxDataAccessFlag::eREADABLE) + { + strncpy(mLastLockedName, "UNDEFINED", sBufferLength); + } + + virtual ~NpParticleFluidReadData() + {} + + // implementation for PxLockedData + virtual void setDataAccessFlags(PxDataAccessFlags flags) { mFlags = flags; } + virtual PxDataAccessFlags getDataAccessFlags() { return mFlags; } + + virtual void unlock() { unlockFast(); } + + // internal methods + void unlockFast() { mIsLocked = false; } + + void lock(const char* callerName) + { + if (mIsLocked) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxParticleReadData access through %s while its still locked by last call of %s.", callerName, mLastLockedName); + PX_ALWAYS_ASSERT_MESSAGE("PxParticleReadData access violation"); + } + strncpy(mLastLockedName, callerName, sBufferLength); + mLastLockedName[sBufferLength-1]=0; + mIsLocked = true; + } + +private: + + static const PxU32 sBufferLength = 128; + bool mIsLocked; + char mLastLockedName[sBufferLength]; + PxDataAccessFlags mFlags; +}; + +} + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/particles/NpParticleSystem.cpp b/PhysX_3.4/Source/PhysX/src/particles/NpParticleSystem.cpp new file mode 100644 index 00000000..e93dd763 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/particles/NpParticleSystem.cpp @@ -0,0 +1,70 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + + +#include "NpParticleSystem.h" + +#if PX_USE_PARTICLE_SYSTEM_API + +#include "PsFoundation.h" +#include "NpPhysics.h" + +#include "NpScene.h" +#include "NpWriteCheck.h" + +#include "PsArray.h" + +using namespace physx; + +NpParticleSystem::NpParticleSystem(PxU32 maxParticles, bool perParticleRestOffset) +: ParticleSystemTemplateClass(PxConcreteType::ePARTICLE_SYSTEM, PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE, PxActorType::ePARTICLE_SYSTEM, maxParticles, perParticleRestOffset) +{} + +NpParticleSystem::~NpParticleSystem() +{} + +// PX_SERIALIZATION +NpParticleSystem* NpParticleSystem::createObject(PxU8*& address, PxDeserializationContext& context) +{ + NpParticleSystem* obj = new (address) NpParticleSystem(PxBaseFlag::eIS_RELEASABLE); + address += sizeof(NpParticleSystem); + obj->importExtraData(context); + obj->resolveReferences(context); + return obj; +} +//~PX_SERIALIZATION + +void NpParticleSystem::setParticleReadDataFlag(PxParticleReadDataFlag::Enum flag, bool val) +{ + NP_WRITE_CHECK(getNpScene()); + PX_CHECK_AND_RETURN( flag != PxParticleReadDataFlag::eDENSITY_BUFFER, + "ParticleSystem has unsupported PxParticleReadDataFlag::eDENSITY_BUFFER set."); + NpParticleSystemT::setParticleReadDataFlag(flag, val); +} +#endif diff --git a/PhysX_3.4/Source/PhysX/src/particles/NpParticleSystem.h b/PhysX_3.4/Source/PhysX/src/particles/NpParticleSystem.h new file mode 100644 index 00000000..8ff947e8 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/particles/NpParticleSystem.h @@ -0,0 +1,95 @@ +// 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_NP_PARTICLESYSTEM +#define PX_PHYSICS_NP_PARTICLESYSTEM + +#include "PxPhysXConfig.h" + +#if PX_USE_PARTICLE_SYSTEM_API + +#include "particles/PxParticleSystem.h" +#include "NpParticleBaseTemplate.h" + +#include "ScbParticleSystem.h" + +// PX_SERIALIZATION +#include "PxSerialFramework.h" +//~PX_SERIALIZATION + +namespace physx +{ + +class NpScene; +class NpParticleSystem; + +namespace Scb +{ + class ParticleSystem; +} + +typedef NpParticleBaseTemplate<PxParticleSystem, NpParticleSystem> NpParticleSystemT; +class NpParticleSystem : public NpParticleSystemT +{ +//= 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 + NpParticleSystem(PxBaseFlags baseFlags) : NpParticleSystemT(baseFlags) {} + virtual void requires(PxProcessPxBaseCallback&) {} + virtual void exportExtraData(PxSerializationContext& stream) { mParticleSystem.exportExtraData(stream); } + void importExtraData(PxDeserializationContext& context) { mParticleSystem.importExtraData(context); } + static NpParticleSystem* createObject(PxU8*& address, PxDeserializationContext& context); + static void getBinaryMetaData(PxOutputStream& stream); + +//~PX_SERIALIZATION + NpParticleSystem(PxU32 maxParticles, bool perParticleRestOffset); + virtual ~NpParticleSystem(); + + virtual void setParticleReadDataFlag(PxParticleReadDataFlag::Enum flag, bool val); + + //--------------------------------------------------------------------------------- + // PxParticleSystem implementation + //--------------------------------------------------------------------------------- + virtual PxActorType::Enum getType() const { return PxActorType::ePARTICLE_SYSTEM; } + +private: + typedef NpParticleBaseTemplate<PxParticleSystem, NpParticleSystem> ParticleSystemTemplateClass; +}; + +} + +#endif // PX_USE_PARTICLE_SYSTEM_API + +#endif diff --git a/PhysX_3.4/Source/PhysX/src/windows/NpWindowsDelayLoadHook.cpp b/PhysX_3.4/Source/PhysX/src/windows/NpWindowsDelayLoadHook.cpp new file mode 100644 index 00000000..9bd62808 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/windows/NpWindowsDelayLoadHook.cpp @@ -0,0 +1,82 @@ +// 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 "windows/PxWindowsDelayLoadHook.h" +#include "windows/PsWindowsInclude.h" +#include "windows/CmWindowsLoadLibrary.h" + +// Prior to Visual Studio 2015 Update 3, these hooks were non-const. +#define DELAYIMP_INSECURE_WRITABLE_HOOKS +#include <delayimp.h> + +static const physx::PxDelayLoadHook* gDelayLoadHook = NULL; + +void physx::PxSetPhysXDelayLoadHook(const physx::PxDelayLoadHook* hook) +{ + gDelayLoadHook = hook; +} + +using namespace physx; + +#pragma comment(lib, "delayimp") + +FARPROC WINAPI delayHook(unsigned dliNotify, PDelayLoadInfo pdli) +{ + switch (dliNotify) { + case dliStartProcessing : + break; + + case dliNotePreLoadLibrary : + { + return Cm::physXCommonDliNotePreLoadLibrary(pdli->szDll,gDelayLoadHook); + } + break; + + case dliNotePreGetProcAddress : + break; + + case dliFailLoadLib : + break; + + case dliFailGetProc : + break; + + case dliNoteEndProcessing : + break; + + default : + + return NULL; + } + + return NULL; +} + +PfnDliHook __pfnDliNotifyHook2 = delayHook; |