827 lines
25 KiB
C++
827 lines
25 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 "NpCast.h"
|
||
|
#include "GuConvexMesh.h"
|
||
|
#include "GuTriangleMesh.h"
|
||
|
#include "ScbNpDeps.h"
|
||
|
#include "GuBounds.h"
|
||
|
|
||
|
using namespace physx;
|
||
|
using namespace Sq;
|
||
|
|
||
|
static PX_FORCE_INLINE void updatePvdProperties(const Scb::Shape& shape)
|
||
|
{
|
||
|
#if PX_SUPPORT_PVD
|
||
|
Scb::Scene* scbScene = shape.getScbSceneForAPI();
|
||
|
if(scbScene)
|
||
|
scbScene->getScenePvdClient().updatePvdProperties(&shape);
|
||
|
#else
|
||
|
PX_UNUSED(shape);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
NpShape::NpShape(const PxGeometry& geometry, PxShapeFlags shapeFlags, const PxU16* materialIndices, PxU16 materialCount, bool isExclusive)
|
||
|
: PxShape (PxConcreteType::eSHAPE, PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE)
|
||
|
, mActor (NULL)
|
||
|
, mShape (geometry, shapeFlags, materialIndices, materialCount, isExclusive)
|
||
|
, mName (NULL)
|
||
|
, mExclusiveAndActorCount (isExclusive ? EXCLUSIVE_MASK : 0)
|
||
|
{
|
||
|
PX_ASSERT(mShape.getScShape().getPxShape() == static_cast<PxShape*>(this));
|
||
|
|
||
|
PxShape::userData = NULL;
|
||
|
|
||
|
incMeshRefCount();
|
||
|
}
|
||
|
|
||
|
NpShape::~NpShape()
|
||
|
{
|
||
|
decMeshRefCount();
|
||
|
|
||
|
PxU32 nbMaterials = mShape.getNbMaterials();
|
||
|
for (PxU32 i=0; i < nbMaterials; i++)
|
||
|
{
|
||
|
NpMaterial* mat = static_cast<NpMaterial*>(mShape.getMaterial(i));
|
||
|
mat->decRefCount();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void NpShape::onRefCountZero()
|
||
|
{
|
||
|
NpFactory::getInstance().onShapeRelease(this);
|
||
|
// see NpShape.h for ref counting semantics for shapes
|
||
|
NpDestroy(getScbShape());
|
||
|
}
|
||
|
|
||
|
// PX_SERIALIZATION
|
||
|
|
||
|
NpShape::NpShape(PxBaseFlags baseFlags) : PxShape(baseFlags), mShape(PxEmpty) {}
|
||
|
|
||
|
void NpShape::preExportDataReset()
|
||
|
{
|
||
|
Cm::RefCountable::preExportDataReset();
|
||
|
mExclusiveAndActorCount &= EXCLUSIVE_MASK;
|
||
|
}
|
||
|
|
||
|
void NpShape::exportExtraData(PxSerializationContext& context)
|
||
|
{
|
||
|
getScbShape().getScShape().exportExtraData(context);
|
||
|
context.writeName(mName);
|
||
|
}
|
||
|
|
||
|
void NpShape::importExtraData(PxDeserializationContext& context)
|
||
|
{
|
||
|
getScbShape().getScShape().importExtraData(context);
|
||
|
context.readName(mName);
|
||
|
}
|
||
|
|
||
|
void NpShape::requiresObjects(PxProcessPxBaseCallback& c)
|
||
|
{
|
||
|
//meshes
|
||
|
PxBase* mesh = NULL;
|
||
|
switch(mShape.getGeometryType())
|
||
|
{
|
||
|
case PxGeometryType::eCONVEXMESH:
|
||
|
mesh = static_cast<const PxConvexMeshGeometry&>(mShape.getGeometry()).convexMesh;
|
||
|
break;
|
||
|
case PxGeometryType::eHEIGHTFIELD:
|
||
|
mesh = static_cast<const PxHeightFieldGeometry&>(mShape.getGeometry()).heightField;
|
||
|
break;
|
||
|
case PxGeometryType::eTRIANGLEMESH:
|
||
|
mesh = static_cast<const PxTriangleMeshGeometry&>(mShape.getGeometry()).triangleMesh;
|
||
|
break;
|
||
|
case PxGeometryType::eSPHERE:
|
||
|
case PxGeometryType::ePLANE:
|
||
|
case PxGeometryType::eCAPSULE:
|
||
|
case PxGeometryType::eBOX:
|
||
|
case PxGeometryType::eGEOMETRY_COUNT:
|
||
|
case PxGeometryType::eINVALID:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(mesh)
|
||
|
c.process(*mesh);
|
||
|
|
||
|
//material
|
||
|
PxU32 nbMaterials = mShape.getNbMaterials();
|
||
|
for (PxU32 i=0; i < nbMaterials; i++)
|
||
|
{
|
||
|
NpMaterial* mat = static_cast<NpMaterial*>(mShape.getMaterial(i));
|
||
|
c.process(*mat);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void NpShape::resolveReferences(PxDeserializationContext& context)
|
||
|
{
|
||
|
// getMaterials() only works after material indices have been patched.
|
||
|
// in order to get to the new material indices, we need access to the new materials.
|
||
|
// this only leaves us with the option of acquiring the material through the context given an old material index (we do have the mapping)
|
||
|
{
|
||
|
PxU32 nbIndices = mShape.getScShape().getNbMaterialIndices();
|
||
|
const PxU16* indices = mShape.getScShape().getMaterialIndices();
|
||
|
|
||
|
for (PxU32 i=0; i < nbIndices; i++)
|
||
|
{
|
||
|
PxBase* base = context.resolveReference(PX_SERIAL_REF_KIND_MATERIAL_IDX, size_t(indices[i]));
|
||
|
PX_ASSERT(base && base->is<PxMaterial>());
|
||
|
|
||
|
NpMaterial& material = *static_cast<NpMaterial*>(base);
|
||
|
getScbShape().getScShape().resolveMaterialReference(i, material.getHandle());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
context.translatePxBase(mActor);
|
||
|
|
||
|
getScbShape().getScShape().resolveReferences(context);
|
||
|
|
||
|
|
||
|
incMeshRefCount();
|
||
|
|
||
|
// Increment materials' refcounts in a second pass. Works better in case of failure above.
|
||
|
PxU32 nbMaterials = mShape.getNbMaterials();
|
||
|
for (PxU32 i=0; i < nbMaterials; i++)
|
||
|
{
|
||
|
NpMaterial* mat = static_cast<NpMaterial*>(mShape.getMaterial(i));
|
||
|
mat->incRefCount();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
NpShape* NpShape::createObject(PxU8*& address, PxDeserializationContext& context)
|
||
|
{
|
||
|
NpShape* obj = new (address) NpShape(PxBaseFlag::eIS_RELEASABLE);
|
||
|
address += sizeof(NpShape);
|
||
|
obj->importExtraData(context);
|
||
|
obj->resolveReferences(context);
|
||
|
return obj;
|
||
|
}
|
||
|
//~PX_SERIALIZATION
|
||
|
|
||
|
PxU32 NpShape::getReferenceCount() const
|
||
|
{
|
||
|
return getRefCount();
|
||
|
}
|
||
|
|
||
|
void NpShape::acquireReference()
|
||
|
{
|
||
|
incRefCount();
|
||
|
}
|
||
|
|
||
|
void NpShape::release()
|
||
|
{
|
||
|
PX_CHECK_AND_RETURN(getRefCount() > 1 || getActorCount() == 0, "PxShape::release: last reference to a shape released while still attached to an actor!");
|
||
|
NP_WRITE_CHECK(getOwnerScene());
|
||
|
releaseInternal();
|
||
|
}
|
||
|
|
||
|
void NpShape::releaseInternal()
|
||
|
{
|
||
|
decRefCount();
|
||
|
}
|
||
|
|
||
|
Sc::RigidCore& NpShape::getScRigidObjectExclusive() const
|
||
|
{
|
||
|
const PxType actorType = mActor->getConcreteType();
|
||
|
|
||
|
if (actorType == PxConcreteType::eRIGID_DYNAMIC)
|
||
|
return static_cast<NpRigidDynamic&>(*mActor).getScbBodyFast().getScBody();
|
||
|
else if (actorType == PxConcreteType::eARTICULATION_LINK)
|
||
|
return static_cast<NpArticulationLink&>(*mActor).getScbBodyFast().getScBody();
|
||
|
else
|
||
|
return static_cast<NpRigidStatic&>(*mActor).getScbRigidStaticFast().getScStatic();
|
||
|
}
|
||
|
|
||
|
void NpShape::updateSQ(const char* errorMessage)
|
||
|
{
|
||
|
if(mActor && (mShape.getFlags() & PxShapeFlag::eSCENE_QUERY_SHAPE))
|
||
|
{
|
||
|
NpScene* scene = NpActor::getAPIScene(*mActor);
|
||
|
NpShapeManager* shapeManager = NpActor::getShapeManager(*mActor);
|
||
|
if(scene)
|
||
|
{
|
||
|
PxU32 compoundId;
|
||
|
const PrunerData sqData = shapeManager->findSceneQueryData(*this, compoundId);
|
||
|
scene->getSceneQueryManagerFast().markForUpdate(compoundId, sqData);
|
||
|
}
|
||
|
|
||
|
// invalidate the pruning structure if the actor bounds changed
|
||
|
if(shapeManager->getPruningStructure())
|
||
|
{
|
||
|
Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, errorMessage);
|
||
|
shapeManager->getPruningStructure()->invalidate(mActor);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PxGeometryType::Enum NpShape::getGeometryType() const
|
||
|
{
|
||
|
NP_READ_CHECK(getOwnerScene());
|
||
|
|
||
|
return mShape.getGeometryType();
|
||
|
}
|
||
|
|
||
|
void NpShape::setGeometry(const PxGeometry& g)
|
||
|
{
|
||
|
NP_WRITE_CHECK(getOwnerScene());
|
||
|
PX_CHECK_AND_RETURN(isWritable(), "PxShape::setGeometry: shared shapes attached to actors are not writable.");
|
||
|
PX_SIMD_GUARD;
|
||
|
|
||
|
// PT: fixes US2117
|
||
|
if(g.getType() != getGeometryTypeFast())
|
||
|
{
|
||
|
Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "PxShape::setGeometry(): Invalid geometry type. Changing the type of the shape is not supported.");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
#if PX_CHECKED
|
||
|
bool isValid = false;
|
||
|
switch(g.getType())
|
||
|
{
|
||
|
case PxGeometryType::eSPHERE:
|
||
|
isValid = static_cast<const PxSphereGeometry&>(g).isValid();
|
||
|
break;
|
||
|
|
||
|
case PxGeometryType::ePLANE:
|
||
|
isValid = static_cast<const PxPlaneGeometry&>(g).isValid();
|
||
|
break;
|
||
|
|
||
|
case PxGeometryType::eCAPSULE:
|
||
|
isValid = static_cast<const PxCapsuleGeometry&>(g).isValid();
|
||
|
break;
|
||
|
|
||
|
case PxGeometryType::eBOX:
|
||
|
isValid = static_cast<const PxBoxGeometry&>(g).isValid();
|
||
|
break;
|
||
|
|
||
|
case PxGeometryType::eCONVEXMESH:
|
||
|
isValid = static_cast<const PxConvexMeshGeometry&>(g).isValid();
|
||
|
break;
|
||
|
|
||
|
case PxGeometryType::eTRIANGLEMESH:
|
||
|
isValid = static_cast<const PxTriangleMeshGeometry&>(g).isValid();
|
||
|
break;
|
||
|
|
||
|
case PxGeometryType::eHEIGHTFIELD:
|
||
|
isValid = static_cast<const PxHeightFieldGeometry&>(g).isValid();
|
||
|
break;
|
||
|
|
||
|
case PxGeometryType::eGEOMETRY_COUNT:
|
||
|
case PxGeometryType::eINVALID:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(!isValid)
|
||
|
{
|
||
|
Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "PxShape::setGeometry(): Invalid geometry!");
|
||
|
return;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
decMeshRefCount();
|
||
|
|
||
|
mShape.setGeometry(g);
|
||
|
|
||
|
incMeshRefCount();
|
||
|
|
||
|
updateSQ("PxShape::setGeometry: Shape is a part of pruning structure, pruning structure is now invalid!");
|
||
|
}
|
||
|
|
||
|
PxGeometryHolder NpShape::getGeometry() const
|
||
|
{
|
||
|
PX_COMPILE_TIME_ASSERT(sizeof(Gu::GeometryUnion)>=sizeof(PxGeometryHolder));
|
||
|
return reinterpret_cast<const PxGeometryHolder&>(mShape.getGeometry());
|
||
|
}
|
||
|
|
||
|
template<class T>
|
||
|
static PX_FORCE_INLINE bool getGeometryT(const NpShape* npShape, PxGeometryType::Enum type, T& geom)
|
||
|
{
|
||
|
NP_READ_CHECK(npShape->getOwnerScene());
|
||
|
|
||
|
if(npShape->getGeometryTypeFast() != type)
|
||
|
return false;
|
||
|
|
||
|
geom = static_cast<const T&>(npShape->getScbShape().getGeometry());
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool NpShape::getBoxGeometry(PxBoxGeometry& g) const { return getGeometryT(this, PxGeometryType::eBOX, g); }
|
||
|
bool NpShape::getSphereGeometry(PxSphereGeometry& g) const { return getGeometryT(this, PxGeometryType::eSPHERE, g); }
|
||
|
bool NpShape::getCapsuleGeometry(PxCapsuleGeometry& g) const { return getGeometryT(this, PxGeometryType::eCAPSULE, g); }
|
||
|
bool NpShape::getPlaneGeometry(PxPlaneGeometry& g) const { return getGeometryT(this, PxGeometryType::ePLANE, g); }
|
||
|
bool NpShape::getConvexMeshGeometry(PxConvexMeshGeometry& g) const { return getGeometryT(this, PxGeometryType::eCONVEXMESH, g); }
|
||
|
bool NpShape::getTriangleMeshGeometry(PxTriangleMeshGeometry& g) const { return getGeometryT(this, PxGeometryType::eTRIANGLEMESH, g); }
|
||
|
bool NpShape::getHeightFieldGeometry(PxHeightFieldGeometry& g) const { return getGeometryT(this, PxGeometryType::eHEIGHTFIELD, g); }
|
||
|
|
||
|
PxRigidActor* NpShape::getActor() const
|
||
|
{
|
||
|
NP_READ_CHECK(getOwnerScene());
|
||
|
return mActor;
|
||
|
}
|
||
|
|
||
|
void NpShape::setLocalPose(const PxTransform& newShape2Actor)
|
||
|
{
|
||
|
PX_CHECK_AND_RETURN(newShape2Actor.isSane(), "PxShape::setLocalPose: pose is not valid.");
|
||
|
PX_CHECK_AND_RETURN(isWritable(), "PxShape::setLocalPose: shared shapes attached to actors are not writable.");
|
||
|
NP_WRITE_CHECK(getOwnerScene());
|
||
|
|
||
|
mShape.setShape2Actor(newShape2Actor.getNormalized());
|
||
|
|
||
|
updateSQ("PxShape::setLocalPose: Shape is a part of pruning structure, pruning structure is now invalid!");
|
||
|
}
|
||
|
|
||
|
PxTransform NpShape::getLocalPose() const
|
||
|
{
|
||
|
NP_READ_CHECK(getOwnerScene());
|
||
|
|
||
|
return mShape.getShape2Actor();
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
void NpShape::setSimulationFilterData(const PxFilterData& data)
|
||
|
{
|
||
|
NP_WRITE_CHECK(getOwnerScene());
|
||
|
PX_CHECK_AND_RETURN(isWritable(), "PxShape::setSimulationFilterData: shared shapes attached to actors are not writable.");
|
||
|
mShape.setSimulationFilterData(data);
|
||
|
}
|
||
|
|
||
|
PxFilterData NpShape::getSimulationFilterData() const
|
||
|
{
|
||
|
NP_READ_CHECK(getOwnerScene());
|
||
|
return mShape.getSimulationFilterData();
|
||
|
}
|
||
|
|
||
|
void NpShape::setQueryFilterData(const PxFilterData& data)
|
||
|
{
|
||
|
NP_WRITE_CHECK(getOwnerScene());
|
||
|
PX_CHECK_AND_RETURN(isWritable(), "PxShape::setQueryFilterData: shared shapes attached to actors are not writable.");
|
||
|
|
||
|
mShape.getScShape().setQueryFilterData(data); // PT: this one doesn't need double-buffering
|
||
|
|
||
|
updatePvdProperties(mShape);
|
||
|
}
|
||
|
|
||
|
PxFilterData NpShape::getQueryFilterData() const
|
||
|
{
|
||
|
NP_READ_CHECK(getOwnerScene());
|
||
|
|
||
|
return getQueryFilterDataFast();
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
void NpShape::setMaterials(PxMaterial*const* materials, PxU16 materialCount)
|
||
|
{
|
||
|
NP_WRITE_CHECK(getOwnerScene());
|
||
|
PX_CHECK_AND_RETURN(isWritable(), "PxShape::setMaterials: shared shapes attached to actors are not writable.");
|
||
|
|
||
|
#if PX_CHECKED
|
||
|
if (!NpShape::checkMaterialSetup(mShape.getGeometry(), "PxShape::setMaterials()", materials, materialCount))
|
||
|
return;
|
||
|
#endif
|
||
|
|
||
|
PxU32 oldMaterialCount = mShape.getNbMaterials();
|
||
|
PX_ALLOCA(oldMaterials, PxMaterial*, oldMaterialCount);
|
||
|
PxU32 tmp = mShape.getMaterials(oldMaterials, oldMaterialCount);
|
||
|
PX_ASSERT(tmp == oldMaterialCount);
|
||
|
PX_UNUSED(tmp);
|
||
|
|
||
|
if (mShape.setMaterials(materials, materialCount))
|
||
|
{
|
||
|
for(PxU32 i=0; i < materialCount; i++)
|
||
|
static_cast<NpMaterial*>(materials[i])->incRefCount();
|
||
|
|
||
|
for(PxU32 i=0; i < oldMaterialCount; i++)
|
||
|
static_cast<NpMaterial*>(oldMaterials[i])->decRefCount();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PxU16 NpShape::getNbMaterials() const
|
||
|
{
|
||
|
NP_READ_CHECK(getOwnerScene());
|
||
|
|
||
|
return mShape.getNbMaterials();
|
||
|
}
|
||
|
|
||
|
PxU32 NpShape::getMaterials(PxMaterial** userBuffer, PxU32 bufferSize, PxU32 startIndex) const
|
||
|
{
|
||
|
NP_READ_CHECK(getOwnerScene());
|
||
|
|
||
|
return mShape.getMaterials(userBuffer, bufferSize, startIndex);
|
||
|
}
|
||
|
|
||
|
PxMaterial* NpShape::getMaterialFromInternalFaceIndex(PxU32 faceIndex) const
|
||
|
{
|
||
|
NP_READ_CHECK(getOwnerScene());
|
||
|
|
||
|
bool isHf = (getGeometryType() == PxGeometryType::eHEIGHTFIELD);
|
||
|
bool isMesh = (getGeometryType() == PxGeometryType::eTRIANGLEMESH);
|
||
|
if( faceIndex == 0xFFFFffff && (isHf || isMesh) )
|
||
|
{
|
||
|
Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__,
|
||
|
"PxShape::getMaterialFromInternalFaceIndex received 0xFFFFffff as input - returning NULL.");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
PxMaterialTableIndex hitMatTableId = 0;
|
||
|
|
||
|
if(isHf)
|
||
|
{
|
||
|
PxHeightFieldGeometry hfGeom;
|
||
|
getHeightFieldGeometry(hfGeom);
|
||
|
|
||
|
hitMatTableId = hfGeom.heightField->getTriangleMaterialIndex(faceIndex);
|
||
|
}
|
||
|
else if(isMesh)
|
||
|
{
|
||
|
PxTriangleMeshGeometry triGeo;
|
||
|
getTriangleMeshGeometry(triGeo);
|
||
|
|
||
|
Gu::TriangleMesh* tm = static_cast<Gu::TriangleMesh*>(triGeo.triangleMesh);
|
||
|
if(tm->hasPerTriangleMaterials())
|
||
|
hitMatTableId = triGeo.triangleMesh->getTriangleMaterialIndex(faceIndex);
|
||
|
}
|
||
|
|
||
|
return getMaterial(hitMatTableId);
|
||
|
}
|
||
|
|
||
|
void NpShape::setContactOffset(PxReal contactOffset)
|
||
|
{
|
||
|
NP_WRITE_CHECK(getOwnerScene());
|
||
|
|
||
|
PX_CHECK_AND_RETURN(PxIsFinite(contactOffset), "PxShape::setContactOffset: invalid float");
|
||
|
PX_CHECK_AND_RETURN((contactOffset >= 0.0f && contactOffset > mShape.getRestOffset()), "PxShape::setContactOffset: contactOffset should be positive, and greater than restOffset!");
|
||
|
PX_CHECK_AND_RETURN(isWritable(), "PxShape::setContactOffset: shared shapes attached to actors are not writable.");
|
||
|
|
||
|
mShape.setContactOffset(contactOffset);
|
||
|
}
|
||
|
|
||
|
PxReal NpShape::getContactOffset() const
|
||
|
{
|
||
|
NP_READ_CHECK(getOwnerScene());
|
||
|
|
||
|
return mShape.getContactOffset();
|
||
|
}
|
||
|
|
||
|
void NpShape::setRestOffset(PxReal restOffset)
|
||
|
{
|
||
|
NP_WRITE_CHECK(getOwnerScene());
|
||
|
PX_CHECK_AND_RETURN(PxIsFinite(restOffset), "PxShape::setRestOffset: invalid float");
|
||
|
PX_CHECK_AND_RETURN((restOffset < mShape.getContactOffset()), "PxShape::setRestOffset: restOffset should be less than contactOffset!");
|
||
|
PX_CHECK_AND_RETURN(isWritable(), "PxShape::setRestOffset: shared shapes attached to actors are not writable.");
|
||
|
|
||
|
mShape.setRestOffset(restOffset);
|
||
|
}
|
||
|
|
||
|
PxReal NpShape::getRestOffset() const
|
||
|
{
|
||
|
NP_READ_CHECK(getOwnerScene());
|
||
|
|
||
|
return mShape.getRestOffset();
|
||
|
}
|
||
|
|
||
|
void NpShape::setTorsionalPatchRadius(PxReal radius)
|
||
|
{
|
||
|
NP_WRITE_CHECK(getOwnerScene());
|
||
|
PX_CHECK_AND_RETURN(PxIsFinite(radius), "PxShape::setTorsionalPatchRadius: invalid float");
|
||
|
PX_CHECK_AND_RETURN((radius >= 0.f), "PxShape::setTorsionalPatchRadius: must be >= 0.f");
|
||
|
|
||
|
mShape.setTorsionalPatchRadius(radius);
|
||
|
}
|
||
|
|
||
|
PxReal NpShape::getTorsionalPatchRadius() const
|
||
|
{
|
||
|
NP_READ_CHECK(getOwnerScene());
|
||
|
return mShape.getTorsionalPatchRadius();
|
||
|
}
|
||
|
|
||
|
void NpShape::setMinTorsionalPatchRadius(PxReal radius)
|
||
|
{
|
||
|
NP_WRITE_CHECK(getOwnerScene());
|
||
|
PX_CHECK_AND_RETURN(PxIsFinite(radius), "PxShape::setMinTorsionalPatchRadius: invalid float");
|
||
|
PX_CHECK_AND_RETURN((radius >= 0.f), "PxShape::setMinTorsionalPatchRadius: must be >= 0.f");
|
||
|
|
||
|
mShape.setMinTorsionalPatchRadius(radius);
|
||
|
}
|
||
|
|
||
|
PxReal NpShape::getMinTorsionalPatchRadius() const
|
||
|
{
|
||
|
NP_READ_CHECK(getOwnerScene());
|
||
|
return mShape.getMinTorsionalPatchRadius();
|
||
|
}
|
||
|
|
||
|
void NpShape::setFlagsInternal(PxShapeFlags inFlags)
|
||
|
{
|
||
|
const bool hasMeshTypeGeom = mShape.getGeometryType() == PxGeometryType::eTRIANGLEMESH || mShape.getGeometryType() == PxGeometryType::eHEIGHTFIELD;
|
||
|
|
||
|
if(hasMeshTypeGeom && (inFlags & PxShapeFlag::eTRIGGER_SHAPE))
|
||
|
{
|
||
|
Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__,
|
||
|
"PxShape::setFlag(s): triangle mesh and heightfield triggers are not supported!");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if((inFlags & PxShapeFlag::eSIMULATION_SHAPE) && (inFlags & PxShapeFlag::eTRIGGER_SHAPE))
|
||
|
{
|
||
|
Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__,
|
||
|
"PxShape::setFlag(s): shapes cannot simultaneously be trigger shapes and simulation shapes.");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
const PxShapeFlags oldFlags = mShape.getFlags();
|
||
|
|
||
|
const bool oldIsSimShape = oldFlags & PxShapeFlag::eSIMULATION_SHAPE;
|
||
|
const bool isSimShape = inFlags & PxShapeFlag::eSIMULATION_SHAPE;
|
||
|
|
||
|
if(mActor)
|
||
|
{
|
||
|
const PxType type = mActor->getConcreteType();
|
||
|
|
||
|
// PT: US5732 - support kinematic meshes
|
||
|
bool isKinematic = false;
|
||
|
if(type==PxConcreteType::eRIGID_DYNAMIC)
|
||
|
{
|
||
|
PxRigidDynamic* rigidDynamic = static_cast<PxRigidDynamic*>(mActor);
|
||
|
isKinematic = rigidDynamic->getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC;
|
||
|
}
|
||
|
|
||
|
if((type != PxConcreteType::eRIGID_STATIC) && !isKinematic && isSimShape && !oldIsSimShape && (hasMeshTypeGeom || mShape.getGeometryType() == PxGeometryType::ePLANE))
|
||
|
{
|
||
|
Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__,
|
||
|
"PxShape::setFlag(s): triangle mesh, heightfield and plane shapes can only be simulation shapes if part of a PxRigidStatic!");
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const bool oldHasSceneQuery = oldFlags & PxShapeFlag::eSCENE_QUERY_SHAPE;
|
||
|
const bool hasSceneQuery = inFlags & PxShapeFlag::eSCENE_QUERY_SHAPE;
|
||
|
|
||
|
mShape.setFlags(inFlags);
|
||
|
|
||
|
if(oldHasSceneQuery != hasSceneQuery && mActor)
|
||
|
{
|
||
|
NpScene* npScene = getAPIScene();
|
||
|
NpShapeManager* shapeManager = NpActor::getShapeManager(*mActor);
|
||
|
if(npScene)
|
||
|
{
|
||
|
if(hasSceneQuery)
|
||
|
shapeManager->setupSceneQuery(npScene->getSceneQueryManagerFast(), *mActor, *this);
|
||
|
else
|
||
|
shapeManager->teardownSceneQuery(npScene->getSceneQueryManagerFast(), *this);
|
||
|
}
|
||
|
|
||
|
// invalidate the pruning structure if the actor bounds changed
|
||
|
if(shapeManager->getPruningStructure())
|
||
|
{
|
||
|
Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxShape::setFlag: Shape is a part of pruning structure, pruning structure is now invalid!");
|
||
|
shapeManager->getPruningStructure()->invalidate(mActor);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void NpShape::setFlag(PxShapeFlag::Enum flag, bool value)
|
||
|
{
|
||
|
NP_WRITE_CHECK(getOwnerScene());
|
||
|
PX_CHECK_AND_RETURN(isWritable(), "PxShape::setFlag: shared shapes attached to actors are not writable.");
|
||
|
PX_SIMD_GUARD;
|
||
|
|
||
|
PxShapeFlags shapeFlags = mShape.getFlags();
|
||
|
shapeFlags = value ? shapeFlags | flag : shapeFlags & ~flag;
|
||
|
|
||
|
setFlagsInternal(shapeFlags);
|
||
|
}
|
||
|
|
||
|
void NpShape::setFlags(PxShapeFlags inFlags)
|
||
|
{
|
||
|
NP_WRITE_CHECK(getOwnerScene());
|
||
|
PX_CHECK_AND_RETURN(isWritable(), "PxShape::setFlags: shared shapes attached to actors are not writable.");
|
||
|
PX_SIMD_GUARD;
|
||
|
|
||
|
setFlagsInternal(inFlags);
|
||
|
}
|
||
|
|
||
|
PxShapeFlags NpShape::getFlags() const
|
||
|
{
|
||
|
NP_READ_CHECK(getOwnerScene());
|
||
|
return mShape.getFlags();
|
||
|
}
|
||
|
|
||
|
bool NpShape::isExclusive() const
|
||
|
{
|
||
|
NP_READ_CHECK(getOwnerScene());
|
||
|
return (mExclusiveAndActorCount & EXCLUSIVE_MASK) != 0;
|
||
|
}
|
||
|
|
||
|
void NpShape::onActorAttach(PxRigidActor& actor)
|
||
|
{
|
||
|
incRefCount();
|
||
|
if(isExclusiveFast())
|
||
|
mActor = &actor;
|
||
|
Ps::atomicIncrement(&mExclusiveAndActorCount);
|
||
|
}
|
||
|
|
||
|
void NpShape::onActorDetach()
|
||
|
{
|
||
|
PX_ASSERT(getActorCount() > 0);
|
||
|
Ps::atomicDecrement(&mExclusiveAndActorCount);
|
||
|
if(isExclusiveFast())
|
||
|
mActor = NULL;
|
||
|
decRefCount();
|
||
|
}
|
||
|
|
||
|
void NpShape::setName(const char* debugName)
|
||
|
{
|
||
|
NP_WRITE_CHECK(getOwnerScene());
|
||
|
PX_CHECK_AND_RETURN(isWritable(), "PxShape::setName: shared shapes attached to actors are not writable.");
|
||
|
|
||
|
mName = debugName;
|
||
|
|
||
|
updatePvdProperties(mShape);
|
||
|
}
|
||
|
|
||
|
const char* NpShape::getName() const
|
||
|
{
|
||
|
NP_READ_CHECK(getOwnerScene());
|
||
|
|
||
|
return mName;
|
||
|
}
|
||
|
|
||
|
NpScene* NpShape::getOwnerScene() const
|
||
|
{
|
||
|
return mActor ? NpActor::getOwnerScene(*mActor) : NULL;
|
||
|
}
|
||
|
|
||
|
NpScene* NpShape::getAPIScene() const
|
||
|
{
|
||
|
// gets called when we update SQ structures due to a write - in which case there must be an actor
|
||
|
PX_ASSERT(mActor);
|
||
|
return NpActor::getAPIScene(*mActor);
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
namespace physx
|
||
|
{
|
||
|
Sc::RigidCore* NpShapeGetScRigidObjectFromScbSLOW(const Scb::Shape& scb)
|
||
|
{
|
||
|
const NpShape* np = getNpShape(&scb);
|
||
|
return np->NpShape::getActor() ? &np->getScRigidObjectExclusive() : NULL;
|
||
|
}
|
||
|
|
||
|
size_t NpShapeGetScPtrOffset()
|
||
|
{
|
||
|
const size_t offset = size_t(&(reinterpret_cast<NpShape*>(0)->getScbShape().getScShape()));
|
||
|
return offset;
|
||
|
}
|
||
|
|
||
|
void NpShapeIncRefCount(Scb::Shape& scb)
|
||
|
{
|
||
|
NpShape* np = const_cast<NpShape*>(getNpShape(&scb));
|
||
|
np->incRefCount();
|
||
|
}
|
||
|
|
||
|
void NpShapeDecRefCount(Scb::Shape& scb)
|
||
|
{
|
||
|
NpShape* np = const_cast<NpShape*>(getNpShape(&scb));
|
||
|
np->decRefCount();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// see NpConvexMesh.h, NpHeightField.h, NpTriangleMesh.h for details on how ref counting works for meshes
|
||
|
Cm::RefCountable* NpShape::getMeshRefCountable()
|
||
|
{
|
||
|
switch(mShape.getGeometryType())
|
||
|
{
|
||
|
case PxGeometryType::eCONVEXMESH:
|
||
|
return static_cast<Gu::ConvexMesh*>(
|
||
|
static_cast<const PxConvexMeshGeometry&>(mShape.getGeometry()).convexMesh);
|
||
|
|
||
|
case PxGeometryType::eHEIGHTFIELD:
|
||
|
return static_cast<Gu::HeightField*>(
|
||
|
static_cast<const PxHeightFieldGeometry&>(mShape.getGeometry()).heightField);
|
||
|
|
||
|
case PxGeometryType::eTRIANGLEMESH:
|
||
|
return static_cast<Gu::TriangleMesh*>(
|
||
|
static_cast<const PxTriangleMeshGeometry&>(mShape.getGeometry()).triangleMesh);
|
||
|
|
||
|
case PxGeometryType::eSPHERE:
|
||
|
case PxGeometryType::ePLANE:
|
||
|
case PxGeometryType::eCAPSULE:
|
||
|
case PxGeometryType::eBOX:
|
||
|
case PxGeometryType::eGEOMETRY_COUNT:
|
||
|
case PxGeometryType::eINVALID:
|
||
|
break;
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
bool NpShape::isWritable()
|
||
|
{
|
||
|
// a shape is writable if it's exclusive, or it's not connected to any actors (which is true if the ref count is 1 and the user ref is not released.)
|
||
|
return isExclusiveFast() || (getRefCount()==1 && (mBaseFlags & PxBaseFlag::eIS_RELEASABLE));
|
||
|
}
|
||
|
|
||
|
void NpShape::incMeshRefCount()
|
||
|
{
|
||
|
Cm::RefCountable* npMesh = getMeshRefCountable();
|
||
|
if(npMesh)
|
||
|
npMesh->incRefCount();
|
||
|
}
|
||
|
|
||
|
void NpShape::decMeshRefCount()
|
||
|
{
|
||
|
Cm::RefCountable* npMesh = getMeshRefCountable();
|
||
|
if(npMesh)
|
||
|
npMesh->decRefCount();
|
||
|
}
|
||
|
|
||
|
bool NpShape::checkMaterialSetup(const PxGeometry& geom, const char* errorMsgPrefix, PxMaterial*const* materials, PxU16 materialCount)
|
||
|
{
|
||
|
for(PxU32 i=0; i<materialCount; ++i)
|
||
|
{
|
||
|
if(!materials[i])
|
||
|
{
|
||
|
Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__,
|
||
|
"material pointer %d is NULL!", i);
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// check that simple shapes don't get assigned multiple materials
|
||
|
if (materialCount > 1 && (geom.getType() != PxGeometryType::eHEIGHTFIELD) && (geom.getType() != PxGeometryType::eTRIANGLEMESH))
|
||
|
{
|
||
|
Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__,
|
||
|
"%s: multiple materials defined for single material geometry!", errorMsgPrefix);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// verify we provide all materials required
|
||
|
if (materialCount > 1 && (geom.getType() == PxGeometryType::eTRIANGLEMESH))
|
||
|
{
|
||
|
const PxTriangleMeshGeometry& meshGeom = static_cast<const PxTriangleMeshGeometry&>(geom);
|
||
|
const PxTriangleMesh& mesh = *meshGeom.triangleMesh;
|
||
|
if(mesh.getTriangleMaterialIndex(0) != 0xffff)
|
||
|
{
|
||
|
for(PxU32 i = 0; i < mesh.getNbTriangles(); i++)
|
||
|
{
|
||
|
const PxMaterialTableIndex meshMaterialIndex = mesh.getTriangleMaterialIndex(i);
|
||
|
if(meshMaterialIndex >= materialCount)
|
||
|
{
|
||
|
Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__,
|
||
|
"%s: PxTriangleMesh material indices reference more materials than provided!", errorMsgPrefix);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (materialCount > 1 && (geom.getType() == PxGeometryType::eHEIGHTFIELD))
|
||
|
{
|
||
|
const PxHeightFieldGeometry& meshGeom = static_cast<const PxHeightFieldGeometry&>(geom);
|
||
|
const PxHeightField& mesh = *meshGeom.heightField;
|
||
|
if(mesh.getTriangleMaterialIndex(0) != 0xffff)
|
||
|
{
|
||
|
const PxU32 nbTris = mesh.getNbColumns()*mesh.getNbRows()*2;
|
||
|
for(PxU32 i = 0; i < nbTris; i++)
|
||
|
{
|
||
|
const PxMaterialTableIndex meshMaterialIndex = mesh.getTriangleMaterialIndex(i);
|
||
|
if(meshMaterialIndex != PxHeightFieldMaterial::eHOLE && meshMaterialIndex >= materialCount)
|
||
|
{
|
||
|
Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__,
|
||
|
"%s: PxHeightField material indices reference more materials than provided!", errorMsgPrefix);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|