// // 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(this)); PxShape::userData = NULL; incMeshRefCount(); } NpShape::~NpShape() { decMeshRefCount(); PxU32 nbMaterials = mShape.getNbMaterials(); for (PxU32 i=0; i < nbMaterials; i++) { NpMaterial* mat = static_cast(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(mShape.getGeometry()).convexMesh; break; case PxGeometryType::eHEIGHTFIELD: mesh = static_cast(mShape.getGeometry()).heightField; break; case PxGeometryType::eTRIANGLEMESH: mesh = static_cast(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(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()); NpMaterial& material = *static_cast(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(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(*mActor).getScbBodyFast().getScBody(); else if (actorType == PxConcreteType::eARTICULATION_LINK) return static_cast(*mActor).getScbBodyFast().getScBody(); else return static_cast(*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(g).isValid(); break; case PxGeometryType::ePLANE: isValid = static_cast(g).isValid(); break; case PxGeometryType::eCAPSULE: isValid = static_cast(g).isValid(); break; case PxGeometryType::eBOX: isValid = static_cast(g).isValid(); break; case PxGeometryType::eCONVEXMESH: isValid = static_cast(g).isValid(); break; case PxGeometryType::eTRIANGLEMESH: isValid = static_cast(g).isValid(); break; case PxGeometryType::eHEIGHTFIELD: isValid = static_cast(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(mShape.getGeometry()); } template 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(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(materials[i])->incRefCount(); for(PxU32 i=0; i < oldMaterialCount; i++) static_cast(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(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(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(0)->getScbShape().getScShape())); return offset; } void NpShapeIncRefCount(Scb::Shape& scb) { NpShape* np = const_cast(getNpShape(&scb)); np->incRefCount(); } void NpShapeDecRefCount(Scb::Shape& scb) { NpShape* np = const_cast(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( static_cast(mShape.getGeometry()).convexMesh); case PxGeometryType::eHEIGHTFIELD: return static_cast( static_cast(mShape.getGeometry()).heightField); case PxGeometryType::eTRIANGLEMESH: return static_cast( static_cast(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 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(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(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; } ///////////////////////////////////////////////////////////////////////////////