00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "std3d.h"
00025
00026 #include "nel/3d/u_visual_collision_entity.h"
00027
00028 #include "nel/3d/visual_collision_entity.h"
00029 #include "nel/3d/landscape.h"
00030 #include "nel/3d/dru.h"
00031 #include "nel/3d/driver.h"
00032 #include "nel/3d/tile_bank.h"
00033 #include "nel/misc/hierarchical_timer.h"
00034
00035
00036 using namespace std;
00037 using namespace NLMISC;
00038
00039
00040 namespace NL3D
00041 {
00042
00043
00044
00045
00046 const float CVisualCollisionEntity::BBoxRadius= 10;
00047 const float CVisualCollisionEntity::BBoxRadiusZ= 20;
00048 const uint32 CVisualCollisionEntity::_StartPatchQuadBlockSize= 64;
00049 vector<CPatchBlockIdent> CVisualCollisionEntity::_TmpBlockIds;
00050 vector<CPatchQuadBlock*> CVisualCollisionEntity::_TmpPatchQuadBlocks;
00051
00052
00053
00054 CVisualCollisionEntity::CVisualCollisionEntity(CVisualCollisionManager *owner) : _LandscapeQuadGrid(owner)
00055 {
00056 _Owner= owner;
00057 _PatchQuadBlocks.reserve(_StartPatchQuadBlockSize);
00058
00059 _CurrentBBoxValidity.setHalfSize(CVector::Null);
00060
00061 _GroundMode= true;
00062 _CeilMode= false;
00063 _SnapToRenderedTesselation= true;
00064
00065 _LastGPTValid= false;
00066 }
00067
00068
00069
00070 CVisualCollisionEntity::~CVisualCollisionEntity()
00071 {
00072
00073 for(sint i=0; i<(sint)_PatchQuadBlocks.size(); i++)
00074 {
00075 _Owner->deletePatchQuadBlock(_PatchQuadBlocks[i]);
00076 }
00077 _PatchQuadBlocks.clear();
00078
00079
00080 _LandscapeQuadGrid.clear();
00081 }
00082
00083
00084
00085 bool CVisualCollisionEntity::snapToGround(CVector &pos)
00086 {
00087 CVector normal;
00088
00089 return snapToGround(pos, normal);
00090 }
00091
00092
00093
00094 CTrianglePatch *CVisualCollisionEntity::getPatchTriangleUnderUs(const CVector &pos, CVector &res)
00095 {
00096
00097 if(_Owner->_Landscape==NULL)
00098 {
00099 _LastGPTValid= false;
00100 return NULL;
00101 }
00102
00103
00104
00105
00106
00107 if(_LastGPTValid && (pos==_LastGPTPosInput || pos==_LastGPTPosOutput) )
00108 {
00109
00110 res= _LastGPTPosOutput;
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120 return &_LastGPTTrianglePatch;
00121 }
00122
00123
00124
00125
00126 testComputeLandscape(pos);
00127
00128
00129
00130
00131 CVisualTileDescNode *ptr= _LandscapeQuadGrid.select(pos);
00132
00133
00134
00135
00136 float sqrBestDist= sqr(1000.f);
00137 CVector hit;
00138
00139 CVector segP0= pos - CVector(0,0,100);
00140 CVector segP1= pos + CVector(0,0,100);
00141
00142
00143
00144 static vector<CTrianglePatch> testTriangles;
00145
00146 testTriangles.clear();
00147 sint bestTriangle= 0;
00148
00149
00150
00151 while(ptr)
00152 {
00153
00154 sint qbId= ptr->PatchQuadBlocId;
00155 nlassert(qbId>=0 && qbId<(sint)_PatchQuadBlocks.size());
00156 CPatchQuadBlock &qb= *_PatchQuadBlocks[qbId];
00157
00158
00159 sint idStart= testTriangles.size();
00160 testTriangles.resize(idStart+2);
00161 qb.buildTileTriangles((uint8)ptr->QuadId, &testTriangles[idStart]);
00162
00163
00164 for(sint i=0; i<2; i++)
00165 {
00166 CTrianglePatch &tri= testTriangles[idStart+i];
00167
00168
00169 if(triangleIntersect(tri, segP0, segP1, hit))
00170 {
00171
00172 float sqrdist= (hit-pos).sqrnorm();
00173 if(sqrdist<sqrBestDist)
00174 {
00175 bestTriangle= idStart+i;
00176 res= hit;
00177 sqrBestDist= sqrdist;
00178 }
00179 }
00180 }
00181
00182
00183
00184 ptr= ptr->Next;
00185 }
00186
00187
00188
00189 if(sqrBestDist<sqr(1000))
00190 {
00191
00192 _LastGPTValid= true;
00193 _LastGPTTrianglePatch= testTriangles[bestTriangle];
00194 _LastGPTPosInput= pos;
00195 _LastGPTPosOutput= res;
00196
00197 return &_LastGPTTrianglePatch;
00198 }
00199 else
00200 {
00201 _LastGPTValid= false;
00202 return NULL;
00203 }
00204
00205 }
00206
00207
00208
00209 bool CVisualCollisionEntity::snapToGround(CVector &pos, CVector &normal)
00210 {
00211
00212 CVector res;
00213 CTrianglePatch *tri= getPatchTriangleUnderUs(pos, res);
00214
00215
00216 if( tri )
00217 {
00218 if(_SnapToRenderedTesselation)
00219 {
00220
00221 pos= res;
00222
00223
00224 snapToLandscapeCurrentTesselation(pos, *tri);
00225 }
00226 else
00227 {
00228
00229 pos= res;
00230 }
00231
00232
00233
00234 normal= (tri->V1-tri->V0)^(tri->V2-tri->V0);
00235 normal.normalize();
00236
00237 return true;
00238 }
00239 else
00240 return false;
00241 }
00242
00243
00244
00245 void CVisualCollisionEntity::computeUvForPos(const CTrianglePatch &tri, const CVector &pos, CUV &uv)
00246 {
00247
00248 CVector Gu;
00249 CVector Gv;
00250 tri.computeGradient(tri.Uv0.U, tri.Uv1.U, tri.Uv2.U, Gu);
00251 tri.computeGradient(tri.Uv0.V, tri.Uv1.V, tri.Uv2.V, Gv);
00252
00253 uv.U= tri.Uv0.U + Gu*(pos-tri.V0);
00254 uv.V= tri.Uv0.V + Gv*(pos-tri.V0);
00255 }
00256
00257
00258
00259 void CVisualCollisionEntity::snapToLandscapeCurrentTesselation(CVector &pos, const CTrianglePatch &tri)
00260 {
00261
00262 CUV uv;
00263 computeUvForPos(tri, pos, uv);
00264
00265
00266 CVector posLand;
00267 posLand= _Owner->_Landscape->getTesselatedPos(tri.PatchId, uv);
00268
00269
00270 pos.z= posLand.z;
00271 }
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297 bool CVisualCollisionEntity::triangleIntersect2DGround(CTriangle &tri, const CVector &pos0)
00298 {
00299 CVector &p0= tri.V0;
00300 CVector &p1= tri.V1;
00301 CVector &p2= tri.V2;
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313 float a,b,c;
00314
00315 a= -(p1.y-p0.y);
00316 b= (p1.x-p0.x);
00317 c= -(p0.x*a + p0.y*b);
00318 if( (a*pos0.x + b*pos0.y + c) < 0) return false;
00319
00320 a= -(p2.y-p1.y);
00321 b= (p2.x-p1.x);
00322 c= -(p1.x*a + p1.y*b);
00323 if( (a*pos0.x + b*pos0.y + c) < 0) return false;
00324
00325 a= -(p0.y-p2.y);
00326 b= (p0.x-p2.x);
00327 c= -(p2.x*a + p2.y*b);
00328 if( (a*pos0.x + b*pos0.y + c) < 0) return false;
00329
00330 return true;
00331 }
00332
00333
00334 bool CVisualCollisionEntity::triangleIntersect2DCeil(CTriangle &tri, const CVector &pos0)
00335 {
00336 CVector &p0= tri.V0;
00337 CVector &p1= tri.V1;
00338 CVector &p2= tri.V2;
00339
00340
00341
00342
00343 float a,b,c;
00344
00345 a= -(p1.y-p0.y);
00346 b= (p1.x-p0.x);
00347 c= -(p0.x*a + p0.y*b);
00348 if( (a*pos0.x + b*pos0.y + c) > 0) return false;
00349
00350 a= -(p2.y-p1.y);
00351 b= (p2.x-p1.x);
00352 c= -(p1.x*a + p1.y*b);
00353 if( (a*pos0.x + b*pos0.y + c) > 0) return false;
00354
00355 a= -(p0.y-p2.y);
00356 b= (p0.x-p2.x);
00357 c= -(p2.x*a + p2.y*b);
00358 if( (a*pos0.x + b*pos0.y + c) > 0) return false;
00359
00360 return true;
00361 }
00362
00363
00364 bool CVisualCollisionEntity::triangleIntersect(CTriangle &tri, const CVector &pos0, const CVector &pos1, CVector &hit)
00365 {
00366 CVector &p0= tri.V0;
00367 CVector &p1= tri.V1;
00368 CVector &p2= tri.V2;
00369
00370 bool ok= false;
00371 if( _GroundMode && triangleIntersect2DGround(tri, pos0) )
00372 ok= true;
00373 if(!ok && _CeilMode && triangleIntersect2DCeil(tri, pos0) )
00374 ok= true;
00375 if(!ok)
00376 return false;
00377
00378
00379
00380 CVector tmp;
00381
00382 CPlane plane;
00383 plane.make (p0, p1, p2);
00384
00385 tmp= plane.intersect(pos0, pos1);
00386
00387 float h= tmp.z;
00388
00389 if(h>pos1.z) return false;
00390 if(h<pos0.z) return false;
00391
00392
00393
00394 hit.x= pos0.x;
00395 hit.y= pos0.y;
00396 hit.z= h;
00397 return true;
00398 }
00399
00400
00401 void CVisualCollisionEntity::testComputeLandscape(const CVector &pos)
00402 {
00403
00404 if(_CurrentBBoxValidity.getHalfSize()==CVector::Null || !_CurrentBBoxValidity.include(pos))
00405 {
00406
00407 doComputeLandscape(pos);
00408 }
00409 }
00410
00411
00412 void CVisualCollisionEntity::doComputeLandscape(const CVector &pos)
00413 {
00414 sint i;
00415
00416
00417
00418
00419 CAABBox bboxToIncludePatchs;
00420 bboxToIncludePatchs.setCenter(pos);
00421 bboxToIncludePatchs.setHalfSize(CVector(BBoxRadius, BBoxRadius, BBoxRadiusZ));
00422
00423 _CurrentBBoxValidity.setCenter(pos);
00424 _CurrentBBoxValidity.setHalfSize(CVector(BBoxRadius, BBoxRadius, BBoxRadiusZ/2));
00425
00426
00427
00428
00429 _Owner->_Landscape->buildPatchBlocksInBBox(bboxToIncludePatchs, _TmpBlockIds);
00430
00431
00432
00433
00434
00435
00436
00437
00438 sort(_TmpBlockIds.begin(), _TmpBlockIds.end());
00439
00440
00441 _TmpPatchQuadBlocks= _PatchQuadBlocks;
00442
00443
00444 _PatchQuadBlocks.resize(_TmpBlockIds.size());
00445
00446
00447
00448 uint iOld=0;
00449
00450 for(i=0; i<(sint)_PatchQuadBlocks.size();)
00451 {
00452
00453 CPatchBlockIdent newBi= _TmpBlockIds[i];
00454
00455
00456 bool oldEnd= false;
00457 CPatchBlockIdent oldBi;
00458 if(iOld==_TmpPatchQuadBlocks.size())
00459 oldEnd= true;
00460 else
00461 oldBi= _TmpPatchQuadBlocks[iOld]->PatchBlockId;
00462
00463
00464 if(oldEnd || newBi < oldBi)
00465 {
00466
00467 _PatchQuadBlocks[i]= _Owner->newPatchQuadBlock();
00468
00469 _PatchQuadBlocks[i]->PatchBlockId= _TmpBlockIds[i];
00470 _Owner->_Landscape->fillPatchQuadBlock(*_PatchQuadBlocks[i]);
00471
00472
00473 i++;
00474 }
00475
00476 else if(newBi==oldBi)
00477 {
00478
00479 _PatchQuadBlocks[i]= _TmpPatchQuadBlocks[iOld];
00480
00481
00482 i++;
00483 iOld++;
00484 }
00485
00486 else
00487 {
00488 _Owner->deletePatchQuadBlock(_TmpPatchQuadBlocks[iOld]);
00489
00490 iOld++;
00491 }
00492 }
00493
00494 for(;iOld<_TmpPatchQuadBlocks.size(); iOld++)
00495 {
00496 _Owner->deletePatchQuadBlock(_TmpPatchQuadBlocks[iOld]);
00497 }
00498 _TmpPatchQuadBlocks.clear();
00499
00500
00501
00502
00503
00504
00505 CVector delta;
00506
00507
00508 delta.x= (float)floor(-pos.x);
00509 delta.y= (float)floor(-pos.y);
00510 delta.z= 0;
00511
00512 float val= (float)ceil(BBoxRadius + 256);
00513
00514
00515 delta.x+= val;
00516 delta.y+= val;
00517
00518
00519 _LandscapeQuadGrid.build(_PatchQuadBlocks, delta);
00520
00521 }
00522
00523
00524
00525 bool CVisualCollisionEntity::getStaticLightSetup(NLMISC::CRGBA sunAmbient, const CVector &pos,
00526 std::vector<CPointLightInfluence> &pointLightList, uint8 &sunContribution, NLMISC::CRGBA &localAmbient)
00527 {
00528
00529 CVector res;
00530 CTrianglePatch *tri= getPatchTriangleUnderUs(pos, res);
00531
00532
00533 localAmbient= sunAmbient;
00534
00535
00536 if( tri )
00537 {
00538
00539 CUV uv;
00540 computeUvForPos(*tri, pos, uv);
00541
00542
00543 sunContribution= _Owner->_Landscape->getLumel(tri->PatchId, uv);
00544
00545 sunContribution= _Owner->_SunContributionLUT[sunContribution];
00546
00547
00548 _Owner->_Landscape->appendTileLightInfluences(tri->PatchId, uv, pointLightList);
00549
00550 return true;
00551 }
00552 else
00553 {
00554
00555 sunContribution= 255;
00556
00557 return false;
00558 }
00559 }
00560
00561
00562
00563 bool CVisualCollisionEntity::getSurfaceInfo(const CVector &pos, CSurfaceInfo &surfaceInfo)
00564 {
00565 H_AUTO( NL3D_CVisualCollisionEntity_getSurfaceInfo )
00566
00567 CVector res;
00568 CTrianglePatch *tri= getPatchTriangleUnderUs(pos, res);
00569
00570
00571 if( tri )
00572 {
00573
00574 CUV uv;
00575 computeUvForPos(*tri, pos, uv);
00576
00577
00578 CTileElement *tileElm = _Owner->_Landscape->getTileElement(tri->PatchId, uv);
00579 if (tileElm)
00580 {
00581
00582 uint16 tileId = tileElm->Tile[0];
00583 if (tileId != NL_TILE_ELM_LAYER_EMPTY)
00584 {
00585
00586 CTileBank &tileBank = _Owner->_Landscape->TileBank;
00587
00588
00589 int tileSet;
00590 int number;
00591 CTileBank::TTileType type;
00592 tileBank.getTileXRef ((int)tileId, tileSet, number, type);
00593
00594
00595 const CTileSet* tileSetPtr = tileBank.getTileSet (tileSet);
00596
00597
00598 surfaceInfo.UserSurfaceData = tileSetPtr->SurfaceData;
00599
00600
00601 return true;
00602 }
00603 }
00604 }
00605 return false;
00606 }
00607
00608
00609
00610 void CVisualCollisionEntity::displayDebugGrid(IDriver &drv) const
00611 {
00612
00613 static CMaterial mat;
00614 static bool inited= false;
00615 if(!inited)
00616 {
00617 inited= true;
00618 mat.initUnlit();
00619 }
00620 static vector<CLine> lineList;
00621 lineList.clear();
00622
00623
00624 for(uint i=0;i<_PatchQuadBlocks.size();i++)
00625 {
00626 CPatchQuadBlock &pqb= *_PatchQuadBlocks[i];
00627
00628 CPatchBlockIdent &pbid= pqb.PatchBlockId;
00629 for(uint t= pbid.T0; t<pbid.T1; t++)
00630 {
00631 for(uint s= pbid.S0; s<pbid.S1; s++)
00632 {
00633
00634 uint sd0= (s-pbid.S0);
00635 uint td0= (t-pbid.T0);
00636 uint sd1= sd0+1;
00637 uint td1= td0+1;
00638
00639 const CVector &p0= pqb.Vertices[sd0 + td0*NL_PATCH_BLOCK_MAX_VERTEX];
00640 const CVector &p1= pqb.Vertices[sd0 + td1*NL_PATCH_BLOCK_MAX_VERTEX];
00641 const CVector &p2= pqb.Vertices[sd1 + td1*NL_PATCH_BLOCK_MAX_VERTEX];
00642 const CVector &p3= pqb.Vertices[sd1 + td0*NL_PATCH_BLOCK_MAX_VERTEX];
00643
00644
00645 lineList.push_back(CLine(p0, p1));
00646 lineList.push_back(CLine(p1, p2));
00647 lineList.push_back(CLine(p2, p3));
00648 lineList.push_back(CLine(p3, p0));
00649 lineList.push_back(CLine(p0, p2));
00650 }
00651 }
00652 }
00653
00654
00655 CDRU::drawLinesUnlit(lineList, mat, drv);
00656 }
00657
00658
00659
00660 }