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