Definition in file move_container.cpp.
#include "stdpacs.h"
#include "pacs/move_primitive.h"
#include "pacs/move_element.h"
#include "pacs/primitive_block.h"
#include "nel/misc/hierarchical_timer.h"
#include "nel/misc/i_xml.h"
#include <math.h>
#include <float.h>
Go to the source code of this file.
Defines | |
#define | NELPACS_ALLOC_DYNAMIC_INFO 100 |
#define | NELPACS_ALLOC_STATIC_INFO 100 |
#define | NLPACS_HAUTO_EVAL_COLLISION H_AUTO_USE ( NLPACS_Eval_Collision ) |
Functions | |
H_AUTO_DECL (NLPACS_Eval_Collision) namespace NLPACS |
|
Definition at line 40 of file move_container.cpp. |
|
Definition at line 41 of file move_container.cpp. |
|
Referenced by H_AUTO_DECL(). |
|
Definition at line 43 of file move_container.cpp. References file, NLMISC::CMatrix::getPos(), H_AUTO, height, index, min, NLMISC::CMatrix::mulVector(), NELPACS_CONTAINER_TRIGGER_DEFAULT_SIZE, NELPACS_DIST_BACK, nlassert, NLPACS_HAUTO_EVAL_COLLISION, nlwarning, NLMISC::CVector::normalize(), NLMISC::Pi, r, NLMISC::IStream::serial(), sint, size, uint, uint16, uint8, width, x, NLMISC::CVector::x, y, NLMISC::CVector::y, and NLMISC::CVector::z.
00048 : 00049 00050 // Non collisionnable primitive 00051 Their moves are evaluate one by one with evalNCPrimitiveCollision(). 00052 If a collision is found, reaction() is called. 00053 00054 // Collisionnable primitives 00055 Each primitive must be moved first with the move() method. 00056 Their moves are evaluate all at once. All the collisions found are time sorted in a time orderin table (_TimeOT). 00057 While the table is not empty, the first collision occured in time is solved and 00058 If a collision is found, reaction() is called. 00059 00060 00061 ****************************************************************************/ 00062 00063 namespace NLPACS 00064 { 00065 00066 // *************************************************************************** 00067 00068 CMoveContainer::~CMoveContainer () 00069 { 00070 clear (); 00071 } 00072 00073 // *************************************************************************** 00074 00075 void CMoveContainer::clear () 00076 { 00077 // Clear all primitives 00078 std::set<CMovePrimitive*>::iterator ite=_PrimitiveSet.begin(); 00079 while (ite!=_PrimitiveSet.end ()) 00080 { 00081 freePrimitive (*ite); 00082 ite++; 00083 } 00084 00085 // Clear primitive set 00086 _PrimitiveSet.clear (); 00087 00088 // Clear root changed 00089 _ChangedRoot.clear (); 00090 00091 // Clear static world image set 00092 _StaticWorldImage.clear (); 00093 00094 // Clear cell array 00095 _VectorCell.clear (); 00096 00097 // Clear time ot 00098 _TimeOT.clear (); 00099 } 00100 00101 // *************************************************************************** 00102 00103 void CMoveContainer::init (double xmin, double ymin, double xmax, double ymax, uint widthCellCount, uint heightCellCount, 00104 double primitiveMaxSize, uint8 numWorldImage, uint maxIteration, uint otSize) 00105 { 00106 // Clear arrays 00107 clear (); 00108 00109 // Create world images 00110 _ChangedRoot.resize (numWorldImage); 00111 for (uint i=0; i<numWorldImage; i++) 00112 _ChangedRoot[i]=NULL; 00113 00114 // Not in test mode 00115 _Retriever=NULL; 00116 00117 // Element size 00118 _PrimitiveMaxSize=primitiveMaxSize; 00119 00120 // BB 00121 _Xmin=xmin; 00122 _Ymin=ymin; 00123 _Xmax=xmax; 00124 _Ymax=ymax; 00125 00126 // Cells count 00127 _CellCountWidth=widthCellCount; 00128 _CellCountHeight=heightCellCount; 00129 00130 // Cells size 00131 _CellWidth=(_Xmax - _Xmin)/(double)_CellCountWidth; 00132 _CellHeight=(_Ymax - _Ymin)/(double)_CellCountHeight; 00133 00134 // Cell array 00135 _VectorCell.resize (numWorldImage); 00136 for (uint j=0; j<numWorldImage; j++) 00137 _VectorCell[j].resize (_CellCountWidth * _CellCountHeight); 00138 00139 // resize OT 00140 _OtSize=otSize; 00141 _TimeOT.resize (otSize); 00142 00143 // Clear the OT 00144 clearOT (); 00145 00146 // Clear test time 00147 _TestTime=0xffffffff; 00148 _MaxTestIteration=maxIteration; 00149 00150 // Resize trigger array 00151 _Triggers.resize (NELPACS_CONTAINER_TRIGGER_DEFAULT_SIZE); 00152 } 00153 00154 // *************************************************************************** 00155 00156 void CMoveContainer::init (CGlobalRetriever* retriever, uint widthCellCount, uint heightCellCount, double primitiveMaxSize, 00157 uint8 numWorldImage, uint maxIteration, uint otSize) 00158 { 00159 // Get min max of the global retriever BB 00160 CVector min=retriever->getBBox().getMin(); 00161 CVector max=retriever->getBBox().getMax(); 00162 00163 // Setup min max 00164 double xmin=min.x; 00165 double ymin=min.y; 00166 double xmax=max.x; 00167 double ymax=max.y; 00168 00169 // Init 00170 init (xmin, ymin, xmax, ymax, widthCellCount, heightCellCount, primitiveMaxSize, numWorldImage, maxIteration, otSize); 00171 00172 // Init the retriever 00173 _Retriever=retriever; 00174 } 00175 00176 // *************************************************************************** 00177 00178 void CMoveContainer::evalCollision (double deltaTime, uint8 worldImage) 00179 { 00180 NL_ALLOC_CONTEXT( Pacs ) 00181 NLPACS_HAUTO_EVAL_COLLISION 00182 00183 // H_AUTO(PACS_MC_evalCollision); 00184 00185 // New test time 00186 _TestTime++; 00187 00188 // Delta time 00189 _DeltaTime=deltaTime; 00190 00191 // Clear triggers 00192 _Triggers.clear (); 00193 00194 // Update the bounding box and position of modified primitives 00195 updatePrimitives (0.f, worldImage); 00196 00197 #ifdef NL_DEBUG 00198 // Check list integrity 00199 //checkSortedList (); 00200 #endif // NL_DEBUG 00201 00202 // Get first collision 00203 _PreviousCollisionNode = &_TimeOT[0]; 00204 00205 // Eval all collisions 00206 evalAllCollisions (0.f, worldImage); 00207 00208 // Clear modified list 00209 clearModifiedList (worldImage); 00210 00211 // Modified list is empty at this point 00212 nlassert (_ChangedRoot[worldImage]==NULL); 00213 00214 // Previous node is a 'hard' OT node 00215 nlassert (!_PreviousCollisionNode->isInfo()); 00216 00217 // Get next collision 00218 CCollisionOTInfo *nextCollision; 00219 { 00220 H_AUTO (NLPACS_Get_Next_Info); 00221 nextCollision=_PreviousCollisionNode->getNextInfo (); 00222 } 00223 00224 // Collision ? 00225 while (nextCollision) 00226 { 00227 // Get new previous OT hard node 00228 _PreviousCollisionNode=nextCollision->getPrevious (); 00229 00230 // Previous node is a 'hard' OT node 00231 nlassert (!_PreviousCollisionNode->isInfo()); 00232 00233 // Keep this collision 00234 reaction (*nextCollision); 00235 00236 // Remove this collision from ot 00237 if (!nextCollision->isCollisionAgainstStatic ()) 00238 { 00239 // Remove the primitive from OT 00240 nextCollision->unlink(); 00241 00242 CCollisionOTDynamicInfo *info = static_cast<CCollisionOTDynamicInfo*>(nextCollision); 00243 if (info->getFirstPrimitive()) 00244 info->getFirstPrimitive()->removeCollisionOTInfo(info); 00245 if (info->getSecondPrimitive()) 00246 info->getSecondPrimitive()->removeCollisionOTInfo(info); 00247 } 00248 00249 // Last time 00250 double newTime=nextCollision->getCollisionTime (); 00251 00252 // Remove modified objects from the OT 00253 removeModifiedFromOT (worldImage); 00254 00255 // Must have been removed 00256 nlassert (nextCollision->getPrevious ()==NULL); 00257 nlassert (nextCollision->CCollisionOT::getNext ()==NULL); 00258 00259 // Update the bounding box and position of modified primitives 00260 updatePrimitives (newTime, worldImage); 00261 00262 // Eval all collisions of modified objects for the new delta t 00263 evalAllCollisions (newTime, worldImage); 00264 00265 // Clear modified list 00266 clearModifiedList (worldImage); 00267 00268 // Get next collision 00269 nextCollision=_PreviousCollisionNode->getNextInfo (); 00270 } 00271 00272 #ifdef NL_DEBUG 00273 // OT must be cleared 00274 checkOT (); 00275 #endif // NL_DEBUG 00276 00277 // Free ordered table info 00278 freeAllOTInfo (); 00279 00280 // Some init 00281 _PreviousCollisionNode=NULL; 00282 } 00283 00284 // *************************************************************************** 00285 00286 bool CMoveContainer::testMove (UMovePrimitive* primitive, const CVectorD& speed, double deltaTime, uint8 worldImage, CVectorD *contactNormal) 00287 { 00288 NL_ALLOC_CONTEXT( Pacs ) 00289 00290 // H_AUTO(PACS_MC_testMove); 00291 00292 if (contactNormal) 00293 *contactNormal = CVectorD::Null; 00294 00295 // Cast 00296 nlassert (dynamic_cast<CMovePrimitive*>(primitive)); 00297 CMovePrimitive* prim=static_cast<CMovePrimitive*>(primitive); 00298 00299 // New test time 00300 _TestTime++; 00301 00302 // Delta time 00303 _DeltaTime=deltaTime; 00304 00305 // Get the world image primitive 00306 uint8 primitiveWorldImage; 00307 CPrimitiveWorldImage *wI; 00308 if (prim->isNonCollisionable ()) 00309 { 00310 wI=prim->getWorldImage (0); 00311 primitiveWorldImage=worldImage; 00312 } 00313 else 00314 { 00315 wI=prim->getWorldImage (worldImage); 00316 primitiveWorldImage=worldImage; 00317 } 00318 00319 // Backup speed 00320 CVectorD oldSpeed=wI->getSpeed (); 00321 00322 // Set speed 00323 wI->move (speed, *this, *prim, primitiveWorldImage); 00324 00325 // Update the bounding box and position of the primitive 00326 wI->update (0, _DeltaTime, *prim); 00327 00328 // Compute cells overlaped by the primitive 00329 if (!prim->isNonCollisionable ()) 00330 updateCells (prim, worldImage); 00331 00332 #ifdef NL_DEBUG 00333 // Check list integrity 00334 // checkSortedList (); 00335 #endif // NL_DEBUG 00336 00337 // Result 00338 bool result=false; 00339 bool testMoveValid; 00340 00341 // Eval first each static world images 00342 result=evalOneTerrainCollision (0, prim, primitiveWorldImage, true, testMoveValid, NULL, contactNormal); 00343 00344 // Eval first each static world images 00345 if (!result) 00346 { 00347 std::set<uint8>::iterator ite=_StaticWorldImage.begin(); 00348 while (ite!=_StaticWorldImage.end()) 00349 { 00350 00351 // Eval in this world image 00352 result=evalOnePrimitiveCollision (0, prim, *ite, primitiveWorldImage, true, true, testMoveValid, NULL, contactNormal); 00353 00354 // If found, abort 00355 if (result) 00356 break; 00357 00358 // Next world image 00359 ite++; 00360 } 00361 } 00362 00363 // Eval collisions if not found and not tested 00364 if ((!result) && (_StaticWorldImage.find (worldImage)==_StaticWorldImage.end())) 00365 result=evalOnePrimitiveCollision (0, prim, worldImage, primitiveWorldImage, true, false, testMoveValid, NULL, contactNormal); 00366 00367 // Backup speed only if the primitive is inserted in the world image 00368 if (prim->isInserted (primitiveWorldImage)) 00369 wI->move (oldSpeed, *this, *prim, primitiveWorldImage); 00370 00371 #ifdef NL_DEBUG 00372 // OT must be cleared 00373 checkOT (); 00374 #endif // NL_DEBUG 00375 00376 // Free ordered table info 00377 freeAllOTInfo (); 00378 00379 // Some init 00380 _PreviousCollisionNode=NULL; 00381 00382 // Return result 00383 return !result; 00384 } 00385 00386 // *************************************************************************** 00387 00388 void CMoveContainer::updatePrimitives (double beginTime, uint8 worldImage) 00389 { 00390 H_AUTO (NLPACS_Update_Primitives); 00391 00392 // For each changed primitives 00393 CMovePrimitive *changed=_ChangedRoot[worldImage]; 00394 while (changed) 00395 { 00396 // Get the primitive world image 00397 CPrimitiveWorldImage *wI; 00398 if (changed->isNonCollisionable()) 00399 wI=changed->getWorldImage (0); 00400 else 00401 wI=changed->getWorldImage (worldImage); 00402 00403 // Force the build of the bounding box 00404 wI->update (beginTime, _DeltaTime, *changed); 00405 00406 // Is inserted in this world image ? 00407 if (changed->isInserted (worldImage)) 00408 { 00409 00410 // Compute cells overlaped by the primitive 00411 updateCells (changed, worldImage); 00412 } 00413 00414 // Next primitive 00415 changed=wI->getNextModified (); 00416 } 00417 } 00418 00419 // *************************************************************************** 00420 00421 void CMoveContainer::updateCells (CMovePrimitive *primitive, uint8 worldImage) 00422 { 00423 // H_AUTO(PACS_MC_updateCells); 00424 00425 // Get the primitive world image 00426 CPrimitiveWorldImage *wI=primitive->getWorldImage (worldImage); 00427 00428 // Check BB width not too large 00429 if (wI->getBBXMax() - wI->getBBXMin() > _CellWidth) 00430 { 00431 nlwarning ("Primitives have moved more than a cell."); 00432 } 00433 00434 // Check BB height not too large 00435 if (wI->getBBYMax() - wI->getBBYMin() > _CellHeight) 00436 { 00437 nlwarning ("Primitives have moved more than a cell."); 00438 } 00439 00440 // Get coordinate in the cell array 00441 sint minx=(int)floor ((wI->getBBXMin() - _Xmin) / _CellWidth); 00442 sint miny=(int)floor ((wI->getBBYMin() - _Ymin) / _CellHeight); 00443 sint maxx=(int)floor ((wI->getBBXMax() - _Xmin) / _CellWidth); 00444 sint maxy=(int)floor ((wI->getBBYMax() - _Ymin) / _CellHeight); 00445 00446 // Born 00447 if (minx<0) 00448 minx=0; 00449 if (miny<0) 00450 miny=0; 00451 if (maxx>=(int)_CellCountWidth) 00452 maxx=(int)_CellCountWidth-1; 00453 if (maxy>=(int)_CellCountHeight) 00454 maxy=(int)_CellCountHeight-1; 00455 00456 maxx=std::min (minx+1, maxx); 00457 maxy=std::min (miny+1, maxy); 00458 00459 // flags founded 00460 bool found[4]={false, false, false, false}; 00461 00462 // For each old cells 00463 uint i; 00464 for (i=0; i<4; i++) 00465 { 00466 // Element 00467 CMoveElement *elm = wI->getMoveElement (i); 00468 00469 // Old element in this cell ? 00470 if ( elm ) 00471 { 00472 // Check 00473 nlassert (elm->X<_CellCountWidth); 00474 nlassert (elm->Y<_CellCountHeight); 00475 00476 // Must remove it ? 00477 if ( (elm->X < minx) || (elm->X > maxx) || (elm->Y < miny) || (elm->Y > maxy) ) 00478 { 00479 // Yes remove it 00480 wI->removeMoveElement (i, *this, worldImage); 00481 } 00482 else 00483 { 00484 // Checks 00485 nlassert (((elm->X - minx)==0)||((elm->X - minx)==1)); 00486 nlassert (((elm->Y - miny)==0)||((elm->Y - miny)==1)); 00487 00488 // Update position 00489 #ifndef TEST_CELL 00490 _VectorCell[worldImage][elm->X+elm->Y*_CellCountWidth].updateSortedLists (elm, worldImage); 00491 #endif 00492 00493 // Check found cells 00494 found[ elm->X - minx + ((elm->Y - miny) << (maxx-minx)) ]=true; 00495 } 00496 } 00497 } 00498 00499 // For each case selected 00500 int x, y; 00501 i=0; 00502 for (y=miny; y<=(int)maxy; y++) 00503 for (x=minx; x<=(int)maxx; x++) 00504 { 00505 // Check the formula 00506 nlassert ((int)i == (x - minx + ((y - miny) << (maxx-minx)) )); 00507 00508 // If the cell is not found 00509 if (!found[i]) 00510 { 00511 // Center of the cell 00512 double cx=((double)x+0.5f)*_CellWidth+_Xmin; 00513 double cy=((double)y+0.5f)*_CellHeight+_Ymin; 00514 00515 // Add it in the list 00516 wI->addMoveElement (_VectorCell[worldImage][x+y*_CellCountWidth], (uint16)x, (uint16)y, cx, cy, primitive, *this, worldImage); 00517 } 00518 00519 // Next cell 00520 i++; 00521 } 00522 } 00523 00524 // *************************************************************************** 00525 00526 void CMoveContainer::getCells (CMovePrimitive *primitive, uint8 worldImage, uint8 primitiveWorldImage, CMoveElement **elementArray) 00527 { 00528 // H_AUTO(PACS_MC_getCells); 00529 00530 // Get the primitive world image 00531 CPrimitiveWorldImage *wI; 00532 if (primitive->isNonCollisionable()) 00533 wI=primitive->getWorldImage (0); 00534 else 00535 wI=primitive->getWorldImage (primitiveWorldImage); 00536 00537 // Check BB width not too large 00538 if (wI->getBBXMax() - wI->getBBXMin() > _CellWidth) 00539 { 00540 nlwarning ("Primitives have moved more than a cell."); 00541 } 00542 00543 // Check BB height not too large 00544 if (wI->getBBYMax() - wI->getBBYMin() > _CellHeight) 00545 { 00546 nlwarning ("Primitives have moved more than a cell."); 00547 } 00548 00549 // Get coordinate in the cell array 00550 int minx=(int)floor ((wI->getBBXMin() - _Xmin) / _CellWidth); 00551 int miny=(int)floor ((wI->getBBYMin() - _Ymin) / _CellHeight); 00552 int maxx=(int)floor ((wI->getBBXMax() - _Xmin) / _CellWidth); 00553 int maxy=(int)floor ((wI->getBBYMax() - _Ymin) / _CellHeight); 00554 00555 // Born 00556 if (minx<0) 00557 minx=0; 00558 if (miny<0) 00559 miny=0; 00560 if (maxx>=(int)_CellCountWidth) 00561 maxx=(int)_CellCountWidth-1; 00562 if (maxy>=(int)_CellCountHeight) 00563 maxy=(int)_CellCountHeight-1; 00564 00565 maxx=std::min (minx+1, maxx); 00566 maxy=std::min (miny+1, maxy); 00567 00568 // For each case selected 00569 int x, y; 00570 int i=0; 00571 for (y=miny; y<=(int)maxy; y++) 00572 for (x=minx; x<=(int)maxx; x++) 00573 { 00574 // Check the formula 00575 nlassert ((int)i == (x - minx + ((y - miny) << (maxx-minx)) )); 00576 00577 // Center of the cell 00578 double cx=((double)x+0.5f)*_CellWidth+_Xmin; 00579 00580 // Primitive center 00581 double pcx=(wI->getBBXMin()+wI->getBBXMax())/2.f; 00582 00583 elementArray[i]->Primitive=primitive; 00584 elementArray[i]->X=x; 00585 elementArray[i]->Y=y; 00586 // Insert in left or right ? 00587 if (pcx<cx) 00588 { 00589 // In the left 00590 elementArray[i]->NextX=_VectorCell[worldImage][x+y*_CellCountWidth].getFirstX (); 00591 elementArray[i]->PreviousX=NULL; 00592 } 00593 else 00594 { 00595 // In the right 00596 elementArray[i]->PreviousX=_VectorCell[worldImage][x+y*_CellCountWidth].getLastX (); 00597 elementArray[i]->NextX=NULL; 00598 } 00599 00600 // Next cell 00601 i++; 00602 } 00603 00604 // Erase last array element 00605 for (; i<4; i++) 00606 { 00607 elementArray[i]=NULL; 00608 } 00609 } 00610 00611 // *************************************************************************** 00612 00613 void CMoveContainer::clearModifiedList (uint8 worldImage) 00614 { 00615 H_AUTO (NLPACS_Clear_Modified_List); 00616 00617 // For each changed primitives 00618 CMovePrimitive *changed=_ChangedRoot[worldImage]; 00619 while (changed) 00620 { 00621 // Get the world image primitive 00622 CPrimitiveWorldImage *wI; 00623 if (changed->isNonCollisionable()) 00624 wI=changed->getWorldImage (0); 00625 else 00626 wI=changed->getWorldImage (worldImage); 00627 00628 // Next primitive 00629 changed=wI->getNextModified (); 00630 00631 // Remove it from the list 00632 wI->setInModifiedListFlag (false); 00633 } 00634 00635 // Empty list 00636 _ChangedRoot[worldImage]=NULL; 00637 } 00638 00639 // *************************************************************************** 00640 00641 void CMoveContainer::checkSortedList () 00642 { 00643 // Check each primitives in the set 00644 std::set<CMovePrimitive*>::iterator ite=_PrimitiveSet.begin(); 00645 while (ite!=_PrimitiveSet.end()) 00646 { 00647 // Check 00648 (*ite)->checkSortedList (); 00649 00650 ite++; 00651 } 00652 } 00653 00654 // *************************************************************************** 00655 00656 bool CMoveContainer::evalOneTerrainCollision (double beginTime, CMovePrimitive *primitive, uint8 primitiveWorldImage, 00657 bool testMove, bool &testMoveValid, CCollisionOTStaticInfo *staticColInfo, CVectorD *contactNormal) 00658 { 00659 // H_AUTO(PACS_MC_evalOneCollision); 00660 H_AUTO(NLPACS_Eval_One_Terrain_Collision); 00661 00662 // Find its collisions 00663 bool found=false; 00664 00665 // Get the primitive world image 00666 CPrimitiveWorldImage *wI; 00667 if (primitive->isNonCollisionable()) 00668 wI=primitive->getWorldImage (0); 00669 else 00670 wI=primitive->getWorldImage (primitiveWorldImage); 00671 00672 // Begin time must be the same as beginTime 00673 //nlassert (wI->getInitTime()==beginTime); 00674 if (wI->getInitTime() != beginTime) 00675 { 00676 nlwarning("PACS: evalOneTerrainCollision() failure, wI->getInitTime() [%f] != beginTime [%f]", wI->getInitTime(), beginTime); 00677 return false; 00678 } 00679 00680 // Test its static collision 00681 if (_Retriever) 00682 { 00683 // Delta pos.. 00684 // Test retriever with the primitive 00685 const TCollisionSurfaceDescVector *result=wI->evalCollision (*_Retriever, _SurfaceTemp, _TestTime, _MaxTestIteration, *primitive); 00686 if (result) 00687 { 00688 // TEST MOVE MUST BE OK !! 00689 testMoveValid=true; 00690 00691 // Size of the array 00692 uint size=result->size(); 00693 00694 // For each detected collisions 00695 for (uint c=0; c<size; c++) 00696 { 00697 // Ref on the collision 00698 CCollisionSurfaceDesc desc=(*result)[c]; 00699 double contactTime = (_DeltaTime-beginTime)*desc.ContactTime+beginTime; 00700 00701 /* 00702 * If beginTime is 0.999999999 and desc.ContactTime<1.0, contactTime will be 1.0. 00703 * In this case, we force contactTime to be beginTime to avoid collision at time == 1.0. 00704 **/ 00705 if ((contactTime >= 1.0) && (beginTime < 1.0) && (desc.ContactTime < 1.0)) 00706 contactTime = beginTime; 00707 00708 // Set the container's time space contact time 00709 desc.ContactTime = contactTime; 00710 00711 // ptr on the surface 00712 const CRetrievableSurface *surf= _Retriever->getSurfaceById (desc.ContactSurface); 00713 00714 // TODO: check surface flags against primitive flags HERE: 00715 // Is a wall ? 00716 bool isWall; 00717 if(!surf) 00718 isWall= true; 00719 else 00720 isWall= !(surf->isFloor() || surf->isCeiling()); 00721 00722 // stop on a wall. 00723 if(isWall) 00724 { 00725 // Test move ? 00726 if (testMove) 00727 { 00728 // return contact normal only when testmove and vector provided 00729 if (contactNormal) 00730 *contactNormal = desc.ContactNormal; 00731 return true; 00732 } 00733 else 00734 { 00735 // OK, collision if we are a collisionable primitive 00736 newCollision (primitive, desc, primitiveWorldImage, beginTime, staticColInfo); 00737 00738 // One collision found 00739 found=true; 00740 break; 00741 } 00742 } 00743 } 00744 } 00745 else 00746 // More than maxtest made, exit 00747 return false; 00748 } 00749 return found; 00750 } 00751 00752 // *************************************************************************** 00753 00754 bool CMoveContainer::evalOnePrimitiveCollision (double beginTime, CMovePrimitive *primitive, uint8 worldImage, uint8 primitiveWorldImage, 00755 bool testMove, bool secondIsStatic, bool &testMoveValid, CCollisionOTDynamicInfo *dynamicColInfo, 00756 CVectorD *contactNormal) 00757 { 00758 // H_AUTO(PACS_MC_evalOneCollision); 00759 H_AUTO(NLPACS_Eval_One_Primitive_Collision); 00760 00761 // Find its collisions 00762 bool found=false; 00763 00764 // Get the primitive world image 00765 CPrimitiveWorldImage *wI; 00766 if (primitive->isNonCollisionable()) 00767 wI=primitive->getWorldImage (0); 00768 else 00769 wI=primitive->getWorldImage (primitiveWorldImage); 00770 00771 // Begin time must be the same as beginTime 00772 //nlassert (wI->getInitTime()==beginTime); 00773 if (wI->getInitTime() != beginTime) 00774 { 00775 nlwarning("PACS: evalOnePrimitiveCollision() failure, wI->getInitTime() [%f] != beginTime [%f]", wI->getInitTime(), beginTime); 00776 return false; 00777 } 00778 00779 // Element table 00780 CMoveElement tableNotInserted[4]; 00781 CMoveElement *table[4]; 00782 00783 // Single test ? 00784 bool singleTest=testMove; 00785 00786 // Is in world image 00787 if ((worldImage==primitiveWorldImage) && wI->isInWorldImageFlag()) 00788 { 00789 // Get move element table from the primitive 00790 table[0]=wI->getMoveElement (0); 00791 table[1]=wI->getMoveElement (1); 00792 table[2]=wI->getMoveElement (2); 00793 table[3]=wI->getMoveElement (3); 00794 } 00795 else 00796 { 00797 // Set table pointers 00798 table[0]=tableNotInserted+0; 00799 table[1]=tableNotInserted+1; 00800 table[2]=tableNotInserted+2; 00801 table[3]=tableNotInserted+3; 00802 00803 // Get cells 00804 getCells (primitive, worldImage, primitiveWorldImage, table); 00805 00806 // Force the test 00807 singleTest=true; 00808 } 00809 00810 // For each move element 00811 for (uint i=0; i<4; i++) 00812 { 00813 // Get the element 00814 CMoveElement *elm=table[i]; 00815 00816 // Element valid ? 00817 if (elm) 00818 { 00819 // Check 00820 nlassert (elm->Primitive==primitive); 00821 // Primitive to the left 00822 00823 // Lookup in X sorted list on the left 00824 CMoveElement *other=elm->PreviousX; 00825 nlassert (other!=elm); 00826 00827 while (other && (wI->getBBXMin() - other->Primitive->getWorldImage(worldImage)->getBBXMin() < _PrimitiveMaxSize) ) 00828 { 00829 // Other primitive 00830 CMovePrimitive *otherPrimitive=other->Primitive; 00831 CPrimitiveWorldImage *otherWI=otherPrimitive->getWorldImage (worldImage); 00832 nlassert (otherPrimitive!=primitive); 00833 00834 // Continue the check if the other primitive is not int the modified list or if its pointer is higher than primitive 00835 if ( singleTest || ( (!otherWI->isInModifiedListFlag ()) || (primitive<otherPrimitive) ) ) 00836 { 00837 // Look if valid in X 00838 if (wI->getBBXMin() < otherWI->getBBXMax()) 00839 { 00840 // Look if valid in Y 00841 if ( (wI->getBBYMin() < otherWI->getBBYMax()) && (otherWI->getBBYMin() < wI->getBBYMax()) ) 00842 { 00843 // If not already in collision with this primitive 00844 if (!primitive->isInCollision (otherPrimitive)) 00845 { 00846 if (evalPrimAgainstPrimCollision (beginTime, primitive, otherPrimitive, wI, otherWI, testMove, 00847 primitiveWorldImage, worldImage, secondIsStatic, dynamicColInfo, contactNormal)) 00848 { 00849 if (testMove) 00850 return true; 00851 found=true; 00852 } 00853 } 00854 } 00855 } 00856 } 00857 00858 // Next primitive to the left 00859 other = other->PreviousX; 00860 } 00861 00862 // Lookup in X sorted list on the right 00863 other=elm->NextX; 00864 00865 // Primitive to the right 00866 while (other && (other->Primitive->getWorldImage(worldImage)->getBBXMin() < wI->getBBXMax()) ) 00867 { 00868 // Other primitive 00869 CMovePrimitive *otherPrimitive=other->Primitive; 00870 CPrimitiveWorldImage *otherWI=otherPrimitive->getWorldImage (worldImage); 00871 nlassert (otherPrimitive!=primitive); 00872 00873 // Continue the check if the other primitive is not in the modified list or if its pointer is higher than primitive 00874 if ( singleTest || ( (!otherWI->isInModifiedListFlag ()) || (primitive<otherPrimitive) ) ) 00875 { 00876 // Look if valid in Y 00877 if ( (wI->getBBYMin() < otherWI->getBBYMax()) && (otherWI->getBBYMin() < wI->getBBYMax()) ) 00878 { 00879 // If not already in collision with this primitive 00880 if (!primitive->isInCollision (otherPrimitive)) 00881 { 00882 if (evalPrimAgainstPrimCollision (beginTime, primitive, otherPrimitive, wI, otherWI, testMove, 00883 primitiveWorldImage, worldImage, secondIsStatic, dynamicColInfo, contactNormal)) 00884 { 00885 if (testMove) 00886 return true; 00887 found=true; 00888 } 00889 } 00890 } 00891 } 00892 00893 // Next primitive to the left 00894 other = other->NextX; 00895 } 00896 } 00897 } 00898 00899 return found; 00900 } 00901 00902 // *************************************************************************** 00903 00904 bool CMoveContainer::evalPrimAgainstPrimCollision (double beginTime, CMovePrimitive *primitive, CMovePrimitive *otherPrimitive, 00905 CPrimitiveWorldImage *wI, CPrimitiveWorldImage *otherWI, bool testMove, 00906 uint8 firstWorldImage, uint8 secondWorldImage, bool secondIsStatic, CCollisionOTDynamicInfo *dynamicColInfo, 00907 CVectorD *contactNormal) 00908 { 00909 // H_AUTO(PACS_MC_evalPrimAgainstPrimCollision); 00910 00911 // Test the primitive 00912 double firstTime, lastTime; 00913 00914 // Collision 00915 CCollisionDesc desc; 00916 if (wI->evalCollision (*otherWI, desc, beginTime, _DeltaTime, _TestTime, _MaxTestIteration, 00917 firstTime, lastTime, *primitive, *otherPrimitive)) 00918 { 00919 // Enter or exit 00920 bool enter = (beginTime<=firstTime) && (firstTime<_DeltaTime) && ((primitive->getTriggerType()&UMovePrimitive::EnterTrigger) 00921 || (otherPrimitive->getTriggerType()&UMovePrimitive::EnterTrigger)); 00922 bool exit = (beginTime<=lastTime) && (lastTime<_DeltaTime) && ((primitive->getTriggerType()&UMovePrimitive::ExitTrigger) 00923 || (otherPrimitive->getTriggerType()&UMovePrimitive::ExitTrigger)); 00924 bool overlap = (firstTime<=beginTime) && (lastTime>_DeltaTime) && ((primitive->getTriggerType()&UMovePrimitive::OverlapTrigger) 00925 || (otherPrimitive->getTriggerType()&UMovePrimitive::OverlapTrigger)); 00926 bool contact = ( beginTime<((firstTime+lastTime)/2) ) && (firstTime<=_DeltaTime); 00927 bool collision = contact && (primitive->isObstacle() && otherPrimitive->isObstacle ()); 00928 00929 // Return collision time 00930 00931 if (testMove) 00932 return contact; 00933 00942 if (primitive->isNonCollisionable () && (enter || exit || overlap)) 00943 { 00944 if (primitive->isTriggered (*otherPrimitive, enter, exit)) 00945 { 00946 // Add a trigger 00947 if (enter) 00948 newTrigger (primitive, otherPrimitive, desc, UTriggerInfo::In); 00949 if (exit) 00950 newTrigger (primitive, otherPrimitive, desc, UTriggerInfo::Out); 00951 if (overlap) 00952 newTrigger (primitive, otherPrimitive, desc, UTriggerInfo::Inside); 00953 } 00954 00955 // If the other primitive is not an obstacle, skip it because it will re-generate collisions. 00956 if (!collision) 00957 return false; 00958 } 00959 00960 // OK, collision 00961 if (contact || enter || exit || overlap) 00962 newCollision (primitive, otherPrimitive, desc, contact, enter, exit, overlap, firstWorldImage, secondWorldImage, secondIsStatic, 00963 dynamicColInfo); 00964 00965 // Collision 00966 return collision; 00967 } 00968 return false; 00969 } 00970 00971 // *************************************************************************** 00972 00973 void CMoveContainer::evalAllCollisions (double beginTime, uint8 worldImage) 00974 { 00975 H_AUTO(NLPACS_Eval_All_Collisions); 00976 00977 // First primitive 00978 CMovePrimitive *primitive=_ChangedRoot[worldImage]; 00979 00980 // For each modified primitive 00981 while (primitive) 00982 { 00983 // Get the primitive world image 00984 uint8 primitiveWorldImage; 00985 CPrimitiveWorldImage *wI; 00986 if (primitive->isNonCollisionable ()) 00987 { 00988 wI=primitive->getWorldImage (0); 00989 primitiveWorldImage=worldImage; 00990 } 00991 else 00992 { 00993 wI=primitive->getWorldImage (worldImage); 00994 primitiveWorldImage=worldImage; 00995 } 00996 00997 CVectorD d0=wI->getDeltaPosition(); 00998 00999 // Find a collision 01000 bool found=false; 01001 bool testMoveValid=false; 01002 01003 // Eval collision on the terrain 01004 found|=evalOneTerrainCollision (beginTime, primitive, primitiveWorldImage, false, testMoveValid, NULL, NULL); 01005 01006 // If the primitive can collid other primitive.. 01007 if (primitive->getCollisionMask()) 01008 { 01009 // Eval collision in each static world image 01010 std::set<uint8>::iterator ite=_StaticWorldImage.begin(); 01011 while (ite!=_StaticWorldImage.end()) 01012 { 01013 // Eval in this world image 01014 found|=evalOnePrimitiveCollision (beginTime, primitive, *ite, primitiveWorldImage, false, true, testMoveValid, NULL, NULL); 01015 01016 // Next world image 01017 ite++; 01018 } 01019 } 01020 01021 CVectorD d1=wI->getDeltaPosition(); 01022 01023 // If the primitive can collid other primitive.. 01024 if (primitive->getCollisionMask()) 01025 { 01026 // Eval collision in the world image if not already tested 01027 if (_StaticWorldImage.find (worldImage)==_StaticWorldImage.end()) 01028 found|=evalOnePrimitiveCollision (beginTime, primitive, worldImage, primitiveWorldImage, false, false, testMoveValid, NULL, NULL); 01029 } 01030 01031 CVectorD d2=wI->getDeltaPosition(); 01032 01033 // No collision ? 01034 if (!found) 01035 { 01036 //nlassert ((d0==d1)&&(d0==d2)); 01037 //nlassert (f1==f2); 01038 01039 if (_Retriever&&testMoveValid) 01040 { 01041 // Do move 01042 wI->doMove (*_Retriever, _SurfaceTemp, _DeltaTime, _DeltaTime, primitive->getDontSnapToGround()); 01043 } 01044 else 01045 { 01046 // Do move 01047 wI->doMove (_DeltaTime); 01048 } 01049 } 01050 01051 // Next primitive 01052 primitive=wI->getNextModified (); 01053 } 01054 } 01055 01056 // *************************************************************************** 01057 01058 void CMoveContainer::newCollision (CMovePrimitive* first, CMovePrimitive* second, const CCollisionDesc& desc, bool collision, bool enter, bool exit, bool inside, 01059 uint firstWorldImage, uint secondWorldImage, bool secondIsStatic, CCollisionOTDynamicInfo *dynamicColInfo) 01060 { 01061 // H_AUTO(PACS_MC_newCollision_short); 01062 01063 nlassert ((dynamicColInfo && first->isNonCollisionable ()) || (!dynamicColInfo && first->isCollisionable ())); 01064 01065 if (dynamicColInfo) 01066 { 01067 dynamicColInfo->init (first, second, desc, collision, enter, exit, inside, firstWorldImage, secondWorldImage, secondIsStatic); 01068 } 01069 else 01070 { 01071 // Get an ordered time index. Always round to the future. 01072 int index=(int)(ceil (desc.ContactTime*(double)_OtSize/_DeltaTime) ); 01073 01074 // Clamp left. 01075 if (index<0) 01076 index=0; 01077 01078 // If in time 01079 if (index<(int)_OtSize) 01080 { 01081 // Build info 01082 CCollisionOTDynamicInfo *info = allocateOTDynamicInfo (); 01083 info->init (first, second, desc, collision, enter, exit, inside, firstWorldImage, secondWorldImage, secondIsStatic); 01084 01085 // Add in the primitive list 01086 first->addCollisionOTInfo (info); 01087 second->addCollisionOTInfo (info); 01088 01089 // Insert in the time ordered table 01090 //nlassert (index<(int)_TimeOT.size()); 01091 if (index >= (int)_TimeOT.size()) 01092 { 01093 nlwarning("PACS: newCollision() failure, index [%d] >= (int)_TimeOT.size() [%d], clamped to max", index, (int)_TimeOT.size()); 01094 index = _TimeOT.size()-1; 01095 } 01096 _TimeOT[index].link (info); 01097 01098 // Check it is after the last hard collision 01099 nlassert (_PreviousCollisionNode<=&_TimeOT[index]); 01100 } 01101 } 01102 } 01103 01104 // *************************************************************************** 01105 01106 void CMoveContainer::newCollision (CMovePrimitive* first, const CCollisionSurfaceDesc& desc, uint8 worldImage, double beginTime, CCollisionOTStaticInfo *staticColInfo) 01107 { 01108 // H_AUTO(PACS_MC_newCollision_long); 01109 01110 // Check 01111 nlassert (_Retriever); 01112 nlassert ((staticColInfo && first->isNonCollisionable ()) || (!staticColInfo && first->isCollisionable ())); 01113 01114 // Get the world image 01115 CPrimitiveWorldImage *wI; 01116 if (first->isNonCollisionable()) 01117 wI=first->getWorldImage (0); 01118 else 01119 wI=first->getWorldImage (worldImage); 01120 01121 // Time 01122 double time=desc.ContactTime; 01123 /* 01124 if (time == _DeltaTime) 01125 time -= _DeltaTime*FLT_EPSILON; 01126 */ 01127 01128 // Check time interval 01129 01130 //nlassertex (beginTime<=time, ("beginTime=%f, time=%f", beginTime, time)); 01131 //nlassertex (time<_DeltaTime, ("time=%f, _DeltaTime=%f", time, _DeltaTime)); 01132 01133 if (beginTime > time) 01134 { 01135 nlwarning("PACS: beginTime=%f > time=%f", beginTime, time); 01136 } 01137 01138 if (time >= _DeltaTime) 01139 { 01140 nlwarning("PACS: time=%f >= _DeltaTime=%f", time, _DeltaTime); 01141 } 01142 01143 01144 // Time of the collision. 01145 time-=NELPACS_DIST_BACK/wI->getSpeed().norm(); 01146 time=std::max(time, beginTime); 01147 double ratio=(time-beginTime)/(_DeltaTime-beginTime); 01148 01149 /* 01150 nlassert (ratio>=0); 01151 nlassert (ratio<=1); 01152 */ 01153 01154 if (ratio < 0.0) 01155 { 01156 nlwarning("PACS: ratio=%f < 0.0", ratio); 01157 ratio = 0.0; 01158 } 01159 01160 if (ratio > 1.0) 01161 { 01162 nlwarning("PACS: ratio=%f > 1.0", ratio); 01163 ratio = 1.0; 01164 } 01165 01166 if (staticColInfo) 01167 { 01168 // Make a new globalposition 01169 UGlobalPosition endPosition=_Retriever->doMove (wI->getGlobalPosition(), wI->getDeltaPosition(), 01170 (float)ratio, _SurfaceTemp, false); 01171 01172 // Init the info descriptor 01173 staticColInfo->init (first, desc, endPosition, ratio, worldImage); 01174 } 01175 else 01176 { 01177 // Get an ordered time index. Always round to the future. 01178 int index=(int)(ceil (time*(double)_OtSize/_DeltaTime) ); 01179 01180 // Clamp left. 01181 if (index<0) 01182 index=0; 01183 01184 // If in time 01185 if (index<(int)_OtSize) 01186 { 01187 // Build info 01188 CCollisionOTStaticInfo *info = allocateOTStaticInfo (); 01189 01190 // Make a new globalposition 01191 UGlobalPosition endPosition=_Retriever->doMove (wI->getGlobalPosition(), wI->getDeltaPosition(), 01192 (float)ratio, _SurfaceTemp, false); 01193 01194 // Init the info descriptor 01195 info->init (first, desc, endPosition, ratio, worldImage); 01196 01197 // Add in the primitive list 01198 first->addCollisionOTInfo (info); 01199 01200 // Insert in the time ordered table 01201 //nlassert (index<(int)_TimeOT.size()); 01202 if (index >= (int)_TimeOT.size()) 01203 { 01204 nlwarning("PACS: newCollision() failure, index [%d] >= (int)_TimeOT.size() [%d], clamped to max", index, (int)_TimeOT.size()); 01205 index = _TimeOT.size()-1; 01206 } 01207 _TimeOT[index].link (info); 01208 01209 // Check it is after the last hard collision 01210 nlassert (_PreviousCollisionNode<=&_TimeOT[index]); 01211 } 01212 } 01213 } 01214 01215 // *************************************************************************** 01216 01217 void CMoveContainer::newTrigger (CMovePrimitive* first, CMovePrimitive* second, const CCollisionDesc& desc, uint triggerType) 01218 { 01219 // Element index 01220 uint index=_Triggers.size(); 01221 01222 // Add one element 01223 _Triggers.resize (index+1); 01224 01225 // Fill info 01226 _Triggers[index].Object0=first->UserData; 01227 _Triggers[index].Object1=second->UserData; 01228 _Triggers[index].CollisionDesc=desc; 01229 _Triggers[index].CollisionType = triggerType; 01230 } 01231 01232 // *************************************************************************** 01233 01234 void CMoveContainer::checkOT () 01235 { 01236 // Check 01237 nlassert (_OtSize==_TimeOT.size()); 01238 01239 // Check linked list 01240 for (uint i=0; i<_OtSize-1; i++) 01241 { 01242 // Check link 01243 nlassert ( _TimeOT[i].getNext() == (&(_TimeOT[i+1])) ); 01244 nlassert ( _TimeOT[i+1].getPrevious() == (&(_TimeOT[i])) ); 01245 } 01246 01247 // Check first and last 01248 nlassert ( _TimeOT[0].getPrevious() == NULL ); 01249 nlassert ( _TimeOT[_OtSize-1].getNext() == NULL ); 01250 } 01251 01252 // *************************************************************************** 01253 01254 void CMoveContainer::clearOT () 01255 { 01256 // Check 01257 nlassert (_OtSize==_TimeOT.size()); 01258 01259 // clear the list 01260 uint i; 01261 for (i=0; i<_OtSize; i++) 01262 _TimeOT[i].clear (); 01263 01264 // Relink the list 01265 for (i=0; i<_OtSize-1; i++) 01266 // Link the two cells 01267 _TimeOT[i].link (&(_TimeOT[i+1])); 01268 } 01269 01270 // *************************************************************************** 01271 01272 void CMoveContainer::removeModifiedFromOT (uint8 worldImage) 01273 { 01274 // For each changed primitives 01275 CMovePrimitive *changed=_ChangedRoot[worldImage]; 01276 while (changed) 01277 { 01278 // Remove from ot list 01279 changed->removeCollisionOTInfo (); 01280 01281 // Get the primitive world image 01282 CPrimitiveWorldImage *wI; 01283 if (changed->isNonCollisionable()) 01284 wI=changed->getWorldImage (0); 01285 else 01286 wI=changed->getWorldImage (worldImage); 01287 01288 // Next primitive 01289 changed=wI->getNextModified (); 01290 } 01291 } 01292 01293 // *************************************************************************** 01294 01295 CCollisionOTDynamicInfo *CMoveContainer::allocateOTDynamicInfo () 01296 { 01297 return _AllocOTDynamicInfo.allocate (); 01298 } 01299 01300 // *************************************************************************** 01301 01302 CCollisionOTStaticInfo *CMoveContainer::allocateOTStaticInfo () 01303 { 01304 return _AllocOTStaticInfo.allocate (); 01305 } 01306 01307 // *************************************************************************** 01308 01309 // Free all ordered table info 01310 void CMoveContainer::freeAllOTInfo () 01311 { 01312 H_AUTO (NLPACS_Free_All_OT_Info); 01313 01314 _AllocOTDynamicInfo.free (); 01315 _AllocOTStaticInfo.free (); 01316 } 01317 01318 // *************************************************************************** 01319 01320 CMovePrimitive *CMoveContainer::allocatePrimitive (uint8 firstWorldImage, uint8 numWorldImage) 01321 { 01322 // Simply allocate 01323 return new CMovePrimitive (this, firstWorldImage, numWorldImage); 01324 } 01325 01326 // *************************************************************************** 01327 01328 void CMoveContainer::freePrimitive (CMovePrimitive *primitive) 01329 { 01330 // Simply deallocate 01331 delete primitive; 01332 } 01333 01334 // *************************************************************************** 01335 01336 CPrimitiveWorldImage **CMoveContainer::allocateWorldImagesPtrs (uint numPtrs) 01337 { 01338 return new CPrimitiveWorldImage*[numPtrs]; 01339 } 01340 01341 // *************************************************************************** 01342 01343 void CMoveContainer::freeWorldImagesPtrs (CPrimitiveWorldImage **ptrs) 01344 { 01345 delete [] ptrs; 01346 } 01347 01348 // *************************************************************************** 01349 01350 CPrimitiveWorldImage *CMoveContainer::allocateWorldImage () 01351 { 01352 return new CPrimitiveWorldImage; 01353 } 01354 01355 // *************************************************************************** 01356 01357 void CMoveContainer::freeWorldImage (CPrimitiveWorldImage *worldImage) 01358 { 01359 delete worldImage; 01360 } 01361 01362 // *************************************************************************** 01363 01364 CMoveElement *CMoveContainer::allocateMoveElement () 01365 { 01366 // Simply allocate 01367 return new CMoveElement; 01368 } 01369 01370 // *************************************************************************** 01371 01372 void CMoveContainer::freeMoveElement (CMoveElement *element) 01373 { 01374 // Simply deallocate 01375 delete element; 01376 } 01377 01378 // *************************************************************************** 01379 01380 void UMoveContainer::deleteMoveContainer (UMoveContainer *container) 01381 { 01382 delete (CMoveContainer*)container; 01383 } 01384 01385 // *************************************************************************** 01386 01387 UMovePrimitive *CMoveContainer::addCollisionablePrimitive (uint8 firstWorldImage, uint8 numWorldImage, const UMovePrimitive *copyFrom) 01388 { 01389 NL_ALLOC_CONTEXT( Pacs ) 01390 01391 // Allocate primitive 01392 CMovePrimitive *primitive=allocatePrimitive (firstWorldImage, numWorldImage); 01393 01394 // Add into the set 01395 _PrimitiveSet.insert (primitive); 01396 01397 // if copy from primitive is not null, copy attributes 01398 if (copyFrom != NULL) 01399 { 01400 primitive->setPrimitiveType(copyFrom->getPrimitiveType()); 01401 primitive->setReactionType(copyFrom->getReactionType()); 01402 primitive->setTriggerType(copyFrom->getTriggerType()); 01403 primitive->setCollisionMask(copyFrom->getCollisionMask()); 01404 primitive->setOcclusionMask(copyFrom->getOcclusionMask()); 01405 primitive->setObstacle(copyFrom->getObstacle()); 01406 primitive->setAbsorbtion(copyFrom->getAbsorbtion()); 01407 primitive->setHeight(copyFrom->getHeight()); 01408 if (primitive->getPrimitiveType() == UMovePrimitive::_2DOrientedBox) 01409 { 01410 float width=0.0f, height=0.0f; 01411 copyFrom->getSize(width, height); 01412 primitive->setSize(width, height); 01413 } 01414 else 01415 { 01416 primitive->setRadius(copyFrom->getRadius()); 01417 } 01418 } 01419 01420 // Return it 01421 return primitive; 01422 } 01423 01424 // *************************************************************************** 01425 01426 UMovePrimitive *CMoveContainer::addNonCollisionablePrimitive (const UMovePrimitive *copyFrom) 01427 { 01428 NL_ALLOC_CONTEXT( Pacs ) 01429 01430 // Allocate primitive 01431 CMovePrimitive *primitive=allocatePrimitive (0, 1); 01432 01433 // Set as noncollisionable 01434 primitive->setNonCollisionable (true); 01435 01436 // Add into the set 01437 _PrimitiveSet.insert (primitive); 01438 01439 // if copy from primitive is not null, copy attributes 01440 if (copyFrom != NULL) 01441 { 01442 primitive->setPrimitiveType(copyFrom->getPrimitiveType()); 01443 primitive->setReactionType(copyFrom->getReactionType()); 01444 primitive->setTriggerType(copyFrom->getTriggerType()); 01445 primitive->setCollisionMask(copyFrom->getCollisionMask()); 01446 primitive->setOcclusionMask(copyFrom->getOcclusionMask()); 01447 primitive->setObstacle(copyFrom->getObstacle()); 01448 primitive->setAbsorbtion(copyFrom->getAbsorbtion()); 01449 primitive->setHeight(copyFrom->getHeight()); 01450 if (primitive->getPrimitiveType() == UMovePrimitive::_2DOrientedBox) 01451 { 01452 float width=0.0f, height=0.0f; 01453 copyFrom->getSize(width, height); 01454 primitive->setSize(width, height); 01455 } 01456 else 01457 { 01458 primitive->setRadius(copyFrom->getRadius()); 01459 } 01460 } 01461 01462 // Return it 01463 return primitive; 01464 } 01465 01466 // *************************************************************************** 01467 01468 void CMoveContainer::removePrimitive (UMovePrimitive* primitive) 01469 { 01470 NL_ALLOC_CONTEXT( Pacs ) 01471 01472 // CMovePrimitive pointer 01473 CMovePrimitive *prim=(CMovePrimitive*)primitive; 01474 01475 // Get the primitive world image 01476 for (uint8 i=0; i<prim->getNumWorldImage (); i++) 01477 { 01478 // World image 01479 uint8 worldImage=prim->getFirstWorldImage ()+i; 01480 01481 // Get primitive world image 01482 CPrimitiveWorldImage *wI=prim->getWorldImage (worldImage); 01483 01484 // In modified list ? 01485 if (wI->isInModifiedListFlag ()) 01486 { 01487 // Non collisionable primitive ? 01488 if (prim->isNonCollisionable()) 01489 { 01490 // Remove from all world image 01491 removeNCFromModifiedList (prim, worldImage); 01492 } 01493 else 01494 { 01495 // Remove from modified list 01496 removeFromModifiedList (prim, worldImage); 01497 } 01498 } 01499 } 01500 01501 // Remove from the set 01502 _PrimitiveSet.erase (prim); 01503 01504 // Erase it 01505 freePrimitive (prim); 01506 } 01507 01508 // *************************************************************************** 01509 01510 void CMoveContainer::removeNCFromModifiedList (CMovePrimitive* primitive, uint8 worldImage) 01511 { 01512 // For each world image 01513 uint i; 01514 uint worldImageCount = _ChangedRoot.size(); 01515 for (i=0; i<worldImageCount; i++) 01516 { 01517 // For each changed primitives 01518 CMovePrimitive *changed=_ChangedRoot[i]; 01519 CPrimitiveWorldImage *previous=NULL; 01520 CPrimitiveWorldImage *wI=primitive->getWorldImage (worldImage); 01521 01522 while (changed) 01523 { 01524 // Get the primitive world image 01525 CPrimitiveWorldImage *changedWI=changed->getWorldImage (worldImage); 01526 01527 // Remove from ot list 01528 if (changed==primitive) 01529 { 01530 // There is a previous primitive ? 01531 if (previous) 01532 previous->linkInModifiedList (wI->getNextModified ()); 01533 else 01534 _ChangedRoot[i]=wI->getNextModified (); 01535 01536 // Unlink 01537 wI->linkInModifiedList (NULL); 01538 wI->setInModifiedListFlag (false); 01539 break; 01540 } 01541 01542 // Next primitive 01543 previous=changedWI; 01544 changed=changedWI->getNextModified (); 01545 } 01546 01547 // Breaked ? 01548 if (changed==primitive) 01549 break; 01550 } 01551 } 01552 01553 // *************************************************************************** 01554 01555 void CMoveContainer::removeFromModifiedList (CMovePrimitive* primitive, uint8 worldImage) 01556 { 01557 // For each changed primitives 01558 CMovePrimitive *changed=_ChangedRoot[worldImage]; 01559 CPrimitiveWorldImage *previous=NULL; 01560 CPrimitiveWorldImage *wI=primitive->getWorldImage (worldImage); 01561 01562 while (changed) 01563 { 01564 // Get the primitive world image 01565 CPrimitiveWorldImage *changedWI=changed->getWorldImage (worldImage); 01566 01567 // Remove from ot list 01568 if (changed==primitive) 01569 { 01570 // There is a previous primitive ? 01571 if (previous) 01572 previous->linkInModifiedList (wI->getNextModified ()); 01573 else 01574 _ChangedRoot[worldImage]=wI->getNextModified (); 01575 01576 // Unlink 01577 wI->linkInModifiedList (NULL); 01578 wI->setInModifiedListFlag (false); 01579 break; 01580 } 01581 01582 // Next primitive 01583 previous=changedWI; 01584 changed=changedWI->getNextModified (); 01585 } 01586 } 01587 01588 // *************************************************************************** 01589 01590 void CMoveContainer::unlinkMoveElement (CMoveElement *element, uint8 worldImage) 01591 { 01592 // Some checks 01593 nlassert (element->X<_CellCountWidth); 01594 nlassert (element->Y<_CellCountHeight); 01595 01596 // Unlink it 01597 CMoveCell &cell=_VectorCell[worldImage][element->X+element->Y*_CellCountWidth]; 01598 cell.unlinkX (element); 01599 //cell.unlinkY (element); 01600 } 01601 01602 // *************************************************************************** 01603 01604 void CMoveContainer::reaction (const CCollisionOTInfo& first) 01605 { 01606 // H_AUTO(PACS_MC_reaction); 01607 01608 // Static collision ? 01609 if (first.isCollisionAgainstStatic()) 01610 { 01611 // Check mode 01612 nlassert (_Retriever); 01613 01614 // Cast 01615 const CCollisionOTStaticInfo *staticInfo=safe_cast<const CCollisionOTStaticInfo*> (&first); 01616 01617 // Get the primitive world image 01618 CMovePrimitive *movePrimitive=staticInfo->getPrimitive (); 01619 CPrimitiveWorldImage *wI; 01620 if (movePrimitive->isNonCollisionable ()) 01621 wI=movePrimitive->getWorldImage (0); 01622 else 01623 wI=movePrimitive->getWorldImage (staticInfo->getWorldImage()); 01624 01625 // Dynamic collision 01626 wI->reaction ( staticInfo->getCollisionDesc (), staticInfo->getGlobalPosition (), 01627 *_Retriever, staticInfo->getDeltaTime(), _DeltaTime, *staticInfo->getPrimitive (), *this, staticInfo->getWorldImage()); 01628 } 01629 else 01630 { 01631 // Cast 01632 const CCollisionOTDynamicInfo *dynInfo=safe_cast<const CCollisionOTDynamicInfo*> (&first); 01633 01634 // Get the primitives world image 01635 CPrimitiveWorldImage *firstWI; 01636 if (dynInfo->getFirstPrimitive ()->isNonCollisionable ()) 01637 firstWI=dynInfo->getFirstPrimitive ()->getWorldImage (0); 01638 else 01639 firstWI=dynInfo->getFirstPrimitive ()->getWorldImage (dynInfo->getFirstWorldImage()); 01640 01641 CPrimitiveWorldImage *secondWI; 01642 if (dynInfo->getSecondPrimitive ()->isNonCollisionable ()) 01643 secondWI=dynInfo->getSecondPrimitive ()->getWorldImage (0); 01644 else 01645 secondWI=dynInfo->getSecondPrimitive ()->getWorldImage (dynInfo->getSecondWorldImage()); 01646 01647 // Dynamic collision 01648 firstWI->reaction ( *secondWI, dynInfo->getCollisionDesc (), _Retriever, _SurfaceTemp, dynInfo->isCollision(), 01649 *dynInfo->getFirstPrimitive (), *dynInfo->getSecondPrimitive (), this, dynInfo->getFirstWorldImage(), 01650 dynInfo->getSecondWorldImage(), dynInfo->isSecondStatic()); 01651 01660 if (dynInfo->getFirstPrimitive ()->isCollisionable ()) 01661 { 01662 if (dynInfo->getFirstPrimitive ()->isTriggered (*dynInfo->getSecondPrimitive (), dynInfo->isEnter(), dynInfo->isExit())) 01663 { 01664 if (dynInfo->isEnter()) 01665 newTrigger (dynInfo->getFirstPrimitive (), dynInfo->getSecondPrimitive (), dynInfo->getCollisionDesc (), UTriggerInfo::In); 01666 if (dynInfo->isExit()) 01667 newTrigger (dynInfo->getFirstPrimitive (), dynInfo->getSecondPrimitive (), dynInfo->getCollisionDesc (), UTriggerInfo::Out); 01668 if (dynInfo->isInside()) 01669 newTrigger (dynInfo->getFirstPrimitive (), dynInfo->getSecondPrimitive (), dynInfo->getCollisionDesc (), UTriggerInfo::Inside); 01670 } 01671 } 01672 } 01673 } 01674 01675 // *************************************************************************** 01676 01677 void CMoveContainer::setAsStatic (uint8 worldImage) 01678 { 01679 NL_ALLOC_CONTEXT( Pacs ) 01680 01681 // Add this world image in the static set of world image 01682 _StaticWorldImage.insert (worldImage); 01683 } 01684 01685 // *************************************************************************** 01686 01687 void CMoveContainer::duplicateWorldImage (uint8 source, uint8 dest) 01688 { 01689 NL_ALLOC_CONTEXT( Pacs ) 01690 01691 // Cell count 01692 uint cellCount=_CellCountWidth*_CellCountHeight; 01693 01694 // Clear dest modified list 01695 clearModifiedList (dest); 01696 01697 // Clear destination cells 01698 uint i; 01699 for (i=0; i<cellCount; i++) 01700 { 01701 // Get first X 01702 CMoveElement *elm; 01703 while ((elm=_VectorCell[dest][i].getFirstX ())) 01704 { 01705 // Get primitive world image 01706 CPrimitiveWorldImage *wI=elm->Primitive->getWorldImage (dest); 01707 01708 // Remove the primitive 01709 int i; 01710 for (i=0; i<4; i++) 01711 { 01712 if (wI->getMoveElement(i)) 01713 wI->removeMoveElement (i, *this, dest); 01714 } 01715 } 01716 } 01717 01718 // Duplicate destination cells 01719 for (i=0; i<cellCount; i++) 01720 { 01721 // Get first X 01722 CMoveElement *elm=_VectorCell[source][i].getFirstX (); 01723 while (elm) 01724 { 01725 // Get primitive world image 01726 CPrimitiveWorldImage *wISource=elm->Primitive->getWorldImage (source); 01727 CPrimitiveWorldImage *wIDest=elm->Primitive->getWorldImage (dest); 01728 01729 // First time the primitive is visited ? 01730 if (wIDest->getMoveElement (0)==NULL) 01731 { 01732 wIDest->copy (*wISource); 01733 } 01734 01735 // Add at the end of the list 01736 wIDest->addMoveElementendOfList (_VectorCell[dest][i], elm->X, elm->Y, elm->Primitive, *this); 01737 01738 // Added ? 01739 nlassert (wIDest->getMoveElement (0)!=NULL); 01740 01741 // Next primitive 01742 elm=elm->NextX; 01743 } 01744 } 01745 } 01746 01747 // *************************************************************************** 01748 01749 UMoveContainer *UMoveContainer::createMoveContainer (double xmin, double ymin, double xmax, double ymax, 01750 uint widthCellCount, uint heightCellCount, double primitiveMaxSize, uint8 numWorldImage, 01751 uint maxIteration, uint otSize) 01752 { 01753 NL_ALLOC_CONTEXT( Pacs ) 01754 01755 // Create a CMoveContainer 01756 return new CMoveContainer (xmin, ymin, xmax, ymax, widthCellCount, heightCellCount, primitiveMaxSize, numWorldImage, maxIteration, otSize); 01757 } 01758 01759 // *************************************************************************** 01760 01761 UMoveContainer *UMoveContainer::createMoveContainer (UGlobalRetriever* retriever, uint widthCellCount, 01762 uint heightCellCount, double primitiveMaxSize, uint8 numWorldImage, uint maxIteration, uint otSize) 01763 { 01764 NL_ALLOC_CONTEXT( Pacs ) 01765 01766 // Cast 01767 nlassert (dynamic_cast<CGlobalRetriever*>(retriever)); 01768 CGlobalRetriever* r=static_cast<CGlobalRetriever*>(retriever); 01769 01770 // Create a CMoveContainer 01771 return new CMoveContainer (r, widthCellCount, heightCellCount, primitiveMaxSize, numWorldImage, maxIteration, otSize); 01772 } 01773 01774 // *************************************************************************** 01775 01776 void UCollisionDesc::serial (NLMISC::IStream& stream) 01777 { 01778 stream.serial (ContactPosition); 01779 stream.serial (ContactNormal0); 01780 stream.serial (ContactNormal1); 01781 stream.serial (ContactTime); 01782 }; 01783 01784 // *************************************************************************** 01785 01786 void UTriggerInfo::serial (NLMISC::IStream& stream) 01787 { 01788 stream.serial (Object0); 01789 stream.serial (Object1); 01790 stream.serial (CollisionDesc); 01791 } 01792 01793 01794 01795 // *************************************************************************** 01796 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)*/) 01797 { 01798 NL_ALLOC_CONTEXT( Pacs ) 01799 01800 CPrimitiveBlock *block = NLMISC::safe_cast<CPrimitiveBlock *>(pb); 01801 // Reserve the pointer array 01802 if (primitives) 01803 primitives->reserve (block->Primitives.size()); 01804 01805 // For each primitive 01806 uint prim; 01807 for (prim=0; prim<block->Primitives.size(); prim++) 01808 { 01809 // Create a collisionable primitive 01810 UMovePrimitive *primitive = addCollisionablePrimitive (firstWorldImage, numWorldImage); 01811 01812 // Ref on the block descriptor 01813 CPrimitiveDesc &desc = block->Primitives[prim]; 01814 01815 // Set its properties 01816 primitive->setPrimitiveType (desc.Type); 01817 primitive->setReactionType (desc.Reaction); 01818 primitive->setTriggerType (desc.Trigger); 01819 primitive->setCollisionMask (desc.CollisionMask); 01820 primitive->setOcclusionMask (desc.OcclusionMask); 01821 primitive->setObstacle (desc.Obstacle); 01822 primitive->setAbsorbtion (desc.Attenuation); 01823 primitive->setDontSnapToGround(dontSnapToGround); 01824 primitive->UserData = desc.UserData; 01825 if (desc.Type == UMovePrimitive::_2DOrientedBox) 01826 { 01827 // ONLY ASSUME UNIFORM SCALE ON X/Y 01828 primitive->setSize (desc.Length[0]*scale.x, desc.Length[1]*scale.x); 01829 } 01830 else 01831 { 01832 // ONLY ASSUME UNIFORM SCALE ON X/Y 01833 nlassert (desc.Type == UMovePrimitive::_2DOrientedCylinder); 01834 primitive->setRadius (desc.Length[0]*scale.x); 01835 } 01836 primitive->setHeight (desc.Height*scale.z); 01837 01838 // Insert the primitives 01839 01840 // For each world image 01841 uint wI; 01842 for (wI=firstWorldImage; wI<(uint)(firstWorldImage+numWorldImage); wI++) 01843 { 01844 // Insert the primitive 01845 primitive->insertInWorldImage (wI); 01846 01847 // Final position& 01848 float cosa = (float) cos (orientation); 01849 float sina = (float) sin (orientation); 01850 CVector finalPos; 01851 finalPos.x = cosa * desc.Position.x * scale.x - sina * desc.Position.y * scale.y + position.x; 01852 finalPos.y = sina * desc.Position.x * scale.x + cosa * desc.Position.y * scale.y + position.y; 01853 finalPos.z = desc.Position.z *scale.z + position.z; 01854 01855 // Set the primtive orientation 01856 if (desc.Type == UMovePrimitive::_2DOrientedBox) 01857 primitive->setOrientation ((float)fmod (desc.Orientation + orientation, 2*Pi), wI); 01858 01859 // Set the primitive global position 01860 primitive->setGlobalPosition (finalPos, wI); 01861 } 01862 01863 // Feedback asked ? 01864 if (primitives) 01865 { 01866 // Add the pointer 01867 primitives->push_back (primitive); 01868 } 01869 } 01870 } 01871 01872 01873 // *************************************************************************** 01874 01875 bool CMoveContainer::loadCollisionablePrimitiveBlock (const char *filename, uint8 firstWorldImage, uint8 numWorldImage, std::vector<UMovePrimitive*> *primitives, float orientation, const NLMISC::CVector &position, bool dontSnapToGround /*= false*/) 01876 { 01877 NL_ALLOC_CONTEXT( Pacs ) 01878 01879 // Check world image 01880 if ( (uint)(firstWorldImage+numWorldImage) > _ChangedRoot.size() ) 01881 { 01882 nlwarning ("Invalid world image number."); 01883 return false; 01884 } 01885 01886 // Try to load the file 01887 CIFile file; 01888 if (file.open (filename)) 01889 { 01890 // Create the XML stream 01891 CIXml input; 01892 01893 // Init 01894 if (input.init (file)) 01895 { 01896 // The primitive block 01897 CPrimitiveBlock block; 01898 01899 // Serial it 01900 file.serial (block); 01901 01902 // add primitives 01903 addCollisionnablePrimitiveBlock(&block, firstWorldImage, numWorldImage, primitives, orientation, position, dontSnapToGround); 01904 01905 return true; 01906 } 01907 else 01908 { 01909 // Warning 01910 nlwarning ("Can't init XML stream with file %s.", filename); 01911 01912 return false; 01913 } 01914 } 01915 else 01916 { 01917 // Warning 01918 nlwarning ("Can't load primitive block %s.", filename); 01919 01920 return false; 01921 } 01922 } 01923 01924 01925 // *************************************************************************** 01926 void CMoveContainer::getPrimitives(std::vector<const UMovePrimitive *> &dest) const 01927 { 01928 NL_ALLOC_CONTEXT( Pacs ) 01929 01930 dest.resize(_PrimitiveSet.size()); 01931 std::copy(_PrimitiveSet.begin(), _PrimitiveSet.end(), dest.begin()); 01932 } 01933 01934 01935 // *************************************************************************** 01936 void UMoveContainer::getPACSCoordsFromMatrix(NLMISC::CVector &pos,float &angle,const NLMISC::CMatrix &mat) 01937 { 01938 pos = mat.getPos(); 01939 CVector orient = mat.mulVector(NLMISC::CVector::I); 01940 orient.z = 0.f; 01941 orient.normalize(); 01942 angle = orient.y >= 0.f ? ::acosf(orient.x) 01943 : 2.f * (float) NLMISC::Pi - ::acosf(orient.x); 01944 01945 } 01946 01947 // *************************************************************************** 01948 bool CMoveContainer::evalNCPrimitiveCollision (double deltaTime, UMovePrimitive *primitive, uint8 worldImage) 01949 { 01950 NL_ALLOC_CONTEXT( Pacs ) 01951 01952 // New test time 01953 _TestTime++; 01954 01955 // Clear triggers 01956 _Triggers.clear (); 01957 01958 // Only non-collisionable primitives 01959 if (!primitive->isCollisionable()) 01960 { 01961 // Delta time 01962 _DeltaTime=deltaTime; 01963 01964 // Begin of the time slice to compute 01965 double beginTime = 0; 01966 double collisionTime = deltaTime; 01967 01968 // Get the world image 01969 CPrimitiveWorldImage *wI = ((CMovePrimitive*)primitive)->getWorldImage (0); 01970 01971 CCollisionOTInfo *firstCollision = NULL; 01972 do 01973 { 01974 //nlassert (beginTime < 1.0); 01975 if (beginTime >= 1.0) 01976 { 01977 nlwarning("PACS: evalNCPrimitiveCollision() failure, beginTime [%f] >= 1.0", beginTime); 01978 return false; 01979 } 01980 01981 // Update the primitive 01982 wI->update (beginTime, deltaTime, *(CMovePrimitive*)primitive); 01983 01984 CVectorD d0=wI->getDeltaPosition(); 01985 01986 // Eval collision again the terrain 01987 bool testMoveValid = false; 01988 CCollisionOTStaticInfo staticColInfo; 01989 CCollisionOTDynamicInfo dynamicColInfoWI0; 01990 CCollisionOTDynamicInfo dynamicColInfoWI; 01991 01992 firstCollision = NULL; 01993 01994 // If collision found, note it is on the landscape 01995 if (evalOneTerrainCollision (beginTime, (CMovePrimitive*)primitive, worldImage, false, testMoveValid, &staticColInfo, NULL)) 01996 { 01997 firstCollision = &staticColInfo; 01998 } 01999 02000 // Eval collision again the static primitives 02001 std::set<uint8>::iterator ite=_StaticWorldImage.begin(); 02002 while (ite!=_StaticWorldImage.end()) 02003 { 02004 // Eval in this world image 02005 if (evalOnePrimitiveCollision (beginTime, (CMovePrimitive*)primitive, *ite, worldImage, false, true, testMoveValid, &dynamicColInfoWI0, NULL)) 02006 { 02007 // First collision.. 02008 if (!firstCollision || (firstCollision->getCollisionTime () > dynamicColInfoWI0.getCollisionTime ())) 02009 { 02010 firstCollision = &dynamicColInfoWI0; 02011 } 02012 } 02013 02014 // Next world image 02015 ite++; 02016 } 02017 02018 // Checks 02019 CVectorD d1=wI->getDeltaPosition(); 02020 02021 // Eval collision again the world image 02022 if (_StaticWorldImage.find (worldImage)==_StaticWorldImage.end()) 02023 { 02024 if (evalOnePrimitiveCollision (beginTime, (CMovePrimitive*)primitive, worldImage, worldImage, false, false, testMoveValid, &dynamicColInfoWI, NULL)) 02025 { 02026 // First collision.. 02027 if (!firstCollision || (firstCollision->getCollisionTime () > dynamicColInfoWI.getCollisionTime ())) 02028 { 02029 firstCollision = &dynamicColInfoWI; 02030 } 02031 } 02032 } 02033 02034 // Checks 02035 CVectorD d2=wI->getDeltaPosition(); 02036 nlassert ((d0==d1)&&(d0==d2)); 02037 02038 // if (found) 02039 // nlstop; 02040 02041 // Reaction 02042 if (firstCollision) 02043 { 02044 collisionTime = firstCollision->getCollisionTime (); 02045 reaction (*firstCollision); 02046 //nlassert (collisionTime != 1); 02047 02048 if (collisionTime == 1) 02049 { 02050 nlwarning("PACS: evalNCPrimitiveCollision() failure, collisionTime [%f] == 1", collisionTime); 02051 return false; 02052 } 02053 } 02054 else 02055 { 02056 // Retriever mode ? 02057 if (_Retriever&&testMoveValid) 02058 { 02059 // Do move 02060 wI->doMove (*_Retriever, _SurfaceTemp, deltaTime, collisionTime, ((CMovePrimitive*)primitive)->getDontSnapToGround()); 02061 } 02062 else 02063 { 02064 // Do move 02065 wI->doMove (_DeltaTime); 02066 } 02067 } 02068 02069 beginTime = collisionTime; 02070 } 02071 while (firstCollision); 02072 } 02073 else 02074 return false; 02075 02076 return true; 02077 } 02078 02079 02080 } // NLPACS |