// // 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_NP_RIGIDACTOR_TEMPLATE #define PX_PHYSICS_NP_RIGIDACTOR_TEMPLATE #include "NpActorTemplate.h" #include "NpShapeManager.h" #include "NpConstraint.h" #include "NpFactory.h" // PX_SERIALIZATION #include "foundation/PxErrors.h" //~PX_SERIALIZATION namespace physx { template class NpRigidActorTemplate : public NpActorTemplate { private: typedef NpActorTemplate ActorTemplateClass; public: // PX_SERIALIZATION NpRigidActorTemplate(PxBaseFlags baseFlags) : ActorTemplateClass(baseFlags), mShapeManager(PxEmpty), mIndex(0xFFFFFFFF) {} virtual void requiresObjects(PxProcessPxBaseCallback& c); void preExportDataReset(); virtual void exportExtraData(PxSerializationContext& context); void importExtraData(PxDeserializationContext& context); void resolveReferences(PxDeserializationContext& context); //~PX_SERIALIZATION virtual ~NpRigidActorTemplate(); //--------------------------------------------------------------------------------- // PxActor implementation //--------------------------------------------------------------------------------- virtual void release(); // The rule is: If an API method is used somewhere in here, it has to be redeclared, else GCC whines virtual PxActorType::Enum getType() const = 0; virtual PxBounds3 getWorldBounds(float inflation=1.01f) const; virtual void setActorFlag(PxActorFlag::Enum flag, bool value); virtual void setActorFlags(PxActorFlags inFlags); //--------------------------------------------------------------------------------- // PxRigidActor implementation //--------------------------------------------------------------------------------- // Shapes virtual PxU32 getNbShapes() const; virtual PxU32 getShapes(PxShape** buffer, PxU32 bufferSize, PxU32 startIndex=0) const; // Constraint shaders virtual PxU32 getNbConstraints() const; virtual PxU32 getConstraints(PxConstraint** userBuffer, PxU32 bufferSize, PxU32 startIndex=0) const; // shared shapes virtual bool attachShape(PxShape& s); virtual void detachShape(PxShape& s, bool wakeOnLostTouch); //--------------------------------------------------------------------------------- // Miscellaneous //--------------------------------------------------------------------------------- NpRigidActorTemplate(PxType concreteType, PxBaseFlags baseFlags); // not optimal but the template alternative is hardly more readable and perf is not that critical here virtual void switchToNoSim() { PX_ASSERT(false); } virtual void switchFromNoSim() { PX_ASSERT(false); } void releaseShape(NpShape& s); PX_FORCE_INLINE NpShapeManager& getShapeManager() { return mShapeManager; } PX_FORCE_INLINE const NpShapeManager& getShapeManager() const { return mShapeManager; } void updateShaderComs(); PX_FORCE_INLINE PxU32 getRigidActorArrayIndex() const { return mIndex; } PX_FORCE_INLINE void setRigidActorArrayIndex(const PxU32& index) { mIndex = index; } bool resetFiltering(Scb::RigidObject& ro, PxShape*const* shapes, PxU32 shapeCount); #if PX_ENABLE_DEBUG_VISUALIZATION public: void visualize(Cm::RenderOutput& out, NpScene* scene); #endif protected: PX_FORCE_INLINE void setActorSimFlag(bool value); NpShapeManager mShapeManager; PxU32 mIndex; // index for the NpScene rigid actor array }; // PX_SERIALIZATION template void NpRigidActorTemplate::requiresObjects(PxProcessPxBaseCallback& c) { // export shapes PxU32 nbShapes = mShapeManager.getNbShapes(); for(PxU32 i=0;i void NpRigidActorTemplate::preExportDataReset() { //Clearing the aggregate ID for serialization so we avoid having a stale //reference after deserialization. The aggregate ID get's reset on readding to the //scene anyway. Sc::ActorCore& actorCore = NpActor::getScbFromPxActor(*this).getActorCore(); actorCore.setAggregateID(PX_INVALID_U32); mShapeManager.preExportDataReset(); mIndex = 0xFFFFFFFF; } template void NpRigidActorTemplate::exportExtraData(PxSerializationContext& context) { mShapeManager.exportExtraData(context); ActorTemplateClass::exportExtraData(context); } template void NpRigidActorTemplate::importExtraData(PxDeserializationContext& context) { mShapeManager.importExtraData(context); ActorTemplateClass::importExtraData(context); } template void NpRigidActorTemplate::resolveReferences(PxDeserializationContext& context) { const PxU32 nbShapes = mShapeManager.getNbShapes(); NpShape** shapes = const_cast(mShapeManager.getShapes()); for(PxU32 j=0;jonActorAttach(*this); } ActorTemplateClass::resolveReferences(context); } //~PX_SERIALIZATION template NpRigidActorTemplate::NpRigidActorTemplate(PxType concreteType, PxBaseFlags baseFlags) : ActorTemplateClass(concreteType, baseFlags, NULL, NULL) { } template NpRigidActorTemplate::~NpRigidActorTemplate() { // TODO: no mechanism for notifying shaders of actor destruction yet } template void NpRigidActorTemplate::release() { NpActor::releaseConstraints(*this); NpScene* scene = NpActor::getAPIScene(*this); if(mShapeManager.getPruningStructure()) { Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxRigidActor::release: Actor is part of a pruning structure, pruning structure is now invalid!"); mShapeManager.getPruningStructure()->invalidate(this); } mShapeManager.detachAll(scene, *this); ActorTemplateClass::release(); // PT: added for PxAggregate } template void NpRigidActorTemplate::releaseShape(NpShape& s) { // invalidate the pruning structure if the actor bounds changed if (mShapeManager.getPruningStructure()) { Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxRigidActor::releaseShape: Actor is part of a pruning structure, pruning structure is now invalid!"); mShapeManager.getPruningStructure()->invalidate(this); } mShapeManager.detachShape(s, *this); } template bool NpRigidActorTemplate::attachShape(PxShape& shape) { NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); PX_CHECK_AND_RETURN_VAL(!static_cast(shape).isExclusive() || shape.getActor()==NULL, "PxRigidActor::attachShape: shape must be shared or unowned", false); PX_SIMD_GUARD // invalidate the pruning structure if the actor bounds changed if (mShapeManager.getPruningStructure()) { Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxRigidActor::attachShape: Actor is part of a pruning structure, pruning structure is now invalid!"); mShapeManager.getPruningStructure()->invalidate(this); } mShapeManager.attachShape(static_cast(shape), *this); return true; } template void NpRigidActorTemplate::detachShape(PxShape& shape, bool wakeOnLostTouch) { NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); if (mShapeManager.getPruningStructure()) { Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxRigidActor::detachShape: Actor is part of a pruning structure, pruning structure is now invalid!"); mShapeManager.getPruningStructure()->invalidate(this); } if(!mShapeManager.detachShape(static_cast(shape), *this, wakeOnLostTouch)) { Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxRigidActor::detachShape: shape is not attached to this actor!"); } } template PxU32 NpRigidActorTemplate::getNbShapes() const { NP_READ_CHECK(NpActor::getOwnerScene(*this)); return mShapeManager.getNbShapes(); } template PxU32 NpRigidActorTemplate::getShapes(PxShape** buffer, PxU32 bufferSize, PxU32 startIndex) const { NP_READ_CHECK(NpActor::getOwnerScene(*this)); return mShapeManager.getShapes(buffer, bufferSize, startIndex); } template PxU32 NpRigidActorTemplate::getNbConstraints() const { NP_READ_CHECK(NpActor::getOwnerScene(*this)); return ActorTemplateClass::getNbConnectors(NpConnectorType::eConstraint); } template PxU32 NpRigidActorTemplate::getConstraints(PxConstraint** buffer, PxU32 bufferSize, PxU32 startIndex) const { NP_READ_CHECK(NpActor::getOwnerScene(*this)); return ActorTemplateClass::template getConnectors(NpConnectorType::eConstraint, buffer, bufferSize, startIndex); // Some people will love me for this one... The syntax is to be standard compliant and // picky gcc won't compile without it. It is needed if you call a templated member function // of a templated class } template PxBounds3 NpRigidActorTemplate::getWorldBounds(float inflation) const { NP_READ_CHECK(NpActor::getOwnerScene(*this)); PX_SIMD_GUARD; const PxBounds3 bounds = mShapeManager.getWorldBounds(*this); PX_ASSERT(bounds.isValid()); // PT: unfortunately we can't just scale the min/max vectors, we need to go through center/extents. const PxVec3 center = bounds.getCenter(); const PxVec3 inflatedExtents = bounds.getExtents() * inflation; return PxBounds3::centerExtents(center, inflatedExtents); } template PX_FORCE_INLINE void NpRigidActorTemplate::setActorSimFlag(bool value) { NpScene* scene = NpActor::getOwnerScene(*this); PxActorFlags oldFlags = ActorTemplateClass::getActorFlags(); bool hadNoSimFlag = oldFlags.isSet(PxActorFlag::eDISABLE_SIMULATION); PX_CHECK_AND_RETURN((getType() != PxActorType::eARTICULATION_LINK) || (!value && !hadNoSimFlag), "PxActor::setActorFlag: PxActorFlag::eDISABLE_SIMULATION is only supported by PxRigidDynamic and PxRigidStatic objects."); if (hadNoSimFlag && (!value)) { switchFromNoSim(); ActorTemplateClass::setActorFlagsInternal(oldFlags & (~PxActorFlag::eDISABLE_SIMULATION)); // needs to be done before the code below to make sure the latest flags get picked up if (scene) NpActor::addConstraintsToScene(); } else if ((!hadNoSimFlag) && value) { if (scene) NpActor::removeConstraintsFromScene(); ActorTemplateClass::setActorFlagsInternal(oldFlags | PxActorFlag::eDISABLE_SIMULATION); switchToNoSim(); } } template void NpRigidActorTemplate::setActorFlag(PxActorFlag::Enum flag, bool value) { NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); if (flag == PxActorFlag::eDISABLE_SIMULATION) setActorSimFlag(value); ActorTemplateClass::setActorFlagInternal(flag, value); } template void NpRigidActorTemplate::setActorFlags(PxActorFlags inFlags) { NP_WRITE_CHECK(NpActor::getOwnerScene(*this)); bool noSim = inFlags.isSet(PxActorFlag::eDISABLE_SIMULATION); setActorSimFlag(noSim); ActorTemplateClass::setActorFlagsInternal(inFlags); } template void NpRigidActorTemplate::updateShaderComs() { NpConnectorIterator iter = ActorTemplateClass::getConnectorIterator(NpConnectorType::eConstraint); while (PxBase* ser = iter.getNext()) { NpConstraint* c = static_cast(ser); c->comShift(this); } } PX_FORCE_INLINE static void fillResetFilteringShapeList(Scb::RigidObject& ro, Scb::Shape& scb, Scb::Shape** shapes, PxU32& shapeCount) { // It is important to filter out shapes that have been added while the simulation was running because for those there is nothing to do. if (!ro.isBuffered(Scb::RigidObjectBuffer::BF_Shapes) || !ro.isAddedShape(scb)) { shapes[shapeCount] = &scb; shapeCount++; } } template bool NpRigidActorTemplate::resetFiltering(Scb::RigidObject& ro, PxShape*const* shapes, PxU32 shapeCount) { PX_CHECK_AND_RETURN_VAL(!(ro.getActorFlags() & PxActorFlag::eDISABLE_SIMULATION), "PxScene::resetFiltering(): Not allowed if PxActorFlag::eDISABLE_SIMULATION is set!", false); for(PxU32 i=0; i < shapeCount; i++) { #if PX_CHECKED PxRigidActor* ra = shapes[i]->getActor(); if (ra != this) { bool found = false; if (ra == NULL) { NpShape*const* sh = mShapeManager.getShapes(); for(PxU32 j=0; j < mShapeManager.getNbShapes(); j++) { if (sh[j] == shapes[i]) { found = true; break; } } } PX_CHECK_AND_RETURN_VAL(found, "PxScene::resetFiltering(): specified shape not in actor!", false); } #endif PX_CHECK_AND_RETURN_VAL(static_cast(shapes[i])->getScbShape().getFlags() & (PxShapeFlag::eSIMULATION_SHAPE | PxShapeFlag::eTRIGGER_SHAPE), "PxScene::resetFiltering(): specified shapes not of type eSIMULATION_SHAPE or eTRIGGER_SHAPE!", false); } PxU32 sCount; if (shapes) sCount = shapeCount; else sCount = mShapeManager.getNbShapes(); PX_ALLOCA(scbShapes, Scb::Shape*, sCount); if (scbShapes) { if (shapes) // the user specified the shapes { PxU32 sAccepted = 0; for(PxU32 i=0; i < sCount; i++) { Scb::Shape& scb = static_cast(shapes[i])->getScbShape(); fillResetFilteringShapeList(ro, scb, scbShapes, sAccepted); } sCount = sAccepted; } else // the user just specified the actor and the shapes are taken from the actor { NpShape* const* sh = mShapeManager.getShapes(); PxU32 sAccepted = 0; for(PxU32 i=0; i < sCount; i++) { Scb::Shape& scb = sh[i]->getScbShape(); if (scb.getFlags() & (PxShapeFlag::eSIMULATION_SHAPE | PxShapeFlag::eTRIGGER_SHAPE)) { fillResetFilteringShapeList(ro, scb, scbShapes, sAccepted); } } sCount = sAccepted; } if (sCount) { ro.resetFiltering(scbShapes, sCount); } } return true; } #if PX_ENABLE_DEBUG_VISUALIZATION template void NpRigidActorTemplate::visualize(Cm::RenderOutput& out, NpScene* scene) { mShapeManager.visualize(out, scene, *this); } #endif // PX_ENABLE_DEBUG_VISUALIZATION } #endif