// // 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(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;igetType() == PxActorType::eARTICULATION_LINK) { NpArticulationLink* link = static_cast(mActors[i]); PxArticulationImpl* impl = reinterpret_cast(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(actor); PxArticulationBase& npArt = al.getRoot(); for(PxU32 i=0; i < npArt.getNbLinks(); i++) { PxArticulationLink* link; npArt.getLinks(&link, 1, i); mAggregate.addActor(static_cast(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(bvhStructure); static_cast(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(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(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(mActors[idx])->getRoot() == &art)) { PxActor* a = mActors[idx]; mActors[idx] = mActors[--mNbActors]; removeAndReinsert(*a, reinsert); found = true; } else idx++; } reinterpret_cast(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(mAggregate.getScbSceneForAPI()->getPxScene()) : NULL; } NpScene* NpAggregate::getOwnerScene() const { return mAggregate.getScbScene() ? static_cast(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(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(mActors[i])->getRoot(); if(!articulation.getAggregate()) reinterpret_cast(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(); if(link) c.process(link->getArticulation()); else c.process(*mActors[i]); } } // ~PX_SERIALIZATION