| 1 | // |
| 2 | // Redistribution and use in source and binary forms, with or without |
| 3 | // modification, are permitted provided that the following conditions |
| 4 | // are met: |
| 5 | // * Redistributions of source code must retain the above copyright |
| 6 | // notice, this list of conditions and the following disclaimer. |
| 7 | // * Redistributions in binary form must reproduce the above copyright |
| 8 | // notice, this list of conditions and the following disclaimer in the |
| 9 | // documentation and/or other materials provided with the distribution. |
| 10 | // * Neither the name of NVIDIA CORPORATION nor the names of its |
| 11 | // contributors may be used to endorse or promote products derived |
| 12 | // from this software without specific prior written permission. |
| 13 | // |
| 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY |
| 15 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| 17 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
| 18 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| 19 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| 20 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| 21 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| 22 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 23 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 24 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 25 | // |
| 26 | // Copyright (c) 2008-2021 NVIDIA Corporation. All rights reserved. |
| 27 | // Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. |
| 28 | // Copyright (c) 2001-2004 NovodeX AG. All rights reserved. |
| 29 | |
| 30 | #include "NpCast.h" |
| 31 | #include "GuConvexMesh.h" |
| 32 | #include "GuTriangleMesh.h" |
| 33 | #include "ScbNpDeps.h" |
| 34 | #include "GuBounds.h" |
| 35 | |
| 36 | using namespace physx; |
| 37 | using namespace Sq; |
| 38 | |
| 39 | static PX_FORCE_INLINE void updatePvdProperties(const Scb::Shape& shape) |
| 40 | { |
| 41 | #if PX_SUPPORT_PVD |
| 42 | Scb::Scene* scbScene = shape.getScbSceneForAPI(); |
| 43 | if(scbScene) |
| 44 | scbScene->getScenePvdClient().updatePvdProperties(&shape); |
| 45 | #else |
| 46 | PX_UNUSED(shape); |
| 47 | #endif |
| 48 | } |
| 49 | |
| 50 | NpShape::NpShape(const PxGeometry& geometry, PxShapeFlags shapeFlags, const PxU16* materialIndices, PxU16 materialCount, bool isExclusive) |
| 51 | : PxShape (PxConcreteType::eSHAPE, PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE) |
| 52 | , mActor (NULL) |
| 53 | , mShape (geometry, shapeFlags, materialIndices, materialCount, isExclusive) |
| 54 | , mName (NULL) |
| 55 | , mExclusiveAndActorCount (isExclusive ? EXCLUSIVE_MASK : 0) |
| 56 | { |
| 57 | PX_ASSERT(mShape.getScShape().getPxShape() == static_cast<PxShape*>(this)); |
| 58 | |
| 59 | PxShape::userData = NULL; |
| 60 | |
| 61 | incMeshRefCount(); |
| 62 | } |
| 63 | |
| 64 | NpShape::~NpShape() |
| 65 | { |
| 66 | decMeshRefCount(); |
| 67 | |
| 68 | PxU32 nbMaterials = mShape.getNbMaterials(); |
| 69 | for (PxU32 i=0; i < nbMaterials; i++) |
| 70 | { |
| 71 | NpMaterial* mat = static_cast<NpMaterial*>(mShape.getMaterial(index: i)); |
| 72 | mat->decRefCount(); |
| 73 | } |
| 74 | } |
| 75 | |
| 76 | void NpShape::onRefCountZero() |
| 77 | { |
| 78 | NpFactory::getInstance().onShapeRelease(this); |
| 79 | // see NpShape.h for ref counting semantics for shapes |
| 80 | NpDestroy(getScbShape()); |
| 81 | } |
| 82 | |
| 83 | // PX_SERIALIZATION |
| 84 | |
| 85 | NpShape::NpShape(PxBaseFlags baseFlags) : PxShape(baseFlags), mShape(PxEmpty) {} |
| 86 | |
| 87 | void NpShape::preExportDataReset() |
| 88 | { |
| 89 | Cm::RefCountable::preExportDataReset(); |
| 90 | mExclusiveAndActorCount &= EXCLUSIVE_MASK; |
| 91 | } |
| 92 | |
| 93 | void NpShape::(PxSerializationContext& context) |
| 94 | { |
| 95 | getScbShape().getScShape().exportExtraData(stream&: context); |
| 96 | context.writeName(name: mName); |
| 97 | } |
| 98 | |
| 99 | void NpShape::(PxDeserializationContext& context) |
| 100 | { |
| 101 | getScbShape().getScShape().importExtraData(context); |
| 102 | context.readName(name&: mName); |
| 103 | } |
| 104 | |
| 105 | void NpShape::requiresObjects(PxProcessPxBaseCallback& c) |
| 106 | { |
| 107 | //meshes |
| 108 | PxBase* mesh = NULL; |
| 109 | switch(mShape.getGeometryType()) |
| 110 | { |
| 111 | case PxGeometryType::eCONVEXMESH: |
| 112 | mesh = static_cast<const PxConvexMeshGeometry&>(mShape.getGeometry()).convexMesh; |
| 113 | break; |
| 114 | case PxGeometryType::eHEIGHTFIELD: |
| 115 | mesh = static_cast<const PxHeightFieldGeometry&>(mShape.getGeometry()).heightField; |
| 116 | break; |
| 117 | case PxGeometryType::eTRIANGLEMESH: |
| 118 | mesh = static_cast<const PxTriangleMeshGeometry&>(mShape.getGeometry()).triangleMesh; |
| 119 | break; |
| 120 | case PxGeometryType::eSPHERE: |
| 121 | case PxGeometryType::ePLANE: |
| 122 | case PxGeometryType::eCAPSULE: |
| 123 | case PxGeometryType::eBOX: |
| 124 | case PxGeometryType::eGEOMETRY_COUNT: |
| 125 | case PxGeometryType::eINVALID: |
| 126 | break; |
| 127 | } |
| 128 | |
| 129 | if(mesh) |
| 130 | c.process(*mesh); |
| 131 | |
| 132 | //material |
| 133 | PxU32 nbMaterials = mShape.getNbMaterials(); |
| 134 | for (PxU32 i=0; i < nbMaterials; i++) |
| 135 | { |
| 136 | NpMaterial* mat = static_cast<NpMaterial*>(mShape.getMaterial(index: i)); |
| 137 | c.process(*mat); |
| 138 | } |
| 139 | } |
| 140 | |
| 141 | void NpShape::resolveReferences(PxDeserializationContext& context) |
| 142 | { |
| 143 | // getMaterials() only works after material indices have been patched. |
| 144 | // in order to get to the new material indices, we need access to the new materials. |
| 145 | // this only leaves us with the option of acquiring the material through the context given an old material index (we do have the mapping) |
| 146 | { |
| 147 | PxU32 nbIndices = mShape.getScShape().getNbMaterialIndices(); |
| 148 | const PxU16* indices = mShape.getScShape().getMaterialIndices(); |
| 149 | |
| 150 | for (PxU32 i=0; i < nbIndices; i++) |
| 151 | { |
| 152 | PxBase* base = context.resolveReference(PX_SERIAL_REF_KIND_MATERIAL_IDX, reference: size_t(indices[i])); |
| 153 | PX_ASSERT(base && base->is<PxMaterial>()); |
| 154 | |
| 155 | NpMaterial& material = *static_cast<NpMaterial*>(base); |
| 156 | getScbShape().getScShape().resolveMaterialReference(materialTableIndex: i, materialIndex: material.getHandle()); |
| 157 | } |
| 158 | } |
| 159 | |
| 160 | context.translatePxBase(base&: mActor); |
| 161 | |
| 162 | getScbShape().getScShape().resolveReferences(context); |
| 163 | |
| 164 | |
| 165 | incMeshRefCount(); |
| 166 | |
| 167 | // Increment materials' refcounts in a second pass. Works better in case of failure above. |
| 168 | PxU32 nbMaterials = mShape.getNbMaterials(); |
| 169 | for (PxU32 i=0; i < nbMaterials; i++) |
| 170 | { |
| 171 | NpMaterial* mat = static_cast<NpMaterial*>(mShape.getMaterial(index: i)); |
| 172 | mat->incRefCount(); |
| 173 | } |
| 174 | } |
| 175 | |
| 176 | NpShape* NpShape::createObject(PxU8*& address, PxDeserializationContext& context) |
| 177 | { |
| 178 | NpShape* obj = new (address) NpShape(PxBaseFlag::eIS_RELEASABLE); |
| 179 | address += sizeof(NpShape); |
| 180 | obj->importExtraData(context); |
| 181 | obj->resolveReferences(context); |
| 182 | return obj; |
| 183 | } |
| 184 | //~PX_SERIALIZATION |
| 185 | |
| 186 | PxU32 NpShape::getReferenceCount() const |
| 187 | { |
| 188 | return getRefCount(); |
| 189 | } |
| 190 | |
| 191 | void NpShape::acquireReference() |
| 192 | { |
| 193 | incRefCount(); |
| 194 | } |
| 195 | |
| 196 | void NpShape::release() |
| 197 | { |
| 198 | PX_CHECK_AND_RETURN(getRefCount() > 1 || getActorCount() == 0, "PxShape::release: last reference to a shape released while still attached to an actor!" ); |
| 199 | NP_WRITE_CHECK(getOwnerScene()); |
| 200 | releaseInternal(); |
| 201 | } |
| 202 | |
| 203 | void NpShape::releaseInternal() |
| 204 | { |
| 205 | decRefCount(); |
| 206 | } |
| 207 | |
| 208 | Sc::RigidCore& NpShape::getScRigidObjectExclusive() const |
| 209 | { |
| 210 | const PxType actorType = mActor->getConcreteType(); |
| 211 | |
| 212 | if (actorType == PxConcreteType::eRIGID_DYNAMIC) |
| 213 | return static_cast<NpRigidDynamic&>(*mActor).getScbBodyFast().getScBody(); |
| 214 | else if (actorType == PxConcreteType::eARTICULATION_LINK) |
| 215 | return static_cast<NpArticulationLink&>(*mActor).getScbBodyFast().getScBody(); |
| 216 | else |
| 217 | return static_cast<NpRigidStatic&>(*mActor).getScbRigidStaticFast().getScStatic(); |
| 218 | } |
| 219 | |
| 220 | void NpShape::updateSQ(const char* errorMessage) |
| 221 | { |
| 222 | if(mActor && (mShape.getFlags() & PxShapeFlag::eSCENE_QUERY_SHAPE)) |
| 223 | { |
| 224 | NpScene* scene = NpActor::getAPIScene(actor: *mActor); |
| 225 | NpShapeManager* shapeManager = NpActor::getShapeManager(actor&: *mActor); |
| 226 | if(scene) |
| 227 | { |
| 228 | PxU32 compoundId; |
| 229 | const PrunerData sqData = shapeManager->findSceneQueryData(shape: *this, compoundId); |
| 230 | scene->getSceneQueryManagerFast().markForUpdate(compoundId, s: sqData); |
| 231 | } |
| 232 | |
| 233 | // invalidate the pruning structure if the actor bounds changed |
| 234 | if(shapeManager->getPruningStructure()) |
| 235 | { |
| 236 | Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, messageFmt: errorMessage); |
| 237 | shapeManager->getPruningStructure()->invalidate(actor: mActor); |
| 238 | } |
| 239 | } |
| 240 | } |
| 241 | |
| 242 | PxGeometryType::Enum NpShape::getGeometryType() const |
| 243 | { |
| 244 | NP_READ_CHECK(getOwnerScene()); |
| 245 | |
| 246 | return mShape.getGeometryType(); |
| 247 | } |
| 248 | |
| 249 | void NpShape::setGeometry(const PxGeometry& g) |
| 250 | { |
| 251 | NP_WRITE_CHECK(getOwnerScene()); |
| 252 | PX_CHECK_AND_RETURN(isWritable(), "PxShape::setGeometry: shared shapes attached to actors are not writable." ); |
| 253 | PX_SIMD_GUARD; |
| 254 | |
| 255 | // PT: fixes US2117 |
| 256 | if(g.getType() != getGeometryTypeFast()) |
| 257 | { |
| 258 | Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, messageFmt: "PxShape::setGeometry(): Invalid geometry type. Changing the type of the shape is not supported." ); |
| 259 | return; |
| 260 | } |
| 261 | |
| 262 | #if PX_CHECKED |
| 263 | bool isValid = false; |
| 264 | switch(g.getType()) |
| 265 | { |
| 266 | case PxGeometryType::eSPHERE: |
| 267 | isValid = static_cast<const PxSphereGeometry&>(g).isValid(); |
| 268 | break; |
| 269 | |
| 270 | case PxGeometryType::ePLANE: |
| 271 | isValid = static_cast<const PxPlaneGeometry&>(g).isValid(); |
| 272 | break; |
| 273 | |
| 274 | case PxGeometryType::eCAPSULE: |
| 275 | isValid = static_cast<const PxCapsuleGeometry&>(g).isValid(); |
| 276 | break; |
| 277 | |
| 278 | case PxGeometryType::eBOX: |
| 279 | isValid = static_cast<const PxBoxGeometry&>(g).isValid(); |
| 280 | break; |
| 281 | |
| 282 | case PxGeometryType::eCONVEXMESH: |
| 283 | isValid = static_cast<const PxConvexMeshGeometry&>(g).isValid(); |
| 284 | break; |
| 285 | |
| 286 | case PxGeometryType::eTRIANGLEMESH: |
| 287 | isValid = static_cast<const PxTriangleMeshGeometry&>(g).isValid(); |
| 288 | break; |
| 289 | |
| 290 | case PxGeometryType::eHEIGHTFIELD: |
| 291 | isValid = static_cast<const PxHeightFieldGeometry&>(g).isValid(); |
| 292 | break; |
| 293 | |
| 294 | case PxGeometryType::eGEOMETRY_COUNT: |
| 295 | case PxGeometryType::eINVALID: |
| 296 | break; |
| 297 | } |
| 298 | |
| 299 | if(!isValid) |
| 300 | { |
| 301 | Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "PxShape::setGeometry(): Invalid geometry!" ); |
| 302 | return; |
| 303 | } |
| 304 | #endif |
| 305 | |
| 306 | decMeshRefCount(); |
| 307 | |
| 308 | mShape.setGeometry(g); |
| 309 | |
| 310 | incMeshRefCount(); |
| 311 | |
| 312 | updateSQ(errorMessage: "PxShape::setGeometry: Shape is a part of pruning structure, pruning structure is now invalid!" ); |
| 313 | } |
| 314 | |
| 315 | PxGeometryHolder NpShape::getGeometry() const |
| 316 | { |
| 317 | PX_COMPILE_TIME_ASSERT(sizeof(Gu::GeometryUnion)>=sizeof(PxGeometryHolder)); |
| 318 | return reinterpret_cast<const PxGeometryHolder&>(mShape.getGeometry()); |
| 319 | } |
| 320 | |
| 321 | template<class T> |
| 322 | static PX_FORCE_INLINE bool getGeometryT(const NpShape* npShape, PxGeometryType::Enum type, T& geom) |
| 323 | { |
| 324 | NP_READ_CHECK(npShape->getOwnerScene()); |
| 325 | |
| 326 | if(npShape->getGeometryTypeFast() != type) |
| 327 | return false; |
| 328 | |
| 329 | geom = static_cast<const T&>(npShape->getScbShape().getGeometry()); |
| 330 | return true; |
| 331 | } |
| 332 | |
| 333 | bool NpShape::getBoxGeometry(PxBoxGeometry& g) const { return getGeometryT(npShape: this, type: PxGeometryType::eBOX, geom&: g); } |
| 334 | bool NpShape::getSphereGeometry(PxSphereGeometry& g) const { return getGeometryT(npShape: this, type: PxGeometryType::eSPHERE, geom&: g); } |
| 335 | bool NpShape::getCapsuleGeometry(PxCapsuleGeometry& g) const { return getGeometryT(npShape: this, type: PxGeometryType::eCAPSULE, geom&: g); } |
| 336 | bool NpShape::getPlaneGeometry(PxPlaneGeometry& g) const { return getGeometryT(npShape: this, type: PxGeometryType::ePLANE, geom&: g); } |
| 337 | bool NpShape::getConvexMeshGeometry(PxConvexMeshGeometry& g) const { return getGeometryT(npShape: this, type: PxGeometryType::eCONVEXMESH, geom&: g); } |
| 338 | bool NpShape::getTriangleMeshGeometry(PxTriangleMeshGeometry& g) const { return getGeometryT(npShape: this, type: PxGeometryType::eTRIANGLEMESH, geom&: g); } |
| 339 | bool NpShape::getHeightFieldGeometry(PxHeightFieldGeometry& g) const { return getGeometryT(npShape: this, type: PxGeometryType::eHEIGHTFIELD, geom&: g); } |
| 340 | |
| 341 | PxRigidActor* NpShape::getActor() const |
| 342 | { |
| 343 | NP_READ_CHECK(getOwnerScene()); |
| 344 | return mActor; |
| 345 | } |
| 346 | |
| 347 | void NpShape::setLocalPose(const PxTransform& newShape2Actor) |
| 348 | { |
| 349 | PX_CHECK_AND_RETURN(newShape2Actor.isSane(), "PxShape::setLocalPose: pose is not valid." ); |
| 350 | PX_CHECK_AND_RETURN(isWritable(), "PxShape::setLocalPose: shared shapes attached to actors are not writable." ); |
| 351 | NP_WRITE_CHECK(getOwnerScene()); |
| 352 | |
| 353 | mShape.setShape2Actor(newShape2Actor.getNormalized()); |
| 354 | |
| 355 | updateSQ(errorMessage: "PxShape::setLocalPose: Shape is a part of pruning structure, pruning structure is now invalid!" ); |
| 356 | } |
| 357 | |
| 358 | PxTransform NpShape::getLocalPose() const |
| 359 | { |
| 360 | NP_READ_CHECK(getOwnerScene()); |
| 361 | |
| 362 | return mShape.getShape2Actor(); |
| 363 | } |
| 364 | |
| 365 | /////////////////////////////////////////////////////////////////////////////// |
| 366 | |
| 367 | void NpShape::setSimulationFilterData(const PxFilterData& data) |
| 368 | { |
| 369 | NP_WRITE_CHECK(getOwnerScene()); |
| 370 | PX_CHECK_AND_RETURN(isWritable(), "PxShape::setSimulationFilterData: shared shapes attached to actors are not writable." ); |
| 371 | mShape.setSimulationFilterData(data); |
| 372 | } |
| 373 | |
| 374 | PxFilterData NpShape::getSimulationFilterData() const |
| 375 | { |
| 376 | NP_READ_CHECK(getOwnerScene()); |
| 377 | return mShape.getSimulationFilterData(); |
| 378 | } |
| 379 | |
| 380 | void NpShape::setQueryFilterData(const PxFilterData& data) |
| 381 | { |
| 382 | NP_WRITE_CHECK(getOwnerScene()); |
| 383 | PX_CHECK_AND_RETURN(isWritable(), "PxShape::setQueryFilterData: shared shapes attached to actors are not writable." ); |
| 384 | |
| 385 | mShape.getScShape().setQueryFilterData(data); // PT: this one doesn't need double-buffering |
| 386 | |
| 387 | updatePvdProperties(shape: mShape); |
| 388 | } |
| 389 | |
| 390 | PxFilterData NpShape::getQueryFilterData() const |
| 391 | { |
| 392 | NP_READ_CHECK(getOwnerScene()); |
| 393 | |
| 394 | return getQueryFilterDataFast(); |
| 395 | } |
| 396 | |
| 397 | /////////////////////////////////////////////////////////////////////////////// |
| 398 | |
| 399 | void NpShape::setMaterials(PxMaterial*const* materials, PxU16 materialCount) |
| 400 | { |
| 401 | NP_WRITE_CHECK(getOwnerScene()); |
| 402 | PX_CHECK_AND_RETURN(isWritable(), "PxShape::setMaterials: shared shapes attached to actors are not writable." ); |
| 403 | |
| 404 | #if PX_CHECKED |
| 405 | if (!NpShape::checkMaterialSetup(mShape.getGeometry(), "PxShape::setMaterials()" , materials, materialCount)) |
| 406 | return; |
| 407 | #endif |
| 408 | |
| 409 | PxU32 oldMaterialCount = mShape.getNbMaterials(); |
| 410 | PX_ALLOCA(oldMaterials, PxMaterial*, oldMaterialCount); |
| 411 | PxU32 tmp = mShape.getMaterials(buffer: oldMaterials, bufferSize: oldMaterialCount); |
| 412 | PX_ASSERT(tmp == oldMaterialCount); |
| 413 | PX_UNUSED(tmp); |
| 414 | |
| 415 | if (mShape.setMaterials(materials, materialCount)) |
| 416 | { |
| 417 | for(PxU32 i=0; i < materialCount; i++) |
| 418 | static_cast<NpMaterial*>(materials[i])->incRefCount(); |
| 419 | |
| 420 | for(PxU32 i=0; i < oldMaterialCount; i++) |
| 421 | static_cast<NpMaterial*>(oldMaterials[i])->decRefCount(); |
| 422 | } |
| 423 | } |
| 424 | |
| 425 | PxU16 NpShape::getNbMaterials() const |
| 426 | { |
| 427 | NP_READ_CHECK(getOwnerScene()); |
| 428 | |
| 429 | return mShape.getNbMaterials(); |
| 430 | } |
| 431 | |
| 432 | PxU32 NpShape::getMaterials(PxMaterial** userBuffer, PxU32 bufferSize, PxU32 startIndex) const |
| 433 | { |
| 434 | NP_READ_CHECK(getOwnerScene()); |
| 435 | |
| 436 | return mShape.getMaterials(buffer: userBuffer, bufferSize, startIndex); |
| 437 | } |
| 438 | |
| 439 | PxMaterial* NpShape::getMaterialFromInternalFaceIndex(PxU32 faceIndex) const |
| 440 | { |
| 441 | NP_READ_CHECK(getOwnerScene()); |
| 442 | |
| 443 | bool isHf = (getGeometryType() == PxGeometryType::eHEIGHTFIELD); |
| 444 | bool isMesh = (getGeometryType() == PxGeometryType::eTRIANGLEMESH); |
| 445 | if( faceIndex == 0xFFFFffff && (isHf || isMesh) ) |
| 446 | { |
| 447 | Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, |
| 448 | messageFmt: "PxShape::getMaterialFromInternalFaceIndex received 0xFFFFffff as input - returning NULL." ); |
| 449 | return NULL; |
| 450 | } |
| 451 | |
| 452 | PxMaterialTableIndex hitMatTableId = 0; |
| 453 | |
| 454 | if(isHf) |
| 455 | { |
| 456 | PxHeightFieldGeometry hfGeom; |
| 457 | getHeightFieldGeometry(g&: hfGeom); |
| 458 | |
| 459 | hitMatTableId = hfGeom.heightField->getTriangleMaterialIndex(triangleIndex: faceIndex); |
| 460 | } |
| 461 | else if(isMesh) |
| 462 | { |
| 463 | PxTriangleMeshGeometry triGeo; |
| 464 | getTriangleMeshGeometry(g&: triGeo); |
| 465 | |
| 466 | Gu::TriangleMesh* tm = static_cast<Gu::TriangleMesh*>(triGeo.triangleMesh); |
| 467 | if(tm->hasPerTriangleMaterials()) |
| 468 | hitMatTableId = triGeo.triangleMesh->getTriangleMaterialIndex(triangleIndex: faceIndex); |
| 469 | } |
| 470 | |
| 471 | return getMaterial(index: hitMatTableId); |
| 472 | } |
| 473 | |
| 474 | void NpShape::setContactOffset(PxReal contactOffset) |
| 475 | { |
| 476 | NP_WRITE_CHECK(getOwnerScene()); |
| 477 | |
| 478 | PX_CHECK_AND_RETURN(PxIsFinite(contactOffset), "PxShape::setContactOffset: invalid float" ); |
| 479 | PX_CHECK_AND_RETURN((contactOffset >= 0.0f && contactOffset > mShape.getRestOffset()), "PxShape::setContactOffset: contactOffset should be positive, and greater than restOffset!" ); |
| 480 | PX_CHECK_AND_RETURN(isWritable(), "PxShape::setContactOffset: shared shapes attached to actors are not writable." ); |
| 481 | |
| 482 | mShape.setContactOffset(contactOffset); |
| 483 | } |
| 484 | |
| 485 | PxReal NpShape::getContactOffset() const |
| 486 | { |
| 487 | NP_READ_CHECK(getOwnerScene()); |
| 488 | |
| 489 | return mShape.getContactOffset(); |
| 490 | } |
| 491 | |
| 492 | void NpShape::setRestOffset(PxReal restOffset) |
| 493 | { |
| 494 | NP_WRITE_CHECK(getOwnerScene()); |
| 495 | PX_CHECK_AND_RETURN(PxIsFinite(restOffset), "PxShape::setRestOffset: invalid float" ); |
| 496 | PX_CHECK_AND_RETURN((restOffset < mShape.getContactOffset()), "PxShape::setRestOffset: restOffset should be less than contactOffset!" ); |
| 497 | PX_CHECK_AND_RETURN(isWritable(), "PxShape::setRestOffset: shared shapes attached to actors are not writable." ); |
| 498 | |
| 499 | mShape.setRestOffset(restOffset); |
| 500 | } |
| 501 | |
| 502 | PxReal NpShape::getRestOffset() const |
| 503 | { |
| 504 | NP_READ_CHECK(getOwnerScene()); |
| 505 | |
| 506 | return mShape.getRestOffset(); |
| 507 | } |
| 508 | |
| 509 | void NpShape::setTorsionalPatchRadius(PxReal radius) |
| 510 | { |
| 511 | NP_WRITE_CHECK(getOwnerScene()); |
| 512 | PX_CHECK_AND_RETURN(PxIsFinite(radius), "PxShape::setTorsionalPatchRadius: invalid float" ); |
| 513 | PX_CHECK_AND_RETURN((radius >= 0.f), "PxShape::setTorsionalPatchRadius: must be >= 0.f" ); |
| 514 | |
| 515 | mShape.setTorsionalPatchRadius(radius); |
| 516 | } |
| 517 | |
| 518 | PxReal NpShape::getTorsionalPatchRadius() const |
| 519 | { |
| 520 | NP_READ_CHECK(getOwnerScene()); |
| 521 | return mShape.getTorsionalPatchRadius(); |
| 522 | } |
| 523 | |
| 524 | void NpShape::setMinTorsionalPatchRadius(PxReal radius) |
| 525 | { |
| 526 | NP_WRITE_CHECK(getOwnerScene()); |
| 527 | PX_CHECK_AND_RETURN(PxIsFinite(radius), "PxShape::setMinTorsionalPatchRadius: invalid float" ); |
| 528 | PX_CHECK_AND_RETURN((radius >= 0.f), "PxShape::setMinTorsionalPatchRadius: must be >= 0.f" ); |
| 529 | |
| 530 | mShape.setMinTorsionalPatchRadius(radius); |
| 531 | } |
| 532 | |
| 533 | PxReal NpShape::getMinTorsionalPatchRadius() const |
| 534 | { |
| 535 | NP_READ_CHECK(getOwnerScene()); |
| 536 | return mShape.getMinTorsionalPatchRadius(); |
| 537 | } |
| 538 | |
| 539 | void NpShape::setFlagsInternal(PxShapeFlags inFlags) |
| 540 | { |
| 541 | const bool hasMeshTypeGeom = mShape.getGeometryType() == PxGeometryType::eTRIANGLEMESH || mShape.getGeometryType() == PxGeometryType::eHEIGHTFIELD; |
| 542 | |
| 543 | if(hasMeshTypeGeom && (inFlags & PxShapeFlag::eTRIGGER_SHAPE)) |
| 544 | { |
| 545 | Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, |
| 546 | messageFmt: "PxShape::setFlag(s): triangle mesh and heightfield triggers are not supported!" ); |
| 547 | return; |
| 548 | } |
| 549 | |
| 550 | if((inFlags & PxShapeFlag::eSIMULATION_SHAPE) && (inFlags & PxShapeFlag::eTRIGGER_SHAPE)) |
| 551 | { |
| 552 | Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, |
| 553 | messageFmt: "PxShape::setFlag(s): shapes cannot simultaneously be trigger shapes and simulation shapes." ); |
| 554 | return; |
| 555 | } |
| 556 | |
| 557 | const PxShapeFlags oldFlags = mShape.getFlags(); |
| 558 | |
| 559 | const bool oldIsSimShape = oldFlags & PxShapeFlag::eSIMULATION_SHAPE; |
| 560 | const bool isSimShape = inFlags & PxShapeFlag::eSIMULATION_SHAPE; |
| 561 | |
| 562 | if(mActor) |
| 563 | { |
| 564 | const PxType type = mActor->getConcreteType(); |
| 565 | |
| 566 | // PT: US5732 - support kinematic meshes |
| 567 | bool isKinematic = false; |
| 568 | if(type==PxConcreteType::eRIGID_DYNAMIC) |
| 569 | { |
| 570 | PxRigidDynamic* rigidDynamic = static_cast<PxRigidDynamic*>(mActor); |
| 571 | isKinematic = rigidDynamic->getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC; |
| 572 | } |
| 573 | |
| 574 | if((type != PxConcreteType::eRIGID_STATIC) && !isKinematic && isSimShape && !oldIsSimShape && (hasMeshTypeGeom || mShape.getGeometryType() == PxGeometryType::ePLANE)) |
| 575 | { |
| 576 | Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, |
| 577 | messageFmt: "PxShape::setFlag(s): triangle mesh, heightfield and plane shapes can only be simulation shapes if part of a PxRigidStatic!" ); |
| 578 | return; |
| 579 | } |
| 580 | } |
| 581 | |
| 582 | const bool oldHasSceneQuery = oldFlags & PxShapeFlag::eSCENE_QUERY_SHAPE; |
| 583 | const bool hasSceneQuery = inFlags & PxShapeFlag::eSCENE_QUERY_SHAPE; |
| 584 | |
| 585 | mShape.setFlags(inFlags); |
| 586 | |
| 587 | if(oldHasSceneQuery != hasSceneQuery && mActor) |
| 588 | { |
| 589 | NpScene* npScene = getAPIScene(); |
| 590 | NpShapeManager* shapeManager = NpActor::getShapeManager(actor&: *mActor); |
| 591 | if(npScene) |
| 592 | { |
| 593 | if(hasSceneQuery) |
| 594 | shapeManager->setupSceneQuery(sqManager&: npScene->getSceneQueryManagerFast(), actor: *mActor, shape: *this); |
| 595 | else |
| 596 | shapeManager->teardownSceneQuery(sqManager&: npScene->getSceneQueryManagerFast(), shape: *this); |
| 597 | } |
| 598 | |
| 599 | // invalidate the pruning structure if the actor bounds changed |
| 600 | if(shapeManager->getPruningStructure()) |
| 601 | { |
| 602 | Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, messageFmt: "PxShape::setFlag: Shape is a part of pruning structure, pruning structure is now invalid!" ); |
| 603 | shapeManager->getPruningStructure()->invalidate(actor: mActor); |
| 604 | } |
| 605 | } |
| 606 | } |
| 607 | |
| 608 | void NpShape::setFlag(PxShapeFlag::Enum flag, bool value) |
| 609 | { |
| 610 | NP_WRITE_CHECK(getOwnerScene()); |
| 611 | PX_CHECK_AND_RETURN(isWritable(), "PxShape::setFlag: shared shapes attached to actors are not writable." ); |
| 612 | PX_SIMD_GUARD; |
| 613 | |
| 614 | PxShapeFlags shapeFlags = mShape.getFlags(); |
| 615 | shapeFlags = value ? shapeFlags | flag : shapeFlags & ~flag; |
| 616 | |
| 617 | setFlagsInternal(shapeFlags); |
| 618 | } |
| 619 | |
| 620 | void NpShape::setFlags(PxShapeFlags inFlags) |
| 621 | { |
| 622 | NP_WRITE_CHECK(getOwnerScene()); |
| 623 | PX_CHECK_AND_RETURN(isWritable(), "PxShape::setFlags: shared shapes attached to actors are not writable." ); |
| 624 | PX_SIMD_GUARD; |
| 625 | |
| 626 | setFlagsInternal(inFlags); |
| 627 | } |
| 628 | |
| 629 | PxShapeFlags NpShape::getFlags() const |
| 630 | { |
| 631 | NP_READ_CHECK(getOwnerScene()); |
| 632 | return mShape.getFlags(); |
| 633 | } |
| 634 | |
| 635 | bool NpShape::isExclusive() const |
| 636 | { |
| 637 | NP_READ_CHECK(getOwnerScene()); |
| 638 | return (mExclusiveAndActorCount & EXCLUSIVE_MASK) != 0; |
| 639 | } |
| 640 | |
| 641 | void NpShape::onActorAttach(PxRigidActor& actor) |
| 642 | { |
| 643 | incRefCount(); |
| 644 | if(isExclusiveFast()) |
| 645 | mActor = &actor; |
| 646 | Ps::atomicIncrement(val: &mExclusiveAndActorCount); |
| 647 | } |
| 648 | |
| 649 | void NpShape::onActorDetach() |
| 650 | { |
| 651 | PX_ASSERT(getActorCount() > 0); |
| 652 | Ps::atomicDecrement(val: &mExclusiveAndActorCount); |
| 653 | if(isExclusiveFast()) |
| 654 | mActor = NULL; |
| 655 | decRefCount(); |
| 656 | } |
| 657 | |
| 658 | void NpShape::setName(const char* debugName) |
| 659 | { |
| 660 | NP_WRITE_CHECK(getOwnerScene()); |
| 661 | PX_CHECK_AND_RETURN(isWritable(), "PxShape::setName: shared shapes attached to actors are not writable." ); |
| 662 | |
| 663 | mName = debugName; |
| 664 | |
| 665 | updatePvdProperties(shape: mShape); |
| 666 | } |
| 667 | |
| 668 | const char* NpShape::getName() const |
| 669 | { |
| 670 | NP_READ_CHECK(getOwnerScene()); |
| 671 | |
| 672 | return mName; |
| 673 | } |
| 674 | |
| 675 | NpScene* NpShape::getOwnerScene() const |
| 676 | { |
| 677 | return mActor ? NpActor::getOwnerScene(actor: *mActor) : NULL; |
| 678 | } |
| 679 | |
| 680 | NpScene* NpShape::getAPIScene() const |
| 681 | { |
| 682 | // gets called when we update SQ structures due to a write - in which case there must be an actor |
| 683 | PX_ASSERT(mActor); |
| 684 | return NpActor::getAPIScene(actor: *mActor); |
| 685 | } |
| 686 | |
| 687 | /////////////////////////////////////////////////////////////////////////////// |
| 688 | |
| 689 | namespace physx |
| 690 | { |
| 691 | Sc::RigidCore* NpShapeGetScRigidObjectFromScbSLOW(const Scb::Shape& scb) |
| 692 | { |
| 693 | const NpShape* np = getNpShape(scbShape: &scb); |
| 694 | return np->NpShape::getActor() ? &np->getScRigidObjectExclusive() : NULL; |
| 695 | } |
| 696 | |
| 697 | size_t NpShapeGetScPtrOffset() |
| 698 | { |
| 699 | return (NpShape::getScbShapeOffset() + Scb::Shape::getScOffset()); |
| 700 | } |
| 701 | |
| 702 | void NpShapeIncRefCount(Scb::Shape& scb) |
| 703 | { |
| 704 | NpShape* np = const_cast<NpShape*>(getNpShape(scbShape: &scb)); |
| 705 | np->incRefCount(); |
| 706 | } |
| 707 | |
| 708 | void NpShapeDecRefCount(Scb::Shape& scb) |
| 709 | { |
| 710 | NpShape* np = const_cast<NpShape*>(getNpShape(scbShape: &scb)); |
| 711 | np->decRefCount(); |
| 712 | } |
| 713 | } |
| 714 | |
| 715 | // see NpConvexMesh.h, NpHeightField.h, NpTriangleMesh.h for details on how ref counting works for meshes |
| 716 | Cm::RefCountable* NpShape::getMeshRefCountable() |
| 717 | { |
| 718 | switch(mShape.getGeometryType()) |
| 719 | { |
| 720 | case PxGeometryType::eCONVEXMESH: |
| 721 | return static_cast<Gu::ConvexMesh*>( |
| 722 | static_cast<const PxConvexMeshGeometry&>(mShape.getGeometry()).convexMesh); |
| 723 | |
| 724 | case PxGeometryType::eHEIGHTFIELD: |
| 725 | return static_cast<Gu::HeightField*>( |
| 726 | static_cast<const PxHeightFieldGeometry&>(mShape.getGeometry()).heightField); |
| 727 | |
| 728 | case PxGeometryType::eTRIANGLEMESH: |
| 729 | return static_cast<Gu::TriangleMesh*>( |
| 730 | static_cast<const PxTriangleMeshGeometry&>(mShape.getGeometry()).triangleMesh); |
| 731 | |
| 732 | case PxGeometryType::eSPHERE: |
| 733 | case PxGeometryType::ePLANE: |
| 734 | case PxGeometryType::eCAPSULE: |
| 735 | case PxGeometryType::eBOX: |
| 736 | case PxGeometryType::eGEOMETRY_COUNT: |
| 737 | case PxGeometryType::eINVALID: |
| 738 | break; |
| 739 | } |
| 740 | return NULL; |
| 741 | } |
| 742 | |
| 743 | bool NpShape::isWritable() |
| 744 | { |
| 745 | // 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.) |
| 746 | return isExclusiveFast() || (getRefCount()==1 && (mBaseFlags & PxBaseFlag::eIS_RELEASABLE)); |
| 747 | } |
| 748 | |
| 749 | void NpShape::incMeshRefCount() |
| 750 | { |
| 751 | Cm::RefCountable* npMesh = getMeshRefCountable(); |
| 752 | if(npMesh) |
| 753 | npMesh->incRefCount(); |
| 754 | } |
| 755 | |
| 756 | void NpShape::decMeshRefCount() |
| 757 | { |
| 758 | Cm::RefCountable* npMesh = getMeshRefCountable(); |
| 759 | if(npMesh) |
| 760 | npMesh->decRefCount(); |
| 761 | } |
| 762 | |
| 763 | bool NpShape::checkMaterialSetup(const PxGeometry& geom, const char* errorMsgPrefix, PxMaterial*const* materials, PxU16 materialCount) |
| 764 | { |
| 765 | for(PxU32 i=0; i<materialCount; ++i) |
| 766 | { |
| 767 | if(!materials[i]) |
| 768 | { |
| 769 | Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, |
| 770 | messageFmt: "material pointer %d is NULL!" , i); |
| 771 | return false; |
| 772 | } |
| 773 | } |
| 774 | |
| 775 | // check that simple shapes don't get assigned multiple materials |
| 776 | if (materialCount > 1 && (geom.getType() != PxGeometryType::eHEIGHTFIELD) && (geom.getType() != PxGeometryType::eTRIANGLEMESH)) |
| 777 | { |
| 778 | Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, |
| 779 | messageFmt: "%s: multiple materials defined for single material geometry!" , errorMsgPrefix); |
| 780 | return false; |
| 781 | } |
| 782 | |
| 783 | // verify we provide all materials required |
| 784 | if (materialCount > 1 && (geom.getType() == PxGeometryType::eTRIANGLEMESH)) |
| 785 | { |
| 786 | const PxTriangleMeshGeometry& meshGeom = static_cast<const PxTriangleMeshGeometry&>(geom); |
| 787 | const PxTriangleMesh& mesh = *meshGeom.triangleMesh; |
| 788 | if(mesh.getTriangleMaterialIndex(triangleIndex: 0) != 0xffff) |
| 789 | { |
| 790 | for(PxU32 i = 0; i < mesh.getNbTriangles(); i++) |
| 791 | { |
| 792 | const PxMaterialTableIndex meshMaterialIndex = mesh.getTriangleMaterialIndex(triangleIndex: i); |
| 793 | if(meshMaterialIndex >= materialCount) |
| 794 | { |
| 795 | Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, |
| 796 | messageFmt: "%s: PxTriangleMesh material indices reference more materials than provided!" , errorMsgPrefix); |
| 797 | break; |
| 798 | } |
| 799 | } |
| 800 | } |
| 801 | } |
| 802 | if (materialCount > 1 && (geom.getType() == PxGeometryType::eHEIGHTFIELD)) |
| 803 | { |
| 804 | const PxHeightFieldGeometry& meshGeom = static_cast<const PxHeightFieldGeometry&>(geom); |
| 805 | const PxHeightField& mesh = *meshGeom.heightField; |
| 806 | if(mesh.getTriangleMaterialIndex(triangleIndex: 0) != 0xffff) |
| 807 | { |
| 808 | const PxU32 nbTris = mesh.getNbColumns()*mesh.getNbRows()*2; |
| 809 | for(PxU32 i = 0; i < nbTris; i++) |
| 810 | { |
| 811 | const PxMaterialTableIndex meshMaterialIndex = mesh.getTriangleMaterialIndex(triangleIndex: i); |
| 812 | if(meshMaterialIndex != PxHeightFieldMaterial::eHOLE && meshMaterialIndex >= materialCount) |
| 813 | { |
| 814 | Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, |
| 815 | messageFmt: "%s: PxHeightField material indices reference more materials than provided!" , errorMsgPrefix); |
| 816 | break; |
| 817 | } |
| 818 | } |
| 819 | } |
| 820 | } |
| 821 | |
| 822 | return true; |
| 823 | } |
| 824 | |
| 825 | /////////////////////////////////////////////////////////////////////////////// |
| 826 | |