// 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-2017 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 "NpParticleSystem.h" #include "NpParticleFluid.h" #include "NpArticulation.h" #include "CmUtils.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) static_cast(mActors[i])->getRoot().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) { if (actor.getType() != PxActorType::eARTICULATION_LINK) { Scb::Actor& scb = NpActor::getScbFromPxActor(actor); mAggregate.addActor(scb); s.addActorInternal(actor); } else if (!actor.getScene()) // This check makes sure that a link of an articulation gets only added once. { NpArticulationLink& al = static_cast(actor); NpArticulation& npArt = al.getRoot(); NpArticulationLink* const* links = npArt.getLinks(); for(PxU32 i=0; i < npArt.getNbLinks(); i++) { mAggregate.addActor(links[i]->getScbActorFast()); } s.addArticulationInternal(npArt); } } bool NpAggregate::addActor(PxActor& actor) { 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); } return true; } bool NpAggregate::removeActorAndReinsert(PxActor& actor, bool reinsert) { for(PxU32 i=0;i 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; } NpArticulation& npArt = static_cast(art); npArt.setAggregate(this); NpArticulationLink* const* links = npArt.getLinks(); for(PxU32 i=0; i < npArt.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(PxArticulation& art, bool reinsert) { NpArticulation* npArt = static_cast(&art); bool found = false; PxU32 idx = 0; while(idx < mNbActors) { if ((mActors[idx]->getType() == PxActorType::eARTICULATION_LINK) && (&static_cast(mActors[idx])->getRoot() == npArt)) { PxActor* a = mActors[idx]; mActors[idx] = mActors[--mNbActors]; removeAndReinsert(*a, reinsert); found = true; } else idx++; } npArt->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(PxArticulation& 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::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) { NpArticulation& articulation = static_cast(mActors[i])->getRoot(); if(!articulation.getAggregate()) articulation.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::requires(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