move_container.cpp

Go to the documentation of this file.
00001 
00005 /* Copyright, 2001 Nevrax Ltd.
00006  *
00007  * This file is part of NEVRAX NEL.
00008  * NEVRAX NEL is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2, or (at your option)
00011  * any later version.
00012 
00013  * NEVRAX NEL is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * General Public License for more details.
00017 
00018  * You should have received a copy of the GNU General Public License
00019  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00020  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00021  * MA 02111-1307, USA.
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 Doc:
00047 
00048       // Non collisionnable primitive
00049     Their moves are evaluate one by one with evalNCPrimitiveCollision().
00050     If a collision is found, reaction() is called.
00051 
00052     // Collisionnable primitives
00053     Each primitive must be moved first with the move() method.
00054     Their moves are evaluate all at once. All the collisions found are time sorted in a time orderin table (_TimeOT).
00055     While the table is not empty, the first collision occured in time is solved and
00056     If a collision is found, reaction() is called.
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     // Clear all primitives
00076     std::set<CMovePrimitive*>::iterator ite=_PrimitiveSet.begin();
00077     while (ite!=_PrimitiveSet.end ())
00078     {
00079         freePrimitive (*ite);
00080         ite++;
00081     }
00082 
00083     // Clear primitive set
00084     _PrimitiveSet.clear ();
00085 
00086     // Clear root changed
00087     _ChangedRoot.clear ();
00088 
00089     // Clear static world image set
00090     _StaticWorldImage.clear ();
00091 
00092     // Clear cell array
00093     _VectorCell.clear ();
00094 
00095     // Clear time ot
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     // Clear arrays
00105     clear ();
00106 
00107     // Create world images
00108     _ChangedRoot.resize (numWorldImage);
00109     for (uint i=0; i<numWorldImage; i++)
00110         _ChangedRoot[i]=NULL;
00111 
00112     // Not in test mode
00113     _Retriever=NULL;
00114 
00115     // Element size
00116     _PrimitiveMaxSize=primitiveMaxSize;
00117 
00118     // BB
00119     _Xmin=xmin;
00120     _Ymin=ymin;
00121     _Xmax=xmax;
00122     _Ymax=ymax;
00123 
00124     // Cells count
00125     _CellCountWidth=widthCellCount;
00126     _CellCountHeight=heightCellCount;
00127 
00128     // Cells size
00129     _CellWidth=(_Xmax - _Xmin)/(double)_CellCountWidth;
00130     _CellHeight=(_Ymax - _Ymin)/(double)_CellCountHeight;
00131 
00132     // Cell array
00133     _VectorCell.resize (numWorldImage);
00134     for (uint j=0; j<numWorldImage; j++)
00135         _VectorCell[j].resize (_CellCountWidth * _CellCountHeight);
00136 
00137     // resize OT
00138     _OtSize=otSize;
00139     _TimeOT.resize (otSize);
00140 
00141     // Clear the OT
00142     clearOT ();
00143 
00144     // Clear test time
00145     _TestTime=0xffffffff;
00146     _MaxTestIteration=maxIteration;
00147 
00148     // Resize trigger array
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     // Get min max of the global retriever BB
00158     CVector min=retriever->getBBox().getMin();
00159     CVector max=retriever->getBBox().getMax();
00160 
00161     // Setup min max
00162     double xmin=min.x;
00163     double ymin=min.y;
00164     double xmax=max.x;
00165     double ymax=max.y;
00166 
00167     // Init
00168     init (xmin, ymin, xmax, ymax, widthCellCount, heightCellCount, primitiveMaxSize, numWorldImage, maxIteration, otSize);
00169 
00170     // Init the retriever
00171     _Retriever=retriever;
00172 }
00173 
00174 // ***************************************************************************
00175 
00176 void  CMoveContainer::evalCollision (double deltaTime, uint8 worldImage)
00177 {
00178     NLPACS_HAUTO_EVAL_COLLISION
00179 
00180 //  H_AUTO(PACS_MC_evalCollision);
00181 
00182     // New test time
00183     _TestTime++;
00184 
00185     // Delta time
00186     _DeltaTime=deltaTime;
00187 
00188     // Clear triggers
00189     _Triggers.clear ();
00190 
00191     // Update the bounding box and position of modified primitives
00192     updatePrimitives (0.f, worldImage);
00193 
00194 #ifdef NL_DEBUG
00195     // Check list integrity
00196     //checkSortedList ();
00197 #endif // NL_DEBUG
00198 
00199     // Get first collision
00200     _PreviousCollisionNode = &_TimeOT[0];
00201     if(_PreviousCollisionNode == NULL)
00202         return;
00203 
00204     // Eval all collisions
00205     evalAllCollisions (0.f, worldImage);
00206 
00207     // Clear modified list
00208     clearModifiedList (worldImage);
00209 
00210     // Modified list is empty at this point
00211     nlassert (_ChangedRoot[worldImage]==NULL);
00212 
00213     // Previous node is a 'hard' OT node
00214     nlassert (!_PreviousCollisionNode->isInfo());
00215 
00216     // Get next collision
00217     CCollisionOTInfo    *nextCollision;
00218     {
00219         H_AUTO (NLPACS_Get_Next_Info);
00220         nextCollision=_PreviousCollisionNode->getNextInfo ();
00221     }
00222 
00223     // Collision ?
00224     while (nextCollision)
00225     {
00226         // Get new previous OT hard node
00227         _PreviousCollisionNode=nextCollision->getPrevious ();
00228 
00229         // Previous node is a 'hard' OT node
00230         nlassert (!_PreviousCollisionNode->isInfo());
00231 
00232         // Keep this collision
00233         reaction (*nextCollision);
00234 
00235         // Remove this collision from ot
00236         if (!nextCollision->isCollisionAgainstStatic ())
00237         {
00238             // Remove the primitive from OT
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         // Last time
00249         double newTime=nextCollision->getCollisionTime ();
00250 
00251         // Remove modified objects from the OT
00252         removeModifiedFromOT (worldImage);
00253 
00254         // Must have been removed
00255         nlassert (nextCollision->getPrevious ()==NULL);
00256         nlassert (nextCollision->CCollisionOT::getNext ()==NULL);
00257 
00258         // Update the bounding box and position of modified primitives
00259         updatePrimitives (newTime, worldImage);
00260 
00261         // Eval all collisions of modified objects for the new delta t
00262         evalAllCollisions (newTime, worldImage);
00263 
00264         // Clear modified list
00265         clearModifiedList (worldImage);
00266 
00267         // Get next collision
00268         nextCollision=_PreviousCollisionNode->getNextInfo ();
00269     }
00270 
00271 #ifdef NL_DEBUG
00272     // OT must be cleared
00273     checkOT ();
00274 #endif // NL_DEBUG
00275 
00276     // Free ordered table info
00277     freeAllOTInfo ();
00278 
00279     // Some init
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 //  H_AUTO(PACS_MC_testMove);
00289 
00290     if (contactNormal)
00291         *contactNormal = CVectorD::Null;
00292 
00293     // Cast
00294     nlassert (dynamic_cast<CMovePrimitive*>(primitive));
00295     CMovePrimitive* prim=static_cast<CMovePrimitive*>(primitive);
00296 
00297     // New test time
00298     _TestTime++;
00299 
00300     // Delta time
00301     _DeltaTime=deltaTime;
00302 
00303     // Get the world image primitive
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     // Backup speed
00318     CVectorD oldSpeed=wI->getSpeed ();
00319 
00320     // Set speed
00321     wI->move (speed, *this, *prim, primitiveWorldImage);
00322 
00323     // Update the bounding box and position of the primitive
00324     wI->update (0, _DeltaTime, *prim);
00325 
00326     // Compute cells overlaped by the primitive
00327     if (!prim->isNonCollisionable ())
00328         updateCells (prim, worldImage);
00329 
00330 #ifdef NL_DEBUG
00331     // Check list integrity
00332 //  checkSortedList ();
00333 #endif // NL_DEBUG
00334 
00335     // Result
00336     bool result=false;
00337     bool testMoveValid;
00338 
00339     // Eval first each static world images
00340     result=evalOneTerrainCollision (0, prim, primitiveWorldImage, true, testMoveValid, NULL, contactNormal);
00341 
00342     // Eval first each static world images
00343     if (!result)
00344     {
00345         std::set<uint8>::iterator ite=_StaticWorldImage.begin();
00346         while (ite!=_StaticWorldImage.end())
00347         {
00348 
00349             // Eval in this world image
00350             result=evalOnePrimitiveCollision (0, prim, *ite, primitiveWorldImage, true, true, testMoveValid, NULL, contactNormal);
00351 
00352             // If found, abort
00353             if (result)
00354                 break;
00355 
00356             // Next world image
00357             ite++;
00358         }
00359     }
00360 
00361     // Eval collisions if not found and not tested
00362     if ((!result) && (_StaticWorldImage.find (worldImage)==_StaticWorldImage.end()))
00363         result=evalOnePrimitiveCollision (0, prim, worldImage, primitiveWorldImage, true, false, testMoveValid, NULL, contactNormal);
00364 
00365     // Backup speed only if the primitive is inserted in the world image
00366     if (prim->isInserted (primitiveWorldImage))
00367         wI->move (oldSpeed, *this, *prim, primitiveWorldImage);
00368 
00369 #ifdef NL_DEBUG
00370     // OT must be cleared
00371     checkOT ();
00372 #endif // NL_DEBUG
00373 
00374     // Free ordered table info
00375     freeAllOTInfo ();
00376 
00377     // Some init
00378     _PreviousCollisionNode=NULL;
00379 
00380     // Return result
00381     return !result;
00382 }
00383 
00384 // ***************************************************************************
00385 
00386 void CMoveContainer::updatePrimitives (double beginTime, uint8 worldImage)
00387 {
00388     H_AUTO (NLPACS_Update_Primitives);
00389 
00390     // For each changed primitives
00391     CMovePrimitive *changed=_ChangedRoot[worldImage];
00392     while (changed)
00393     {
00394         // Get the primitive world image
00395         CPrimitiveWorldImage *wI;
00396         if (changed->isNonCollisionable())
00397             wI=changed->getWorldImage (0);
00398         else
00399             wI=changed->getWorldImage (worldImage);
00400 
00401         // Force the build of the bounding box
00402         wI->update (beginTime, _DeltaTime, *changed);
00403 
00404         // Is inserted in this world image ?
00405         if (changed->isInserted (worldImage))
00406         {
00407 
00408             // Compute cells overlaped by the primitive
00409             updateCells (changed, worldImage);
00410         }
00411 
00412         // Next primitive
00413         changed=wI->getNextModified ();
00414     }
00415 }
00416 
00417 // ***************************************************************************
00418 
00419 void CMoveContainer::updateCells (CMovePrimitive *primitive, uint8 worldImage)
00420 {
00421 //  H_AUTO(PACS_MC_updateCells);
00422 
00423     // Get the primitive world image
00424     CPrimitiveWorldImage *wI=primitive->getWorldImage (worldImage);
00425 
00426 #if !FINAL_VERSION
00427     // Check BB width not too large
00428     if (wI->getBBXMax() - wI->getBBXMin() > _CellWidth)
00429     {
00430         nlwarning ("Primitives have moved more than a cell.");
00431     }
00432 
00433     // Check BB height not too large
00434     if (wI->getBBYMax() - wI->getBBYMin() > _CellHeight)
00435     {
00436         nlwarning ("Primitives have moved more than a cell.");
00437     }
00438 #endif
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 #if !FINAL_VERSION
00538     // Check BB width not too large
00539     if (wI->getBBXMax() - wI->getBBXMin() > _CellWidth)
00540     {
00541         //nlwarning ("Primitives have moved more than a cell.");
00542     }
00543 
00544     // Check BB height not too large
00545     if (wI->getBBYMax() - wI->getBBYMin() > _CellHeight)
00546     {
00547         //nlwarning ("Primitives have moved more than a cell.");
00548     }
00549 #endif
00550 
00551     // Get coordinate in the cell array
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     // Born
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     // For each case selected
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         // Check the formula
00577         nlassert ((int)i == (x - minx + ((y - miny) << (maxx-minx)) ));
00578 
00579         // Center of the cell
00580         double cx=((double)x+0.5f)*_CellWidth+_Xmin;
00581 
00582         // Primitive center
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         // Insert in left or right ?
00589         if (pcx<cx)
00590         {
00591             // In the left
00592             elementArray[i]->NextX=_VectorCell[worldImage][x+y*_CellCountWidth].getFirstX ();
00593             elementArray[i]->PreviousX=NULL;
00594         }
00595         else
00596         {
00597             // In the right
00598             elementArray[i]->PreviousX=_VectorCell[worldImage][x+y*_CellCountWidth].getLastX ();
00599             elementArray[i]->NextX=NULL;
00600         }
00601 
00602         // Next cell
00603         i++;
00604     }
00605 
00606     // Erase last array element
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     // For each changed primitives
00620     CMovePrimitive *changed=_ChangedRoot[worldImage];
00621     while (changed)
00622     {
00623         // Get the world image primitive
00624         CPrimitiveWorldImage *wI;
00625         if (changed->isNonCollisionable())
00626             wI=changed->getWorldImage (0);
00627         else
00628             wI=changed->getWorldImage (worldImage);
00629 
00630         // Next primitive
00631         changed=wI->getNextModified ();
00632 
00633         // Remove it from the list
00634         wI->setInModifiedListFlag (false);
00635     }
00636 
00637     // Empty list
00638     _ChangedRoot[worldImage]=NULL;
00639 }
00640 
00641 // ***************************************************************************
00642 
00643 void CMoveContainer::checkSortedList ()
00644 {
00645     // Check each primitives in the set
00646     std::set<CMovePrimitive*>::iterator ite=_PrimitiveSet.begin();
00647     while (ite!=_PrimitiveSet.end())
00648     {
00649         // Check
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 //  H_AUTO(PACS_MC_evalOneCollision);
00662     H_AUTO(NLPACS_Eval_One_Terrain_Collision);
00663 
00664     // Find its collisions
00665     bool found=false;
00666 
00667     // Get the primitive world image
00668     CPrimitiveWorldImage *wI;
00669     if (primitive->isNonCollisionable())
00670         wI=primitive->getWorldImage (0);
00671     else
00672         wI=primitive->getWorldImage (primitiveWorldImage);
00673 
00674     // Begin time must be the same as beginTime
00675     //nlassert (wI->getInitTime()==beginTime);
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     // Test its static collision
00683     if (_Retriever)
00684     {
00685         // Delta pos..
00686         // Test retriever with the primitive
00687         const TCollisionSurfaceDescVector *result=wI->evalCollision (*_Retriever, _SurfaceTemp, _TestTime, _MaxTestIteration, *primitive);
00688         if (result)
00689         {
00690             // TEST MOVE MUST BE OK !!
00691             testMoveValid=true;
00692 
00693             // Size of the array
00694             uint size=result->size();
00695 
00696             // For each detected collisions
00697             for (uint c=0; c<size; c++)
00698             {
00699                 // Ref on the collision
00700                 CCollisionSurfaceDesc desc=(*result)[c];
00701                 double contactTime = (_DeltaTime-beginTime)*desc.ContactTime+beginTime;
00702 
00703                 /*
00704                  *  If beginTime is 0.999999999 and desc.ContactTime<1.0, contactTime will be 1.0.
00705                  *  In this case, we force contactTime to be beginTime to avoid collision at time == 1.0.
00706                 **/
00707                 if ((contactTime >= 1.0) && (beginTime < 1.0) && (desc.ContactTime < 1.0))
00708                     contactTime = beginTime;
00709 
00710                 // Set the container's time space contact time
00711                 desc.ContactTime = contactTime;
00712 
00713                 // ptr on the surface
00714                 const CRetrievableSurface *surf= _Retriever->getSurfaceById (desc.ContactSurface);
00715 
00716                 // TODO: check surface flags  against primitive flags HERE:
00717                 // Is a wall ?
00718                 bool isWall;
00719                 if(!surf)
00720                     isWall= true;
00721                 else
00722                     isWall= !(surf->isFloor() || surf->isCeiling());
00723 
00724                 // stop on a wall.
00725                 if(isWall)
00726                 {
00727                     // Test move ?
00728                     if (testMove)
00729                     {
00730                         // return contact normal only when testmove and vector provided
00731                         if (contactNormal)
00732                             *contactNormal = desc.ContactNormal;
00733                         return true;
00734                     }
00735                     else
00736                     {
00737                         // OK, collision if we are a collisionable primitive
00738                         newCollision (primitive, desc, primitiveWorldImage, beginTime, staticColInfo);
00739 
00740                         // One collision found
00741                         found=true;
00742                         break;
00743                     }
00744                 }
00745             }
00746         }
00747         else
00748             // More than maxtest made, exit
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 &/* testMoveValid */, CCollisionOTDynamicInfo *dynamicColInfo,
00758                                         CVectorD *contactNormal)
00759 {
00760 //  H_AUTO(PACS_MC_evalOneCollision);
00761     H_AUTO(NLPACS_Eval_One_Primitive_Collision);
00762 
00763     // Find its collisions
00764     bool found=false;
00765 
00766     // Get the primitive world image
00767     CPrimitiveWorldImage *wI;
00768     if (primitive->isNonCollisionable())
00769         wI=primitive->getWorldImage (0);
00770     else
00771         wI=primitive->getWorldImage (primitiveWorldImage);
00772 
00773     // Begin time must be the same as beginTime
00774     //nlassert (wI->getInitTime()==beginTime);
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     // Element table
00782     CMoveElement    tableNotInserted[4];
00783     CMoveElement    *table[4];
00784 
00785     // Single test ?
00786     bool singleTest=testMove;
00787 
00788     // Is in world image
00789     if ((worldImage==primitiveWorldImage) && wI->isInWorldImageFlag())
00790     {
00791         // Get move element table from the primitive
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         // Set table pointers
00800         table[0]=tableNotInserted+0;
00801         table[1]=tableNotInserted+1;
00802         table[2]=tableNotInserted+2;
00803         table[3]=tableNotInserted+3;
00804 
00805         // Get cells
00806         getCells (primitive, worldImage, primitiveWorldImage, table);
00807 
00808         // Force the test
00809         singleTest=true;
00810     }
00811 
00812     // For each move element
00813     for (uint i=0; i<4; i++)
00814     {
00815         // Get the element
00816         CMoveElement    *elm=table[i];
00817 
00818         // Element valid ?
00819         if (elm)
00820         {
00821             // Check
00822             nlassert (elm->Primitive==primitive);
00823             // Primitive to the left
00824 
00825             // Lookup in X sorted list on the left
00826             CMoveElement    *other=elm->PreviousX;
00827             nlassert (other!=elm);
00828 
00829             while (other && (wI->getBBXMin() - other->Primitive->getWorldImage(worldImage)->getBBXMin() < _PrimitiveMaxSize) )
00830             {
00831                 // Other primitive
00832                 CMovePrimitive  *otherPrimitive=other->Primitive;
00833                 CPrimitiveWorldImage *otherWI=otherPrimitive->getWorldImage (worldImage);
00834                 nlassert (otherPrimitive!=primitive);
00835 
00836                 // Continue the check if the other primitive is not int the modified list or if its pointer is higher than primitive
00837                 if ( singleTest || ( (!otherWI->isInModifiedListFlag ()) || (primitive<otherPrimitive) ) )
00838                 {
00839                     // Look if valid in X
00840                     if (wI->getBBXMin() < otherWI->getBBXMax())
00841                     {
00842                         // Look if valid in Y
00843                         if ( (wI->getBBYMin() < otherWI->getBBYMax()) && (otherWI->getBBYMin() < wI->getBBYMax()) )
00844                         {
00845                             // If not already in collision with this primitive
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                 // Next primitive to the left
00861                 other = other->PreviousX;
00862             }
00863 
00864             // Lookup in X sorted list on the right
00865             other=elm->NextX;
00866 
00867             // Primitive to the right
00868             while (other && (other->Primitive->getWorldImage(worldImage)->getBBXMin() < wI->getBBXMax()) )
00869             {
00870                 // Other primitive
00871                 CMovePrimitive  *otherPrimitive=other->Primitive;
00872                 CPrimitiveWorldImage *otherWI=otherPrimitive->getWorldImage (worldImage);
00873                 nlassert (otherPrimitive!=primitive);
00874 
00875                 // Continue the check if the other primitive is not in the modified list or if its pointer is higher than primitive
00876                 if ( singleTest || ( (!otherWI->isInModifiedListFlag ()) || (primitive<otherPrimitive) ) )
00877                 {
00878                     // Look if valid in Y
00879                     if ( (wI->getBBYMin() < otherWI->getBBYMax()) && (otherWI->getBBYMin() < wI->getBBYMax()) )
00880                     {
00881                         // If not already in collision with this primitive
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                 // Next primitive to the left
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 * /* contactNormal */)
00910 {
00911 //  H_AUTO(PACS_MC_evalPrimAgainstPrimCollision);
00912 
00913     // Test the primitive
00914     double firstTime, lastTime;
00915 
00916     // Collision
00917     CCollisionDesc desc;
00918     if (wI->evalCollision (*otherWI, desc, beginTime, _DeltaTime, _TestTime, _MaxTestIteration,
00919                                 firstTime, lastTime, *primitive, *otherPrimitive))
00920     {
00921         // Enter or exit
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         // Return collision time
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                 // Add a trigger
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             // If the other primitive is not an obstacle, skip it because it will re-generate collisions.
00958             if (!collision)
00959                 return false;
00960         }
00961 
00962         // OK, collision
00963         if (contact || enter || exit || overlap)
00964             newCollision (primitive, otherPrimitive, desc, contact, enter, exit, overlap, firstWorldImage, secondWorldImage, secondIsStatic,
00965                             dynamicColInfo);
00966 
00967         // Collision
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     // First primitive
00980     CMovePrimitive  *primitive=_ChangedRoot[worldImage];
00981 
00982     // For each modified primitive
00983     while (primitive)
00984     {
00985         // Get the primitive world image
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         // Find a collision
01002         bool found=false;
01003         bool testMoveValid=false;
01004 
01005         // Eval collision on the terrain
01006         found|=evalOneTerrainCollision (beginTime, primitive, primitiveWorldImage, false, testMoveValid, NULL, NULL);
01007 
01008         // If the primitive can collid other primitive..
01009         if (primitive->getCollisionMask())
01010         {
01011             // Eval collision in each static world image
01012             std::set<uint8>::iterator ite=_StaticWorldImage.begin();
01013             while (ite!=_StaticWorldImage.end())
01014             {
01015                 // Eval in this world image
01016                 found|=evalOnePrimitiveCollision (beginTime, primitive, *ite, primitiveWorldImage, false, true, testMoveValid, NULL, NULL);
01017 
01018                 // Next world image
01019                 ite++;
01020             }
01021         }
01022 
01023         CVectorD d1=wI->getDeltaPosition();
01024 
01025         // If the primitive can collid other primitive..
01026         if (primitive->getCollisionMask())
01027         {
01028             // Eval collision in the world image if not already tested
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         // No collision ?
01036         if (!found)
01037         {
01038             //nlassert ((d0==d1)&&(d0==d2));
01039             //nlassert (f1==f2);
01040 
01041             if (_Retriever&&testMoveValid)
01042             {
01043                 // Do move
01044                 wI->doMove (*_Retriever, _SurfaceTemp, _DeltaTime, _DeltaTime, primitive->getDontSnapToGround());
01045             }
01046             else
01047             {
01048                 // Do move
01049                 wI->doMove (_DeltaTime);
01050             }
01051         }
01052 
01053         // Next primitive
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 //  H_AUTO(PACS_MC_newCollision_short);
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         // Get an ordered time index. Always round to the future.
01074         int index=(int)(ceil (desc.ContactTime*(double)_OtSize/_DeltaTime) );
01075 
01076         // Clamp left.
01077         if (index<0)
01078             index=0;
01079 
01080         // If in time
01081         if (index<(int)_OtSize)
01082         {
01083             // Build info
01084             CCollisionOTDynamicInfo *info = allocateOTDynamicInfo ();
01085             info->init (first, second, desc, collision, enter, exit, inside, uint8(firstWorldImage), uint8(secondWorldImage), secondIsStatic);
01086 
01087             // Add in the primitive list
01088             first->addCollisionOTInfo (info);
01089             second->addCollisionOTInfo (info);
01090 
01091             // Insert in the time ordered table
01092             //nlassert (index<(int)_TimeOT.size());
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             // Check it is after the last hard collision
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 //  H_AUTO(PACS_MC_newCollision_long);
01111 
01112     // Check
01113     nlassert (_Retriever);
01114     nlassert ((staticColInfo && first->isNonCollisionable ()) || (!staticColInfo && first->isCollisionable ()));
01115 
01116     // Get the world image
01117     CPrimitiveWorldImage *wI;
01118     if (first->isNonCollisionable())
01119         wI=first->getWorldImage (0);
01120     else
01121         wI=first->getWorldImage (worldImage);
01122 
01123     // Time
01124     double time=desc.ContactTime;
01125 /*
01126     if (time == _DeltaTime)
01127         time -= _DeltaTime*FLT_EPSILON;
01128 */
01129 
01130     // Check time interval
01131 
01132     //nlassertex (beginTime<=time, ("beginTime=%f, time=%f", beginTime, time));
01133     //nlassertex (time<_DeltaTime, ("time=%f, _DeltaTime=%f", time, _DeltaTime));
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     // Time of the collision.
01147     time-=NELPACS_DIST_BACK/wI->getSpeed().norm();
01148     time=std::max(time, beginTime);
01149     double ratio=(time-beginTime)/(_DeltaTime-beginTime);
01150 
01151 /*
01152     nlassert (ratio>=0);
01153     nlassert (ratio<=1);
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         // Make a new globalposition
01171         UGlobalPosition endPosition=_Retriever->doMove (wI->getGlobalPosition(), wI->getDeltaPosition(),
01172             (float)ratio, _SurfaceTemp, false);
01173 
01174         // Init the info descriptor
01175         staticColInfo->init (first, desc, endPosition, ratio, worldImage);
01176     }
01177     else
01178     {
01179         // Get an ordered time index. Always round to the future.
01180         int index=(int)(ceil (time*(double)_OtSize/_DeltaTime) );
01181 
01182         // Clamp left.
01183         if (index<0)
01184             index=0;
01185 
01186         // If in time
01187         if (index<(int)_OtSize)
01188         {
01189             // Build info
01190             CCollisionOTStaticInfo *info = allocateOTStaticInfo ();
01191 
01192             // Make a new globalposition
01193             UGlobalPosition endPosition=_Retriever->doMove (wI->getGlobalPosition(), wI->getDeltaPosition(),
01194                 (float)ratio, _SurfaceTemp, false);
01195 
01196             // Init the info descriptor
01197             info->init (first, desc, endPosition, ratio, worldImage);
01198 
01199             // Add in the primitive list
01200             first->addCollisionOTInfo (info);
01201 
01202             // Insert in the time ordered table
01203             //nlassert (index<(int)_TimeOT.size());
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             // Check it is after the last hard collision
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     // Element index
01222     uint index=_Triggers.size();
01223 
01224     // Add one element
01225     _Triggers.resize (index+1);
01226 
01227     // Fill info
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     // Check
01239     nlassert (_OtSize==_TimeOT.size());
01240 
01241     // Check linked list
01242     for (uint i=0; i<_OtSize-1; i++)
01243     {
01244         // Check link
01245         nlassert ( _TimeOT[i].getNext() == (&(_TimeOT[i+1])) );
01246         nlassert ( _TimeOT[i+1].getPrevious() == (&(_TimeOT[i])) );
01247     }
01248 
01249     // Check first and last
01250     nlassert ( _TimeOT[0].getPrevious() == NULL );
01251     nlassert ( _TimeOT[_OtSize-1].getNext() == NULL );
01252 }
01253 
01254 // ***************************************************************************
01255 
01256 void CMoveContainer::clearOT ()
01257 {
01258     // Check
01259     nlassert (_OtSize==_TimeOT.size());
01260 
01261     // clear the list
01262     uint i;
01263     for (i=0; i<_OtSize; i++)
01264         _TimeOT[i].clear ();
01265 
01266     // Relink the list
01267     for (i=0; i<_OtSize-1; i++)
01268         // Link the two cells
01269         _TimeOT[i].link (&(_TimeOT[i+1]));
01270 }
01271 
01272 // ***************************************************************************
01273 
01274 void CMoveContainer::removeModifiedFromOT (uint8 worldImage)
01275 {
01276     // For each changed primitives
01277     CMovePrimitive *changed=_ChangedRoot[worldImage];
01278     while (changed)
01279     {
01280         // Remove from ot list
01281         changed->removeCollisionOTInfo ();
01282 
01283         // Get the primitive world image
01284         CPrimitiveWorldImage *wI;
01285         if (changed->isNonCollisionable())
01286             wI=changed->getWorldImage (0);
01287         else
01288             wI=changed->getWorldImage (worldImage);
01289 
01290         // Next primitive
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 // Free all ordered table info
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     // Simply allocate
01325     return new CMovePrimitive (this, firstWorldImage, numWorldImage);
01326 }
01327 
01328 // ***************************************************************************
01329 
01330 void CMoveContainer::freePrimitive (CMovePrimitive *primitive)
01331 {
01332     // Simply deallocate
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     // Simply allocate
01369     return new CMoveElement;
01370 }
01371 
01372 // ***************************************************************************
01373 
01374 void CMoveContainer::freeMoveElement (CMoveElement *element)
01375 {
01376     // Simply deallocate
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     // Allocate primitive
01393     CMovePrimitive *primitive=allocatePrimitive (firstWorldImage, numWorldImage);
01394 
01395     // Add into the set
01396     _PrimitiveSet.insert (primitive);
01397 
01398     // if copy from primitive is not null, copy attributes
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     // Return it
01422     return primitive;
01423 }
01424 
01425 // ***************************************************************************
01426 
01427 UMovePrimitive *CMoveContainer::addNonCollisionablePrimitive (const UMovePrimitive *copyFrom)
01428 {
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 
01471     // CMovePrimitive pointer
01472     CMovePrimitive *prim=(CMovePrimitive*)primitive;
01473 
01474     // Get the primitive world image
01475     for (uint8 i=0; i<prim->getNumWorldImage (); i++)
01476     {
01477         // World image
01478         uint8 worldImage=prim->getFirstWorldImage ()+i;
01479 
01480         // Get primitive world image
01481         CPrimitiveWorldImage *wI=prim->getWorldImage (worldImage);
01482 
01483         // In modified list ?
01484         if (wI->isInModifiedListFlag ())
01485         {
01486             // Non collisionable primitive ?
01487             if (prim->isNonCollisionable())
01488             {
01489                 // Remove from all world image
01490                 removeNCFromModifiedList (prim, worldImage);
01491             }
01492             else
01493             {
01494                 // Remove from modified list
01495                 removeFromModifiedList (prim, worldImage);
01496             }
01497         }
01498     }
01499 
01500     // Remove from the set
01501     _PrimitiveSet.erase (prim);
01502 
01503     // Erase it
01504     freePrimitive (prim);
01505 }
01506 
01507 // ***************************************************************************
01508 
01509 void CMoveContainer::removeNCFromModifiedList (CMovePrimitive* primitive, uint8 worldImage)
01510 {
01511     // For each world image
01512     uint i;
01513     uint worldImageCount = _ChangedRoot.size();
01514     for (i=0; i<worldImageCount; i++)
01515     {
01516         // For each changed primitives
01517         CMovePrimitive *changed=_ChangedRoot[i];
01518         CPrimitiveWorldImage *previous=NULL;
01519         CPrimitiveWorldImage *wI=primitive->getWorldImage (worldImage);
01520 
01521         while (changed)
01522         {
01523             // Get the primitive world image
01524             CPrimitiveWorldImage *changedWI=changed->getWorldImage (worldImage);
01525 
01526             // Remove from ot list
01527             if (changed==primitive)
01528             {
01529                 // There is a previous primitive ?
01530                 if (previous)
01531                     previous->linkInModifiedList (wI->getNextModified ());
01532                 else
01533                     _ChangedRoot[i]=wI->getNextModified ();
01534 
01535                 // Unlink
01536                 wI->linkInModifiedList (NULL);
01537                 wI->setInModifiedListFlag (false);
01538                 break;
01539             }
01540 
01541             // Next primitive
01542             previous=changedWI;
01543             changed=changedWI->getNextModified ();
01544         }
01545 
01546         // Breaked ?
01547         if (changed==primitive)
01548             break;
01549     }
01550 }
01551 
01552 // ***************************************************************************
01553 
01554 void CMoveContainer::removeFromModifiedList (CMovePrimitive* primitive, uint8 worldImage)
01555 {
01556     // For each changed primitives
01557     CMovePrimitive *changed=_ChangedRoot[worldImage];
01558     CPrimitiveWorldImage *previous=NULL;
01559     CPrimitiveWorldImage *wI=primitive->getWorldImage (worldImage);
01560 
01561     while (changed)
01562     {
01563         // Get the primitive world image
01564         CPrimitiveWorldImage *changedWI=changed->getWorldImage (worldImage);
01565 
01566         // Remove from ot list
01567         if (changed==primitive)
01568         {
01569             // There is a previous primitive ?
01570             if (previous)
01571                 previous->linkInModifiedList (wI->getNextModified ());
01572             else
01573                 _ChangedRoot[worldImage]=wI->getNextModified ();
01574 
01575             // Unlink
01576             wI->linkInModifiedList (NULL);
01577             wI->setInModifiedListFlag (false);
01578             break;
01579         }
01580 
01581         // Next primitive
01582         previous=changedWI;
01583         changed=changedWI->getNextModified ();
01584     }
01585 }
01586 
01587 // ***************************************************************************
01588 
01589 void CMoveContainer::unlinkMoveElement  (CMoveElement *element, uint8 worldImage)
01590 {
01591     // Some checks
01592     nlassert (element->X<_CellCountWidth);
01593     nlassert (element->Y<_CellCountHeight);
01594 
01595     // Unlink it
01596     CMoveCell &cell=_VectorCell[worldImage][element->X+element->Y*_CellCountWidth];
01597     cell.unlinkX (element);
01598     //cell.unlinkY (element);
01599 }
01600 
01601 // ***************************************************************************
01602 
01603 void CMoveContainer::reaction (const CCollisionOTInfo& first)
01604 {
01605 //  H_AUTO(PACS_MC_reaction);
01606 
01607     // Static collision ?
01608     if (first.isCollisionAgainstStatic())
01609     {
01610         // Check mode
01611         nlassert (_Retriever);
01612 
01613         // Cast
01614         const CCollisionOTStaticInfo *staticInfo=safe_cast<const CCollisionOTStaticInfo*> (&first);
01615 
01616         // Get the primitive world image
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         // Dynamic collision
01625         wI->reaction ( staticInfo->getCollisionDesc (), staticInfo->getGlobalPosition (),
01626                         *_Retriever, staticInfo->getDeltaTime(), _DeltaTime, *staticInfo->getPrimitive (), *this, staticInfo->getWorldImage());
01627     }
01628     else
01629     {
01630         // Cast
01631         const CCollisionOTDynamicInfo *dynInfo=safe_cast<const CCollisionOTDynamicInfo*> (&first);
01632 
01633         // Get the primitives world image
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         // Dynamic collision
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     // Add this world image in the static set of world image
01680     _StaticWorldImage.insert (worldImage);
01681 }
01682 
01683 // ***************************************************************************
01684 
01685 void CMoveContainer::duplicateWorldImage (uint8 source, uint8 dest)
01686 {
01687 
01688     // Cell count
01689     uint cellCount=_CellCountWidth*_CellCountHeight;
01690 
01691     // Clear dest modified list
01692     clearModifiedList (dest);
01693 
01694     // Clear destination cells
01695     uint i;
01696     for (i=0; i<cellCount; i++)
01697     {
01698         // Get first X
01699         CMoveElement *elm;
01700         while ((elm=_VectorCell[dest][i].getFirstX ()))
01701         {
01702             // Get primitive world image
01703             CPrimitiveWorldImage *wI=elm->Primitive->getWorldImage (dest);
01704 
01705             // Remove the primitive
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     // Duplicate destination cells
01716     for (i=0; i<cellCount; i++)
01717     {
01718         // Get first X
01719         CMoveElement *elm=_VectorCell[source][i].getFirstX ();
01720         while (elm)
01721         {
01722             // Get primitive world image
01723             CPrimitiveWorldImage *wISource=elm->Primitive->getWorldImage (source);
01724             CPrimitiveWorldImage *wIDest=elm->Primitive->getWorldImage (dest);
01725 
01726             // First time the primitive is visited ?
01727             if (wIDest->getMoveElement (0)==NULL)
01728             {
01729                 wIDest->copy (*wISource);
01730             }
01731 
01732             // Add at the end of the list
01733             wIDest->addMoveElementendOfList (_VectorCell[dest][i], elm->X, elm->Y, elm->Primitive, *this);
01734 
01735             // Added ?
01736             nlassert (wIDest->getMoveElement (0)!=NULL);
01737 
01738             // Next primitive
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     // Create a CMoveContainer
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     // Cast
01762     nlassert (dynamic_cast<CGlobalRetriever*>(retriever));
01763     CGlobalRetriever* r=static_cast<CGlobalRetriever*>(retriever);
01764 
01765     // Create a CMoveContainer
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 /* = false*/, const NLMISC::CVector &scale /* = NLMISC::CVector(1.0f, 1.0f, 1.0f)*/)
01792 {
01793 
01794     CPrimitiveBlock *block = NLMISC::safe_cast<CPrimitiveBlock *>(pb);
01795     // Reserve the pointer array
01796     if (primitives)
01797         primitives->reserve (block->Primitives.size());
01798 
01799     // For each primitive
01800     uint prim;
01801     for (prim=0; prim<block->Primitives.size(); prim++)
01802     {
01803         // Create a collisionable primitive
01804         UMovePrimitive *primitive = addCollisionablePrimitive (firstWorldImage, numWorldImage);
01805 
01806         // Ref on the block descriptor
01807         CPrimitiveDesc &desc = block->Primitives[prim];
01808 
01809         // Set its properties
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             // ONLY ASSUME UNIFORM SCALE ON X/Y
01822             primitive->setSize (desc.Length[0]*scale.x, desc.Length[1]*scale.x);
01823         }
01824         else
01825         {
01826             // ONLY ASSUME UNIFORM SCALE ON X/Y
01827             nlassert (desc.Type == UMovePrimitive::_2DOrientedCylinder);
01828             primitive->setRadius (desc.Length[0]*scale.x);
01829         }
01830         primitive->setHeight (desc.Height*scale.z);
01831 
01832         // Insert the primitives
01833 
01834         // For each world image
01835         uint wI;
01836         for (wI=firstWorldImage; wI<(uint)(firstWorldImage+numWorldImage); wI++)
01837         {
01838             // Insert the primitive
01839             primitive->insertInWorldImage (uint8(wI));
01840 
01841             // Final position&
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             // Set the primtive orientation
01850             if (desc.Type == UMovePrimitive::_2DOrientedBox)
01851                 primitive->setOrientation ((float)fmod ((float)(desc.Orientation + orientation), (float)(2.0f*Pi)), uint8(wI));
01852 
01853             // Set the primitive global position
01854             primitive->setGlobalPosition (finalPos, uint8(wI));
01855         }
01856 
01857         // Feedback asked ?
01858         if (primitives)
01859         {
01860             // Add the pointer
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 /*= false*/)
01870 {
01871 
01872     // Check world image
01873     if ( (uint)(firstWorldImage+numWorldImage) > _ChangedRoot.size() )
01874     {
01875         nlwarning ("Invalid world image number.");
01876         return false;
01877     }
01878 
01879     // Try to load the file
01880     CIFile file;
01881     if (file.open (filename))
01882     {
01883         // Create the XML stream
01884         CIXml input;
01885 
01886         // Init
01887         if (input.init (file))
01888         {
01889             // The primitive block
01890             CPrimitiveBlock block;
01891 
01892             // Serial it
01893             file.serial (block);
01894 
01895             // add primitives
01896             addCollisionnablePrimitiveBlock(&block, firstWorldImage, numWorldImage, primitives, orientation, position, dontSnapToGround);
01897 
01898             return true;
01899         }
01900         else
01901         {
01902             // Warning
01903             nlwarning ("Can't init XML stream with file %s.", filename);
01904 
01905             return false;
01906         }
01907     }
01908     else
01909     {
01910         // Warning
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     // New test time
01944     _TestTime++;
01945 
01946     // Clear triggers
01947     _Triggers.clear ();
01948 
01949     // Only non-collisionable primitives
01950     if (!primitive->isCollisionable())
01951     {
01952         // Delta time
01953         _DeltaTime=deltaTime;
01954 
01955         // Begin of the time slice to compute
01956         double beginTime = 0;
01957         double collisionTime = deltaTime;
01958 
01959         // Get the world image
01960         CPrimitiveWorldImage *wI = ((CMovePrimitive*)primitive)->getWorldImage (0);
01961 
01962         CCollisionOTInfo *firstCollision = NULL;
01963         do
01964         {
01965             //nlassert (beginTime < 1.0);
01966             if (beginTime >= 1.0)
01967             {
01968                 nlwarning("PACS: evalNCPrimitiveCollision() failure, beginTime [%f] >= 1.0", beginTime);
01969                 return false;
01970             }
01971 
01972             // Update the primitive
01973             wI->update (beginTime, deltaTime, *(CMovePrimitive*)primitive);
01974 
01975             CVectorD d0=wI->getDeltaPosition();
01976 
01977             // Eval collision again the terrain
01978             bool testMoveValid = false;
01979             CCollisionOTStaticInfo staticColInfo;
01980             CCollisionOTDynamicInfo dynamicColInfoWI0;
01981             CCollisionOTDynamicInfo dynamicColInfoWI;
01982 
01983             firstCollision = NULL;
01984 
01985             // If collision found, note it is on the landscape
01986             if (evalOneTerrainCollision (beginTime, (CMovePrimitive*)primitive, worldImage, false, testMoveValid, &staticColInfo, NULL))
01987             {
01988                 firstCollision = &staticColInfo;
01989             }
01990 
01991             // Eval collision again the static primitives
01992             std::set<uint8>::iterator ite=_StaticWorldImage.begin();
01993             while (ite!=_StaticWorldImage.end())
01994             {
01995                 // Eval in this world image
01996                 if (evalOnePrimitiveCollision (beginTime, (CMovePrimitive*)primitive, *ite, worldImage, false, true, testMoveValid, &dynamicColInfoWI0, NULL))
01997                 {
01998                     // First collision..
01999                     if (!firstCollision || (firstCollision->getCollisionTime () > dynamicColInfoWI0.getCollisionTime ()))
02000                     {
02001                         firstCollision = &dynamicColInfoWI0;
02002                     }
02003                 }
02004 
02005                 // Next world image
02006                 ite++;
02007             }
02008 
02009             // Checks
02010             CVectorD d1=wI->getDeltaPosition();
02011 
02012             // Eval collision again the world image
02013             if (_StaticWorldImage.find (worldImage)==_StaticWorldImage.end())
02014             {
02015                 if (evalOnePrimitiveCollision (beginTime, (CMovePrimitive*)primitive, worldImage, worldImage, false, false, testMoveValid, &dynamicColInfoWI, NULL))
02016                 {
02017                     // First collision..
02018                     if (!firstCollision || (firstCollision->getCollisionTime () > dynamicColInfoWI.getCollisionTime ()))
02019                     {
02020                         firstCollision = &dynamicColInfoWI;
02021                     }
02022                 }
02023             }
02024 
02025             // Checks
02026             CVectorD d2=wI->getDeltaPosition();
02027             nlassert ((d0==d1)&&(d0==d2));
02028 
02029 //          if (found)
02030 //              nlstop;
02031 
02032             // Reaction
02033             if (firstCollision)
02034             {
02035                 collisionTime = firstCollision->getCollisionTime ();
02036                 reaction (*firstCollision);
02037                 //nlassert (collisionTime != 1);
02038 
02039                 if (collisionTime == 1)
02040                 {
02041                     nlinfo("PACS: evalNCPrimitiveCollision() failure, collisionTime [%f] == 1", collisionTime);
02042                     return false;
02043                 }
02044             }
02045             else
02046             {
02047                 // Retriever mode ?
02048                 if (_Retriever&&testMoveValid)
02049                 {
02050                     // Do move
02051                     wI->doMove (*_Retriever, _SurfaceTemp, deltaTime, collisionTime, ((CMovePrimitive*)primitive)->getDontSnapToGround());
02052                 }
02053                 else
02054                 {
02055                     // Do move
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 } // NLPACS

Generated on Thu Jan 7 08:26:36 2010 for NeL by  doxygen 1.6.1