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 | |