00001
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "std3d.h"
00028
00029 #include "3d/tessellation.h"
00030 #include "3d/patch.h"
00031 #include "3d/zone.h"
00032 #include "nel/misc/common.h"
00033 #include "3d/landscape_profile.h"
00034 #include "3d/landscape.h"
00035 #include "3d/patchdlm_context.h"
00036 using namespace NLMISC;
00037 using namespace std;
00038
00039
00040 namespace NL3D
00041 {
00042
00043
00044
00045 #define NL3D_TESS_USE_QUADRANT_THRESHOLD 0.1f
00046
00047
00048
00049
00050 const uint8 TileUvFmtNormal1= 0;
00051 const uint8 TileUvFmtNormal2= 1;
00052 const uint8 TileUvFmtNormal3= 2;
00053 const uint8 TileUvFmtNormal4= 3;
00054 const uint8 TileUvFmtNormal5= 4;
00055
00056
00057
00058
00059 const float TileSize= 128;
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072 CTileMaterial::CTileMaterial()
00073 {
00074
00075 for(uint i=0; i<NL3D_MAX_TILE_FACE; i++)
00076 {
00077 TileFaceVectors[i]= NULL;
00078 }
00079 }
00080
00081
00082
00083 void CTileMaterial::appendTileToEachRenderPass(uint patchNumRenderableFaces)
00084 {
00085 for(uint i=0;i<NL3D_MAX_TILE_PASS;i++)
00086 {
00087
00088 CPatchRdrPass *rdrPass= Pass[i].PatchRdrPass;
00089 if(rdrPass!=NULL)
00090 {
00091
00092
00093
00094
00095
00096
00097
00098
00099 rdrPass->appendRdrPatchTile(i, &Pass[i], patchNumRenderableFaces);
00100 }
00101 }
00102 }
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113 void CTessVertex::computeGeomPos()
00114 {
00115
00116 float sqrDist= (StartPos - CLandscapeGlobals::RefineCenter).sqrnorm();
00117 float pgeom= MaxFaceSize * CLandscapeGlobals::OORefineThreshold / sqrDist;
00118
00119
00120 if( sqrDist< CLandscapeGlobals::TileDistFarSqr )
00121 {
00122
00123 if(pgeom < MaxNearLimit)
00124 {
00125 float f= (CLandscapeGlobals::TileDistFarSqr - sqrDist) * CLandscapeGlobals::OOTileDistDeltaSqr;
00126 clamp(f, 0, 1);
00127
00128 f= sqr(f);
00129 f= sqr(f);
00130
00131 pgeom= MaxNearLimit*f + pgeom*(1-f);
00132 }
00133 }
00134
00135
00136 if(pgeom<=1.0f)
00137 Pos= StartPos;
00138 else if(pgeom>=2.0f)
00139 Pos= EndPos;
00140 else
00141 {
00142 float f= pgeom - 1.0f;
00143 Pos= f * (EndPos-StartPos) + StartPos;
00144 }
00145 }
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156 CTessFace CTessFace::CantMergeFace;
00157 CTessFace CTessFace::MultipleBindFace;
00158
00159
00160
00161 CTessFace::CTessFace()
00162 {
00163
00164
00165
00166 Patch= NULL;
00167 VBase=VLeft=VRight= NULL;
00168 FBase=FLeft=FRight= NULL;
00169 Father=SonLeft=SonRight= NULL;
00170 Level=0;
00171 ErrorMetricDate= 0;
00172
00173
00174 TileMaterial= NULL;
00175
00176 for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
00177 {
00178 TileFaces[i]=NULL;
00179 }
00180
00181 RecursMarkCanMerge=false;
00182 RecursMarkForceMerge=false;
00183
00184
00185 NL3D_PROFILE_LAND_ADD(ProfNTessFace, 1);
00186 }
00187
00188
00189
00190 CTessFace::~CTessFace()
00191 {
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206 NL3D_PROFILE_LAND_ADD(ProfNTessFace, -1);
00207 }
00208
00209
00210
00211 float CTessFace::computeNearLimit()
00212 {
00213
00214
00215
00216
00217
00218
00219
00220
00221 nlassert(Level<=20);
00222 static const uint BigValue= 1<<20;
00223 static const float OOBigValue= 1.0f / BigValue;
00224 return (1<<Patch->TileLimitLevel) * (OOBigValue*(BigValue>>Level));
00225 }
00226
00227
00228
00229 void CTessFace::computeTileErrorMetric()
00230 {
00231
00232
00233
00234 float s0= (VBase->EndPos - CLandscapeGlobals::RefineCenter).sqrnorm();
00235 float s1= (VLeft->EndPos - CLandscapeGlobals::RefineCenter).sqrnorm();
00236 float s2= (VRight->EndPos - CLandscapeGlobals::RefineCenter).sqrnorm();
00237 float sqrdist= minof(s0, s1, s2);
00238
00239
00240
00241
00242
00243
00244 if(sqrdist< CLandscapeGlobals::TileDistFarSqr)
00245 {
00246 float nearLimit;
00247 nearLimit= CLandscapeGlobals::RefineThreshold * computeNearLimit();
00248
00249 if(ErrorMetric<nearLimit)
00250 {
00251 if(sqrdist< CLandscapeGlobals::TileDistNearSqr)
00252 {
00253 ErrorMetric=nearLimit;
00254 }
00255 else
00256 {
00257
00258 float f= ( CLandscapeGlobals::TileDistFarSqr - sqrdist ) * CLandscapeGlobals::OOTileDistDeltaSqr;
00259
00260 f= sqr(f);
00261 f= sqr(f);
00262 ErrorMetric= ErrorMetric + (nearLimit-ErrorMetric)*f;
00263
00264
00265
00266 }
00267 }
00268 }
00269 }
00270
00271
00272
00273 void CTessFace::updateErrorMetric()
00274 {
00275
00276 if(ErrorMetricDate>= CLandscapeGlobals::CurrentDate)
00277 return;
00278
00279 CVector viewdir= SplitPoint - CLandscapeGlobals::RefineCenter;
00280 float sqrdist= viewdir.sqrnorm();
00281
00282
00283
00284 ErrorMetric= Size/ sqrdist;
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297 if( Level<Patch->TileLimitLevel && sqrdist < sqr(CLandscapeGlobals::TileDistFar+MaxDistToSplitPoint) )
00298 {
00299 computeTileErrorMetric();
00300 }
00301
00302 ErrorMetricDate= CLandscapeGlobals::CurrentDate;
00303 }
00304
00305
00306
00307 inline float CTessFace::computeTileEMForUpdateRefine(float distSplitPoint, float distMinFace, float nearLimit)
00308 {
00309 float ema;
00310
00311 ema= Size / sqr(distSplitPoint);
00312
00313
00314 if(distMinFace < CLandscapeGlobals::TileDistFar)
00315 {
00316
00317 if( ema<nearLimit )
00318 {
00319 if( distMinFace< CLandscapeGlobals::TileDistNear)
00320 {
00321 ema= nearLimit;
00322 }
00323 else
00324 {
00325
00326 float f= ( CLandscapeGlobals::TileDistFarSqr - sqr(distMinFace) ) * CLandscapeGlobals::OOTileDistDeltaSqr;
00327
00328 f= sqr(f);
00329 f= sqr(f);
00330 ema= ema + (nearLimit-ema)*f;
00331 }
00332 }
00333 }
00334
00335 return ema * CLandscapeGlobals::OORefineThreshold;
00336 }
00337
00338
00339
00340 void CTessFace::computeSplitPoint()
00341 {
00342 if(isRectangular())
00343 {
00344
00345
00346
00347 SplitPoint= (VLeft->EndPos + VBase->EndPos)/2;
00348 }
00349 else
00350 {
00351
00352
00353 SplitPoint= (VLeft->EndPos + VRight->EndPos)/2;
00354 }
00355
00356
00357 float d0= (VBase->EndPos - SplitPoint).sqrnorm();
00358 float d1= (VLeft->EndPos - SplitPoint).sqrnorm();
00359 float d2= (VRight->EndPos - SplitPoint).sqrnorm();
00360 MaxDistToSplitPoint= max(d0, d1);
00361 MaxDistToSplitPoint= max(MaxDistToSplitPoint, d2);
00362
00363 MaxDistToSplitPoint= sqrtf(MaxDistToSplitPoint);
00364 }
00365
00366
00367 void CTessFace::allocTileUv(TTileUvId id)
00368 {
00369
00370 nlassert(TileFaces[NL3D_TILE_PASS_RGB0]);
00371
00372
00373 CTessVertex *vertexSrc;
00374 switch(id)
00375 {
00376 case IdUvBase: vertexSrc= VBase; break;
00377 case IdUvLeft: vertexSrc= VLeft; break;
00378 case IdUvRight: vertexSrc= VRight; break;
00379 default: nlstop;
00380 };
00381
00382
00383 for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
00384 {
00385 if(TileFaces[i])
00386 {
00387 CTessNearVertex *newNear= Patch->getLandscape()->newTessNearVertex();
00388 newNear->Src= vertexSrc;
00389 TileFaces[i]->V[id]= newNear;
00390 Patch->appendNearVertexToRenderList(TileMaterial, newNear);
00391
00392
00393 }
00394 }
00395 }
00396
00397
00398 void CTessFace::checkCreateFillTileVB(TTileUvId id)
00399 {
00400
00401 nlassert(TileFaces[NL3D_TILE_PASS_RGB0]);
00402
00403 for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
00404 {
00405 if(TileFaces[i])
00406 {
00407 CTessNearVertex *vertNear;
00408 vertNear= TileFaces[i]->V[id];
00409
00410
00411 Patch->checkCreateVertexVBNear(vertNear);
00412 Patch->checkFillVertexVBNear(vertNear);
00413 }
00414 }
00415 }
00416
00417
00418
00419 void CTessFace::checkFillTileVB(TTileUvId id)
00420 {
00421
00422 nlassert(TileFaces[NL3D_TILE_PASS_RGB0]);
00423
00424 for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
00425 {
00426 if(TileFaces[i])
00427 {
00428 CTessNearVertex *vertNear;
00429 vertNear= TileFaces[i]->V[id];
00430
00431
00432 Patch->checkFillVertexVBNear(vertNear);
00433 }
00434 }
00435 }
00436
00437
00438
00439 void CTessFace::deleteTileUv(TTileUvId id)
00440 {
00441
00442 nlassert(TileFaces[NL3D_TILE_PASS_RGB0]);
00443
00444 for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
00445 {
00446 if(TileFaces[i])
00447 {
00448 CTessNearVertex *oldNear;
00449 oldNear= TileFaces[i]->V[id];
00450 TileFaces[i]->V[id]=NULL;
00451
00452
00453 Patch->checkDeleteVertexVBNear(oldNear);
00454
00455 Patch->removeNearVertexFromRenderList(TileMaterial, oldNear);
00456 Patch->getLandscape()->deleteTessNearVertex(oldNear);
00457 }
00458 }
00459 }
00460
00461 void CTessFace::copyTileUv(TTileUvId dstId, CTessFace *srcFace, TTileUvId srcId)
00462 {
00463
00464 nlassert(TileFaces[NL3D_TILE_PASS_RGB0]);
00465
00466
00467
00468 for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
00469 {
00470 if(TileFaces[i])
00471 {
00472
00473 nlassert(srcFace->TileFaces[i]);
00474
00475
00476 CTessNearVertex *copyNear;
00477 copyNear= srcFace->TileFaces[i]->V[srcId];
00478
00479
00480 TileFaces[i]->V[dstId]= copyNear;
00481 }
00482 }
00483 }
00484
00485 void CTessFace::heritTileUv(CTessFace *baseFace)
00486 {
00487
00488 nlassert(TileFaces[NL3D_TILE_PASS_RGB0]);
00489
00490 for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
00491 {
00492 if(TileFaces[i])
00493 {
00494
00495 nlassert(baseFace->TileFaces[i]);
00496
00497 nlassert(TileFaces[i]->V[IdUvBase]);
00498 TileFaces[i]->V[IdUvBase]->initMiddleUv(
00499 *baseFace->TileFaces[i]->V[IdUvLeft], *baseFace->TileFaces[i]->V[IdUvRight]);
00500 }
00501 }
00502 }
00503
00504
00505
00506 void CTessFace::buildTileFaces()
00507 {
00508 nlassert(TileMaterial);
00509
00510
00511 for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
00512 {
00513 if(TileMaterial->Pass[i].PatchRdrPass)
00514 {
00515 TileFaces[i]= Patch->getLandscape()->newTileFace();
00516 TileFaces[i]->V[IdUvBase]= NULL;
00517 TileFaces[i]->V[IdUvLeft]= NULL;
00518 TileFaces[i]->V[IdUvRight]= NULL;
00519 }
00520 }
00521 }
00522
00523 void CTessFace::deleteTileFaces()
00524 {
00525 nlassert(TileMaterial);
00526
00527
00528 for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
00529 {
00530 if(TileMaterial->Pass[i].PatchRdrPass)
00531 {
00532 nlassert(TileFaces[i]);
00533 Patch->getLandscape()->deleteTileFace(TileFaces[i]);
00534 TileFaces[i]= NULL;
00535 }
00536 else
00537 {
00538 nlassert(TileFaces[i]==NULL);
00539 }
00540 }
00541 }
00542
00543
00544 bool CTessFace::emptyTileFaces()
00545 {
00546
00547 for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
00548 {
00549
00550 if(TileFaces[i])
00551 return false;
00552 }
00553
00554 return true;
00555 }
00556
00557
00558
00559
00560 void CTessFace::initTileUvRGBA(sint pass, bool alpha, CParamCoord pointCoord, CParamCoord middle, CUV &uv)
00561 {
00562
00563 uv.U= pointCoord.S<=middle.S? 0.0f: 1.0f;
00564 uv.V= pointCoord.T<=middle.T? 0.0f: 1.0f;
00565
00566
00567 uint8 orient;
00568 CVector uvScaleBias;
00569 bool is256;
00570 uint8 uvOff;
00571 Patch->getTileUvInfo(TileId, pass, alpha, orient, uvScaleBias, is256, uvOff);
00572
00573
00574 float u= uv.U;
00575 float v= uv.V;
00576
00577 switch(orient)
00578 {
00579 case 0:
00580 uv.U= u;
00581 uv.V= v;
00582 break;
00583 case 1:
00584 uv.U= 1-v;
00585 uv.V= u;
00586 break;
00587 case 2:
00588 uv.U= 1-u;
00589 uv.V= 1-v;
00590 break;
00591 case 3:
00592 uv.U= v;
00593 uv.V= 1-u;
00594 break;
00595 }
00596
00597
00598 if(is256)
00599 {
00600 uv*= 0.5;
00601 if(uvOff==2 || uvOff==3)
00602 uv.U+= 0.5;
00603 if(uvOff==1 || uvOff==2)
00604 uv.V+= 0.5;
00605 }
00606
00607
00608
00609 float hBiasXY, hBiasZ;
00610 if(is256)
00611 {
00612 hBiasXY= CLandscapeGlobals::TilePixelBias256;
00613 hBiasZ = CLandscapeGlobals::TilePixelScale256;
00614 }
00615 else
00616 {
00617 hBiasXY= CLandscapeGlobals::TilePixelBias128;
00618 hBiasZ = CLandscapeGlobals::TilePixelScale128;
00619 }
00620
00621
00622
00623 uv.U*= uvScaleBias.z*hBiasZ;
00624 uv.V*= uvScaleBias.z*hBiasZ;
00625 uv.U+= uvScaleBias.x+hBiasXY;
00626 uv.V+= uvScaleBias.y+hBiasXY;
00627 }
00628
00629
00630
00631 void CTessFace::initTileUvLightmap(CParamCoord pointCoord, CParamCoord middle, CUV &uv)
00632 {
00633
00634 uv.U= pointCoord.S<=middle.S? 0.0f: 1.0f;
00635 uv.V= pointCoord.T<=middle.T? 0.0f: 1.0f;
00636
00637
00638 CVector uvScaleBias;
00639 Patch->getTileLightMapUvInfo(TileMaterial->TileS, TileMaterial->TileT, uvScaleBias);
00640
00641
00642 uv.U*= uvScaleBias.z;
00643 uv.V*= uvScaleBias.z;
00644 uv.U+= uvScaleBias.x;
00645 uv.V+= uvScaleBias.y;
00646 }
00647
00648
00649
00650 void CTessFace::initTileUvDLM(CParamCoord pointCoord, CUV &uv)
00651 {
00652
00653 CPatchDLMContext *dlmCtx= Patch->_DLMContext;
00654
00655 nlassert(dlmCtx);
00656
00657
00658 uv.U= pointCoord.getS();
00659 uv.V= pointCoord.getT();
00660
00661
00662 uv.U*= dlmCtx->DLMUScale;
00663 uv.V*= dlmCtx->DLMVScale;
00664 uv.U+= dlmCtx->DLMUBias;
00665 uv.V+= dlmCtx->DLMVBias;
00666 }
00667
00668
00669
00670 void CTessFace::computeTileMaterial()
00671 {
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689 CParamCoord middle(PVLeft,PVRight);
00690 sint ts= ((sint)middle.S * (sint)Patch->OrderS) / 0x8000;
00691 sint tt= ((sint)middle.T * (sint)Patch->OrderT) / 0x8000;
00692 TileId= tt*Patch->OrderS + ts;
00693
00694
00695
00696
00697
00698 nlassert(!FBase || FBase->Patch!=Patch || FBase->Level<=Patch->TileLimitLevel);
00699 bool copyFromBase;
00700 copyFromBase= (FBase && FBase->Patch==Patch);
00701 copyFromBase= copyFromBase && (FBase->Level==Patch->TileLimitLevel && FBase->TileMaterial!=NULL);
00702
00703 if(copyFromBase)
00704 {
00705 TileMaterial= FBase->TileMaterial;
00706 nlassert(FBase->TileId== TileId);
00707 }
00708 else
00709 {
00710 sint i;
00711 TileMaterial= Patch->getLandscape()->newTileMaterial();
00712 TileMaterial->TileS= ts;
00713 TileMaterial->TileT= tt;
00714
00715
00716 Patch->appendTileMaterialToRenderList(TileMaterial);
00717
00718
00719
00720 Patch->getTileLightMap(ts, tt, TileMaterial->Pass[NL3D_TILE_PASS_LIGHTMAP].PatchRdrPass);
00721
00722
00723 for(i=0;i<NL3D_MAX_TILE_PASS;i++)
00724 {
00725
00726 if(i!=NL3D_TILE_PASS_LIGHTMAP)
00727 TileMaterial->Pass[i].PatchRdrPass= Patch->getTileRenderPass(TileId, i);
00728 }
00729
00730
00731 for(i=0;i<NL3D_MAX_TILE_PASS;i++)
00732 {
00733 TileMaterial->Pass[i].TileMaterial= TileMaterial;
00734 }
00735
00736
00737 }
00738
00739
00740
00741
00742
00743
00744
00745 buildTileFaces();
00746
00747
00748 allocTileUv(IdUvBase);
00749
00750
00751
00752 initTileUvLightmap(PVBase, middle, TileFaces[NL3D_TILE_PASS_RGB0]->V[IdUvBase]->PUv1);
00753
00754 initTileUvDLM(PVBase, TileFaces[NL3D_TILE_PASS_RGB0]->V[IdUvBase]->PUv2);
00755
00756
00757 for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
00758 {
00759 nlassert(i!=NL3D_TILE_PASS_LIGHTMAP);
00760
00761 if( TileMaterial->Pass[i].PatchRdrPass)
00762 {
00763
00764 nlassert(TileFaces[i]);
00765
00766 initTileUvRGBA(i, false, PVBase, middle, TileFaces[i]->V[IdUvBase]->PUv0);
00767
00768
00769 if(i== NL3D_TILE_PASS_RGB1 || i==NL3D_TILE_PASS_RGB2 || i==NL3D_TILE_PASS_ADD)
00770 initTileUvRGBA(i, true, PVBase, middle, TileFaces[i]->V[IdUvBase]->PUv1);
00771 }
00772 }
00773
00774
00775 checkCreateFillTileVB(IdUvBase);
00776
00777
00778
00779 if(copyFromBase)
00780 {
00781
00782
00783 copyTileUv(IdUvLeft, FBase, IdUvRight);
00784
00785 copyTileUv(IdUvRight, FBase, IdUvLeft);
00786 }
00787 else
00788 {
00789
00790 allocTileUv(IdUvLeft);
00791 allocTileUv(IdUvRight);
00792
00793
00794
00795 initTileUvLightmap(PVLeft, middle, TileFaces[NL3D_TILE_PASS_RGB0]->V[IdUvLeft]->PUv1);
00796 initTileUvLightmap(PVRight, middle, TileFaces[NL3D_TILE_PASS_RGB0]->V[IdUvRight]->PUv1);
00797
00798 initTileUvDLM(PVLeft, TileFaces[NL3D_TILE_PASS_RGB0]->V[IdUvLeft]->PUv2);
00799 initTileUvDLM(PVRight, TileFaces[NL3D_TILE_PASS_RGB0]->V[IdUvRight]->PUv2);
00800
00801
00802 for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
00803 {
00804 nlassert(i!=NL3D_TILE_PASS_LIGHTMAP);
00805
00806 if(TileMaterial->Pass[i].PatchRdrPass)
00807 {
00808
00809 nlassert(TileFaces[i]);
00810
00811 initTileUvRGBA(i, false, PVLeft, middle, TileFaces[i]->V[IdUvLeft]->PUv0);
00812 initTileUvRGBA(i, false, PVRight, middle, TileFaces[i]->V[IdUvRight]->PUv0);
00813
00814
00815 if(i== NL3D_TILE_PASS_RGB1 || i==NL3D_TILE_PASS_RGB2 || i==NL3D_TILE_PASS_ADD)
00816 {
00817 initTileUvRGBA(i, true, PVLeft, middle, TileFaces[i]->V[IdUvLeft]->PUv1);
00818 initTileUvRGBA(i, true, PVRight, middle, TileFaces[i]->V[IdUvRight]->PUv1);
00819 }
00820 }
00821 }
00822
00823
00824 checkCreateFillTileVB(IdUvLeft);
00825 checkCreateFillTileVB(IdUvRight);
00826 }
00827
00828 }
00829
00830 void CTessFace::releaseTileMaterial()
00831 {
00832
00833 deleteTileUv(IdUvBase);
00834
00835 nlassert(!FBase || FBase->Level<=Patch->TileLimitLevel);
00836 if(FBase && FBase->Level==Patch->TileLimitLevel && FBase->TileMaterial!=NULL)
00837 {
00838
00839
00840 deleteTileFaces();
00841
00842 TileMaterial= NULL;
00843 }
00844 else
00845 {
00846
00847 deleteTileUv(IdUvLeft);
00848 deleteTileUv(IdUvRight);
00849
00850
00851 deleteTileFaces();
00852
00853
00854 Patch->releaseTileLightMap(TileMaterial->TileS, TileMaterial->TileT);
00855
00856
00857
00858 Patch->removeTileMaterialFromRenderList(TileMaterial);
00859
00860 Patch->getLandscape()->deleteTileMaterial(TileMaterial);
00861 TileMaterial= NULL;
00862 }
00863 }
00864
00865
00866
00867
00868 void CTessFace::updateNearFarVertices()
00869 {
00870 nlassert(VBase && FVBase);
00871 nlassert(VLeft && FVLeft);
00872 nlassert(VRight && FVRight);
00873
00874 FVBase->Src= VBase;
00875 FVLeft->Src= VLeft;
00876 FVRight->Src= VRight;
00877 FVBase->PCoord= PVBase;
00878 FVLeft->PCoord= PVLeft;
00879 FVRight->PCoord= PVRight;
00880
00881
00882 Patch->checkFillVertexVBFar(FVBase);
00883 Patch->checkFillVertexVBFar(FVLeft);
00884 Patch->checkFillVertexVBFar(FVRight);
00885
00886
00887 for(sint i=0; i<NL3D_MAX_TILE_FACE; i++)
00888 {
00889 if(TileFaces[i])
00890 {
00891 TileFaces[i]->V[IdUvBase]->Src= VBase;
00892 TileFaces[i]->V[IdUvLeft]->Src= VLeft;
00893 TileFaces[i]->V[IdUvRight]->Src= VRight;
00894
00895
00896 Patch->checkFillVertexVBNear(TileFaces[i]->V[IdUvBase]);
00897 Patch->checkFillVertexVBNear(TileFaces[i]->V[IdUvLeft]);
00898 Patch->checkFillVertexVBNear(TileFaces[i]->V[IdUvRight]);
00899 }
00900 }
00901
00902 }
00903
00904
00905
00906 void CTessFace::splitRectangular(bool propagateSplit)
00907 {
00908 CTessFace *f0= this;
00909 CTessFace *f1= FBase;
00910
00911 nlassert(f1);
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932 CParamCoord pclt= f1->PVLeft;
00933 CParamCoord pclb= f0->PVBase;
00934 CParamCoord pcrt= f1->PVBase;
00935 CParamCoord pcrb= f1->PVRight;
00936 CTessVertex *vlt= f1->VLeft;
00937 CTessVertex *vlb= f0->VBase;
00938 CTessVertex *vrt= f1->VBase;
00939 CTessVertex *vrb= f1->VRight;
00940
00941 CTessFarVertex *farvlt= f1->FVLeft;
00942 CTessFarVertex *farvlb= f0->FVBase;
00943 CTessFarVertex *farvrt= f1->FVBase;
00944 CTessFarVertex *farvrb= f1->FVRight;
00945
00946
00947
00948
00949
00950
00951 CParamCoord pctop(f1->PVBase, f1->PVLeft);
00952 CParamCoord pcbot(f0->PVBase, f0->PVLeft);
00953 CTessVertex *vtop= NULL;
00954 CTessVertex *vbot= NULL;
00955
00956 if(f1->FLeft==NULL || f1->FLeft->isLeaf())
00957 {
00958
00959 vtop= Patch->getLandscape()->newTessVertex();
00960
00961
00962 vtop->StartPos= (f1->VLeft->EndPos + f1->VBase->EndPos)/2;
00963 vtop->EndPos= f1->Patch->computeVertex(pctop.getS(), pctop.getT());
00964
00965 vtop->Pos= vtop->StartPos;
00966
00967
00968 vtop->MaxFaceSize= f1->Size;
00969 vtop->MaxNearLimit= f1->computeNearLimit();
00970 }
00971 else
00972 {
00973
00974
00975
00976 vtop= f1->FLeft->SonLeft->VBase;
00977
00978
00979 vtop->MaxFaceSize= max( vtop->MaxFaceSize, f1->Size);
00980 vtop->MaxNearLimit= max( vtop->MaxNearLimit, f1->computeNearLimit());
00981 }
00982
00983 if(f0->FLeft==NULL || f0->FLeft->isLeaf())
00984 {
00985
00986 vbot= Patch->getLandscape()->newTessVertex();
00987
00988
00989 vbot->StartPos= (f0->VLeft->EndPos + f0->VBase->EndPos)/2;
00990 vbot->EndPos= Patch->computeVertex(pcbot.getS(), pcbot.getT());
00991
00992 vbot->Pos= vbot->StartPos;
00993
00994
00995 vbot->MaxFaceSize= f0->Size;
00996 vbot->MaxNearLimit= f0->computeNearLimit();
00997 }
00998 else
00999 {
01000
01001
01002
01003 vbot= f0->FLeft->SonLeft->VBase;
01004
01005
01006 vbot->MaxFaceSize= max( vbot->MaxFaceSize, f0->Size);
01007 vbot->MaxNearLimit= max( vbot->MaxNearLimit, f0->computeNearLimit());
01008 }
01009
01010
01011 CTessFarVertex *farvtop= Patch->getLandscape()->newTessFarVertex();
01012 CTessFarVertex *farvbot= Patch->getLandscape()->newTessFarVertex();
01013 farvtop->Src= vtop;
01014 farvbot->Src= vbot;
01015 farvtop->PCoord= pctop;
01016 farvbot->PCoord= pcbot;
01017 Patch->appendFarVertexToRenderList(farvtop);
01018 Patch->appendFarVertexToRenderList(farvbot);
01019
01020
01021 Patch->checkCreateVertexVBFar(farvtop);
01022 Patch->checkFillVertexVBFar(farvtop);
01023 Patch->checkCreateVertexVBFar(farvbot);
01024 Patch->checkFillVertexVBFar(farvbot);
01025
01026
01027
01028 if( CLandscapeGlobals::VertexProgramEnabled )
01029 {
01030
01031 if( ! (f0->FLeft==NULL || f0->FLeft->isLeaf()) )
01032 f0->FLeft->Patch->checkFillVertexVBFar(f0->FLeft->SonLeft->FVBase);
01033
01034 if( ! (f1->FLeft==NULL || f1->FLeft->isLeaf()) )
01035 f1->FLeft->Patch->checkFillVertexVBFar(f1->FLeft->SonLeft->FVBase);
01036 }
01037
01038
01039
01040
01041
01042 CTessFace *f0l, *f0r;
01043 CTessFace *f1l, *f1r;
01044
01045
01046 f0l= f0->SonLeft= Patch->getLandscape()->newTessFace();
01047 f0r= f0->SonRight= Patch->getLandscape()->newTessFace();
01048 f1l= f1->SonLeft= Patch->getLandscape()->newTessFace();
01049 f1r= f1->SonRight= Patch->getLandscape()->newTessFace();
01050
01051
01052 f0l->Patch= f0->Patch;
01053 f0l->Father= f0;
01054 f0l->Level= f0->Level+1;
01055 f0l->Size= f0->Size*0.5f;
01056
01057 f0r->Patch= f0->Patch;
01058 f0r->Father= f0;
01059 f0r->Level= f0->Level+1;
01060 f0r->Size= f0->Size*0.5f;
01061
01062 f1l->Patch= f1->Patch;
01063 f1l->Father= f1;
01064 f1l->Level= f1->Level+1;
01065 f1l->Size= f1->Size*0.5f;
01066
01067 f1r->Patch= f1->Patch;
01068 f1r->Father= f1;
01069 f1r->Level= f1->Level+1;
01070 f1r->Size= f1->Size*0.5f;
01071
01072
01073 f0r->PVRight= pclt;
01074 f0r->PVBase= pclb;
01075 f0r->PVLeft= pcbot;
01076 f1l->PVBase= pctop;
01077 f1l->PVLeft= f0r->PVRight;
01078 f1l->PVRight= f0r->PVLeft;
01079
01080 f0l->PVRight= pctop;
01081 f0l->PVBase= pcbot;
01082 f0l->PVLeft= pcrb;
01083 f1r->PVBase= pcrt;
01084 f1r->PVLeft= f0l->PVRight;
01085 f1r->PVRight= f0l->PVLeft;
01086
01087
01088 f0r->VRight= vlt;
01089 f0r->VBase= vlb;
01090 f0r->VLeft= vbot;
01091 f1l->VBase= vtop;
01092 f1l->VLeft= f0r->VRight;
01093 f1l->VRight= f0r->VLeft;
01094
01095 f0l->VRight= vtop;
01096 f0l->VBase= vbot;
01097 f0l->VLeft= vrb;
01098 f1r->VBase= vrt;
01099 f1r->VLeft= f0l->VRight;
01100 f1r->VRight= f0l->VLeft;
01101
01102
01103 f0r->FVRight= farvlt;
01104 f0r->FVBase= farvlb;
01105 f0r->FVLeft= farvbot;
01106 f1l->FVBase= farvtop;
01107 f1l->FVLeft= f0r->FVRight;
01108 f1l->FVRight= f0r->FVLeft;
01109
01110 f0l->FVRight= farvtop;
01111 f0l->FVBase= farvbot;
01112 f0l->FVLeft= farvrb;
01113 f1r->FVBase= farvrt;
01114 f1r->FVLeft= f0l->FVRight;
01115 f1r->FVRight= f0l->FVLeft;
01116
01117
01118 f0r->FBase= f1l;
01119 f1l->FBase= f0r;
01120 f0l->FBase= f1r;
01121 f1r->FBase= f0l;
01122 f1l->FRight= f0l;
01123 f0l->FRight= f1l;
01124 f0r->FRight= f0->FRight;
01125 if(f0->FRight)
01126 f0->FRight->changeNeighbor(f0, f0r);
01127 f1r->FRight= f1->FRight;
01128 if(f1->FRight)
01129 f1->FRight->changeNeighbor(f1, f1r);
01130
01131 f0l->FLeft= NULL;
01132 f0r->FLeft= NULL;
01133 f1l->FLeft= NULL;
01134 f1r->FLeft= NULL;
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146 if( CLandscapeGlobals::VertexProgramEnabled )
01147 {
01148
01149
01150 if( f0->FLeft!=NULL && !f0->FLeft->isLeaf() && f0->FLeft->Patch!=Patch )
01151 {
01152
01153 if( f0->FLeft->SonLeft->Level >= f0->FLeft->Patch->TileLimitLevel )
01154 {
01155 f0->FLeft->SonLeft->checkFillTileVB(IdUvBase);
01156 f0->FLeft->SonRight->checkFillTileVB(IdUvBase);
01157 }
01158 }
01159
01160 if( f1->FLeft!=NULL && !f1->FLeft->isLeaf() && f1->FLeft->Patch!=Patch )
01161 {
01162
01163 if( f1->FLeft->SonLeft->Level >= f1->FLeft->Patch->TileLimitLevel )
01164 {
01165 f1->FLeft->SonLeft->checkFillTileVB(IdUvBase);
01166 f1->FLeft->SonRight->checkFillTileVB(IdUvBase);
01167 }
01168 }
01169 }
01170
01171
01172
01173
01174 f0r->computeSplitPoint();
01175 f0l->computeSplitPoint();
01176 f1r->computeSplitPoint();
01177 f1l->computeSplitPoint();
01178
01179
01180
01181
01182 for(sint i=0;i<2;i++)
01183 {
01184 CTessFace *f, *fl, *fr;
01185
01186 if(i==0)
01187 {
01188 f= f1;
01189 fl= f1l;
01190 fr= f1r;
01191 }
01192
01193 else
01194 {
01195 f= f0;
01196 fl= f0l;
01197 fr= f0r;
01198 }
01199
01200
01201 if(f->FLeft==NULL)
01202 {
01203
01204 fl->FLeft= NULL;
01205 fr->FLeft= NULL;
01206 }
01207 else if(!f->FLeft->isLeaf())
01208 {
01209 CTessFace *toLeft, *toRight;
01210 toLeft= f->FLeft->SonLeft;
01211 toRight= f->FLeft->SonRight;
01212
01213 if( !f->FLeft->isRectangular() )
01214 {
01215
01216 fl->FLeft= toLeft;
01217 fr->FLeft= toRight;
01218 toLeft->FRight= fl;
01219 toRight->FLeft= fr;
01220 }
01221 else
01222 {
01223
01224 fl->FLeft= toRight;
01225 fr->FLeft= toLeft;
01226 toLeft->FLeft= fr;
01227 toRight->FLeft= fl;
01228 }
01229 }
01230 else if (propagateSplit)
01231 {
01232
01233
01234 while(f->FLeft->isLeaf())
01235 f->FLeft->split();
01236
01237
01238
01239 nlassert(fl->isLeaf() && fr->isLeaf());
01240 }
01241 }
01242
01243
01244
01245
01246
01247 Patch->appendFaceToRenderList(f0l);
01248 Patch->appendFaceToRenderList(f0r);
01249 Patch->appendFaceToRenderList(f1l);
01250 Patch->appendFaceToRenderList(f1r);
01251 Patch->removeFaceFromRenderList(f0);
01252 Patch->removeFaceFromRenderList(f1);
01253
01254
01255
01256
01257
01258
01259 Patch->getLandscape()->_MergePriorityList.insert(0, 0, f0);
01260 Patch->getLandscape()->_MergePriorityList.insert(0, 0, f1);
01261
01262
01263 if(f0->Father)
01264 {
01265
01266 f0->Father->unlinkInPList();
01267 }
01268 if(f1->Father)
01269 {
01270
01271 f1->Father->unlinkInPList();
01272 }
01273
01274 }
01275
01276
01277
01278 void CTessFace::split(bool propagateSplit)
01279 {
01280
01281
01282
01283
01284 if(!isLeaf())
01285 return;
01286
01287
01288
01289
01290
01291 NL3D_PROFILE_LAND_ADD(ProfNSplits, 1);
01292
01293
01294
01295 if(isRectangular())
01296 {
01297 splitRectangular(propagateSplit);
01298 return;
01299 }
01300
01301
01302
01303
01304
01305 SonLeft= Patch->getLandscape()->newTessFace();
01306 SonRight= Patch->getLandscape()->newTessFace();
01307
01308
01309 SonLeft->Patch= Patch;
01310 SonLeft->Father= this;
01311 SonLeft->Level= Level+1;
01312 SonLeft->Size= Size*0.5f;
01313
01314 SonRight->Patch= Patch;
01315 SonRight->Father= this;
01316 SonRight->Level= Level+1;
01317 SonRight->Size= Size*0.5f;
01318
01319
01320
01321
01322 SonLeft->FBase= FLeft;
01323 if(FLeft) FLeft->changeNeighbor(this, SonLeft);
01324 SonLeft->FLeft= SonRight;
01325 SonLeft->FRight= NULL;
01326
01327 SonLeft->VLeft= VBase;
01328 SonLeft->VRight= VLeft;
01329
01330 SonLeft->FVLeft= FVBase;
01331 SonLeft->FVRight= FVLeft;
01332
01333 SonLeft->PVBase= CParamCoord(PVLeft, PVRight);
01334 SonLeft->PVLeft= PVBase;
01335 SonLeft->PVRight= PVLeft;
01336
01337
01338
01339 SonRight->FBase= FRight;
01340 if(FRight) FRight->changeNeighbor(this, SonRight);
01341 SonRight->FLeft= NULL;
01342 SonRight->FRight= SonLeft;
01343
01344 SonRight->VLeft= VRight;
01345 SonRight->VRight= VBase;
01346
01347 SonRight->FVLeft= FVRight;
01348 SonRight->FVRight= FVBase;
01349
01350 SonRight->PVBase= CParamCoord(PVLeft, PVRight);
01351 SonRight->PVLeft= PVRight;
01352 SonRight->PVRight= PVBase;
01353
01354
01355
01356
01357
01358
01359
01360
01361
01362 if(FBase==NULL || FBase->isLeaf())
01363 {
01364
01365 CTessVertex *newVertex= Patch->getLandscape()->newTessVertex();
01366 SonRight->VBase= newVertex;
01367 SonLeft->VBase= newVertex;
01368
01369
01370 newVertex->StartPos= (VLeft->EndPos + VRight->EndPos)/2;
01371 newVertex->EndPos= Patch->computeVertex(SonLeft->PVBase.getS(), SonLeft->PVBase.getT());
01372
01373
01374 newVertex->Pos= newVertex->StartPos;
01375
01376
01377 newVertex->MaxFaceSize= Size;
01378 newVertex->MaxNearLimit= computeNearLimit();
01379 }
01380 else
01381 {
01382
01383
01384
01385 SonRight->VBase= FBase->SonLeft->VBase;
01386 SonLeft->VBase= FBase->SonLeft->VBase;
01387
01388
01389 SonLeft->VBase->MaxFaceSize= max( SonLeft->VBase->MaxFaceSize, Size);
01390 SonLeft->VBase->MaxNearLimit= max( SonLeft->VBase->MaxNearLimit, computeNearLimit());
01391 }
01392
01393
01394
01395
01396 if(FBase==NULL || FBase->isLeaf() || FBase->Patch!=Patch)
01397 {
01398
01399 CTessFarVertex *newFar= Patch->getLandscape()->newTessFarVertex();
01400 SonRight->FVBase= newFar;
01401 SonLeft->FVBase= newFar;
01402
01403
01404 newFar->Src= SonLeft->VBase;
01405 newFar->PCoord= SonLeft->PVBase;
01406
01407
01408 Patch->appendFarVertexToRenderList(newFar);
01409
01410
01411
01412 Patch->checkCreateVertexVBFar(newFar);
01413 Patch->checkFillVertexVBFar(newFar);
01414
01415
01416
01417 if( CLandscapeGlobals::VertexProgramEnabled && ! (FBase==NULL || FBase->isLeaf()) )
01418 FBase->Patch->checkFillVertexVBFar(FBase->SonLeft->FVBase);
01419 }
01420 else
01421 {
01422
01423
01424
01425 SonRight->FVBase= FBase->SonLeft->FVBase;
01426 SonLeft->FVBase= FBase->SonLeft->FVBase;
01427
01428
01429
01430 }
01431
01432
01433
01434
01435
01436
01437
01438
01439 if(SonLeft->Level==Patch->TileLimitLevel)
01440 {
01441 SonLeft->computeTileMaterial();
01442 SonRight->computeTileMaterial();
01443 }
01444
01445 else if(SonLeft->Level > Patch->TileLimitLevel)
01446 {
01447 heritTileMaterial();
01448 }
01449
01450
01451 if( CLandscapeGlobals::VertexProgramEnabled )
01452 {
01453
01454
01455 if( FBase!=NULL && !FBase->isLeaf() && FBase->Patch!=Patch )
01456 {
01457
01458 if( FBase->SonLeft->Level >= FBase->Patch->TileLimitLevel )
01459 {
01460 FBase->SonLeft->checkFillTileVB(IdUvBase);
01461 FBase->SonRight->checkFillTileVB(IdUvBase);
01462 }
01463 }
01464 }
01465
01466
01467
01468
01469 SonRight->computeSplitPoint();
01470 SonLeft->computeSplitPoint();
01471
01472
01473
01474
01475
01476 if(FBase==NULL)
01477 {
01478
01479 SonLeft->FRight= NULL;
01480 SonRight->FLeft= NULL;
01481 }
01482 else if(!FBase->isLeaf())
01483 {
01484 CTessFace *toLeft, *toRight;
01485 CTessFace *fl, *fr;
01486 fl= SonLeft;
01487 fr= SonRight;
01488 toLeft= FBase->SonLeft;
01489 toRight= FBase->SonRight;
01490
01491 if(!FBase->isRectangular())
01492 {
01493
01494 fl->FRight= toRight;
01495 fr->FLeft= toLeft;
01496 toLeft->FRight= fr;
01497 toRight->FLeft= fl;
01498 }
01499 else
01500 {
01501
01502 fl->FRight= toLeft;
01503 fr->FLeft= toRight;
01504 toLeft->FLeft= fl;
01505 toRight->FLeft= fr;
01506 }
01507 }
01508 else if (propagateSplit)
01509 {
01510
01511
01512 while(FBase->isLeaf())
01513 FBase->split();
01514
01515
01516
01517 nlassert(SonLeft->isLeaf() && SonRight->isLeaf());
01518 }
01519
01520
01521
01522
01523
01524 Patch->appendFaceToRenderList(SonLeft);
01525 Patch->appendFaceToRenderList(SonRight);
01526 Patch->removeFaceFromRenderList(this);
01527
01528
01529
01530
01531
01532
01533 Patch->getLandscape()->_MergePriorityList.insert(0, 0, this);
01534
01535
01536 if(Father)
01537 {
01538
01539 Father->unlinkInPList();
01540 }
01541 }
01542
01543
01544 bool CTessFace::canMerge(bool testEm)
01545 {
01546 if(this== &CantMergeFace)
01547 return false;
01548
01549 nlassert(!isLeaf());
01550
01551
01552 if(!SonLeft->isLeaf())
01553 return false;
01554 if(!SonRight->isLeaf())
01555 return false;
01556
01557 if(testEm)
01558 {
01559 updateErrorMetric();
01560 float ps2= ErrorMetric;
01561 ps2*= CLandscapeGlobals::OORefineThreshold;
01562 if(ps2>=1.0f)
01563 return false;
01564 }
01565
01566
01567 RecursMarkCanMerge= true;
01568 bool ok= true;
01569 if(!isRectangular())
01570 {
01571 if(FBase && !FBase->RecursMarkCanMerge)
01572 {
01573 if(!FBase->canMerge(testEm))
01574 ok= false;
01575 }
01576 }
01577 else
01578 {
01579
01580 if(FBase && !FBase->RecursMarkCanMerge)
01581 {
01582 if(!FBase->canMerge(testEm))
01583 ok= false;
01584 }
01585 if(ok && FLeft && !FLeft->RecursMarkCanMerge)
01586 {
01587 if(!FLeft->canMerge(testEm))
01588 ok= false;
01589 }
01590 }
01591
01592 RecursMarkCanMerge= false;
01593
01594 return ok;
01595 }
01596
01597
01598
01599 void CTessFace::doMerge()
01600 {
01601
01602
01603 nlassert(!isLeaf());
01604
01605 if(!isRectangular())
01606 {
01607
01608
01609
01610
01611 if(!FBase || !FBase->isLeaf())
01612 Patch->getLandscape()->deleteTessVertex(SonLeft->VBase);
01613
01614
01615 if(!FBase || !FBase->isLeaf() || FBase->Patch!=Patch)
01616 {
01617
01618 Patch->checkDeleteVertexVBFar(SonLeft->FVBase);
01619
01620 Patch->removeFarVertexFromRenderList(SonLeft->FVBase);
01621 Patch->getLandscape()->deleteTessFarVertex(SonLeft->FVBase);
01622 }
01623
01624
01625
01626
01627
01628
01629 Patch->appendFaceToRenderList(this);
01630 Patch->removeFaceFromRenderList(SonLeft);
01631 Patch->removeFaceFromRenderList(SonRight);
01632
01633
01634
01635
01636
01637
01638 if(SonLeft->Level== Patch->TileLimitLevel)
01639 {
01640
01641 nlassert(!sameTile(SonLeft, SonRight));
01642
01643 SonLeft->releaseTileMaterial();
01644 SonRight->releaseTileMaterial();
01645 }
01646 else if(SonLeft->Level > Patch->TileLimitLevel)
01647 {
01648
01649
01650
01651 if(!FBase || !FBase->isLeaf() || !sameTile(this, FBase))
01652 {
01653 SonLeft->deleteTileUv(IdUvBase);
01654 }
01655
01656 SonLeft->deleteTileFaces();
01657 SonRight->deleteTileFaces();
01658 }
01659
01660
01661
01662
01663
01664 FLeft= SonLeft->FBase;
01665 if(FLeft) FLeft->changeNeighbor(SonLeft, this);
01666 FRight= SonRight->FBase;
01667 if(FRight) FRight->changeNeighbor(SonRight, this);
01668
01669 Patch->getLandscape()->deleteTessFace(SonLeft);
01670 Patch->getLandscape()->deleteTessFace(SonRight);
01671 SonLeft=NULL;
01672 SonRight=NULL;
01673
01674
01675 if(FBase!=NULL && !FBase->isLeaf())
01676 {
01677 FBase->doMerge();
01678 }
01679
01680 }
01681 else
01682 {
01683
01684
01685 nlassert(SonLeft->Level< Patch->TileLimitLevel);
01686 nlassert(FBase);
01687
01688
01689
01690
01691
01692 if(!FLeft || !FLeft->isLeaf())
01693 Patch->getLandscape()->deleteTessVertex(SonLeft->VBase);
01694
01695
01696 nlassert(!FLeft || FLeft->Patch!=Patch);
01697
01698 Patch->checkDeleteVertexVBFar(SonLeft->FVBase);
01699
01700 Patch->removeFarVertexFromRenderList(SonLeft->FVBase);
01701 Patch->getLandscape()->deleteTessFarVertex(SonLeft->FVBase);
01702
01703
01704
01705
01706
01707 Patch->appendFaceToRenderList(this);
01708 Patch->removeFaceFromRenderList(SonLeft);
01709 Patch->removeFaceFromRenderList(SonRight);
01710
01711
01712
01713
01714
01715 FRight= SonRight->FRight;
01716 if(FRight) FRight->changeNeighbor(SonRight, this);
01717
01718 Patch->getLandscape()->deleteTessFace(SonLeft);
01719 Patch->getLandscape()->deleteTessFace(SonRight);
01720 SonLeft=NULL;
01721 SonRight=NULL;
01722
01723
01724 if(!FBase->isLeaf())
01725 {
01726 FBase->doMerge();
01727 }
01728
01729 if(FLeft!=NULL && !FLeft->isLeaf())
01730 {
01731 FLeft->doMerge();
01732 }
01733 }
01734
01735
01736
01737
01738
01739
01740 Patch->getLandscape()->_SplitPriorityList.insert(0, 0, this);
01741
01742
01743 if(Father)
01744 {
01745 nlassert(!Father->isLeaf());
01746
01747 if( Father->SonLeft->isLeaf() && Father->SonRight->isLeaf() )
01748 {
01749 Patch->getLandscape()->_MergePriorityList.insert(0, 0, Father);
01750 }
01751 }
01752
01753 }
01754
01755
01756
01757 bool CTessFace::merge()
01758 {
01759
01760 nlassert(!isLeaf());
01761
01762
01763
01764 if(!canMerge(false))
01765 return false;
01766
01767 NL3D_PROFILE_LAND_ADD(ProfNMerges, 1);
01768
01769
01770
01771
01772 doMerge();
01773
01774 return true;
01775 }
01776
01777
01778 void CTessFace::refineAll()
01779 {
01780 NL3D_PROFILE_LAND_ADD(ProfNRefineFaces, 1);
01781 NL3D_PROFILE_LAND_ADD(ProfNRefineLeaves, isLeaf()?1:0);
01782
01783
01784
01785
01786
01787
01788
01789
01790
01791 {
01792 NL3D_PROFILE_LAND_ADD(ProfNRefineComputeFaces, 1);
01793
01794 updateErrorMetric();
01795 float ps=ErrorMetric;
01796 ps*= CLandscapeGlobals::OORefineThreshold;
01797
01798
01799
01800
01801
01802
01803
01804 if(isLeaf())
01805 {
01806 if(ps>1.0f && Level< (Patch->TileLimitLevel + CLandscapeGlobals::TileMaxSubdivision) )
01807 split();
01808 }
01809 else
01810 {
01811
01812 if(ps<1.0f)
01813 {
01814
01815
01816
01817 if(canMerge(true))
01818 {
01819 merge();
01820 }
01821 }
01822 }
01823 }
01824
01825
01826
01827 if(SonLeft)
01828 {
01829 SonLeft->refineAll();
01830 SonRight->refineAll();
01831 }
01832
01833 }
01834
01835
01836
01837
01838
01839
01840
01841
01842
01843
01844
01845
01846
01847
01848
01849
01850
01851
01852
01853
01854
01855
01856
01857
01858
01859
01860
01861
01862
01863
01864
01865
01866
01867
01868
01869
01870
01871
01872
01873
01874
01875
01876
01877
01878
01879
01880
01881
01882
01883
01884
01885
01886
01887
01888
01889
01890
01891
01892
01893
01894
01895 void CTessFace::updateRefineSplit()
01896 {
01897 NL3D_PROFILE_LAND_ADD(ProfNRefineFaces, 1);
01898
01899 nlassert(Patch);
01900
01901 nlassert(isLeaf());
01902
01903
01904
01905
01906
01907
01908
01909 bool splitted= false;
01910 {
01911 updateErrorMetric();
01912 float ps=ErrorMetric;
01913 ps*= CLandscapeGlobals::OORefineThreshold;
01914
01915
01916
01917
01918
01919
01920
01921 if(ps>1.0f && Level< (Patch->TileLimitLevel + CLandscapeGlobals::TileMaxSubdivision) )
01922 {
01923 split();
01924
01925
01926 if(!isLeaf())
01927 {
01928 splitted= true;
01929 }
01930 }
01931 }
01932
01933
01934
01935
01936
01937
01938 if(!splitted)
01939 {
01940
01941 nlassert(isLeaf());
01942
01943 float minDeltaDistToUpdate;
01944
01945
01946 uint quadrantId= 0;
01947
01948
01949 CVector dirToSplitPoint= SplitPoint - CLandscapeGlobals::RefineCenter;
01950
01951 float distSplitPoint= dirToSplitPoint.norm();
01952
01953 float distNormalSplitMerge= (float)sqrt(Size*CLandscapeGlobals::OORefineThreshold);
01954
01955
01956
01957 if(Level>=Patch->TileLimitLevel+CLandscapeGlobals::TileMaxSubdivision)
01958 {
01959
01960
01961 unlinkInPList();
01962 return;
01963 }
01964 else if(Level>=Patch->TileLimitLevel)
01965 {
01966
01967
01968
01969
01970 quadrantId= Patch->getLandscape()->_SplitPriorityList.selectQuadrant(dirToSplitPoint);
01971
01972
01973 minDeltaDistToUpdate= distSplitPoint - distNormalSplitMerge;
01974
01975
01976 if(quadrantId>0)
01977 {
01978 const CVector &quadrantDir= Patch->getLandscape()->_SplitPriorityList.getQuadrantDirection(quadrantId);
01979
01980
01981 float dMin= quadrantDir*dirToSplitPoint - distNormalSplitMerge;
01982
01983
01984 if( dMin<NL3D_TESS_USE_QUADRANT_THRESHOLD )
01985 quadrantId= 0;
01986
01987 else
01988 minDeltaDistToUpdate= dMin;
01989 }
01990 }
01991 else
01992 {
01993
01994 CVector dirToV0= VBase->EndPos - CLandscapeGlobals::RefineCenter;
01995 CVector dirToV1= VLeft->EndPos - CLandscapeGlobals::RefineCenter;
01996 CVector dirToV2= VRight->EndPos - CLandscapeGlobals::RefineCenter;
01997 float s0= dirToV0.sqrnorm();
01998 float s1= dirToV1.sqrnorm();
01999 float s2= dirToV2.sqrnorm();
02000 float distMinFace= (float)sqrt( minof(s0, s1, s2) );
02001
02002
02003 float normalEMDeltaDist;
02004 normalEMDeltaDist= distSplitPoint - distNormalSplitMerge;
02005
02006
02007
02008
02009
02011 if( distMinFace > CLandscapeGlobals::TileDistFar )
02012 {
02013
02014 quadrantId= Patch->getLandscape()->_SplitPriorityList.selectQuadrant(dirToSplitPoint);
02015
02016
02017 minDeltaDistToUpdate= normalEMDeltaDist;
02018
02019 minDeltaDistToUpdate= min(minDeltaDistToUpdate, distMinFace - CLandscapeGlobals::TileDistFar);
02020
02021
02022 if(quadrantId>0)
02023 {
02024 const CVector &quadrantDir= Patch->getLandscape()->_SplitPriorityList.getQuadrantDirection(quadrantId);
02025
02026
02027 float dMin= quadrantDir*dirToSplitPoint - distNormalSplitMerge;
02028
02029 float d0 = quadrantDir*dirToV0 - CLandscapeGlobals::TileDistFar;
02030 float d1 = quadrantDir*dirToV1 - CLandscapeGlobals::TileDistFar;
02031 float d2 = quadrantDir*dirToV2 - CLandscapeGlobals::TileDistFar;
02032
02033 dMin= minof(dMin, d0, d1, d2);
02034
02035
02036 if( dMin<NL3D_TESS_USE_QUADRANT_THRESHOLD )
02037 quadrantId= 0;
02038
02039 else
02040 minDeltaDistToUpdate= dMin;
02041 }
02042 }
02044 else if( distMinFace > CLandscapeGlobals::TileDistNear )
02045 {
02046
02047
02048
02049 NL3D_PROFILE_LAND_ADD(ProfNRefineInTileTransition, 1);
02050
02051
02052 float distTileTransSplitMerge;
02053 float maxDeltaDist= 8;
02054 float minDeltaDist= 0;
02055 uint nbRecurs= 6;
02056 float nearLimit;
02057 nearLimit= CLandscapeGlobals::RefineThreshold * computeNearLimit();
02058
02059 for(uint i=0; i< nbRecurs; i++)
02060 {
02061 float pivotDeltaDist= (maxDeltaDist-minDeltaDist)/2;
02062
02063 if ( computeTileEMForUpdateRefine(distSplitPoint-pivotDeltaDist, distMinFace-pivotDeltaDist, nearLimit ) < 1)
02064 minDeltaDist= pivotDeltaDist;
02065
02066 else
02067 maxDeltaDist= pivotDeltaDist;
02068 }
02069
02070 distTileTransSplitMerge= minDeltaDist;
02071
02072
02073
02074 minDeltaDistToUpdate= min(distTileTransSplitMerge, CLandscapeGlobals::TileDistFar - distMinFace );
02075 minDeltaDistToUpdate= min(minDeltaDistToUpdate, distMinFace - CLandscapeGlobals::TileDistNear);
02076 }
02078 else
02079 {
02080
02081
02082
02083 minDeltaDistToUpdate= 0;
02084 }
02085
02086 }
02087
02088
02089 if(minDeltaDistToUpdate<0.0625)
02090 {
02091 NL3D_PROFILE_LAND_ADD(ProfNRefineWithLowDistance, 1);
02092 }
02093
02094
02095
02096
02097 Patch->getLandscape()->_SplitPriorityList.insert(quadrantId, minDeltaDistToUpdate, this);
02098 }
02099 }
02100
02101
02102
02103 void CTessFace::updateRefineMerge()
02104 {
02105 NL3D_PROFILE_LAND_ADD(ProfNRefineFaces, 1);
02106
02107 nlassert(Patch);
02108
02109 nlassert(!isLeaf());
02110
02111
02112
02113
02114
02115
02116
02117 bool merged= false;
02118 {
02119 updateErrorMetric();
02120 float ps=ErrorMetric;
02121 ps*= CLandscapeGlobals::OORefineThreshold;
02122
02123
02124
02125
02126
02127
02128
02129 if(ps<1.0f)
02130 {
02131
02132
02133
02134 if(canMerge(true))
02135 {
02136 merge();
02137
02138
02139
02140 if(isLeaf())
02141 {
02142 merged= true;
02143 }
02144 }
02145 }
02146 }
02147
02148
02149
02150
02151
02152
02153 if(!merged)
02154 {
02155
02156 nlassert(!isLeaf());
02157
02158 float minDeltaDistToUpdate;
02159
02160
02161
02162 float distSplitPoint= (SplitPoint - CLandscapeGlobals::RefineCenter).norm();
02163
02164 float distNormalSplitMerge= (float)sqrt(Size*CLandscapeGlobals::OORefineThreshold);
02165
02166
02167
02168 if(Level>=Patch->TileLimitLevel+CLandscapeGlobals::TileMaxSubdivision)
02169 {
02170
02171 minDeltaDistToUpdate= 0;
02172 }
02173 else if(Level>=Patch->TileLimitLevel)
02174 {
02175
02176
02177
02178 minDeltaDistToUpdate= distNormalSplitMerge - distSplitPoint;
02179
02180
02181
02182 minDeltaDistToUpdate= max( 0.f, minDeltaDistToUpdate );
02183 }
02184 else
02185 {
02186
02187 float s0= (VBase->EndPos - CLandscapeGlobals::RefineCenter).sqrnorm();
02188 float s1= (VLeft->EndPos - CLandscapeGlobals::RefineCenter).sqrnorm();
02189 float s2= (VRight->EndPos - CLandscapeGlobals::RefineCenter).sqrnorm();
02190 float distMinFace= (float)sqrt( minof(s0, s1, s2) );
02191
02192
02193 float normalEMDeltaDist;
02194 normalEMDeltaDist= distNormalSplitMerge - distSplitPoint;
02195 normalEMDeltaDist= max( 0.f, normalEMDeltaDist );
02196
02197
02198
02199
02200
02202 if( distMinFace > CLandscapeGlobals::TileDistFar )
02203 {
02204
02205
02206 minDeltaDistToUpdate= normalEMDeltaDist;
02207
02208
02209 minDeltaDistToUpdate= min(minDeltaDistToUpdate, distMinFace - CLandscapeGlobals::TileDistFar);
02210 }
02212 else if( distMinFace > CLandscapeGlobals::TileDistNear )
02213 {
02214
02215 NL3D_PROFILE_LAND_ADD(ProfNRefineInTileTransition, 1);
02216
02217
02218
02219 float distTileTransSplitMerge;
02220 float maxDeltaDist= 8;
02221 float minDeltaDist= 0;
02222 uint nbRecurs= 6;
02223 float nearLimit;
02224 nearLimit= CLandscapeGlobals::RefineThreshold * computeNearLimit();
02225
02226
02227 for(uint i=0; i< nbRecurs; i++)
02228 {
02229 float pivotDeltaDist= (maxDeltaDist-minDeltaDist)/2;
02230
02231 if ( computeTileEMForUpdateRefine(distSplitPoint+pivotDeltaDist, distMinFace+pivotDeltaDist, nearLimit ) > 1)
02232 minDeltaDist= pivotDeltaDist;
02233
02234 else
02235 maxDeltaDist= pivotDeltaDist;
02236 }
02237
02238 distTileTransSplitMerge= minDeltaDist;
02239
02240
02241
02242 minDeltaDistToUpdate= min(distTileTransSplitMerge, CLandscapeGlobals::TileDistFar - distMinFace );
02243 minDeltaDistToUpdate= min(minDeltaDistToUpdate, distMinFace - CLandscapeGlobals::TileDistNear);
02244 }
02246 else
02247 {
02248
02249
02250
02251 minDeltaDistToUpdate= CLandscapeGlobals::TileDistNear - distMinFace;
02252 }
02253
02254 }
02255
02256
02257
02258
02259 minDeltaDistToUpdate+= NL3D_REFINE_MERGE_THRESHOLD;
02260
02261
02262
02263 Patch->getLandscape()->_MergePriorityList.insert(0, minDeltaDistToUpdate, this);
02264 }
02265 }
02266
02267
02268
02269 void CTessFace::unbind()
02270 {
02271
02272
02273
02274
02275 if(!isRectangular())
02276 {
02277
02278 if(isLeaf())
02279 {
02280
02281 if(FLeft && FLeft->Patch!=Patch)
02282 {
02283 FLeft->changeNeighbor(this, NULL);
02284 FLeft= NULL;
02285 }
02286 if(FRight && FRight->Patch!=Patch)
02287 {
02288 FRight->changeNeighbor(this, NULL);
02289 FRight= NULL;
02290 }
02291 }
02292
02293 if(FBase && FBase->Patch!=Patch)
02294 {
02295 CTessFace *oldNeigbhorFace= FBase;
02296
02297 FBase->changeNeighbor(this, NULL);
02298 FBase= NULL;
02299 if(!isLeaf())
02300 {
02301
02302 CTessVertex *old= SonLeft->VBase;
02303 SonLeft->VBase= Patch->getLandscape()->newTessVertex();
02304 *(SonLeft->VBase)= *old;
02305 SonRight->VBase= SonLeft->VBase;
02306
02307
02308
02309 SonLeft->VBase->MaxFaceSize= Size;
02310 SonLeft->VBase->MaxNearLimit= computeNearLimit();
02311
02312 if(oldNeigbhorFace->Patch)
02313 {
02314 old->MaxFaceSize= oldNeigbhorFace->Size;
02315 old->MaxNearLimit= oldNeigbhorFace->computeNearLimit();
02316 }
02317 }
02318 }
02319 }
02320
02321
02322 else
02323 {
02324
02325
02326 if(FLeft && FLeft->Patch!=Patch)
02327 {
02328 CTessFace *oldNeigbhorFace= FLeft;
02329
02330 FLeft->changeNeighbor(this, NULL);
02331 FLeft= NULL;
02332 if(!isLeaf())
02333 {
02334
02335
02336 CTessVertex *old= SonLeft->VBase;
02337 SonLeft->VBase= Patch->getLandscape()->newTessVertex();
02338 *(SonLeft->VBase)= *old;
02339
02340 SonRight->VLeft= SonLeft->VBase;
02341
02342 nlassert(FBase && FBase->SonLeft);
02343 FBase->SonLeft->VRight= SonLeft->VBase;
02344
02345
02346
02347
02348 SonLeft->VBase->MaxFaceSize= Size;
02349 SonLeft->VBase->MaxNearLimit= computeNearLimit();
02350
02351 if(oldNeigbhorFace->Patch)
02352 {
02353 old->MaxFaceSize= oldNeigbhorFace->Size;
02354 old->MaxNearLimit= oldNeigbhorFace->computeNearLimit();
02355 }
02356 }
02357 }
02358
02359 if(isLeaf())
02360 {
02361 if(FRight && FRight->Patch!=Patch)
02362 {
02363 FRight->changeNeighbor(this, NULL);
02364 FRight= NULL;
02365 }
02366 }
02367 }
02368
02369
02370
02371 if(!isLeaf())
02372 {
02373
02374 if(!isRectangular())
02375 {
02376 SonLeft->VLeft= VBase;
02377 SonLeft->VRight= VLeft;
02378 SonRight->VLeft= VRight;
02379 SonRight->VRight= VBase;
02380 }
02381 else
02382 {
02383
02384 SonLeft->VLeft= VLeft;
02385 SonRight->VBase= VBase;
02386 SonRight->VRight= VRight;
02387 }
02388
02389
02390 SonLeft->updateNearFarVertices();
02391 SonRight->updateNearFarVertices();
02392 if(isRectangular())
02393 {
02394
02395 nlassert(FBase && FBase->SonLeft && FBase->SonRight);
02396 FBase->SonLeft->updateNearFarVertices();
02397 FBase->SonRight->updateNearFarVertices();
02398 }
02399
02400
02401 SonLeft->unbind();
02402 SonRight->unbind();
02403 }
02404
02405 }
02406
02407 void CTessFace::forceMerge()
02408 {
02409 if(this== &CantMergeFace)
02410 return;
02411
02412 if(!isLeaf())
02413 {
02414
02415 SonLeft->forceMerge();
02416 SonRight->forceMerge();
02417
02418
02419 RecursMarkForceMerge=true;
02420 if(!isRectangular())
02421 {
02422 if(FBase && !FBase->RecursMarkForceMerge)
02423 FBase->forceMerge();
02424 }
02425 else
02426 {
02427
02428 if(FBase && !FBase->RecursMarkForceMerge)
02429 FBase->forceMerge();
02430 if(FLeft && !FLeft->RecursMarkForceMerge)
02431 FLeft->forceMerge();
02432 }
02433 RecursMarkForceMerge=false;
02434
02435
02436 if(!isLeaf())
02437 merge();
02438 }
02439 }
02440
02441
02442
02443 void CTessFace::forceMergeAtTileLevel()
02444 {
02445 if(this== &CantMergeFace)
02446 return;
02447
02448 if(!isLeaf())
02449 {
02450 SonLeft->forceMergeAtTileLevel();
02451 SonRight->forceMergeAtTileLevel();
02452 }
02453 else
02454 {
02455
02456 if(Level==Patch->TileLimitLevel)
02457 forceMerge();
02458 }
02459 }
02460
02461
02462
02463 void CTessFace::averageTesselationVertices()
02464 {
02465
02466 if(isLeaf())
02467 return;
02468
02469
02470 CTessFace *neighbor;
02471
02472 if(!isRectangular())
02473 {
02474 neighbor= FBase;
02475 }
02476
02477 else
02478 {
02479
02480
02481
02482 neighbor= FLeft;
02483 }
02484
02485
02486
02487
02488
02489
02490
02491 if(neighbor!=NULL && neighbor!=&CantMergeFace && Patch!= neighbor->Patch)
02492 {
02493 nlassert(neighbor->Patch);
02494 nlassert(!neighbor->isLeaf());
02495
02496
02497 nlassert(SonLeft->VBase == neighbor->SonLeft->VBase);
02498
02499 CVector v0= Patch->computeVertex(SonLeft->PVBase.getS(), SonLeft->PVBase.getT());
02500 CVector v1= neighbor->Patch->computeVertex(neighbor->SonLeft->PVBase.getS(), neighbor->SonLeft->PVBase.getT());
02501
02502
02503 SonLeft->VBase->EndPos= (v0+v1)/2;
02504 }
02505
02506
02507
02508 SonLeft->averageTesselationVertices();
02509 SonRight->averageTesselationVertices();
02510 }
02511
02512
02513
02514 void CTessFace::refreshTesselationGeometry()
02515 {
02516
02517 Patch->extendTessBlockWithEndPos(this);
02518
02519
02520 if(isLeaf())
02521 return;
02522
02523
02524
02525
02526
02527
02528 SonLeft->VBase->EndPos= Patch->computeVertex(SonLeft->PVBase.getS(), SonLeft->PVBase.getT());
02529
02530 SonLeft->VBase->Pos= SonLeft->VBase->EndPos;
02531
02532
02533 SonLeft->refreshTesselationGeometry();
02534 SonRight->refreshTesselationGeometry();
02535 }
02536
02537
02538
02539 bool CTessFace::updateBindEdge(CTessFace *&edgeFace, bool &splitWanted)
02540 {
02541
02542
02543
02544 if(edgeFace==NULL)
02545 return true;
02546
02547 if(edgeFace->isLeaf())
02548 return true;
02549
02550
02551
02552
02553
02554
02555
02556
02557
02558 if(edgeFace->Patch==NULL && edgeFace->FBase==this)
02559 {
02560 splitWanted= true;
02561 return true;
02562 }
02563
02564
02565
02566
02567 if(!edgeFace->isRectangular())
02568 {
02569
02570
02571
02572 if(edgeFace->FBase==this)
02573 {
02574 splitWanted= true;
02575 return true;
02576 }
02577 else
02578 {
02579
02580 if(edgeFace->FLeft==this)
02581 {
02582 CTessFace *sonLeft= edgeFace->SonLeft;
02583 sonLeft->FBase= this;
02584 edgeFace= sonLeft;
02585 }
02586 else if(edgeFace->FRight==this)
02587 {
02588 CTessFace *sonRight= edgeFace->SonRight;
02589 sonRight->FBase= this;
02590 edgeFace= sonRight;
02591 }
02592 else
02593 {
02594
02595
02596 nlstop;
02597 }
02598 }
02599 }
02600
02601
02602 else
02603 {
02604
02605
02606
02607
02608
02609 if(edgeFace->FLeft==this || edgeFace->FBase==this)
02610 {
02611 splitWanted= true;
02612 return true;
02613 }
02614 else
02615 {
02616 if(edgeFace->FRight==this)
02617 {
02618
02619 CTessFace *sonRight= edgeFace->SonRight;
02620 sonRight->FRight= this;
02621 edgeFace= sonRight;
02622 }
02623 else
02624 {
02625
02626
02627 nlstop;
02628 }
02629 }
02630 }
02631
02632 return false;
02633 }
02634
02635
02636
02637
02638 void CTessFace::updateBindAndSplit()
02639 {
02640 bool splitWanted= false;
02641 CTessFace *f0= NULL;
02642 CTessFace *f1= NULL;
02643
02644
02645
02646
02647 nlassert(isLeaf());
02648 while(!updateBindEdge(FBase, splitWanted));
02649
02650 while(!updateBindEdge(FLeft, splitWanted));
02651 while(!updateBindEdge(FRight, splitWanted));
02652
02653
02654 if(isRectangular())
02655 {
02656 f0= this;
02657 f1= FBase;
02658 nlassert(FBase);
02659 nlassert(FBase->isLeaf());
02660
02661
02662 while(!FBase->updateBindEdge(FBase->FLeft, splitWanted));
02663 while(!FBase->updateBindEdge(FBase->FRight, splitWanted));
02664 }
02665
02666
02667
02668 CTessFace *fmult= NULL;
02669 CTessFace *fmult0= NULL;
02670 CTessFace *fmult1= NULL;
02671
02672
02673 if(!isRectangular())
02674 {
02675
02676 if(FBase && FBase->Patch==NULL)
02677 {
02678 fmult= FBase;
02679
02680 FBase= NULL;
02681 }
02682 }
02683 else
02684 {
02685
02686 if(f0->FLeft && f0->FLeft->Patch==NULL)
02687 {
02688 fmult0= f0->FLeft;
02689
02690 f0->FLeft= NULL;
02691 }
02692
02693 if(f1->FLeft && f1->FLeft->Patch==NULL)
02694 {
02695 fmult1= f1->FLeft;
02696
02697 f1->FLeft= NULL;
02698 }
02699 }
02700
02701
02702
02703 split(false);
02704 if(!isRectangular())
02705 {
02706 if(FBase)
02707 {
02708 while(FBase->isLeaf())
02709 FBase->updateBindAndSplit();
02710 }
02711
02712
02713 nlassert(SonLeft->isLeaf() && SonRight->isLeaf());
02714 }
02715 else
02716 {
02717 if(f0->FLeft)
02718 {
02719 while(f0->FLeft->isLeaf())
02720 f0->FLeft->updateBindAndSplit();
02721 }
02722 if(f1->FLeft)
02723 {
02724 while(f1->FLeft->isLeaf())
02725 f1->FLeft->updateBindAndSplit();
02726 }
02727
02728
02729 nlassert(f0->SonLeft->isLeaf() && f0->SonRight->isLeaf());
02730 nlassert(f1->SonLeft->isLeaf() && f1->SonRight->isLeaf());
02731 }
02732
02733
02734
02735
02736 if(!isRectangular() && fmult)
02737 {
02738
02739
02740 SonLeft->FRight= fmult->SonRight;
02741 fmult->SonRight->changeNeighbor(&CTessFace::MultipleBindFace, SonLeft);
02742
02743 SonRight->FLeft= fmult->SonLeft;
02744 fmult->SonLeft->changeNeighbor(&CTessFace::MultipleBindFace, SonRight);
02745
02746
02747
02748
02749
02750
02751 CTessVertex *vert= fmult->VBase;
02752
02753
02754 vert->Pos= vert->StartPos= vert->EndPos= SonLeft->VBase->EndPos;
02755
02756 Patch->getLandscape()->deleteTessVertex(SonLeft->VBase);
02757
02758 SonLeft->VBase= vert;
02759 SonRight->VBase= vert;
02760
02761 SonRight->computeSplitPoint();
02762 SonLeft->computeSplitPoint();
02763
02764
02765
02766
02767
02768
02769
02770 nlassert(SonLeft->isLeaf() && SonRight->isLeaf());
02771
02772 SonLeft->updateNearFarVertices();
02773 SonRight->updateNearFarVertices();
02774
02775
02776
02777
02778 FBase= &CantMergeFace;
02779
02780
02781
02782 }
02783
02784 else if(fmult0 || fmult1)
02785 {
02786 CTessFace *f;
02787 sint i;
02788
02789
02790 for(i=0;i<2;i++)
02791 {
02792 if(i==0)
02793 f= f0, fmult= fmult0;
02794 else
02795 f= f1, fmult= fmult1;
02796 if(fmult)
02797 {
02798
02799
02800
02801 CTessFace *toLeft, *toRight;
02802 CTessFace *fl=f->SonLeft, *fr=f->SonRight;
02803 toLeft= fmult->SonLeft;
02804 toRight= fmult->SonRight;
02805
02806 fl->FLeft= toLeft;
02807 fr->FLeft= toRight;
02808 toLeft->changeNeighbor(&CTessFace::MultipleBindFace, fl);
02809 toRight->changeNeighbor(&CTessFace::MultipleBindFace, fr);
02810
02811
02812
02813 CTessVertex *vert= fmult->VBase;
02814
02815
02816
02817 vert->Pos= vert->StartPos= vert->EndPos= fl->VBase->EndPos;
02818
02819 Patch->getLandscape()->deleteTessVertex(fl->VBase);
02820
02821 fl->VBase= vert;
02822 fr->VLeft= vert;
02823 f->FBase->SonLeft->VRight= vert;
02824
02825
02826 f->FLeft= &CantMergeFace;
02827 }
02828 }
02829
02830 for(i=0;i<2;i++)
02831 {
02832 if(i==0)
02833 f= f0;
02834 else
02835 f= f1;
02836
02837 f->SonRight->computeSplitPoint();
02838 f->SonLeft->computeSplitPoint();
02839
02840
02841
02842
02843
02844
02845 nlassert(f->SonLeft->isLeaf() && f->SonRight->isLeaf());
02846
02847 f->SonLeft->updateNearFarVertices();
02848 f->SonRight->updateNearFarVertices();
02849 }
02850 }
02851 }
02852
02853
02854
02855 void CTessFace::updateBind()
02856 {
02857
02858
02859
02860
02861
02862
02863
02864
02865
02866
02867 if(isLeaf())
02868 {
02869 bool splitWanted= false;
02870 while(!updateBindEdge(FBase, splitWanted));
02871
02872 while(!updateBindEdge(FLeft, splitWanted));
02873 while(!updateBindEdge(FRight, splitWanted));
02874 if(splitWanted)
02875 updateBindAndSplit();
02876 }
02877
02878
02879
02880 if(!isLeaf())
02881 {
02882
02883 SonLeft->updateBind();
02884 SonRight->updateBind();
02885 }
02886 }
02887
02888
02889 static inline bool matchEdge(const CVector2f &uv0, const CVector2f &uv1, const CVector2f &uva, const CVector2f &uvb)
02890 {
02891 if(uv0==uva && uv1==uvb)
02892 return true;
02893 if(uv0==uvb && uv1==uva)
02894 return true;
02895 return false;
02896 }
02897
02898
02899 CTessFace *CTessFace::linkTessFaceWithEdge(const CVector2f &uv0, const CVector2f &uv1, CTessFace *linkTo)
02900 {
02901
02902 CVector2f vb( PVBase.getS(), PVBase.getT() );
02903 CVector2f vl( PVLeft.getS(), PVLeft.getT() );
02904 CVector2f vr( PVRight.getS(), PVRight.getT() );
02905
02906
02907
02908 if(matchEdge(uv0, uv1, vl, vr))
02909 {
02910
02911 nlassert(FBase==NULL || !isLeaf());
02912 FBase= linkTo;
02913 return this;
02914 }
02915
02916 if(matchEdge(uv0, uv1, vb, vl))
02917 {
02918
02919 nlassert(FLeft==NULL || !isLeaf());
02920 FLeft= linkTo;
02921 return this;
02922 }
02923
02924 if(matchEdge(uv0, uv1, vb, vr))
02925 {
02926
02927 nlassert(FRight==NULL || !isLeaf())
02928 FRight= linkTo;
02929 return this;
02930 }
02931
02932
02933
02934 CTessFace *ret= NULL;
02935 if( !isLeaf() )
02936 {
02937 ret= SonLeft->linkTessFaceWithEdge(uv0, uv1, linkTo);
02938
02939 if(!ret)
02940 ret= SonRight->linkTessFaceWithEdge(uv0, uv1, linkTo);
02941 }
02942
02943
02944 return ret;
02945 }
02946
02947
02948
02949 bool CTessFace::isRectangular() const
02950 {
02951 return Level<Patch->SquareLimitLevel;
02952 }
02953
02954
02955
02956
02957
02958
02959
02960
02961
02962
02963
02964 void CTessFace::deleteTileUvs()
02965 {
02966
02967
02968 if(!isLeaf())
02969 {
02970
02971 SonLeft->deleteTileUvs();
02972 SonRight->deleteTileUvs();
02973 if(SonLeft->Level== Patch->TileLimitLevel)
02974 {
02975
02976 nlassert(!sameTile(SonLeft, SonRight));
02977
02978 SonLeft->releaseTileMaterial();
02979 SonRight->releaseTileMaterial();
02980 }
02981 else if(SonLeft->Level > Patch->TileLimitLevel)
02982 {
02983 nlassert(!FBase || !FBase->isLeaf());
02984
02985
02986
02987
02988 if(!FBase || !FBase->SonLeft->emptyTileFaces() || !sameTile(this, FBase))
02989 {
02990 SonLeft->deleteTileUv(IdUvBase);
02991 }
02992
02993 SonLeft->deleteTileFaces();
02994 SonRight->deleteTileFaces();
02995
02996 SonLeft->TileMaterial= NULL;
02997 SonRight->TileMaterial= NULL;
02998 }
02999 }
03000 else
03001 {
03002
03003
03004 if(TileMaterial)
03005 Patch->removeFaceFromTileRenderList(this);
03006 }
03007
03008 }
03009
03010
03011
03012 void CTessFace::recreateTileUvs()
03013 {
03014
03015
03016 if(!isLeaf())
03017 {
03018
03019
03020
03021
03022 if(SonLeft->Level==Patch->TileLimitLevel)
03023 {
03024 SonLeft->computeTileMaterial();
03025 SonRight->computeTileMaterial();
03026 }
03027
03028 else if(SonLeft->Level > Patch->TileLimitLevel)
03029 {
03030 heritTileMaterial();
03031 }
03032
03033 SonLeft->recreateTileUvs();
03034 SonRight->recreateTileUvs();
03035 }
03036 else
03037 {
03038
03039
03040 if(TileMaterial)
03041 Patch->appendFaceToTileRenderList(this);
03042 }
03043 }
03044
03045
03046
03047
03048 void CTessFace::heritTileMaterial()
03049 {
03050 SonLeft->TileMaterial= TileMaterial;
03051 SonLeft->TileId= TileId;
03052 SonLeft->buildTileFaces();
03053 SonLeft->copyTileUv(IdUvLeft, this, IdUvBase);
03054 SonLeft->copyTileUv(IdUvRight, this, IdUvLeft);
03055
03056 SonRight->TileMaterial= TileMaterial;
03057 SonRight->TileId= TileId;
03058 SonRight->buildTileFaces();
03059 SonRight->copyTileUv(IdUvLeft, this, IdUvRight);
03060 SonRight->copyTileUv(IdUvRight, this, IdUvBase);
03061
03062
03063
03064
03065 if(FBase!=NULL && !FBase->isLeaf() && FBase->SonLeft->TileMaterial!=NULL && sameTile(this, FBase) )
03066 {
03067
03068
03069 SonLeft->copyTileUv(IdUvBase, FBase->SonLeft, IdUvBase);
03070 SonRight->copyTileUv(IdUvBase, FBase->SonLeft, IdUvBase);
03071 }
03072 else
03073 {
03074
03075 SonLeft->allocTileUv(IdUvBase);
03076 SonRight->copyTileUv(IdUvBase, SonLeft, IdUvBase);
03077
03078
03079 SonLeft->heritTileUv(this);
03080
03081
03082 SonLeft->checkCreateFillTileVB(IdUvBase);
03083 }
03084
03085 }
03086
03087
03088
03089
03090
03091
03092
03093
03094
03095
03096 void CTessFace::getTesselatedPos(const CUV &uv, bool verifInclusion, CVector &ret)
03097 {
03098 CVector uvPos(uv.U, uv.V, 0);
03099
03100
03101 if(verifInclusion && !(isRectangular() && !isLeaf()) )
03102 {
03103 CVector uvs[3];
03104 uvs[0].set( PVBase.getS(), PVBase.getT(), 0);
03105 uvs[1].set( PVLeft.getS(), PVLeft.getT(), 0);
03106 uvs[2].set( PVRight.getS(), PVRight.getT(), 0);
03107 for(sint i=0; i<3; i++)
03108 {
03109 CVector dUv= uvs[(i+1)%3] - uvs[i];
03110 CVector normalUv(dUv.y, -dUv.x, 0);
03111
03112 if(normalUv * (uvPos-uvs[i]) <0)
03113 return;
03114 }
03115 }
03116
03117
03118 if(isLeaf())
03119
03120 computeTesselatedPos(uv, ret);
03121 else
03122 {
03123
03124
03125 if(isRectangular())
03126 {
03127 SonLeft->getTesselatedPos(uv, true, ret);
03128 SonRight->getTesselatedPos(uv, true, ret);
03129 }
03130 else
03131 {
03132
03133 CVector uvBase, uvMiddle;
03134 uvBase.set ( PVBase.getS(), PVBase.getT(), 0);
03135 uvMiddle.set( SonLeft->PVBase.getS(), SonLeft->PVBase.getT(), 0);
03136 CVector dUv= uvMiddle - uvBase;
03137 CVector normalUv(dUv.y, -dUv.x, 0);
03138
03139 if(normalUv * (uvPos - uvBase) <0)
03140 SonLeft->getTesselatedPos(uv, false, ret);
03141 else
03142 SonRight->getTesselatedPos(uv, false, ret);
03143
03144 }
03145 }
03146
03147 }
03148
03149
03150
03151 void CTessFace::computeTesselatedPos(const CUV &uv, CVector &ret)
03152 {
03153 CVector uvPos(uv.U, uv.V, 0);
03154
03155
03156 CTriangle uvTri;
03157 uvTri.V0.set( PVBase.getS(), PVBase.getT(), 0);
03158 uvTri.V1.set( PVLeft.getS(), PVLeft.getT(), 0);
03159 uvTri.V2.set( PVRight.getS(), PVRight.getT(), 0);
03160
03161
03162 CVector Gx;
03163 CVector Gy;
03164 CVector Gz;
03165
03166 if( CLandscapeGlobals::VertexProgramEnabled )
03167 {
03168
03169 VBase->computeGeomPos();
03170 VLeft->computeGeomPos();
03171 VRight->computeGeomPos();
03172 }
03173
03174 uvTri.computeGradient(VBase->Pos.x, VLeft->Pos.x, VRight->Pos.x, Gx);
03175 uvTri.computeGradient(VBase->Pos.y, VLeft->Pos.y, VRight->Pos.y, Gy);
03176 uvTri.computeGradient(VBase->Pos.z, VLeft->Pos.z, VRight->Pos.z, Gz);
03177
03178
03179 ret= VBase->Pos;
03180 uvPos-= uvTri.V0;
03181 ret.x+= Gx*uvPos;
03182 ret.y+= Gy*uvPos;
03183 ret.z+= Gz*uvPos;
03184
03185 }
03186
03187
03188
03189 void CTessFace::appendTessellationLeaves(std::vector<const CTessFace*> &leaves) const
03190 {
03191 if(isLeaf())
03192 leaves.push_back(this);
03193 else
03194 {
03195 SonLeft->appendTessellationLeaves(leaves);
03196 SonRight->appendTessellationLeaves(leaves);
03197 }
03198 }
03199
03200
03201 }