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

408 lines
13 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 "PxConstraint.h"
#include "NpConstraint.h"
#include "NpPhysics.h"
#include "NpRigidDynamic.h"
#include "NpRigidStatic.h"
#include "NpArticulationLink.h"
#include "ScbConstraint.h"
#include "ScbNpDeps.h"
using namespace physx;
void NpConstraint::setConstraintFunctions(PxConstraintConnector& n, const PxConstraintShaderTable& shaders)
{
mConstraint.getScConstraint().setConstraintFunctions(n, shaders);
//update mConnectorArray, since mActor0 or mActor1 should be in external reference
bool bNeedUpdate = false;
if(mActor0)
{
NpActor& npActor = NpActor::getFromPxActor(*mActor0);
if(npActor.findConnector(NpConnectorType::eConstraint, this) == 0xffffffff)
{
bNeedUpdate = true;
npActor.addConnector(NpConnectorType::eConstraint, this, "PxConstraint: Add to rigid actor 0: Constraint already added");
}
}
if(mActor1)
{
NpActor& npActor = NpActor::getFromPxActor(*mActor1);
if(npActor.findConnector(NpConnectorType::eConstraint, this) == 0xffffffff)
{
bNeedUpdate = true;
npActor.addConnector(NpConnectorType::eConstraint, this, "PxConstraint: Add to rigid actor 1: Constraint already added");
}
}
if(bNeedUpdate)
{
NpScene* newScene = getSceneFromActors(mActor0, mActor1);
NpScene* oldScene = getNpScene();
if (oldScene != newScene)
{
if (oldScene)
{
oldScene->removeFromConstraintList(*this);
oldScene->getScene().removeConstraint(getScbConstraint());
}
if (newScene)
{
newScene->addToConstraintList(*this);
newScene->getScene().addConstraint(getScbConstraint());
}
}
}
}
NpConstraint::NpConstraint(PxRigidActor* actor0, PxRigidActor* actor1, PxConstraintConnector& connector, const PxConstraintShaderTable& shaders, PxU32 dataSize)
: PxConstraint(PxConcreteType::eCONSTRAINT, PxBaseFlag::eOWNS_MEMORY)
, mActor0 (actor0)
, mActor1 (actor1)
, mConstraint (connector, shaders, dataSize)
, mIsDirty (true)
{
mConstraint.setFlags(shaders.flag);
if(actor0)
NpActor::getFromPxActor(*actor0).addConnector(NpConnectorType::eConstraint, this, "PxConstraint: Add to rigid actor 0: Constraint already added");
if(actor1)
NpActor::getFromPxActor(*actor1).addConnector(NpConnectorType::eConstraint, this, "PxConstraint: Add to rigid actor 1: Constraint already added");
NpScene* s = getSceneFromActors(actor0, actor1);
if (s)
{
s->addToConstraintList(*this);
s->getScene().addConstraint(mConstraint);
}
}
NpConstraint::~NpConstraint()
{
if(getBaseFlags()&PxBaseFlag::eOWNS_MEMORY)
mConstraint.getPxConnector()->onConstraintRelease();
NpFactory::getInstance().onConstraintRelease(this);
}
void NpConstraint::release()
{
NpScene* npScene = getNpScene();
NP_WRITE_CHECK(npScene);
NpPhysics::getInstance().notifyDeletionListenersUserRelease(this, NULL);
if(mActor0)
NpActor::getFromPxActor(*mActor0).removeConnector(*mActor0, NpConnectorType::eConstraint, this, "PxConstraint: Add to rigid actor 0: Constraint already added");
if(mActor1)
NpActor::getFromPxActor(*mActor1).removeConnector(*mActor1, NpConnectorType::eConstraint, this, "PxConstraint: Add to rigid actor 1: Constraint already added");
if (npScene)
{
npScene->removeFromConstraintList(*this);
npScene->getScene().removeConstraint(getScbConstraint());
}
mConstraint.destroy();
}
// PX_SERIALIZATION
void NpConstraint::resolveReferences(PxDeserializationContext& context)
{
context.translatePxBase(mActor0);
context.translatePxBase(mActor1);
}
NpConstraint* NpConstraint::createObject(PxU8*& address, PxDeserializationContext& context)
{
NpConstraint* obj = new (address) NpConstraint(PxBaseFlags(0));
address += sizeof(NpConstraint);
obj->importExtraData(context);
obj->resolveReferences(context);
return obj;
}
// ~PX_SERIALIZATION
PxScene* NpConstraint::getScene() const
{
return getNpScene();
}
void NpConstraint::getActors(PxRigidActor*& actor0, PxRigidActor*& actor1) const
{
NP_READ_CHECK(getNpScene());
actor0 = mActor0;
actor1 = mActor1;
}
void NpConstraint::setActors(PxRigidActor* actor0, PxRigidActor* actor1)
{
NP_WRITE_CHECK(getNpScene());
PX_CHECK_AND_RETURN((actor0 && !actor0->is<PxRigidStatic>()) || (actor1 && !actor1->is<PxRigidStatic>()), "PxConstraint: at least one actor must be non-static");
PX_SIMD_GUARD;
if(mActor0)
NpActor::getFromPxActor(*mActor0).removeConnector(*mActor0, NpConnectorType::eConstraint, this, "PxConstraint: Add to rigid actor 0: Constraint already added");
if(mActor1)
NpActor::getFromPxActor(*mActor1).removeConnector(*mActor1, NpConnectorType::eConstraint, this, "PxConstraint: Add to rigid actor 1: Constraint already added");
if(actor0)
NpActor::getFromPxActor(*actor0).addConnector(NpConnectorType::eConstraint, this, "PxConstraint: Add to rigid actor 0: Constraint already added");
if(actor1)
NpActor::getFromPxActor(*actor1).addConnector(NpConnectorType::eConstraint, this, "PxConstraint: Add to rigid actor 1: Constraint already added");
mActor0 = actor0;
mActor1 = actor1;
NpScene* newScene = getSceneFromActors(actor0, actor1);
NpScene* oldScene = getNpScene();
if (oldScene != newScene)
{
if (oldScene)
{
oldScene->removeFromConstraintList(*this);
oldScene->getScene().removeConstraint(getScbConstraint());
}
getScbConstraint().setBodies(getScbRigidObject(actor0), getScbRigidObject(actor1));
if (newScene)
{
newScene->addToConstraintList(*this);
newScene->getScene().addConstraint(getScbConstraint());
}
}
else
getScbConstraint().setBodies(getScbRigidObject(actor0), getScbRigidObject(actor1));
}
void NpConstraint::markDirty()
{
mIsDirty = true;
}
void NpConstraint::setFlags(PxConstraintFlags flags)
{
NP_WRITE_CHECK(getNpScene());
// check for eBROKEN which is a read only flag
PX_CHECK_AND_RETURN(!(flags & PxConstraintFlag::eBROKEN), "PxConstraintFlag::eBROKEN is a read only flag");
PX_CHECK_AND_RETURN(!(flags & PxConstraintFlag::eGPU_COMPATIBLE), "PxConstraintFlag::eGPU_COMPATIBLE is an internal flag and is illegal to set via the API");
PX_SIMD_GUARD;
mConstraint.setFlags(flags);
}
PxConstraintFlags NpConstraint::getFlags() const
{
NP_READ_CHECK(getNpScene());
return mConstraint.getFlags();
}
void NpConstraint::setFlag(PxConstraintFlag::Enum flag, bool value)
{
NP_WRITE_CHECK(getNpScene());
// check for eBROKEN which is a read only flag
PX_CHECK_AND_RETURN(flag != PxConstraintFlag::eBROKEN, "PxConstraintFlag::eBROKEN is a read only flag");
PX_CHECK_AND_RETURN(flag != PxConstraintFlag::eGPU_COMPATIBLE, "PxConstraintFlag::eGPU_COMPATIBLE is an internal flag and is illegal to set via the API");
PX_SIMD_GUARD;
PxConstraintFlags f = mConstraint.getFlags();
mConstraint.setFlags(value ? f|flag : f&~flag);
}
void NpConstraint::getForce(PxVec3& linear, PxVec3& angular) const
{
NP_READ_CHECK(getNpScene());
mConstraint.getForce(linear, angular);
}
void NpConstraint::updateConstants()
{
if(!mIsDirty)
return;
//ML - we can't just set dirty to false because this fails with constraints that were created while the scene was buffering!
if(mConstraint.updateConstants(mConstraint.getPxConnector()->prepareData()))
mIsDirty = false;
#if PX_SUPPORT_PVD
Scb::Scene* scbScene = mConstraint.getScbSceneForAPI();
//Changed to use the visual scenes update system which respects
//the debugger's connection type flag.
if( scbScene && !scbScene->isPhysicsBuffering() )
scbScene->getScenePvdClient().updatePvdProperties( &mConstraint );
#endif
}
void NpConstraint::setBreakForce(PxReal linear, PxReal angular)
{
NP_WRITE_CHECK(getNpScene());
PX_SIMD_GUARD;
mConstraint.setBreakForce(linear, angular);
}
void NpConstraint::getBreakForce(PxReal& linear, PxReal& angular) const
{
NP_READ_CHECK(getNpScene());
PX_SIMD_GUARD;
mConstraint.getBreakForce(linear, angular);
}
void NpConstraint::setMinResponseThreshold(PxReal threshold)
{
PX_CHECK_AND_RETURN(PxIsFinite(threshold) && threshold>=0, "PxConstraint::setMinResponseThreshold: threshold must be non-negative");
NP_WRITE_CHECK(getNpScene());
PX_SIMD_GUARD;
mConstraint.setMinResponseThreshold(threshold);
}
PxReal NpConstraint::getMinResponseThreshold() const
{
NP_READ_CHECK(getNpScene());
PX_SIMD_GUARD;
return mConstraint.getMinResponseThreshold();
}
bool NpConstraint::isValid() const
{
NP_READ_CHECK(getNpScene());
bool isValid0 = mActor0 && !mActor0->is<PxRigidStatic>();
bool isValid1 = mActor1 && !mActor1->is<PxRigidStatic>();
return isValid0 || isValid1;
}
void* NpConstraint::getExternalReference(PxU32& typeID)
{
NP_READ_CHECK(getNpScene());
PxConstraintConnector* connector = mConstraint.getPxConnector();
return connector->getExternalReference(typeID);
}
void NpConstraint::comShift(PxRigidActor* actor)
{
PX_ASSERT(actor == mActor0 || actor == mActor1);
PxConstraintConnector* connector = mConstraint.getPxConnector();
if(actor == mActor0)
connector->onComShift(0);
if(actor == mActor1)
connector->onComShift(1);
}
void NpConstraint::actorDeleted(PxRigidActor* actor)
{
// the actor cannot be deleted without also removing it from the scene,
// which means that the joint will also have been removed from the scene,
// so we can just reset the actor here.
PX_ASSERT(actor == mActor0 || actor == mActor1);
if(actor == mActor0)
mActor0 = 0;
else
mActor1 = 0;
}
NpScene* NpConstraint::getNpScene() const
{
return mConstraint.getScbSceneForAPI() ? static_cast<NpScene*>(mConstraint.getScbSceneForAPI()->getPxScene()) : NULL;
}
Scb::RigidObject* NpConstraint::getScbRigidObject(PxRigidActor* a)
{
if(!a)
return NULL;
PxType type = a->getConcreteType();
if (type == PxConcreteType::eRIGID_DYNAMIC)
return &(static_cast<NpRigidDynamic*>(a)->getScbBodyFast());
else if (type == PxConcreteType::eARTICULATION_LINK)
return &(static_cast<NpArticulationLink*>(a)->getScbBodyFast());
else
{
PX_ASSERT(type == PxConcreteType::eRIGID_STATIC);
return &(static_cast<NpRigidStatic*>(a)->getScbRigidStaticFast());
}
}
void physx::NpConstraintGetRigidObjectsFromScb(const Scb::Constraint&c, Scb::RigidObject*&b0, Scb::RigidObject*&b1)
{
const size_t offset = size_t(&(reinterpret_cast<NpConstraint*>(0)->getScbConstraint()));
const NpConstraint* np = reinterpret_cast<const NpConstraint*>(reinterpret_cast<const char*>(&c)-offset);
PxRigidActor* a0, * a1;
np->getActors(a0, a1);
b0 = NpConstraint::getScbRigidObject(a0);
b1 = NpConstraint::getScbRigidObject(a1);
}
NpScene* NpConstraint::getSceneFromActors() const
{
return getSceneFromActors(mActor0, mActor1);
}
PX_FORCE_INLINE NpScene* NpConstraint::getSceneFromActors(const PxRigidActor* actor0, const PxRigidActor* actor1)
{
NpScene* s0 = NULL;
NpScene* s1 = NULL;
if (actor0 && (!(actor0->getActorFlags() & PxActorFlag::eDISABLE_SIMULATION)))
s0 = static_cast<NpScene*>(actor0->getScene());
if (actor1 && (!(actor1->getActorFlags() & PxActorFlag::eDISABLE_SIMULATION)))
s1 = static_cast<NpScene*>(actor1->getScene());
#if PX_CHECKED
if ((s0 && s1) && (s0 != s1))
Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "Adding constraint to scene: Actors belong to different scenes, undefined behavior expected!");
#endif
if ((!actor0 || s0) && (!actor1 || s1))
return s0 ? s0 : s1;
else
return NULL;
}