RavEngine
Loading...
Searching...
No Matches
PxsIslandSim.h
1// Redistribution and use in source and binary forms, with or without
2// modification, are permitted provided that the following conditions
3// are met:
4// * Redistributions of source code must retain the above copyright
5// notice, this list of conditions and the following disclaimer.
6// * Redistributions in binary form must reproduce the above copyright
7// notice, this list of conditions and the following disclaimer in the
8// documentation and/or other materials provided with the distribution.
9// * Neither the name of NVIDIA CORPORATION nor the names of its
10// contributors may be used to endorse or promote products derived
11// from this software without specific prior written permission.
12//
13// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
14// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24//
25// Copyright (c) 2008-2022 NVIDIA Corporation. All rights reserved.
26// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
27// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
28
29#ifndef PXS_ISLAND_SIM_H
30#define PXS_ISLAND_SIM_H
31
32#include "foundation/PxAssert.h"
33#include "foundation/PxBitMap.h"
34#include "foundation/PxArray.h"
35#include "CmPriorityQueue.h"
36#include "CmBlockArray.h"
37#include "PxNodeIndex.h"
38
39namespace physx
40{
41
42namespace Dy
43{
44 struct Constraint;
45 class FeatherstoneArticulation;
46#if PX_SUPPORT_GPU_PHYSX
47 class SoftBody;
48 class FEMCloth;
49 class ParticleSystem;
50 class HairSystem;
51#endif
52}
53
54namespace Sc
55{
56 class ArticulationSim;
57}
58
59class PxsContactManager;
60class PxsRigidBody;
61
62struct PartitionEdge;
63
64namespace IG
65{
66
67//This index is
68#define IG_INVALID_ISLAND 0xFFFFFFFFu
69#define IG_INVALID_EDGE 0xFFFFFFFFu
70#define IG_INVALID_LINK 0xFFu
71
72
73typedef PxU32 IslandId;
74typedef PxU32 EdgeIndex;
75typedef PxU32 EdgeInstanceIndex;
76
77class IslandSim;
78
79struct Edge
80{
81 //Edge instances can be implicitly calculated based on this edge index, which is an offset into the array of edges.
82 //From that, the child edge index is simply the
83 //The constraint or contact referenced by this edge
84
85 enum EdgeType
86 {
87 eCONTACT_MANAGER,
88 eCONSTRAINT,
89 eSOFT_BODY_CONTACT,
90 eFEM_CLOTH_CONTACT,
91 ePARTICLE_SYSTEM_CONTACT,
92 eHAIR_SYSTEM_CONTACT,
93 eEDGE_TYPE_COUNT
94 };
95
96
97 enum EdgeState
98 {
99 eINSERTED =1<<0,
100 ePENDING_DESTROYED =1<<1,
101 eACTIVE =1<<2,
102 eIN_DIRTY_LIST =1<<3,
103 eDESTROYED =1<<4,
104 eREPORT_ONLY_DESTROY=1<<5,
105 eACTIVATING =1<<6
106 };
107
108
109 //NodeIndex mNode1, mNode2;
110 EdgeType mEdgeType;
111 PxU16 mEdgeState;
112
113 EdgeIndex mNextIslandEdge, mPrevIslandEdge;
114
115
116
117 PX_FORCE_INLINE void setInserted() { mEdgeState |= (eINSERTED); }
118
119 PX_FORCE_INLINE void clearInserted() { mEdgeState &= (~eINSERTED); }
120
121 PX_FORCE_INLINE void clearDestroyed() { mEdgeState &=(~eDESTROYED);}
122 PX_FORCE_INLINE void setPendingDestroyed() { mEdgeState |= ePENDING_DESTROYED; }
123 PX_FORCE_INLINE void clearPendingDestroyed() { mEdgeState &= (~ePENDING_DESTROYED); }
124 PX_FORCE_INLINE void activateEdge() { mEdgeState |= eACTIVE; }
125 PX_FORCE_INLINE void deactivateEdge() { mEdgeState &= (~eACTIVE); }
126 PX_FORCE_INLINE void markInDirtyList() { mEdgeState |= (eIN_DIRTY_LIST); }
127 PX_FORCE_INLINE void clearInDirtyList() { mEdgeState &= (~eIN_DIRTY_LIST); }
128 PX_FORCE_INLINE void setReportOnlyDestroy() { mEdgeState |= (eREPORT_ONLY_DESTROY); }
129 PX_FORCE_INLINE void clearReportOnlyDestroy() { mEdgeState &= (~eREPORT_ONLY_DESTROY); }
130public:
131 Edge() : mEdgeType(Edge::eCONTACT_MANAGER), mEdgeState(eDESTROYED),
132 mNextIslandEdge(IG_INVALID_EDGE), mPrevIslandEdge(IG_INVALID_EDGE)
133 {
134 }
135 PX_FORCE_INLINE bool isInserted() const { return !!(mEdgeState & eINSERTED);}
136 PX_FORCE_INLINE bool isDestroyed() const { return !!(mEdgeState & eDESTROYED); }
137 PX_FORCE_INLINE bool isPendingDestroyed() const { return !!(mEdgeState & ePENDING_DESTROYED); }
138 PX_FORCE_INLINE bool isActive() const { return !!(mEdgeState & eACTIVE); }
139 PX_FORCE_INLINE bool isInDirtyList() const { return !!(mEdgeState & eIN_DIRTY_LIST); }
140 PX_FORCE_INLINE EdgeType getEdgeType() const { return mEdgeType; }
141 //PX_FORCE_INLINE const NodeIndex getIndex1() const { return mNode1; }
142 //PX_FORCE_INLINE const NodeIndex getIndex2() const { return mNode2; }
143 PX_FORCE_INLINE bool isReportOnlyDestroy() { return !!(mEdgeState & eREPORT_ONLY_DESTROY); }
144};
145
147{
148 EdgeInstanceIndex mNextEdge, mPrevEdge; //The next edge instance in this node's list of edge instances
149
150 EdgeInstance() : mNextEdge(IG_INVALID_EDGE), mPrevEdge(IG_INVALID_EDGE)
151 {
152 }
153};
154
155template<typename Handle>
157{
158 PxArray<Handle> mFreeHandles;
159 Handle mCurrentHandle;
160
161public:
162
163 HandleManager() : mFreeHandles("FreeHandles"), mCurrentHandle(0)
164 {
165 }
166
168
169 Handle getHandle()
170 {
171 if(mFreeHandles.size())
172 {
173 Handle handle = mFreeHandles.popBack();
174 PX_ASSERT(isValidHandle(handle));
175 return handle;
176 }
177 return mCurrentHandle++;
178 }
179
180 bool isNotFreeHandle(Handle handle)
181 {
182 for(PxU32 a = 0; a < mFreeHandles.size(); ++a)
183 {
184 if(mFreeHandles[a] == handle)
185 return false;
186 }
187 return true;
188 }
189
190 void freeHandle(Handle handle)
191 {
192 PX_ASSERT(isValidHandle(handle));
193 PX_ASSERT(isNotFreeHandle(handle));
194 if(handle == mCurrentHandle)
195 mCurrentHandle--;
196 else
197 mFreeHandles.pushBack(handle);
198 }
199
200 bool isValidHandle(Handle handle)
201 {
202 return handle < mCurrentHandle;
203 }
204
205 PX_FORCE_INLINE PxU32 getTotalHandles() const { return mCurrentHandle; }
206};
207
208class Node
209{
210
211public:
212 enum NodeType
213 {
214 eRIGID_BODY_TYPE,
215 eARTICULATION_TYPE,
216 eSOFTBODY_TYPE,
217 eFEMCLOTH_TYPE,
218 ePARTICLESYSTEM_TYPE,
219 eHAIRSYSTEM_TYPE,
220 eTYPE_COUNT
221 };
222 enum State
223 {
224 eREADY_FOR_SLEEPING = 1u << 0,
225 eACTIVE = 1u << 1,
226 eKINEMATIC = 1u << 2,
227 eDELETED = 1u << 3,
228 eDIRTY = 1u << 4,
229 eACTIVATING = 1u << 5,
230 eDEACTIVATING = 1u << 6
231 };
232 EdgeInstanceIndex mFirstEdgeIndex;
233
234 PxU8 mFlags;
235 PxU8 mType;
236 PxU16 mStaticTouchCount;
237 //PxU32 mActiveNodeIndex; //! Look-up for this node in the active nodes list, activating list or deactivating list...
238
239 PxNodeIndex mNextNode, mPrevNode;
240
241 //A counter for the number of active references to this body. Whenever an edge is activated, this is incremented.
242 //Whenver an edge is deactivated, this is decremented. This is used for kinematic bodies to determine if they need
243 //to be in the active kinematics list
244 PxU32 mActiveRefCount;
245
246
247 //A node can correspond with either a rigid body or an articulation or softBody
248 union
249 {
250 PxsRigidBody* mRigidBody;
251 Dy::FeatherstoneArticulation* mLLArticulation;
252#if PX_SUPPORT_GPU_PHYSX
253 Dy::SoftBody* mLLSoftBody;
254 Dy::FEMCloth* mLLFEMCloth;
255 Dy::ParticleSystem* mLLParticleSystem;
256 Dy::HairSystem* mLLHairSystem;
257#endif
258 };
259
260
261
262 PX_FORCE_INLINE Node() : mFirstEdgeIndex(IG_INVALID_EDGE), mFlags(eDELETED), mType(eRIGID_BODY_TYPE),
263 mStaticTouchCount(0), mActiveRefCount(0), mRigidBody(NULL)
264 {
265 }
266
267 PX_FORCE_INLINE ~Node() {}
268
269 PX_FORCE_INLINE void reset()
270 {
271 mFirstEdgeIndex = IG_INVALID_EDGE;
272 mFlags = eDELETED;
273 mRigidBody = NULL;
274 mActiveRefCount = 0;
275 mStaticTouchCount = 0;
276 }
277
278 PX_FORCE_INLINE void setRigidBody(PxsRigidBody* body) { mRigidBody = body; }
279
280 PX_FORCE_INLINE PxsRigidBody* getRigidBody() const { return mRigidBody; }
281
282 PX_FORCE_INLINE Dy::FeatherstoneArticulation* getArticulation() const { return mLLArticulation; }
283
284#if PX_SUPPORT_GPU_PHYSX
285 PX_FORCE_INLINE Dy::SoftBody* getSoftBody() const { return mLLSoftBody; }
286 PX_FORCE_INLINE Dy::FEMCloth* getFEMCloth() const { return mLLFEMCloth; }
287 PX_FORCE_INLINE Dy::HairSystem* getHairSystem() const { return mLLHairSystem; }
288#endif
289
290 PX_FORCE_INLINE void setActive() { mFlags |= eACTIVE; }
291 PX_FORCE_INLINE void clearActive() { mFlags &= ~eACTIVE; }
292
293 PX_FORCE_INLINE void setActivating() { mFlags |= eACTIVATING; }
294 PX_FORCE_INLINE void clearActivating() { mFlags &= ~eACTIVATING; }
295
296 PX_FORCE_INLINE void setDeactivating() { mFlags |= eDEACTIVATING; }
297 PX_FORCE_INLINE void clearDeactivating() { mFlags &= (~eDEACTIVATING); }
298
299
300 //Activates a body/node.
301 PX_FORCE_INLINE void setIsReadyForSleeping() { mFlags |= eREADY_FOR_SLEEPING; }
302
303 PX_FORCE_INLINE void clearIsReadyForSleeping(){ mFlags &= (~eREADY_FOR_SLEEPING);}
304
305 PX_FORCE_INLINE void setIsDeleted(){mFlags |= eDELETED; }
306
307 PX_FORCE_INLINE void setKinematicFlag() {PX_ASSERT(!isKinematic()); mFlags |= eKINEMATIC;}
308
309 PX_FORCE_INLINE void clearKinematicFlag(){ PX_ASSERT(isKinematic()); mFlags &= (~eKINEMATIC);}
310
311 PX_FORCE_INLINE void markDirty(){mFlags |= eDIRTY;}
312
313 PX_FORCE_INLINE void clearDirty(){mFlags &= (~eDIRTY);}
314
315public:
316
317 PX_FORCE_INLINE bool isActive() const { return !!(mFlags & eACTIVE); }
318
319 PX_FORCE_INLINE bool isActiveOrActivating() const { return !!(mFlags & (eACTIVE | eACTIVATING)); }
320
321 PX_FORCE_INLINE bool isActivating() const { return !!(mFlags & eACTIVATING); }
322
323 PX_FORCE_INLINE bool isDeactivating() const { return !!(mFlags & eDEACTIVATING); }
324
325 PX_FORCE_INLINE bool isKinematic() const { return !!(mFlags & eKINEMATIC); }
326
327 PX_FORCE_INLINE bool isDeleted() const { return !!(mFlags & eDELETED); }
328
329 PX_FORCE_INLINE bool isDirty() const { return !!(mFlags & eDIRTY); }
330
331 PX_FORCE_INLINE bool isReadyForSleeping() const { return !!(mFlags & eREADY_FOR_SLEEPING); }
332
333 PX_FORCE_INLINE NodeType getNodeType() const { return NodeType(mType); }
334
335 friend class SimpleIslandManager;
336
337};
338
339struct Island
340{
341 PxNodeIndex mRootNode;
342 PxNodeIndex mLastNode;
343 PxU32 mSize[Node::eTYPE_COUNT];
344 PxU32 mActiveIndex;
345
346 EdgeIndex mFirstEdge[Edge::eEDGE_TYPE_COUNT], mLastEdge[Edge::eEDGE_TYPE_COUNT];
347 PxU32 mEdgeCount[Edge::eEDGE_TYPE_COUNT];
348
349 Island() : mActiveIndex(IG_INVALID_ISLAND)
350 {
351 for(PxU32 a = 0; a < Edge::eEDGE_TYPE_COUNT; ++a)
352 {
353 mFirstEdge[a] = IG_INVALID_EDGE;
354 mLastEdge[a] = IG_INVALID_EDGE;
355 mEdgeCount[a] = 0;
356 }
357
358 for(PxU32 a = 0; a < Node::eTYPE_COUNT; ++a)
359 {
360 mSize[a] = 0;
361 }
362 }
363};
364
366{
367 PxNodeIndex mNodeIndex;
368 PxU32 mCurrentIndex;
369 PxU32 mPrevIndex;
370 PxU32 mDepth;
371
373 {
374 }
375
376 TraversalState(PxNodeIndex nodeIndex, PxU32 currentIndex, PxU32 prevIndex, PxU32 depth) :
377 mNodeIndex(nodeIndex), mCurrentIndex(currentIndex), mPrevIndex(prevIndex), mDepth(depth)
378 {
379 }
380};
381
383{
384 TraversalState* mState;
385 PxU32 mHopCount;
386
388 {
389 }
390
391 QueueElement(TraversalState* state, PxU32 hopCount) : mState(state), mHopCount(hopCount)
392 {
393 }
394};
395
397{
399 {
400 }
401
402 bool operator() (const QueueElement& node0, const QueueElement& node1) const
403 {
404 return node0.mHopCount < node1.mHopCount;
405 }
406private:
407 NodeComparator& operator = (const NodeComparator&);
408};
409
410
412{
413 HandleManager<IslandId> mIslandHandles;
414
415 PxArray<Node> mNodes;
416 PxArray<PxU32> mActiveNodeIndex;
418 Cm::BlockArray<EdgeInstance> mEdgeInstances;
419 PxArray<Island> mIslands;
420 PxArray<PxU32> mIslandStaticTouchCount;
421
422
423 PxArray<PxNodeIndex> mActiveNodes[Node::eTYPE_COUNT];
424 PxArray<PxNodeIndex> mActiveKinematicNodes;
425 PxArray<EdgeIndex> mActivatedEdges[Edge::eEDGE_TYPE_COUNT];
426
427 PxU32 mActiveEdgeCount[Edge::eEDGE_TYPE_COUNT];
428
429 PxArray<PxU32> mHopCounts;
430 PxArray<PxNodeIndex> mFastRoute;
431
432 PxArray<IslandId> mIslandIds;
433
434 PxBitMap mIslandAwake;
435
436 PxBitMap mActiveContactEdges;
437
438 //An array of active islands
439 PxArray<IslandId> mActiveIslands;
440
441 PxU32 mInitialActiveNodeCount[Edge::eEDGE_TYPE_COUNT];
442
443 PxArray<PxNodeIndex> mNodesToPutToSleep[Node::eTYPE_COUNT];
444
445 //Input to this frame's island management (changed nodes/edges)
446
447 //Input list of changes observed this frame. If there no changes, no work to be done.
448 PxArray<EdgeIndex> mDirtyEdges[Edge::eEDGE_TYPE_COUNT];
449 //Dirty nodes. These nodes lost at least one connection so we need to recompute islands from these nodes
450 //PxArray<NodeIndex> mDirtyNodes;
451 PxBitMap mDirtyMap;
452 PxU32 mLastMapIndex;
453
454 //An array of nodes to activate
455 PxArray<PxNodeIndex> mActivatingNodes;
456 PxArray<EdgeIndex> mDestroyedEdges;
457 PxArray<IslandId> mTempIslandIds;
458
459
460 //Temporary, transient data used for traversals. TODO - move to PxsSimpleIslandManager. Or if we keep it here, we can
461 //process multiple island simulations in parallel
463 mPriorityQueue;
464 PxArray<TraversalState> mVisitedNodes;
465 PxBitMap mVisitedState;
466 PxArray<EdgeIndex> mIslandSplitEdges[Edge::eEDGE_TYPE_COUNT];
467
468 PxArray<EdgeIndex> mDeactivatingEdges[Edge::eEDGE_TYPE_COUNT];
469
470 PxArray<PartitionEdge*>* mFirstPartitionEdges;
471 Cm::BlockArray<PxNodeIndex>& mEdgeNodeIndices;
472 PxArray<physx::PartitionEdge*>* mDestroyedPartitionEdges;
473
474 PxU32* mNpIndexPtr;
475
476 PxU64 mContextId;
477
478public:
479
480 IslandSim(PxArray<PartitionEdge*>* firstPartitionEdges, Cm::BlockArray<PxNodeIndex>& edgeNodeIndices, PxArray<PartitionEdge*>* destroyedPartitionEdges, PxU64 contextID);
481 ~IslandSim() {}
482
483 void resize(const PxU32 nbNodes, const PxU32 nbContactManagers, const PxU32 nbConstraints);
484
485 void addRigidBody(PxsRigidBody* body, bool isKinematic, bool isActive, PxNodeIndex nodeIndex);
486
487 void addArticulation(Sc::ArticulationSim* articulation, Dy::FeatherstoneArticulation* llArtic, bool isActive, PxNodeIndex nodeIndex);
488
489#if PX_SUPPORT_GPU_PHYSX
490 void addSoftBody(Dy::SoftBody* llArtic, bool isActive, PxNodeIndex nodeIndex);
491
492 void addFEMCloth(Dy::FEMCloth* llArtic, bool isActive, PxNodeIndex nodeIndex);
493
494 void addParticleSystem(Dy::ParticleSystem* llArtic, bool isActive, PxNodeIndex nodeIndex);
495
496 void addHairSystem(Dy::HairSystem* llHairSystem, bool isActive, PxNodeIndex nodeIndex);
497#endif
498
499 void addContactManager(PxsContactManager* manager, PxNodeIndex nodeHandle1, PxNodeIndex nodeHandle2, EdgeIndex handle);
500
501 void addConstraint(Dy::Constraint* constraint, PxNodeIndex nodeHandle1, PxNodeIndex nodeHandle2, EdgeIndex handle);
502
503 void activateNode(PxNodeIndex index);
504 void deactivateNode(PxNodeIndex index);
505 void putNodeToSleep(PxNodeIndex index);
506
507 void removeConnection(EdgeIndex edgeIndex);
508
509 PX_FORCE_INLINE PxU32 getNbNodes() const { return mNodes.size(); }
510
511 PX_FORCE_INLINE PxU32 getNbActiveNodes(Node::NodeType type) const { return mActiveNodes[type].size(); }
512
513 PX_FORCE_INLINE const PxNodeIndex* getActiveNodes(Node::NodeType type) const { return mActiveNodes[type].begin(); }
514
515 PX_FORCE_INLINE PxU32 getNbActiveKinematics() const { return mActiveKinematicNodes.size(); }
516
517 PX_FORCE_INLINE const PxNodeIndex* getActiveKinematics() const { return mActiveKinematicNodes.begin(); }
518
519 PX_FORCE_INLINE PxU32 getNbNodesToActivate(Node::NodeType type) const { return mActiveNodes[type].size() - mInitialActiveNodeCount[type]; }
520
521 PX_FORCE_INLINE const PxNodeIndex* getNodesToActivate(Node::NodeType type) const { return mActiveNodes[type].begin() + mInitialActiveNodeCount[type]; }
522
523 PX_FORCE_INLINE PxU32 getNbNodesToDeactivate(Node::NodeType type) const { return mNodesToPutToSleep[type].size(); }
524
525 PX_FORCE_INLINE const PxNodeIndex* getNodesToDeactivate(Node::NodeType type) const { return mNodesToPutToSleep[type].begin(); }
526
527 PX_FORCE_INLINE PxU32 getNbActivatedEdges(Edge::EdgeType type) const { return mActivatedEdges[type].size(); }
528
529 PX_FORCE_INLINE const EdgeIndex* getActivatedEdges(Edge::EdgeType type) const { return mActivatedEdges[type].begin(); }
530
531 PX_FORCE_INLINE PxU32 getNbActiveEdges(Edge::EdgeType type) const { return mActiveEdgeCount[type]; }
532
533 PX_FORCE_INLINE PartitionEdge* getFirstPartitionEdge(IG::EdgeIndex edgeIndex) const { return (*mFirstPartitionEdges)[edgeIndex]; }
534 PX_FORCE_INLINE void setFirstPartitionEdge(IG::EdgeIndex edgeIndex, PartitionEdge* partitionEdge) { (*mFirstPartitionEdges)[edgeIndex] = partitionEdge; }
535
536 //PX_FORCE_INLINE const EdgeIndex* getActiveEdges(Edge::EdgeType type) const { return mActiveEdges[type].begin(); }
537
538 PX_FORCE_INLINE PxsRigidBody* getRigidBody(PxNodeIndex nodeIndex) const
539 {
540 const Node& node = mNodes[nodeIndex.index()];
541 PX_ASSERT(node.mType == Node::eRIGID_BODY_TYPE);
542 return node.mRigidBody;
543 }
544
545 PX_FORCE_INLINE Dy::FeatherstoneArticulation* getLLArticulation(PxNodeIndex nodeIndex) const
546 {
547 const Node& node = mNodes[nodeIndex.index()];
548 PX_ASSERT(node.mType == Node::eARTICULATION_TYPE);
549 return node.mLLArticulation;
550 }
551
552 Sc::ArticulationSim* getArticulationSim(PxNodeIndex nodeIndex) const;
553
554#if PX_SUPPORT_GPU_PHYSX
555 PX_FORCE_INLINE Dy::SoftBody* getLLSoftBody(PxNodeIndex nodeIndex) const
556 {
557 const Node& node = mNodes[nodeIndex.index()];
558 PX_ASSERT(node.mType == Node::eSOFTBODY_TYPE);
559 return node.mLLSoftBody;
560 }
561
562 PX_FORCE_INLINE Dy::FEMCloth* getLLFEMCloth(PxNodeIndex nodeIndex) const
563 {
564 const Node& node = mNodes[nodeIndex.index()];
565 PX_ASSERT(node.mType == Node::eFEMCLOTH_TYPE);
566 return node.mLLFEMCloth;
567 }
568
569 PX_FORCE_INLINE Dy::HairSystem* getLLHairSystem(PxNodeIndex nodeIndex) const
570 {
571 const Node& node = mNodes[nodeIndex.index()];
572 PX_ASSERT(node.mType == Node::eHAIRSYSTEM_TYPE);
573 return node.mLLHairSystem;
574 }
575#endif
576
577 PX_FORCE_INLINE void clearDeactivations()
578 {
579 for (PxU32 i = 0; i < Node::eTYPE_COUNT; ++i)
580 {
581 mNodesToPutToSleep[i].forceSize_Unsafe(0);
582 mDeactivatingEdges[i].forceSize_Unsafe(0);
583 }
584 }
585
586 PX_FORCE_INLINE const Island& getIsland(IG::IslandId islandIndex) const { return mIslands[islandIndex]; }
587
588 PX_FORCE_INLINE PxU32 getNbActiveIslands() const { return mActiveIslands.size(); }
589 PX_FORCE_INLINE const IslandId* getActiveIslands() const { return mActiveIslands.begin(); }
590
591 PX_FORCE_INLINE PxU32 getNbDeactivatingEdges(const IG::Edge::EdgeType edgeType) const { return mDeactivatingEdges[edgeType].size(); }
592 PX_FORCE_INLINE const EdgeIndex* getDeactivatingEdges(const IG::Edge::EdgeType edgeType) const { return mDeactivatingEdges[edgeType].begin(); }
593
594 PX_FORCE_INLINE PxU32 getNbDestroyedEdges() const { return mDestroyedEdges.size(); }
595 PX_FORCE_INLINE const EdgeIndex* getDestroyedEdges() const { return mDestroyedEdges.begin(); }
596
597 PX_FORCE_INLINE PxU32 getNbDestroyedPartitionEdges() const { return mDestroyedPartitionEdges->size(); }
598 PX_FORCE_INLINE const PartitionEdge*const * getDestroyedPartitionEdges() const { return mDestroyedPartitionEdges->begin(); }
599 PX_FORCE_INLINE PartitionEdge** getDestroyedPartitionEdges() { return mDestroyedPartitionEdges->begin(); }
600
601 PX_FORCE_INLINE PxU32 getNbDirtyEdges(IG::Edge::EdgeType type) const { return mDirtyEdges[type].size(); }
602 PX_FORCE_INLINE const EdgeIndex* getDirtyEdges(IG::Edge::EdgeType type) const { return mDirtyEdges[type].begin(); }
603
604 PX_FORCE_INLINE const Edge& getEdge(const EdgeIndex edgeIndex) const { return mEdges[edgeIndex]; }
605
606 PX_FORCE_INLINE Edge& getEdge(const EdgeIndex edgeIndex) { return mEdges[edgeIndex]; }
607
608 PX_FORCE_INLINE const Node& getNode(const PxNodeIndex& nodeIndex) const { return mNodes[nodeIndex.index()]; }
609
610 PX_FORCE_INLINE const Island& getIsland(const PxNodeIndex& nodeIndex) const { PX_ASSERT(mIslandIds[nodeIndex.index()] != IG_INVALID_ISLAND); return mIslands[mIslandIds[nodeIndex.index()]]; }
611
612 PX_FORCE_INLINE PxU32 getIslandStaticTouchCount(const PxNodeIndex& nodeIndex) const { PX_ASSERT(mIslandIds[nodeIndex.index()] != IG_INVALID_ISLAND); return mIslandStaticTouchCount[mIslandIds[nodeIndex.index()]]; }
613
614 PX_FORCE_INLINE const PxBitMap& getActiveContactManagerBitmap() const { return mActiveContactEdges; }
615
616 PX_FORCE_INLINE PxU32 getActiveNodeIndex(const PxNodeIndex& nodeIndex) const { PxU32 activeNodeIndex = mActiveNodeIndex[nodeIndex.index()]; return activeNodeIndex;}
617
618 PX_FORCE_INLINE const PxU32* getActiveNodeIndex() const { return mActiveNodeIndex.begin(); }
619
620 PX_FORCE_INLINE PxU32 getNbActiveNodeIndex() const { return mActiveNodeIndex.size(); }
621
622 void setKinematic(PxNodeIndex nodeIndex);
623
624 void setDynamic(PxNodeIndex nodeIndex);
625
626 PX_FORCE_INLINE void setEdgeNodeIndexPtr(PxU32* ptr) { mNpIndexPtr = ptr; }
627
628 PX_FORCE_INLINE PxNodeIndex getNodeIndex1(IG::EdgeIndex index) const { return mEdgeNodeIndices[2 * index]; }
629 PX_FORCE_INLINE PxNodeIndex getNodeIndex2(IG::EdgeIndex index) const { return mEdgeNodeIndices[2 * index + 1]; }
630
631 PX_FORCE_INLINE PxU32* getEdgeNodeIndexPtr() const { return mNpIndexPtr; }
632 PX_FORCE_INLINE PxU64 getContextId() const { return mContextId; }
633
634 PxU32 getNbIslands() const { return mIslandStaticTouchCount.size(); }
635
636 const PxU32* getIslandStaticTouchCount() const { return mIslandStaticTouchCount.begin(); }
637
638 const PxU32* getIslandIds() const { return mIslandIds.begin(); }
639
640 bool checkInternalConsistency();
641
642
643 PX_INLINE void activateNode_ForGPUSolver(PxNodeIndex index)
644 {
645 IG::Node& node = mNodes[index.index()];
646 node.clearIsReadyForSleeping(); //Clear the "isReadyForSleeping" flag. Just in case it was set
647 node.clearDeactivating();
648 }
649 PX_INLINE void deactivateNode_ForGPUSolver(PxNodeIndex index)
650 {
651 IG::Node& node = mNodes[index.index()];
652 node.setIsReadyForSleeping();
653 }
654
655private:
656
657 void insertNewEdges();
658 void removeDestroyedEdges();
659 void wakeIslands();
660 void wakeIslands2();
661 void processNewEdges();
662 void processLostEdges(PxArray<PxNodeIndex>& destroyedNodes, bool allowDeactivation, bool permitKinematicDeactivation, PxU32 dirtyNodeLimit);
663
664 void removeConnectionInternal(EdgeIndex edgeIndex);
665
666 void addConnection(PxNodeIndex nodeHandle1, PxNodeIndex nodeHandle2, Edge::EdgeType edgeType, EdgeIndex handle);
667
668 void addConnectionToGraph(EdgeIndex index);
669 void removeConnectionFromGraph(EdgeIndex edgeIndex);
670 void connectEdge(EdgeInstance& instance, EdgeInstanceIndex edgeIndex, Node& source, PxNodeIndex destination);
671 void disconnectEdge(EdgeInstance& instance, EdgeInstanceIndex edgeIndex, Node& node);
672
673 //Merges 2 islands together. The returned id is the id of the merged island
674 IslandId mergeIslands(IslandId island0, IslandId island1, PxNodeIndex node0, PxNodeIndex node1);
675
676 void mergeIslandsInternal(Island& island0, Island& island1, IslandId islandId0, IslandId islandId1, PxNodeIndex node0, PxNodeIndex node1);
677
678
679 IslandSim& operator = (const IslandSim&);
680 IslandSim(const IslandSim&);
681
682 void unwindRoute(PxU32 traversalIndex, PxNodeIndex lastNode, PxU32 hopCount, IslandId id);
683
684 void activateIsland(IslandId island);
685
686 void deactivateIsland(IslandId island);
687
688 bool canFindRoot(PxNodeIndex startNode, PxNodeIndex targetNode, PxArray<PxNodeIndex>* visitedNodes);
689
690 bool tryFastPath(PxNodeIndex startNode, PxNodeIndex targetNode, IslandId islandId);
691
692 bool findRoute(PxNodeIndex startNode, PxNodeIndex targetNode, IslandId islandId);
693
694 bool isPathTo(PxNodeIndex startNode, PxNodeIndex targetNode);
695
696 void addNode(bool isActive, bool isKinematic, Node::NodeType type, PxNodeIndex nodeIndex);
697
698 void activateNodeInternal(PxNodeIndex index);
699 void deactivateNodeInternal(PxNodeIndex index);
700
701 PX_FORCE_INLINE void notifyReadyForSleeping(const PxNodeIndex nodeIndex)
702 {
703 Node& node = mNodes[nodeIndex.index()];
704 //PX_ASSERT(node.isActive());
705 node.setIsReadyForSleeping();
706 }
707
708 PX_FORCE_INLINE void notifyNotReadyForSleeping(const PxNodeIndex nodeIndex)
709 {
710 Node& node = mNodes[nodeIndex.index()];
711 PX_ASSERT(node.isActive() || node.isActivating());
712 node.clearIsReadyForSleeping();
713 }
714
715 PX_FORCE_INLINE void markIslandActive(IslandId islandId)
716 {
717 Island& island = mIslands[islandId];
718 PX_ASSERT(!mIslandAwake.test(islandId));
719 PX_ASSERT(island.mActiveIndex == IG_INVALID_ISLAND);
720
721 mIslandAwake.set(islandId);
722 island.mActiveIndex = mActiveIslands.size();
723 mActiveIslands.pushBack(islandId);
724 }
725
726 PX_FORCE_INLINE void markIslandInactive(IslandId islandId)
727 {
728 Island& island = mIslands[islandId];
729 PX_ASSERT(mIslandAwake.test(islandId));
730 PX_ASSERT(island.mActiveIndex != IG_INVALID_ISLAND);
731 PX_ASSERT(mActiveIslands[island.mActiveIndex] == islandId);
732 IslandId replaceId = mActiveIslands[mActiveIslands.size()-1];
733 PX_ASSERT(mIslandAwake.test(replaceId));
734 Island& replaceIsland = mIslands[replaceId];
735 replaceIsland.mActiveIndex = island.mActiveIndex;
736 mActiveIslands[island.mActiveIndex] = replaceId;
737 mActiveIslands.forceSize_Unsafe(mActiveIslands.size()-1);
738 island.mActiveIndex = IG_INVALID_ISLAND;
739 mIslandAwake.reset(islandId);
740 }
741
742 PX_FORCE_INLINE void markKinematicActive(PxNodeIndex index)
743 {
744 Node& node = mNodes[index.index()];
745 PX_ASSERT(node.isKinematic());
746 if(node.mActiveRefCount == 0 && mActiveNodeIndex[index.index()] == PX_INVALID_NODE)
747 {
748 //PX_ASSERT(mActiveNodeIndex[index.index()] == PX_INVALID_NODE);
749 //node.mActiveNodeIndex = mActiveKinematicNodes.size();
750 mActiveNodeIndex[index.index()] = mActiveKinematicNodes.size();
751 PxNodeIndex nodeIndex;
752 nodeIndex = index;
753 mActiveKinematicNodes.pushBack(nodeIndex);
754 }
755 }
756
757 PX_FORCE_INLINE void markKinematicInactive(PxNodeIndex index)
758 {
759 Node& node = mNodes[index.index()];
760 PX_ASSERT(node.isKinematic());
761 PX_ASSERT(mActiveNodeIndex[index.index()] != PX_INVALID_NODE);
762 PX_ASSERT(mActiveKinematicNodes[mActiveNodeIndex[index.index()]].index() == index.index());
763
764 if(node.mActiveRefCount == 0)
765 {
766 //Only remove from active kinematic list if it has no active contacts referencing it *and* it is asleep
767 if(mActiveNodeIndex[index.index()] != PX_INVALID_NODE)
768 {
769 //Need to verify active node index because there is an edge case where a node could be woken, then put to
770 //sleep in the same frame. This would mean that it would not have an active index at this stage.
771 PxNodeIndex replaceIndex = mActiveKinematicNodes.back();
772 PX_ASSERT(mActiveNodeIndex[replaceIndex.index()] == mActiveKinematicNodes.size()-1);
773 mActiveNodeIndex[replaceIndex.index()] = mActiveNodeIndex[index.index()];
774 mActiveKinematicNodes[mActiveNodeIndex[index.index()]] = replaceIndex;
775 mActiveKinematicNodes.forceSize_Unsafe(mActiveKinematicNodes.size()-1);
776 mActiveNodeIndex[index.index()] = PX_INVALID_NODE;
777 }
778 }
779 }
780
781 PX_FORCE_INLINE void markActive(PxNodeIndex index)
782 {
783 Node& node = mNodes[index.index()];
784 PX_ASSERT(!node.isKinematic());
785 PX_ASSERT(mActiveNodeIndex[index.index()] == PX_INVALID_NODE);
786 mActiveNodeIndex[index.index()] = mActiveNodes[node.mType].size();
787 PxNodeIndex nodeIndex;
788 nodeIndex = index;
789 mActiveNodes[node.mType].pushBack(nodeIndex);
790 }
791
792 PX_FORCE_INLINE void markInactive(PxNodeIndex index)
793 {
794 Node& node = mNodes[index.index()];
795
796 PX_ASSERT(!node.isKinematic());
797 PX_ASSERT(mActiveNodeIndex[index.index()] != PX_INVALID_NODE);
798
799 PxArray<PxNodeIndex>& activeNodes = mActiveNodes[node.mType];
800
801 PX_ASSERT(activeNodes[mActiveNodeIndex[index.index()]].index() == index.index());
802 const PxU32 initialActiveNodeCount = mInitialActiveNodeCount[node.mType];
803
804 if(mActiveNodeIndex[index.index()] < initialActiveNodeCount)
805 {
806 //It's in the initial active node set. We retain a list of active nodes, where the existing active nodes
807 //are at the beginning of the array and the newly activated nodes are at the end of the array...
808 //The solution is to move the node to the end of the initial active node list in this case
809 PxU32 activeNodeIndex = mActiveNodeIndex[index.index()];
810 PxNodeIndex replaceIndex = activeNodes[initialActiveNodeCount-1];
811 PX_ASSERT(mActiveNodeIndex[replaceIndex.index()] == initialActiveNodeCount-1);
812 mActiveNodeIndex[index.index()] = mActiveNodeIndex[replaceIndex.index()];
813 mActiveNodeIndex[replaceIndex.index()] = activeNodeIndex;
814 activeNodes[activeNodeIndex] = replaceIndex;
815 activeNodes[mActiveNodeIndex[index.index()]] = index;
816 mInitialActiveNodeCount[node.mType]--;
817 }
818
819 PX_ASSERT(!node.isKinematic());
820 PX_ASSERT(mActiveNodeIndex[index.index()] != PX_INVALID_NODE);
821 PX_ASSERT(activeNodes[mActiveNodeIndex[index.index()]].index() == index.index());
822
823 PxNodeIndex replaceIndex = activeNodes.back();
824 PX_ASSERT(mActiveNodeIndex[replaceIndex.index()] == activeNodes.size()-1);
825 mActiveNodeIndex[replaceIndex.index()] = mActiveNodeIndex[index.index()];
826 activeNodes[mActiveNodeIndex[index.index()]] = replaceIndex;
827 activeNodes.forceSize_Unsafe(activeNodes.size()-1);
828 mActiveNodeIndex[index.index()] = PX_INVALID_NODE;
829 }
830
831 PX_FORCE_INLINE void markEdgeActive(EdgeIndex index)
832 {
833 Edge& edge = mEdges[index];
834
835 PX_ASSERT((edge.mEdgeState & Edge::eACTIVATING) == 0);
836
837 edge.mEdgeState |= Edge::eACTIVATING;
838
839 mActivatedEdges[edge.mEdgeType].pushBack(index);
840
841 mActiveEdgeCount[edge.mEdgeType]++;
842
843 //Set the active bit...
844 if(edge.mEdgeType == Edge::eCONTACT_MANAGER)
845 mActiveContactEdges.set(index);
846
847 PxNodeIndex nodeIndex1 = mEdgeNodeIndices[2 * index];
848 PxNodeIndex nodeIndex2 = mEdgeNodeIndices[2 * index + 1];
849
850 if (nodeIndex1.index() != PX_INVALID_NODE && nodeIndex2.index() != PX_INVALID_NODE)
851 {
852 PX_ASSERT((!mNodes[nodeIndex1.index()].isKinematic()) || (!mNodes[nodeIndex2.index()].isKinematic()) || edge.getEdgeType() == IG::Edge::eCONTACT_MANAGER);
853 {
854 Node& node = mNodes[nodeIndex1.index()];
855
856 if(node.mActiveRefCount == 0 && node.isKinematic() && !(node.isActive() || node.isActivating()))
857 {
858 //Add to active kinematic list
859 markKinematicActive(nodeIndex1);
860 }
861 node.mActiveRefCount++;
862 }
863
864 {
865 Node& node = mNodes[nodeIndex2.index()];
866 if(node.mActiveRefCount == 0 && node.isKinematic() && !(node.isActive() || node.isActivating()))
867 {
868 //Add to active kinematic list
869 markKinematicActive(nodeIndex2);
870 }
871 node.mActiveRefCount++;
872 }
873 }
874
875 }
876
877 void removeEdgeFromActivatingList(EdgeIndex index);
878
879 PX_FORCE_INLINE void removeEdgeFromIsland(Island& island, EdgeIndex edgeIndex)
880 {
881 Edge& edge = mEdges[edgeIndex];
882 if(edge.mNextIslandEdge != IG_INVALID_EDGE)
883 {
884 PX_ASSERT(mEdges[edge.mNextIslandEdge].mPrevIslandEdge == edgeIndex);
885 mEdges[edge.mNextIslandEdge].mPrevIslandEdge = edge.mPrevIslandEdge;
886 }
887 else
888 {
889 PX_ASSERT(island.mLastEdge[edge.mEdgeType] == edgeIndex);
890 island.mLastEdge[edge.mEdgeType] = edge.mPrevIslandEdge;
891 }
892
893 if(edge.mPrevIslandEdge != IG_INVALID_EDGE)
894 {
895 PX_ASSERT(mEdges[edge.mPrevIslandEdge].mNextIslandEdge == edgeIndex);
896 mEdges[edge.mPrevIslandEdge].mNextIslandEdge = edge.mNextIslandEdge;
897 }
898 else
899 {
900 PX_ASSERT(island.mFirstEdge[edge.mEdgeType] == edgeIndex);
901 island.mFirstEdge[edge.mEdgeType] = edge.mNextIslandEdge;
902 }
903
904 island.mEdgeCount[edge.mEdgeType]--;
905 edge.mNextIslandEdge = edge.mPrevIslandEdge = IG_INVALID_EDGE;
906 }
907
908 PX_FORCE_INLINE void addEdgeToIsland(Island& island, EdgeIndex edgeIndex)
909 {
910 Edge& edge = mEdges[edgeIndex];
911 PX_ASSERT(edge.mNextIslandEdge == IG_INVALID_EDGE && edge.mPrevIslandEdge == IG_INVALID_EDGE);
912
913 if(island.mLastEdge[edge.mEdgeType] != IG_INVALID_EDGE)
914 {
915 PX_ASSERT(mEdges[island.mLastEdge[edge.mEdgeType]].mNextIslandEdge == IG_INVALID_EDGE);
916 mEdges[island.mLastEdge[edge.mEdgeType]].mNextIslandEdge = edgeIndex;
917 }
918 else
919 {
920 PX_ASSERT(island.mFirstEdge[edge.mEdgeType] == IG_INVALID_EDGE);
921 island.mFirstEdge[edge.mEdgeType] = edgeIndex;
922 }
923
924 edge.mPrevIslandEdge = island.mLastEdge[edge.mEdgeType];
925 island.mLastEdge[edge.mEdgeType] = edgeIndex;
926 island.mEdgeCount[edge.mEdgeType]++;
927 }
928
929 PX_FORCE_INLINE void removeNodeFromIsland(Island& island, PxNodeIndex nodeIndex)
930 {
931 Node& node = mNodes[nodeIndex.index()];
932 if(node.mNextNode.isValid())
933 {
934 PX_ASSERT(mNodes[node.mNextNode.index()].mPrevNode.index() == nodeIndex.index());
935 mNodes[node.mNextNode.index()].mPrevNode = node.mPrevNode;
936 }
937 else
938 {
939 PX_ASSERT(island.mLastNode.index() == nodeIndex.index());
940 island.mLastNode = node.mPrevNode;
941 }
942
943 if(node.mPrevNode.isValid())
944 {
945 PX_ASSERT(mNodes[node.mPrevNode.index()].mNextNode.index() == nodeIndex.index());
946 mNodes[node.mPrevNode.index()].mNextNode = node.mNextNode;
947 }
948 else
949 {
950 PX_ASSERT(island.mRootNode.index() == nodeIndex.index());
951 island.mRootNode = node.mNextNode;
952 }
953
954 island.mSize[node.mType]--;
955
956 node.mNextNode = PxNodeIndex(); node.mPrevNode = PxNodeIndex();
957 }
958
959 //void setEdgeConnectedInternal(EdgeIndex edgeIndex);
960
961 //void setEdgeDisconnectedInternal(EdgeIndex edgeIndex);
962
963 friend class SimpleIslandManager;
964 friend class ThirdPassTask;
965
966};
967
968
969}
970
971
973{
974 PxU16 mPartitionIndex;
976 PxU8 mCType;
978};
979
981{
982 PxNodeIndex mNodeIndex0;
983 PxNodeIndex mNodeIndex1;
984 PxU32 mNextIndex0;
985 PxU32 mNextIndex1;
986};
987
988
989#define INVALID_PARTITION_INDEX 0xFFFF
990
992{
993 IG::EdgeIndex mEdgeIndex;
1000
1002
1004
1005
1006 //KS - This constructor explicitly does not set mUniqueIndex. It is filled in by the pool allocator and this constructor
1007 //is called afterwards. We do not want to stomp the uniqueIndex value
1008 PartitionEdge() : mEdgeIndex(IG_INVALID_EDGE), mInfiniteMass0(false), mArticulation0(false),
1009 mInfiniteMass1(false), mArticulation1(false), mNextPatch(NULL)//, mUniqueIndex(IG_INVALID_EDGE)
1010 {
1011 }
1012};
1013
1014}
1015
1016#endif
Definition SnippetSoftBody.h:36
Definition CmBlockArray.h:47
Definition CmPriorityQueue.h:182
Definition DyFEMCloth.h:50
Definition DyFeatherstoneArticulation.h:590
Definition DyHairSystem.h:81
Definition DyParticleSystem.h:66
Definition DySoftBody.h:52
Definition PxsIslandSim.h:157
Definition PxsIslandSim.h:412
Definition PxsIslandSim.h:209
State
Definition PxsIslandSim.h:223
@ eACTIVATING
Is dirty (i.e. lost a connection)
Definition PxsIslandSim.h:229
@ eACTIVE
Ready to go to sleep.
Definition PxsIslandSim.h:225
@ eKINEMATIC
Active.
Definition PxsIslandSim.h:226
@ eDELETED
Kinematic.
Definition PxsIslandSim.h:227
@ eDEACTIVATING
Is in the activating list.
Definition PxsIslandSim.h:230
@ eDIRTY
Is pending deletion.
Definition PxsIslandSim.h:228
Definition PxsSimpleIslandManager.h:87
Definition PxsSimpleIslandManager.h:49
Definition PxArray.h:53
PX_FORCE_INLINE uint32_t size() const
Definition PxArray.h:242
PX_FORCE_INLINE void forceSize_Unsafe(uint32_t size)
Definition PxArray.h:507
PX_FORCE_INLINE ConstIterator begin() const
Definition PxArray.h:176
PX_FORCE_INLINE T & pushBack(const T &a)
Definition PxArray.h:296
PX_INLINE T popBack()
Definition PxArray.h:311
PX_FORCE_INLINE const T & back() const
Definition PxArray.h:224
Definition PxBitMap.h:52
PxNodeIndex.
Definition PxNodeIndex.h:51
Definition PxsContactManager.h:77
Definition PxsRigidBody.h:43
Definition ScArticulationSim.h:68
#define PX_FORCE_INLINE
Definition PxPreprocessor.h:335
#define PX_INLINE
Definition PxPreprocessor.h:320
Sorts an array of objects in ascending order, assuming that the predicate implements the < operator:
Definition PxBoxController.h:39
Definition DyConstraint.h:53
Definition PxsIslandSim.h:147
Definition PxsIslandSim.h:80
Definition PxsIslandSim.h:340
Definition PxsIslandSim.h:397
Definition PxsIslandSim.h:383
Definition PxsIslandSim.h:366
Definition PxsIslandSim.h:992
PxNodeIndex mNode1
The node index for node 0. Can be obtained from the edge index alternatively.
Definition PxsIslandSim.h:995
bool mInfiniteMass1
Whether body 0 is an articulation link.
Definition PxsIslandSim.h:998
PartitionEdge * mNextPatch
Whether body 1 is an articulation link.
Definition PxsIslandSim.h:1001
PxU32 mUniqueIndex
for the contact manager has more than 1 patch, we have next patch's edge and previous patch's edge to...
Definition PxsIslandSim.h:1003
bool mArticulation1
Whether body 1 is kinematic.
Definition PxsIslandSim.h:999
PartitionEdge()
a unique ID for this edge
Definition PxsIslandSim.h:1008
bool mArticulation0
Whether body 0 is kinematic.
Definition PxsIslandSim.h:997
bool mInfiniteMass0
The node idnex for node 1. Can be obtained from the edge index alternatively.
Definition PxsIslandSim.h:996
PxNodeIndex mNode0
The edge index into the island manager. Used to identify the contact manager/constraint.
Definition PxsIslandSim.h:994
Definition PxsIslandSim.h:973
PxU8 mCType
The patch index for this partition edge. There may be multiple entries for a given edge if there are ...
Definition PxsIslandSim.h:976
PxU8 mPatchIndex
The current partition this edge is in. Used to find the edge efficiently. PxU8 is probably too small ...
Definition PxsIslandSim.h:975
PxU32 mPartitionEntryIndex
The type of constraint this is.
Definition PxsIslandSim.h:977
Definition PxsIslandSim.h:981