From 0ea5fc66924303d1bf73ba283a383e2aadee02f2 Mon Sep 17 00:00:00 2001 From: neodarz Date: Sat, 11 Aug 2018 20:21:34 +0200 Subject: Initial commit --- docs/doxygen/nel/tessellation_8cpp-source.html | 3263 ++++++++++++++++++++++++ 1 file changed, 3263 insertions(+) create mode 100644 docs/doxygen/nel/tessellation_8cpp-source.html (limited to 'docs/doxygen/nel/tessellation_8cpp-source.html') diff --git a/docs/doxygen/nel/tessellation_8cpp-source.html b/docs/doxygen/nel/tessellation_8cpp-source.html new file mode 100644 index 00000000..1aec2208 --- /dev/null +++ b/docs/doxygen/nel/tessellation_8cpp-source.html @@ -0,0 +1,3263 @@ + + + + nevrax.org : docs + + + + + + + + + + + + + + +
# Home   # nevrax.com   
+ + + + +
Nevrax
+ + + + + + + + + + +
+ + +
+ Nevrax.org
+ + + + + + + +
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
+
+ + +
+ + +
+Docs + +
+  + + + + + +
Documentation 
+ +
+Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  
+

tessellation.cpp

Go to the documentation of this file.
00001 
+00008 /* Copyright, 2000 Nevrax Ltd.
+00009  *
+00010  * This file is part of NEVRAX NEL.
+00011  * NEVRAX NEL is free software; you can redistribute it and/or modify
+00012  * it under the terms of the GNU General Public License as published by
+00013  * the Free Software Foundation; either version 2, or (at your option)
+00014  * any later version.
+00015 
+00016  * NEVRAX NEL is distributed in the hope that it will be useful, but
+00017  * WITHOUT ANY WARRANTY; without even the implied warranty of
+00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+00019  * General Public License for more details.
+00020 
+00021  * You should have received a copy of the GNU General Public License
+00022  * along with NEVRAX NEL; see the file COPYING. If not, write to the
+00023  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+00024  * MA 02111-1307, USA.
+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 // The normal Uvs format.
+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 // \todo yoyo: may change this.
+00059 const   float TileSize= 128;
+00060 
+00061 
+00062 
+00063 
+00064 // ***************************************************************************
+00065 // ***************************************************************************
+00066 // CTileMaterial
+00067 // ***************************************************************************
+00068 // ***************************************************************************
+00069 
+00070 
+00071 // ***************************************************************************
+00072 CTileMaterial::CTileMaterial()
+00073 {
+00074         // By default, all pass are NULL.
+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                 // If RdrPass exist, add this Material Id
+00088                 CPatchRdrPass   *rdrPass= Pass[i].PatchRdrPass;
+00089                 if(rdrPass!=NULL)
+00090                 {
+00091                         /* enlarge the capacity of the pass so it can renders the tile faces of this patch.
+00092                          *      NumRenderableFaces is really too big since the tile-material surely doesn't use all
+00093                          *      faces of the patch (except if same texture...)
+00094                          *      But doesn't matter. Even if all the visible Tile Surface (80m*80m) is in the same pass,
+00095                          *      it leads to only 76K final in CLandscapeGlobals::PassTriArray:
+00096                          *      80*80(Visible surface at 80m max) /4 (2m*2m) *2(triangles) *2 (over-estimate) *3*4(triSize)=
+00097                          *      76800
+00098                          */
+00099                         rdrPass->appendRdrPatchTile(i, &Pass[i], patchNumRenderableFaces);
+00100                 }
+00101         }
+00102 }
+00103 
+00104 
+00105 // ***************************************************************************
+00106 // ***************************************************************************
+00107 //      CTessVertex
+00108 // ***************************************************************************
+00109 // ***************************************************************************
+00110 
+00111 
+00112 // ***************************************************************************
+00113 void            CTessVertex::computeGeomPos()
+00114 {
+00115         // Compute Basic ErrorMetric.
+00116         float   sqrDist= (StartPos - CLandscapeGlobals::RefineCenter).sqrnorm();
+00117         float   pgeom= MaxFaceSize * CLandscapeGlobals::OORefineThreshold / sqrDist;
+00118 
+00119         // Compute ErrorMetric modified by TileNear transition, only if TileNear transition.
+00120         if( sqrDist< CLandscapeGlobals::TileDistFarSqr )
+00121         {
+00122                 // Soft optim: do it only if necessary, ie result of max(errorMetric, errorMetricModified) is foreseeable here.
+00123                 if(pgeom < MaxNearLimit)
+00124                 {
+00125                         float   f= (CLandscapeGlobals::TileDistFarSqr - sqrDist) * CLandscapeGlobals::OOTileDistDeltaSqr;
+00126                         clamp(f, 0, 1);
+00127                         // ^4 gives better smooth result
+00128                         f= sqr(f);
+00129                         f= sqr(f);
+00130                         // interpolate the errorMetric
+00131                         pgeom= MaxNearLimit*f + pgeom*(1-f);
+00132                 }
+00133         }
+00134 
+00135         // Interpolate StartPos to EndPos, between 1 and 2.
+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 // CTessFace
+00151 // ***************************************************************************
+00152 // ***************************************************************************
+00153 
+00154 
+00155 // ***************************************************************************
+00156 CTessFace       CTessFace::CantMergeFace;
+00157 CTessFace       CTessFace::MultipleBindFace;
+00158 
+00159 
+00160 // ***************************************************************************
+00161 CTessFace::CTessFace()
+00162 {
+00163         // Don't modify any of it!!
+00164         // Patch, SonLeft and SonRight nullity are very usefull for MultiplePatch faces, and CantMergeFace.
+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         // Size, Center, paramcoord undetermined.
+00173 
+00174         TileMaterial= NULL;
+00175         // Very important (for split reasons). Init Tilefaces to NULL.
+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         // Old Code. This is not sufficient to clear the CTessFace.
+00193         // Vertices and Uvs must be correctly cleared too (but difficult because of sharing).
+00194         /*
+00195         Patch->getLandscape()->deleteTessFace(SonLeft);
+00196         Patch->getLandscape()->deleteTessFace(SonRight);
+00197 
+00198         // update neighbors.
+00199         if(FBase)       FBase->changeNeighbor(this, NULL);
+00200         if(FLeft)       FLeft->changeNeighbor(this, NULL);
+00201         if(FRight)      FRight->changeNeighbor(this, NULL);
+00202 
+00203         FBase=FLeft=FRight= NULL;
+00204         */
+00205 
+00206         NL3D_PROFILE_LAND_ADD(ProfNTessFace, -1);
+00207 }
+00208 
+00209 
+00210 // ***************************************************************************
+00211 float                   CTessFace::computeNearLimit()
+00212 {
+00213         // General formula for Level, function of Size, treshold etc...:
+00214         // WantedLevel= log2(BaseSize / sqrdist / RefineThreshold);
+00215         // <=> WantedLevel= log2( CurSize*2^Level / sqrdist / RefineThreshold).
+00216         // <=> WantedLevel= log2( ProjectedSize* 2^Level / RefineThreshold).
+00217         // <=> 2^WantedLevel= ProjectedSize* 2^Level / RefineThreshold.
+00218         // <=> ProjectedSize= (2^WantedLevel) * RefineThreshold / (2^Level);
+00219         // <=> ProjectedSize= (1<<WantedLevel) * RefineThreshold / (1<<Level);
+00220         // UnOptimised formula: limit= (1<<Patch->TileLimitLevel) / (1<<Level);
+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         // We must take a more correct errometric here: We must have sons face which have
+00232         // lower projectedsize than father. This is not the case if Center of face is taken (but when not in
+00233         // tile mode this is nearly the case). So take the min dist from 3 points.
+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         // It is also VERY important to take the min of 3, to ensure the split in TileMode when Far1 vertex begin
+00239         // to blend (see Patch::renderFar1() render).
+00240 
+00241         // NB: VertexProgram geomorph take sqrdist= (SplitPoint - RefineCenter).sqrnorm();
+00242         // It's OK because geomorph will start "far" after the split.
+00243 
+00244         if(sqrdist< CLandscapeGlobals::TileDistFarSqr)
+00245         {
+00246                 float   nearLimit;
+00247                 nearLimit= CLandscapeGlobals::RefineThreshold * computeNearLimit();
+00248                 // If we are not so subdivided.
+00249                 if(ErrorMetric<nearLimit)
+00250                 {
+00251                         if(sqrdist< CLandscapeGlobals::TileDistNearSqr)
+00252                         {
+00253                                 ErrorMetric=nearLimit;
+00254                         }
+00255                         else
+00256                         {
+00257                                 // Smooth transition to the nearLimit of tesselation.
+00258                                 float   f= ( CLandscapeGlobals::TileDistFarSqr - sqrdist ) * CLandscapeGlobals::OOTileDistDeltaSqr;
+00259                                 // sqr gives better result, by smoothing more the start of transition.
+00260                                 f= sqr(f);
+00261                                 f= sqr(f);
+00262                                 ErrorMetric= ErrorMetric + (nearLimit-ErrorMetric)*f;
+00263 
+00264                                 // If threshold is big like 0.5, transition is still hard, and pops occurs. But The goal is 
+00265                                 // 0.005 and less, so don't bother. 
+00266                         }
+00267                 }
+00268         }
+00269 }
+00270 
+00271 
+00272 // ***************************************************************************
+00273 void            CTessFace::updateErrorMetric()
+00274 {
+00275         // If already updated for this pass...
+00276         if(ErrorMetricDate>= CLandscapeGlobals::CurrentDate)
+00277                 return;
+00278 
+00279         CVector viewdir= SplitPoint - CLandscapeGlobals::RefineCenter;
+00280         float   sqrdist= viewdir.sqrnorm();
+00281 
+00282         // trivial formula.
+00283         //-----------------
+00284         ErrorMetric= Size/ sqrdist;
+00285 
+00286 
+00287         // Hoppe97 formula:  k²= a² * ("v-e"² - ((v-e).n)²) / "v-e"^4.
+00288         //-----------------
+00289         // Can't do it because geomorph is made on Graphic card, so the simplier is the better.
+00290 
+00291 
+00292         // TileMode Impact.
+00293         //-----------------
+00294         /* TileMode Impact. We must split at least at TileLimitLevel, but only if the triangle
+00295                 has a chance to enter in the TileDistFar sphere.
+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         // Normal ErrorMetric simulation.
+00311         ema= Size / sqr(distSplitPoint);
+00312 
+00313         // TileErrorMetric simulation.
+00314         if(distMinFace < CLandscapeGlobals::TileDistFar)
+00315         {
+00316                 // If we are not so subdivided.
+00317                 if( ema<nearLimit )
+00318                 {
+00319                         if( distMinFace< CLandscapeGlobals::TileDistNear)
+00320                         {
+00321                                 ema= nearLimit;
+00322                         }
+00323                         else
+00324                         {
+00325                                 // Smooth transition to the nearLimit of tesselation.
+00326                                 float   f= ( CLandscapeGlobals::TileDistFarSqr - sqr(distMinFace) ) * CLandscapeGlobals::OOTileDistDeltaSqr;
+00327                                 // sqr gives better result, by smoothing more the start of transition.
+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                 // If it is a rectangular triangle, it will be splitted on the middle of VBase/VLeft.
+00345                 // see splitRectangular() conventions.
+00346                 // So for good geomorph compute per vertex, we must have this SplitPoint on this middle.
+00347                 SplitPoint= (VLeft->EndPos + VBase->EndPos)/2;
+00348         }
+00349         else
+00350         {
+00351                 // If it is a square triangle, it will be splitted on middle of VLeft/VRight. 
+00352                 // So for good geomorph compute per vertex, we must have this SplitPoint on this middle.
+00353                 SplitPoint= (VLeft->EndPos + VRight->EndPos)/2;
+00354         }
+00355 
+00356         // compute MaxDistToSplitPoint
+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         // Get the distance.
+00363         MaxDistToSplitPoint= sqrtf(MaxDistToSplitPoint);
+00364 }
+00365 
+00366 // ***************************************************************************
+00367 void    CTessFace::allocTileUv(TTileUvId id)
+00368 {
+00369         // TileFaces must have been build.
+00370         nlassert(TileFaces[NL3D_TILE_PASS_RGB0]);
+00371 
+00372         // what src??
+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         // Do it for all possible pass
+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                         // May Allocate/Fill VB. Do it after allocTileUv, because UVs are not comuted yet.
+00393                 }
+00394         }
+00395 }
+00396 
+00397 // ***************************************************************************
+00398 void    CTessFace::checkCreateFillTileVB(TTileUvId id)
+00399 {
+00400         // TileFaces must have been build.
+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                         // May Allocate/Fill VB.
+00411                         Patch->checkCreateVertexVBNear(vertNear);
+00412                         Patch->checkFillVertexVBNear(vertNear);
+00413                 }
+00414         }
+00415 }
+00416 
+00417 
+00418 // ***************************************************************************
+00419 void    CTessFace::checkFillTileVB(TTileUvId id)
+00420 {
+00421         // TileFaces must have been build.
+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                         // May Fill VB.
+00432                         Patch->checkFillVertexVBNear(vertNear);
+00433                 }
+00434         }
+00435 }
+00436 
+00437 
+00438 // ***************************************************************************
+00439 void    CTessFace::deleteTileUv(TTileUvId id)
+00440 {
+00441         // TileFaces must still exist.
+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                         // May delete this vertex from VB.
+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         // TileFaces must have been build.
+00464         nlassert(TileFaces[NL3D_TILE_PASS_RGB0]);
+00465 
+00466         // Since this a ptr-copy, no need to add/remove the renderlist of near vertices.
+00467 
+00468         for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
+00469         {
+00470                 if(TileFaces[i])
+00471                 {
+00472                         // The srcface should have the same tileFaces enabled.
+00473                         nlassert(srcFace->TileFaces[i]);
+00474 
+00475                         // copy from src.
+00476                         CTessNearVertex         *copyNear;
+00477                         copyNear= srcFace->TileFaces[i]->V[srcId];
+00478 
+00479                         // copy to dst.
+00480                         TileFaces[i]->V[dstId]=  copyNear;
+00481                 }
+00482         }
+00483 }
+00484 // ***************************************************************************
+00485 void    CTessFace::heritTileUv(CTessFace *baseFace)
+00486 {
+00487         // TileFaces must have been build.
+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                         // The baseface should have the same tileFaces enabled.
+00495                         nlassert(baseFace->TileFaces[i]);
+00496                         // VBase should be allocated.
+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         // Do nothgin for lightmap pass, of course.
+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         // Do nothgin for lightmap pass, of course.
+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         // Do nothgin for lightmap pass, of course.
+00547         for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
+00548         {
+00549                 // Some TileFace exist??
+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         // Get good coordinate according to patch orientation.
+00563         uv.U= pointCoord.S<=middle.S? 0.0f: 1.0f;
+00564         uv.V= pointCoord.T<=middle.T? 0.0f: 1.0f;
+00565         
+00566         // Get Tile Uv info: orientation and scale.
+00567         uint8           orient;
+00568         CVector         uvScaleBias;
+00569         bool            is256;
+00570         uint8           uvOff;
+00571         Patch->getTileUvInfo(TileId, pass, alpha, orient, uvScaleBias, is256, uvOff);
+00572 
+00573         // Orient the UV.
+00574         float   u= uv.U;
+00575         float   v= uv.V;
+00576         // Speed rotation.
+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         // Do the 256x256.
+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         // Do the HalfPixel scale bias.
+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         // Scale the UV.
+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         // Get good coordinate according to patch orientation.
+00634         uv.U= pointCoord.S<=middle.S? 0.0f: 1.0f;
+00635         uv.V= pointCoord.T<=middle.T? 0.0f: 1.0f;
+00636         
+00637         // Get Tile Lightmap Uv info: bias and scale.
+00638         CVector         uvScaleBias;
+00639         Patch->getTileLightMapUvInfo(TileMaterial->TileS, TileMaterial->TileT, uvScaleBias);
+00640 
+00641         // Scale the UV.
+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         // get the dlm context from the patch.
+00653         CPatchDLMContext        *dlmCtx= Patch->_DLMContext;
+00654         // mmust exist at creation of the tile.
+00655         nlassert(dlmCtx);
+00656 
+00657         // get coord in 0..1 range, along the patch.
+00658         uv.U= pointCoord.getS();
+00659         uv.V= pointCoord.getT();
+00660 
+00661         // ScaleBias according to the context.
+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         // 0. Compute TileId.
+00673         //-------------------
+00674         // Square Order Patch assumption: assume that when a CTessFace become a tile, his base can ONLY be diagonal...
+00675         /* a Patch:
+00676                 A ________
+00677                 |\      /|
+00678                 | \    / |
+00679            C|__\B_/  |
+00680                 |  /  \  |
+00681                 | /    \ |
+00682                 |/______\|
+00683 
+00684                 Here, if OrderS*OrderT=2*2, ABC is a new CTessFace of a Tile, and AB is the diagonal of the tile.
+00685                 Hence the middle of the tile is the middle of AB.
+00686 
+00687                 C must be created, but A and B may be created or copied from neighbor.
+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         // 1. Compute Tile Material.
+00696         //--------------------------
+00697         // if base neighbor is already at TileLimitLevel just ptr-copy, else create the TileMaterial...
+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         // NB: because of delete/recreateTileUvs(), FBase->TileMaterial may be NULL, even if face is at good TileLimitLevel.
+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                 // Add this new material to the render list.
+00716                 Patch->appendTileMaterialToRenderList(TileMaterial);
+00717 
+00718                 // First, get a lightmap for this tile. NB: important to do this after appendTileMaterialToRenderList(), 
+00719                 // because use TessBlocks.
+00720                 Patch->getTileLightMap(ts, tt, TileMaterial->Pass[NL3D_TILE_PASS_LIGHTMAP].PatchRdrPass);
+00721 
+00722                 // Fill pass of multi pass material.
+00723                 for(i=0;i<NL3D_MAX_TILE_PASS;i++)
+00724                 {
+00725                         // Get the correct render pass, according to the tile number, and the pass.
+00726                         if(i!=NL3D_TILE_PASS_LIGHTMAP)
+00727                                 TileMaterial->Pass[i].PatchRdrPass= Patch->getTileRenderPass(TileId, i);
+00728                 }
+00729 
+00730                 // Fill Pass Info.
+00731                 for(i=0;i<NL3D_MAX_TILE_PASS;i++)
+00732                 {
+00733                         TileMaterial->Pass[i].TileMaterial= TileMaterial;
+00734                 }
+00735 
+00736                 // Do not append this tile to each RenderPass, done in preRender().
+00737         }
+00738 
+00739 
+00740         // 2. Compute Uvs.
+00741         //----------------
+00742         // NB: TileMaterial is already setup. Usefull for initTileUvLightmap() and initTileUvRGBA().
+00743 
+00744         // First, must create The TileFaces, according to the TileMaterial passes.
+00745         buildTileFaces();
+00746 
+00747         // Must allocate the Base, and insert into list.
+00748         allocTileUv(IdUvBase);
+00749 
+00750 
+00751         // Init LightMap UV, in RGB0 pass, UV1..
+00752         initTileUvLightmap(PVBase, middle, TileFaces[NL3D_TILE_PASS_RGB0]->V[IdUvBase]->PUv1);
+00753         // Init DLM Uv, in RGB0 pass, UV2.
+00754         initTileUvDLM(PVBase, TileFaces[NL3D_TILE_PASS_RGB0]->V[IdUvBase]->PUv2);
+00755 
+00756         // Init UV RGBA, for all pass (but lightmap).
+00757         for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
+00758         {
+00759                 nlassert(i!=NL3D_TILE_PASS_LIGHTMAP);
+00760                 // If pass is valid
+00761                 if( TileMaterial->Pass[i].PatchRdrPass)
+00762                 {
+00763                         // Face must exist.
+00764                         nlassert(TileFaces[i]);
+00765                         // Compute RGB UV in UV0.
+00766                         initTileUvRGBA(i, false, PVBase, middle, TileFaces[i]->V[IdUvBase]->PUv0);
+00767                         // If transition tile, compute alpha UV in UV1. 
+00768                         // Do it also for Additive, because may have Transition
+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         // UVs are computed, may create and fill VB.
+00775         checkCreateFillTileVB(IdUvBase);
+00776 
+00777 
+00778         // if base neighbor is already at TileLimitLevel just ptr-copy, else create the left/right TileUvs...
+00779         if(copyFromBase)
+00780         {
+00781                 // Just cross-copy the pointers.
+00782                 // Make Left near vertices be the Right vertices of FBase
+00783                 copyTileUv(IdUvLeft, FBase, IdUvRight);
+00784                 // Make Right near vertices be the Left vertices of FBase
+00785                 copyTileUv(IdUvRight, FBase, IdUvLeft);
+00786         }
+00787         else
+00788         {
+00789                 // Must allocate the left/right uv (and insert into list).
+00790                 allocTileUv(IdUvLeft);
+00791                 allocTileUv(IdUvRight);
+00792 
+00793 
+00794                 // Init LightMap UV, in UvPass 0, UV1..
+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                 // Init DLM Uv, in RGB0 pass, UV2.
+00798                 initTileUvDLM(PVLeft, TileFaces[NL3D_TILE_PASS_RGB0]->V[IdUvLeft]->PUv2);
+00799                 initTileUvDLM(PVRight, TileFaces[NL3D_TILE_PASS_RGB0]->V[IdUvRight]->PUv2);
+00800 
+00801                 // Init UV RGBA!
+00802                 for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
+00803                 {
+00804                         nlassert(i!=NL3D_TILE_PASS_LIGHTMAP);
+00805                         // If pass is valid
+00806                         if(TileMaterial->Pass[i].PatchRdrPass)
+00807                         {
+00808                                 // Face must exist.
+00809                                 nlassert(TileFaces[i]);
+00810                                 // Compute RGB UV in UV0.
+00811                                 initTileUvRGBA(i, false, PVLeft, middle, TileFaces[i]->V[IdUvLeft]->PUv0);
+00812                                 initTileUvRGBA(i, false, PVRight, middle, TileFaces[i]->V[IdUvRight]->PUv0);
+00813                                 // If transition tile, compute alpha UV in UV1.
+00814                                 // Do it also for Additive, because may have Transition
+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                 // UVs are computed, may create and fill VB.
+00824                 checkCreateFillTileVB(IdUvLeft);
+00825                 checkCreateFillTileVB(IdUvRight);
+00826         }
+00827 
+00828 }
+00829 // ***************************************************************************
+00830 void    CTessFace::releaseTileMaterial()
+00831 {
+00832         // Hence, must release the tile. TileUvBase is differnet for each of leaves.
+00833         deleteTileUv(IdUvBase);
+00834 
+00835         nlassert(!FBase || FBase->Level<=Patch->TileLimitLevel);
+00836         if(FBase && FBase->Level==Patch->TileLimitLevel && FBase->TileMaterial!=NULL)
+00837         {
+00838                 // Do not release Uvs, since neighbor need it...
+00839                 // But release faces.
+00840                 deleteTileFaces();
+00841                 // Do not release TileMaterial, since neighbor need it...
+00842                 TileMaterial= NULL;
+00843         }
+00844         else
+00845         {
+00846                 // release Uvs.
+00847                 deleteTileUv(IdUvLeft);
+00848                 deleteTileUv(IdUvRight);
+00849 
+00850                 // After, release Tile faces.
+00851                 deleteTileFaces();
+00852 
+00853                 // Release the tile lightmap part. Do it before removeTileMaterialFromRenderList().
+00854                 Patch->releaseTileLightMap(TileMaterial->TileS, TileMaterial->TileT);
+00855 
+00856                 // Remove this material from the render list. DO it before deletion of course :).
+00857                 // NB: TileS/TileT still valid.
+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         // Update VB for far vertices (if needed)
+00882         Patch->checkFillVertexVBFar(FVBase);
+00883         Patch->checkFillVertexVBFar(FVLeft);
+00884         Patch->checkFillVertexVBFar(FVRight);
+00885 
+00886         // Near Vertices update (Src only).
+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                         // Update VB for near vertices (if needed)
+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         // Rectangular case: FBase must exist.
+00911         nlassert(f1);
+00912 
+00913         // In rectangular case, we split at the same time this and FBase (f0 and f1).
+00914 
+00915 
+00916         /*
+00917                 Tesselation is:
+00918         
+00919        lt                    rt        lt        top         rt
+00920                 ---------------------           ---------------------
+00921                 |----               |           |\        |\        |
+00922                 |    ----      f1   |           |  \  f1l |  \  f1r |
+00923                 |        ----       |    -->    |    \    |    \    |
+00924                 |   f0       ----   |           | f0r  \  | f0l  \  |
+00925                 |                ---|           |        \|        \|
+00926                 ---------------------           ---------------------
+00927            lb                    rb        lb        bot         rb
+00928 
+00929                 Why? For symetry and bind/split reasons: FBase->SonLeft->VBase is always the good vertex to take 
+00930                 (see vertex binding).
+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         // 1. create new vertices.
+00948         //------------------------
+00949 
+00950         // Create splitted vertices.
+00951         CParamCoord             pctop(f1->PVBase, f1->PVLeft);
+00952         CParamCoord             pcbot(f0->PVBase, f0->PVLeft);
+00953         CTessVertex             *vtop= NULL;
+00954         CTessVertex             *vbot= NULL;
+00955         // Compute top.
+00956         if(f1->FLeft==NULL || f1->FLeft->isLeaf())
+00957         {
+00958                 // The base neighbor is a leaf or NULL. So must create the new vertex.
+00959                 vtop= Patch->getLandscape()->newTessVertex();
+00960 
+00961                 // Compute pos.
+00962                 vtop->StartPos= (f1->VLeft->EndPos + f1->VBase->EndPos)/2;
+00963                 vtop->EndPos= f1->Patch->computeVertex(pctop.getS(), pctop.getT());
+00964                 // Init Pos= InitialPos. Important in the case of enforced split.
+00965                 vtop->Pos= vtop->StartPos;
+00966 
+00967                 // For geomorph (VertexProgram or soft), compute MaxFaceSize and MaxNearLimit.
+00968                 vtop->MaxFaceSize= f1->Size;
+00969                 vtop->MaxNearLimit= f1->computeNearLimit();
+00970         }
+00971         else
+00972         {
+00973                 // Else, get from neighbor.
+00974                 // NB: since *FLeft is not a leaf, FBase->SonLeft!=NULL...
+00975                 // NB: this work with both rectangular and square triangles.
+00976                 vtop= f1->FLeft->SonLeft->VBase;
+00977 
+00978                 // For geomorph (VertexProgram or soft), compute MaxFaceSize and MaxNearLimit.
+00979                 vtop->MaxFaceSize= max( vtop->MaxFaceSize, f1->Size);
+00980                 vtop->MaxNearLimit= max( vtop->MaxNearLimit, f1->computeNearLimit());
+00981         }
+00982         // Compute bot.
+00983         if(f0->FLeft==NULL || f0->FLeft->isLeaf())
+00984         {
+00985                 // The base neighbor is a leaf or NULL. So must create the new vertex.
+00986                 vbot= Patch->getLandscape()->newTessVertex();
+00987 
+00988                 // Compute pos.
+00989                 vbot->StartPos= (f0->VLeft->EndPos + f0->VBase->EndPos)/2;
+00990                 vbot->EndPos= Patch->computeVertex(pcbot.getS(), pcbot.getT());
+00991                 // Init Pos= InitialPos. Important in the case of enforced split.
+00992                 vbot->Pos= vbot->StartPos;
+00993 
+00994                 // For geomorph (VertexProgram or soft), compute MaxFaceSize and MaxNearLimit.
+00995                 vbot->MaxFaceSize= f0->Size;
+00996                 vbot->MaxNearLimit= f0->computeNearLimit();
+00997         }
+00998         else
+00999         {
+01000                 // Else, get from neighbor.
+01001                 // NB: since *FLeft is not a leaf, FBase->SonLeft!=NULL...
+01002                 // NB: this work with both rectangular and square triangles.
+01003                 vbot= f0->FLeft->SonLeft->VBase;
+01004 
+01005                 // For geomorph (VertexProgram or soft), compute MaxFaceSize and MaxNearLimit.
+01006                 vbot->MaxFaceSize= max( vbot->MaxFaceSize, f0->Size);
+01007                 vbot->MaxNearLimit= max( vbot->MaxNearLimit, f0->computeNearLimit());
+01008         }
+01009 
+01010         // In all case, must create new FarVertices, since rect split occurs on border!!
+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         // May Allocate/Fill VB.
+01020         // NB: vtop / vbot are well computed  and ready for the fill in VB.
+01021         Patch->checkCreateVertexVBFar(farvtop);
+01022         Patch->checkFillVertexVBFar(farvtop);
+01023         Patch->checkCreateVertexVBFar(farvbot);
+01024         Patch->checkFillVertexVBFar(farvbot);
+01025 
+01026         // For VertexProgram only, must refill the Far vertex of neighbor(s), 
+01027         // because MaxFaceSize, and MaxNearLimit may have change.
+01028         if( CLandscapeGlobals::VertexProgramEnabled )
+01029         {
+01030                 // f0
+01031                 if( ! (f0->FLeft==NULL || f0->FLeft->isLeaf()) )
+01032                         f0->FLeft->Patch->checkFillVertexVBFar(f0->FLeft->SonLeft->FVBase);
+01033                 // f1
+01034                 if( ! (f1->FLeft==NULL || f1->FLeft->isLeaf()) )
+01035                         f1->FLeft->Patch->checkFillVertexVBFar(f1->FLeft->SonLeft->FVBase);
+01036         }
+01037 
+01038         
+01039         // 2. Create sons, and update links.
+01040         //----------------------------------
+01041 
+01042         CTessFace       *f0l, *f0r;
+01043         CTessFace       *f1l, *f1r;
+01044 
+01045         // create and bind Sons.
+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         // subdivision left.
+01052         f0l->Patch= f0->Patch;
+01053         f0l->Father= f0;
+01054         f0l->Level= f0->Level+1;
+01055         f0l->Size= f0->Size*0.5f;
+01056         // subdivision right.
+01057         f0r->Patch= f0->Patch;
+01058         f0r->Father= f0;
+01059         f0r->Level= f0->Level+1;
+01060         f0r->Size= f0->Size*0.5f;
+01061         // subdivision left.
+01062         f1l->Patch= f1->Patch;
+01063         f1l->Father= f1;
+01064         f1l->Level= f1->Level+1;
+01065         f1l->Size= f1->Size*0.5f;
+01066         // subdivision right.
+01067         f1r->Patch= f1->Patch;
+01068         f1r->Father= f1;
+01069         f1r->Level= f1->Level+1;
+01070         f1r->Size= f1->Size*0.5f;
+01071 
+01072         // Patch coordinates.
+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         // link existing vertex.
+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         // link Far vertices.
+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         // link neigbhor faces.
+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         // 4 links (all FLeft sons ) are stil invalid here.
+01131         f0l->FLeft= NULL;
+01132         f0r->FLeft= NULL;
+01133         f1l->FLeft= NULL;
+01134         f1r->FLeft= NULL;
+01135 
+01136         // Neigbors pointers of undetermined splitted face are not changed. Must Doesn't change this. 
+01137         // Used and Updated in section 5. ...
+01138 
+01139 
+01140         // 3. Update Tile infos.
+01141         //----------------------
+01142         // There is no update tileinfo with rectangular patch, since tiles are always squares. (TileLimitLevel>SquareLimitLevel).
+01143 
+01144         // NB: but must test update of tile info for neighboring, ie 2 faces around the splits.
+01145         // For Vertex program only
+01146         if( CLandscapeGlobals::VertexProgramEnabled )
+01147         {
+01148                 // if neighbor face splitted, and if 2 different patchs, we must update the Tile vertices
+01149                 // because MaxFaceSize and MaxNearLimit may have changed.
+01150                 if( f0->FLeft!=NULL && !f0->FLeft->isLeaf() && f0->FLeft->Patch!=Patch )
+01151                 {
+01152                         // If neighbors sons at tile level, must update their Tile vertices.
+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                 // idem for f1.
+01160                 if( f1->FLeft!=NULL && !f1->FLeft->isLeaf() && f1->FLeft->Patch!=Patch )
+01161                 {
+01162                         // If neighbors sons at tile level, must update their Tile vertices.
+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         // 4. Compute centers.
+01173         //--------------------
+01174         f0r->computeSplitPoint();
+01175         f0l->computeSplitPoint();
+01176         f1r->computeSplitPoint();
+01177         f1l->computeSplitPoint();
+01178 
+01179 
+01180         // 5. Propagate, or link sons of base.
+01181         //------------------------------------
+01182         for(sint i=0;i<2;i++)
+01183         {
+01184                 CTessFace       *f, *fl, *fr;
+01185                 // TOP face.
+01186                 if(i==0)
+01187                 {
+01188                         f= f1;
+01189                         fl= f1l;
+01190                         fr= f1r;
+01191                 }
+01192                 // then BOT face.
+01193                 else
+01194                 {
+01195                         f= f0;
+01196                         fl= f0l;
+01197                         fr= f0r;
+01198                 }
+01199 
+01200                 // If current face and FBase has sons, just links.
+01201                 if(f->FLeft==NULL)
+01202                 {
+01203                         // Just update sons neighbors.
+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                         // Cross connection of sons.
+01213                         if( !f->FLeft->isRectangular() )
+01214                         {
+01215                                 // Case neigbhor is square.
+01216                                 fl->FLeft= toLeft;
+01217                                 fr->FLeft= toRight;
+01218                                 toLeft->FRight= fl;
+01219                                 toRight->FLeft= fr;
+01220                         }
+01221                         else
+01222                         {
+01223                                 // Case neigbhor is rectangle.
+01224                                 fl->FLeft= toRight;
+01225                                 fr->FLeft= toLeft;
+01226                                 toLeft->FLeft= fr;
+01227                                 toRight->FLeft= fl;
+01228                         }
+01229                 }
+01230                 else if (propagateSplit)
+01231                 {
+01232                         // Warning: at each iteration, the pointer of FLeft may change (because of split() which can change the neighbor 
+01233                         // and so f).
+01234                         while(f->FLeft->isLeaf())
+01235                                 f->FLeft->split();
+01236 
+01237                         // There is a possible bug here (maybe easily patched). Sons may have be propagated splitted.
+01238                         // And problems may arise because this face hasn't yet good connectivity (especially for rectangles!! :) ).
+01239                         nlassert(fl->isLeaf() && fr->isLeaf());
+01240                 }
+01241         }
+01242 
+01243         
+01244         // 6. Must remove father from rdr list, and insert sons.
+01245         //------------------------------------------------------
+01246         // UGLY REFCOUNT SIDE EFFECT: do the append first.
+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         // 7. Update priority list.
+01256         //------------------------------------------------------
+01257         // Since we are freshly splitted, unlink from any list, and link to the MergePriorityList, because must look 
+01258         // now when should merge.
+01259         Patch->getLandscape()->_MergePriorityList.insert(0, 0, f0);
+01260         Patch->getLandscape()->_MergePriorityList.insert(0, 0, f1);
+01261 
+01262         // Since we are split, no need to test father for merge, because it cannot!
+01263         if(f0->Father)
+01264         {
+01265                 // remove father from any priority list.
+01266                 f0->Father->unlinkInPList();
+01267         }
+01268         if(f1->Father)
+01269         {
+01270                 // remove father from any priority list.
+01271                 f1->Father->unlinkInPList();
+01272         }
+01273 
+01274 }
+01275 
+01276 
+01277 // ***************************************************************************
+01278 void            CTessFace::split(bool propagateSplit)
+01279 {
+01280 
+01281         // 0. Some easy ending.
+01282         //---------------------
+01283         // Already splitted??
+01284         if(!isLeaf())
+01285                 return;
+01286         // Don't do this!!!
+01287         //if(Level>=LS_MAXLEVEL)
+01288         //      return;
+01289         // since split() may reach LS_MAXLEVEL, but enforce splits which outpass this stage!!
+01290 
+01291         NL3D_PROFILE_LAND_ADD(ProfNSplits, 1);
+01292 
+01293 
+01294         // Special Rectangular case.
+01295         if(isRectangular())
+01296         {
+01297                 splitRectangular(propagateSplit);
+01298                 return;
+01299         }
+01300 
+01301         // 1. Create sons, and update links.
+01302         //----------------------------------
+01303 
+01304         // create and bind Sons.
+01305         SonLeft= Patch->getLandscape()->newTessFace();
+01306         SonRight= Patch->getLandscape()->newTessFace();
+01307 
+01308         // subdivision left.
+01309         SonLeft->Patch= Patch;
+01310         SonLeft->Father= this;
+01311         SonLeft->Level= Level+1;
+01312         SonLeft->Size= Size*0.5f;
+01313         // subdivision right.
+01314         SonRight->Patch= Patch;
+01315         SonRight->Father= this;
+01316         SonRight->Level= Level+1;
+01317         SonRight->Size= Size*0.5f;
+01318 
+01319 
+01320         // link Left Son.
+01321         // link neighbor face.
+01322         SonLeft->FBase= FLeft;
+01323         if(FLeft)       FLeft->changeNeighbor(this, SonLeft);
+01324         SonLeft->FLeft= SonRight;
+01325         SonLeft->FRight= NULL;          // Temporary. updated later.
+01326         // link neighbor vertex.
+01327         SonLeft->VLeft= VBase;
+01328         SonLeft->VRight= VLeft;
+01329         // link neighbor Far vertex.
+01330         SonLeft->FVLeft= FVBase;
+01331         SonLeft->FVRight= FVLeft;
+01332         // Patch coordinates.
+01333         SonLeft->PVBase= CParamCoord(PVLeft, PVRight);
+01334         SonLeft->PVLeft= PVBase;
+01335         SonLeft->PVRight= PVLeft;
+01336 
+01337         // linkRight Son.
+01338         // link neighbor face.
+01339         SonRight->FBase= FRight;
+01340         if(FRight)      FRight->changeNeighbor(this, SonRight);
+01341         SonRight->FLeft= NULL;          // Temporary. updated later.
+01342         SonRight->FRight= SonLeft;
+01343         // link neighbor vertex.
+01344         SonRight->VLeft= VRight;
+01345         SonRight->VRight= VBase;
+01346         // link neighbor Far vertex.
+01347         SonRight->FVLeft= FVRight;
+01348         SonRight->FVRight= FVBase;
+01349         // Patch coordinates.
+01350         SonRight->PVBase= CParamCoord(PVLeft, PVRight);
+01351         SonRight->PVLeft= PVRight;
+01352         SonRight->PVRight= PVBase;
+01353 
+01354 
+01355         // FBase->FBase==this. Must Doesn't change this. Used and Updated in section 5. ...
+01356 
+01357 
+01358         // 2. Update/Create Vertex infos.
+01359         //-------------------------------
+01360 
+01361         // Must create/link *->VBase.
+01362         if(FBase==NULL || FBase->isLeaf())
+01363         {
+01364                 // The base neighbor is a leaf or NULL. So must create the new vertex.
+01365                 CTessVertex     *newVertex= Patch->getLandscape()->newTessVertex();
+01366                 SonRight->VBase= newVertex;
+01367                 SonLeft->VBase= newVertex;
+01368 
+01369                 // Compute pos.
+01370                 newVertex->StartPos= (VLeft->EndPos + VRight->EndPos)/2;
+01371                 newVertex->EndPos= Patch->computeVertex(SonLeft->PVBase.getS(), SonLeft->PVBase.getT());
+01372 
+01373                 // Init Pos= InitialPos. Important in the case of enforced split.
+01374                 newVertex->Pos= newVertex->StartPos;
+01375 
+01376                 // For geomorph (VertexProgram or soft), compute MaxFaceSize and MaxNearLimit.
+01377                 newVertex->MaxFaceSize= Size;
+01378                 newVertex->MaxNearLimit= computeNearLimit();
+01379         }
+01380         else
+01381         {
+01382                 // Else, get from neighbor.
+01383                 // NB: since *FBase is not a leaf, FBase->SonLeft!=NULL...
+01384                 // NB: this work with both rectangular and square triangles (see splitRectangular()).
+01385                 SonRight->VBase= FBase->SonLeft->VBase;
+01386                 SonLeft->VBase= FBase->SonLeft->VBase;
+01387 
+01388                 // For geomorph (VertexProgram or soft), compute MaxFaceSize and MaxNearLimit.
+01389                 SonLeft->VBase->MaxFaceSize= max( SonLeft->VBase->MaxFaceSize, Size);
+01390                 SonLeft->VBase->MaxNearLimit= max( SonLeft->VBase->MaxNearLimit, computeNearLimit());
+01391         }
+01392 
+01393 
+01394         // Must create/link *->FVBase.
+01395         // HERE, we must create a FarVertex too if the neighbor is not of the same patch as me.
+01396         if(FBase==NULL || FBase->isLeaf() || FBase->Patch!=Patch)
+01397         {
+01398                 // The base neighbor is a leaf or NULL. So must create the new far vertex.
+01399                 CTessFarVertex  *newFar= Patch->getLandscape()->newTessFarVertex();
+01400                 SonRight->FVBase= newFar;
+01401                 SonLeft->FVBase= newFar;
+01402 
+01403                 // Compute.
+01404                 newFar->Src= SonLeft->VBase;
+01405                 newFar->PCoord= SonLeft->PVBase;
+01406 
+01407                 // Append.
+01408                 Patch->appendFarVertexToRenderList(newFar);
+01409 
+01410                 // May Allocate/Fill VB.
+01411                 // NB: SonLeft->VBase->Pos is well computed and ready for the fill in VB.
+01412                 Patch->checkCreateVertexVBFar(newFar);
+01413                 Patch->checkFillVertexVBFar(newFar);
+01414 
+01415                 // For VertexProgram only, must refill the Far vertex of neighbor, 
+01416                 // because MaxFaceSize, and MaxNearLimit may have change.
+01417                 if( CLandscapeGlobals::VertexProgramEnabled && ! (FBase==NULL || FBase->isLeaf()) )
+01418                         FBase->Patch->checkFillVertexVBFar(FBase->SonLeft->FVBase);
+01419         }
+01420         else
+01421         {
+01422                 // Else, get from neighbor.
+01423                 // NB: since *FBase is not a leaf, FBase->SonLeft!=NULL...
+01424                 // NB: this work with both rectangular and square triangles (see splitRectangular()).
+01425                 SonRight->FVBase= FBase->SonLeft->FVBase;
+01426                 SonLeft->FVBase= FBase->SonLeft->FVBase;
+01427 
+01428                 // NB For VertexProgram only: no need to refill the Far vertex of neighbor, because neighbor is of same Patch
+01429                 // So MaxNearLimit and MaxFaceSize should be the same.
+01430         }
+01431 
+01432 
+01433         // 3. Update Tile infos.
+01434         //----------------------
+01435         // NB: must do it before appendFaceToRenderList().
+01436         // NB: must do it after compute of SonLeft->VBase->Pos for good filling in VBuffer.
+01437         // There is no problem with rectangular patch, since tiles are always squares.
+01438         // If new tile ....
+01439         if(SonLeft->Level==Patch->TileLimitLevel)
+01440         {
+01441                 SonLeft->computeTileMaterial();
+01442                 SonRight->computeTileMaterial();
+01443         }
+01444         // else Tile herit.
+01445         else if(SonLeft->Level > Patch->TileLimitLevel)
+01446         {
+01447                 heritTileMaterial();
+01448         }
+01449 
+01450         // For Vertex program only
+01451         if( CLandscapeGlobals::VertexProgramEnabled )
+01452         {
+01453                 // if neighbor face splitted, and if 2 different patchs, we must update the Tile vertices
+01454                 // because MaxFaceSize and MaxNearLimit may have changed.
+01455                 if( FBase!=NULL && !FBase->isLeaf() && FBase->Patch!=Patch )
+01456                 {
+01457                         // If neighbors sons at tile level, must update their Tile vertices.
+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         // 4. Compute centers.
+01468         //--------------------
+01469         SonRight->computeSplitPoint();
+01470         SonLeft->computeSplitPoint();
+01471 
+01472 
+01473         // 5. Propagate, or link sons of base.
+01474         //------------------------------------
+01475         // If current face and FBase has sons, just links.
+01476         if(FBase==NULL)
+01477         {
+01478                 // Just update sons neighbors.
+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                 // Cross connection of sons.
+01491                 if(!FBase->isRectangular())
+01492                 {
+01493                         // Case neigbhor is square.
+01494                         fl->FRight= toRight;
+01495                         fr->FLeft= toLeft;
+01496                         toLeft->FRight= fr;
+01497                         toRight->FLeft= fl;
+01498                 }
+01499                 else
+01500                 {
+01501                         // Case neigbhor is rectangular.
+01502                         fl->FRight= toLeft;
+01503                         fr->FLeft= toRight;
+01504                         toLeft->FLeft= fl;
+01505                         toRight->FLeft= fr;
+01506                 }
+01507         }
+01508         else if (propagateSplit)
+01509         {
+01510                 // Warning: at each iteration, the pointer of FBase may change (because of split() which can change the neighbor 
+01511                 // and so "this").
+01512                 while(FBase->isLeaf())
+01513                         FBase->split();
+01514 
+01515                 // There is a possible bug here (maybe easily patched). Sons may have be propagated splitted.
+01516                 // And problems may arise because this face hasn't yet good connectivity.
+01517                 nlassert(SonLeft->isLeaf() && SonRight->isLeaf());
+01518         }
+01519 
+01520 
+01521         // 6. Must remove father from rdr list, and insert sons.
+01522         //------------------------------------------------------
+01523         // UGLY REFCOUNT SIDE EFFECT: do the append first.
+01524         Patch->appendFaceToRenderList(SonLeft);
+01525         Patch->appendFaceToRenderList(SonRight);
+01526         Patch->removeFaceFromRenderList(this);
+01527 
+01528 
+01529         // 7. Update priority list.
+01530         //------------------------------------------------------
+01531         // Since we are freshly splitted, unlink from any list, and link to the MergePriorityList, because must look 
+01532         // now when should merge.
+01533         Patch->getLandscape()->_MergePriorityList.insert(0, 0, this);
+01534 
+01535         // Since we are split, no need to test father for merge, because it cannot!
+01536         if(Father)
+01537         {
+01538                 // remove father from any priority list.
+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         // Test diamond config (sons must be leaves).
+01552         if(!SonLeft->isLeaf())
+01553                 return false;
+01554         if(!SonRight->isLeaf())
+01555                 return false;
+01556         // If Errormetric must be considered for this test.
+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         // Then test neighbors.
+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                 // Rectangular case. May have a longer propagation...
+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         // Must not return false in preceding tests, because must set RecursMarkCanMerge to false.
+01592         RecursMarkCanMerge= false;
+01593 
+01594         return ok;
+01595 }
+01596 
+01597 
+01598 // ***************************************************************************
+01599 void            CTessFace::doMerge()
+01600 {
+01601         // Assume that canMerge() return true.
+01602         // And Assume that !isLeaf().
+01603         nlassert(!isLeaf());
+01604 
+01605         if(!isRectangular())
+01606         {
+01607                 // 1. Let's merge vertex.
+01608                 //-----------------------
+01609                 // Delete vertex, only if not already done by the neighbor (ie neighbor not already merged to a leaf).
+01610                 // NB: this work even if neigbor is rectnagular.
+01611                 if(!FBase || !FBase->isLeaf())
+01612                         Patch->getLandscape()->deleteTessVertex(SonLeft->VBase);
+01613 
+01614                 // Delete Far Vertex. Idem, but test too if != patch...
+01615                 if(!FBase || !FBase->isLeaf() || FBase->Patch!=Patch)
+01616                 {
+01617                         // May delete this vertex from VB.
+01618                         Patch->checkDeleteVertexVBFar(SonLeft->FVBase);
+01619 
+01620                         Patch->removeFarVertexFromRenderList(SonLeft->FVBase);
+01621                         Patch->getLandscape()->deleteTessFarVertex(SonLeft->FVBase);
+01622                 }
+01623 
+01624 
+01625                 // 2. Must remove sons from rdr list, and insert father.
+01626                 //------------------------------------------------------
+01627                 // Must do it BEFORE the TileFaces are released.
+01628                 // UGLY REFCOUNT SIDE EFFECT: do the append first.
+01629                 Patch->appendFaceToRenderList(this);
+01630                 Patch->removeFaceFromRenderList(SonLeft);
+01631                 Patch->removeFaceFromRenderList(SonRight);
+01632 
+01633                 
+01634                 // 3. Let's merge Uv.
+01635                 //-------------------
+01636                 // Delete Uv.
+01637                 // Must do it for this and FBase separately, since they may not have same tile level (if != patch).
+01638                 if(SonLeft->Level== Patch->TileLimitLevel)
+01639                 {
+01640                         // Square patch assumption: the sons are not of the same TileId/Patch.
+01641                         nlassert(!sameTile(SonLeft, SonRight));
+01642                         // release tiles: NearVertices, TileFaces, and TileMaterial.
+01643                         SonLeft->releaseTileMaterial();
+01644                         SonRight->releaseTileMaterial();
+01645                 }
+01646                 else if(SonLeft->Level > Patch->TileLimitLevel)
+01647                 {
+01648                         // Delete Uv, only if not already done by the neighbor (ie neighbor not already merged to a leaf).
+01649                         // But Always delete if neighbor exist and has not same tile as me.
+01650                         // NB: this work with rectangular neigbor patch, since sameTile() will return false if different patch.
+01651                         if(!FBase || !FBase->isLeaf() || !sameTile(this, FBase))
+01652                         {
+01653                                 SonLeft->deleteTileUv(IdUvBase);
+01654                         }
+01655                         // In all case, must delete the tilefaces of those face.
+01656                         SonLeft->deleteTileFaces();
+01657                         SonRight->deleteTileFaces();
+01658                 }
+01659 
+01660 
+01661                 // 4. Let's merge Face.
+01662                 //-------------------
+01663                 // Change father 's neighbor pointers.
+01664                 FLeft= SonLeft->FBase;
+01665                 if(FLeft)       FLeft->changeNeighbor(SonLeft, this);
+01666                 FRight= SonRight->FBase;
+01667                 if(FRight)      FRight->changeNeighbor(SonRight, this);
+01668                 // delete sons.
+01669                 Patch->getLandscape()->deleteTessFace(SonLeft);
+01670                 Patch->getLandscape()->deleteTessFace(SonRight);
+01671                 SonLeft=NULL;
+01672                 SonRight=NULL;
+01673 
+01674                 // If not already done, merge the neighbor.
+01675                 if(FBase!=NULL && !FBase->isLeaf())
+01676                 {
+01677                         FBase->doMerge();
+01678                 }
+01679 
+01680         }
+01681         else
+01682         {
+01683                 // Rectangular case.
+01684                 // Since minimum Order is 2, Sons of rectangular face are NEVER at TileLimitLevel. => no Uv merge to do.
+01685                 nlassert(SonLeft->Level< Patch->TileLimitLevel);
+01686                 nlassert(FBase);
+01687 
+01688                 // 1. Let's merge vertex.
+01689                 //-----------------------
+01690                 // Delete vertex, only if not already done by the neighbor (ie neighbor not already merged to a leaf).
+01691                 // NB: this work even if neigbor is rectangular (see tesselation rules in splitRectangular()).
+01692                 if(!FLeft || !FLeft->isLeaf())
+01693                         Patch->getLandscape()->deleteTessVertex(SonLeft->VBase);
+01694 
+01695                 // Delete Far Vertex. Rect patch: neightb must be of a != pathc as me => must delete FarVertex.
+01696                 nlassert(!FLeft || FLeft->Patch!=Patch);
+01697                 // May delete this vertex from VB.
+01698                 Patch->checkDeleteVertexVBFar(SonLeft->FVBase);
+01699 
+01700                 Patch->removeFarVertexFromRenderList(SonLeft->FVBase);
+01701                 Patch->getLandscape()->deleteTessFarVertex(SonLeft->FVBase);
+01702 
+01703 
+01704                 // 2. Must remove sons from rdr list, and insert father.
+01705                 //------------------------------------------------------
+01706                 // UGLY REFCOUNT SIDE EFFECT: do the append first.
+01707                 Patch->appendFaceToRenderList(this);
+01708                 Patch->removeFaceFromRenderList(SonLeft);
+01709                 Patch->removeFaceFromRenderList(SonRight);
+01710 
+01711 
+01712                 // 3. Let's merge Face.
+01713                 //-------------------
+01714                 // Change father 's neighbor pointers (see splitRectangular()).
+01715                 FRight= SonRight->FRight;
+01716                 if(FRight)      FRight->changeNeighbor(SonRight, this);
+01717                 // delete sons.
+01718                 Patch->getLandscape()->deleteTessFace(SonLeft);
+01719                 Patch->getLandscape()->deleteTessFace(SonRight);
+01720                 SonLeft=NULL;
+01721                 SonRight=NULL;
+01722 
+01723                 // First, do it for my rectangular co-worker FBase (if not already done).
+01724                 if(!FBase->isLeaf())
+01725                 {
+01726                         FBase->doMerge();
+01727                 }
+01728                 // If not already done, merge the neighbor.
+01729                 if(FLeft!=NULL && !FLeft->isLeaf())
+01730                 {
+01731                         FLeft->doMerge();
+01732                 }
+01733         }
+01734 
+01735 
+01736         // Update priority list.
+01737         //------------------------------------------------------
+01738         // Since we are freshly merged, unlink from any list, and link to the SplitPriorityList, because must look 
+01739         // now when we should split again.
+01740         Patch->getLandscape()->_SplitPriorityList.insert(0, 0, this);
+01741 
+01742         // since we are now merged maybe re-insert father in priority list.
+01743         if(Father)
+01744         {
+01745                 nlassert(!Father->isLeaf());
+01746                 // If sons of father are both leaves (ie this, and the other (complexe case if rectangle) )
+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         // Must not be a leaf.
+01760         nlassert(!isLeaf());
+01761 
+01762         // 0. Verify if merge is posible.
+01763         //----------------------------
+01764         if(!canMerge(false))
+01765                 return false;
+01766 
+01767         NL3D_PROFILE_LAND_ADD(ProfNMerges, 1);
+01768 
+01769         // 1. Let's merge the face.
+01770         //-----------------------
+01771         // Propagation is done in doMerge().
+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                 if(ps<RefineThreshold), the face must be merged (ie have no leaves).
+01785                 if(ps E [RefineThreshold, RefineTreshold*2]), the face must be splitted (ave leaves), and is geomorphed.
+01786                 if(ps>RefineThreshold*2), the face is fully splitted/geomoprhed (tests reported on sons...).
+01787         */
+01788 
+01789         // Test for Split or merge.
+01790         //-----------------------
+01791         {
+01792                 NL3D_PROFILE_LAND_ADD(ProfNRefineComputeFaces, 1);
+01793 
+01794                 updateErrorMetric();
+01795                 float   ps=ErrorMetric;
+01796                 ps*= CLandscapeGlobals::OORefineThreshold;
+01797                 // 1.0f is the point of split().
+01798                 // 2.0f is the end of geomorph.
+01799 
+01800 
+01801                 // Test split/merge.
+01802                 //---------------------
+01803                 // If wanted, not already done, and limit not reached, split().
+01804                 if(isLeaf())
+01805                 {
+01806                         if(ps>1.0f && Level< (Patch->TileLimitLevel + CLandscapeGlobals::TileMaxSubdivision) )
+01807                                 split();
+01808                 }
+01809                 else
+01810                 {
+01811                         // Else, if splitted, must merge (if not already the case).
+01812                         if(ps<1.0f)
+01813                         {
+01814                                 // Merge only if agree, and neighbors agree.
+01815                                 // canMerge() test all the good thing: FBase==CantMergeFace, or this is rectangular etc...
+01816                                 // The test is propagated to neighbors.
+01817                                 if(canMerge(true))
+01818                                 {
+01819                                         merge();
+01820                                 }
+01821                         }
+01822                 }
+01823         }
+01824 
+01825         // Recurs.
+01826         //-----------------------
+01827         if(SonLeft)
+01828         {
+01829                 SonLeft->refineAll();
+01830                 SonRight->refineAll();
+01831         }
+01832 
+01833 }
+01834 
+01835 
+01836 // ***************************************************************************
+01837 // Some updateRefine***() Doc:
+01838 
+01839 // Split or merge, and meaning of errorMetric:
+01840 /*
+01841         if(errorMetric<RefineThreshold), the face must be merged (ie have no leaves).
+01842         if(errorMetric E [RefineThreshold, RefineTreshold*2]), the face must be splitted (ave leaves), and is geomorphed.
+01843         if(errorMetric>RefineThreshold*2), the face is fully splitted/geomoprhed.
+01844 */
+01845 
+01846 
+01847 // Compute distNormalSplitMerge: distance from refineCenter to normal split/merge (ie without tile transition):
+01848 /* 
+01849         normal ErrorMetric formula is:
+01850                 em = Size*OORefineThreshold/ dist^2;    with dist == (SplitPoint - CLandscapeGlobals::RefineCenter).norm()
+01851         So inverse this function and we have:
+01852                 dist= sqrt(Size*OORefineThreshold/em).
+01853         Split or merge is when em==1, so 
+01854                 distSplitMerge= sqrt(Size*OORefineThreshold)
+01855 */
+01856 
+01857 
+01858 // Compute distTileTransSplitMerge.
+01859 /* When we are sure that CLandscapeGlobals::TileDistNear < distMinFace < CLandscapeGlobals::TileDistFar, 
+01860         the clamp in the original formula is skipped
+01861         
+01862         So the TileErrorMetric formula is:
+01863 
+01864         {
+01865                 ema= Sife*OORefineThreshold / distSP^2.
+01866                 f= (TileDistFar^2 - distMinFace^2) * OOTileDeltaDist^2
+01867                 f= f ^ 4.               // no clamp. see above.
+01868                 emb= NL*f + ema*(1-f)
+01869                 emFinal= max(ema, emb).
+01870         }
+01871 
+01872         The problem is that the formula is too complex (degree 8 equation). 
+01873         So search for the result recursively.
+01874 */
+01875 
+01876 
+01877 // Quadrant Selection
+01878 /*
+01879         Quadrant/Direction is interesting for updateRefineSplit() only.
+01880         In the 2 most simples cases, the action we want is "Know when we enters in a bounding volume"
+01881         This fit well for Quadrant notion.
+01882 
+01883         In the case "TileDistNear to TileDistFar", the rule is too complicated and there is also
+01884         the notion of "Know when we LEAVE the TileDistFar sphere around the face" which is incompatible
+01885         with Quadrant behavior (since can go in any direction to leave the sphere).
+01886 
+01887         updateRefineMerge() are at least all notion of "Know when we LEAVE the SplitSphere around the SplitPoint"
+01888         which is incompatible with Quadrant behavior.
+01889         This is why updateRefineMerge() don't bother at all quadrant, and so the _MergePriorityList is inited with 0
+01890         quadrants.
+01891 
+01892 */
+01893 
+01894 // ***************************************************************************
+01895 void            CTessFace::updateRefineSplit()
+01896 {
+01897         NL3D_PROFILE_LAND_ADD(ProfNRefineFaces, 1);
+01898 
+01899         nlassert(Patch);
+01900         // The face must be not splitted, because tested for split.
+01901         nlassert(isLeaf());
+01902 
+01903         /*
+01904                 NB: see above for some updateRefine*** doc.
+01905         */
+01906 
+01907         // Test for Split.
+01908         //-----------------------
+01909         bool    splitted= false;
+01910         {
+01911                 updateErrorMetric();
+01912                 float   ps=ErrorMetric;
+01913                 ps*= CLandscapeGlobals::OORefineThreshold;
+01914                 // 1.0f is the point of split().
+01915                 // 2.0f is the end of geomorph.
+01916 
+01917 
+01918                 // Test split.
+01919                 //---------------------
+01920                 // If wanted and limit not reached, split().
+01921                 if(ps>1.0f && Level< (Patch->TileLimitLevel + CLandscapeGlobals::TileMaxSubdivision) )
+01922                 {
+01923                         split();
+01924 
+01925                         // if split ok
+01926                         if(!isLeaf())
+01927                         {
+01928                                 splitted= true;
+01929                         }
+01930                 }
+01931         }
+01932 
+01933 
+01934         // Insert the face in the priority list.
+01935         //-----------------------
+01936         // If splitted, then insertion in Landscape->MergePriorityList at 0 has been done. so nothing to update.
+01937         // Else, must compute when whe should re-test.
+01938         if(!splitted)
+01939         {
+01940                 // the face is not splitted here.
+01941                 nlassert(isLeaf());
+01942 
+01943                 float   minDeltaDistToUpdate;
+01944 
+01945                 // by default insert in the quadrant-less rolling table.
+01946                 uint    quadrantId= 0;
+01947 
+01948 
+01949                 CVector         dirToSplitPoint= SplitPoint - CLandscapeGlobals::RefineCenter;
+01950                 // The distance of SplitPoint to center.
+01951                 float           distSplitPoint= dirToSplitPoint.norm();
+01952                 // The distance where we should split/merge. see updateRefin() doc.
+01953                 float           distNormalSplitMerge= (float)sqrt(Size*CLandscapeGlobals::OORefineThreshold);
+01954 
+01955 
+01956                 // If the face is at its max subdivision
+01957                 if(Level>=Patch->TileLimitLevel+CLandscapeGlobals::TileMaxSubdivision)
+01958                 {
+01959                         // special case: the face do not need to be tested for splitting, because Max subdivision reached.
+01960                         // Hence just unlink from any list, and return.
+01961                         unlinkInPList();
+01962                         return;
+01963                 }
+01964                 else if(Level>=Patch->TileLimitLevel)
+01965                 {
+01966                         // Always normal ErrorMetric. Because Faces at Tile level decide to split or merge their sons independently 
+01967                         // of "Tile ErrorMetric".
+01968 
+01969                         // The test is "when do we enter in the Split area?", so we can use Quadrant PriorityList
+01970                         quadrantId= Patch->getLandscape()->_SplitPriorityList.selectQuadrant(dirToSplitPoint);
+01971 
+01972                         // compute distance to split as default "No Quadrant"
+01973                         minDeltaDistToUpdate= distSplitPoint - distNormalSplitMerge;
+01974 
+01975                         // If a quadrant is  selected, try to use it
+01976                         if(quadrantId>0)
+01977                         {
+01978                                 const CVector   &quadrantDir= Patch->getLandscape()->_SplitPriorityList.getQuadrantDirection(quadrantId);
+01979 
+01980                                 // We must not approach the SplitPoint at distNormalSplitMerge
+01981                                 float   dMin= quadrantDir*dirToSplitPoint - distNormalSplitMerge;
+01982 
+01983                                 // If the dist with quadrant is too small then use the std way (without quadrant).
+01984                                 if( dMin<NL3D_TESS_USE_QUADRANT_THRESHOLD )
+01985                                         quadrantId= 0;
+01986                                 // else ok, use quadrant behavior
+01987                                 else
+01988                                         minDeltaDistToUpdate= dMin;
+01989                         }
+01990                 }
+01991                 else
+01992                 {
+01993                         // Compute Distance of the face from RefineCenter. It is the min of the 3 points, as in computeTileErrorMetric().
+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                         // compute the delta distance to the normal split point. See above for doc.
+02003                         float   normalEMDeltaDist;
+02004                         normalEMDeltaDist= distSplitPoint - distNormalSplitMerge;
+02005 
+02006 
+02007                         /* 
+02008                         There is 3 possibles cases, according to level, and the distances minFaceDist:
+02009                         */
+02011                         if( distMinFace > CLandscapeGlobals::TileDistFar )
+02012                         {
+02013                                 // The test is "when do we enter in the Split area OR in TileDistFar area?", so we can use Quadrant PriorityList
+02014                                 quadrantId= Patch->getLandscape()->_SplitPriorityList.selectQuadrant(dirToSplitPoint);
+02015 
+02016                                 // compute deltaDist as default "Direction less quadrant"
+02017                                 minDeltaDistToUpdate= normalEMDeltaDist;
+02018                                 // We must know when we enter in TileErrorMetric zone, because the computing is different.
+02019                                 minDeltaDistToUpdate= min(minDeltaDistToUpdate, distMinFace - CLandscapeGlobals::TileDistFar);
+02020 
+02021                                 // try with quadrant if > 0.
+02022                                 if(quadrantId>0)                                
+02023                                 {
+02024                                         const CVector   &quadrantDir= Patch->getLandscape()->_SplitPriorityList.getQuadrantDirection(quadrantId);
+02025 
+02026                                         // We must not approach the SplitPoint at distNormalSplitMerge
+02027                                         float   dMin= quadrantDir*dirToSplitPoint - distNormalSplitMerge;
+02028                                         // and we must not reach one of the 3 sphere (Vi, TileDistFar).
+02029                                         float   d0 = quadrantDir*dirToV0 - CLandscapeGlobals::TileDistFar;
+02030                                         float   d1 = quadrantDir*dirToV1 - CLandscapeGlobals::TileDistFar;
+02031                                         float   d2 = quadrantDir*dirToV2 - CLandscapeGlobals::TileDistFar;
+02032                                         // take min dist
+02033                                         dMin= minof(dMin, d0, d1, d2);
+02034 
+02035                                         // If the dist with quadrant is too small then use the std way (without quadrant).
+02036                                         if( dMin<NL3D_TESS_USE_QUADRANT_THRESHOLD )
+02037                                                 quadrantId= 0;
+02038                                         // else ok, use quadrant behavior
+02039                                         else
+02040                                                 minDeltaDistToUpdate= dMin;
+02041                                 }
+02042                         }
+02044                         else if( distMinFace > CLandscapeGlobals::TileDistNear )
+02045                         {
+02046                                 // NB: can't use quadrant behavior here. Leave quadrantId at 0.
+02047 
+02048                                 // Profile
+02049                                 NL3D_PROFILE_LAND_ADD(ProfNRefineInTileTransition, 1);
+02050 
+02051                                 // Compute distance to split/Merge in TileTransition
+02052                                 float   distTileTransSplitMerge;
+02053                                 float   maxDeltaDist= 8;
+02054                                 float   minDeltaDist= 0;
+02055                                 uint    nbRecurs= 6;
+02056                                 float   nearLimit;
+02057                                 nearLimit= CLandscapeGlobals::RefineThreshold * computeNearLimit();
+02058                                 // search the distance to split recursively.
+02059                                 for(uint i=0; i< nbRecurs; i++)
+02060                                 {
+02061                                         float   pivotDeltaDist= (maxDeltaDist-minDeltaDist)/2;
+02062                                         // If the em computed with this distance is still <1 (ie merged), then we can move further.
+02063                                         if ( computeTileEMForUpdateRefine(distSplitPoint-pivotDeltaDist, distMinFace-pivotDeltaDist, nearLimit ) < 1)
+02064                                                 minDeltaDist= pivotDeltaDist;
+02065                                         // else we must move not as far
+02066                                         else
+02067                                                 maxDeltaDist= pivotDeltaDist;
+02068                                 }
+02069                                 // And so take the minimum resulting delta distance
+02070                                 distTileTransSplitMerge= minDeltaDist;
+02071                                 
+02072                                 // take the min with distance of distMinFace to the TileDistNear and TileDistFar sphere, because formula change at
+02073                                 // those limits.
+02074                                 minDeltaDistToUpdate= min(distTileTransSplitMerge, CLandscapeGlobals::TileDistFar - distMinFace );
+02075                                 minDeltaDistToUpdate= min(minDeltaDistToUpdate, distMinFace - CLandscapeGlobals::TileDistNear);
+02076                         }
+02078                         else
+02079                         {
+02080                                 // because the face is not a Tile Level (ie Level<Patch->TileLimitLevel), it should be splitted, 
+02081                                 // and won't merge until reaching at least the TileDistNear sphere.
+02082                                 // if not splited (should not arise), force the split next time.
+02083                                 minDeltaDistToUpdate= 0;
+02084                         }
+02085 
+02086                 }
+02087 
+02088                 // Profile.
+02089                 if(minDeltaDistToUpdate<0.0625)
+02090                 {
+02091                         NL3D_PROFILE_LAND_ADD(ProfNRefineWithLowDistance, 1);
+02092                 }
+02093 
+02094 
+02095                 // insert in the Split priority list.
+02096                 // Until the RefineCenter move under minDeltaDistToUpdate, we don't need to test face.
+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         // The face must be splitted, because tested for merge.
+02109         nlassert(!isLeaf());
+02110 
+02111         /*
+02112                 NB: see above for some updateRefine*** doc.
+02113         */
+02114 
+02115         // Test for merge.
+02116         //-----------------------
+02117         bool    merged= false;
+02118         {
+02119                 updateErrorMetric();
+02120                 float   ps=ErrorMetric;
+02121                 ps*= CLandscapeGlobals::OORefineThreshold;
+02122                 // 1.0f is the point of split().
+02123                 // 2.0f is the end of geomorph.
+02124 
+02125 
+02126                 // Test merge.
+02127                 //---------------------
+02128                 // Else, must merge ??
+02129                 if(ps<1.0f)
+02130                 {
+02131                         // Merge only if agree, and neighbors agree.
+02132                         // canMerge() test all the good thing: FBase==CantMergeFace, or this is rectangular etc...
+02133                         // The test is propagated to neighbors.
+02134                         if(canMerge(true))
+02135                         {
+02136                                 merge();
+02137 
+02138                                 // NB: here, merge() is not propagated to fathers (supposed to be not very usefull).
+02139 
+02140                                 if(isLeaf())
+02141                                 {
+02142                                         merged= true;
+02143                                 }
+02144                         }
+02145                 }
+02146         }
+02147 
+02148 
+02149         // Insert the face in the priority list.
+02150         //-----------------------
+02151         // If merged, then insertion in Landscape->SplitPriorityList at 0 has been done. so nothing to update.
+02152         // Else, must compute when whe should re-test.
+02153         if(!merged)
+02154         {
+02155                 // the face is splitted here.
+02156                 nlassert(!isLeaf());
+02157 
+02158                 float   minDeltaDistToUpdate;
+02159 
+02160 
+02161                 // The distance of SplitPoint to center.
+02162                 float   distSplitPoint= (SplitPoint - CLandscapeGlobals::RefineCenter).norm();
+02163                 // Compute distance from refineCenter to normal split/merge (ie without tile transition).
+02164                 float   distNormalSplitMerge= (float)sqrt(Size*CLandscapeGlobals::OORefineThreshold);
+02165 
+02166 
+02167                 // If the face is at its max subdivision
+02168                 if(Level>=Patch->TileLimitLevel+CLandscapeGlobals::TileMaxSubdivision)
+02169                 {
+02170                         // since the face is splitted, then must test always this face, because we must merge it (as soon as it is possible).
+02171                         minDeltaDistToUpdate= 0;
+02172                 }
+02173                 else if(Level>=Patch->TileLimitLevel)
+02174                 {
+02175                         // Always normal ErrorMetric. Because Faces at Tile level decide to split or merge their sons independently 
+02176                         // of "Tile ErrorMetric".
+02177                         // since splitted, compute distance to merge.
+02178                         minDeltaDistToUpdate= distNormalSplitMerge - distSplitPoint;
+02179                         // NB: it is possible that minDeltaDistToUpdate<0. A good example is when we are enforced split.
+02180                         // Then, distSplitMerge may be < distSplitPoint, meaning we should have not split, but a neigbhor has enforced us.
+02181                         // So now, must test every frame if we can merge....
+02182                         minDeltaDistToUpdate= max( 0.f, minDeltaDistToUpdate );
+02183                 }
+02184                 else
+02185                 {
+02186                         // Compute Distance of the face from RefineCenter. It is the min of the 3 points, as in computeTileErrorMetric().
+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                         // compute the delta distance to the normal split point. See above for doc.
+02193                         float   normalEMDeltaDist;
+02194                         normalEMDeltaDist= distNormalSplitMerge - distSplitPoint;
+02195                         normalEMDeltaDist= max( 0.f, normalEMDeltaDist );
+02196 
+02197 
+02198                         /* 
+02199                         There is 3 possibles cases, according to level, and the distances minFaceDist:
+02200                         */
+02202                         if( distMinFace > CLandscapeGlobals::TileDistFar )
+02203                         {
+02204                                 // normal geomorph. Any face compute the distance to the SplitPoint, and take min with distance to
+02205                                 // the TileDistFar sphere. 
+02206                                 minDeltaDistToUpdate= normalEMDeltaDist;
+02207 
+02208                                 // We must know when we enter in TileErrorMetric zone, because the computing is different.
+02209                                 minDeltaDistToUpdate= min(minDeltaDistToUpdate, distMinFace - CLandscapeGlobals::TileDistFar);
+02210                         }
+02212                         else if( distMinFace > CLandscapeGlobals::TileDistNear )
+02213                         {
+02214                                 // Profile
+02215                                 NL3D_PROFILE_LAND_ADD(ProfNRefineInTileTransition, 1);
+02216 
+02217 
+02218                                 // Compute distance to split/Merge in TileTransition
+02219                                 float   distTileTransSplitMerge;
+02220                                 float   maxDeltaDist= 8;
+02221                                 float   minDeltaDist= 0;
+02222                                 uint    nbRecurs= 6;
+02223                                 float   nearLimit;
+02224                                 nearLimit= CLandscapeGlobals::RefineThreshold * computeNearLimit();
+02225                                 // Since splitted, compute distance to merge.
+02226                                 // search the distance recursively.
+02227                                 for(uint i=0; i< nbRecurs; i++)
+02228                                 {
+02229                                         float   pivotDeltaDist= (maxDeltaDist-minDeltaDist)/2;
+02230                                         // If the em computed with this distance is still >1 (ie splitted), then we can move further.
+02231                                         if ( computeTileEMForUpdateRefine(distSplitPoint+pivotDeltaDist, distMinFace+pivotDeltaDist, nearLimit ) > 1)
+02232                                                 minDeltaDist= pivotDeltaDist;
+02233                                         // else we must move not as far
+02234                                         else
+02235                                                 maxDeltaDist= pivotDeltaDist;
+02236                                 }
+02237                                 // And so take the minimum resulting delta distance
+02238                                 distTileTransSplitMerge= minDeltaDist;
+02239                                 
+02240                                 // take the min with distance of distMinFace to the TileDistNear and TileDistFar sphere, because formula change at
+02241                                 // those limits.
+02242                                 minDeltaDistToUpdate= min(distTileTransSplitMerge, CLandscapeGlobals::TileDistFar - distMinFace );
+02243                                 minDeltaDistToUpdate= min(minDeltaDistToUpdate, distMinFace - CLandscapeGlobals::TileDistNear);
+02244                         }
+02246                         else
+02247                         {
+02248                                 // because the face is not a Tile Level (ie Level<Patch->TileLimitLevel), it should be splitted, 
+02249                                 // and won't merge until reaching at least the TileDistNear sphere.
+02250                                 // Since splitted, Must enter in TileErrorMetric area to know when to merge.
+02251                                 minDeltaDistToUpdate= CLandscapeGlobals::TileDistNear - distMinFace;
+02252                         }
+02253 
+02254                 }
+02255 
+02256                 // Merge Refine Threshold: because of enforced splits, we have lot of faces whit minDeltaDistToUpdate<0, because
+02257                 // they alwayas want to merge. To avoid this, add a delta, which delay the test for merge.
+02258                 // The caveat is that faces which do not need this may merge later. But 2 meters won't add too many faces.
+02259                 minDeltaDistToUpdate+= NL3D_REFINE_MERGE_THRESHOLD;
+02260 
+02261                 // insert in the Merge priority list.
+02262                 // Until the RefineCenter move under minDeltaDistToUpdate, we don't need to test face.
+02263                 Patch->getLandscape()->_MergePriorityList.insert(0, minDeltaDistToUpdate, this);
+02264         }
+02265 }
+02266 
+02267 
+02268 // ***************************************************************************
+02269 void            CTessFace::unbind()
+02270 {
+02271         // NB: since CantMergeFace has a NULL patch ptr, it is unbound too.
+02272 
+02273         // Square case.
+02274         //=============
+02275         if(!isRectangular())
+02276         {
+02277                 // Change Left/Right neighbors.
+02278                 if(isLeaf())
+02279                 {
+02280                         // FLeft and FRight pointers are only valid in Leaves nodes.
+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                 // Change Base neighbors.
+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                                 // Duplicate the VBase of sons, so the unbind is correct and no vertices are shared.
+02302                                 CTessVertex     *old= SonLeft->VBase;
+02303                                 SonLeft->VBase= Patch->getLandscape()->newTessVertex();
+02304                                 *(SonLeft->VBase)= *old;
+02305                                 SonRight->VBase= SonLeft->VBase;
+02306 
+02307                                 // For geomorph (VertexProgram or soft), compute good MaxFaceSize and MaxNearLimit (change since unbinded)
+02308                                 // update us.
+02309                                 SonLeft->VBase->MaxFaceSize= Size;
+02310                                 SonLeft->VBase->MaxNearLimit= computeNearLimit();
+02311                                 // update our neigbhor, only if not a multiple patch face.
+02312                                 if(oldNeigbhorFace->Patch)
+02313                                 {
+02314                                         old->MaxFaceSize= oldNeigbhorFace->Size;
+02315                                         old->MaxNearLimit= oldNeigbhorFace->computeNearLimit();
+02316                                 }
+02317                         }
+02318                 }
+02319         }
+02320         // Rectangular case.
+02321         //==================
+02322         else
+02323         {
+02324                 // Doens't need to test FBase, since must be same patch.
+02325                 // In rectangular, FLeft has the behavior of FBase in square case.
+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                                 // Duplicate the VBase of sons, so the unbind is correct and no vertices are shared.
+02335                                 // NB: this code is a bit different from square case.
+02336                                 CTessVertex     *old= SonLeft->VBase;
+02337                                 SonLeft->VBase= Patch->getLandscape()->newTessVertex();
+02338                                 *(SonLeft->VBase)= *old;
+02339                                 // This is the difference:  (see rectangle tesselation rules).
+02340                                 SonRight->VLeft= SonLeft->VBase;
+02341                                 // Yoyo_patch_himself (12/02/2001): I forgot this one!!
+02342                                 nlassert(FBase && FBase->SonLeft);
+02343                                 FBase->SonLeft->VRight= SonLeft->VBase;
+02344 
+02345 
+02346                                 // For geomorph (VertexProgram or soft), compute good MaxFaceSize and MaxNearLimit (change since unbinded)
+02347                                 // update us.
+02348                                 SonLeft->VBase->MaxFaceSize= Size;
+02349                                 SonLeft->VBase->MaxNearLimit= computeNearLimit();
+02350                                 // update our neigbhor, only if not a multiple patch face.
+02351                                 if(oldNeigbhorFace->Patch)
+02352                                 {
+02353                                         old->MaxFaceSize= oldNeigbhorFace->Size;
+02354                                         old->MaxNearLimit= oldNeigbhorFace->computeNearLimit();
+02355                                 }
+02356                         }
+02357                 }
+02358                 // But FRight still valid in leaves nodes only.
+02359                 if(isLeaf())
+02360                 {
+02361                         if(FRight && FRight->Patch!=Patch)
+02362                         {
+02363                                 FRight->changeNeighbor(this, NULL);
+02364                                 FRight= NULL;
+02365                         }
+02366                 }
+02367         }
+02368 
+02369         // Propagate unbind.
+02370         //==================
+02371         if(!isLeaf())
+02372         {
+02373                 // update sons vertex pointers (since they may have been updated by me or my grandfathers).
+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                         // Rectangular case. Update only ptrs which may have changed.
+02384                         SonLeft->VLeft= VLeft;
+02385                         SonRight->VBase= VBase;
+02386                         SonRight->VRight= VRight;
+02387                 }
+02388 
+02389                 // Must re-create good Vertex links for Far and Near Vertices!!!
+02390                 SonLeft->updateNearFarVertices();
+02391                 SonRight->updateNearFarVertices();
+02392                 if(isRectangular())
+02393                 {
+02394                         //NB: must do this for Base neighbor (see unbind() rectangular case...).
+02395                         nlassert(FBase && FBase->SonLeft && FBase->SonRight);
+02396                         FBase->SonLeft->updateNearFarVertices();
+02397                         FBase->SonRight->updateNearFarVertices();
+02398                 }
+02399 
+02400                 // unbind the sons.
+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                 // First, force merge of Sons and neighbor sons, to have a diamond configuration.
+02415                 SonLeft->forceMerge();
+02416                 SonRight->forceMerge();
+02417 
+02418                 // forceMerge of necessary neighbors.
+02419                 RecursMarkForceMerge=true;
+02420                 if(!isRectangular())
+02421                 {
+02422                         if(FBase && !FBase->RecursMarkForceMerge)
+02423                                 FBase->forceMerge();
+02424                 }
+02425                 else
+02426                 {
+02427                         // Rectangular case. May have a longer propagation...
+02428                         if(FBase && !FBase->RecursMarkForceMerge)
+02429                                 FBase->forceMerge();
+02430                         if(FLeft && !FLeft->RecursMarkForceMerge)
+02431                                 FLeft->forceMerge();
+02432                 }
+02433                 RecursMarkForceMerge=false;
+02434 
+02435                 // If still a parent, merge.
+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                 // If we are at tile subdivision, we must force our sons to merge.
+02456                 if(Level==Patch->TileLimitLevel)
+02457                         forceMerge();
+02458         }
+02459 }
+02460 
+02461 
+02462 // ***************************************************************************
+02463 void            CTessFace::averageTesselationVertices()
+02464 {
+02465         // If we are not splitted, no-op.
+02466         if(isLeaf())
+02467                 return;
+02468 
+02469 
+02470         CTessFace       *neighbor;
+02471         // Normal square case.
+02472         if(!isRectangular())
+02473         {
+02474                 neighbor= FBase;
+02475         }
+02476         // Special Rectangular case.
+02477         else
+02478         {
+02479                 // NB: here, just need to compute average of myself with FLeft, because my neighbor FBase 
+02480                 // is on same patch (see splitRectangular()), and is average with its FLeft neighbor is done 
+02481                 // on an other branch of the recurs call.
+02482                 neighbor= FLeft;
+02483         }
+02484 
+02485 
+02486         /* Try to average with neighbor.
+02487                 - if no neighbor, no-op :).
+02488                 - if neighbor is bind 1/N (CantMergeFace), no-op too, because the vertex is a BaseVertex, so don't modify.
+02489                 - if my patch is same than my neighbor, then we are on a same patch :), and so no need to average.
+02490         */
+02491         if(neighbor!=NULL && neighbor!=&CantMergeFace && Patch!= neighbor->Patch)
+02492         {
+02493                 nlassert(neighbor->Patch);
+02494                 nlassert(!neighbor->isLeaf());
+02495                 // must compute average beetween me and my neighbor.
+02496                 // NB: this work with both rectangular and square triangles (see split*()).
+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                 // And so set the average.
+02503                 SonLeft->VBase->EndPos= (v0+v1)/2;
+02504         }
+02505 
+02506 
+02507         // Do same thing for sons. NB: see above, we are not a leaf.
+02508         SonLeft->averageTesselationVertices();
+02509         SonRight->averageTesselationVertices();
+02510 }
+02511 
+02512 
+02513 // ***************************************************************************
+02514 void            CTessFace::refreshTesselationGeometry()
+02515 {
+02516         // must enlarge the little tessBlock (if any), for clipping.
+02517         Patch->extendTessBlockWithEndPos(this);
+02518 
+02519         // If we are not splitted, no-op.
+02520         if(isLeaf())
+02521                 return;
+02522 
+02523 
+02524         /* NB: rectangular case: just need to take SonLeft->VBase, because my neighbor on FBase will compute his son
+02525                 on an other branch of the recurs call.
+02526         */
+02527         // re-compute this position (maybe with new noise geometry in Tile Edition).
+02528         SonLeft->VBase->EndPos= Patch->computeVertex(SonLeft->PVBase.getS(), SonLeft->PVBase.getT());
+02529         // overwrite cur Pos (NB: specialy hardcoded for Tile edition).
+02530         SonLeft->VBase->Pos= SonLeft->VBase->EndPos;
+02531 
+02532         // Do same thing for sons. NB: see above, we are not a leaf.
+02533         SonLeft->refreshTesselationGeometry();
+02534         SonRight->refreshTesselationGeometry();
+02535 }
+02536 
+02537 
+02538 // ***************************************************************************
+02539 bool            CTessFace::updateBindEdge(CTessFace     *&edgeFace, bool &splitWanted)
+02540 {
+02541         // Return true, when the bind should be Ok, or if a split has occured.
+02542         // Return false only if pointers are updated, without splits.
+02543 
+02544         if(edgeFace==NULL)
+02545                 return true;
+02546 
+02547         if(edgeFace->isLeaf())
+02548                 return true;
+02549 
+02550         /*
+02551                 Look at the callers, and you'll see that "this" is always a leaf.
+02552                 Therefore, edgeFace is a valid pointer (either if it is FLeft, FRight or FBase).
+02553         */
+02554 
+02555         // MultiPatch face case.
+02556         //======================
+02557         // If neighbor is a multiple face.
+02558         if(edgeFace->Patch==NULL && edgeFace->FBase==this)
+02559         {
+02560                 splitWanted= true;
+02561                 return true;
+02562         }
+02563 
+02564 
+02565         // neighbor is a "Square face" case.
+02566         //==================================
+02567         if(!edgeFace->isRectangular())
+02568         {
+02569                 // NB: this code works either if I AM a rectangular face or a square face.
+02570 
+02571                 // If the neighbor is splitted  on ourself, split...
+02572                 if(edgeFace->FBase==this)
+02573                 {
+02574                         splitWanted= true;
+02575                         return true;
+02576                 }
+02577                 else
+02578                 {
+02579                         // Just update pointers...
+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                                 // Look at the callers, and you'll see that "this" is always a leaf.
+02595                                 // Therefore, we should never be here.
+02596                                 nlstop;
+02597                         }
+02598                 }
+02599         }
+02600         // neighbor is a "Rectangle face" case.
+02601         //=====================================
+02602         else
+02603         {
+02604                 // NB: this code works either if I AM a rectangular face or a square face.
+02605 
+02606                 // If the neighbor is splitted  on ourself, split...
+02607                 // Test FLeft because of rectangular case... :)
+02608                 // FBase should be tested too. If edgeFace->FBase==this, I should be myself a rectangular face.
+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                                 // See rectangular tesselation rules, too know why we do this.
+02619                                 CTessFace       *sonRight= edgeFace->SonRight;
+02620                                 sonRight->FRight= this;
+02621                                 edgeFace= sonRight;
+02622                         }
+02623                         else
+02624                         {
+02625                                 // Look at the callers, and you'll see that "this" is always a leaf.
+02626                                 // Therefore, we should never be here.
+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                 Look at the callers, and you'll see that "this" is always a leaf.
+02645                 Therefore, FBase, FLeft and FRight are good pointers, and *FLeft and *FRight should be Ok too.
+02646         */
+02647         nlassert(isLeaf());
+02648         while(!updateBindEdge(FBase, splitWanted));
+02649         // FLeft and FRight pointers are only valid in Leaves nodes.
+02650         while(!updateBindEdge(FLeft, splitWanted));
+02651         while(!updateBindEdge(FRight, splitWanted));
+02652         // In rectangular case, we MUST also update edges of FBase.
+02653         // Because splitRectangular() split those two faces at the same time.
+02654         if(isRectangular())
+02655         {
+02656                 f0= this;
+02657                 f1= FBase;
+02658                 nlassert(FBase);
+02659                 nlassert(FBase->isLeaf());
+02660                 // Doesn't need to update FBase->FBase, since it's me!
+02661                 // FLeft and FRight pointers are only valid in Leaves nodes.
+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         // If multipatch face case.
+02672         //=========================
+02673         if(!isRectangular())
+02674         {
+02675                 // multipatch face case are detected when face->Patch==NULL !!!
+02676                 if(FBase && FBase->Patch==NULL)
+02677                 {
+02678                         fmult= FBase;
+02679                         // First, trick: FBase is NULL, so during the split. => no ptr problem.
+02680                         FBase= NULL;
+02681                 }
+02682         }
+02683         else
+02684         {
+02685                 // multipatch face case are detected when face->Patch==NULL !!!
+02686                 if(f0->FLeft && f0->FLeft->Patch==NULL)
+02687                 {
+02688                         fmult0= f0->FLeft;
+02689                         // First, trick: neighbor is NULL, so during the split. => no ptr problem.
+02690                         f0->FLeft= NULL;
+02691                 }
+02692                 // multipatch face case are detected when face->Patch==NULL !!!
+02693                 if(f1->FLeft && f1->FLeft->Patch==NULL)
+02694                 {
+02695                         fmult1= f1->FLeft;
+02696                         // First, trick: neighbor is NULL, so during the split. => no ptr problem.
+02697                         f1->FLeft= NULL;
+02698                 }
+02699         }
+02700 
+02701         // Then split, and propagate.
+02702         //===========================
+02703         split(false);
+02704         if(!isRectangular())
+02705         {
+02706                 if(FBase)
+02707                 {
+02708                         while(FBase->isLeaf())
+02709                                 FBase->updateBindAndSplit();
+02710                 }
+02711                 // There is a possible bug here (maybe easily patched). Sons may have be propagated splitted.
+02712                 // And problems may arise because this face hasn't yet good connectivity.
+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                 // There is a possible bug here (maybe easily patched). Sons may have be propagated splitted.
+02728                 // And problems may arise because this face hasn't yet good connectivity.
+02729                 nlassert(f0->SonLeft->isLeaf() && f0->SonRight->isLeaf());
+02730                 nlassert(f1->SonLeft->isLeaf() && f1->SonRight->isLeaf());
+02731         }
+02732 
+02733 
+02734         // If multipatch face case, update neighbors.
+02735         //===========================================
+02736         if(!isRectangular() && fmult)
+02737         {
+02738                 // Update good Face neighbors.
+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                 // NB: this work auto with 1/2 or 1/4. See CPatch::bind(), to understand.
+02747                 // In 1/4 case, fmult->SonLeft and fmult->SonRight are themselves MultiPatch face. So it will recurse.
+02748 
+02749                 // Update good vertex pointer.
+02750                 //============================
+02751                 CTessVertex     *vert= fmult->VBase;
+02752 
+02753                 // Copy the good coordinate: those splitted (because of noise).
+02754                 vert->Pos= vert->StartPos= vert->EndPos= SonLeft->VBase->EndPos;
+02755                 // But delete the pointer.
+02756                 Patch->getLandscape()->deleteTessVertex(SonLeft->VBase);
+02757                 // And update sons pointers, to good vertex.
+02758                 SonLeft->VBase= vert;
+02759                 SonRight->VBase= vert;
+02760                 // Compute correct centers.
+02761                 SonRight->computeSplitPoint();
+02762                 SonLeft->computeSplitPoint();
+02763 
+02764 
+02765                 // Update good Far vertex pointer.
+02766                 //================================
+02767                 // Because *->VBase may have been merged to the multiple bind face, Near/FarVertices which pointed on it must
+02768                 // be setup.
+02769                 // We do not have to propagate this vertex ptr change since sons are leaves!!
+02770                 nlassert(SonLeft->isLeaf() && SonRight->isLeaf());
+02771                 // update pointers on vertex.
+02772                 SonLeft->updateNearFarVertices();
+02773                 SonRight->updateNearFarVertices();
+02774 
+02775 
+02776                 // Bind FBase to a false face which indicate a bind 1/N.
+02777                 // This face prevent for "this" face to be merged...
+02778                 FBase= &CantMergeFace;
+02779 
+02780                 // Therefore, the vertex will be never deleted (since face not merged).
+02781                 // The only way to do this, is to unbind the patch from all (then the vertex is cloned), then the merge will be Ok.
+02782         }
+02783         // Else if rectangular.
+02784         else if(fmult0 || fmult1)
+02785         {
+02786                 CTessFace       *f;
+02787                 sint            i;
+02788 
+02789                 // Same reasoning for rectangular patchs, as above.
+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                                 // Update good Face neighbors (when I am a rectangle).
+02799                                 //============================
+02800                                 // Consider the fmult face as a square face.
+02801                                 CTessFace       *toLeft, *toRight;
+02802                                 CTessFace       *fl=f->SonLeft, *fr=f->SonRight;
+02803                                 toLeft= fmult->SonLeft;
+02804                                 toRight= fmult->SonRight;
+02805                                 // Cross connection of sons.
+02806                                 fl->FLeft= toLeft;
+02807                                 fr->FLeft= toRight;
+02808                                 toLeft->changeNeighbor(&CTessFace::MultipleBindFace, fl);
+02809                                 toRight->changeNeighbor(&CTessFace::MultipleBindFace, fr);
+02810 
+02811                                 // Update good vertex pointer.
+02812                                 //============================
+02813                                 CTessVertex     *vert= fmult->VBase;
+02814 
+02815                                 // Copy the good coordinate: those splitted (because of noise).
+02816                                 // NB: this work too with rectangular patch (see tesselation rules).
+02817                                 vert->Pos= vert->StartPos= vert->EndPos= fl->VBase->EndPos;
+02818                                 // But delete the pointer.
+02819                                 Patch->getLandscape()->deleteTessVertex(fl->VBase);
+02820                                 // And update sons pointers, to good vertex (rectangular case, see tesselation rules).
+02821                                 fl->VBase= vert;
+02822                                 fr->VLeft= vert;
+02823                                 f->FBase->SonLeft->VRight= vert;
+02824 
+02825                                 // Point to a bind 1/N indicator.
+02826                                 f->FLeft= &CantMergeFace;
+02827                         }
+02828                 }
+02829                 // After all updates done. recompute centers of both sons 's faces, and update far vertices pointers.
+02830                 for(i=0;i<2;i++)
+02831                 {
+02832                         if(i==0)
+02833                                 f= f0;
+02834                         else
+02835                                 f= f1;
+02836                         // Compute correct centers.
+02837                         f->SonRight->computeSplitPoint();
+02838                         f->SonLeft->computeSplitPoint();
+02839 
+02840                         // Update good Far vertex pointer.
+02841                         //================================
+02842                         // Because *->VBase may have been merged to the multiple bind face, Near/FarVertices which pointed on it must
+02843                         // be setup.
+02844                         // We do not have to propagate this vertex ptr change, since sons are leaves!!
+02845                         nlassert(f->SonLeft->isLeaf() && f->SonRight->isLeaf());
+02846                         // update pointers on vertex.
+02847                         f->SonLeft->updateNearFarVertices();
+02848                         f->SonRight->updateNearFarVertices();
+02849                 }
+02850         }
+02851 }
+02852 
+02853 
+02854 // ***************************************************************************
+02855 void            CTessFace::updateBind()
+02856 {
+02857         /*
+02858                 Remind that updateBind() is called ONLY on the patch which is binded (not the neighbors).
+02859                 Since updateBind() is called on the bintree, and that precedent propagated split may have occur, we may not
+02860                 be a leaf here. So we are not sure that FLeft and FRight are good, and we doesn't need to update them (since we have
+02861                 sons).
+02862                 Also, since we are splitted, and correctly linked (this may not be the case in updateBindAndSplit()), FBase IS
+02863                 correct. His FBase neighbor and him form a diamond. So we don't need to update him.
+02864 
+02865                 Same remarks for rectangular patchs.
+02866         */
+02867         if(isLeaf())
+02868         {
+02869                 bool    splitWanted= false;
+02870                 while(!updateBindEdge(FBase, splitWanted));
+02871                 // FLeft and FRight pointers are only valid in Leaves nodes.
+02872                 while(!updateBindEdge(FLeft, splitWanted));
+02873                 while(!updateBindEdge(FRight, splitWanted));
+02874                 if(splitWanted)
+02875                         updateBindAndSplit();
+02876         }
+02877 
+02878 
+02879         // Recurse to sons.
+02880         if(!isLeaf())
+02881         {
+02882                 // Update bind of sons.
+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         // Compute 0,1 coords of 3 patch coords.
+02902         CVector2f       vb( PVBase.getS(), PVBase.getT() );
+02903         CVector2f       vl( PVLeft.getS(), PVLeft.getT() );
+02904         CVector2f       vr( PVRight.getS(), PVRight.getT() );
+02905 
+02906         // Search if one of the 3 edges of this triangle match the wanted edge.
+02907         // Base Edge
+02908         if(matchEdge(uv0, uv1, vl, vr))
+02909         {
+02910                 // If leaf, check if unbound (else ptr is invalid)
+02911                 nlassert(FBase==NULL || !isLeaf());
+02912                 FBase= linkTo;
+02913                 return this;
+02914         }
+02915         // Left Edge
+02916         if(matchEdge(uv0, uv1, vb, vl))
+02917         {
+02918                 // If leaf, check if unbound (else ptr is invalid)
+02919                 nlassert(FLeft==NULL || !isLeaf());
+02920                 FLeft= linkTo;
+02921                 return this;
+02922         }
+02923         // Right Edge
+02924         if(matchEdge(uv0, uv1, vb, vr))
+02925         {
+02926                 // If leaf, check if unbound (else ptr is invalid)
+02927                 nlassert(FRight==NULL || !isLeaf())
+02928                 FRight= linkTo;
+02929                 return this;
+02930         }
+02931 
+02932 
+02933         // If not found here, recurs to children
+02934         CTessFace       *ret= NULL;
+02935         if( !isLeaf() )
+02936         {
+02937                 ret= SonLeft->linkTessFaceWithEdge(uv0, uv1, linkTo);
+02938                 // if no found in this branch, recusr right branch.
+02939                 if(!ret)
+02940                         ret= SonRight->linkTessFaceWithEdge(uv0, uv1, linkTo);
+02941         }
+02942         
+02943         // return the result from subBranchs
+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 // For changePatchTexture.
+02959 // ***************************************************************************
+02960 // ***************************************************************************
+02961 
+02962 
+02963 // ***************************************************************************
+02964 void            CTessFace::deleteTileUvs()
+02965 {
+02966         // NB: NearVertices are removed from renderlist with deleteTileUv (called in releaseTileMaterial()).
+02967 
+02968         if(!isLeaf())
+02969         {
+02970                 // Must delete the materials of leaves first.
+02971                 SonLeft->deleteTileUvs();
+02972                 SonRight->deleteTileUvs();
+02973                 if(SonLeft->Level== Patch->TileLimitLevel)
+02974                 {
+02975                         // Square patch assumption: the sons are not of the same TileId/Patch.
+02976                         nlassert(!sameTile(SonLeft, SonRight));
+02977                         // release tiles.
+02978                         SonLeft->releaseTileMaterial();
+02979                         SonRight->releaseTileMaterial();
+02980                 }
+02981                 else if(SonLeft->Level > Patch->TileLimitLevel)
+02982                 {
+02983                         nlassert(!FBase || !FBase->isLeaf());
+02984 
+02985                         // Delete Uv, only if not already done by the neighbor (ie neighbor has yet TileFaces!!).
+02986                         // But Always delete if neighbor exist and has not same tile as me.
+02987                         // NB: this work with rectangular neigbor patch, since sameTile() will return false if different patch.
+02988                         if(!FBase || !FBase->SonLeft->emptyTileFaces() || !sameTile(this, FBase))
+02989                         {
+02990                                 SonLeft->deleteTileUv(IdUvBase);
+02991                         }
+02992                         // In all case, must delete the tilefaces of those face.
+02993                         SonLeft->deleteTileFaces();
+02994                         SonRight->deleteTileFaces();
+02995                         // For createTileUvs, it is important to mark those faces as NO TileMaterial.
+02996                         SonLeft->TileMaterial= NULL;
+02997                         SonRight->TileMaterial= NULL;
+02998                 }
+02999         }
+03000         else
+03001         {
+03002                 // NB: this is done always BELOW tile creation (see above).
+03003                 // Do this only for tiles.
+03004                 if(TileMaterial)
+03005                         Patch->removeFaceFromTileRenderList(this);
+03006         }
+03007 
+03008 }
+03009 
+03010 
+03011 // ***************************************************************************
+03012 void            CTessFace::recreateTileUvs()
+03013 {
+03014         // NB: NearVertices are append to renderlist with allocTileUv (called in computeTileMaterial()/heritTileMaterial()).
+03015 
+03016         if(!isLeaf())
+03017         {
+03018                 // Must recreate the materials of parent first.
+03019 
+03020                 // There is no problem with rectangular patch, since tiles are always squares.
+03021                 // If new tile ....
+03022                 if(SonLeft->Level==Patch->TileLimitLevel)
+03023                 {
+03024                         SonLeft->computeTileMaterial();
+03025                         SonRight->computeTileMaterial();
+03026                 }
+03027                 // else Tile herit.
+03028                 else if(SonLeft->Level > Patch->TileLimitLevel)
+03029                 {
+03030                         heritTileMaterial();
+03031                 }
+03032 
+03033                 SonLeft->recreateTileUvs();
+03034                 SonRight->recreateTileUvs();
+03035         }
+03036         else
+03037         {
+03038                 // NB: this is done always AFTER tile creation (see above).
+03039                 // Do this only for tiles.
+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         // Create, or link to the tileUv.
+03063         // Try to link to a neighbor TileUv.
+03064         // Can only work iff exist, and iff FBase is same patch, and same TileId.
+03065         if(FBase!=NULL && !FBase->isLeaf() && FBase->SonLeft->TileMaterial!=NULL && sameTile(this, FBase) )
+03066         {
+03067                 // Ok!! link to the (existing) TileUv.
+03068                 // FBase->SonLeft!=NULL since FBase->isLeaf()==false.
+03069                 SonLeft->copyTileUv(IdUvBase, FBase->SonLeft, IdUvBase);
+03070                 SonRight->copyTileUv(IdUvBase, FBase->SonLeft, IdUvBase);
+03071         }
+03072         else
+03073         {
+03074                 // Allocate a new vertex, and copy it to SonLeft and SonRight.
+03075                 SonLeft->allocTileUv(IdUvBase);
+03076                 SonRight->copyTileUv(IdUvBase, SonLeft, IdUvBase);
+03077 
+03078                 // Fill the new near vertex, with middle of Left/Right father.
+03079                 SonLeft->heritTileUv(this);
+03080 
+03081                 // UVs are computed, may create and fill VB.
+03082                 SonLeft->checkCreateFillTileVB(IdUvBase);
+03083         }
+03084 
+03085 }
+03086 
+03087 
+03088 // ***************************************************************************
+03089 // ***************************************************************************
+03090 // For getTesselatedPos
+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         // may verif if uv is In this triangle. supposed true if rectangular branch.
+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                         // if out this 2D plane, uv is out this triangle
+03112                         if(normalUv * (uvPos-uvs[i]) <0)
+03113                                 return;
+03114                 }
+03115         }
+03116 
+03117         // compute tesselated pos in this face.
+03118         if(isLeaf())
+03119                 // ok, no more sons, let's do it.
+03120                 computeTesselatedPos(uv, ret);
+03121         else
+03122         {
+03123                 // must subdivide.
+03124                 // if we are rectangular (strange tesselation), must test in both leaves, else, choose only one.
+03125                 if(isRectangular())
+03126                 {
+03127                         SonLeft->getTesselatedPos(uv, true, ret);
+03128                         SonRight->getTesselatedPos(uv, true, ret);
+03129                 }
+03130                 else
+03131                 {
+03132                         // Compute the uv plane which separate the 2 leaves.
+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                         // choose what leaf to recurs.
+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         // compute the UV triangle of this face.
+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         // must interpolate the position with given UV, so compute XYZ gradients.
+03162         CVector         Gx;
+03163         CVector         Gy;
+03164         CVector         Gz;
+03165         // If VertexProgram activated
+03166         if( CLandscapeGlobals::VertexProgramEnabled )
+03167         {
+03168                 // then Must update geomorphed position because not done !!
+03169                 VBase->computeGeomPos();
+03170                 VLeft->computeGeomPos();
+03171                 VRight->computeGeomPos();
+03172         }
+03173         // NB: take geomorphed position.
+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         // Compute interpolated position.
+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 } // NL3D
+
+ + +
                                                                                                                                                                    +
+ + -- cgit v1.2.1