466 lines
16 KiB
C++
466 lines
16 KiB
C++
//
|
|
// 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 APIClass>
|
|
class NpRigidActorTemplate : public NpActorTemplate<APIClass>
|
|
{
|
|
private:
|
|
typedef NpActorTemplate<APIClass> 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<class APIClass>
|
|
void NpRigidActorTemplate<APIClass>::requiresObjects(PxProcessPxBaseCallback& c)
|
|
{
|
|
// export shapes
|
|
PxU32 nbShapes = mShapeManager.getNbShapes();
|
|
for(PxU32 i=0;i<nbShapes;i++)
|
|
{
|
|
NpShape* np = mShapeManager.getShapes()[i];
|
|
c.process(*np);
|
|
}
|
|
}
|
|
|
|
template<class APIClass>
|
|
void NpRigidActorTemplate<APIClass>::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<class APIClass>
|
|
void NpRigidActorTemplate<APIClass>::exportExtraData(PxSerializationContext& context)
|
|
{
|
|
mShapeManager.exportExtraData(context);
|
|
ActorTemplateClass::exportExtraData(context);
|
|
}
|
|
|
|
template<class APIClass>
|
|
void NpRigidActorTemplate<APIClass>::importExtraData(PxDeserializationContext& context)
|
|
{
|
|
mShapeManager.importExtraData(context);
|
|
ActorTemplateClass::importExtraData(context);
|
|
}
|
|
|
|
template<class APIClass>
|
|
void NpRigidActorTemplate<APIClass>::resolveReferences(PxDeserializationContext& context)
|
|
{
|
|
const PxU32 nbShapes = mShapeManager.getNbShapes();
|
|
NpShape** shapes = const_cast<NpShape**>(mShapeManager.getShapes());
|
|
for(PxU32 j=0;j<nbShapes;j++)
|
|
{
|
|
context.translatePxBase(shapes[j]);
|
|
shapes[j]->onActorAttach(*this);
|
|
}
|
|
|
|
ActorTemplateClass::resolveReferences(context);
|
|
}
|
|
|
|
//~PX_SERIALIZATION
|
|
|
|
template<class APIClass>
|
|
NpRigidActorTemplate<APIClass>::NpRigidActorTemplate(PxType concreteType, PxBaseFlags baseFlags)
|
|
: ActorTemplateClass(concreteType, baseFlags, NULL, NULL)
|
|
{
|
|
}
|
|
|
|
template<class APIClass>
|
|
NpRigidActorTemplate<APIClass>::~NpRigidActorTemplate()
|
|
{
|
|
// TODO: no mechanism for notifying shaders of actor destruction yet
|
|
}
|
|
|
|
|
|
template<class APIClass>
|
|
void NpRigidActorTemplate<APIClass>::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<class APIClass>
|
|
void NpRigidActorTemplate<APIClass>::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<class APIClass>
|
|
bool NpRigidActorTemplate<APIClass>::attachShape(PxShape& shape)
|
|
{
|
|
NP_WRITE_CHECK(NpActor::getOwnerScene(*this));
|
|
PX_CHECK_AND_RETURN_VAL(!static_cast<NpShape&>(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<NpShape&>(shape), *this);
|
|
return true;
|
|
}
|
|
|
|
template<class APIClass>
|
|
void NpRigidActorTemplate<APIClass>::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<NpShape&>(shape), *this, wakeOnLostTouch))
|
|
{
|
|
Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxRigidActor::detachShape: shape is not attached to this actor!");
|
|
}
|
|
}
|
|
|
|
|
|
template<class APIClass>
|
|
PxU32 NpRigidActorTemplate<APIClass>::getNbShapes() const
|
|
{
|
|
NP_READ_CHECK(NpActor::getOwnerScene(*this));
|
|
return mShapeManager.getNbShapes();
|
|
}
|
|
|
|
|
|
template<class APIClass>
|
|
PxU32 NpRigidActorTemplate<APIClass>::getShapes(PxShape** buffer, PxU32 bufferSize, PxU32 startIndex) const
|
|
{
|
|
NP_READ_CHECK(NpActor::getOwnerScene(*this));
|
|
return mShapeManager.getShapes(buffer, bufferSize, startIndex);
|
|
}
|
|
|
|
template<class APIClass>
|
|
PxU32 NpRigidActorTemplate<APIClass>::getNbConstraints() const
|
|
{
|
|
NP_READ_CHECK(NpActor::getOwnerScene(*this));
|
|
return ActorTemplateClass::getNbConnectors(NpConnectorType::eConstraint);
|
|
}
|
|
|
|
|
|
template<class APIClass>
|
|
PxU32 NpRigidActorTemplate<APIClass>::getConstraints(PxConstraint** buffer, PxU32 bufferSize, PxU32 startIndex) const
|
|
{
|
|
NP_READ_CHECK(NpActor::getOwnerScene(*this));
|
|
return ActorTemplateClass::template getConnectors<PxConstraint>(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<class APIClass>
|
|
PxBounds3 NpRigidActorTemplate<APIClass>::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<class APIClass>
|
|
PX_FORCE_INLINE void NpRigidActorTemplate<APIClass>::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<class APIClass>
|
|
void NpRigidActorTemplate<APIClass>::setActorFlag(PxActorFlag::Enum flag, bool value)
|
|
{
|
|
NP_WRITE_CHECK(NpActor::getOwnerScene(*this));
|
|
|
|
if (flag == PxActorFlag::eDISABLE_SIMULATION)
|
|
setActorSimFlag(value);
|
|
|
|
ActorTemplateClass::setActorFlagInternal(flag, value);
|
|
}
|
|
|
|
|
|
template<class APIClass>
|
|
void NpRigidActorTemplate<APIClass>::setActorFlags(PxActorFlags inFlags)
|
|
{
|
|
NP_WRITE_CHECK(NpActor::getOwnerScene(*this));
|
|
|
|
bool noSim = inFlags.isSet(PxActorFlag::eDISABLE_SIMULATION);
|
|
setActorSimFlag(noSim);
|
|
|
|
ActorTemplateClass::setActorFlagsInternal(inFlags);
|
|
}
|
|
|
|
|
|
template<class APIClass>
|
|
void NpRigidActorTemplate<APIClass>::updateShaderComs()
|
|
{
|
|
NpConnectorIterator iter = ActorTemplateClass::getConnectorIterator(NpConnectorType::eConstraint);
|
|
while (PxBase* ser = iter.getNext())
|
|
{
|
|
NpConstraint* c = static_cast<NpConstraint*>(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<class APIClass>
|
|
bool NpRigidActorTemplate<APIClass>::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<NpShape*>(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<NpShape*>(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<class APIClass>
|
|
void NpRigidActorTemplate<APIClass>::visualize(Cm::RenderOutput& out, NpScene* scene)
|
|
{
|
|
mShapeManager.visualize(out, scene, *this);
|
|
}
|
|
#endif // PX_ENABLE_DEBUG_VISUALIZATION
|
|
|
|
}
|
|
|
|
#endif
|