diff options
Diffstat (limited to 'PhysX_3.4/Source/PhysX/src/buffering/ScbRigidObject.h')
| -rw-r--r-- | PhysX_3.4/Source/PhysX/src/buffering/ScbRigidObject.h | 530 |
1 files changed, 530 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/PhysX/src/buffering/ScbRigidObject.h b/PhysX_3.4/Source/PhysX/src/buffering/ScbRigidObject.h new file mode 100644 index 00000000..e1ea7a43 --- /dev/null +++ b/PhysX_3.4/Source/PhysX/src/buffering/ScbRigidObject.h @@ -0,0 +1,530 @@ +// 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. + + +#ifndef PX_PHYSICS_SCB_RIGID_OBJECT +#define PX_PHYSICS_SCB_RIGID_OBJECT + +#include "../../SimulationController/include/ScRigidCore.h" +#include "ScbScene.h" +#include "ScbActor.h" +#include "ScbShape.h" +#include "PsInlineArray.h" + +namespace physx +{ + +// base class for dynamic and static rigid objects, so that shapes can have something to refer to + +namespace Scb +{ + +struct RemovedShape +{ + RemovedShape() : mShape(NULL), mWakeTouching(0) {} + RemovedShape(Scb::Shape* s, PxU8 wakeTouching) : mShape(s), mWakeTouching(wakeTouching) {} + + PX_FORCE_INLINE bool operator == (const RemovedShape& other) const + { + return (mShape == other.mShape); + } + + PX_FORCE_INLINE bool operator != (const RemovedShape& other) const + { + return (mShape != other.mShape); + } + + Scb::Shape* mShape; + PxU8 mWakeTouching; +}; + + +struct RigidObjectBuffer : public ActorBuffer //once RigidObject has its own buffered elements, derive from that instead +{ + RigidObjectBuffer(): mResetFilterShape(0), mResetFilterShapeCount(0) {} + + // TODO(dsequeira): ideally we would use an allocator that allocates from the buffered memory stream + Ps::InlineArray<Scb::Shape*, 4> mAddedShapes; + Ps::InlineArray<Scb::RemovedShape, 4> mRemovedShapes; + union + { + PxU32 mResetFilterShapesIdx; + Scb::Shape* mResetFilterShape; + }; + PxU32 mResetFilterShapeCount; + + enum { BF_Base = ActorBuffer::AttrCount }; + + enum + { + BF_Shapes = 1<<BF_Base, + BF_WakeTouching = 1<<(BF_Base+1), + BF_ResetFiltering = 1<<(BF_Base+2) + }; + + enum { AttrCount = ActorBuffer::AttrCount+3 }; +}; + + +class RigidObject : public Scb::Actor +{ +//= ATTENTION! ===================================================================================== +// Changing the data layout of this class breaks the binary serialization format. See comments for +// PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData +// function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION +// accordingly. +//================================================================================================== + + typedef RigidObjectBuffer Buf; + typedef Sc::RigidCore Core; + +public: +// PX_SERIALIZATION + RigidObject() {} + RigidObject(const PxEMPTY) : Scb::Actor(PxEmpty) {} + static void getBinaryMetaData(PxOutputStream& stream); +//~PX_SERIALIZATION + + //--------------------------------------------------------------------------------- + // Wrapper for Sc::RigidCore interface + //--------------------------------------------------------------------------------- + + PX_INLINE void resetFiltering(Scb::Shape*const* shapes, PxU32 shapeCount); + + + //--------------------------------------------------------------------------------- + // Data synchronization + //--------------------------------------------------------------------------------- + + // the fetchResults order is to process removes, do callbacks, and then do the other synchronization. So we need to split sync'ing of + // adds and removes + // Note: The array of removed shapes must be reset here to avoid memory leaks: even if the control state means we don't process the + // array of removed shapes, we still need to clear the array. + PX_INLINE void processShapeRemoves() + { + if(getBufferFlags() & Buf::BF_Shapes) + { + RigidObjectBuffer* b = getBuffer(); + + if(getControlState() == ControlState::eIN_SCENE) + { +#if PX_SUPPORT_PVD + PxActor& pxActor = *getScRigidCore().getPxActor(); +#endif + for(PxU32 i=0;i<b->mRemovedShapes.size();i++) + { + RemovedShape& rs = b->mRemovedShapes[i]; + Shape& shape = *rs.mShape; + shape.setControlStateIfExclusive(NULL, Scb::ControlState::eNOT_IN_SCENE); + + Sc::RigidCore& rc = getScRigidCore(); + Scb::Scene* scene = getScbScene(); +#if PX_SUPPORT_PVD + scene->getScenePvdClient().releasePvdInstance(&shape, pxActor); +#endif + if (!isSimDisabledInternally()) + { + rc.removeShapeFromScene(shape.getScShape(), (rs.mWakeTouching != 0)); + + shape.checkUpdateOnRemove<true>(scene); + + NpShapeDecRefCount(shape); + } + } + } + + // The array of removed shapes must be reset to avoid memory leaks. + b->mRemovedShapes.reset(); + } + } + + PX_INLINE void syncState() + { + PxU32 bufferFlags = getBufferFlags(); + + if (bufferFlags & Buf::BF_ResetFiltering) + { + PX_ASSERT(getControlState() != ControlState::eREMOVE_PENDING); // removing the actor should have cleared BF_ResetFiltering + + Scb::Scene* scene = getScbScene(); + Sc::RigidCore& scCore = getScRigidCore(); + RigidObjectBuffer* b = getBuffer(); + Scb::Shape* const* shapes = (b->mResetFilterShapeCount == 1) ? &b->mResetFilterShape : scene->getShapeBuffer(b->mResetFilterShapesIdx); + for(PxU32 i=0; i < b->mResetFilterShapeCount; i++) + { + Sc::ShapeCore& scShape = shapes[i]->getScShape(); + + // do not process the call if the shape will not be a broadphase shape any longer + if (shapes[i]->getFlags() & (PxShapeFlag::eSIMULATION_SHAPE | PxShapeFlag::eTRIGGER_SHAPE)) + scCore.onShapeChange(scShape, Sc::ShapeChangeNotifyFlag::eRESET_FILTERING, PxShapeFlags()); + } + } + + if(bufferFlags & Buf::BF_Shapes) + { + RigidObjectBuffer* b = getBuffer(); + ControlState::Enum cs = getControlState(); +#if PX_SUPPORT_PVD + PxActor& pxActor = *getScRigidCore().getPxActor(); +#endif + for(PxU32 i=0;i<b->mAddedShapes.size();i++) + { + Shape& shape = *b->mAddedShapes[i]; + + // it can happen that a shape gets attached while the sim is running but then the actor is removed from the scene, + // so we need to distinguish those two cases + if (cs != ControlState::eREMOVE_PENDING) + { + shape.setControlStateIfExclusive(getScbScene(), Scb::ControlState::eIN_SCENE); + + if (!(getActorFlags() & PxActorFlag::eDISABLE_SIMULATION)) // important to use the buffered flags since we want the new state. + { + getScRigidCore().addShapeToScene(shape.getScShape()); + NpShapeIncRefCount(shape); + } +#if PX_SUPPORT_PVD + getScbScene()->getScenePvdClient().createPvdInstance(&shape, pxActor); +#endif + } + else + shape.setControlStateIfExclusive(getScbScene(), Scb::ControlState::eNOT_IN_SCENE); + } + + // reset the arrays, because destructors don't run on buffers + b->mAddedShapes.reset(); + } + + Actor::syncState(); + } + + PX_FORCE_INLINE void scheduleForWakeTouching() { PX_ASSERT(getScbScene() && getScbScene()->isPhysicsBuffering()); setBufferFlag(RigidObjectBuffer::BF_WakeTouching); } + + //--------------------------------------------------------------------------------- + // Miscellaneous + //--------------------------------------------------------------------------------- +public: + PX_INLINE const Sc::RigidCore& getScRigidCore() const { return static_cast<const Sc::RigidCore&>(getActorCore()); } // Only use if you know what you're doing! + PX_INLINE Sc::RigidCore& getScRigidCore() { return static_cast<Sc::RigidCore&>(getActorCore()); } // Only use if you know what you're doing! + + PX_INLINE void setShapeStateIfExclusive(Scb::Shape& shape, ControlState::Enum cs, Scb::Scene& scene) + { + if(shape.isExclusive()) + { + shape.setScbScene(&scene); + shape.setControlState(cs); + } + } + + PX_INLINE void onShapeAttach(Scb::Shape& shape) + { + // there are two things to do here: add the shape to the sim (if unbuffered) or set it up for + // * if unbuffered, add the shape to the sim and PVD and increment its refcount, else set it up for buffered insertion, + // * if the shape is exclusive, set its Scb control state appropriately. + + ControlState::Enum cs = getControlState(); + if(cs==ControlState::eNOT_IN_SCENE) + return; + + Scene* scbScene = getScbScene(); + if(!scbScene->isPhysicsBuffering()) + { + if (!(getActorFlags() & PxActorFlag::eDISABLE_SIMULATION)) + { + NpShapeIncRefCount(shape); + getScRigidCore().addShapeToScene(shape.getScShape()); + } + +#if PX_SUPPORT_PVD + getScbScene()->getScenePvdClient().createPvdInstance(&shape, *getScRigidCore().getPxActor()); +#endif + shape.setControlStateIfExclusive(scbScene, ControlState::eIN_SCENE); + return; + } + else if (cs == ControlState::eINSERT_PENDING) + { + shape.setControlStateIfExclusive(scbScene, ControlState::eINSERT_PENDING); + return; + } + + RigidObjectBuffer* b = getBuffer(); + if(!b->mRemovedShapes.findAndReplaceWithLast(RemovedShape(&shape, 0))) + b->mAddedShapes.pushBack(&shape); + markUpdated(Buf::BF_Shapes); + + shape.setControlStateIfExclusive(scbScene, ControlState::eINSERT_PENDING); + } + + + PX_INLINE void onShapeDetach(Scb::Shape& shape, bool wakeOnLostTouch, bool toBeReleased) + { + // see comments in onShapeAttach + ControlState::Enum cs = getControlState(); + if(cs==ControlState::eNOT_IN_SCENE) + return; + + Scene* scbScene = getScbScene(); + if(!scbScene->isPhysicsBuffering()) + { +#if PX_SUPPORT_PVD + scbScene->getScenePvdClient().releasePvdInstance(&shape, *getScRigidCore().getPxActor()); +#endif + if (!(getActorFlags() & PxActorFlag::eDISABLE_SIMULATION)) + { + getScRigidCore().removeShapeFromScene(shape.getScShape(), wakeOnLostTouch); + NpShapeDecRefCount(shape); + } + + shape.setControlStateIfExclusive(NULL, ControlState::eNOT_IN_SCENE); + return; + } + else if (cs == ControlState::eINSERT_PENDING) + { + shape.setControlStateIfExclusive(NULL, ControlState::eNOT_IN_SCENE); + return; + } + + RigidObjectBuffer* b = getBuffer(); + + // remove from the resetFiltering list + PxU32 bufferFlags = getBufferFlags(); + if (bufferFlags & Buf::BF_ResetFiltering) + { + if (b->mResetFilterShapeCount == 1) + { + if (b->mResetFilterShape == &shape) + { + b->mResetFilterShapeCount = 0; + b->mResetFilterShape = 0; + resetBufferFlag(Buf::BF_ResetFiltering); + } + } + else + { + Scb::Shape** shapes = scbScene->getShapeBuffer(b->mResetFilterShapesIdx); + PxU32 idx = 0; + PxU32 lastIdx = b->mResetFilterShapeCount; + for(PxU32 k=0; k < b->mResetFilterShapeCount; k++) // need to iterate over whole list, same shape can be in there multiple times + { + if (shapes[idx] != &shape) + idx++; + else + { + lastIdx--; + shapes[idx] = shapes[lastIdx]; + } + } + b->mResetFilterShapeCount = idx; + if (idx == 0) + { + b->mResetFilterShape = 0; + resetBufferFlag(Buf::BF_ResetFiltering); + } + else if (idx == 1) + b->mResetFilterShape = shapes[0]; + } + } + + if(b->mAddedShapes.findAndReplaceWithLast(&shape)) + shape.setControlStateIfExclusive(scbScene, ControlState::eIN_SCENE); + else + { + if (!isSimDisabledInternally()) + { + b->mRemovedShapes.pushBack(RemovedShape(&shape, PxU8(wakeOnLostTouch ? 1 : 0))); + } + else + { + PX_ASSERT(scbScene); + PX_ASSERT(scbScene->isPhysicsBuffering()); + if (toBeReleased) + { + shape.checkUpdateOnRemove<false>(scbScene); +#if PX_SUPPORT_PVD + scbScene->getScenePvdClient().releasePvdInstance(&shape, *getScRigidCore().getPxActor()); +#endif + } + else + b->mRemovedShapes.pushBack(RemovedShape(&shape, 0)); + } + shape.setControlStateIfExclusive(scbScene, ControlState::eREMOVE_PENDING); + } + markUpdated(Buf::BF_Shapes); + } + + PX_INLINE bool isAddedShape(Scb::Shape&); // check whether the specified shape is pending for insertion. Only call this method if you know that there are pending shape adds/removes. + + PX_FORCE_INLINE void switchToNoSim(bool isDynamic); + PX_FORCE_INLINE void switchFromNoSim(bool isDynamic); + PX_FORCE_INLINE void syncNoSimSwitch(const Buf& buf, Sc::RigidCore& rc, bool isDynamic); + + // IMPORTANT: This is the non-buffered state, for the case where it is important to know what the current internal state is. + // Reading is fine even if the sim is running because actor flags are read-only internally. + PX_FORCE_INLINE bool isSimDisabledInternally() const { return getScRigidCore().getActorFlags().isSet(PxActorFlag::eDISABLE_SIMULATION); } + + PX_FORCE_INLINE void clearBufferedState() { resetBufferFlag(Buf::BF_ResetFiltering); } + + PX_FORCE_INLINE static const RigidObject& fromSc(const Sc::RigidCore& a) { return static_cast<const RigidObject&>(Actor::fromSc(a)); } + PX_FORCE_INLINE static RigidObject& fromSc(Sc::RigidCore &a) { return static_cast<RigidObject&>(Actor::fromSc(a)); } +protected: + ~RigidObject() {} +private: + Buf* getBuffer() { return reinterpret_cast<Buf*>(getStream()); } + + PX_FORCE_INLINE void copyResetFilterShapes(Scb::Shape** shapePtrs, Scb::Shape*const* oldShapes, PxU32 oldShapeCount, Scb::Shape*const* newShapes, PxU32 newShapeCount); +}; + + +PX_INLINE void RigidObject::resetFiltering(Scb::Shape*const* shapes, PxU32 shapeCount) +{ + PX_ASSERT(!(getActorFlags() & PxActorFlag::eDISABLE_SIMULATION)); + + if(!isBuffering()) + { + for(PxU32 i=0; i < shapeCount; i++) + getScRigidCore().onShapeChange(shapes[i]->getScShape(), Sc::ShapeChangeNotifyFlag::eRESET_FILTERING, PxShapeFlags()); + } + else + { + RigidObjectBuffer* b = getBuffer(); + + if (b->mResetFilterShapeCount == 0) + { + if (shapeCount == 1) + { + b->mResetFilterShape = shapes[0]; + b->mResetFilterShapeCount = 1; + markUpdated(Buf::BF_ResetFiltering); + } + else + { + PxU32 bufferIdx; + Scb::Shape** shapePtrs = getScbScene()->allocShapeBuffer(shapeCount, bufferIdx); + if (shapePtrs) + { + for(PxU32 i=0; i < shapeCount; i++) + shapePtrs[i] = shapes[i]; + b->mResetFilterShapesIdx = bufferIdx; + b->mResetFilterShapeCount = shapeCount; + markUpdated(Buf::BF_ResetFiltering); + } + } + } + else + { + PxU32 newCount = b->mResetFilterShapeCount + shapeCount; + PxU32 bufferIdx; + Scb::Shape** shapePtrs = getScbScene()->allocShapeBuffer(newCount, bufferIdx); + if (shapePtrs) + { + if (b->mResetFilterShapeCount == 1) + copyResetFilterShapes(shapePtrs, &b->mResetFilterShape, 1, shapes, shapeCount); + else + copyResetFilterShapes(shapePtrs, getScbScene()->getShapeBuffer(b->mResetFilterShapesIdx), b->mResetFilterShapeCount, shapes, shapeCount); + b->mResetFilterShapesIdx = bufferIdx; + b->mResetFilterShapeCount = newCount; + markUpdated(Buf::BF_ResetFiltering); + } + } + } +} + + +PX_INLINE bool RigidObject::isAddedShape(Scb::Shape& shape) +{ + PX_ASSERT(isBuffered(Buf::BF_Shapes)); + + if (shape.isExclusive()) + { + return (shape.getControlState() == Scb::ControlState::eINSERT_PENDING); + } + else + { + // For shared shapes it is not clear from the shape alone whether it has been added while the simulation was running. + + RigidObjectBuffer* buf = getBuffer(); + PX_ASSERT(buf); + const PxU32 addedShapeCount = buf->mAddedShapes.size(); + for(PxU32 k=0; k < addedShapeCount; k++) + { + if (&shape == buf->mAddedShapes[k]) + { + return true; + } + } + + return false; + } +} + + +PX_FORCE_INLINE void RigidObject::switchToNoSim(bool isDynamic) +{ + Scb::Scene* scene = getScbScene(); + + if (scene && (!scene->isPhysicsBuffering())) + scene->switchRigidToNoSim(*this, isDynamic); +} + + +PX_FORCE_INLINE void RigidObject::switchFromNoSim(bool isDynamic) +{ + Scb::Scene* scene = getScbScene(); + + if (scene && (!scene->isPhysicsBuffering())) + scene->switchRigidFromNoSim(*this, isDynamic); +} + + +PX_FORCE_INLINE void RigidObject::syncNoSimSwitch(const Buf& buf, Sc::RigidCore& rc, bool isDynamic) +{ + PxActorFlags oldFlags = rc.getActorFlags(); + bool oldNoSim = oldFlags.isSet(PxActorFlag::eDISABLE_SIMULATION); + bool newNoSim = buf.mActorFlags.isSet(PxActorFlag::eDISABLE_SIMULATION); + + if (oldNoSim && (!newNoSim)) + getScbScene()->switchRigidFromNoSim(*this, isDynamic); + else if ((!oldNoSim) && newNoSim) + getScbScene()->switchRigidToNoSim(*this, isDynamic); +} + + +PX_FORCE_INLINE void RigidObject::copyResetFilterShapes(Scb::Shape** shapePtrs, Scb::Shape*const* oldShapes, PxU32 oldShapeCount, Scb::Shape*const* newShapes, PxU32 newShapeCount) +{ + for(PxU32 i=0; i < oldShapeCount; i++) + shapePtrs[i] = oldShapes[i]; + for(PxU32 i=0; i < newShapeCount; i++) + shapePtrs[i+oldShapeCount] = newShapes[i]; +} + + +} // namespace Scb + +} + +#endif |