# 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