591 lines
20 KiB
C++
591 lines
20 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 NP_ARTICULATION_TEMPLATE
|
|
#define NP_ARTICULATION_TEMPLATE
|
|
|
|
#include "CmPhysXCommon.h"
|
|
|
|
#if PX_ENABLE_DEBUG_VISUALIZATION
|
|
#include "CmRenderOutput.h"
|
|
#endif
|
|
|
|
#include "ScbArticulation.h"
|
|
#include "NpArticulationLink.h"
|
|
#include "NpAggregate.h"
|
|
|
|
namespace physx
|
|
{
|
|
class NpArticulationLink;
|
|
class NpScene;
|
|
class NpAggregate;
|
|
class PxAggregate;
|
|
|
|
class PxArticulationImpl
|
|
{
|
|
//= 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.
|
|
//==================================================================================================
|
|
public:
|
|
|
|
~PxArticulationImpl()
|
|
{
|
|
}
|
|
|
|
PxArticulationImpl(bool reducedCoordinate) :
|
|
mArticulation(reducedCoordinate), mAggregate(NULL), mName(NULL), mCacheVersion(0) {}
|
|
|
|
// PX_SERIALIZATION
|
|
PxArticulationImpl(const PxEMPTY) : mArticulation(PxEmpty), mArticulationLinks(PxEmpty) {}
|
|
|
|
static void getBinaryMetaData(PxOutputStream& stream);
|
|
//~PX_SERIALIZATION
|
|
|
|
|
|
PX_INLINE PxScene* getScene() const;
|
|
|
|
PX_INLINE void setSleepThreshold(PxReal threshold);
|
|
PX_INLINE PxReal getSleepThreshold() const;
|
|
|
|
PX_INLINE void setStabilizationThreshold(PxReal threshold);
|
|
PX_INLINE PxReal getStabilizationThreshold() const;
|
|
|
|
PX_INLINE void setWakeCounter(PxReal wakeCounterValue);
|
|
PX_INLINE PxReal getWakeCounter() const;
|
|
|
|
PX_INLINE void setSolverIterationCounts(PxU32 positionIters, PxU32 velocityIters);
|
|
PX_INLINE void getSolverIterationCounts(PxU32 & positionIters, PxU32 & velocityIters) const;
|
|
|
|
PX_INLINE bool isSleeping() const;
|
|
PX_INLINE void wakeUp();
|
|
PX_INLINE void putToSleep();
|
|
|
|
PX_INLINE PxU32 getNbLinks() const;
|
|
PX_INLINE PxU32 getLinks(PxArticulationLink** userBuffer, PxU32 bufferSize, PxU32 startIndex) const;
|
|
|
|
PX_INLINE PxBounds3 getWorldBounds(float inflation = 1.01f) const;
|
|
|
|
PX_INLINE PxAggregate* getAggregate() const;
|
|
|
|
// Debug name
|
|
PX_INLINE void setName(const char*);
|
|
PX_INLINE const char* getName() const;
|
|
|
|
|
|
//---------------------------------------------------------------------------------
|
|
// Miscellaneous
|
|
//---------------------------------------------------------------------------------
|
|
|
|
PX_INLINE void addToLinkList(NpArticulationLink& link) { mArticulationLinks.pushBack(&link); }
|
|
PX_INLINE bool removeLinkFromList(NpArticulationLink& link) { PX_ASSERT(mArticulationLinks.find(&link) != mArticulationLinks.end()); return mArticulationLinks.findAndReplaceWithLast(&link); }
|
|
PX_FORCE_INLINE NpArticulationLink* const* getLinks() { return mArticulationLinks.begin(); }
|
|
|
|
PX_INLINE NpArticulationLink* getRoot();
|
|
|
|
PX_INLINE NpScene* getAPIScene() const;
|
|
PX_INLINE NpScene* getOwnerScene() const; // the scene the user thinks the actor is in, or from which the actor is pending removal
|
|
|
|
PX_FORCE_INLINE void setAggregate(PxAggregate* a) { mAggregate = static_cast<NpAggregate*>(a); }
|
|
|
|
PX_INLINE void wakeUpInternal(bool forceWakeUp, bool autowake);
|
|
|
|
PX_INLINE void setGlobalPose();
|
|
|
|
PX_FORCE_INLINE Scb::Articulation& getScbArticulation() { return mArticulation; }
|
|
PX_FORCE_INLINE const Scb::Articulation& getScbArticulation() const { return mArticulation; }
|
|
|
|
PX_FORCE_INLINE void increaseCacheVersion() { mCacheVersion++; }
|
|
|
|
void recomputeLinkIDs();
|
|
|
|
#if PX_ENABLE_DEBUG_VISUALIZATION
|
|
public:
|
|
PX_INLINE void visualize(Cm::RenderOutput& out, NpScene* scene);
|
|
#endif
|
|
|
|
Scb::Articulation mArticulation;
|
|
NpArticulationLinkArray mArticulationLinks;
|
|
NpAggregate* mAggregate;
|
|
const char* mName;
|
|
PxU32 mCacheVersion;
|
|
};
|
|
|
|
template <typename APIClass>
|
|
class NpArticulationTemplate : public APIClass, public Ps::UserAllocated
|
|
{
|
|
//= 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.
|
|
//==================================================================================================
|
|
public:
|
|
|
|
virtual ~NpArticulationTemplate();
|
|
NpArticulationTemplate(PxType concreteType, PxBaseFlags baseFlags)
|
|
: APIClass(concreteType, baseFlags)
|
|
, mImpl(concreteType == PxConcreteType::eARTICULATION_REDUCED_COORDINATE)
|
|
{}
|
|
|
|
// PX_SERIALIZATION
|
|
NpArticulationTemplate(PxBaseFlags baseFlags) : APIClass(baseFlags), mImpl(PxEmpty) {}
|
|
void preExportDataReset() {}
|
|
|
|
virtual void exportExtraData(PxSerializationContext& stream);
|
|
void importExtraData(PxDeserializationContext& context);
|
|
void resolveReferences(PxDeserializationContext& context);
|
|
virtual void requiresObjects(PxProcessPxBaseCallback& c);
|
|
|
|
//~PX_SERIALIZATION
|
|
|
|
virtual void release();
|
|
|
|
virtual PxScene* getScene() const { return mImpl.getScene(); }
|
|
|
|
virtual void setSleepThreshold(PxReal threshold) { mImpl.setSleepThreshold(threshold); }
|
|
virtual PxReal getSleepThreshold() const { return mImpl.getSleepThreshold();}
|
|
|
|
virtual void setStabilizationThreshold(PxReal threshold) { mImpl.setStabilizationThreshold(threshold); }
|
|
virtual PxReal getStabilizationThreshold() const { return mImpl.getStabilizationThreshold(); }
|
|
|
|
virtual void setWakeCounter(PxReal wakeCounterValue) { mImpl.setWakeCounter(wakeCounterValue); }
|
|
virtual PxReal getWakeCounter() const {return mImpl.getWakeCounter(); }
|
|
|
|
virtual void setSolverIterationCounts(PxU32 positionIters, PxU32 velocityIters) { mImpl.setSolverIterationCounts(positionIters, velocityIters); }
|
|
virtual void getSolverIterationCounts(PxU32 & positionIters, PxU32 & velocityIters) const { mImpl.getSolverIterationCounts(positionIters, velocityIters); }
|
|
|
|
virtual bool isSleeping() const { return mImpl.isSleeping(); }
|
|
virtual void wakeUp() { mImpl.wakeUp(); }
|
|
virtual void putToSleep() { mImpl.putToSleep(); }
|
|
|
|
virtual PxU32 getNbLinks() const { return mImpl.getNbLinks(); }
|
|
virtual PxU32 getLinks(PxArticulationLink** userBuffer, PxU32 bufferSize, PxU32 startIndex) const
|
|
{
|
|
return mImpl.getLinks(userBuffer, bufferSize, startIndex);
|
|
}
|
|
|
|
virtual PxBounds3 getWorldBounds(float inflation = 1.01f) const { return mImpl.getWorldBounds(inflation); }
|
|
|
|
virtual PxAggregate* getAggregate() const { return mImpl.getAggregate(); }
|
|
|
|
// Debug name
|
|
virtual void setName(const char* name) { return mImpl.setName(name); }
|
|
virtual const char* getName() const { return mImpl.getName(); }
|
|
|
|
virtual PxArticulationLink* createLink(PxArticulationLink* parent, const PxTransform& pose);
|
|
|
|
//---------------------------------------------------------------------------------
|
|
// Miscellaneous
|
|
//---------------------------------------------------------------------------------
|
|
NpArticulationTemplate();
|
|
|
|
virtual const PxArticulationImpl* getImpl() const { return &mImpl; }
|
|
|
|
virtual PxArticulationImpl* getImpl() { return &mImpl; }
|
|
|
|
#if PX_ENABLE_DEBUG_VISUALIZATION
|
|
public:
|
|
void visualize(Cm::RenderOutput& out, NpScene* scene) { mImpl.visualize(out, scene); }
|
|
#endif
|
|
|
|
public:
|
|
PxArticulationImpl mImpl;
|
|
};
|
|
|
|
// PX_SERIALIZATION
|
|
template<typename APIClass>
|
|
void NpArticulationTemplate<APIClass>::requiresObjects(PxProcessPxBaseCallback& c)
|
|
{
|
|
// Collect articulation links
|
|
const PxU32 nbLinks = mImpl.mArticulationLinks.size();
|
|
for (PxU32 i = 0; i < nbLinks; i++)
|
|
c.process(*mImpl.mArticulationLinks[i]);
|
|
}
|
|
|
|
template<typename APIClass>
|
|
void NpArticulationTemplate<APIClass>::exportExtraData(PxSerializationContext& stream)
|
|
{
|
|
Cm::exportInlineArray(mImpl.mArticulationLinks, stream);
|
|
stream.writeName(mImpl.mName);
|
|
}
|
|
|
|
template<typename APIClass>
|
|
void NpArticulationTemplate<APIClass>::importExtraData(PxDeserializationContext& context)
|
|
{
|
|
Cm::importInlineArray(mImpl.mArticulationLinks, context);
|
|
context.readName(mImpl.mName);
|
|
}
|
|
|
|
void NpSetArticulationOnJoint(PxArticulationJointBase& jointBase, PxArticulationImpl& articulation);
|
|
|
|
template<typename APIClass>
|
|
void NpArticulationTemplate<APIClass>::resolveReferences(PxDeserializationContext& context)
|
|
{
|
|
const PxU32 nbLinks = mImpl.mArticulationLinks.size();
|
|
for (PxU32 i = 0; i < nbLinks; i++)
|
|
{
|
|
NpArticulationLink*& link = mImpl.mArticulationLinks[i];
|
|
context.translatePxBase(link);
|
|
|
|
PxArticulationJointBase* pxJointBase = link->getInboundJoint();
|
|
if (pxJointBase)
|
|
{
|
|
//KS - introduced C function to do this to avoid undefined types and circular dependency problems
|
|
//backlinks to articulation impl can only be initialized
|
|
//after articulation object has been constructed.
|
|
NpSetArticulationOnJoint(*pxJointBase, mImpl);
|
|
}
|
|
}
|
|
|
|
mImpl.mAggregate = NULL;
|
|
}
|
|
// ~PX_SERIALIZATION
|
|
|
|
template<typename APIClass>
|
|
NpArticulationTemplate<APIClass>::NpArticulationTemplate()
|
|
: APIClass(PxConcreteType::eARTICULATION, PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE)
|
|
{
|
|
}
|
|
|
|
template<typename APIClass>
|
|
NpArticulationTemplate<APIClass>::~NpArticulationTemplate()
|
|
{
|
|
NpFactory::getInstance().onArticulationRelease(this);
|
|
}
|
|
|
|
template<typename APIClass>
|
|
void NpArticulationTemplate<APIClass>::release()
|
|
{
|
|
NP_WRITE_CHECK(mImpl.getOwnerScene());
|
|
|
|
NpPhysics::getInstance().notifyDeletionListenersUserRelease(this, PxArticulationBase::userData);
|
|
|
|
//!!!AL TODO: Order should not matter in this case. Optimize by having a path which does not restrict release to leaf links or
|
|
// by using a more advanced data structure
|
|
PxU32 idx = 0;
|
|
while (mImpl.mArticulationLinks.size())
|
|
{
|
|
idx = idx % mImpl.mArticulationLinks.size();
|
|
|
|
if (mImpl.mArticulationLinks[idx]->getNbChildren() == 0)
|
|
{
|
|
mImpl.mArticulationLinks[idx]->releaseInternal(); // deletes joint, link and removes link from list
|
|
}
|
|
else
|
|
{
|
|
idx++;
|
|
}
|
|
}
|
|
|
|
NpScene* npScene = mImpl.getAPIScene();
|
|
if (npScene)
|
|
{
|
|
npScene->getScene().removeArticulation(mImpl.getScbArticulation());
|
|
|
|
npScene->removeFromArticulationList(*this);
|
|
}
|
|
|
|
mImpl.mArticulationLinks.clear();
|
|
|
|
mImpl.mArticulation.destroy();
|
|
}
|
|
|
|
template<typename APIClass>
|
|
PxArticulationLink* NpArticulationTemplate<APIClass>::createLink(PxArticulationLink* parent, const PxTransform& pose)
|
|
{
|
|
PX_CHECK_AND_RETURN_NULL(pose.isSane(), "NpArticulation::createLink pose is not valid.");
|
|
PX_CHECK_AND_RETURN_NULL(mImpl.mArticulationLinks.size()<64, "NpArticulation::createLink: at most 64 links allowed in an articulation");
|
|
|
|
NP_WRITE_CHECK(mImpl.getOwnerScene());
|
|
|
|
if (parent && mImpl.mArticulationLinks.empty())
|
|
{
|
|
Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Root articulation link must have NULL parent pointer!");
|
|
return NULL;
|
|
}
|
|
|
|
if (!parent && !mImpl.mArticulationLinks.empty())
|
|
{
|
|
Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Non-root articulation link must have valid parent pointer!");
|
|
return NULL;
|
|
}
|
|
|
|
//increase cache version
|
|
mImpl.mCacheVersion++;
|
|
|
|
NpArticulationLink* parentLink = static_cast<NpArticulationLink*>(parent);
|
|
|
|
NpArticulationLink* link = static_cast<NpArticulationLink*>(NpFactory::getInstance().createArticulationLink(*this, parentLink, pose.getNormalized()));
|
|
|
|
if (link)
|
|
{
|
|
NpScene* scene = mImpl.getAPIScene();
|
|
if (scene)
|
|
scene->addArticulationLink(*link);
|
|
|
|
mImpl.addToLinkList(*link);
|
|
}
|
|
return link;
|
|
}
|
|
|
|
PxScene* PxArticulationImpl::getScene() const
|
|
{
|
|
return getAPIScene();
|
|
}
|
|
|
|
void PxArticulationImpl::setSolverIterationCounts(PxU32 positionIters, PxU32 velocityIters)
|
|
{
|
|
NP_WRITE_CHECK(getOwnerScene());
|
|
PX_CHECK_AND_RETURN(positionIters > 0, "Articulation::setSolverIterationCount: positionIters must be more than zero!");
|
|
PX_CHECK_AND_RETURN(positionIters <= 255, "Articulation::setSolverIterationCount: positionIters must be no greater than 255!");
|
|
PX_CHECK_AND_RETURN(velocityIters > 0, "Articulation::setSolverIterationCount: velocityIters must be more than zero!");
|
|
PX_CHECK_AND_RETURN(velocityIters <= 255, "Articulation::setSolverIterationCount: velocityIters must be no greater than 255!");
|
|
|
|
getScbArticulation().setSolverIterationCounts((velocityIters & 0xff) << 8 | (positionIters & 0xff));
|
|
}
|
|
|
|
void PxArticulationImpl::getSolverIterationCounts(PxU32 & positionIters, PxU32 & velocityIters) const
|
|
{
|
|
NP_READ_CHECK(getOwnerScene());
|
|
PxU16 x = getScbArticulation().getSolverIterationCounts();
|
|
velocityIters = PxU32(x >> 8);
|
|
positionIters = PxU32(x & 0xff);
|
|
}
|
|
|
|
void PxArticulationImpl::setGlobalPose()
|
|
{
|
|
PX_CHECK_AND_RETURN(getAPIScene(), "PxArticulation::setGlobalPose: object must be in a scene");
|
|
NP_WRITE_CHECK(getOwnerScene());
|
|
|
|
mArticulation.setGlobalPose();
|
|
|
|
//This code is force PVD to update other links position
|
|
if (!mArticulation.isBuffering())
|
|
{
|
|
physx::NpArticulationLink*const* links = getLinks();
|
|
|
|
const PxU32 nbLinks = getNbLinks();
|
|
for (PxU32 i = 1; i < nbLinks; ++i)
|
|
{
|
|
physx::NpArticulationLink* link = links[i];
|
|
//in the lowlevel articulation, we have already updated bodyCore's body2World
|
|
const PxTransform internalPose = link->getScbBodyFast().getScBody().getBody2World();
|
|
link->getScbBodyFast().setBody2World(internalPose, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool PxArticulationImpl::isSleeping() const
|
|
{
|
|
NP_READ_CHECK(getOwnerScene());
|
|
PX_CHECK_AND_RETURN_VAL(getAPIScene(), "Articulation::isSleeping: articulation must be in a scene.", true);
|
|
|
|
return getScbArticulation().isSleeping();
|
|
}
|
|
|
|
void PxArticulationImpl::setSleepThreshold(PxReal threshold)
|
|
{
|
|
NP_WRITE_CHECK(getOwnerScene());
|
|
getScbArticulation().setSleepThreshold(threshold);
|
|
}
|
|
|
|
PxReal PxArticulationImpl::getSleepThreshold() const
|
|
{
|
|
NP_READ_CHECK(getOwnerScene());
|
|
return getScbArticulation().getSleepThreshold();
|
|
}
|
|
|
|
void PxArticulationImpl::setStabilizationThreshold(PxReal threshold)
|
|
{
|
|
NP_WRITE_CHECK(getOwnerScene());
|
|
getScbArticulation().setFreezeThreshold(threshold);
|
|
}
|
|
|
|
PxReal PxArticulationImpl::getStabilizationThreshold() const
|
|
{
|
|
NP_READ_CHECK(getOwnerScene());
|
|
return getScbArticulation().getFreezeThreshold();
|
|
}
|
|
|
|
void PxArticulationImpl::setWakeCounter(PxReal wakeCounterValue)
|
|
{
|
|
NP_WRITE_CHECK(getOwnerScene());
|
|
|
|
for (PxU32 i = 0; i < mArticulationLinks.size(); i++)
|
|
{
|
|
mArticulationLinks[i]->getScbBodyFast().setWakeCounter(wakeCounterValue);
|
|
}
|
|
|
|
getScbArticulation().setWakeCounter(wakeCounterValue);
|
|
}
|
|
|
|
PxReal PxArticulationImpl::getWakeCounter() const
|
|
{
|
|
NP_READ_CHECK(getOwnerScene());
|
|
return getScbArticulation().getWakeCounter();
|
|
}
|
|
|
|
void PxArticulationImpl::wakeUpInternal(bool forceWakeUp, bool autowake)
|
|
{
|
|
NpScene* scene = getAPIScene();
|
|
PX_ASSERT(scene);
|
|
PxReal wakeCounterResetValue = scene->getWakeCounterResetValueInteral();
|
|
|
|
Scb::Articulation& a = getScbArticulation();
|
|
PxReal wakeCounter = a.getWakeCounter();
|
|
|
|
bool needsWakingUp = isSleeping() && (autowake || forceWakeUp);
|
|
if (autowake && (wakeCounter < wakeCounterResetValue))
|
|
{
|
|
wakeCounter = wakeCounterResetValue;
|
|
needsWakingUp = true;
|
|
}
|
|
|
|
if (needsWakingUp)
|
|
{
|
|
for (PxU32 i = 0; i < mArticulationLinks.size(); i++)
|
|
{
|
|
mArticulationLinks[i]->getScbBodyFast().wakeUpInternal(wakeCounter);
|
|
}
|
|
|
|
a.wakeUpInternal(wakeCounter);
|
|
}
|
|
}
|
|
|
|
void PxArticulationImpl::wakeUp()
|
|
{
|
|
NpScene* scene = getAPIScene();
|
|
|
|
NP_WRITE_CHECK(getOwnerScene()); // don't use the API scene, since it will be NULL on pending removal
|
|
PX_CHECK_AND_RETURN(scene, "Articulation::wakeUp: articulation must be in a scene.");
|
|
|
|
for (PxU32 i = 0; i < mArticulationLinks.size(); i++)
|
|
{
|
|
mArticulationLinks[i]->getScbBodyFast().wakeUpInternal(scene->getWakeCounterResetValueInteral());
|
|
}
|
|
|
|
getScbArticulation().wakeUp();
|
|
}
|
|
|
|
void PxArticulationImpl::putToSleep()
|
|
{
|
|
NP_WRITE_CHECK(getOwnerScene());
|
|
PX_CHECK_AND_RETURN(getAPIScene(), "Articulation::putToSleep: articulation must be in a scene.");
|
|
|
|
for (PxU32 i = 0; i < mArticulationLinks.size(); i++)
|
|
{
|
|
mArticulationLinks[i]->getScbBodyFast().putToSleepInternal();
|
|
}
|
|
|
|
getScbArticulation().putToSleep();
|
|
}
|
|
|
|
PxU32 PxArticulationImpl::getNbLinks() const
|
|
{
|
|
NP_READ_CHECK(getOwnerScene());
|
|
return mArticulationLinks.size();
|
|
}
|
|
|
|
PxU32 PxArticulationImpl::getLinks(PxArticulationLink** userBuffer, PxU32 bufferSize, PxU32 startIndex) const
|
|
{
|
|
NP_READ_CHECK(getOwnerScene());
|
|
return Cm::getArrayOfPointers(userBuffer, bufferSize, startIndex, mArticulationLinks.begin(), mArticulationLinks.size());
|
|
}
|
|
|
|
PxBounds3 PxArticulationImpl::getWorldBounds(float inflation) const
|
|
{
|
|
NP_READ_CHECK(getOwnerScene());
|
|
PxBounds3 bounds = PxBounds3::empty();
|
|
|
|
for (PxU32 i = 0; i < mArticulationLinks.size(); i++)
|
|
{
|
|
bounds.include(mArticulationLinks[i]->getWorldBounds());
|
|
}
|
|
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);
|
|
}
|
|
|
|
PxAggregate* PxArticulationImpl::getAggregate() const
|
|
{
|
|
NP_READ_CHECK(getOwnerScene());
|
|
return mAggregate;
|
|
}
|
|
|
|
void PxArticulationImpl::setName(const char* debugName)
|
|
{
|
|
NP_WRITE_CHECK(getOwnerScene());
|
|
mName = debugName;
|
|
}
|
|
|
|
const char* PxArticulationImpl::getName() const
|
|
{
|
|
NP_READ_CHECK(getOwnerScene());
|
|
return mName;
|
|
}
|
|
|
|
NpScene* PxArticulationImpl::getAPIScene() const
|
|
{
|
|
return static_cast<NpScene*>(mArticulation.getScbSceneForAPI() ? mArticulation.getScbSceneForAPI()->getPxScene() : NULL);
|
|
}
|
|
|
|
NpScene* PxArticulationImpl::getOwnerScene() const
|
|
{
|
|
return static_cast<NpScene*>(mArticulation.getScbScene() ? mArticulation.getScbScene()->getPxScene() : NULL);
|
|
}
|
|
|
|
#if PX_ENABLE_DEBUG_VISUALIZATION
|
|
|
|
void PxArticulationImpl::visualize(Cm::RenderOutput& out, NpScene* scene)
|
|
{
|
|
for (PxU32 i = 0; i<mArticulationLinks.size(); i++)
|
|
mArticulationLinks[i]->visualize(out, scene);
|
|
}
|
|
#endif // PX_ENABLE_DEBUG_VISUALIZATION
|
|
|
|
NpArticulationLink* PxArticulationImpl::getRoot()
|
|
{
|
|
if (!mArticulationLinks.size())
|
|
return NULL;
|
|
|
|
PX_ASSERT(mArticulationLinks[0]->getInboundJoint() == NULL);
|
|
return mArticulationLinks[0];
|
|
}
|
|
|
|
}
|
|
|
|
#endif //NP_ARTICULATION_TEMPLATE
|
|
|