aboutsummaryrefslogtreecommitdiff
path: root/PhysX_3.4/Source/PhysX/src/buffering/ScbRigidObject.h
diff options
context:
space:
mode:
Diffstat (limited to 'PhysX_3.4/Source/PhysX/src/buffering/ScbRigidObject.h')
-rw-r--r--PhysX_3.4/Source/PhysX/src/buffering/ScbRigidObject.h530
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