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