// 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_PARTICLE_SYSTEM #define PX_PHYSICS_SCB_PARTICLE_SYSTEM #include "PxPhysXConfig.h" #if PX_USE_PARTICLE_SYSTEM_API #include "ScParticleSystemCore.h" #include "ScbActor.h" #include "NpPhysics.h" #include "NpParticleFluidReadData.h" namespace physx { struct PxCudaReadWriteParticleBuffers; namespace Scb { struct ParticleSystemBuffer : public Scb::ActorBuffer { template struct Fns {}; // TODO : make the base class traits visible typedef Sc::ParticleSystemCore Core; typedef ParticleSystemBuffer Buf; enum { BF_Base = ActorBuffer::AttrCount }; // Regular attributes SCB_REGULAR_ATTRIBUTE(BF_Base+2, PxReal, Stiffness) SCB_REGULAR_ATTRIBUTE(BF_Base+3, PxReal, Viscosity) SCB_REGULAR_ATTRIBUTE(BF_Base+4, PxReal, Damping) SCB_REGULAR_ATTRIBUTE(BF_Base+5, PxVec3, ExternalAcceleration) SCB_REGULAR_ATTRIBUTE(BF_Base+6, PxPlane, ProjectionPlane) SCB_REGULAR_ATTRIBUTE(BF_Base+7, PxReal, ParticleMass) SCB_REGULAR_ATTRIBUTE(BF_Base+8, PxReal, Restitution) SCB_REGULAR_ATTRIBUTE(BF_Base+9, PxReal, DynamicFriction) SCB_REGULAR_ATTRIBUTE(BF_Base+10, PxReal, StaticFriction) SCB_REGULAR_ATTRIBUTE(BF_Base+11, PxFilterData, SimulationFilterData) SCB_REGULAR_ATTRIBUTE(BF_Base+12, PxParticleBaseFlags, Flags) enum { BF_ResetFiltering = 1<<(BF_Base+13) }; }; class DebugIndexPool; class ParticleSystem : 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 Sc::ParticleSystemCore Core; typedef ParticleSystemBuffer Buf; struct UserBufferLock { UserBufferLock(NpParticleFluidReadData* db, const char* callerName) : dataBuffer(db) { if(dataBuffer) { dataBuffer->lock(callerName); } } ~UserBufferLock() { if(dataBuffer) { dataBuffer->unlock(); } } NpParticleFluidReadData* dataBuffer; private: UserBufferLock& operator=(const UserBufferLock&); }; #define LOCK_PARTICLE_USER_BUFFERS(callerName) UserBufferLock userBufferLock(mReadParticleFluidData, callerName); struct ForceUpdates { ForceUpdates() : map(NULL), values(NULL), hasUpdates(false) {} void initialize(PxU32 maxParticles); void destroy(); PX_INLINE void add(PxU32 index, const PxVec3& value) { hasUpdates = true; if(!map->test(index)) { map->set(index); values[index] = value; return; } values[index] += value; } PX_INLINE void clear(PxU32 index) { PX_ASSERT(map); map->reset(index); } PX_INLINE void clear() { if(!hasUpdates) return; PX_ASSERT(map); map->clear(); hasUpdates = false; } Cm::BitMap* map; // can we make this an instance? PxVec3* values; bool hasUpdates; }; public: // PX_SERIALIZATION ParticleSystem(const PxEMPTY) : Scb::Actor(PxEmpty), mParticleSystem(PxEmpty) { mReadParticleFluidData = NULL; } void exportExtraData(PxSerializationContext& stream) { mParticleSystem.exportExtraData(stream); } void importExtraData(PxDeserializationContext& context) { mParticleSystem.importExtraData(context); } static void getBinaryMetaData(PxOutputStream& stream); //~PX_SERIALIZATION ParticleSystem(const PxActorType::Enum&, PxU32, bool); ~ParticleSystem(); //--------------------------------------------------------------------------------- // Wrapper for Sc::ParticleSystemCore interface //--------------------------------------------------------------------------------- PX_INLINE PxParticleBase* getPxParticleSystem(); PX_INLINE void removeFromScene(); bool createParticles(const PxParticleCreationData& creationData); void releaseParticles(PxU32 numParticles, const PxStrideIterator& indexBuffer); void releaseParticles(); void setPositions(PxU32 numParticles, const PxStrideIterator& indexBuffer, const PxStrideIterator& positionBuffer); void setVelocities(PxU32 numParticles, const PxStrideIterator& indexBuffer, const PxStrideIterator& velocitiesBuffer); void setRestOffsets(PxU32 numParticles, const PxStrideIterator& indexBuffer, const PxStrideIterator& restOffsetBuffer); void addForces(PxU32 numParticles, const PxStrideIterator& indexBuffer, const PxStrideIterator& forceBuffer, PxForceMode::Enum forceMode); PX_INLINE PxParticleReadData* lockParticleReadData(PxDataAccessFlags flags); PX_INLINE PxU32 getSimulationMethod() const; PX_INLINE PxReal getStiffness() const { return read(); } PX_INLINE void setStiffness(PxReal v) { write(v); } PX_INLINE PxReal getViscosity() const { return read(); } PX_INLINE void setViscosity(PxReal v) { write(v); } PX_INLINE PxReal getDamping() const { return read(); } PX_INLINE void setDamping(PxReal v) { write(v); } PX_INLINE PxVec3 getExternalAcceleration() const { return read(); } PX_INLINE void setExternalAcceleration(const PxVec3& v) { write(v); } PX_INLINE PxPlane getProjectionPlane() const { return read(); } PX_INLINE void setProjectionPlane(const PxPlane& v) { write(v); } PX_INLINE PxReal getParticleMass() const { return read(); } PX_INLINE void setParticleMass(PxReal v) { write(v); } PX_INLINE PxReal getRestitution() const { return read(); } PX_INLINE void setRestitution(PxReal v) { write(v); } PX_INLINE PxReal getDynamicFriction() const { return read(); } PX_INLINE void setDynamicFriction(PxReal v) { write(v);} PX_INLINE PxReal getStaticFriction() const { return read(); } PX_INLINE void setStaticFriction(PxReal v) { write(v); } PX_INLINE PxParticleBaseFlags getFlags() const { return read();} PX_INLINE void setFlags(PxParticleBaseFlags v) { write(v); } PX_INLINE PxFilterData getSimulationFilterData() const { return read(); } PX_INLINE void setSimulationFilterData(const PxFilterData& v) { write(v); } PX_INLINE void resetFiltering(); PX_INLINE PxParticleReadDataFlags getParticleReadDataFlags() const; PX_INLINE void setParticleReadDataFlags(PxParticleReadDataFlags); PX_INLINE PxU32 getParticleCount() const; PX_INLINE const Cm::BitMap& getParticleMap() const; PX_INLINE PxU32 getMaxParticles() const; PX_INLINE PxReal getMaxMotionDistance() const; PX_INLINE void setMaxMotionDistance(PxReal); PX_INLINE PxReal getRestOffset() const; PX_INLINE void setRestOffset(PxReal); PX_INLINE PxReal getContactOffset() const; PX_INLINE void setContactOffset(PxReal); PX_INLINE PxReal getRestParticleDistance() const; PX_INLINE void setRestParticleDistance(PxReal); PX_INLINE PxReal getGridSize() const; PX_INLINE void setGridSize(PxReal); PX_INLINE PxBounds3 getWorldBounds() const; //--------------------------------------------------------------------------------- // Data synchronization //--------------------------------------------------------------------------------- // Synchronously called when the scene starts to be simulated. void submitForceUpdates(PxReal timeStep); // Synchronously called with fetchResults. void syncState(); //--------------------------------------------------------------------------------- // Miscellaneous //--------------------------------------------------------------------------------- PX_FORCE_INLINE const Core& getScParticleSystem() const { return mParticleSystem; } // Only use if you know what you're doing! PX_FORCE_INLINE Core& getScParticleSystem() { return mParticleSystem; } // Only use if you know what you're doing! PX_FORCE_INLINE static const ParticleSystem&fromSc(const Core& a) { return static_cast(Actor::fromSc(a)); } PX_FORCE_INLINE static ParticleSystem& fromSc(Core &a) { Scb::Actor& actor = Actor::fromSc(a); ParticleSystem& ps = static_cast(actor); PX_UNUSED(ps); return static_cast(Actor::fromSc(a)); } static size_t getScOffset() { return reinterpret_cast(&reinterpret_cast(0)->mParticleSystem); } #if PX_SUPPORT_GPU_PHYSX PX_INLINE void enableDeviceExclusiveModeGpu(); PX_INLINE PxParticleDeviceExclusiveAccess* getDeviceExclusiveAccessGpu() const; #endif private: Core mParticleSystem; NpParticleFluidReadData* mReadParticleFluidData; ForceUpdates mForceUpdatesAcc; ForceUpdates mForceUpdatesVel; PX_FORCE_INLINE const Scb::ParticleSystemBuffer* getParticleSystemBuffer() const { return reinterpret_cast(getStream()); } PX_FORCE_INLINE Scb::ParticleSystemBuffer* getParticleSystemBuffer() { return reinterpret_cast(getStream()); } //--------------------------------------------------------------------------------- // Infrastructure for regular attributes //--------------------------------------------------------------------------------- struct Access: public BufferedAccess {}; template PX_FORCE_INLINE typename Buf::Fns::Arg read() const { return Access::read >(*this, mParticleSystem); } template PX_FORCE_INLINE void write(typename Buf::Fns::Arg v) { Access::write >(*this, mParticleSystem, v); } template PX_FORCE_INLINE void flush(const Buf& buf) { Access::flush >(*this, mParticleSystem, buf); } }; PX_INLINE PxParticleBase* ParticleSystem::getPxParticleSystem() { return mParticleSystem.getPxParticleBase(); } PX_INLINE void ParticleSystem::removeFromScene() { PX_ASSERT(!isBuffering() || getControlState()==ControlState::eREMOVE_PENDING); mForceUpdatesAcc.destroy(); mForceUpdatesVel.destroy(); } PX_INLINE PxParticleReadData* ParticleSystem::lockParticleReadData(PxDataAccessFlags flags) { // Don't use the macro here since releasing the lock should not be done automatically but by the user if(isBuffering()) { Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Particle data read not allowed while simulation is running."); return NULL; } if(!mReadParticleFluidData) mReadParticleFluidData = PX_NEW(NpParticleFluidReadData)(); mReadParticleFluidData->lock("PxParticleBase::lockParticleReadData()"); mReadParticleFluidData->setDataAccessFlags(flags); mParticleSystem.getParticleReadData(*mReadParticleFluidData); return mReadParticleFluidData; } PX_INLINE void ParticleSystem::resetFiltering() { if(!isBuffering()) { mParticleSystem.resetFiltering(); UPDATE_PVD_PROPERTIES_OBJECT() } else markUpdated(Buf::BF_ResetFiltering); } PX_INLINE PxParticleReadDataFlags ParticleSystem::getParticleReadDataFlags() const { return mParticleSystem.getParticleReadDataFlags(); } PX_INLINE void ParticleSystem::setParticleReadDataFlags(PxParticleReadDataFlags flags) { if(!isBuffering()) { mParticleSystem.setParticleReadDataFlags(flags); UPDATE_PVD_PROPERTIES_OBJECT() } } PX_INLINE PxU32 ParticleSystem::getParticleCount() const { return mParticleSystem.getParticleCount(); } PX_INLINE const Cm::BitMap& ParticleSystem::getParticleMap() const { return mParticleSystem.getParticleMap(); } PX_INLINE PxU32 ParticleSystem::getMaxParticles() const { return mParticleSystem.getMaxParticles(); } PX_INLINE PxReal ParticleSystem::getMaxMotionDistance() const { return mParticleSystem.getMaxMotionDistance(); } PX_INLINE void ParticleSystem::setMaxMotionDistance(PxReal distance) { if(!isBuffering()) { mParticleSystem.setMaxMotionDistance(distance); UPDATE_PVD_PROPERTIES_OBJECT() } } PX_INLINE PxReal ParticleSystem::getRestOffset() const { return mParticleSystem.getRestOffset(); } PX_INLINE void ParticleSystem::setRestOffset(PxReal restOffset) { if(!isBuffering()) { mParticleSystem.setRestOffset(restOffset); UPDATE_PVD_PROPERTIES_OBJECT() } } PX_INLINE PxReal ParticleSystem::getContactOffset() const { return mParticleSystem.getContactOffset(); } PX_INLINE void ParticleSystem::setContactOffset(PxReal contactOffset) { if(!isBuffering()) { mParticleSystem.setContactOffset(contactOffset); UPDATE_PVD_PROPERTIES_OBJECT() } } PX_INLINE PxReal ParticleSystem::getRestParticleDistance() const { return mParticleSystem.getRestParticleDistance(); } PX_INLINE void ParticleSystem::setRestParticleDistance(PxReal restParticleDistance) { if(!isBuffering()) { mParticleSystem.setRestParticleDistance(restParticleDistance); UPDATE_PVD_PROPERTIES_OBJECT() } } PX_INLINE PxReal ParticleSystem::getGridSize() const { return mParticleSystem.getGridSize(); } PX_INLINE void ParticleSystem::setGridSize(PxReal gridSize) { if(!isBuffering()) { mParticleSystem.setGridSize(gridSize); UPDATE_PVD_PROPERTIES_OBJECT() } } PX_INLINE PxBounds3 ParticleSystem::getWorldBounds() const { if(isBuffering()) { Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "PxActor::getWorldBounds(): Can't access particle world bounds during simulation without enabling bulk buffering."); return PxBounds3(); } return mParticleSystem.getWorldBounds(); } #if PX_SUPPORT_GPU_PHYSX PX_INLINE void ParticleSystem::enableDeviceExclusiveModeGpu() { mParticleSystem.enableDeviceExclusiveModeGpu(); } PX_INLINE PxParticleDeviceExclusiveAccess* ParticleSystem::getDeviceExclusiveAccessGpu() const { if(getFlags() & PxParticleBaseFlag::eGPU) return mParticleSystem.getDeviceExclusiveAccessGpu(); return NULL; } #endif } // namespace Scb } #endif // PX_USE_PARTICLE_SYSTEM_API #endif