Projekt_Grafika/dependencies/physx-4.1/source/physx/src/NpActor.cpp

487 lines
14 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.
#include "NpActor.h"
#include "PxRigidActor.h"
#include "NpConstraint.h"
#include "NpFactory.h"
#include "NpShape.h"
#include "NpPhysics.h"
#include "NpAggregate.h"
#include "NpScene.h"
#include "NpRigidStatic.h"
#include "NpRigidDynamic.h"
#include "NpArticulationLink.h"
#include "CmTransformUtils.h"
using namespace physx;
///////////////////////////////////////////////////////////////////////////////
NpActor::NpActor(const char* name) :
mName(name),
mConnectorArray(NULL)
{
}
NpActor::~NpActor()
{
}
typedef Ps::HashMap<NpActor*, NpConnectorArray*> ConnectorMap;
struct NpActorUserData
{
PxU32 referenceCount;
ConnectorMap* tmpOriginalConnectors;
};
void NpActor::exportExtraData(PxSerializationContext& stream)
{
const PxCollection& collection = stream.getCollection();
if(mConnectorArray)
{
PxU32 connectorSize = mConnectorArray->size();
PxU32 missedCount = 0;
for(PxU32 i = 0; i < connectorSize; ++i)
{
NpConnector& c = (*mConnectorArray)[i];
PxBase* object = c.mObject;
if(!collection.contains(*object))
{
++missedCount;
}
}
NpConnectorArray* exportConnectorArray = mConnectorArray;
if(missedCount > 0)
{
exportConnectorArray = NpFactory::getInstance().acquireConnectorArray();
if(missedCount < connectorSize)
{
exportConnectorArray->reserve(connectorSize - missedCount);
for(PxU32 i = 0; i < connectorSize; ++i)
{
NpConnector& c = (*mConnectorArray)[i];
PxBase* object = c.mObject;
if(collection.contains(*object))
{
exportConnectorArray->pushBack(c);
}
}
}
}
stream.alignData(PX_SERIAL_ALIGN);
stream.writeData(exportConnectorArray, sizeof(NpConnectorArray));
Cm::exportInlineArray(*exportConnectorArray, stream);
if(missedCount > 0)
NpFactory::getInstance().releaseConnectorArray(exportConnectorArray);
}
stream.writeName(mName);
}
void NpActor::importExtraData(PxDeserializationContext& context)
{
if(mConnectorArray)
{
mConnectorArray = context.readExtraData<NpConnectorArray, PX_SERIAL_ALIGN>();
new (mConnectorArray) NpConnectorArray(PxEmpty);
if(mConnectorArray->size() == 0)
mConnectorArray = NULL;
else
Cm::importInlineArray(*mConnectorArray, context);
}
context.readName(mName);
}
void NpActor::resolveReferences(PxDeserializationContext& context)
{
// Resolve connector pointers if needed
if(mConnectorArray)
{
const PxU32 nbConnectors = mConnectorArray->size();
for(PxU32 i=0; i<nbConnectors; i++)
{
NpConnector& c = (*mConnectorArray)[i];
context.translatePxBase(c.mObject);
}
}
}
///////////////////////////////////////////////////////////////////////////////
void NpActor::releaseConstraints(PxRigidActor& owner)
{
if(mConnectorArray)
{
PxU32 nbConnectors = mConnectorArray->size();
PxU32 currentIndex = 0;
while(nbConnectors--)
{
NpConnector& connector = (*mConnectorArray)[currentIndex];
if (connector.mType == NpConnectorType::eConstraint)
{
NpConstraint* c = static_cast<NpConstraint*>(connector.mObject);
c->actorDeleted(&owner);
NpScene* s = c->getNpScene();
if (s)
{
s->getScene().removeConstraint(c->getScbConstraint());
s->removeFromConstraintList(*c);
}
removeConnector(owner, currentIndex);
}
else
currentIndex++;
}
}
}
void NpActor::release(PxActor& owner)
{
if(mConnectorArray) // Need to test again because the code above might purge the connector array if no element remains
{
PX_ASSERT(mConnectorArray->size() == 1); // At this point only the aggregate should remain
PX_ASSERT((*mConnectorArray)[0].mType == NpConnectorType::eAggregate);
NpAggregate* a = static_cast<NpAggregate*>((*mConnectorArray)[0].mObject);
bool status = a->removeActorAndReinsert(owner, false);
PX_ASSERT(status);
PX_UNUSED(status);
PX_ASSERT(!mConnectorArray); // Remove should happen in aggregate code
}
PX_ASSERT(!mConnectorArray); // All the connector objects should have been removed at this point
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
PxU32 NpActor::findConnector(NpConnectorType::Enum type, PxBase* object) const
{
if(!mConnectorArray)
return 0xffffffff;
for(PxU32 i=0; i < mConnectorArray->size(); i++)
{
NpConnector& c = (*mConnectorArray)[i];
if (c.mType == type && c.mObject == object)
return i;
}
return 0xffffffff;
}
void NpActor::addConnector(NpConnectorType::Enum type, PxBase* object, const char* errMsg)
{
if(!mConnectorArray)
mConnectorArray = NpFactory::getInstance().acquireConnectorArray();
PX_CHECK_MSG(findConnector(type, object) == 0xffffffff, errMsg);
PX_UNUSED(errMsg);
if(mConnectorArray->isInUserMemory() && mConnectorArray->size() == mConnectorArray->capacity())
{
NpConnectorArray* newConnectorArray = NpFactory::getInstance().acquireConnectorArray();
newConnectorArray->assign(mConnectorArray->begin(), mConnectorArray->end());
mConnectorArray->~NpConnectorArray();
mConnectorArray = newConnectorArray;
}
NpConnector c(type, object);
mConnectorArray->pushBack(c);
}
void NpActor::removeConnector(PxActor& /*owner*/, PxU32 index)
{
PX_ASSERT(mConnectorArray);
PX_ASSERT(index < mConnectorArray->size());
mConnectorArray->replaceWithLast(index);
if(mConnectorArray->size() == 0)
{
if(!mConnectorArray->isInUserMemory())
NpFactory::getInstance().releaseConnectorArray(mConnectorArray);
else
mConnectorArray->~NpConnectorArray();
mConnectorArray = NULL;
}
}
void NpActor::removeConnector(PxActor& owner, NpConnectorType::Enum type, PxBase* object, const char* errorMsg)
{
PX_CHECK_MSG(mConnectorArray, errorMsg);
PX_UNUSED(errorMsg);
if(mConnectorArray)
{
PxU32 index = findConnector(type, object);
PX_CHECK_MSG(index != 0xffffffff, errorMsg);
removeConnector(owner, index);
}
}
PxU32 NpActor::getNbConnectors(NpConnectorType::Enum type) const
{
PxU32 nbConnectors = 0;
if(mConnectorArray)
{
for(PxU32 i=0; i < mConnectorArray->size(); i++)
{
if ((*mConnectorArray)[i].mType == type)
nbConnectors++;
}
}
return nbConnectors;
}
///////////////////////////////////////////////////////////////////////////////
NpAggregate* NpActor::getNpAggregate(PxU32& index) const
{
PX_ASSERT(getNbConnectors(NpConnectorType::eAggregate) <= 1);
if(mConnectorArray)
{
// PT: TODO: sort by type to optimize this...
for(PxU32 i=0; i < mConnectorArray->size(); i++)
{
NpConnector& c = (*mConnectorArray)[i];
if (c.mType == NpConnectorType::eAggregate)
{
index = i;
return static_cast<NpAggregate*>(c.mObject);
}
}
}
return NULL;
}
void NpActor::setAggregate(NpAggregate* np, PxActor& owner)
{
PxU32 index = 0xffffffff;
NpAggregate* a = getNpAggregate(index);
if (!a)
{
PX_ASSERT(np);
addConnector(NpConnectorType::eAggregate, np, "NpActor::setAggregate() failed");
}
else
{
PX_ASSERT(mConnectorArray);
PX_ASSERT(index != 0xffffffff);
if (!np)
removeConnector(owner, index);
else
(*mConnectorArray)[index].mObject = np;
}
}
PxAggregate* NpActor::getAggregate() const
{
PxU32 index = 0xffffffff;
NpAggregate* a = getNpAggregate(index);
return static_cast<PxAggregate*>(a);
}
///////////////////////////////////////////////////////////////////////////////
void NpActor::removeConstraintsFromScene()
{
NpConnectorIterator iter = getConnectorIterator(NpConnectorType::eConstraint);
while (PxBase* ser = iter.getNext())
{
NpConstraint* c = static_cast<NpConstraint*>(ser);
NpScene* s = c->getNpScene();
if (s)
{
s->removeFromConstraintList(*c);
s->getScene().removeConstraint(c->getScbConstraint());
}
}
}
void NpActor::addConstraintsToSceneInternal()
{
if(!mConnectorArray)
return;
NpConnectorIterator iter = getConnectorIterator(NpConnectorType::eConstraint);
while (PxBase* ser = iter.getNext())
{
NpConstraint* c = static_cast<NpConstraint*>(ser);
PX_ASSERT(c->getNpScene() == NULL);
c->markDirty(); // PT: "temp" fix for crash when removing/re-adding jointed actor from/to a scene
NpScene* s = c->getSceneFromActors();
if (s)
{
s->addToConstraintList(*c);
s->getScene().addConstraint(c->getScbConstraint());
}
}
}
///////////////////////////////////////////////////////////////////////////////
NpShapeManager* NpActor::getShapeManager(PxRigidActor& actor)
{
// DS: if the performance here becomes an issue we can use the same kind of offset hack as below
const PxType actorType = actor.getConcreteType();
if (actorType == PxConcreteType::eRIGID_DYNAMIC)
return &static_cast<NpRigidDynamic&>(actor).getShapeManager();
else if(actorType == PxConcreteType::eRIGID_STATIC)
return &static_cast<NpRigidStatic&>(actor).getShapeManager();
else if (actorType == PxConcreteType::eARTICULATION_LINK)
return &static_cast<NpArticulationLink&>(actor).getShapeManager();
else
{
PX_ASSERT(0);
return NULL;
}
}
const NpShapeManager* NpActor::getShapeManager(const PxRigidActor& actor)
{
// DS: if the performance here becomes an issue we can use the same kind of offset hack as below
const PxType actorType = actor.getConcreteType();
if (actorType == PxConcreteType::eRIGID_DYNAMIC)
return &static_cast<const NpRigidDynamic&>(actor).getShapeManager();
else if(actorType == PxConcreteType::eRIGID_STATIC)
return &static_cast<const NpRigidStatic&>(actor).getShapeManager();
else if (actorType == PxConcreteType::eARTICULATION_LINK)
return &static_cast<const NpArticulationLink&>(actor).getShapeManager();
else
{
PX_ASSERT(0);
return NULL;
}
}
void NpActor::getGlobalPose(PxTransform& globalPose, const NpShape& shape, const PxRigidActor& actor)
{
const Scb::Actor& scbActor = NpActor::getScbFromPxActor(actor);
const Scb::Shape& scbShape = shape.getScbShape();
NpActor::getGlobalPose(globalPose, scbShape, scbActor);
}
void NpActor::getGlobalPose(PxTransform& globalPose, const Scb::Shape& scbShape, const Scb::Actor& scbActor)
{
const PxTransform& shape2Actor = scbShape.getShape2Actor();
// PT: TODO: duplicated from SqBounds.cpp. Refactor.
const ScbType::Enum actorType = scbActor.getScbType();
if(actorType==ScbType::eRIGID_STATIC)
{
Cm::getStaticGlobalPoseAligned(static_cast<const Scb::RigidStatic&>(scbActor).getActor2World(), shape2Actor, globalPose);
}
else
{
PX_ASSERT(actorType==ScbType::eBODY || actorType == ScbType::eBODY_FROM_ARTICULATION_LINK);
const Scb::Body& body = static_cast<const Scb::Body&>(scbActor);
PX_ALIGN(16, PxTransform) kinematicTarget;
const PxU16 sqktFlags = PxRigidBodyFlag::eKINEMATIC | PxRigidBodyFlag::eUSE_KINEMATIC_TARGET_FOR_SCENE_QUERIES;
const bool useTarget = (PxU16(body.getFlags()) & sqktFlags) == sqktFlags;
const PxTransform& body2World = (useTarget && body.getKinematicTarget(kinematicTarget)) ? kinematicTarget : body.getBody2World();
Cm::getDynamicGlobalPoseAligned(body2World, shape2Actor, body.getBody2Actor(), globalPose);
}
}
namespace
{
template <typename N> NpActor* pxToNpActor(PxActor *p)
{
return static_cast<NpActor*>(static_cast<N*>(p));
}
}
NpActor::Offsets::Offsets()
{
for(PxU32 i=0;i<PxConcreteType::ePHYSX_CORE_COUNT;i++)
pxActorToScbActor[i] = pxActorToNpActor[i] = 0;
size_t addr = 0x100; // casting the null ptr takes a special-case code path, which we don't want
PxActor* n = reinterpret_cast<PxActor*>(addr);
pxActorToNpActor[PxConcreteType::eRIGID_STATIC] = reinterpret_cast<size_t>(pxToNpActor<NpRigidStatic>(n)) - addr;
pxActorToNpActor[PxConcreteType::eRIGID_DYNAMIC] = reinterpret_cast<size_t>(pxToNpActor<NpRigidDynamic>(n)) - addr;
pxActorToNpActor[PxConcreteType::eARTICULATION_LINK] = reinterpret_cast<size_t>(pxToNpActor<NpArticulationLink>(n)) - addr;
pxActorToScbActor[PxConcreteType::eRIGID_STATIC] = PX_OFFSET_OF_RT(NpRigidStatic, getScbActorFast());
pxActorToScbActor[PxConcreteType::eRIGID_DYNAMIC] = PX_OFFSET_OF_RT(NpRigidDynamic, getScbActorFast());
pxActorToScbActor[PxConcreteType::eARTICULATION_LINK] = PX_OFFSET_OF_RT(NpArticulationLink, getScbActorFast());
}
const NpActor::Offsets NpActor::sOffsets;
NpScene* NpActor::getOwnerScene(const PxActor& actor)
{
const Scb::Actor& scbActor = getScbFromPxActor(actor);
Scb::Scene* scbScene = scbActor.getScbScene();
return scbScene? static_cast<NpScene*>(scbScene->getPxScene()) : NULL;
}
NpScene* NpActor::getAPIScene(const PxActor& actor)
{
const Scb::Actor& scbActor = getScbFromPxActor(actor);
Scb::Scene* scbScene = scbActor.getScbSceneForAPI();
return scbScene? static_cast<NpScene*>(scbScene->getPxScene()) : NULL;
}
void NpActor::onActorRelease(PxActor* actor)
{
NpFactory::getInstance().onActorRelease(actor);
}