diff options
| author | git perforce import user <a@b> | 2016-10-25 12:29:14 -0600 |
|---|---|---|
| committer | Sheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees> | 2016-10-25 18:56:37 -0500 |
| commit | 3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch) | |
| tree | fa6485c169e50d7415a651bf838f5bcd0fd3bfbd /PhysX_3.4/Source/PhysX/src/buffering/ScbScene.cpp | |
| download | physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip | |
Initial commit:
PhysX 3.4.0 Update @ 21294896
APEX 1.4.0 Update @ 21275617
[CL 21300167]
Diffstat (limited to 'PhysX_3.4/Source/PhysX/src/buffering/ScbScene.cpp')
| -rw-r--r-- | PhysX_3.4/Source/PhysX/src/buffering/ScbScene.cpp | 1514 |
1 files changed, 1514 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/PhysX/src/buffering/ScbScene.cpp b/PhysX_3.4/Source/PhysX/src/buffering/ScbScene.cpp new file mode 100644 index 00000000..0d0ac638 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/buffering/ScbScene.cpp @@ -0,0 +1,1514 @@ +// 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-2016 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 "ScbScene.h" +#include "ScbRigidStatic.h" +#include "ScbBody.h" +#include "ScbShape.h" +#include "ScbConstraint.h" +#include "ScbParticleSystem.h" +#include "ScbArticulation.h" +#include "ScbArticulationJoint.h" +#include "ScbCloth.h" +#include "ScbNpDeps.h" +#include "ScbAggregate.h" + +#include "PsFoundation.h" +#include "PxArticulation.h" + +namespace physx +{ + class NpMaterial; +} + +using namespace physx; + +// constants to make boolean template parameters more readable +static const bool tSimRunning = true; +static const bool tAdd = true; +static const bool tDynamic = true; +static const bool tNonSimObject = true; +static const bool tSyncOnRemove = true; +static const bool tWakeOnLostTouchCheck = true; + +void Scb::ObjectTracker::scheduleForInsert(Scb::Base& element) +{ + ControlState::Enum state = element.getControlState(); + PxU32 flags = element.getControlFlags(); + PX_ASSERT(!(flags & ControlFlag::eIS_RELEASED)); + PX_ASSERT(state == ControlState::eNOT_IN_SCENE || state == ControlState::eREMOVE_PENDING); + + if(state == ControlState::eREMOVE_PENDING) + { + element.setControlState(ControlState::eIN_SCENE); + if(!(flags & ControlFlag::eIS_UPDATED)) + remove(element); + } + else + { + PX_ASSERT(!(flags & ControlFlag::eIS_UPDATED)); + element.setControlState(ControlState::eINSERT_PENDING); + insert(element); + } +} + +void Scb::ObjectTracker::scheduleForRemove(Scb::Base& element) +{ + ControlState::Enum state = element.getControlState(); + PxU32 flags = element.getControlFlags(); + + PX_ASSERT(!(flags & ControlFlag::eIS_RELEASED)); + + if(state == ControlState::eINSERT_PENDING) + { + // if it's inserted this frame, just remove it - it can't be dirty + //ML: this assert wont' work because buffered insert raises this flag. We have a unit test which called TEST_F(ObserverTest, OnRelease) to verify it + //PX_ASSERT(!(flags & ControlFlag::eIS_UPDATED)); + element.setControlState(ControlState::eNOT_IN_SCENE); + remove(element); + } + else if(state == ControlState::eIN_SCENE) + { + element.setControlState(ControlState::eREMOVE_PENDING); + if(!(flags & ControlFlag::eIS_UPDATED)) + insert(element); + } + else + { + PX_ALWAYS_ASSERT_MESSAGE("Trying to remove element not in scene."); + } +} + +void Scb::ObjectTracker::scheduleForUpdate(Scb::Base& element) +{ + ControlState::Enum state = element.getControlState(); + PxU32 flags = element.getControlFlags(); + + PX_ASSERT(!(flags & ControlFlag::eIS_RELEASED)); + PX_ASSERT(state == ControlState::eIN_SCENE || state == ControlState::eREMOVE_PENDING || state == ControlState::eINSERT_PENDING); + + if(!(flags & ControlFlag::eIS_UPDATED)) + { + element.setControlFlag(ControlFlag::eIS_UPDATED); + if(state == ControlState::eIN_SCENE) + insert(element); + } +} + +void Scb::ObjectTracker::clear() +{ + Scb::Base *const * elements = mBuffered.getEntries(); + for(PxU32 i=0;i<mBuffered.size();i++) + { + ControlState::Enum state = elements[i]->getControlState(); + PxU32 flags = elements[i]->getControlFlags(); + + if(state == ControlState::eIN_SCENE || state == ControlState::eINSERT_PENDING) + elements[i]->resetControl(ControlState::eIN_SCENE); + else + { + elements[i]->resetControl(ControlState::eNOT_IN_SCENE); + elements[i]->resetScbScene(); + } + + if(flags & ControlFlag::eIS_RELEASED) + NpDestroy(*elements[i]); + } + mBuffered.clear(); +} + +void Scb::ObjectTracker::insert(Scb::Base& element) +{ + PX_ASSERT(!mBuffered.contains(&element)); + mBuffered.insert(&element); +} + +void Scb::ObjectTracker::remove(Scb::Base& element) +{ + mBuffered.erase(&element); +} + +/////////////////////////////////////////////////////////////////////////////// + +template <bool TSimRunning, bool TAdd, bool TIsDynamic, bool TIsNonSimObject, class T> +PX_FORCE_INLINE static void addOrRemoveRigidObject(Sc::Scene& s, T& rigidObject, bool wakeOnLostTouch, PxBounds3* uninflatedBounds); + +template <typename T>struct ScSceneFns {}; + +template<> struct ScSceneFns<Scb::Articulation> +{ + static PX_FORCE_INLINE void insert(Sc::Scene& s, Scb::Articulation& v, PxBounds3*) + { + Scb::Body* b = NpArticulationGetRootFromScb(v); + s.addArticulation(v.getScArticulation(), b->getScBody()); + } + static PX_FORCE_INLINE void remove(Sc::Scene& s, Scb::Articulation& v, bool wakeOnLostTouch) + { + PX_UNUSED(wakeOnLostTouch); + + v.clearBufferedSleepStateChange(); // see comment in remove code of Scb::Body + + s.removeArticulation(v.getScArticulation()); + } +}; + +template<> struct ScSceneFns<Scb::ArticulationJoint> +{ + static PX_FORCE_INLINE void insert(Sc::Scene& s, Scb::ArticulationJoint& v, PxBounds3*) + { + Scb::Body* scb0, * scb1; + NpArticulationJointGetBodiesFromScb(v, scb0, scb1); + s.addArticulationJoint(v.getScArticulationJoint(), scb0->getScBody(), scb1->getScBody()); + } + static PX_FORCE_INLINE void remove(Sc::Scene& s, Scb::ArticulationJoint& v, bool wakeOnLostTouch) { PX_UNUSED(wakeOnLostTouch); s.removeArticulationJoint(v.getScArticulationJoint()); } +}; + +template<> struct ScSceneFns<Scb::Constraint> +{ + static PX_FORCE_INLINE void insert(Sc::Scene& s, Scb::Constraint& v, PxBounds3*) + { + Scb::RigidObject* scb0, * scb1; + NpConstraintGetRigidObjectsFromScb(v, scb0, scb1); + + PX_ASSERT((!scb0) || (!(scb0->getActorFlags() & PxActorFlag::eDISABLE_SIMULATION))); + PX_ASSERT((!scb1) || (!(scb1->getActorFlags() & PxActorFlag::eDISABLE_SIMULATION))); + + s.addConstraint(v.getScConstraint(), scb0 ? &scb0->getScRigidCore() : NULL, scb1 ? &scb1->getScRigidCore() : NULL); + } + static PX_FORCE_INLINE void remove(Sc::Scene& s, Scb::Constraint& v, bool wakeOnLostTouch) + { + PX_UNUSED(wakeOnLostTouch); + s.removeConstraint(v.getScConstraint()); + } +}; + +template<> struct ScSceneFns<Scb::RigidStatic> +{ + static PX_FORCE_INLINE void insert(Sc::Scene& s, Scb::RigidStatic& v, PxBounds3* uninflatedBounds) + { + // important to use the buffered flags because for a pending insert those describe the end state the + // user expects. + + if (!(v.getActorFlags() & PxActorFlag::eDISABLE_SIMULATION)) + addOrRemoveRigidObject<!tSimRunning, tAdd, !tDynamic, !tNonSimObject>(s, v, false, uninflatedBounds); + else + addOrRemoveRigidObject<!tSimRunning, tAdd, !tDynamic, tNonSimObject>(s, v, false, uninflatedBounds); + } + static PX_FORCE_INLINE void remove(Sc::Scene& s, Scb::RigidStatic& v, bool wakeOnLostTouch) + { + // important to use the original flags because for a pending removal those describe the original state that needs + // to get cleaned up. + + if (!v.isSimDisabledInternally()) + addOrRemoveRigidObject<!tSimRunning, !tAdd, !tDynamic, !tNonSimObject>(s, v, wakeOnLostTouch, NULL); + else + addOrRemoveRigidObject<!tSimRunning, !tAdd, !tDynamic, tNonSimObject>(s, v, false, NULL); + } +}; + +template<> struct ScSceneFns<Scb::Body> +{ + static PX_FORCE_INLINE void insert(Sc::Scene& s, Scb::Body& v, PxBounds3* uninflatedBounds) + { + // see comments in rigid static case + if (!(v.getActorFlags() & PxActorFlag::eDISABLE_SIMULATION)) + addOrRemoveRigidObject<!tSimRunning, tAdd, tDynamic, !tNonSimObject>(s, v, false, uninflatedBounds); + else + addOrRemoveRigidObject<!tSimRunning, tAdd, tDynamic, tNonSimObject>(s, v, false, uninflatedBounds); + } + static PX_FORCE_INLINE void remove(Sc::Scene& s, Scb::Body& v, bool wakeOnLostTouch) + { + // strictly speaking, the following is only necessary for pending removes but it does not have a + // functional side effect if applied all the time. + // When an object gets removed from the scene, pending wakeUp/putToSleep events should be ignored because + // the internal sleep state for a free standing object is specified as sleeping. All the other parameter changes + // that go along with a sleep state change should still get processed though (zero vel, zero wake counter on + // putToSleep for example). Those are not affected because they are tracked through buffered updates + // of the velocity and wake counter. + // The clearing happens here because only here we are sure that the object does get removed for real. At earlier + // stages someone might remove and then re-insert and object and for such cases it is important to keep the + // sleep state change buffered. + v.clearBufferedSleepStateChange(); + + // see comments in rigid static case + if (!v.isSimDisabledInternally()) + addOrRemoveRigidObject<!tSimRunning, !tAdd, tDynamic, !tNonSimObject>(s, v, wakeOnLostTouch, NULL); + else + addOrRemoveRigidObject<!tSimRunning, !tAdd, tDynamic, tNonSimObject>(s, v, false, NULL); + } +}; + +#if PX_USE_PARTICLE_SYSTEM_API +template<> struct ScSceneFns<Scb::ParticleSystem> +{ + static PX_FORCE_INLINE void insert(Sc::Scene& s, Scb::ParticleSystem& v, PxBounds3*) { s.addParticleSystem(v.getScParticleSystem()); } + static PX_FORCE_INLINE void remove(Sc::Scene& s, Scb::ParticleSystem& v, bool wakeOnLostTouch) { PX_UNUSED(wakeOnLostTouch); s.removeParticleSystem(v.getScParticleSystem(), (v.getControlFlags() & Scb::ControlFlag::eIS_RELEASED) != 0); } +}; +#endif + +#if PX_USE_CLOTH_API +template<> struct ScSceneFns<Scb::Cloth> +{ +// static PX_FORCE_INLINE void insert(Sc::Scene& s, Scb::Cloth& v) { s.addRigidObject(v.getScCloth()); } + static PX_FORCE_INLINE void remove(Sc::Scene& s, Scb::Cloth& v, bool wakeOnLostTouch) { PX_UNUSED(wakeOnLostTouch); s.removeCloth(v.getScCloth()); } +}; +#endif + +/////////////////////////////////////////////////////////////////////////////// +#if PX_SUPPORT_PVD +template<typename T> struct PvdFns +{ + // PT: in the following functions, checkPvdDebugFlag() is done by the callers to save time when functions are called from a loop. + + static void createInstance(Scb::Scene& scene, Vd::ScbScenePvdClient& d, T* v) + { + PX_PROFILE_ZONE("PVD.createPVDInstance", scene.getContextId()); + PX_UNUSED(scene); + d.createPvdInstance(v); + } + + static void updateInstance(Scb::Scene& scene, Vd::ScbScenePvdClient& d, T* v) + { + PX_UNUSED(scene); + if(((v->getControlFlags() & Scb::ControlFlag::eIS_RELEASED) == 0) && (v->getControlState() != Scb::ControlState::eREMOVE_PENDING)) + { + PX_PROFILE_ZONE("PVD.updatePVDProperties", scene.getContextId()); + d.updatePvdProperties(v); + } + } + + static void releaseInstance(Scb::Scene& scene, Vd::ScbScenePvdClient& d, T* v) + { + PX_UNUSED(scene); + PX_PROFILE_ZONE("PVD.releasePVDInstance", scene.getContextId()); + d.releasePvdInstance(v); + } +}; + + #define CREATE_PVD_INSTANCE(obj) \ + { \ + if(mScenePvdClient.checkPvdDebugFlag()) \ + { \ + PX_PROFILE_ZONE("PVD.createPVDInstance", getContextId());\ + mScenePvdClient.createPvdInstance(obj); \ + } \ + } + #define RELEASE_PVD_INSTANCE(obj) \ + { \ + if(mScenePvdClient.checkPvdDebugFlag()) \ + { \ + PX_PROFILE_ZONE("PVD.releasePVDInstance", getContextId());\ + mScenePvdClient.releasePvdInstance(obj); \ + } \ + } + #define UPDATE_PVD_PROPERTIES(obj) \ + { \ + if(mScenePvdClient.checkPvdDebugFlag()) \ + { \ + PX_PROFILE_ZONE("PVD.updatePVDProperties", getContextId());\ + mScenePvdClient.updatePvdProperties(obj); \ + } \ + } + #define PVD_ORIGIN_SHIFT(shift) \ + { \ + if(mScenePvdClient.checkPvdDebugFlag()) \ + { \ + PX_PROFILE_ZONE("PVD.originShift", getContextId());\ + mScenePvdClient.originShift(shift); \ + } \ + } +#else + #define CREATE_PVD_INSTANCE(obj) {} + #define RELEASE_PVD_INSTANCE(obj) {} + #define UPDATE_PVD_PROPERTIES(obj) {} + #define PVD_ORIGIN_SHIFT(shift){} +#endif + +/////////////////////////////////////////////////////////////////////////////// + +Scb::Scene::Scene(const PxSceneDesc& desc, PxU64 contextID) : + mScene (desc, contextID), + mSimulationRunning (false), + mIsBuffering (false), + mStream (16384), + mShapeMaterialBuffer (PX_DEBUG_EXP("shapeMaterialBuffer")), + mShapePtrBuffer (PX_DEBUG_EXP("shapePtrBuffer")), + mActorPtrBuffer (PX_DEBUG_EXP("actorPtrBuffer")), +#if PX_SUPPORT_PVD + mScenePvdClient (*this), +#endif + mWakeCounterResetValue (desc.wakeCounterResetValue), + mBufferFlags (0) +{ +} + +void Scb::Scene::release() +{ +#if PX_SUPPORT_PVD + mScenePvdClient.releasePvdInstance(); +#endif + mScene.release(); + mShapeMaterialBuffer.clear(); + mShapePtrBuffer.clear(); + mActorPtrBuffer.clear(); + mStream.clear(); +} + +// PT: TODO: inline this +PxScene* Scb::Scene::getPxScene() +{ + return const_cast<NpScene*>(getNpScene(this)); +} + +/////////////////////////////////////////////////////////////////////////////// +template<typename T> +void Scb::Scene::add(T& v, ObjectTracker &tracker, PxBounds3* uninflatedBounds) +{ + v.setScbScene(this); + + if (!mIsBuffering) + { + v.resetControl(ControlState::eIN_SCENE); + ScSceneFns<T>::insert(mScene, v, uninflatedBounds); +#if PX_SUPPORT_PVD + if(mScenePvdClient.checkPvdDebugFlag()) + PvdFns<T>::createInstance(*this, mScenePvdClient, &v); +#endif + } + else + tracker.scheduleForInsert(v); +} + +template<typename T> +void Scb::Scene::remove(T& v, ObjectTracker &tracker, bool wakeOnLostTouch) +{ + if (!mIsBuffering) + { + ScSceneFns<T>::remove(mScene, v, wakeOnLostTouch); +#if PX_SUPPORT_PVD + if(mScenePvdClient.checkPvdDebugFlag()) + PvdFns<T>::releaseInstance(*this, mScenePvdClient, &v); +#endif + v.resetControl(ControlState::eNOT_IN_SCENE); + v.setScbScene(NULL); + } + else + { + tracker.scheduleForRemove(v); + } +} + + +/////////////////////////////////////////////////////////////////////////////// + +template<bool TIsDynamic, class T> +void Scb::Scene::addRigidNoSim(T& v, ObjectTracker &tracker) +{ + PX_ASSERT(v.getActorFlags() & PxActorFlag::eDISABLE_SIMULATION); + v.setScbScene(this); + + if (!mIsBuffering) + { + v.resetControl(ControlState::eIN_SCENE); +#if PX_SUPPORT_PVD + if(mScenePvdClient.checkPvdDebugFlag()) + PvdFns<T>::createInstance(*this, mScenePvdClient, &v); +#endif + addOrRemoveRigidObject<!tSimRunning, tAdd, TIsDynamic, tNonSimObject>(mScene, v, false, NULL); + } + else + { + tracker.scheduleForInsert(v); + addOrRemoveRigidObject<tSimRunning, tAdd, TIsDynamic, tNonSimObject>(mScene, v, false, NULL); + } +} + + +template<bool TIsDynamic, class T> +void Scb::Scene::removeRigidNoSim(T& v, ObjectTracker &tracker) +{ + PX_ASSERT(v.isSimDisabledInternally()); + + if (!mIsBuffering) + { + addOrRemoveRigidObject<!tSimRunning, !tAdd, TIsDynamic, tNonSimObject>(mScene, v, false, NULL); +#if PX_SUPPORT_PVD + if(mScenePvdClient.checkPvdDebugFlag()) + PvdFns<T>::releaseInstance(*this, mScenePvdClient, &v); +#endif + v.resetControl(ControlState::eNOT_IN_SCENE); + v.setScbScene(NULL); + } + else + { + tracker.scheduleForRemove(v); + addOrRemoveRigidObject<tSimRunning, !tAdd, TIsDynamic, tNonSimObject>(mScene, v, false, NULL); + } +} + + +void Scb::Scene::switchRigidToNoSim(Scb::RigidObject& r, bool isDynamic) +{ + PX_ASSERT(!mIsBuffering); + + // when a simulation objects has a pending remove and then gets switched to a non-simulation object, + // we must not process the code below. On sync the object will get removed before this call. + if (r.getControlState() == ControlState::eIN_SCENE) + { + size_t ptrOffset = -Scb::Shape::getScOffset(); + Ps::InlineArray<const Sc::ShapeCore*, 64> scShapes; + + if (isDynamic) + mScene.removeBody(static_cast<Sc::BodyCore&>(r.getScRigidCore()), scShapes, true); + else + mScene.removeStatic(static_cast<Sc::StaticCore&>(r.getScRigidCore()), scShapes, true); + + // not in simulation anymore -> decrement shape ref-counts + void* const* shapes = reinterpret_cast<void*const*>(const_cast<Sc::ShapeCore*const*>(scShapes.begin())); + for(PxU32 i=0; i < scShapes.size(); i++) + { + Scb::Shape& scbShape = *Ps::pointerOffset<Scb::Shape*>(shapes[i], ptrdiff_t(ptrOffset)); + NpShapeDecRefCount(scbShape); + } + } +} + + +void Scb::Scene::switchRigidFromNoSim(Scb::RigidObject& r, bool isDynamic) +{ + PX_ASSERT(!mIsBuffering); + + // when a non-simulation objects has a pending remove and then gets switched to a simulation object, + // we must not process the code below. On sync the object will get removed before this call. + if (r.getControlState() == ControlState::eIN_SCENE) + { + void* const* shapes; + size_t shapePtrOffset = NpShapeGetScPtrOffset(); + size_t ptrOffset = shapePtrOffset - Scb::Shape::getScOffset(); + + PxU32 nbShapes; + if (isDynamic) + { + nbShapes = NpRigidDynamicGetShapes(static_cast<Scb::Body&>(r), shapes); + mScene.addBody(static_cast<Sc::BodyCore&>(r.getScRigidCore()), shapes, nbShapes, shapePtrOffset, NULL); + } + else + { + nbShapes = NpRigidStaticGetShapes(static_cast<Scb::RigidStatic&>(r), shapes); + mScene.addStatic(static_cast<Sc::StaticCore&>(r.getScRigidCore()), shapes, nbShapes, shapePtrOffset, NULL); + } + + // add to simulation -> increment shape ref-counts + for(PxU32 i=0; i < nbShapes; i++) + { + Scb::Shape& scbShape = *Ps::pointerOffset<Scb::Shape*>(shapes[i], ptrdiff_t(ptrOffset)); + NpShapeIncRefCount(scbShape); + } + } +} + + +/////////////////////////////////////////////////////////////////////////////// + +// PT: TODO: +// - consider making these templates not scene member functions + +template<bool TIsDynamic, class T> +PX_FORCE_INLINE void Scb::Scene::addActorT(T& actor, Scb::ObjectTracker& tracker, bool noSim, PxBounds3* uninflatedBounds) +{ + PX_PROFILE_ZONE("API.addActorToSim", getContextId()); + if(!noSim) + { + add<T>(actor, tracker, uninflatedBounds); + actor.initBufferedState(); + + // copy buffer control state from rigid object to shapes and set scene + if(mIsBuffering) + addOrRemoveRigidObject<tSimRunning, tAdd, TIsDynamic, !tNonSimObject>(mScene, actor, false, NULL); + } + else + { + addRigidNoSim<TIsDynamic>(actor, tracker); + actor.initBufferedState(); + } +} + +void Scb::Scene::addActor(Scb::RigidStatic& rigidStatic, bool noSim, PxBounds3* uninflatedBounds) +{ + addActorT<false>(rigidStatic, mRigidStaticManager, noSim, uninflatedBounds); +} + +void Scb::Scene::addActor(Scb::Body& body, bool noSim, PxBounds3* uninflatedBounds) +{ + addActorT<true>(body, mBodyManager, noSim, uninflatedBounds); +} + +/////////////////////////////////////////////////////////////////////////////// + +void Scb::Scene::removeActor(Scb::RigidStatic& rigidStatic, bool wakeOnLostTouch, bool noSim) +{ + PX_PROFILE_ZONE("API.removeActorFromSim", getContextId()); + if (!noSim) + { + remove<Scb::RigidStatic>(rigidStatic, mRigidStaticManager, wakeOnLostTouch); + + // copy buffer control state from rigid object to shapes and set scene + if (mIsBuffering) + { + if (wakeOnLostTouch) + rigidStatic.scheduleForWakeTouching(); + addOrRemoveRigidObject<tSimRunning, !tAdd, !tDynamic, !tNonSimObject>(mScene, rigidStatic, wakeOnLostTouch, NULL); + } + } + else + { + removeRigidNoSim<!tDynamic>(rigidStatic, mRigidStaticManager); + } + + rigidStatic.clearBufferedState(); +} + +void Scb::Scene::removeActor(Scb::Body& body, bool wakeOnLostTouch, bool noSim) +{ + PX_PROFILE_ZONE("API.removeActorFromSim", getContextId()); + if (!noSim) + { + body.clearSimStateDataForPendingInsert(); + + remove<Scb::Body>(body, mBodyManager, wakeOnLostTouch); + body.clearBufferedState(); + + // copy buffer control state from rigid object to shapes and set scene + if (mIsBuffering) + { + if (wakeOnLostTouch) + body.scheduleForWakeTouching(); + addOrRemoveRigidObject<tSimRunning, !tAdd, tDynamic, !tNonSimObject>(mScene, body, wakeOnLostTouch, NULL); + } + } + else + { + removeRigidNoSim<tDynamic>(body, mBodyManager); + + // note: "noSim" refers to the internal state here. The following asserts only apply if the bufferd state has not switched to "sim". + PX_ASSERT(!(body.getActorFlags() & PxActorFlag::eDISABLE_SIMULATION) || body.isSleeping()); + PX_ASSERT(!(body.getActorFlags() & PxActorFlag::eDISABLE_SIMULATION) || !body.isBuffered(BodyBuffer::BF_KinematicTarget | BodyBuffer::BF_Acceleration | BodyBuffer::BF_DeltaVelocity)); + // What about velocity, wakeCounter, ...? + // Those are not allowed on a no-sim object, however, they might still be necessary due to complex buffering scenarios: + // Imagine the following operation flow (all buffered): + // - dynamic sim object awake with velocities + // - switch to no-sim -> needs to clear velocities, wake counter, put to sleep, ... + // - switch back to sim -> the velocities, wake counter, ... still need to get cleared and it needs to be asleep (that would be the non-buffered behavior of the operations) + + body.clearBufferedState(); // this also covers the buffered case where a noSim object gets switched to a sim object, followed by a wakeUp() call and then a remove. + // If we checked whether the buffered object is still a noSim object then only body.RigidObject::clearBufferedState() would be necessary. + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void Scb::Scene::addConstraint(Scb::Constraint& constraint) +{ + add<Scb::Constraint>(constraint, mConstraintManager, NULL); +} + +void Scb::Scene::removeConstraint(Scb::Constraint& constraint) +{ + if (!mIsBuffering) + { + mScene.removeConstraint(constraint.getScConstraint()); + + // Release pvd constraint immediately since delayed removal with already released ext::joints does not work, can't call callback. + if(constraint.getControlState() != ControlState::eINSERT_PENDING) + RELEASE_PVD_INSTANCE(&constraint) + + constraint.resetControl(ControlState::eNOT_IN_SCENE); + constraint.setScbScene(NULL); + } + else + { + mConstraintManager.scheduleForRemove(constraint); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void Scb::Scene::addArticulation(Scb::Articulation& articulation) +{ + add<Scb::Articulation>(articulation, mArticulationManager, NULL); + articulation.initBufferedState(); +} + +void Scb::Scene::removeArticulation(Scb::Articulation& articulation) +{ + remove<Scb::Articulation>(articulation, mArticulationManager); + articulation.clearBufferedState(); +} + +/////////////////////////////////////////////////////////////////////////////// + +void Scb::Scene::addArticulationJoint(Scb::ArticulationJoint& joint) +{ + add<Scb::ArticulationJoint>(joint, mArticulationJointManager, NULL); +} + +void Scb::Scene::removeArticulationJoint(Scb::ArticulationJoint& joint) +{ + remove<Scb::ArticulationJoint>(joint, mArticulationJointManager); +} + +/////////////////////////////////////////////////////////////////////////////// + +void Scb::Scene::addAggregate(Scb::Aggregate& agg) +{ + agg.setScbScene(this); + + if (!mIsBuffering) + { + PxU32 aggregateID = mScene.createAggregate(agg.mPxAggregate, agg.getSelfCollide()); + agg.setAggregateID(aggregateID); + agg.resetControl(ControlState::eIN_SCENE); +#if PX_SUPPORT_PVD + //Sending pvd events after all aggregates's actors are inserted into scene + mScenePvdClient.createPvdInstance(&agg); +#endif + } + else + mAggregateManager.scheduleForInsert(agg); +} + + +void Scb::Scene::removeAggregate(Scb::Aggregate& agg) +{ + if (!mIsBuffering) + { + mScene.deleteAggregate(agg.getAggregateID()); + agg.resetControl(ControlState::eNOT_IN_SCENE); + agg.setScbScene(NULL); +#if PX_SUPPORT_PVD + mScenePvdClient.releasePvdInstance(&agg); +#endif + } + else + { + mAggregateManager.scheduleForRemove(agg); + } +} + + +void Scb::Scene::addMaterial(const Sc::MaterialCore& material) +{ + Ps::Mutex::ScopedLock lock(mSceneMaterialBufferLock); + + mSceneMaterialBuffer.pushBack(MaterialEvent(material.getMaterialIndex(), MATERIAL_ADD)); + + CREATE_PVD_INSTANCE(&material) +} + +void Scb::Scene::updateMaterial(const Sc::MaterialCore& material) +{ + Ps::Mutex::ScopedLock lock(mSceneMaterialBufferLock); + + mSceneMaterialBuffer.pushBack(MaterialEvent(material.getMaterialIndex(), MATERIAL_UPDATE)); + + UPDATE_PVD_PROPERTIES(&material) +} + +void Scb::Scene::removeMaterial(const Sc::MaterialCore& material) +{ + if(material.getMaterialIndex() == MATERIAL_INVALID_HANDLE) + return; + + Ps::Mutex::ScopedLock lock(mSceneMaterialBufferLock); + + mSceneMaterialBuffer.pushBack(MaterialEvent(material.getMaterialIndex(), MATERIAL_REMOVE)); + + RELEASE_PVD_INSTANCE(&material); +} + +/////////////////////////////////////////////////////////////////////////////// + +#if PX_USE_PARTICLE_SYSTEM_API +void Scb::Scene::addParticleSystem(Scb::ParticleSystem& ps) +{ + add<Scb::ParticleSystem>(ps, mParticleSystemManager, NULL); +} + +void Scb::Scene::removeParticleSystem(Scb::ParticleSystem& ps, bool isRelease) +{ + if (!mIsBuffering) + { + RELEASE_PVD_INSTANCE(&ps) + ps.removeFromScene(); + mScene.removeParticleSystem(ps.getScParticleSystem(), isRelease); + ps.resetControl(ControlState::eNOT_IN_SCENE); + ps.setScbScene(NULL); + } + else + { + mParticleSystemManager.scheduleForRemove(ps); + } +} +#endif + + +/////////////////////////////////////////////////////////////////////////////// + +#if PX_USE_CLOTH_API +void Scb::Scene::addCloth(Scb::Cloth& cl) +{ + cl.setScbScene(this); + + if (!mIsBuffering) + { + if (mScene.addCloth(cl.getScCloth())) + { + cl.resetControl(ControlState::eIN_SCENE); + CREATE_PVD_INSTANCE(&cl) + } + else + Ps::getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __LINE__, "Adding cloth to the scene failed!"); + } + else + mClothManager.scheduleForInsert(cl); +} + +void Scb::Scene::removeCloth(Scb::Cloth& cl) +{ + if (!mIsBuffering) + { + RELEASE_PVD_INSTANCE(&cl) + mScene.removeCloth(cl.getScCloth()); + cl.resetControl(ControlState::eNOT_IN_SCENE); + cl.setScbScene(NULL); + } + else + { + mClothManager.scheduleForRemove(cl); + } +} +#endif // PX_USE_CLOTH_API + +/////////////////////////////////////////////////////////////////////////////// + +void Scb::Scene::updateLowLevelMaterial(NpMaterial** masterMaterial) +{ + Ps::Mutex::ScopedLock lock(mSceneMaterialBufferLock); + + //sync all the material events + PxsMaterialManager& manager = mScene.getMaterialManager(); + for(PxU32 i=0; i< mSceneMaterialBuffer.size(); ++i) + { + const MaterialEvent& event = mSceneMaterialBuffer[i]; + const NpMaterial* masMat = masterMaterial[event.mHandle]; + switch(event.mType) + { + case MATERIAL_ADD: + if(masMat) + { + Sc::MaterialCore* materialCore = &masterMaterial[event.mHandle]->getScMaterial(); + manager.setMaterial(materialCore); + mScene.registerMaterialInNP(*materialCore); + } + break; + case MATERIAL_UPDATE: + if(masMat) + { + Sc::MaterialCore* materialCore = &masterMaterial[event.mHandle]->getScMaterial(); + manager.updateMaterial(materialCore); + mScene.updateMaterialInNP(*materialCore); + } + break; + case MATERIAL_REMOVE: + if (event.mHandle < manager.getMaxSize()) // materials might get added and then removed again immediately. However, the add does not get processed (see case MATERIAL_ADD above), + { // so the remove might end up reading out of bounds memory unless checked. + PxsMaterialCore* materialCore = manager.getMaterial(event.mHandle); + mScene.unregisterMaterialInNP(*materialCore); + manager.removeMaterial(materialCore); + } + break; + }; + } + + mSceneMaterialBuffer.resize(0); +} + +/////////////////////////////////////////////////////////////////////////////// +#if PX_USE_PARTICLE_SYSTEM_API +void Scb::Scene::preSimulateUpdateAppThread(PxReal timeStep) +{ + // Submit applied forces to particle systems + PxU32 nbParticleSystems = mScene.getNbParticleSystems(); + Sc::ParticleSystemCore* const* particleSystems = mScene.getParticleSystems(); + for(PxU32 i=0; i < nbParticleSystems; i++) + Scb::ParticleSystem::fromSc(*particleSystems[i]).submitForceUpdates(timeStep); +} +#endif + +//-------------------------------------------------------------- +// +// Data synchronization +// +//-------------------------------------------------------------- +void Scb::Scene::syncState() +{ + //process client creation -- must be done before BF_CLIENT_BEHAVIOR_FLAGS processing in the below block: + while (mBufferedData.numClientsCreated) + { + mScene.createClient(); + mBufferedData.numClientsCreated--; + } + + if (mBufferFlags) + { + if (isBuffered(BF_GRAVITY)) + mScene.setGravity(mBufferedData.gravity); + + if(isBuffered(BF_BOUNCETHRESHOLDVELOCITY)) + mScene.setBounceThresholdVelocity(mBufferedData.bounceThresholdVelocity); + + if (isBuffered(BF_FLAGS)) + mScene.setPublicFlags(mBufferedData.flags); + + if (isBuffered(BF_DOMINANCE_PAIRS)) + mBufferedData.syncDominancePairs(mScene); + + if (isBuffered(BF_SOLVER_BATCH_SIZE)) + mScene.setSolverBatchSize(mBufferedData.solverBatchSize); + + if (isBuffered(BF_CLIENT_BEHAVIOR_FLAGS)) + { + for (PxU32 i = 0; i < mBufferedData.clientBehaviorFlags.size(); i++) + { + if (mBufferedData.clientBehaviorFlags[i] != PxClientBehaviorFlag_eNOT_BUFFERED) //not PxClientBehaviorFlag_eNOT_BUFFERED means it was written. + { + mScene.setClientBehaviorFlags(PxClientID(i), mBufferedData.clientBehaviorFlags[i]); + mBufferedData.clientBehaviorFlags[i] = PxClientBehaviorFlag_eNOT_BUFFERED; + } + + } + } + + if (isBuffered(BF_VISUALIZATION)) + { + for(PxU32 i=0; i < PxVisualizationParameter::eNUM_VALUES; i++) + { + if (mBufferedData.visualizationParamChanged[i]) + { + mScene.setVisualizationParameter(static_cast<PxVisualizationParameter::Enum>(i), mBufferedData.visualizationParam[i]); + } + } + } + +#if PX_SUPPORT_PVD + if(mScenePvdClient.checkPvdDebugFlag()) + mScenePvdClient.updatePvdProperties(); +#endif + } + + + mBufferFlags = 0; + mBufferedData.clearDominanceBuffer(); + mBufferedData.clearVisualizationParams(); +} + +template<typename T> +void Scb::Scene::processUserUpdates(ObjectTracker &tracker) +{ +#if PX_SUPPORT_PVD + bool isPvdValid = mScenePvdClient.checkPvdDebugFlag(); +#endif + Base*const * buffered = tracker.getBuffered(); + for(PxU32 i=0; i < tracker.getBufferedCount(); i++) + { + T& v = *static_cast<T*>(buffered[i]); + if (v.getControlState() == ControlState::eINSERT_PENDING) + { + ScSceneFns<T>::insert(mScene, v, NULL); +#if PX_SUPPORT_PVD + if(isPvdValid) + PvdFns<T>::createInstance(*this, mScenePvdClient, &v); +#endif + } + else if(v.getControlFlags() & ControlFlag::eIS_UPDATED) + { + v.syncState(); +#if PX_SUPPORT_PVD + if(isPvdValid) + PvdFns<T>::updateInstance(*this, mScenePvdClient, &v); +#endif + } + } +} + +template<typename T, typename S> +void Scb::Scene::processSimUpdates(S*const * scObjects, PxU32 nbObjects) +{ +#if PX_SUPPORT_PVD + bool isPvdValid = mScenePvdClient.checkPvdDebugFlag(); +#endif + for(PxU32 i=0;i<nbObjects;i++) + { + T& v = T::fromSc(*scObjects[i]); + + if(!(v.getControlFlags() & ControlFlag::eIS_UPDATED)) // else the data will be synced further below + { + v.syncState(); +#if PX_SUPPORT_PVD + if(isPvdValid) + PvdFns<T>::updateInstance(*this, mScenePvdClient, &v); +#endif + } + } +} + +#define ENABLE_PVD_ORIGINSHIFT_EVENT +void Scb::Scene::shiftOrigin(const PxVec3& shift) +{ + PX_ASSERT(!isPhysicsBuffering()); + mScene.shiftOrigin(shift); + +#ifdef ENABLE_PVD_ORIGINSHIFT_EVENT + PVD_ORIGIN_SHIFT(shift); +#endif +} + +void Scb::Scene::syncWriteThroughProperties() +{ + mStream.lock(); + + Base*const * buffered = mBodyManager.getBuffered(); + PxU32 count = mBodyManager.getBufferedCount(); + for(PxU32 i=0; i < count; i++) + { + Scb::Body& bufferedBody = *static_cast<Scb::Body*>(buffered[i]); + bufferedBody.syncCollisionWriteThroughState(); + } + + mStream.unlock(); +} + +void Scb::Scene::syncEntireScene(PxU32* error) +{ + PX_PROFILE_ZONE("Sim.syncState", getContextId()); + if (error) + *error = mScene.getErrorState(); + + mStream.lock(); + syncState(); + // + // Process aggregates (needs to be done before adding actors because the actor's aggregateID needs to get set) + // + + for(PxU32 i=0; i < mAggregateManager.getBufferedCount(); i++) + { + Aggregate* a = static_cast<Aggregate*>(mAggregateManager.getBuffered()[i]); + if (a->getControlState() == ControlState::eINSERT_PENDING) + { + PxU32 aggregateID = mScene.createAggregate(a->mPxAggregate, a->getSelfCollide()); + a->setAggregateID(aggregateID); +#if PX_SUPPORT_PVD + mScenePvdClient.createPvdInstance(a); +#endif + a->syncState(*this); // Necessary to set the aggregate ID for all actors of the aggregate + } + else if(a->getControlFlags() & ControlFlag::eIS_UPDATED) + { + a->syncState(*this); + } + } + mAggregateManager.clear(); + mActorPtrBuffer.clear(); + + + // rigid statics + processUserUpdates<Scb::RigidStatic>(mRigidStaticManager); + mRigidStaticManager.clear(); + + + // rigid dynamics and articulation links + // + // 1) Sync simulation changed data + { + Sc::BodyCore*const* activeBodies = mScene.getActiveBodiesArray(); + PxU32 nbActiveBodies = mScene.getNumActiveBodies(); + while(nbActiveBodies--) + { + Sc::BodyCore* bodyCore = *activeBodies++; + Scb::Body& bufferedBody = Scb::Body::fromSc(*bodyCore); + if (!(bufferedBody.getControlFlags() & ControlFlag::eIS_UPDATED)) // Else the data will be synced further below + bufferedBody.syncState(); + } + } + + // 2) Sync data of rigid dynamics which were put to sleep by the simulation + + PxU32 nbSleepingBodies; + Sc::BodyCore* const* sleepingBodies = mScene.getSleepBodiesArray(nbSleepingBodies); + processSimUpdates<Scb::Body, Sc::BodyCore>(sleepingBodies, nbSleepingBodies); + + // user updates + processUserUpdates<Scb::Body>(mBodyManager); + mBodyManager.clear(); + mShapePtrBuffer.clear(); + + + // rigid body shapes + // + // IMPORTANT: This has to run after the material update + // + // Sync user changed data. Inserts and removes are handled in actor sync + for(PxU32 i=0; i < mShapeManager.getBufferedCount(); i++) + { + Scb::Shape* s = static_cast<Scb::Shape*>(mShapeManager.getBuffered()[i]); + + if(s->getControlFlags() & ControlFlag::eIS_UPDATED) + { + s->syncState(); + UPDATE_PVD_PROPERTIES(s) + } + } + + mShapeManager.clear(); + mShapeMaterialBuffer.clear(); + + // constraints (get break force and broken status from sim) + + processSimUpdates<Scb::Constraint, Sc::ConstraintCore>(mScene.getConstraints(), mScene.getNbConstraints()); + processUserUpdates<Scb::Constraint>(mConstraintManager); + mConstraintManager.clear(); + + + // articulations (get sleep state from sim) + + processSimUpdates<Scb::Articulation, Sc::ArticulationCore>(mScene.getArticulations(), mScene.getNbArticulations()); + processUserUpdates<Scb::Articulation>(mArticulationManager); + mArticulationManager.clear(); + + + // Process articulation joints + + processUserUpdates<Scb::ArticulationJoint>(mArticulationJointManager); + mArticulationJointManager.clear(); + +#if PX_USE_PARTICLE_SYSTEM_API + // + // Process particle systems + // + // 1) Sync simulation changed data + + PxU32 nbParticleSystems = mScene.getNbParticleSystems(); + Sc::ParticleSystemCore* const* particleSystems = mScene.getParticleSystems(); + for(PxU32 i=0; i < nbParticleSystems; i++) + { + Scb::ParticleSystem& scbParticleSystem = Scb::ParticleSystem::fromSc(*particleSystems[i]); + scbParticleSystem.syncState(); + if(scbParticleSystem.hasUpdates()) + UPDATE_PVD_PROPERTIES(&scbParticleSystem) + } + + // 2) Sync user changed data + for(PxU32 i=0; i < mParticleSystemManager.getBufferedCount(); i++) + { + ParticleSystem* p = static_cast<ParticleSystem*>(mParticleSystemManager.getBuffered()[i]); + + //special handling to release bulk buffer data + if (p->getControlState() == ControlState::eREMOVE_PENDING) + p->removeFromScene(); + + else if (p->getControlState() == ControlState::eINSERT_PENDING) + { + mScene.addParticleSystem(p->getScParticleSystem()); + CREATE_PVD_INSTANCE(p) + } + } + mParticleSystemManager.clear(); +#endif + +#if PX_USE_CLOTH_API + // + // Process cloth + // + // Pending insert & sync user changed data + + for(PxU32 i=0; i < mClothManager.getBufferedCount(); i++) + { + Cloth* cl = static_cast<Cloth*>(mClothManager.getBuffered()[i]); + if (cl->getControlState() == ControlState::eINSERT_PENDING) + { + if (mScene.addCloth(cl->getScCloth())) + { + CREATE_PVD_INSTANCE(cl) + } + else + Ps::getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __LINE__, "Adding cloth to the scene failed!"); + } + // no need yet + //else if(cl->getControlFlags() & ControlFlag::eIS_UPDATED) + //{ + // cl->syncState(); + // UPDATE_PVD_PROPERTIES(pvdConnected, cl) + //} + } + mClothManager.clear(); +#endif // PX_USE_CLOTH_API + + mStream.clearNotThreadSafe(); + mStream.unlock(); +} + + + +template<typename T, bool syncOnRemove, bool wakeOnLostTouchCheck> +void Scb::Scene::processRemoves(ObjectTracker& tracker) +{ +#if PX_SUPPORT_PVD + bool isPvdValid = mScenePvdClient.checkPvdDebugFlag(); +#endif + typedef ScSceneFns<T> Fns; + for(PxU32 i=0; i < tracker.getBufferedCount(); i++) + { + T* v = static_cast<T*>(tracker.getBuffered()[i]); + if(v->getControlState() == ControlState::eREMOVE_PENDING) + { + bool wakeOnLostTouch = false; + if (wakeOnLostTouchCheck) + { + PX_ASSERT( (v->getScbType() == ScbType::BODY) || + (v->getScbType() == ScbType::BODY_FROM_ARTICULATION_LINK) || + (v->getScbType() == ScbType::RIGID_STATIC) ); + wakeOnLostTouch = (v->Base::isBuffered(RigidObjectBuffer::BF_WakeTouching) != 0); // important to use Scb::Base::isBuffered() because Scb::Body, for example, has a shadowed implementation of this method + } + + Fns::remove(mScene, *v, wakeOnLostTouch); + + // if no object param has been updated, the state sync still needs to be processed to write simulation results + // back to the permanently buffered params. + if (syncOnRemove && !(v->getControlFlags() & ControlFlag::eIS_UPDATED)) + v->syncState(); +#if PX_SUPPORT_PVD + if(isPvdValid) + PvdFns<T>::releaseInstance(*this, mScenePvdClient, v); +#endif + } + } +} + +template<typename T> +void Scb::Scene::processShapeRemoves(ObjectTracker& tracker) +{ + for(PxU32 i=0; i < tracker.getBufferedCount(); i++) + { + T* v = static_cast<T*>(tracker.getBuffered()[i]); + v->processShapeRemoves(); + } +} + +void Scb::Scene::processPendingRemove() +{ + processShapeRemoves<Scb::RigidStatic>(mRigidStaticManager); + processShapeRemoves<Scb::Body>(mBodyManager); + + processRemoves<Scb::Constraint, tSyncOnRemove, !tWakeOnLostTouchCheck>(mConstraintManager); + + Scb::Base *const * buffered = mConstraintManager.getBuffered(); + for(PxU32 i=0; i < mConstraintManager.getBufferedCount(); i++) + { + Scb::Constraint* constraint = static_cast<Scb::Constraint*>(buffered[i]); + + if(constraint->getControlFlags() & ControlFlag::eIS_UPDATED) + constraint->prepareForActorRemoval(); // see comments in Scb::Constraint + } + + processRemoves<Scb::ArticulationJoint, !tSyncOnRemove, !tWakeOnLostTouchCheck> (mArticulationJointManager); + processRemoves<Scb::RigidStatic, !tSyncOnRemove, tWakeOnLostTouchCheck> (mRigidStaticManager); + processRemoves<Scb::Body, tSyncOnRemove, tWakeOnLostTouchCheck> (mBodyManager); + processRemoves<Scb::Articulation, tSyncOnRemove, !tWakeOnLostTouchCheck> (mArticulationManager); + +#if PX_USE_PARTICLE_SYSTEM_API + processRemoves<Scb::ParticleSystem, !tSyncOnRemove, !tWakeOnLostTouchCheck> (mParticleSystemManager); +#endif + +#if PX_USE_CLOTH_API + processRemoves<Scb::Cloth, !tSyncOnRemove, !tWakeOnLostTouchCheck> (mClothManager); +#endif + + // Do after actors have been removed (coumpound can only be removed after all its elements are gone) + for(PxU32 i=0; i < mAggregateManager.getBufferedCount(); i++) + { + Aggregate* a = static_cast<Aggregate*>(mAggregateManager.getBuffered()[i]); + + if(a->getControlState() == ControlState::eREMOVE_PENDING) + { + a->syncState(*this); // Clears the aggregate ID for all actors of the aggregate + mScene.deleteAggregate(a->getAggregateID()); + +#if PX_SUPPORT_PVD + mScenePvdClient.releasePvdInstance(a); +#endif + } + } + + +} + +void Scb::Scene::scheduleForUpdate(Scb::Base& object) +{ + switch(object.getScbType()) + { + case ScbType::SHAPE_EXCLUSIVE: + case ScbType::SHAPE_SHARED: { mShapeManager.scheduleForUpdate(object); }break; + case ScbType::BODY: { mBodyManager.scheduleForUpdate(object); }break; + case ScbType::BODY_FROM_ARTICULATION_LINK: { mBodyManager.scheduleForUpdate(object); }break; + case ScbType::RIGID_STATIC: { mRigidStaticManager.scheduleForUpdate(object); }break; + case ScbType::CONSTRAINT: { mConstraintManager.scheduleForUpdate(object); }break; +#if PX_USE_PARTICLE_SYSTEM_API + case ScbType::PARTICLE_SYSTEM: { mParticleSystemManager.scheduleForUpdate(object); }break; +#endif + case ScbType::ARTICULATION: { mArticulationManager.scheduleForUpdate(object); }break; + case ScbType::ARTICULATION_JOINT: { mArticulationJointManager.scheduleForUpdate(object); }break; + case ScbType::AGGREGATE: { mAggregateManager.scheduleForUpdate(object); }break; +#if PX_USE_CLOTH_API + case ScbType::CLOTH: { mClothManager.scheduleForUpdate(object); }break; +#endif + case ScbType::UNDEFINED: + case ScbType::TYPE_COUNT: + PX_ALWAYS_ASSERT_MESSAGE( "scheduleForUpdate: missing type!"); + break; + } +} + +PxU8* Scb::Scene::getStream(ScbType::Enum type) +{ + PxU8* memory = NULL; + switch(type) + { + case ScbType::SHAPE_EXCLUSIVE: + case ScbType::SHAPE_SHARED: { memory = reinterpret_cast<PxU8*>(mStream.allocateNotThreadSafe(sizeof(Scb::ShapeBuffer))); new (memory) Scb::ShapeBuffer; }break; + case ScbType::BODY: { memory = reinterpret_cast<PxU8*>(mStream.allocateNotThreadSafe(sizeof(Scb::BodyBuffer))); new (memory) Scb::BodyBuffer; }break; + case ScbType::BODY_FROM_ARTICULATION_LINK: { memory = reinterpret_cast<PxU8*>(mStream.allocateNotThreadSafe(sizeof(Scb::BodyBuffer))); new (memory) Scb::BodyBuffer; }break; + case ScbType::RIGID_STATIC: { memory = reinterpret_cast<PxU8*>(mStream.allocateNotThreadSafe(sizeof(Scb::RigidStaticBuffer))); new (memory) Scb::RigidStaticBuffer; }break; + case ScbType::CONSTRAINT: { memory = reinterpret_cast<PxU8*>(mStream.allocateNotThreadSafe(sizeof(Scb::ConstraintBuffer))); new (memory) Scb::ConstraintBuffer; }break; +#if PX_USE_PARTICLE_SYSTEM_API + case ScbType::PARTICLE_SYSTEM: { memory = reinterpret_cast<PxU8*>(mStream.allocateNotThreadSafe(sizeof(Scb::ParticleSystemBuffer))); new (memory) Scb::ParticleSystemBuffer; }break; +#endif + case ScbType::ARTICULATION: { memory = reinterpret_cast<PxU8*>(mStream.allocateNotThreadSafe(sizeof(Scb::ArticulationBuffer))); new (memory) Scb::ArticulationBuffer; }break; + case ScbType::ARTICULATION_JOINT: { memory = reinterpret_cast<PxU8*>(mStream.allocateNotThreadSafe(sizeof(Scb::ArticulationJointBuffer))); new (memory) Scb::ArticulationJointBuffer; }break; + case ScbType::AGGREGATE: { memory = reinterpret_cast<PxU8*>(mStream.allocateNotThreadSafe(sizeof(Scb::AggregateBuffer))); new (memory) Scb::AggregateBuffer; }break; + +#if PX_USE_CLOTH_API + case ScbType::CLOTH: +#endif + case ScbType::UNDEFINED: + case ScbType::TYPE_COUNT: + PX_ALWAYS_ASSERT_MESSAGE("getStream: missing type!"); + return NULL; + } + return memory; +} + +/////////////////////////////////////////////////////////////////////////////// + +PxBroadPhaseType::Enum Scb::Scene::getBroadPhaseType() const +{ + return mScene.getBroadPhaseType(); +} + +bool Scb::Scene::getBroadPhaseCaps(PxBroadPhaseCaps& caps) const +{ + return mScene.getBroadPhaseCaps(caps); +} + +PxU32 Scb::Scene::getNbBroadPhaseRegions() const +{ + return mScene.getNbBroadPhaseRegions(); +} + +PxU32 Scb::Scene::getBroadPhaseRegions(PxBroadPhaseRegionInfo* userBuffer, PxU32 bufferSize, PxU32 startIndex) const +{ + return mScene.getBroadPhaseRegions(userBuffer, bufferSize, startIndex); +} + +PxU32 Scb::Scene::addBroadPhaseRegion(const PxBroadPhaseRegion& region, bool populateRegion) +{ + if(!isPhysicsBuffering()) + return mScene.addBroadPhaseRegion(region, populateRegion); + else + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::addBroadPhaseRegion() not allowed while simulation is running. Call will be ignored."); + return 0xffffffff; +} + +bool Scb::Scene::removeBroadPhaseRegion(PxU32 handle) +{ + if(!isPhysicsBuffering()) + return mScene.removeBroadPhaseRegion(handle); + else + Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::removeBroadPhaseRegion() not allowed while simulation is running. Call will be ignored."); + return false; +} + +////////////////////////////////////////////////////////////////////////// + +// +// To avoid duplication of a lot of similar code, the following templated method was introduced. Its main purpose is to +// take care of all the operations related to adding/removing a rigid object to/from the scene. Depending on the type +// of rigid object and the simulation state, there are slight changes to the code flow necessary. Among the operations are: +// +// - Add/remove rigid object to/from scene +// - Add/remove shapes from PVD +// - Adjust buffer control state of shapes +// - Adjust ref-count of shapes +// +template <bool TSimRunning, bool TAdd, bool TIsDynamic, bool TIsNonSimObject, class T> +PX_FORCE_INLINE static void addOrRemoveRigidObject(Sc::Scene& s, T& rigidObject, bool wakeOnLostTouch, PxBounds3* uninflatedBounds) +{ + PX_ASSERT(TIsDynamic || (rigidObject.getScbType() == ScbType::RIGID_STATIC)); + if (TSimRunning && TIsNonSimObject && TAdd) + PX_ASSERT(rigidObject.getActorFlags() & PxActorFlag::eDISABLE_SIMULATION); + if (TSimRunning && TIsNonSimObject&& !TAdd) + PX_ASSERT(rigidObject.isSimDisabledInternally()); + if (!TSimRunning && TIsNonSimObject) + PX_ASSERT(rigidObject.isSimDisabledInternally()); // when the simulation flag gets cleared on an object with pending removal, only the core flag knows that internally it is still a non-simulation object. + PX_ASSERT(!uninflatedBounds || (TAdd && !TSimRunning && !TIsNonSimObject)); + + Ps::InlineArray<const Sc::ShapeCore*, 64> localShapes; + Ps::InlineArray<const Sc::ShapeCore*, 64>& scShapes = s.getBatchRemove() ? s.getBatchRemove()->removedShapes : localShapes; + + PxActor* pxActor = NULL; + void* const* shapes; + PxU32 nbShapes; + size_t shapePtrOffset = NpShapeGetScPtrOffset(); + + Scb::Body& dynamicObject = reinterpret_cast<Scb::Body&>(rigidObject); + Scb::RigidStatic& staticObject = reinterpret_cast<Scb::RigidStatic&>(rigidObject); + + if (!TSimRunning) + { + if (TIsDynamic) + pxActor = dynamicObject.getScBody().getPxActor(); + else + pxActor = staticObject.getScStatic().getPxActor(); + } + PX_UNUSED(pxActor); + size_t ptrOffset; + if (TAdd || TSimRunning || TIsNonSimObject) + { + // Np buffers are still valid when the object gets removed while the sim is running. + // Furthermore, for non-simulation objects, there exists no shape buffer in the simulation controller + // and we need to fetch from Np all the time. + + ptrOffset = shapePtrOffset - Scb::Shape::getScOffset(); + + if (TIsDynamic) + nbShapes = NpRigidDynamicGetShapes(dynamicObject, shapes); + else + nbShapes = NpRigidStaticGetShapes(staticObject, shapes); + } + + if ((!TSimRunning) && (!TIsNonSimObject)) + { + if (TAdd) + { + if (TIsDynamic) + s.addBody(dynamicObject.getScBody(), shapes, nbShapes, shapePtrOffset, uninflatedBounds); + else + s.addStatic(staticObject.getScStatic(), shapes, nbShapes, shapePtrOffset, uninflatedBounds); + } + else + { + ptrOffset = -Scb::Shape::getScOffset(); + + if (TIsDynamic) + s.removeBody(dynamicObject.getScBody(), scShapes, wakeOnLostTouch); + else + s.removeStatic(staticObject.getScStatic(), scShapes, wakeOnLostTouch); + + shapes = reinterpret_cast<void*const*>(const_cast<Sc::ShapeCore*const*>(scShapes.begin())); + nbShapes = scShapes.size(); + } + } + + Scb::Scene* scbScene = rigidObject.getScbScene(); + Scb::Scene* shapeScenePtr = scbScene; + Scb::ControlState::Enum controlState = rigidObject.getControlState(); + + if (!TSimRunning) + { + // hacky: in the non-buffered case the rigid objects might not have been updated properly at this point, so it's done explicitly. + + if (TAdd) + { + PX_ASSERT(shapeScenePtr == scbScene); + controlState = Scb::ControlState::eIN_SCENE; + } + else + { + shapeScenePtr = NULL; + controlState = Scb::ControlState::eNOT_IN_SCENE; + } + } + + for(PxU32 i=0; i < nbShapes; i++) + { + Scb::Shape& scbShape = *Ps::pointerOffset<Scb::Shape*>(shapes[i], ptrdiff_t(ptrOffset)); + + if (!TSimRunning) + { + PX_ASSERT(pxActor); + PX_ASSERT(scbScene); + + if (TAdd) + { + scbShape.setControlStateIfExclusive(shapeScenePtr, controlState); + + if (!TIsNonSimObject) + NpShapeIncRefCount(scbShape); // simulation increases the refcount to avoid that shapes get destroyed while the sim is running + +#if PX_SUPPORT_PVD + scbScene->getScenePvdClient().createPvdInstance(&scbShape, *pxActor); +#endif + } + else + { + scbShape.checkUpdateOnRemove<true>(scbScene); + +#if PX_SUPPORT_PVD + scbScene->getScenePvdClient().releasePvdInstance(&scbShape, *pxActor); +#endif + scbShape.setControlStateIfExclusive(shapeScenePtr, controlState); + + if (!TIsNonSimObject) + NpShapeDecRefCount(scbShape); // see comment in the "TAdd" section above + } + } + else + scbShape.setControlStateIfExclusive(shapeScenePtr, controlState); + } +} |