aboutsummaryrefslogtreecommitdiff
path: root/PhysX_3.4/Source/PhysX/src/NpPhysics.cpp
diff options
context:
space:
mode:
authorgit perforce import user <a@b>2016-10-25 12:29:14 -0600
committerSheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees>2016-10-25 18:56:37 -0500
commit3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch)
treefa6485c169e50d7415a651bf838f5bcd0fd3bfbd /PhysX_3.4/Source/PhysX/src/NpPhysics.cpp
downloadphysx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz
physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip
Initial commit:
PhysX 3.4.0 Update @ 21294896 APEX 1.4.0 Update @ 21275617 [CL 21300167]
Diffstat (limited to 'PhysX_3.4/Source/PhysX/src/NpPhysics.cpp')
-rw-r--r--PhysX_3.4/Source/PhysX/src/NpPhysics.cpp893
1 files changed, 893 insertions, 0 deletions
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);
+}