428 lines
13 KiB
C++
428 lines
13 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 "NpAggregate.h"
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#include "PxActor.h"
|
||
|
#include "NpRigidStatic.h"
|
||
|
#include "NpRigidDynamic.h"
|
||
|
#include "NpArticulation.h"
|
||
|
#include "NpActor.h"
|
||
|
#include "GuBVHStructure.h"
|
||
|
#include "CmUtils.h"
|
||
|
#include "NpArticulationTemplate.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)
|
||
|
{
|
||
|
NpArticulationLink* link = static_cast<NpArticulationLink*>(mActors[i]);
|
||
|
PxArticulationImpl* impl = reinterpret_cast<PxArticulationImpl*>(link->getRoot().getImpl());
|
||
|
impl->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, const PxBVHStructure* bvhStructure)
|
||
|
{
|
||
|
if (actor.getType() != PxActorType::eARTICULATION_LINK)
|
||
|
{
|
||
|
Scb::Actor& scb = NpActor::getScbFromPxActor(actor);
|
||
|
|
||
|
mAggregate.addActor(scb);
|
||
|
|
||
|
s.addActorInternal(actor, bvhStructure);
|
||
|
}
|
||
|
else if (!actor.getScene()) // This check makes sure that a link of an articulation gets only added once.
|
||
|
{
|
||
|
NpArticulationLink& al = static_cast<NpArticulationLink&>(actor);
|
||
|
PxArticulationBase& npArt = al.getRoot();
|
||
|
for(PxU32 i=0; i < npArt.getNbLinks(); i++)
|
||
|
{
|
||
|
PxArticulationLink* link;
|
||
|
npArt.getLinks(&link, 1, i);
|
||
|
mAggregate.addActor(static_cast<NpArticulationLink*>(link)->getScbActorFast());
|
||
|
}
|
||
|
|
||
|
s.addArticulationInternal(npArt);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool NpAggregate::addActor(PxActor& actor, const PxBVHStructure* bvhStructure)
|
||
|
{
|
||
|
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, bvhStructure);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// A.B. if BVH structure is provided we need to keep it stored till the aggregate is inseted into a scene
|
||
|
if(bvhStructure)
|
||
|
{
|
||
|
PxBVHStructure* bvhStructureMutable = const_cast<PxBVHStructure*>(bvhStructure);
|
||
|
static_cast<Gu::BVHStructure*>(bvhStructureMutable)->incRefCount();
|
||
|
NpActor::getFromPxActor(actor).addConnector(NpConnectorType::eBvhStructure, bvhStructureMutable, "PxBVHStructure already added to the PxActor!");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
// A.B. remove the BVH structure reference if there is and the aggregate was not added to a scene
|
||
|
NpScene* s = getAPIScene();
|
||
|
if(!s)
|
||
|
{
|
||
|
NpActor& np = NpActor::getFromPxActor(actor);
|
||
|
Gu::BVHStructure* bvhStructure = NULL;
|
||
|
if(np.getConnectors<Gu::BVHStructure>(NpConnectorType::eBvhStructure, &bvhStructure, 1))
|
||
|
{
|
||
|
np.removeConnector(actor, NpConnectorType::eBvhStructure, bvhStructure, "PxBVHStructure connector could not have been removed!");
|
||
|
bvhStructure->decRefCount();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 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(PxArticulationBase& 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;
|
||
|
}
|
||
|
|
||
|
PxArticulationImpl* impl = reinterpret_cast<PxArticulationImpl*>(art.getImpl());
|
||
|
impl->setAggregate(this);
|
||
|
NpArticulationLink* const* links = impl->getLinks();
|
||
|
for(PxU32 i=0; i < impl->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(PxArticulationBase& art, bool reinsert)
|
||
|
{
|
||
|
bool found = false;
|
||
|
PxU32 idx = 0;
|
||
|
while(idx < mNbActors)
|
||
|
{
|
||
|
if ((mActors[idx]->getType() == PxActorType::eARTICULATION_LINK) && (&static_cast<NpArticulationLink*>(mActors[idx])->getRoot() == &art))
|
||
|
{
|
||
|
PxActor* a = mActors[idx];
|
||
|
mActors[idx] = mActors[--mNbActors];
|
||
|
removeAndReinsert(*a, reinsert);
|
||
|
found = true;
|
||
|
}
|
||
|
else
|
||
|
idx++;
|
||
|
}
|
||
|
|
||
|
reinterpret_cast<PxArticulationImpl*>(art.getImpl())->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(PxArticulationBase& 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::preExportDataReset()
|
||
|
{
|
||
|
mAggregate.setAggregateID(PX_INVALID_U32);
|
||
|
}
|
||
|
|
||
|
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)
|
||
|
{
|
||
|
PxArticulationBase& articulation = static_cast<NpArticulationLink*>(mActors[i])->getRoot();
|
||
|
if(!articulation.getAggregate())
|
||
|
reinterpret_cast<PxArticulationImpl*>(articulation.getImpl())->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::requiresObjects(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
|