857 lines
28 KiB
C++
857 lines
28 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 "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"
|
|
|
|
#include "NpConnector.h"
|
|
#include "NpPtrTableStorageManager.h"
|
|
#include "CmCollection.h"
|
|
#include "NpArticulationReducedCoordinate.h"
|
|
#include "NpArticulationJointReducedCoordinate.h"
|
|
|
|
using namespace physx;
|
|
|
|
NpFactory::NpFactory()
|
|
: GuMeshFactory()
|
|
, mConnectorArrayPool(PX_DEBUG_EXP("connectorArrayPool"))
|
|
, mPtrTableStorageManager(PX_NEW(NpPtrTableStorageManager))
|
|
, mMaterialPool(PX_DEBUG_EXP("MaterialPool"))
|
|
#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 invalidating 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();
|
|
|
|
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;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
template <class T0, class T1>
|
|
static void addToTracking(T1& set, T0* element, Ps::Mutex& mutex, bool lock)
|
|
{
|
|
if(!element)
|
|
return;
|
|
|
|
if(lock)
|
|
mutex.lock();
|
|
|
|
set.insert(element);
|
|
|
|
if(lock)
|
|
mutex.unlock();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////// Actors
|
|
|
|
void NpFactory::addRigidStatic(PxRigidStatic* npActor, bool lock)
|
|
{
|
|
addToTracking(mActorTracking, npActor, mTrackingMutex, lock);
|
|
}
|
|
|
|
void NpFactory::addRigidDynamic(PxRigidDynamic* npBody, bool lock)
|
|
{
|
|
addToTracking(mActorTracking, npBody, mTrackingMutex, lock);
|
|
}
|
|
|
|
void NpFactory::addShape(PxShape* shape, bool lock)
|
|
{
|
|
addToTracking(mShapeTracking, shape, mTrackingMutex, lock);
|
|
}
|
|
|
|
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(PxArticulationBase* npArticulation, bool lock)
|
|
{
|
|
addToTracking(mArticulationTracking, npArticulation, mTrackingMutex, lock);
|
|
}
|
|
|
|
namespace
|
|
{
|
|
PxArticulationBase* createArticulation()
|
|
{
|
|
NpArticulation* npArticulation = NpFactory::getInstance().createNpArticulation();
|
|
if (!npArticulation)
|
|
Ps::getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __LINE__, "Articulation initialization failed: returned NULL.");
|
|
|
|
return npArticulation;
|
|
}
|
|
|
|
PxArticulationBase* createArticulationRC()
|
|
{
|
|
NpArticulationReducedCoordinate* npArticulation = NpFactory::getInstance().createNpArticulationRC();
|
|
if (!npArticulation)
|
|
Ps::getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __LINE__, "Articulation initialization failed: returned NULL.");
|
|
|
|
return npArticulation;
|
|
}
|
|
|
|
NpArticulationLink* createArticulationLink(PxArticulationBase&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);
|
|
|
|
PxArticulationJointBase* npArticulationJoint = root.createArticulationJoint(*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 PxArticulationBase* (*sCreateArticulationFn)() = 0;
|
|
static PxArticulationBase* (*sCreateArticulationRCFn)() = 0;
|
|
static NpArticulationLink* (*sCreateArticulationLinkFn)(PxArticulationBase&, NpArticulationLink* parent, const PxTransform& pose) = 0;
|
|
}
|
|
|
|
void NpFactory::registerArticulations()
|
|
{
|
|
sCreateArticulationFn = &::createArticulation;
|
|
sCreateArticulationLinkFn = &::createArticulationLink;
|
|
}
|
|
|
|
void NpFactory::registerArticulationRCs()
|
|
{
|
|
sCreateArticulationRCFn = &::createArticulationRC;
|
|
sCreateArticulationLinkFn = &::createArticulationLink;
|
|
}
|
|
|
|
void NpFactory::releaseArticulationToPool(PxArticulationBase& articulation)
|
|
{
|
|
|
|
PX_ASSERT(articulation.getBaseFlags() & PxBaseFlag::eOWNS_MEMORY);
|
|
if (articulation.getConcreteType() == PxConcreteType::eARTICULATION)
|
|
{
|
|
Ps::Mutex::ScopedLock lock(mArticulationPoolLock);
|
|
mArticulationPool.destroy(static_cast<NpArticulation*>(&articulation));
|
|
}
|
|
else
|
|
{
|
|
PX_ASSERT(articulation.getConcreteType() == PxConcreteType::eARTICULATION_REDUCED_COORDINATE);
|
|
Ps::Mutex::ScopedLock lock(mArticulationRCPoolLock);
|
|
mArticulationRCPool.destroy(static_cast<NpArticulationReducedCoordinate*>(&articulation));
|
|
}
|
|
}
|
|
|
|
NpArticulation* NpFactory::createNpArticulation()
|
|
{
|
|
Ps::Mutex::ScopedLock lock(mArticulationPoolLock);
|
|
return mArticulationPool.construct();
|
|
}
|
|
|
|
PxArticulation* NpFactory::createArticulation()
|
|
{
|
|
if(!sCreateArticulationFn)
|
|
{
|
|
Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__,
|
|
"Articulations not registered: returned NULL.");
|
|
return NULL;
|
|
}
|
|
|
|
PxArticulationBase* npArticulation = (*sCreateArticulationFn)();
|
|
if(npArticulation)
|
|
addArticulation(npArticulation);
|
|
|
|
return static_cast<PxArticulation*>(npArticulation);
|
|
}
|
|
|
|
PxArticulationReducedCoordinate* NpFactory::createArticulationRC()
|
|
{
|
|
if (!sCreateArticulationRCFn)
|
|
{
|
|
Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__,
|
|
"Articulations not registered: returned NULL.");
|
|
return NULL;
|
|
}
|
|
|
|
PxArticulationBase* npArticulation = (*sCreateArticulationRCFn)();
|
|
if (npArticulation)
|
|
addArticulation(npArticulation);
|
|
|
|
return static_cast<PxArticulationReducedCoordinate*>(npArticulation);
|
|
}
|
|
|
|
NpArticulationReducedCoordinate* NpFactory::createNpArticulationRC()
|
|
{
|
|
Ps::Mutex::ScopedLock lock(mArticulationRCPoolLock);
|
|
return mArticulationRCPool.construct();
|
|
}
|
|
|
|
void NpFactory::onArticulationRelease(PxArticulationBase* a)
|
|
{
|
|
Ps::Mutex::ScopedLock lock(mTrackingMutex);
|
|
mArticulationTracking.erase(a);
|
|
}
|
|
|
|
NpArticulationLink* NpFactory::createNpArticulationLink(PxArticulationBase&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(PxArticulationBase& 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);
|
|
}
|
|
|
|
NpArticulationJointReducedCoordinate* NpFactory::createNpArticulationJointRC(NpArticulationLink& parent, const PxTransform& parentFrame, NpArticulationLink& child, const PxTransform& childFrame)
|
|
{
|
|
NpArticulationJointReducedCoordinate* npArticulationJoint;
|
|
{
|
|
Ps::Mutex::ScopedLock lock(mArticulationJointRCPoolLock);
|
|
npArticulationJoint = mArticulationRCJointPool.construct(parent, parentFrame, child, childFrame);
|
|
}
|
|
return npArticulationJoint;
|
|
}
|
|
|
|
void NpFactory::releaseArticulationJointRCToPool(NpArticulationJointReducedCoordinate& articulationJoint)
|
|
{
|
|
PX_ASSERT(articulationJoint.getBaseFlags() & PxBaseFlag::eOWNS_MEMORY);
|
|
Ps::Mutex::ScopedLock lock(mArticulationJointRCPoolLock);
|
|
mArticulationRCJointPool.destroy(&articulationJoint);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////// constraint
|
|
|
|
void NpFactory::addConstraint(PxConstraint* npConstraint, bool lock)
|
|
{
|
|
addToTracking(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
|
|
|
|
void NpFactory::addAggregate(PxAggregate* npAggregate, bool lock)
|
|
{
|
|
addToTracking(mAggregateTracking, npAggregate, mTrackingMutex, lock);
|
|
}
|
|
|
|
PxAggregate* NpFactory::createAggregate(PxU32 maxActors, bool selfCollisions)
|
|
{
|
|
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);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
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 materialData;
|
|
materialData.staticFriction = staticFriction;
|
|
materialData.dynamicFriction = dynamicFriction;
|
|
materialData.restitution = restitution;
|
|
|
|
NpMaterial* npMaterial;
|
|
{
|
|
Ps::Mutex::ScopedLock lock(mMaterialPoolLock);
|
|
npMaterial = mMaterialPool.construct(materialData);
|
|
}
|
|
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] = 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
|
|
{
|
|
// PT: TODO: isn't there a lock missing here? See usage in MeshFactory
|
|
return mShapeTracking.size();
|
|
}
|
|
|
|
PxU32 NpFactory::getShapes(PxShape** userBuffer, PxU32 bufferSize, PxU32 startIndex) const
|
|
{
|
|
// PT: TODO: isn't there a lock missing here? See usage in MeshFactory
|
|
return Cm::getArrayOfPointers(userBuffer, bufferSize, startIndex, mShapeTracking.getEntries(), mShapeTracking.size());
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
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);
|
|
}
|
|
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);
|
|
}
|
|
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::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_REDUCED_COORDINATE)
|
|
{
|
|
NpArticulationReducedCoordinate* np = static_cast<NpArticulationReducedCoordinate*>(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_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);
|
|
}
|
|
|
|
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)
|
|
{
|
|
PxArticulationJointBase* np = scb.getScArticulationJoint().getRoot();
|
|
|
|
if (np->getBaseFlags() & PxBaseFlag::eOWNS_MEMORY)
|
|
{
|
|
if (np->getConcreteType() == PxConcreteType::eARTICULATION_JOINT)
|
|
{
|
|
NpFactory::getInstance().releaseArticulationJointToPool(*static_cast<NpArticulationJoint*>(np));
|
|
}
|
|
else
|
|
{
|
|
PX_ASSERT(np->getConcreteType() == PxConcreteType::eARTICULATION_JOINT_REDUCED_COORDINATE);
|
|
NpFactory::getInstance().releaseArticulationJointRCToPool(*static_cast<NpArticulationJointReducedCoordinate*>(np));
|
|
}
|
|
}
|
|
else
|
|
np->~PxArticulationJointBase();
|
|
NpPhysics::getInstance().notifyDeletionListenersMemRelease(np, NULL);
|
|
}
|
|
|
|
static void NpDestroyArticulation(Scb::Articulation& scb)
|
|
{
|
|
PxArticulationBase* artic = const_cast<PxArticulationBase*>(static_cast<const PxArticulationBase*>(getNpArticulation(&scb)));
|
|
|
|
void* ud = artic->PxArticulationBase::userData;
|
|
if (artic->getBaseFlags() & PxBaseFlag::eOWNS_MEMORY)
|
|
NpFactory::getInstance().releaseArticulationToPool(*artic);
|
|
else
|
|
artic->~PxArticulationBase();
|
|
NpPhysics::getInstance().notifyDeletionListenersMemRelease(artic, 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);
|
|
}
|
|
|
|
namespace physx
|
|
{
|
|
void NpDestroy(Scb::Base& base)
|
|
{
|
|
switch(base.getScbType())
|
|
{
|
|
case ScbType::eSHAPE_EXCLUSIVE:
|
|
case ScbType::eSHAPE_SHARED: { NpDestroyShape(static_cast<Scb::Shape&>(base)); }break;
|
|
case ScbType::eBODY: { NpDestroyRigidDynamic(static_cast<Scb::Body&>(base)); }break;
|
|
case ScbType::eBODY_FROM_ARTICULATION_LINK: { NpDestroyArticulationLink(static_cast<Scb::Body&>(base)); }break;
|
|
case ScbType::eRIGID_STATIC: { NpDestroyRigidActor(static_cast<Scb::RigidStatic&>(base)); }break;
|
|
case ScbType::eCONSTRAINT: { NpDestroyConstraint(static_cast<Scb::Constraint&>(base)); }break;
|
|
case ScbType::eARTICULATION: { NpDestroyArticulation(static_cast<Scb::Articulation&>(base)); }break;
|
|
case ScbType::eARTICULATION_JOINT: { NpDestroyArticulationJoint(static_cast<Scb::ArticulationJoint&>(base)); }break;
|
|
case ScbType::eAGGREGATE: { NpDestroyAggregate(static_cast<Scb::Aggregate&>(base)); }break;
|
|
case ScbType::eUNDEFINED:
|
|
case ScbType::eTYPE_COUNT:
|
|
PX_ALWAYS_ASSERT_MESSAGE("NpDestroy: missing type!");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|