// // 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-2018 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_BASE #define PX_PHYSICS_SCB_BASE #include "CmPhysXCommon.h" #include "ScbScene.h" namespace physx { #if PX_SUPPORT_PVD // PT: updatePvdProperties() is overloaded and the compiler needs to know 'this' type to do the right thing. // Thus we can't just move this as an inlined Base function. #define UPDATE_PVD_PROPERTIES_OBJECT() { \ Scb::Scene* scene_ = getScbSceneForAPI(); \ if(scene_ && !insertPending() ) \ scene_->getScenePvdClient().updatePvdProperties(this); } #else #define UPDATE_PVD_PROPERTIES_OBJECT() {} #endif namespace Scb { struct ControlState { enum Enum { /** \brief The object is not in the scene. The object has not been added to a scene yet. This is the default when an object gets created. In this state... \li ...user changes get written to Core directly. \li ...the object can not be in the list of dirty objects. \li ...the object can not be marked as eIS_UPDATED or eIS_RELEASED. */ eNOT_IN_SCENE = 0, /** \brief The object waits to get inserted into the scene internally. The object has been added to the scene while the simulation is running and is waiting to get fully registered in all layers. In this state... \li ...user changes get written to Core directly (since the object has not yet registered in the inner layers, hence, will not get accessed internally). \li ...the object is in the list of dirty objects. \li ...the object can not be marked as eIS_UPDATED or eIS_RELEASED. */ eINSERT_PENDING = 1, /** \brief The object is registered in the scene internally. The object has been added to the scene and is fully registered in all layers. In this state... \li ...user changes get written to a buffer object and get synced with Core at a sync point. \li ...the object can be in the list of dirty objects. \li ...the object can be marked as eIS_UPDATED but not eIS_RELEASED. */ eIN_SCENE = 2, /** \brief The object waits to get removed from the scene internally. The object is in the scene and fully registered in all layers but has been removed while the simulation is running and is now waiting to get unregistered from all layers. In this state... \li ...user changes get written to a buffer object and get synced with Core at a sync point. \li ...the object is in the list of dirty objects. \li ...the object can be marked as eIS_UPDATED or eIS_RELEASED. */ eREMOVE_PENDING = 3 }; }; struct ControlFlag { enum Enum { /** \brief An object property/state has been changed. A property/state of the object has been changed and needs to get synced to Core. Insertion & removal don't count. */ eIS_UPDATED = 1, /** \brief The object has been released. The object has not just been removed from the scene it has been released as well. The object will get destroyed after the sync has been completed. */ eIS_RELEASED = 2 }; }; /** \brief Base class for objects that should support buffering. This class has members to track the buffering related object state and mark which properties have been changed and need to get synced at sync points. */ class Base { //= 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. //================================================================================================== protected: // No-copy Base(const Base& c); Base& operator=(const Base& c); public: // PX_SERIALIZATION Base(const PxEMPTY) : mScene (NULL), mStreamPtr (NULL) { resetAllBufferFlags(); resetControl(ControlState::eNOT_IN_SCENE); } static void getBinaryMetaData(PxOutputStream& stream); //~PX_SERIALIZATION Base() : mScene (NULL), mStreamPtr (NULL) { setScbType(ScbType::eUNDEFINED); resetControl(ControlState::eNOT_IN_SCENE); resetAllBufferFlags(); } PX_INLINE bool isBuffering() const { const ControlState::Enum state = getControlState(); return state == ControlState::eREMOVE_PENDING || // pending remove not possible if not buffered (state == ControlState::eIN_SCENE && mScene->isPhysicsBuffering()); } PX_FORCE_INLINE Ps::IntBool insertPending() const { return getControlState() == ControlState::eINSERT_PENDING; } PX_FORCE_INLINE ScbType::Enum getScbType() const { return ScbType::Enum((mControlState&eTYPE_MASK)>>eTYPE_SHIFT); } PX_FORCE_INLINE void setScbType(ScbType::Enum type) { mControlState = (mControlState&~eTYPE_MASK)|(type<>eCONTROLFLAG_SHIFT; } PX_FORCE_INLINE void setControlFlag(ControlFlag::Enum f) { mControlState |= (f<>eCONTROLSTATE_SHIFT);} PX_FORCE_INLINE void setControlState(ControlState::Enum s) { mControlState = (mControlState&~eCONTROLSTATE_MASK)|(s<scheduleForUpdate(*this); } /** \brief Destroys the object. If the simulation is not running, this will release the object, else it will just mark the object as eIS_RELEASED and thus it will get deleted when the next sync point is reached. This method expects that the object has been removed from the scene first (or waits for removal). */ void destroy(); /** \brief Test if a property has been changed by the user. \param[in] flag The flag of the property to test for. Has to be within the bounds of eBUFFERFLAG_MASK. \return Positive value if the property has been changed by the user. */ PX_FORCE_INLINE Ps::IntBool isBuffered(PxU32 flag) const { PX_ASSERT((flag & eBUFFERFLAG_MASK) == flag); return Ps::IntBool(mControlState & flag); } PX_FORCE_INLINE PxU8* getStream() { return mStreamPtr ? mStreamPtr : mStreamPtr = mScene->getStream(getScbType()); } PX_FORCE_INLINE const PxU8* getStream() const { PX_ASSERT(mStreamPtr); return mStreamPtr; } /** \brief Helper method to trigger object tracking after a property change. This method will flag the marked property as changed and will add the object to the list of updated objects if it is not registered already. \param[in] flag The flag of the changed property. Has to be within the bounds of eBUFFERFLAG_MASK. */ PX_FORCE_INLINE void markUpdated(PxU32 flag) { PX_ASSERT((flag & eBUFFERFLAG_MASK) == flag); scheduleForUpdate(); mControlState |= flag; } protected: ~Base(){} PX_FORCE_INLINE PxU32 getBufferFlags() const { return mControlState & eBUFFERFLAG_MASK; } PX_FORCE_INLINE void setBufferFlag(PxU32 flag) { PX_ASSERT((flag & eBUFFERFLAG_MASK) == flag); mControlState |= flag; } PX_FORCE_INLINE void resetBufferFlag(PxU32 flag) { PX_ASSERT((flag & eBUFFERFLAG_MASK) == flag); mControlState &= ~flag; } PX_FORCE_INLINE void resetAllBufferFlags() { mControlState &=~eBUFFERFLAG_MASK; } /** \brief Cleanup method after the object has been synced. Every buffering object should implement a syncState() method where the buffered user changes get synced with Core. Call this method at the end of the syncState() method to clear all buffer flags and references. */ PX_FORCE_INLINE void postSyncState() { // DS: this can get called even when mScene == NULL, by removeAggregate (see AggregateFreeStandingCreateDelete test) // TODO(dsequeira): investigate that when the dust settles on shape refactoring PX_ASSERT(getControlState()!=ControlState::eNOT_IN_SCENE || mScene == NULL); PX_ASSERT(getScbType()!=ScbType::eUNDEFINED); mStreamPtr = NULL; resetAllBufferFlags(); // resetControlFlag(ControlFlag::eIS_UPDATED); } private: enum { eBUFFERFLAG_MASK = (1<<24) - 1, eTYPE_MASK = 15<<24, eCONTROLFLAG_MASK = 3<<28, eCONTROLSTATE_MASK = 3<<30, eCONTROL_MASK = 15<<28}; enum { eTYPE_SHIFT = 24, eCONTROLFLAG_SHIFT = 28, eCONTROLSTATE_SHIFT = 30}; /** \brief Scene pointer. The scene pointer get set as soon as the user adds an object to the scene. However, it does not get cleared until the object has been removed from the scene internally, i.e., removing an object while the simulation is running will not set this pointer to NULL immediately. */ Scb::Scene* mScene; /** \brief Mix of buffering related states/flags. highest lowest | 2 | 2 | 4 | 24 | | ControlState | ControlFlag | ScbType | buffer attribute flags | The buffer attribute flags mark which of the properties have been updated. The specific implementation of this class defines those flags. */ PxU32 mControlState; /** \brief Data buffer to store property/state changes temporarily. Pointer to a temporary struct where user changes made while the simulation is running are buffered. The structure is currently as large as necessary to hold all properties of a buffered object. Even if only a single property of an object gets changed, the whole structure is assigned. The motivation for this was to keep the implementation complexity low based on the assumption that users will not change all objects in a scene every frame. The temporary buffer gets assigned on demand and is returned to pools after the data has been synced to Core. The pointer is then set to NULL again. This kind of buffer can not be used for properties that get written by the simulation (for example, pose, velocity, sleep state). Those need to be permanently buffered in the specific implementation of this class, else the user might get an inconsistent picture of the scene object state. @see postSyncState() */ PxU8* mStreamPtr; }; } // namespace Scb } #endif