1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010-2019 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "nel/pacs/move_primitive.h"
23 #include "nel/pacs/move_element.h"
24 #include "nel/pacs/primitive_block.h"
26 #include "nel/misc/hierarchical_timer.h"
28 #include "nel/misc/i_xml.h"
30 using namespace NLMISC
;
32 #define NELPACS_ALLOC_DYNAMIC_INFO 100
33 #define NELPACS_ALLOC_STATIC_INFO 100
35 H_AUTO_DECL ( NLPACS_Eval_Collision
)
36 #define NLPACS_HAUTO_EVAL_COLLISION H_AUTO_USE ( NLPACS_Eval_Collision )
38 /****************************************************************************
42 // Non collisionnable primitive
43 Their moves are evaluate one by one with evalNCPrimitiveCollision().
44 If a collision is found, reaction() is called.
46 // Collisionnable primitives
47 Each primitive must be moved first with the move() method.
48 Their moves are evaluate all at once. All the collisions found are time sorted in a time orderin table (_TimeOT).
49 While the table is not empty, the first collision occurred in time is solved and
50 If a collision is found, reaction() is called.
53 ****************************************************************************/
58 // ***************************************************************************
60 CMoveContainer::~CMoveContainer ()
65 // ***************************************************************************
67 void CMoveContainer::clear ()
69 // Clear all primitives
70 std::set
<CMovePrimitive
*>::iterator ite
=_PrimitiveSet
.begin();
71 while (ite
!=_PrimitiveSet
.end ())
77 // Clear primitive set
78 _PrimitiveSet
.clear ();
81 _ChangedRoot
.clear ();
83 // Clear static world image set
84 _StaticWorldImage
.clear ();
93 // ***************************************************************************
95 void CMoveContainer::init (double xmin
, double ymin
, double xmax
, double ymax
, uint widthCellCount
, uint heightCellCount
,
96 double primitiveMaxSize
, uint8 numWorldImage
, uint maxIteration
, uint otSize
)
101 // Create world images
102 _ChangedRoot
.resize (numWorldImage
);
103 for (uint i
=0; i
<numWorldImage
; i
++)
104 _ChangedRoot
[i
]=NULL
;
110 _PrimitiveMaxSize
=primitiveMaxSize
;
119 _CellCountWidth
=widthCellCount
;
120 _CellCountHeight
=heightCellCount
;
123 _CellWidth
=(_Xmax
- _Xmin
)/(double)_CellCountWidth
;
124 _CellHeight
=(_Ymax
- _Ymin
)/(double)_CellCountHeight
;
127 _VectorCell
.resize (numWorldImage
);
128 for (uint j
=0; j
<numWorldImage
; j
++)
129 _VectorCell
[j
].resize (_CellCountWidth
* _CellCountHeight
);
133 _TimeOT
.resize (otSize
);
139 _TestTime
=0xffffffff;
140 _MaxTestIteration
=maxIteration
;
142 // Resize trigger array
143 _Triggers
.resize (NELPACS_CONTAINER_TRIGGER_DEFAULT_SIZE
);
146 // ***************************************************************************
148 void CMoveContainer::init (CGlobalRetriever
* retriever
, uint widthCellCount
, uint heightCellCount
, double primitiveMaxSize
,
149 uint8 numWorldImage
, uint maxIteration
, uint otSize
)
151 // Get min max of the global retriever BB
152 CVector min
=retriever
->getBBox().getMin();
153 CVector max
=retriever
->getBBox().getMax();
162 init (xmin
, ymin
, xmax
, ymax
, widthCellCount
, heightCellCount
, primitiveMaxSize
, numWorldImage
, maxIteration
, otSize
);
164 // Init the retriever
165 _Retriever
=retriever
;
168 // ***************************************************************************
170 void CMoveContainer::evalCollision (double deltaTime
, uint8 worldImage
)
172 NLPACS_HAUTO_EVAL_COLLISION
174 // H_AUTO(PACS_MC_evalCollision);
180 _DeltaTime
=deltaTime
;
185 // Update the bounding box and position of modified primitives
186 updatePrimitives (0.f
, worldImage
);
189 // Check list integrity
190 //checkSortedList ();
193 // Get first collision
194 _PreviousCollisionNode
= &_TimeOT
[0];
195 if(_PreviousCollisionNode
== NULL
)
198 // Eval all collisions
199 evalAllCollisions (0.f
, worldImage
);
201 // Clear modified list
202 clearModifiedList (worldImage
);
204 // Modified list is empty at this point
205 nlassert (_ChangedRoot
[worldImage
]==NULL
);
207 // Previous node is a 'hard' OT node
208 nlassert (!_PreviousCollisionNode
->isInfo());
210 // Get next collision
211 CCollisionOTInfo
*nextCollision
;
213 H_AUTO (NLPACS_Get_Next_Info
);
214 nextCollision
=_PreviousCollisionNode
->getNextInfo ();
218 while (nextCollision
)
220 // Get new previous OT hard node
221 _PreviousCollisionNode
=nextCollision
->getPrevious ();
223 // Previous node is a 'hard' OT node
224 nlassert (!_PreviousCollisionNode
->isInfo());
226 // Keep this collision
227 reaction (*nextCollision
);
229 // Remove this collision from ot
230 if (!nextCollision
->isCollisionAgainstStatic ())
232 // Remove the primitive from OT
233 nextCollision
->unlink();
235 CCollisionOTDynamicInfo
*info
= static_cast<CCollisionOTDynamicInfo
*>(nextCollision
);
236 if (info
->getFirstPrimitive())
237 info
->getFirstPrimitive()->removeCollisionOTInfo(info
);
238 if (info
->getSecondPrimitive())
239 info
->getSecondPrimitive()->removeCollisionOTInfo(info
);
243 double newTime
=nextCollision
->getCollisionTime ();
245 // Remove modified objects from the OT
246 removeModifiedFromOT (worldImage
);
248 // Must have been removed
249 nlassert (nextCollision
->getPrevious ()==NULL
);
250 nlassert (nextCollision
->CCollisionOT::getNext ()==NULL
);
252 // Update the bounding box and position of modified primitives
253 updatePrimitives (newTime
, worldImage
);
255 // Eval all collisions of modified objects for the new delta t
256 evalAllCollisions (newTime
, worldImage
);
258 // Clear modified list
259 clearModifiedList (worldImage
);
261 // Get next collision
262 nextCollision
=_PreviousCollisionNode
->getNextInfo ();
266 // OT must be cleared
270 // Free ordered table info
274 _PreviousCollisionNode
=NULL
;
277 // ***************************************************************************
279 bool CMoveContainer::testMove (UMovePrimitive
* primitive
, const CVectorD
& speed
, double deltaTime
, uint8 worldImage
, CVectorD
*contactNormal
)
282 // H_AUTO(PACS_MC_testMove);
285 *contactNormal
= CVectorD::Null
;
288 nlassert (dynamic_cast<CMovePrimitive
*>(primitive
));
289 CMovePrimitive
* prim
=static_cast<CMovePrimitive
*>(primitive
);
295 _DeltaTime
=deltaTime
;
297 // Get the world image primitive
298 uint8 primitiveWorldImage
;
299 CPrimitiveWorldImage
*wI
;
300 if (prim
->isNonCollisionable ())
302 wI
=prim
->getWorldImage (0);
303 primitiveWorldImage
=worldImage
;
307 wI
=prim
->getWorldImage (worldImage
);
308 primitiveWorldImage
=worldImage
;
312 CVectorD oldSpeed
=wI
->getSpeed ();
315 wI
->move (speed
, *this, *prim
, primitiveWorldImage
);
317 // Update the bounding box and position of the primitive
318 wI
->update (0, _DeltaTime
, *prim
);
320 // Compute cells overlaped by the primitive
321 if (!prim
->isNonCollisionable ())
322 updateCells (prim
, worldImage
);
325 // Check list integrity
326 // checkSortedList ();
333 // Eval first each static world images
334 result
=evalOneTerrainCollision (0, prim
, primitiveWorldImage
, true, testMoveValid
, NULL
, contactNormal
);
336 // Eval first each static world images
339 std::set
<uint8
>::iterator ite
=_StaticWorldImage
.begin();
340 while (ite
!=_StaticWorldImage
.end())
343 // Eval in this world image
344 result
=evalOnePrimitiveCollision (0, prim
, *ite
, primitiveWorldImage
, true, true, testMoveValid
, NULL
, contactNormal
);
355 // Eval collisions if not found and not tested
356 if ((!result
) && (_StaticWorldImage
.find (worldImage
)==_StaticWorldImage
.end()))
357 result
=evalOnePrimitiveCollision (0, prim
, worldImage
, primitiveWorldImage
, true, false, testMoveValid
, NULL
, contactNormal
);
359 // Backup speed only if the primitive is inserted in the world image
360 if (prim
->isInserted (primitiveWorldImage
))
361 wI
->move (oldSpeed
, *this, *prim
, primitiveWorldImage
);
364 // OT must be cleared
368 // Free ordered table info
372 _PreviousCollisionNode
=NULL
;
378 // ***************************************************************************
380 void CMoveContainer::updatePrimitives (double beginTime
, uint8 worldImage
)
382 H_AUTO (NLPACS_Update_Primitives
);
384 // For each changed primitives
385 CMovePrimitive
*changed
=_ChangedRoot
[worldImage
];
388 // Get the primitive world image
389 CPrimitiveWorldImage
*wI
;
390 if (changed
->isNonCollisionable())
391 wI
=changed
->getWorldImage (0);
393 wI
=changed
->getWorldImage (worldImage
);
395 // Force the build of the bounding box
396 wI
->update (beginTime
, _DeltaTime
, *changed
);
398 // Is inserted in this world image ?
399 if (changed
->isInserted (worldImage
))
402 // Compute cells overlaped by the primitive
403 updateCells (changed
, worldImage
);
407 changed
=wI
->getNextModified ();
411 // ***************************************************************************
413 void CMoveContainer::updateCells (CMovePrimitive
*primitive
, uint8 worldImage
)
415 // H_AUTO(PACS_MC_updateCells);
417 // Get the primitive world image
418 CPrimitiveWorldImage
*wI
=primitive
->getWorldImage (worldImage
);
421 /* // Check BB width not too large
422 if (wI->getBBXMax() - wI->getBBXMin() > _CellWidth)
424 nlwarning ("Primitives have moved more than a cell, width: %f.", (float)(wI->getBBXMax() - wI->getBBXMin()));
427 // Check BB height not too large
428 if (wI->getBBYMax() - wI->getBBYMin() > _CellHeight)
430 nlwarning ("Primitives have moved more than a cell, height: %f.", (float)(wI->getBBYMax() - wI->getBBYMin()));
435 // Get coordinate in the cell array
436 sint minx
=(int)floor ((wI
->getBBXMin() - _Xmin
) / _CellWidth
);
437 sint miny
=(int)floor ((wI
->getBBYMin() - _Ymin
) / _CellHeight
);
438 sint maxx
=(int)floor ((wI
->getBBXMax() - _Xmin
) / _CellWidth
);
439 sint maxy
=(int)floor ((wI
->getBBYMax() - _Ymin
) / _CellHeight
);
446 if (maxx
>=(int)_CellCountWidth
)
447 maxx
=(int)_CellCountWidth
-1;
448 if (maxy
>=(int)_CellCountHeight
)
449 maxy
=(int)_CellCountHeight
-1;
451 maxx
=std::min (minx
+1, maxx
);
452 maxy
=std::min (miny
+1, maxy
);
455 bool found
[4]={false, false, false, false};
457 // For each old cells
462 CMoveElement
*elm
= wI
->getMoveElement (i
);
464 // Old element in this cell ?
468 nlassert (elm
->X
<_CellCountWidth
);
469 nlassert (elm
->Y
<_CellCountHeight
);
472 if ( (elm
->X
< minx
) || (elm
->X
> maxx
) || (elm
->Y
< miny
) || (elm
->Y
> maxy
) )
475 wI
->removeMoveElement (i
, *this, worldImage
);
480 nlassert (((elm
->X
- minx
)==0)||((elm
->X
- minx
)==1));
481 nlassert (((elm
->Y
- miny
)==0)||((elm
->Y
- miny
)==1));
485 _VectorCell
[worldImage
][elm
->X
+elm
->Y
*_CellCountWidth
].updateSortedLists (elm
, worldImage
);
489 found
[ elm
->X
- minx
+ ((elm
->Y
- miny
) << (maxx
-minx
)) ]=true;
494 // For each case selected
497 for (y
=miny
; y
<=(int)maxy
; y
++)
498 for (x
=minx
; x
<=(int)maxx
; x
++)
501 nlassert ((int)i
== (x
- minx
+ ((y
- miny
) << (maxx
-minx
)) ));
503 // If the cell is not found
506 // Center of the cell
507 double cx
=((double)x
+0.5f
)*_CellWidth
+_Xmin
;
508 double cy
=((double)y
+0.5f
)*_CellHeight
+_Ymin
;
510 // Add it in the list
511 wI
->addMoveElement (_VectorCell
[worldImage
][x
+y
*_CellCountWidth
], (uint16
)x
, (uint16
)y
, cx
, cy
, primitive
, *this, worldImage
);
519 // ***************************************************************************
521 void CMoveContainer::getCells (CMovePrimitive
*primitive
, uint8 worldImage
, uint8 primitiveWorldImage
, CMoveElement
**elementArray
)
523 // H_AUTO(PACS_MC_getCells);
525 // Get the primitive world image
526 CPrimitiveWorldImage
*wI
;
527 if (primitive
->isNonCollisionable())
528 wI
=primitive
->getWorldImage (0);
530 wI
=primitive
->getWorldImage (primitiveWorldImage
);
533 // Check BB width not too large
534 if (wI
->getBBXMax() - wI
->getBBXMin() > _CellWidth
)
536 //nlwarning ("Primitives have moved more than a cell.");
539 // Check BB height not too large
540 if (wI
->getBBYMax() - wI
->getBBYMin() > _CellHeight
)
542 //nlwarning ("Primitives have moved more than a cell.");
546 // Get coordinate in the cell array
547 int minx
=(int)floor ((wI
->getBBXMin() - _Xmin
) / _CellWidth
);
548 int miny
=(int)floor ((wI
->getBBYMin() - _Ymin
) / _CellHeight
);
549 int maxx
=(int)floor ((wI
->getBBXMax() - _Xmin
) / _CellWidth
);
550 int maxy
=(int)floor ((wI
->getBBYMax() - _Ymin
) / _CellHeight
);
557 if (maxx
>=(int)_CellCountWidth
)
558 maxx
=(int)_CellCountWidth
-1;
559 if (maxy
>=(int)_CellCountHeight
)
560 maxy
=(int)_CellCountHeight
-1;
562 maxx
=std::min (minx
+1, maxx
);
563 maxy
=std::min (miny
+1, maxy
);
565 // For each case selected
568 for (y
=miny
; y
<=(int)maxy
; y
++)
569 for (x
=minx
; x
<=(int)maxx
; x
++)
572 nlassert ((int)i
== (x
- minx
+ ((y
- miny
) << (maxx
-minx
)) ));
574 // Center of the cell
575 double cx
=((double)x
+0.5f
)*_CellWidth
+_Xmin
;
578 double pcx
=(wI
->getBBXMin()+wI
->getBBXMax())/2.f
;
580 elementArray
[i
]->Primitive
=primitive
;
581 elementArray
[i
]->X
=uint16(x
);
582 elementArray
[i
]->Y
=uint16(y
);
583 // Insert in left or right ?
587 elementArray
[i
]->NextX
=_VectorCell
[worldImage
][x
+y
*_CellCountWidth
].getFirstX ();
588 elementArray
[i
]->PreviousX
=NULL
;
593 elementArray
[i
]->PreviousX
=_VectorCell
[worldImage
][x
+y
*_CellCountWidth
].getLastX ();
594 elementArray
[i
]->NextX
=NULL
;
601 // Erase last array element
604 elementArray
[i
]=NULL
;
608 // ***************************************************************************
610 void CMoveContainer::clearModifiedList (uint8 worldImage
)
612 H_AUTO (NLPACS_Clear_Modified_List
);
614 // For each changed primitives
615 CMovePrimitive
*changed
=_ChangedRoot
[worldImage
];
618 // Get the world image primitive
619 CPrimitiveWorldImage
*wI
;
620 if (changed
->isNonCollisionable())
621 wI
=changed
->getWorldImage (0);
623 wI
=changed
->getWorldImage (worldImage
);
626 changed
=wI
->getNextModified ();
628 // Remove it from the list
629 wI
->setInModifiedListFlag (false);
633 _ChangedRoot
[worldImage
]=NULL
;
636 // ***************************************************************************
638 void CMoveContainer::checkSortedList ()
640 // Check each primitives in the set
641 std::set
<CMovePrimitive
*>::iterator ite
=_PrimitiveSet
.begin();
642 while (ite
!=_PrimitiveSet
.end())
645 (*ite
)->checkSortedList ();
651 // ***************************************************************************
653 bool CMoveContainer::evalOneTerrainCollision (double beginTime
, CMovePrimitive
*primitive
, uint8 primitiveWorldImage
,
654 bool testMove
, bool &testMoveValid
, CCollisionOTStaticInfo
*staticColInfo
, CVectorD
*contactNormal
)
656 // H_AUTO(PACS_MC_evalOneCollision);
657 H_AUTO(NLPACS_Eval_One_Terrain_Collision
);
659 // Find its collisions
662 // Get the primitive world image
663 CPrimitiveWorldImage
*wI
;
664 if (primitive
->isNonCollisionable())
665 wI
=primitive
->getWorldImage (0);
667 wI
=primitive
->getWorldImage (primitiveWorldImage
);
669 // Begin time must be the same as beginTime
670 //nlassert (wI->getInitTime()==beginTime);
671 if (wI
->getInitTime() != beginTime
)
673 nlwarning("PACS: evalOneTerrainCollision() failure, wI->getInitTime() [%f] != beginTime [%f]", wI
->getInitTime(), beginTime
);
677 // Test its static collision
681 // Test retriever with the primitive
682 const TCollisionSurfaceDescVector
*result
=wI
->evalCollision (*_Retriever
, _SurfaceTemp
, _TestTime
, _MaxTestIteration
, *primitive
);
685 // TEST MOVE MUST BE OK !!
689 uint size
=(uint
)result
->size();
691 // For each detected collisions
692 for (uint c
=0; c
<size
; c
++)
694 // Ref on the collision
695 CCollisionSurfaceDesc desc
=(*result
)[c
];
696 double contactTime
= (_DeltaTime
-beginTime
)*desc
.ContactTime
+beginTime
;
699 * If beginTime is 0.999999999 and desc.ContactTime<1.0, contactTime will be 1.0.
700 * In this case, we force contactTime to be beginTime to avoid collision at time == 1.0.
702 if ((contactTime
>= 1.0) && (beginTime
< 1.0) && (desc
.ContactTime
< 1.0))
703 contactTime
= beginTime
;
705 // Set the container's time space contact time
706 desc
.ContactTime
= contactTime
;
708 // ptr on the surface
709 const CRetrievableSurface
*surf
= _Retriever
->getSurfaceById (desc
.ContactSurface
);
711 // TODO: check surface flags against primitive flags HERE:
717 isWall
= !(surf
->isFloor() || surf
->isCeiling());
725 // return contact normal only when testmove and vector provided
727 *contactNormal
= desc
.ContactNormal
;
732 // OK, collision if we are a collisionable primitive
733 newCollision (primitive
, desc
, primitiveWorldImage
, beginTime
, staticColInfo
);
735 // One collision found
743 // More than maxtest made, exit
749 // ***************************************************************************
751 bool CMoveContainer::evalOnePrimitiveCollision (double beginTime
, CMovePrimitive
*primitive
, uint8 worldImage
, uint8 primitiveWorldImage
,
752 bool testMove
, bool secondIsStatic
, bool &/* testMoveValid */, CCollisionOTDynamicInfo
*dynamicColInfo
,
753 CVectorD
*contactNormal
)
755 // H_AUTO(PACS_MC_evalOneCollision);
756 H_AUTO(NLPACS_Eval_One_Primitive_Collision
);
758 // Find its collisions
761 // Get the primitive world image
762 CPrimitiveWorldImage
*wI
;
763 if (primitive
->isNonCollisionable())
764 wI
=primitive
->getWorldImage (0);
766 wI
=primitive
->getWorldImage (primitiveWorldImage
);
768 // Begin time must be the same as beginTime
769 //nlassert (wI->getInitTime()==beginTime);
770 if (wI
->getInitTime() != beginTime
)
772 nlwarning("PACS: evalOnePrimitiveCollision() failure, wI->getInitTime() [%f] != beginTime [%f]", wI
->getInitTime(), beginTime
);
777 CMoveElement tableNotInserted
[4];
778 CMoveElement
*table
[4];
781 bool singleTest
=testMove
;
784 if ((worldImage
==primitiveWorldImage
) && wI
->isInWorldImageFlag())
786 // Get move element table from the primitive
787 table
[0]=wI
->getMoveElement (0);
788 table
[1]=wI
->getMoveElement (1);
789 table
[2]=wI
->getMoveElement (2);
790 table
[3]=wI
->getMoveElement (3);
794 // Set table pointers
795 table
[0]=tableNotInserted
+0;
796 table
[1]=tableNotInserted
+1;
797 table
[2]=tableNotInserted
+2;
798 table
[3]=tableNotInserted
+3;
801 getCells (primitive
, worldImage
, primitiveWorldImage
, table
);
807 // For each move element
808 for (uint i
=0; i
<4; i
++)
811 CMoveElement
*elm
=table
[i
];
817 nlassert (elm
->Primitive
==primitive
);
818 // Primitive to the left
820 // Lookup in X sorted list on the left
821 CMoveElement
*other
=elm
->PreviousX
;
822 nlassert (other
!=elm
);
824 while (other
&& (wI
->getBBXMin() - other
->Primitive
->getWorldImage(worldImage
)->getBBXMin() < _PrimitiveMaxSize
) )
827 CMovePrimitive
*otherPrimitive
=other
->Primitive
;
828 CPrimitiveWorldImage
*otherWI
=otherPrimitive
->getWorldImage (worldImage
);
829 nlassert (otherPrimitive
!=primitive
);
831 // Continue the check if the other primitive is not int the modified list or if its pointer is higher than primitive
832 if ( singleTest
|| ( (!otherWI
->isInModifiedListFlag ()) || (primitive
<otherPrimitive
) ) )
834 // Look if valid in X
835 if (wI
->getBBXMin() < otherWI
->getBBXMax())
837 // Look if valid in Y
838 if ( (wI
->getBBYMin() < otherWI
->getBBYMax()) && (otherWI
->getBBYMin() < wI
->getBBYMax()) )
840 // If not already in collision with this primitive
841 if (!primitive
->isInCollision (otherPrimitive
))
843 if (evalPrimAgainstPrimCollision (beginTime
, primitive
, otherPrimitive
, wI
, otherWI
, testMove
,
844 primitiveWorldImage
, worldImage
, secondIsStatic
, dynamicColInfo
, contactNormal
))
855 // Next primitive to the left
856 other
= other
->PreviousX
;
859 // Lookup in X sorted list on the right
862 // Primitive to the right
863 while (other
&& (other
->Primitive
->getWorldImage(worldImage
)->getBBXMin() < wI
->getBBXMax()) )
866 CMovePrimitive
*otherPrimitive
=other
->Primitive
;
867 CPrimitiveWorldImage
*otherWI
=otherPrimitive
->getWorldImage (worldImage
);
868 nlassert (otherPrimitive
!=primitive
);
870 // Continue the check if the other primitive is not in the modified list or if its pointer is higher than primitive
871 if ( singleTest
|| ( (!otherWI
->isInModifiedListFlag ()) || (primitive
<otherPrimitive
) ) )
873 // Look if valid in Y
874 if ( (wI
->getBBYMin() < otherWI
->getBBYMax()) && (otherWI
->getBBYMin() < wI
->getBBYMax()) )
876 // If not already in collision with this primitive
877 if (!primitive
->isInCollision (otherPrimitive
))
879 if (evalPrimAgainstPrimCollision (beginTime
, primitive
, otherPrimitive
, wI
, otherWI
, testMove
,
880 primitiveWorldImage
, worldImage
, secondIsStatic
, dynamicColInfo
, contactNormal
))
890 // Next primitive to the left
891 other
= other
->NextX
;
899 // ***************************************************************************
901 bool CMoveContainer::evalPrimAgainstPrimCollision (double beginTime
, CMovePrimitive
*primitive
, CMovePrimitive
*otherPrimitive
,
902 CPrimitiveWorldImage
*wI
, CPrimitiveWorldImage
*otherWI
, bool testMove
,
903 uint8 firstWorldImage
, uint8 secondWorldImage
, bool secondIsStatic
, CCollisionOTDynamicInfo
*dynamicColInfo
,
904 CVectorD
* /* contactNormal */)
906 // H_AUTO(PACS_MC_evalPrimAgainstPrimCollision);
908 // Test the primitive
909 double firstTime
, lastTime
;
913 if (wI
->evalCollision (*otherWI
, desc
, beginTime
, _DeltaTime
, _TestTime
, _MaxTestIteration
,
914 firstTime
, lastTime
, *primitive
, *otherPrimitive
))
917 bool enter
= (beginTime
<=firstTime
) && (firstTime
<_DeltaTime
) && ((primitive
->getTriggerType()&UMovePrimitive::EnterTrigger
)
918 || (otherPrimitive
->getTriggerType()&UMovePrimitive::EnterTrigger
));
919 bool exit
= (beginTime
<=lastTime
) && (lastTime
<_DeltaTime
) && ((primitive
->getTriggerType()&UMovePrimitive::ExitTrigger
)
920 || (otherPrimitive
->getTriggerType()&UMovePrimitive::ExitTrigger
));
921 bool overlap
= (firstTime
<=beginTime
) && (lastTime
>_DeltaTime
) && ((primitive
->getTriggerType()&UMovePrimitive::OverlapTrigger
)
922 || (otherPrimitive
->getTriggerType()&UMovePrimitive::OverlapTrigger
));
923 bool contact
= ( beginTime
<((firstTime
+lastTime
)/2) ) && (firstTime
<=_DeltaTime
);
924 bool collision
= contact
&& (primitive
->isObstacle() && otherPrimitive
->isObstacle ());
926 // Return collision time
933 * For collisionnable primitives, trigger are raised here (in reaction) because
934 * this is the moment we are sure the collision happened.
936 * For non collisionable primitves, the trigger is raised at collision time because without OT,
937 * we can't stop evaluating collision on triggers.
939 if (primitive
->isNonCollisionable () && (enter
|| exit
|| overlap
))
941 if (primitive
->isTriggered (*otherPrimitive
, enter
, exit
))
945 newTrigger (primitive
, otherPrimitive
, desc
, UTriggerInfo::In
);
947 newTrigger (primitive
, otherPrimitive
, desc
, UTriggerInfo::Out
);
949 newTrigger (primitive
, otherPrimitive
, desc
, UTriggerInfo::Inside
);
952 // If the other primitive is not an obstacle, skip it because it will re-generate collisions.
958 if (contact
|| enter
|| exit
|| overlap
)
959 newCollision (primitive
, otherPrimitive
, desc
, contact
, enter
, exit
, overlap
, firstWorldImage
, secondWorldImage
, secondIsStatic
,
968 // ***************************************************************************
970 void CMoveContainer::evalAllCollisions (double beginTime
, uint8 worldImage
)
972 H_AUTO(NLPACS_Eval_All_Collisions
);
975 CMovePrimitive
*primitive
=_ChangedRoot
[worldImage
];
977 // For each modified primitive
980 // Get the primitive world image
981 uint8 primitiveWorldImage
;
982 CPrimitiveWorldImage
*wI
;
983 if (primitive
->isNonCollisionable ())
985 wI
=primitive
->getWorldImage (0);
986 primitiveWorldImage
=worldImage
;
990 wI
=primitive
->getWorldImage (worldImage
);
991 primitiveWorldImage
=worldImage
;
994 CVectorD d0
=wI
->getDeltaPosition();
998 bool testMoveValid
=false;
1000 // Eval collision on the terrain
1001 found
|=evalOneTerrainCollision (beginTime
, primitive
, primitiveWorldImage
, false, testMoveValid
, NULL
, NULL
);
1003 // If the primitive can collid other primitive..
1004 if (primitive
->getCollisionMask())
1006 // Eval collision in each static world image
1007 std::set
<uint8
>::iterator ite
=_StaticWorldImage
.begin();
1008 while (ite
!=_StaticWorldImage
.end())
1010 // Eval in this world image
1011 found
|=evalOnePrimitiveCollision (beginTime
, primitive
, *ite
, primitiveWorldImage
, false, true, testMoveValid
, NULL
, NULL
);
1018 CVectorD d1
=wI
->getDeltaPosition();
1020 // If the primitive can collid other primitive..
1021 if (primitive
->getCollisionMask())
1023 // Eval collision in the world image if not already tested
1024 if (_StaticWorldImage
.find (worldImage
)==_StaticWorldImage
.end())
1025 found
|=evalOnePrimitiveCollision (beginTime
, primitive
, worldImage
, primitiveWorldImage
, false, false, testMoveValid
, NULL
, NULL
);
1028 CVectorD d2
=wI
->getDeltaPosition();
1033 //nlassert ((d0==d1)&&(d0==d2));
1034 //nlassert (f1==f2);
1036 if (_Retriever
&&testMoveValid
)
1039 wI
->doMove (*_Retriever
, _SurfaceTemp
, _DeltaTime
, _DeltaTime
, primitive
->getDontSnapToGround());
1044 wI
->doMove (_DeltaTime
);
1049 primitive
=wI
->getNextModified ();
1053 // ***************************************************************************
1055 void CMoveContainer::newCollision (CMovePrimitive
* first
, CMovePrimitive
* second
, const CCollisionDesc
& desc
, bool collision
, bool enter
, bool exit
, bool inside
,
1056 uint firstWorldImage
, uint secondWorldImage
, bool secondIsStatic
, CCollisionOTDynamicInfo
*dynamicColInfo
)
1058 // H_AUTO(PACS_MC_newCollision_short);
1060 nlassert ((dynamicColInfo
&& first
->isNonCollisionable ()) || (!dynamicColInfo
&& first
->isCollisionable ()));
1064 dynamicColInfo
->init (first
, second
, desc
, collision
, enter
, exit
, inside
, uint8(firstWorldImage
), uint8(secondWorldImage
), secondIsStatic
);
1068 // Get an ordered time index. Always round to the future.
1069 int index
=(int)(ceil (desc
.ContactTime
*(double)_OtSize
/_DeltaTime
) );
1076 if (index
<(int)_OtSize
)
1079 CCollisionOTDynamicInfo
*info
= allocateOTDynamicInfo ();
1080 info
->init (first
, second
, desc
, collision
, enter
, exit
, inside
, uint8(firstWorldImage
), uint8(secondWorldImage
), secondIsStatic
);
1082 // Add in the primitive list
1083 first
->addCollisionOTInfo (info
);
1084 second
->addCollisionOTInfo (info
);
1086 // Insert in the time ordered table
1087 //nlassert (index<(int)_TimeOT.size());
1088 if (index
>= (int)_TimeOT
.size())
1090 nlwarning("PACS: newCollision() failure, index [%d] >= (int)_TimeOT.size() [%d], clamped to max", index
, (int)_TimeOT
.size());
1091 index
= (int)_TimeOT
.size()-1;
1093 _TimeOT
[index
].link (info
);
1095 // Check it is after the last hard collision
1096 nlassert (_PreviousCollisionNode
<=&_TimeOT
[index
]);
1101 // ***************************************************************************
1103 void CMoveContainer::newCollision (CMovePrimitive
* first
, const CCollisionSurfaceDesc
& desc
, uint8 worldImage
, double beginTime
, CCollisionOTStaticInfo
*staticColInfo
)
1105 // H_AUTO(PACS_MC_newCollision_long);
1108 nlassert (_Retriever
);
1109 nlassert ((staticColInfo
&& first
->isNonCollisionable ()) || (!staticColInfo
&& first
->isCollisionable ()));
1111 // Get the world image
1112 CPrimitiveWorldImage
*wI
;
1113 if (first
->isNonCollisionable())
1114 wI
=first
->getWorldImage (0);
1116 wI
=first
->getWorldImage (worldImage
);
1119 double time
=desc
.ContactTime
;
1121 if (time == _DeltaTime)
1122 time -= _DeltaTime*FLT_EPSILON;
1125 // Check time interval
1127 //nlassertex (beginTime<=time, ("beginTime=%f, time=%f", beginTime, time));
1128 //nlassertex (time<_DeltaTime, ("time=%f, _DeltaTime=%f", time, _DeltaTime));
1130 if (beginTime
> time
)
1132 nlwarning("PACS: beginTime=%f > time=%f", beginTime
, time
);
1135 if (time
>= _DeltaTime
)
1137 nlinfo("PACS: time=%f >= _DeltaTime=%f", time
, _DeltaTime
);
1141 // Time of the collision.
1142 time
-=NELPACS_DIST_BACK
/wI
->getSpeed().norm();
1143 time
=std::max(time
, beginTime
);
1144 double ratio
=(time
-beginTime
)/(_DeltaTime
-beginTime
);
1147 nlassert (ratio>=0);
1148 nlassert (ratio<=1);
1153 nlwarning("PACS: ratio=%f < 0.0", ratio
);
1159 nlwarning("PACS: ratio=%f > 1.0", ratio
);
1165 // Make a new globalposition
1166 UGlobalPosition endPosition
=_Retriever
->doMove (wI
->getGlobalPosition(), wI
->getDeltaPosition(),
1167 (float)ratio
, _SurfaceTemp
, false);
1169 // Init the info descriptor
1170 staticColInfo
->init (first
, desc
, endPosition
, ratio
, worldImage
);
1174 // Get an ordered time index. Always round to the future.
1175 int index
=(int)(ceil (time
*(double)_OtSize
/_DeltaTime
) );
1182 if (index
<(int)_OtSize
)
1185 CCollisionOTStaticInfo
*info
= allocateOTStaticInfo ();
1187 // Make a new globalposition
1188 UGlobalPosition endPosition
=_Retriever
->doMove (wI
->getGlobalPosition(), wI
->getDeltaPosition(),
1189 (float)ratio
, _SurfaceTemp
, false);
1191 // Init the info descriptor
1192 info
->init (first
, desc
, endPosition
, ratio
, worldImage
);
1194 // Add in the primitive list
1195 first
->addCollisionOTInfo (info
);
1197 // Insert in the time ordered table
1198 //nlassert (index<(int)_TimeOT.size());
1199 if (index
>= (int)_TimeOT
.size())
1201 nlwarning("PACS: newCollision() failure, index [%d] >= (int)_TimeOT.size() [%d], clamped to max", index
, (int)_TimeOT
.size());
1202 index
= (int)_TimeOT
.size()-1;
1204 _TimeOT
[index
].link (info
);
1206 // Check it is after the last hard collision
1207 nlassert (_PreviousCollisionNode
<=&_TimeOT
[index
]);
1212 // ***************************************************************************
1214 void CMoveContainer::newTrigger (CMovePrimitive
* first
, CMovePrimitive
* second
, const CCollisionDesc
& desc
, uint triggerType
)
1217 uint index
=(uint
)_Triggers
.size();
1220 _Triggers
.resize (index
+1);
1223 _Triggers
[index
].Object0
=first
->UserData
;
1224 _Triggers
[index
].Object1
=second
->UserData
;
1225 _Triggers
[index
].CollisionDesc
=desc
;
1226 _Triggers
[index
].CollisionType
= uint8(triggerType
);
1229 // ***************************************************************************
1231 void CMoveContainer::checkOT ()
1234 nlassert (_OtSize
==_TimeOT
.size());
1236 // Check linked list
1237 for (uint i
=0; i
<_OtSize
-1; i
++)
1240 nlassert ( _TimeOT
[i
].getNext() == (&(_TimeOT
[i
+1])) );
1241 nlassert ( _TimeOT
[i
+1].getPrevious() == (&(_TimeOT
[i
])) );
1244 // Check first and last
1245 nlassert ( _TimeOT
[0].getPrevious() == NULL
);
1246 nlassert ( _TimeOT
[_OtSize
-1].getNext() == NULL
);
1249 // ***************************************************************************
1251 void CMoveContainer::clearOT ()
1254 nlassert (_OtSize
==_TimeOT
.size());
1258 for (i
=0; i
<_OtSize
; i
++)
1259 _TimeOT
[i
].clear ();
1262 for (i
=0; i
<_OtSize
-1; i
++)
1263 // Link the two cells
1264 _TimeOT
[i
].link (&(_TimeOT
[i
+1]));
1267 // ***************************************************************************
1269 void CMoveContainer::removeModifiedFromOT (uint8 worldImage
)
1271 // For each changed primitives
1272 CMovePrimitive
*changed
=_ChangedRoot
[worldImage
];
1275 // Remove from ot list
1276 changed
->removeCollisionOTInfo ();
1278 // Get the primitive world image
1279 CPrimitiveWorldImage
*wI
;
1280 if (changed
->isNonCollisionable())
1281 wI
=changed
->getWorldImage (0);
1283 wI
=changed
->getWorldImage (worldImage
);
1286 changed
=wI
->getNextModified ();
1290 // ***************************************************************************
1292 CCollisionOTDynamicInfo
*CMoveContainer::allocateOTDynamicInfo ()
1294 return _AllocOTDynamicInfo
.allocate ();
1297 // ***************************************************************************
1299 CCollisionOTStaticInfo
*CMoveContainer::allocateOTStaticInfo ()
1301 return _AllocOTStaticInfo
.allocate ();
1304 // ***************************************************************************
1306 // Free all ordered table info
1307 void CMoveContainer::freeAllOTInfo ()
1309 H_AUTO (NLPACS_Free_All_OT_Info
);
1311 _AllocOTDynamicInfo
.freeBlock ();
1312 _AllocOTStaticInfo
.freeBlock ();
1315 // ***************************************************************************
1317 CMovePrimitive
*CMoveContainer::allocatePrimitive (uint8 firstWorldImage
, uint8 numWorldImage
)
1320 return new CMovePrimitive (this, firstWorldImage
, numWorldImage
);
1323 // ***************************************************************************
1325 void CMoveContainer::freePrimitive (CMovePrimitive
*primitive
)
1327 // Simply deallocate
1331 // ***************************************************************************
1333 CPrimitiveWorldImage
**CMoveContainer::allocateWorldImagesPtrs (uint numPtrs
)
1335 return new CPrimitiveWorldImage
*[numPtrs
];
1338 // ***************************************************************************
1340 void CMoveContainer::freeWorldImagesPtrs (CPrimitiveWorldImage
**ptrs
)
1345 // ***************************************************************************
1347 CPrimitiveWorldImage
*CMoveContainer::allocateWorldImage ()
1349 return new CPrimitiveWorldImage
;
1352 // ***************************************************************************
1354 void CMoveContainer::freeWorldImage (CPrimitiveWorldImage
*worldImage
)
1359 // ***************************************************************************
1361 CMoveElement
*CMoveContainer::allocateMoveElement ()
1364 return new CMoveElement
;
1367 // ***************************************************************************
1369 void CMoveContainer::freeMoveElement (CMoveElement
*element
)
1371 // Simply deallocate
1375 // ***************************************************************************
1377 void UMoveContainer::deleteMoveContainer (UMoveContainer
*container
)
1379 delete (CMoveContainer
*)container
;
1382 // ***************************************************************************
1384 UMovePrimitive
*CMoveContainer::addCollisionablePrimitive (uint8 firstWorldImage
, uint8 numWorldImage
, const UMovePrimitive
*copyFrom
)
1387 // Allocate primitive
1388 CMovePrimitive
*primitive
=allocatePrimitive (firstWorldImage
, numWorldImage
);
1391 _PrimitiveSet
.insert (primitive
);
1393 // if copy from primitive is not null, copy attributes
1394 if (copyFrom
!= NULL
)
1396 primitive
->setPrimitiveType(copyFrom
->getPrimitiveType());
1397 primitive
->setReactionType(copyFrom
->getReactionType());
1398 primitive
->setTriggerType(copyFrom
->getTriggerType());
1399 primitive
->setCollisionMask(copyFrom
->getCollisionMask());
1400 primitive
->setOcclusionMask(copyFrom
->getOcclusionMask());
1401 primitive
->setObstacle(copyFrom
->getObstacle());
1402 primitive
->setAbsorbtion(copyFrom
->getAbsorbtion());
1403 primitive
->setHeight(copyFrom
->getHeight());
1404 if (primitive
->getPrimitiveType() == UMovePrimitive::_2DOrientedBox
)
1406 float width
=0.0f
, height
=0.0f
;
1407 copyFrom
->getSize(width
, height
);
1408 primitive
->setSize(width
, height
);
1412 primitive
->setRadius(copyFrom
->getRadius());
1420 // ***************************************************************************
1422 UMovePrimitive
*CMoveContainer::addNonCollisionablePrimitive (const UMovePrimitive
*copyFrom
)
1425 // Allocate primitive
1426 CMovePrimitive
*primitive
=allocatePrimitive (0, 1);
1428 // Set as noncollisionable
1429 primitive
->setNonCollisionable (true);
1432 _PrimitiveSet
.insert (primitive
);
1434 // if copy from primitive is not null, copy attributes
1435 if (copyFrom
!= NULL
)
1437 primitive
->setPrimitiveType(copyFrom
->getPrimitiveType());
1438 primitive
->setReactionType(copyFrom
->getReactionType());
1439 primitive
->setTriggerType(copyFrom
->getTriggerType());
1440 primitive
->setCollisionMask(copyFrom
->getCollisionMask());
1441 primitive
->setOcclusionMask(copyFrom
->getOcclusionMask());
1442 primitive
->setObstacle(copyFrom
->getObstacle());
1443 primitive
->setAbsorbtion(copyFrom
->getAbsorbtion());
1444 primitive
->setHeight(copyFrom
->getHeight());
1445 if (primitive
->getPrimitiveType() == UMovePrimitive::_2DOrientedBox
)
1447 float width
=0.0f
, height
=0.0f
;
1448 copyFrom
->getSize(width
, height
);
1449 primitive
->setSize(width
, height
);
1453 primitive
->setRadius(copyFrom
->getRadius());
1461 // ***************************************************************************
1463 void CMoveContainer::removePrimitive (UMovePrimitive
* primitive
)
1466 // CMovePrimitive pointer
1467 CMovePrimitive
*prim
=(CMovePrimitive
*)primitive
;
1469 // Get the primitive world image
1470 for (uint8 i
=0; i
<prim
->getNumWorldImage (); i
++)
1473 uint8 worldImage
=prim
->getFirstWorldImage ()+i
;
1475 // Get primitive world image
1476 CPrimitiveWorldImage
*wI
=prim
->getWorldImage (worldImage
);
1478 // In modified list ?
1479 if (wI
->isInModifiedListFlag ())
1481 // Non collisionable primitive ?
1482 if (prim
->isNonCollisionable())
1484 // Remove from all world image
1485 removeNCFromModifiedList (prim
, worldImage
);
1489 // Remove from modified list
1490 removeFromModifiedList (prim
, worldImage
);
1495 // Remove from the set
1496 _PrimitiveSet
.erase (prim
);
1499 freePrimitive (prim
);
1502 // ***************************************************************************
1504 void CMoveContainer::removeNCFromModifiedList (CMovePrimitive
* primitive
, uint8 worldImage
)
1506 // For each world image
1508 uint worldImageCount
= (uint
)_ChangedRoot
.size();
1509 for (i
=0; i
<worldImageCount
; i
++)
1511 // For each changed primitives
1512 CMovePrimitive
*changed
=_ChangedRoot
[i
];
1513 CPrimitiveWorldImage
*previous
=NULL
;
1514 CPrimitiveWorldImage
*wI
=primitive
->getWorldImage (worldImage
);
1518 // Get the primitive world image
1519 CPrimitiveWorldImage
*changedWI
=changed
->getWorldImage (worldImage
);
1521 // Remove from ot list
1522 if (changed
==primitive
)
1524 // There is a previous primitive ?
1526 previous
->linkInModifiedList (wI
->getNextModified ());
1528 _ChangedRoot
[i
]=wI
->getNextModified ();
1531 wI
->linkInModifiedList (NULL
);
1532 wI
->setInModifiedListFlag (false);
1538 changed
=changedWI
->getNextModified ();
1542 if (changed
==primitive
)
1547 // ***************************************************************************
1549 void CMoveContainer::removeFromModifiedList (CMovePrimitive
* primitive
, uint8 worldImage
)
1551 // For each changed primitives
1552 CMovePrimitive
*changed
=_ChangedRoot
[worldImage
];
1553 CPrimitiveWorldImage
*previous
=NULL
;
1554 CPrimitiveWorldImage
*wI
=primitive
->getWorldImage (worldImage
);
1558 // Get the primitive world image
1559 CPrimitiveWorldImage
*changedWI
=changed
->getWorldImage (worldImage
);
1561 // Remove from ot list
1562 if (changed
==primitive
)
1564 // There is a previous primitive ?
1566 previous
->linkInModifiedList (wI
->getNextModified ());
1568 _ChangedRoot
[worldImage
]=wI
->getNextModified ();
1571 wI
->linkInModifiedList (NULL
);
1572 wI
->setInModifiedListFlag (false);
1578 changed
=changedWI
->getNextModified ();
1582 // ***************************************************************************
1584 void CMoveContainer::unlinkMoveElement (CMoveElement
*element
, uint8 worldImage
)
1587 nlassert (element
->X
<_CellCountWidth
);
1588 nlassert (element
->Y
<_CellCountHeight
);
1591 CMoveCell
&cell
=_VectorCell
[worldImage
][element
->X
+element
->Y
*_CellCountWidth
];
1592 cell
.unlinkX (element
);
1593 //cell.unlinkY (element);
1596 // ***************************************************************************
1598 void CMoveContainer::reaction (const CCollisionOTInfo
& first
)
1600 // H_AUTO(PACS_MC_reaction);
1602 // Static collision ?
1603 if (first
.isCollisionAgainstStatic())
1606 nlassert (_Retriever
);
1609 const CCollisionOTStaticInfo
*staticInfo
=safe_cast
<const CCollisionOTStaticInfo
*> (&first
);
1611 // Get the primitive world image
1612 CMovePrimitive
*movePrimitive
=staticInfo
->getPrimitive ();
1613 CPrimitiveWorldImage
*wI
;
1614 if (movePrimitive
->isNonCollisionable ())
1615 wI
=movePrimitive
->getWorldImage (0);
1617 wI
=movePrimitive
->getWorldImage (staticInfo
->getWorldImage());
1619 // Dynamic collision
1620 wI
->reaction ( staticInfo
->getCollisionDesc (), staticInfo
->getGlobalPosition (),
1621 *_Retriever
, staticInfo
->getDeltaTime(), _DeltaTime
, *staticInfo
->getPrimitive (), *this, staticInfo
->getWorldImage());
1626 const CCollisionOTDynamicInfo
*dynInfo
=safe_cast
<const CCollisionOTDynamicInfo
*> (&first
);
1628 // Get the primitives world image
1629 CPrimitiveWorldImage
*firstWI
;
1630 if (dynInfo
->getFirstPrimitive ()->isNonCollisionable ())
1631 firstWI
=dynInfo
->getFirstPrimitive ()->getWorldImage (0);
1633 firstWI
=dynInfo
->getFirstPrimitive ()->getWorldImage (dynInfo
->getFirstWorldImage());
1635 CPrimitiveWorldImage
*secondWI
;
1636 if (dynInfo
->getSecondPrimitive ()->isNonCollisionable ())
1637 secondWI
=dynInfo
->getSecondPrimitive ()->getWorldImage (0);
1639 secondWI
=dynInfo
->getSecondPrimitive ()->getWorldImage (dynInfo
->getSecondWorldImage());
1641 // Dynamic collision
1642 firstWI
->reaction ( *secondWI
, dynInfo
->getCollisionDesc (), _Retriever
, _SurfaceTemp
, dynInfo
->isCollision(),
1643 *dynInfo
->getFirstPrimitive (), *dynInfo
->getSecondPrimitive (), this, dynInfo
->getFirstWorldImage(),
1644 dynInfo
->getSecondWorldImage(), dynInfo
->isSecondStatic());
1648 * For collisionnable primitives, trigger are raised here (in reaction) because
1649 * this is the moment we are sure the collision happened.
1651 * For non collisionable primitves, the trigger is raised at collision time because without OT,
1652 * we can't stop evaluating collision on triggers.
1654 if (dynInfo
->getFirstPrimitive ()->isCollisionable ())
1656 if (dynInfo
->getFirstPrimitive ()->isTriggered (*dynInfo
->getSecondPrimitive (), dynInfo
->isEnter(), dynInfo
->isExit()))
1658 if (dynInfo
->isEnter())
1659 newTrigger (dynInfo
->getFirstPrimitive (), dynInfo
->getSecondPrimitive (), dynInfo
->getCollisionDesc (), UTriggerInfo::In
);
1660 if (dynInfo
->isExit())
1661 newTrigger (dynInfo
->getFirstPrimitive (), dynInfo
->getSecondPrimitive (), dynInfo
->getCollisionDesc (), UTriggerInfo::Out
);
1662 if (dynInfo
->isInside())
1663 newTrigger (dynInfo
->getFirstPrimitive (), dynInfo
->getSecondPrimitive (), dynInfo
->getCollisionDesc (), UTriggerInfo::Inside
);
1669 // ***************************************************************************
1671 void CMoveContainer::setAsStatic (uint8 worldImage
)
1674 // Add this world image in the static set of world image
1675 _StaticWorldImage
.insert (worldImage
);
1678 // ***************************************************************************
1680 void CMoveContainer::duplicateWorldImage (uint8 source
, uint8 dest
)
1684 uint cellCount
=_CellCountWidth
*_CellCountHeight
;
1686 // Clear dest modified list
1687 clearModifiedList (dest
);
1689 // Clear destination cells
1691 for (i
=0; i
<cellCount
; i
++)
1695 while ((elm
=_VectorCell
[dest
][i
].getFirstX ()))
1697 // Get primitive world image
1698 CPrimitiveWorldImage
*wI
=elm
->Primitive
->getWorldImage (dest
);
1700 // Remove the primitive
1704 if (wI
->getMoveElement(i
))
1705 wI
->removeMoveElement (i
, *this, dest
);
1710 // Duplicate destination cells
1711 for (i
=0; i
<cellCount
; i
++)
1714 CMoveElement
*elm
=_VectorCell
[source
][i
].getFirstX ();
1717 // Get primitive world image
1718 CPrimitiveWorldImage
*wISource
=elm
->Primitive
->getWorldImage (source
);
1719 CPrimitiveWorldImage
*wIDest
=elm
->Primitive
->getWorldImage (dest
);
1721 // First time the primitive is visited ?
1722 if (wIDest
->getMoveElement (0)==NULL
)
1724 wIDest
->copy (*wISource
);
1727 // Add at the end of the list
1728 wIDest
->addMoveElementendOfList (_VectorCell
[dest
][i
], elm
->X
, elm
->Y
, elm
->Primitive
, *this);
1731 nlassert (wIDest
->getMoveElement (0)!=NULL
);
1739 // ***************************************************************************
1741 UMoveContainer
*UMoveContainer::createMoveContainer (double xmin
, double ymin
, double xmax
, double ymax
,
1742 uint widthCellCount
, uint heightCellCount
, double primitiveMaxSize
, uint8 numWorldImage
,
1743 uint maxIteration
, uint otSize
)
1746 // Create a CMoveContainer
1747 return new CMoveContainer (xmin
, ymin
, xmax
, ymax
, widthCellCount
, heightCellCount
, primitiveMaxSize
, numWorldImage
, maxIteration
, otSize
);
1750 // ***************************************************************************
1752 UMoveContainer
*UMoveContainer::createMoveContainer (UGlobalRetriever
* retriever
, uint widthCellCount
,
1753 uint heightCellCount
, double primitiveMaxSize
, uint8 numWorldImage
, uint maxIteration
, uint otSize
)
1757 nlassert (dynamic_cast<CGlobalRetriever
*>(retriever
));
1758 CGlobalRetriever
* r
=static_cast<CGlobalRetriever
*>(retriever
);
1760 // Create a CMoveContainer
1761 return new CMoveContainer (r
, widthCellCount
, heightCellCount
, primitiveMaxSize
, numWorldImage
, maxIteration
, otSize
);
1764 // ***************************************************************************
1766 void UCollisionDesc::serial (NLMISC::IStream
& stream
)
1768 stream
.serial (ContactPosition
);
1769 stream
.serial (ContactNormal0
);
1770 stream
.serial (ContactNormal1
);
1771 stream
.serial (ContactTime
);
1774 // ***************************************************************************
1776 void UTriggerInfo::serial (NLMISC::IStream
& stream
)
1778 stream
.serial (Object0
);
1779 stream
.serial (Object1
);
1780 stream
.serial (CollisionDesc
);
1785 // ***************************************************************************
1786 void CMoveContainer::addCollisionnablePrimitiveBlock(UPrimitiveBlock
*pb
,uint8 firstWorldImage
,uint8 numWorldImage
,std::vector
<UMovePrimitive
*> *primitives
,float orientation
,const NLMISC::CVector
&position
, bool dontSnapToGround
/* = false*/, const NLMISC::CVector
&scale
/* = NLMISC::CVector(1.0f, 1.0f, 1.0f)*/)
1789 CPrimitiveBlock
*block
= NLMISC::safe_cast
<CPrimitiveBlock
*>(pb
);
1790 // Reserve the pointer array
1792 primitives
->reserve (block
->Primitives
.size());
1794 // For each primitive
1796 for (prim
=0; prim
<block
->Primitives
.size(); prim
++)
1798 // Create a collisionable primitive
1799 UMovePrimitive
*primitive
= addCollisionablePrimitive (firstWorldImage
, numWorldImage
);
1801 // Ref on the block descriptor
1802 CPrimitiveDesc
&desc
= block
->Primitives
[prim
];
1804 // Set its properties
1805 primitive
->setPrimitiveType (desc
.Type
);
1806 primitive
->setReactionType (desc
.Reaction
);
1807 primitive
->setTriggerType (desc
.Trigger
);
1808 primitive
->setCollisionMask (desc
.CollisionMask
);
1809 primitive
->setOcclusionMask (desc
.OcclusionMask
);
1810 primitive
->setObstacle (desc
.Obstacle
);
1811 primitive
->setAbsorbtion (desc
.Attenuation
);
1812 primitive
->setDontSnapToGround(dontSnapToGround
);
1813 primitive
->UserData
= desc
.UserData
;
1814 if (desc
.Type
== UMovePrimitive::_2DOrientedBox
)
1816 // ONLY ASSUME UNIFORM SCALE ON X/Y
1817 primitive
->setSize (desc
.Length
[0]*scale
.x
, desc
.Length
[1]*scale
.x
);
1821 // ONLY ASSUME UNIFORM SCALE ON X/Y
1822 nlassert (desc
.Type
== UMovePrimitive::_2DOrientedCylinder
);
1823 primitive
->setRadius (desc
.Length
[0]*scale
.x
);
1825 primitive
->setHeight (desc
.Height
*scale
.z
);
1827 // Insert the primitives
1829 // For each world image
1831 for (wI
=firstWorldImage
; wI
<(uint
)(firstWorldImage
+numWorldImage
); wI
++)
1833 // Insert the primitive
1834 primitive
->insertInWorldImage (uint8(wI
));
1837 float cosa
= (float) cos (orientation
);
1838 float sina
= (float) sin (orientation
);
1840 finalPos
.x
= cosa
* desc
.Position
.x
* scale
.x
- sina
* desc
.Position
.y
* scale
.y
+ position
.x
;
1841 finalPos
.y
= sina
* desc
.Position
.x
* scale
.x
+ cosa
* desc
.Position
.y
* scale
.y
+ position
.y
;
1842 finalPos
.z
= desc
.Position
.z
*scale
.z
+ position
.z
;
1844 // Set the primtive orientation
1845 if (desc
.Type
== UMovePrimitive::_2DOrientedBox
)
1846 primitive
->setOrientation ((float)fmod ((float)(desc
.Orientation
+ orientation
), (float)(2.0f
*Pi
)), uint8(wI
));
1848 // Set the primitive global position
1849 primitive
->setGlobalPosition (finalPos
, uint8(wI
));
1856 primitives
->push_back (primitive
);
1862 // ***************************************************************************
1864 bool CMoveContainer::loadCollisionablePrimitiveBlock (const char *filename
, uint8 firstWorldImage
, uint8 numWorldImage
, std::vector
<UMovePrimitive
*> *primitives
, float orientation
, const NLMISC::CVector
&position
, bool dontSnapToGround
/*= false*/)
1867 // Check world image
1868 if ( (uint
)(firstWorldImage
+numWorldImage
) > _ChangedRoot
.size() )
1870 nlwarning ("Invalid world image number.");
1874 // Try to load the file
1876 if (file
.open (filename
))
1878 // Create the XML stream
1882 if (input
.init (file
))
1884 // The primitive block
1885 CPrimitiveBlock block
;
1888 file
.serial (block
);
1891 addCollisionnablePrimitiveBlock(&block
, firstWorldImage
, numWorldImage
, primitives
, orientation
, position
, dontSnapToGround
);
1898 nlwarning ("Can't init XML stream with file %s.", filename
);
1906 nlwarning ("Can't load primitive block %s.", filename
);
1913 // ***************************************************************************
1914 void CMoveContainer::getPrimitives(std::vector
<const UMovePrimitive
*> &dest
) const
1917 dest
.resize(_PrimitiveSet
.size());
1918 std::copy(_PrimitiveSet
.begin(), _PrimitiveSet
.end(), dest
.begin());
1922 // ***************************************************************************
1923 void UMoveContainer::getPACSCoordsFromMatrix(NLMISC::CVector
&pos
,float &angle
,const NLMISC::CMatrix
&mat
)
1926 CVector orient
= mat
.mulVector(NLMISC::CVector::I
);
1929 angle
= orient
.y
>= 0.f
? ::acosf(orient
.x
)
1930 : 2.f
* (float) NLMISC::Pi
- ::acosf(orient
.x
);
1934 // ***************************************************************************
1935 bool CMoveContainer::evalNCPrimitiveCollision (double deltaTime
, UMovePrimitive
*primitive
, uint8 worldImage
)
1944 // Only non-collisionable primitives
1945 if (!primitive
->isCollisionable())
1948 _DeltaTime
=deltaTime
;
1950 // Begin of the time slice to compute
1951 double beginTime
= 0;
1952 double collisionTime
= deltaTime
;
1954 // Get the world image
1955 CPrimitiveWorldImage
*wI
= ((CMovePrimitive
*)primitive
)->getWorldImage (0);
1957 CCollisionOTInfo
*firstCollision
= NULL
;
1960 //nlassert (beginTime < 1.0);
1961 if (beginTime
>= 1.0)
1963 nlwarning("PACS: evalNCPrimitiveCollision() failure, beginTime [%f] >= 1.0", beginTime
);
1967 // Update the primitive
1968 wI
->update (beginTime
, deltaTime
, *(CMovePrimitive
*)primitive
);
1970 CVectorD d0
=wI
->getDeltaPosition();
1972 // Eval collision again the terrain
1973 bool testMoveValid
= false;
1974 CCollisionOTStaticInfo staticColInfo
;
1975 CCollisionOTDynamicInfo dynamicColInfoWI0
;
1976 CCollisionOTDynamicInfo dynamicColInfoWI
;
1978 firstCollision
= NULL
;
1980 // If collision found, note it is on the landscape
1981 if (evalOneTerrainCollision (beginTime
, (CMovePrimitive
*)primitive
, worldImage
, false, testMoveValid
, &staticColInfo
, NULL
))
1983 firstCollision
= &staticColInfo
;
1986 // Eval collision again the static primitives
1987 std::set
<uint8
>::iterator ite
=_StaticWorldImage
.begin();
1988 while (ite
!=_StaticWorldImage
.end())
1990 // Eval in this world image
1991 if (evalOnePrimitiveCollision (beginTime
, (CMovePrimitive
*)primitive
, *ite
, worldImage
, false, true, testMoveValid
, &dynamicColInfoWI0
, NULL
))
1993 // First collision..
1994 if (!firstCollision
|| (firstCollision
->getCollisionTime () > dynamicColInfoWI0
.getCollisionTime ()))
1996 firstCollision
= &dynamicColInfoWI0
;
2005 CVectorD d1
=wI
->getDeltaPosition();
2007 // Eval collision again the world image
2008 if (_StaticWorldImage
.find (worldImage
)==_StaticWorldImage
.end())
2010 if (evalOnePrimitiveCollision (beginTime
, (CMovePrimitive
*)primitive
, worldImage
, worldImage
, false, false, testMoveValid
, &dynamicColInfoWI
, NULL
))
2012 // First collision..
2013 if (!firstCollision
|| (firstCollision
->getCollisionTime () > dynamicColInfoWI
.getCollisionTime ()))
2015 firstCollision
= &dynamicColInfoWI
;
2021 CVectorD d2
=wI
->getDeltaPosition();
2022 nlassert ((d0
==d1
)&&(d0
==d2
));
2030 collisionTime
= firstCollision
->getCollisionTime ();
2031 reaction (*firstCollision
);
2032 //nlassert (collisionTime != 1);
2034 if (collisionTime
== 1)
2036 nlinfo("PACS: evalNCPrimitiveCollision() failure, collisionTime [%f] == 1", collisionTime
);
2043 if (_Retriever
&&testMoveValid
)
2046 wI
->doMove (*_Retriever
, _SurfaceTemp
, deltaTime
, collisionTime
, ((CMovePrimitive
*)primitive
)->getDontSnapToGround());
2051 wI
->doMove (_DeltaTime
);
2055 beginTime
= collisionTime
;
2057 while (firstCollision
);