00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "eGrid.h"
00029 #include "eTess2.h"
00030 #include "ePath.h"
00031 #include "eGameObject.h"
00032 #include "tConsole.h"
00033 #include "eWall.h"
00034 #include "eSensor.h"
00035
00036
00037 static tHeap<eHalfEdge> openEdges;
00038 static tHeap<eHalfEdge> closedEdges;
00039
00040
00041
00042 static REAL Distance(const eHalfEdge* a, const eCoord& b)
00043 {
00044 tASSERT( a );
00045 tASSERT( a->Point() );
00046
00047 return sqrt(((*a->Point()) - b).NormSquared());
00048 }
00049
00050
00051
00052 static REAL Modifier(const eGameObject *gameObject,
00053 const eHalfEdge *edge)
00054 {
00055 tASSERT(edge);
00056 tASSERT(gameObject);
00057
00058 eWall* w = edge->GetWall();
00059 if (!w && edge->Other())
00060 w = edge->Other()->GetWall();
00061
00062 return gameObject->PathfindingModifier(w);
00063 }
00064
00065 static bool CanPass(const eGameObject *gameObject,
00066 const eHalfEdge *edge)
00067 {
00068 tASSERT(edge);
00069 tASSERT(gameObject);
00070
00071 eWall* w = edge->GetWall();
00072 if (!w && edge->Other())
00073 w = edge->Other()->GetWall();
00074
00075 return !gameObject->EdgeIsDangerous(w, gameObject->LastTime(), 0.5f);
00076 }
00077
00078
00079
00080
00081 eWall* eHalfEdge::CrossesNewWall(const eGrid *grid) const
00082 {
00083
00084 for(int i=grid->wallsNotYetInserted.Len()-1;i>=0;i--)
00085 {
00086 const eHalfEdge *other_e=grid->wallsNotYetInserted(i)->Edge();
00087 if (
00088 other_e->Point() && other_e->Other() && other_e->Other()->Point())
00089 {
00090 tJUST_CONTROLLED_PTR< ePoint > new_cross_p=IntersectWith(other_e);
00091 if (new_cross_p)
00092 {
00093 REAL e_ratio =Ratio(*new_cross_p);
00094 REAL o_ratio =other_e->Ratio(*new_cross_p);
00095 if (0<=e_ratio && 1>=e_ratio &&
00096 0<=o_ratio && 1>=o_ratio)
00097 {
00098 eWall *w = other_e->GetWall();
00099 if (!w)
00100 w = other_e->Other()->GetWall();
00101
00102 if (w)
00103 return w;
00104 }
00105 }
00106 }
00107 }
00108 return NULL;
00109 }
00110
00111 void eHalfEdge::ClearPathData()
00112 {
00113 while (openEdges.Len())
00114 {
00115 eHalfEdge *e = openEdges.Remove(0);
00116 e->origin_ = PATH_NONE;
00117 }
00118 while (closedEdges.Len())
00119 {
00120 eHalfEdge *e = closedEdges.Remove(0);
00121 e->origin_ = PATH_NONE;
00122 }
00123 }
00124
00125
00126 REAL EdgePenalty(const eHalfEdge *e, const eGameObject *g)
00127 {
00128 eCoord probePre = e->Vec().Turn(0, 1);
00129 eCoord probe = probePre * (1/sqrt(probePre.NormSquared()));
00130
00131 eSensor s (const_cast<eGameObject * >( g ), *e->Point() + e->Vec() * .5f + probePre * .0001f, probe);
00132 s.SetCurrentFace(e->Face());
00133 s.detect(1);
00134 if (s.hit > 1)
00135 s.hit = 1;
00136
00137 return 100 * (1/(s.hit + .1) - (1/1.1));
00138 }
00139
00140 void eHalfEdge::SetMinPathLength( REAL length, tHeapBase& heap, ePATH_ORIGIN origin )
00141 {
00142 origin_ = origin;
00143 tHeapElement::SetVal( length, heap );
00144
00145 tASSERT( &heap == Heap() );
00146 }
00147
00148
00149 void eHalfEdge::FindPath(const eCoord& startPoint, const eFace* startFace,
00150 const eCoord& stopPoint , const eFace* stopFace,
00151 const eGameObject* gameObject,
00152 ePath& path)
00153 {
00154 tASSERT( startFace );
00155 tASSERT( stopFace );
00156 tASSERT( gameObject );
00157
00158
00159 ClearPathData();
00160 path.Clear();
00161
00162
00163 {
00164 eHalfEdge *run = startFace->Edge();
00165 for (int i=2; i>=0; i--)
00166 {
00167 run->SetMinPathLength( Distance(run, startPoint) + Distance(run, stopPoint), openEdges, PATH_START );
00168
00169 run = run->Next();
00170 }
00171 }
00172
00173
00174 eHalfEdge* stopEdge = NULL;
00175
00176 while (openEdges.Len() > 0 && !stopEdge)
00177 {
00178
00179
00180
00181
00182 eHalfEdge *e = openEdges.Remove(0);
00183
00184 int origin = e->origin_;
00185 origin |= PATH_CLOSED;
00186 e->origin_ = static_cast<ePATH_ORIGIN>(origin);
00187
00188 closedEdges.Insert(e);
00189
00190
00191 if (e->Face() == stopFace)
00192 stopEdge = e;
00193
00194 #ifdef DEBUG
00195
00196 #endif
00197
00198 eHalfEdge *next = e->Next();
00199 eHalfEdge *prev = NULL;
00200
00201 eHalfEdge *other_next = e->Other()->Next();
00202 eHalfEdge *prev_other = NULL;
00203
00204
00205 {
00206 if (next)
00207 {
00208 prev = next->Next();
00209
00210
00211 if (!e->CrossesNewWall(gameObject->Grid()))
00212 {
00213
00214 REAL closer = Distance(e, stopPoint) - Distance(next, stopPoint);
00215
00216
00217 REAL way = sqrt(e->Vec().NormSquared()) * Modifier(gameObject, e);
00218
00219
00220 next->PossiblePath(PATH_PREV, e->MinPathLength() + way - closer + EdgePenalty(e, gameObject) );
00221 }
00222 }
00223 }
00224
00225
00226
00227 if (prev)
00228 {
00229 tASSERT(prev->Next() == e);
00230 prev_other = prev->Other();
00231
00232
00233 if (!prev->CrossesNewWall(gameObject->Grid()))
00234 {
00235
00236 REAL closer = Distance(e, stopPoint) - Distance(prev, stopPoint);
00237
00238
00239 REAL way = sqrt(prev->Vec().NormSquared()) * Modifier(gameObject, e);
00240
00241
00242 prev->PossiblePath(PATH_NEXT, e->MinPathLength() + way - closer + EdgePenalty(e, gameObject));
00243 }
00244 }
00245
00246
00247
00248
00249
00250
00251 if (other_next && CanPass(gameObject, e))
00252 other_next->PossiblePath(PATH_PREV_OTHER, e->MinPathLength() + EdgePenalty(e, gameObject) + .000001f);
00253 if (prev_other && CanPass(gameObject, prev))
00254 prev_other->PossiblePath(PATH_OTHER_NEXT, e->MinPathLength() + EdgePenalty(e, gameObject) + .000001f);
00255 }
00256
00257
00258 if (!stopEdge)
00259 {
00260 ClearPathData();
00261 return;
00262 }
00263
00264
00265
00266
00267 #ifdef DEBUG
00268 con << "Found path.\n";
00269
00270 #endif
00271
00272 path.Add(stopPoint);
00273
00274 eHalfEdge* run = stopEdge;
00275 while (run && run->Face() != startFace)
00276 {
00277 path.Add(run);
00278
00279 #ifdef DEBUG
00280
00281 #endif
00282
00283 tASSERT(run->origin_ >= PATH_CLOSED);
00284
00285 switch (run->origin_-PATH_CLOSED)
00286 {
00287 case (PATH_NEXT):
00288 run = run->Next();
00289 break;
00290 case (PATH_PREV):
00291 run = run->Next()->Next();
00292 break;
00293 case (PATH_OTHER_NEXT):
00294 run = run->Other()->Next();
00295 break;
00296 case (PATH_PREV_OTHER):
00297 run = run->Next()->Next()->Other();
00298 break;
00299 default:
00300 tERR_WARN("Pathfinding error!\n");
00301 run = startFace->Edge();
00302 }
00303 }
00304
00305
00306
00307
00308 #ifdef DEBUG
00309
00310 #endif
00311
00312 ClearPathData();
00313 }
00314
00315
00316 void eHalfEdge::PossiblePath( ePATH_ORIGIN newOrigin, REAL minLength )
00317 {
00318
00319 if( origin_ == PATH_NONE )
00320 {
00321
00322
00323 SetMinPathLength( minLength, openEdges, newOrigin );
00324
00325 #ifdef DEBUG
00326
00327
00328 #endif
00329 }
00330 else if( minLength < MinPathLength() && origin_ < PATH_CLOSED)
00331 {
00332
00333 SetMinPathLength( minLength, openEdges, newOrigin );
00334
00335 #ifdef DEBUG
00336
00337
00338 #endif
00339
00340 }
00341 }
00342
00343
00344 tHeapBase *eHalfEdge::Heap() const
00345 {
00346 if (origin_ >= PATH_NONE)
00347 return NULL;
00348 if (origin_ >= PATH_CLOSED)
00349 return &closedEdges;
00350
00351 return &openEdges;
00352 }
00353
00354
00355 static ePath* lastPath = NULL;
00356
00357 #ifdef DEBUG
00358 #include "rRender.h"
00359
00360 void ePath::RenderLast()
00361 {
00362 #ifndef DEDICATED
00363 if (!lastPath)
00364 return;
00365
00366 glDisable(GL_TEXTURE_2D);
00367 glDisable(GL_LIGHTING);
00368
00369 glColor4f(1,0,0,1);
00370
00371 BeginLineStrip();
00372 for (int i = lastPath->positions.Len()-1; i>=0; i--)
00373 {
00374 eCoord c = lastPath->positions(i) + lastPath->offsets(i);
00375 Vertex(c.x, c.y, 0.1f);
00376 }
00377 RenderEnd();
00378
00379 glColor4f(1,1,0,1);
00380
00381 BeginLineStrip();
00382 if (lastPath->current >= 0 && lastPath->positions.Len() > 0)
00383 {
00384 eCoord c = lastPath->CurrentPosition();
00385 Vertex(c.x, c.y, 0);
00386 Vertex(c.x, c.y, 50);
00387 }
00388 RenderEnd();
00389 #endif
00390 }
00391 #endif
00392
00393 bool ePath::Proceed()
00394 {
00395 if (current > 0)
00396 {
00397 current--;
00398 return true;
00399 }
00400 else
00401 return false;
00402 }
00403
00404 bool ePath::GoBack()
00405 {
00406 if (current < positions.Len()-1)
00407 {
00408 current++;
00409 return true;
00410 }
00411 else
00412 return false;
00413 }
00414
00415 ePath::ePath(){
00416 current=-1;
00417 }
00418
00419 ePath::~ePath(){
00420 if ( lastPath == this )
00421 lastPath = NULL;
00422 }
00423
00424 void ePath::Add(eHalfEdge *e)
00425 {
00426 tASSERT (e->Point() && e->Next() && e->Next()->Point() && e->Next()->Next() && e->Next()->Next()->Point());
00427
00428 current++;
00429
00430 eCoord pos = *e->Point();
00431
00432 eCoord offset = ((*e->Next()->Next()->Point() + *e->Next()->Point()) * .5f - pos) * .5f;
00433
00434
00435 REAL ol = sqrt(offset.NormSquared());
00436 if (ol > 1)
00437 offset = offset * (1/ol);
00438
00439 positions[current] = pos;
00440 offsets[current] = offset;
00441 }
00442
00443 void ePath::Add(const eCoord& point)
00444 {
00445 current++;
00446
00447 positions[current] = point;
00448 offsets[current] = eCoord(0, 0);
00449 }
00450
00451
00452 void ePath::Clear()
00453 {
00454 lastPath = this;
00455
00456 current=-1;
00457
00458 offsets.SetLen(0);
00459 positions.SetLen(0);
00460 }
00461
00462
00463
00464