Projekt_Grafika/dependencies/physx-4.1/source/physx/src/NpPhysics.cpp

754 lines
25 KiB
C++

//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of NVIDIA CORPORATION nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Copyright (c) 2008-2019 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 "common/PxTolerancesScale.h"
#include "PxPhysicsVersion.h"
#include "CmCollection.h"
#include "CmUtils.h"
#include "NpRigidStatic.h"
#include "NpRigidDynamic.h"
#include "NpArticulation.h"
#include "NpArticulationReducedCoordinate.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 "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
#include "NpFactory.h"
#if PX_SWITCH
#include "switch/NpMiddlewareInfo.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, pvdsdk::PsPvd* pvd) :
mSceneArray(PX_DEBUG_EXP("physicsSceneArray"))
, mPhysics(scale, pxvOffsetTable)
, mDeletionListenersExist(false)
#if PX_SUPPORT_GPU_PHYSX
, mNbRegisteredGpuClients(0)
#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.scArticulationMC2Px = -reinterpret_cast<ptrdiff_t>(&(reinterpret_cast<NpArticulation*>(0)->mImpl.getScbArticulation())) - static_cast<ptrdiff_t>(Scb::Articulation::getScOffset());
offsetTable.scArticulationRC2Px = -reinterpret_cast<ptrdiff_t>(&(reinterpret_cast<NpArticulationReducedCoordinate*>(0)->mImpl.getScbArticulation())) - static_cast<ptrdiff_t>(Scb::Articulation::getScOffset());
offsetTable.scArticulationJointMC2Px = -reinterpret_cast<ptrdiff_t>(&(reinterpret_cast<NpArticulationJoint*>(0)->mImpl.getScbArticulationJoint())) - static_cast<ptrdiff_t>(Scb::ArticulationJoint::getScOffset());
offsetTable.scArticulationJointRC2Px = -reinterpret_cast<ptrdiff_t>(&(reinterpret_cast<NpArticulationJointReducedCoordinate*>(0)->mImpl.getScbArticulationJoint())) - static_cast<ptrdiff_t>(Scb::ArticulationJoint::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());
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;
}
{
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, pvdsdk::PsPvd* pvd)
{
PX_UNUSED(foundation);
#if PX_SWITCH
NpSetMiddlewareInfo(); // register middleware info such that PhysX usage can be tracked
#endif
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.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();
}
PxArticulationReducedCoordinate* NpPhysics::createArticulationReducedCoordinate()
{
return NpFactory::getInstance().createArticulationRC();
}
PxAggregate* NpPhysics::createAggregate(PxU32 maxSize, bool selfCollisionEnabled)
{
return NpFactory::getInstance().createAggregate(maxSize, selfCollisionEnabled);
}
///////////////////////////////////////////////////////////////////////////////
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
{
physx::shdfnd::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__,
"PxPhysics::createMaterial: limit of 64K materials reached.");
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);
}
///////////////////////////////////////////////////////////////////////////////
PxBVHStructure* NpPhysics::createBVHStructure(PxInputStream& stream)
{
return NpFactory::getInstance().createBVHStructure(stream);
}
PxU32 NpPhysics::getNbBVHStructures() const
{
return NpFactory::getInstance().getNbBVHStructures();
}
PxU32 NpPhysics::getBVHStructures(PxBVHStructure** userBuffer, PxU32 bufferSize, PxU32 startIndex) const
{
return NpFactory::getInstance().getBVHStructures(userBuffer, bufferSize, startIndex);
}
///////////////////////////////////////////////////////////////////////////////
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, PxPvd* pvd)
{
return NpPhysics::createInstance(version, foundation, scale, trackOutstandingAllocations, static_cast<pvdsdk::PsPvd*>(pvd));
}
void PxRegisterArticulations(PxPhysics& physics)
{
PX_UNUSED(&physics); // for the moment
Dy::PxvRegisterArticulations();
NpFactory::registerArticulations();
}
void PxRegisterArticulationsReducedCoordinate(PxPhysics& physics)
{
PX_UNUSED(&physics); // for the moment
Dy::PxvRegisterArticulationsReducedCoordinate();
NpFactory::registerArticulationRCs();
}
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 PxAddCollectionToPhysics(const PxCollection& collection)
{
NpFactory& factory = NpFactory::getInstance();
const Cm::Collection& c = static_cast<const Cm::Collection&>(collection);
factory.addCollection(c);
}