// // 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. #ifndef PX_PHYSICS_SCB_SCENE #define PX_PHYSICS_SCB_SCENE #include "ScScene.h" #include "ScbSceneBuffer.h" #include "ScbType.h" #include "PsFoundation.h" #include "PsMutex.h" #include "PsHashSet.h" #if PX_SUPPORT_PVD #include "PxPhysics.h" #include "ScbScenePvdClient.h" #endif namespace physx { class NpMaterial; namespace Sc { class BodyDesc; } namespace Gu { class BVHStructure; } namespace Scb { class Base; class RigidObject; class RigidStatic; class Body; class Actor; class Shape; class Constraint; class Material; class Articulation; class ArticulationJoint; class Aggregate; struct ShapeBuffer; /** \brief Helper class to track inserted/removed/updated buffering objects. */ class ObjectTracker { public: ObjectTracker() {} /** \brief An object has been inserted while the simulation was running -> track it for insertion at sync point */ void scheduleForInsert(Base& element); /** \brief An object has been removed while the simulation was running -> track it for removal at sync point */ void scheduleForRemove(Base& element); /** \brief An object has been changed while the simulation was running -> track it for update at sync point */ void scheduleForUpdate(Base& element); /** \brief Get the list of dirty objects that require processing at a sync point. */ Base*const * getBuffered() { return mBuffered.getEntries(); } /** \brief Get number of dirty objects that require processing at a sync point. */ PxU32 getBufferedCount() const { return mBuffered.size(); } /** \brief Cleanup dirty objects after sync point. \li Transition pending insertion objects from eINSERT_PENDING to eIN_SCENE. \li Transition pending removal objects from eREMOVE_PENDING to eNOT_IN_SCENE. \li Destroy objects marked as eIS_RELEASED. \li Clear dirty list. */ void clear(); void insert(Base& element); void remove(Base& element); private: Ps::CoalescedHashSet mBuffered; }; typedef ObjectTracker ShapeManager; typedef ObjectTracker RigidStaticManager; typedef ObjectTracker BodyManager; typedef ObjectTracker ArticulationManager; typedef ObjectTracker ConstraintManager; typedef ObjectTracker ArticulationJointManager; typedef ObjectTracker AggregateManager; enum MATERIAL_EVENT { MATERIAL_ADD, MATERIAL_UPDATE, MATERIAL_REMOVE }; class MaterialEvent { public: PX_FORCE_INLINE MaterialEvent(PxU16 handle, MATERIAL_EVENT type) : mHandle(handle), mType(type) {} PX_FORCE_INLINE MaterialEvent() {} PxU16 mHandle;//handle to the master material table MATERIAL_EVENT mType; }; class Scene : public Ps::UserAllocated { PX_NOCOPY(Scene) public: enum BufferFlag { BF_GRAVITY = (1 << 0), BF_BOUNCETHRESHOLDVELOCITY = (1 << 1), BF_FLAGS = (1 << 2), BF_DOMINANCE_PAIRS = (1 << 3), BF_SOLVER_BATCH_SIZE = (1 << 4), BF_VISUALIZATION = (1 << 5), BF_CULLING_BOX = (1 << 6), BF_SOLVER_ARTIC_BATCH_SIZE = (1 << 7) }; public: Scene(const PxSceneDesc& desc, PxU64 contextID); ~Scene() {} //use release() plz. //--------------------------------------------------------------------------------- // Wrapper for Sc::Scene interface //--------------------------------------------------------------------------------- void release(); PxScene* getPxScene(); PX_INLINE void setGravity(const PxVec3& gravity); PX_INLINE PxVec3 getGravity() const; PX_INLINE void setBounceThresholdVelocity(const PxReal t); PX_INLINE PxReal getBounceThresholdVelocity() const; PX_INLINE void setFlags(PxSceneFlags flags); PX_INLINE PxSceneFlags getFlags() const; PX_INLINE void setFrictionType(PxFrictionType::Enum type) { mScene.setFrictionType(type); } PX_INLINE PxFrictionType::Enum getFrictionType() const { return mScene.getFrictionType(); } void addActor(Scb::RigidStatic&, bool noSim, PxBounds3* uninflatedBounds, const Gu::BVHStructure* bvhStructure); void removeActor(Scb::RigidStatic&, bool wakeOnLostTouch, bool noSim); void addActor(Scb::Body&, bool noSim, PxBounds3* uninflatedBounds, const Gu::BVHStructure* bvhStructure); void removeActor(Scb::Body&, bool wakeOnLostTouch, bool noSim); void addConstraint(Scb::Constraint&); void removeConstraint(Scb::Constraint&); void addArticulation(Scb::Articulation&); void removeArticulation(Scb::Articulation&); void addArticulationJoint(Scb::ArticulationJoint&); void removeArticulationJoint(Scb::ArticulationJoint&); void addAggregate(Scb::Aggregate&); void removeAggregate(Scb::Aggregate&); void addMaterial(const Sc::MaterialCore& mat); void updateMaterial(const Sc::MaterialCore& mat); void removeMaterial(const Sc::MaterialCore& mat); void updateLowLevelMaterial(NpMaterial** masterMaterials); // These methods are only to be called at fetchResults! PX_INLINE PxU32 getNumActiveBodies() const { return mScene.getNumActiveBodies(); } PX_INLINE Sc::BodyCore* const* getActiveBodiesArray() const { return mScene.getActiveBodiesArray(); } PX_INLINE PxSimulationEventCallback* getSimulationEventCallback() const; PX_INLINE void setSimulationEventCallback(PxSimulationEventCallback* callback); PX_INLINE PxContactModifyCallback* getContactModifyCallback() const; PX_INLINE void setContactModifyCallback(PxContactModifyCallback* callback); PX_INLINE PxCCDContactModifyCallback* getCCDContactModifyCallback() const; PX_INLINE void setCCDContactModifyCallback(PxCCDContactModifyCallback* callback); PX_INLINE PxU32 getCCDMaxPasses() const; PX_INLINE void setCCDMaxPasses(PxU32 ccdMaxPasses); PX_INLINE void setBroadPhaseCallback(PxBroadPhaseCallback* callback); PX_INLINE PxBroadPhaseCallback* getBroadPhaseCallback() const; PxBroadPhaseType::Enum getBroadPhaseType() const; bool getBroadPhaseCaps(PxBroadPhaseCaps& caps) const; PxU32 getNbBroadPhaseRegions() const; PxU32 getBroadPhaseRegions(PxBroadPhaseRegionInfo* userBuffer, PxU32 bufferSize, PxU32 startIndex) const; PxU32 addBroadPhaseRegion(const PxBroadPhaseRegion& region, bool populateRegion); bool removeBroadPhaseRegion(PxU32 handle); // Collision filtering PX_INLINE void setFilterShaderData(const void* data, PxU32 dataSize); PX_INLINE const void* getFilterShaderData() const; PX_INLINE PxU32 getFilterShaderDataSize() const; PX_INLINE PxSimulationFilterShader getFilterShader() const; PX_INLINE PxSimulationFilterCallback* getFilterCallback() const; // Groups PX_INLINE void setDominanceGroupPair(PxDominanceGroup group1, PxDominanceGroup group2, const PxDominanceGroupPair& dominance); PX_INLINE PxDominanceGroupPair getDominanceGroupPair(PxDominanceGroup group1, PxDominanceGroup group2) const; PX_INLINE void setSolverBatchSize(PxU32 solverBatchSize); PX_INLINE PxU32 getSolverBatchSize() const; PX_INLINE void setSolverArticulationBatchSize(PxU32 solverBatchSize); PX_INLINE PxU32 getSolverArticulationBatchSize() const; PX_INLINE void simulate(PxReal timeStep, PxBaseTask* continuation) { mScene.simulate(timeStep, continuation); } PX_INLINE void collide(PxReal timeStep, PxBaseTask* continuation) { mScene.collide(timeStep, continuation); } PX_INLINE void advance(PxReal timeStep, PxBaseTask* continuation) { mScene.advance(timeStep, continuation); } PX_INLINE void endSimulation() { mScene.endSimulation(); } PX_INLINE void flush(bool sendPendingReports); PX_INLINE void fireBrokenConstraintCallbacks() { mScene.fireBrokenConstraintCallbacks(); } PX_INLINE void fireTriggerCallbacks() { mScene.fireTriggerCallbacks(); } PX_INLINE void fireQueuedContactCallbacks() { mScene.fireQueuedContactCallbacks(false); } PX_INLINE const Ps::Array& getQueuedContactPairHeaders() { return mScene.getQueuedContactPairHeaders(); } PX_FORCE_INLINE void postCallbacksPreSync() { mScene.postCallbacksPreSync(); } //cleanup tasks after the pre-sync callbacks have fired PX_INLINE void fireCallBacksPostSync() { mScene.fireCallbacksPostSync(); } //callbacks that are fired on the core side, after the buffers get synced PX_INLINE void postReportsCleanup(); PX_INLINE const PxSceneLimits& getLimits() const { return mScene.getLimits(); } PX_INLINE void setLimits(const PxSceneLimits& limits) { mScene.setLimits(limits); } PX_INLINE void getStats(PxSimulationStatistics& stats) const; PX_INLINE void buildActiveActors(); //build the list of active actors PX_INLINE void buildActiveAndFrozenActors(); //build the list of active and frozen actors PX_INLINE PxActor** getActiveActors(PxU32& nbActorsOut); PX_INLINE void setActiveActors(PxActor** actors, PxU32 nbActors); PX_INLINE PxActor** getFrozenActors(PxU32& nbActorsOut); PX_INLINE PxClientID createClient(); PX_INLINE void setVisualizationParameter(PxVisualizationParameter::Enum param, PxReal value); PX_INLINE PxReal getVisualizationParameter(PxVisualizationParameter::Enum param) const; PX_INLINE void setVisualizationCullingBox(const PxBounds3& box); PX_INLINE const PxBounds3& getVisualizationCullingBox() const; void shiftOrigin(const PxVec3& shift); //--------------------------------------------------------------------------------- // Data synchronization //--------------------------------------------------------------------------------- public: void syncWriteThroughProperties(); void syncEntireScene(); void processPendingRemove(); PX_FORCE_INLINE PxU16* allocShapeMaterialBuffer(PxU32 count, PxU32& startIdx) { return allocArrayBuffer(mShapeMaterialBuffer, count, startIdx); } PX_FORCE_INLINE const PxU16* getShapeMaterialBuffer(PxU32 startIdx) const { return &mShapeMaterialBuffer[startIdx]; } PX_FORCE_INLINE Scb::Shape** allocShapeBuffer(PxU32 count, PxU32& startIdx) { return allocArrayBuffer(mShapePtrBuffer, count, startIdx); } PX_FORCE_INLINE Scb::Shape** getShapeBuffer(PxU32 startIdx) { return &mShapePtrBuffer[startIdx]; } PX_FORCE_INLINE Scb::Actor** allocActorBuffer(PxU32 count, PxU32& startIdx) { return allocArrayBuffer(mActorPtrBuffer, count, startIdx); } PX_FORCE_INLINE Scb::Actor** getActorBuffer(PxU32 startIdx) { return &mActorPtrBuffer[startIdx]; } void scheduleForUpdate(Scb::Base& object); PxU8* getStream(ScbType::Enum type); PX_FORCE_INLINE void removeShapeFromPendingUpdateList(Scb::Base& shape) { mShapeManager.remove(shape); } PX_FORCE_INLINE const Sc::Scene& getScScene() const { return mScene; } PX_FORCE_INLINE Sc::Scene& getScScene() { return mScene; } PX_FORCE_INLINE void prepareOutOfBoundsCallbacks() { mScene.prepareOutOfBoundsCallbacks(); } private: void syncState(); PX_FORCE_INLINE Ps::IntBool isBuffered(BufferFlag f) const { return Ps::IntBool(mBufferFlags& f); } PX_FORCE_INLINE void markUpdated(BufferFlag f) { mBufferFlags |= f; } //--------------------------------------------------------------------------------- // Miscellaneous //--------------------------------------------------------------------------------- public: PX_FORCE_INLINE bool isPhysicsBuffering() const { return mIsBuffering; } PX_FORCE_INLINE void setPhysicsBuffering(bool buffering) { mIsBuffering = buffering; } PX_FORCE_INLINE Sc::SimulationStage::Enum getSimulationStage() const { return mScene.getSimulationStage(); } PX_FORCE_INLINE void setSimulationStage(Sc::SimulationStage::Enum stage) { mScene.setSimulationStage(stage); } PX_FORCE_INLINE bool isValid() const { return mScene.isValid(); } PX_FORCE_INLINE PxReal getWakeCounterResetValue() const { return mWakeCounterResetValue; } void switchRigidToNoSim(Scb::RigidObject&, bool isDynamic); void switchRigidFromNoSim(Scb::RigidObject&, bool isDynamic); static size_t getScOffset() { return reinterpret_cast(&reinterpret_cast(0)->mScene); } #if PX_SUPPORT_PVD PX_FORCE_INLINE Vd::ScbScenePvdClient& getScenePvdClient() { return mScenePvdClient; } PX_FORCE_INLINE const Vd::ScbScenePvdClient& getScenePvdClient() const { return mScenePvdClient; } #endif PX_FORCE_INLINE PxU64 getContextId() const { return mScene.getContextId(); } private: void addShapeInternal(Scb::Shape&); void addShapesInternal(PxU32 nbShapes, PxShape** PX_RESTRICT shapes, size_t scbOffset, PxActor** PX_RESTRICT owners, PxU32 offsetNpToCore, bool isDynamic); template T* allocArrayBuffer(Ps::Array& buffer, PxU32 count, PxU32& startIdx); private: template PX_FORCE_INLINE void addActorT(T& actor, ObjectTracker& tracker, bool noSim, PxBounds3* uninflatedBounds, const Gu::BVHStructure* bvhStructure); template void add(T& v, ObjectTracker& tracker, PxBounds3* uninflatedBounds, const Gu::BVHStructure* bvhStructure); template void remove(T& v, ObjectTracker& tracker, bool wakeOnLostTouch = false); template void addRigidNoSim(T& v, ObjectTracker& tracker, const Gu::BVHStructure* bvhStructure); template void removeRigidNoSim(T& v, ObjectTracker& tracker); template void processSimUpdates(S*const * scObjects, PxU32 nbObjects); template void processUserUpdates(ObjectTracker& tracker); template void processRemoves(ObjectTracker& tracker); template void processShapeRemoves(ObjectTracker& tracker); Sc::Scene mScene; Ps::Array mSceneMaterialBuffer; Ps::Mutex mSceneMaterialBufferLock; bool mSimulationRunning; bool mIsBuffering; Cm::FlushPool mStream; // Pool for temporarily buffering user changes on objects ShapeManager mShapeManager; Ps::Array mShapeMaterialBuffer; // Buffered setMaterial() call might need to track list of materials (for multi material shapes) Ps::Array mShapePtrBuffer; // List of shape pointers to track buffered calls to resetFiltering(), for example Ps::Array mActorPtrBuffer; RigidStaticManager mRigidStaticManager; BodyManager mBodyManager; ConstraintManager mConstraintManager; ArticulationManager mArticulationManager; ArticulationJointManager mArticulationJointManager; AggregateManager mAggregateManager; #if PX_SUPPORT_PVD Vd::ScbScenePvdClient mScenePvdClient; #endif PX_FORCE_INLINE void updatePvdProperties() { #if PX_SUPPORT_PVD // PT: TODO: shouldn't we test PxPvdInstrumentationFlag::eDEBUG here? if(mScenePvdClient.isConnected()) mScenePvdClient.updatePvdProperties(); #endif } PxReal mWakeCounterResetValue; // note: If deletion of rigid objects is done before the sync of the simulation data then we // might wanna consider having a separate list for deleted rigid objects (for performance // reasons) //--------------------------------------------------------------------------------- // On demand buffered data (simulation read-only data) //--------------------------------------------------------------------------------- Scb::SceneBuffer mBufferedData; PxU32 mBufferFlags; }; } // namespace Scb template T* Scb::Scene::allocArrayBuffer(Ps::Array& buffer, PxU32 count, PxU32& startIdx) { PxU32 oldSize = buffer.size(); buffer.resize(oldSize + count); startIdx = oldSize; return &buffer[oldSize]; } PX_INLINE void Scb::Scene::setGravity(const PxVec3& gravity) { if(!isPhysicsBuffering()) { mScene.setGravity(gravity); updatePvdProperties(); } else { mBufferedData.mGravity = gravity; markUpdated(BF_GRAVITY); } } PX_INLINE PxVec3 Scb::Scene::getGravity() const { if(isBuffered(BF_GRAVITY)) return mBufferedData.mGravity; else return mScene.getGravity(); } void Scb::Scene::setBounceThresholdVelocity(const PxReal t) { if(!isPhysicsBuffering()) { mScene.setBounceThresholdVelocity(t); updatePvdProperties(); } else { mBufferedData.mBounceThresholdVelocity = t; markUpdated(BF_BOUNCETHRESHOLDVELOCITY); } } PxReal Scb::Scene::getBounceThresholdVelocity() const { if(isBuffered(BF_BOUNCETHRESHOLDVELOCITY)) return mBufferedData.mBounceThresholdVelocity; else return mScene.getBounceThresholdVelocity(); } PX_INLINE void Scb::Scene::setFlags(PxSceneFlags flags) { if(!isPhysicsBuffering()) { mScene.setPublicFlags(flags); const bool pcm = (flags & PxSceneFlag::eENABLE_PCM); mScene.setPCM(pcm); const bool contactCache = !(flags & PxSceneFlag::eDISABLE_CONTACT_CACHE); mScene.setContactCache(contactCache); updatePvdProperties(); } else { mBufferedData.mFlags = flags; markUpdated(BF_FLAGS); } } PX_INLINE PxSceneFlags Scb::Scene::getFlags() const { if(isBuffered(BF_FLAGS)) return mBufferedData.mFlags; else return mScene.getPublicFlags(); } /////////////////////////////////////////////////////////////////////////////// PX_INLINE PxSimulationEventCallback* Scb::Scene::getSimulationEventCallback() const { return mScene.getSimulationEventCallback(); } PX_INLINE void Scb::Scene::setSimulationEventCallback(PxSimulationEventCallback* callback) { if(!isPhysicsBuffering()) mScene.setSimulationEventCallback(callback); else Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::setSimulationEventCallback() not allowed while simulation is running. Call will be ignored."); } PX_INLINE PxContactModifyCallback* Scb::Scene::getContactModifyCallback() const { return mScene.getContactModifyCallback(); } PX_INLINE void Scb::Scene::setContactModifyCallback(PxContactModifyCallback* callback) { if(!isPhysicsBuffering()) mScene.setContactModifyCallback(callback); else Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::setContactModifyCallback() not allowed while simulation is running. Call will be ignored."); } PX_INLINE PxCCDContactModifyCallback* Scb::Scene::getCCDContactModifyCallback() const { return mScene.getCCDContactModifyCallback(); } PX_INLINE void Scb::Scene::setCCDContactModifyCallback(PxCCDContactModifyCallback* callback) { if(!isPhysicsBuffering()) mScene.setCCDContactModifyCallback(callback); else Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::setCCDContactModifyCallback() not allowed while simulation is running. Call will be ignored."); } PX_INLINE PxU32 Scb::Scene::getCCDMaxPasses() const { return mScene.getCCDMaxPasses(); } PX_INLINE void Scb::Scene::setCCDMaxPasses(PxU32 ccdMaxPasses) { if(!isPhysicsBuffering()) mScene.setCCDMaxPasses(ccdMaxPasses); else Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::setCCDMaxPasses() not allowed while simulation is running. Call will be ignored."); } PX_INLINE PxBroadPhaseCallback* Scb::Scene::getBroadPhaseCallback() const { return mScene.getBroadPhaseCallback(); } PX_INLINE void Scb::Scene::setBroadPhaseCallback(PxBroadPhaseCallback* callback) { if(!isPhysicsBuffering()) mScene.setBroadPhaseCallback(callback); else Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::setBroadPhaseCallback() not allowed while simulation is running. Call will be ignored."); } /////////////////////////////////////////////////////////////////////////////// PX_INLINE void Scb::Scene::setFilterShaderData(const void* data, PxU32 dataSize) { if(!isPhysicsBuffering()) mScene.setFilterShaderData(data, dataSize); else Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxScene::setFilterShaderData() not allowed while simulation is running. Call will be ignored."); } PX_INLINE const void* Scb::Scene::getFilterShaderData() const { return mScene.getFilterShaderDataFast(); } PX_INLINE PxU32 Scb::Scene::getFilterShaderDataSize() const { return mScene.getFilterShaderDataSizeFast(); } PX_INLINE PxSimulationFilterShader Scb::Scene::getFilterShader() const { return mScene.getFilterShaderFast(); } PX_INLINE PxSimulationFilterCallback* Scb::Scene::getFilterCallback() const { return mScene.getFilterCallbackFast(); } PX_INLINE void Scb::Scene::flush(bool sendPendingReports) { PX_ASSERT(!isPhysicsBuffering()); mShapeMaterialBuffer.reset(); mShapePtrBuffer.reset(); mActorPtrBuffer.reset(); //!!! TODO: Clear all buffers used for double buffering changes (see ObjectTracker::mBufferPool) mScene.flush(sendPendingReports); } PX_INLINE void Scb::Scene::postReportsCleanup() { PX_ASSERT(!isPhysicsBuffering()); mScene.postReportsCleanup(); } PX_INLINE void Scb::Scene::setDominanceGroupPair(PxDominanceGroup group1, PxDominanceGroup group2, const PxDominanceGroupPair& dominance) { if(!isPhysicsBuffering()) { mScene.setDominanceGroupPair(group1, group2, dominance); updatePvdProperties(); } else { mBufferedData.setDominancePair(group1, group2, dominance); markUpdated(BF_DOMINANCE_PAIRS); } } PX_INLINE PxDominanceGroupPair Scb::Scene::getDominanceGroupPair(PxDominanceGroup group1, PxDominanceGroup group2) const { if(isBuffered(BF_DOMINANCE_PAIRS)) { PxDominanceGroupPair dominance(0, 0); if(mBufferedData.getDominancePair(group1, group2, dominance)) return dominance; } return mScene.getDominanceGroupPair(group1, group2); } PX_INLINE void Scb::Scene::setSolverBatchSize(PxU32 solverBatchSize) { if(!isPhysicsBuffering()) { mScene.setSolverBatchSize(solverBatchSize); updatePvdProperties(); } else { mBufferedData.mSolverBatchSize = solverBatchSize; markUpdated(BF_SOLVER_BATCH_SIZE); } } PX_INLINE PxU32 Scb::Scene::getSolverArticulationBatchSize() const { if(isBuffered(BF_SOLVER_ARTIC_BATCH_SIZE)) return mBufferedData.mSolverBatchSize; else return mScene.getSolverArticBatchSize(); } PX_INLINE void Scb::Scene::setSolverArticulationBatchSize(PxU32 solverBatchSize) { if (!isPhysicsBuffering()) { mScene.setSolverArticBatchSize(solverBatchSize); updatePvdProperties(); } else { mBufferedData.mSolverArticulationBatchSize = solverBatchSize; markUpdated(BF_SOLVER_ARTIC_BATCH_SIZE); } } PX_INLINE PxU32 Scb::Scene::getSolverBatchSize() const { if (isBuffered(BF_SOLVER_BATCH_SIZE)) return mBufferedData.mSolverBatchSize; else return mScene.getSolverBatchSize(); } PX_INLINE void Scb::Scene::getStats(PxSimulationStatistics& stats) const { PX_ASSERT(!isPhysicsBuffering()); mScene.getStats(stats); } PX_INLINE void Scb::Scene::buildActiveActors() { PX_ASSERT(!isPhysicsBuffering()); mScene.buildActiveActors(); } PX_INLINE void Scb::Scene::buildActiveAndFrozenActors() { PX_ASSERT(!isPhysicsBuffering()); mScene.buildActiveAndFrozenActors(); } PX_INLINE PxActor** Scb::Scene::getActiveActors(PxU32& nbActorsOut) { if(!isPhysicsBuffering()) return mScene.getActiveActors(nbActorsOut); else { Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::getActiveActors() not allowed while simulation is running. Call will be ignored."); nbActorsOut = 0; return NULL; } } PX_INLINE void Scb::Scene::setActiveActors(PxActor** actors, PxU32 nbActors) { mScene.setActiveActors(actors, nbActors); } PX_INLINE PxActor** Scb::Scene::getFrozenActors(PxU32& nbActorsOut) { if(!isPhysicsBuffering()) return mScene.getFrozenActors(nbActorsOut); else { Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxScene::getFrozenActors() not allowed while simulation is running. Call will be ignored."); nbActorsOut = 0; return NULL; } } PX_INLINE PxClientID Scb::Scene::createClient() { if(!isPhysicsBuffering()) return mScene.createClient(); else return PxClientID(mScene.getNbClients() + mBufferedData.mNumClientsCreated++); } PX_INLINE void Scb::Scene::setVisualizationParameter(PxVisualizationParameter::Enum param, PxReal value) { if(!isPhysicsBuffering()) mScene.setVisualizationParameter(param, value); else { PX_ASSERT(param < PxVisualizationParameter::eNUM_VALUES); mBufferedData.mVisualizationParamChanged[param] = 1; mBufferedData.mVisualizationParam[param] = value; markUpdated(BF_VISUALIZATION); } } PX_INLINE PxReal Scb::Scene::getVisualizationParameter(PxVisualizationParameter::Enum param) const { PX_ASSERT(param < PxVisualizationParameter::eNUM_VALUES); if(isBuffered(BF_VISUALIZATION) && mBufferedData.mVisualizationParamChanged[param]) return mBufferedData.mVisualizationParam[param]; else return mScene.getVisualizationParameter(param); } PX_INLINE void Scb::Scene::setVisualizationCullingBox(const PxBounds3& box) { if(!isPhysicsBuffering()) mScene.setVisualizationCullingBox(box); else { mBufferedData.mVisualizationCullingBox = box; markUpdated(BF_CULLING_BOX); } } PX_INLINE const PxBounds3& Scb::Scene::getVisualizationCullingBox() const { if(isBuffered(BF_CULLING_BOX)) return mBufferedData.mVisualizationCullingBox; else return mScene.getVisualizationCullingBox(); } } #endif