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
36using namespace physx;
37using namespace Sq;
38
39static 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
50NpShape::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
64NpShape::~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
76void 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
85NpShape::NpShape(PxBaseFlags baseFlags) : PxShape(baseFlags), mShape(PxEmpty) {}
86
87void NpShape::preExportDataReset()
88{
89 Cm::RefCountable::preExportDataReset();
90 mExclusiveAndActorCount &= EXCLUSIVE_MASK;
91}
92
93void NpShape::exportExtraData(PxSerializationContext& context)
94{
95 getScbShape().getScShape().exportExtraData(stream&: context);
96 context.writeName(name: mName);
97}
98
99void NpShape::importExtraData(PxDeserializationContext& context)
100{
101 getScbShape().getScShape().importExtraData(context);
102 context.readName(name&: mName);
103}
104
105void 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
141void 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
176NpShape* 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
186PxU32 NpShape::getReferenceCount() const
187{
188 return getRefCount();
189}
190
191void NpShape::acquireReference()
192{
193 incRefCount();
194}
195
196void 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
203void NpShape::releaseInternal()
204{
205 decRefCount();
206}
207
208Sc::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
220void 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
242PxGeometryType::Enum NpShape::getGeometryType() const
243{
244 NP_READ_CHECK(getOwnerScene());
245
246 return mShape.getGeometryType();
247}
248
249void 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
315PxGeometryHolder NpShape::getGeometry() const
316{
317 PX_COMPILE_TIME_ASSERT(sizeof(Gu::GeometryUnion)>=sizeof(PxGeometryHolder));
318 return reinterpret_cast<const PxGeometryHolder&>(mShape.getGeometry());
319}
320
321template<class T>
322static 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
333bool NpShape::getBoxGeometry(PxBoxGeometry& g) const { return getGeometryT(npShape: this, type: PxGeometryType::eBOX, geom&: g); }
334bool NpShape::getSphereGeometry(PxSphereGeometry& g) const { return getGeometryT(npShape: this, type: PxGeometryType::eSPHERE, geom&: g); }
335bool NpShape::getCapsuleGeometry(PxCapsuleGeometry& g) const { return getGeometryT(npShape: this, type: PxGeometryType::eCAPSULE, geom&: g); }
336bool NpShape::getPlaneGeometry(PxPlaneGeometry& g) const { return getGeometryT(npShape: this, type: PxGeometryType::ePLANE, geom&: g); }
337bool NpShape::getConvexMeshGeometry(PxConvexMeshGeometry& g) const { return getGeometryT(npShape: this, type: PxGeometryType::eCONVEXMESH, geom&: g); }
338bool NpShape::getTriangleMeshGeometry(PxTriangleMeshGeometry& g) const { return getGeometryT(npShape: this, type: PxGeometryType::eTRIANGLEMESH, geom&: g); }
339bool NpShape::getHeightFieldGeometry(PxHeightFieldGeometry& g) const { return getGeometryT(npShape: this, type: PxGeometryType::eHEIGHTFIELD, geom&: g); }
340
341PxRigidActor* NpShape::getActor() const
342{
343 NP_READ_CHECK(getOwnerScene());
344 return mActor;
345}
346
347void 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
358PxTransform NpShape::getLocalPose() const
359{
360 NP_READ_CHECK(getOwnerScene());
361
362 return mShape.getShape2Actor();
363}
364
365///////////////////////////////////////////////////////////////////////////////
366
367void 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
374PxFilterData NpShape::getSimulationFilterData() const
375{
376 NP_READ_CHECK(getOwnerScene());
377 return mShape.getSimulationFilterData();
378}
379
380void 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
390PxFilterData NpShape::getQueryFilterData() const
391{
392 NP_READ_CHECK(getOwnerScene());
393
394 return getQueryFilterDataFast();
395}
396
397///////////////////////////////////////////////////////////////////////////////
398
399void 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
425PxU16 NpShape::getNbMaterials() const
426{
427 NP_READ_CHECK(getOwnerScene());
428
429 return mShape.getNbMaterials();
430}
431
432PxU32 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
439PxMaterial* 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
474void 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
485PxReal NpShape::getContactOffset() const
486{
487 NP_READ_CHECK(getOwnerScene());
488
489 return mShape.getContactOffset();
490}
491
492void 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
502PxReal NpShape::getRestOffset() const
503{
504 NP_READ_CHECK(getOwnerScene());
505
506 return mShape.getRestOffset();
507}
508
509void 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
518PxReal NpShape::getTorsionalPatchRadius() const
519{
520 NP_READ_CHECK(getOwnerScene());
521 return mShape.getTorsionalPatchRadius();
522}
523
524void 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
533PxReal NpShape::getMinTorsionalPatchRadius() const
534{
535 NP_READ_CHECK(getOwnerScene());
536 return mShape.getMinTorsionalPatchRadius();
537}
538
539void 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
608void 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
620void 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
629PxShapeFlags NpShape::getFlags() const
630{
631 NP_READ_CHECK(getOwnerScene());
632 return mShape.getFlags();
633}
634
635bool NpShape::isExclusive() const
636{
637 NP_READ_CHECK(getOwnerScene());
638 return (mExclusiveAndActorCount & EXCLUSIVE_MASK) != 0;
639}
640
641void NpShape::onActorAttach(PxRigidActor& actor)
642{
643 incRefCount();
644 if(isExclusiveFast())
645 mActor = &actor;
646 Ps::atomicIncrement(val: &mExclusiveAndActorCount);
647}
648
649void NpShape::onActorDetach()
650{
651 PX_ASSERT(getActorCount() > 0);
652 Ps::atomicDecrement(val: &mExclusiveAndActorCount);
653 if(isExclusiveFast())
654 mActor = NULL;
655 decRefCount();
656}
657
658void 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
668const char* NpShape::getName() const
669{
670 NP_READ_CHECK(getOwnerScene());
671
672 return mName;
673}
674
675NpScene* NpShape::getOwnerScene() const
676{
677 return mActor ? NpActor::getOwnerScene(actor: *mActor) : NULL;
678}
679
680NpScene* 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
689namespace physx
690{
691Sc::RigidCore* NpShapeGetScRigidObjectFromScbSLOW(const Scb::Shape& scb)
692{
693 const NpShape* np = getNpShape(scbShape: &scb);
694 return np->NpShape::getActor() ? &np->getScRigidObjectExclusive() : NULL;
695}
696
697size_t NpShapeGetScPtrOffset()
698{
699 return (NpShape::getScbShapeOffset() + Scb::Shape::getScOffset());
700}
701
702void NpShapeIncRefCount(Scb::Shape& scb)
703{
704 NpShape* np = const_cast<NpShape*>(getNpShape(scbShape: &scb));
705 np->incRefCount();
706}
707
708void 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
716Cm::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
743bool 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
749void NpShape::incMeshRefCount()
750{
751 Cm::RefCountable* npMesh = getMeshRefCountable();
752 if(npMesh)
753 npMesh->incRefCount();
754}
755
756void NpShape::decMeshRefCount()
757{
758 Cm::RefCountable* npMesh = getMeshRefCountable();
759 if(npMesh)
760 npMesh->decRefCount();
761}
762
763bool 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

source code of qtquick3dphysics/src/3rdparty/PhysX/source/physx/src/NpShape.cpp