NL3D::CTessFace Class Reference

#include <tessellation.h>

Inheritance diagram for NL3D::CTessFace:

NL3D::CTessNodeList NL3D::CTessFacePListNode

Detailed Description

A Landscape Triangle. MemSize: 28*4 octets. => for 100K faces, it takes 11.2 Mo.
Author:
Lionel Berenguier

Nevrax France

Date:
2000

Definition at line 233 of file tessellation.h.

Tile Material Infos (uvs...).

enum  TTileUvId { IdUvBase = 0, IdUvLeft, IdUvRight }
CTileFaceTileFaces [NL3D_MAX_TILE_FACE]
uint8 TileId
CTileMaterialTileMaterial

Public Types


Public Member Functions

void appendPList (CTessFacePListNode &root)
void appendTessellationLeaves (std::vector< const CTessFace * > &leaves) const
void averageTesselationVertices ()
void changeNeighbor (CTessFace *from, CTessFace *to)
float computeNearLimit ()
void computeSplitPoint ()
void computeTileMaterial ()
 CTessFace ()
void deleteTileUvs ()
void forceMerge ()
void forceMergeAtTileLevel ()
void getTesselatedPos (const CUV &uv, bool verifInclusion, CVector &ret)
bool hasEdge (CTessVertex *v0, CTessVertex *v1) const
bool hasVertex (CTessVertex *v) const
bool isLeaf () const
bool isRectangular () const
void linkInPList (CTessFacePListNode &root)
 unlinkInPList, then link this node to the root of a list.

CTessFacelinkTessFaceWithEdge (const NLMISC::CVector2f &uv0, const NLMISC::CVector2f &uv1, CTessFace *linkTo)
bool merge ()
CTessFacePListNodenextInPList () const
CTessFacePListNodeprecInPList () const
 get next ptr. next==this if list empty.

void recreateTileUvs ()
void refineAll ()
 refine the node, and his sons. Refine all nodes.

void refreshTesselationGeometry ()
void releaseTileMaterial ()
void split (bool propagateSplit=true)
void unbind ()
void unlinkInPList ()
 if linked, unlink this node from his list.

void updateBind ()
void updateBindAndSplit ()
bool updateBindEdge (CTessFace *&edgeFace, bool &splitWanted)
void updateErrorMetric ()
void updateRefineMerge ()
void updateRefineSplit ()
 ~CTessFace ()

Data Fields

CTessFarVertexFVBase
CTessFarVertexFVLeft
CTessFarVertexFVRight
CTessNodeListNext
CTessNodeListPrec
sint ShadowMapTriId
Error metric.
float ErrorMetric
sint ErrorMetricDate
float MaxDistToSplitPoint
float Size
CVector SplitPoint
geometric tesselation.
CTessFaceFather
CTessFaceFBase
CTessFaceFLeft
CTessFaceFRight
uint8 Level
CPatchPatch
CParamCoord PVBase
CParamCoord PVLeft
CParamCoord PVRight
bool RecursMarkCanMerge
bool RecursMarkForceMerge
CTessFaceSonLeft
CTessFaceSonRight
CTessVertexVBase
CTessVertexVLeft
CTessVertexVRight

Static Public Attributes

CTessFace MultipleBindFace

Private Member Functions

bool canMerge (bool testEm)
void computeTesselatedPos (const CUV &uv, CVector &ret)
float computeTileEMForUpdateRefine (float distSplitPoint, float distMinFace, float nearLimit)
void computeTileErrorMetric ()
void doMerge ()
void heritTileMaterial ()
void initTileUvDLM (CParamCoord pointCoord, CUV &uv)
void initTileUvLightmap (CParamCoord pointCoord, CParamCoord middleCoord, CUV &uv)
void initTileUvRGBA (sint pass, bool alpha, CParamCoord pointCoord, CParamCoord middleCoord, CUV &uv)
void splitRectangular (bool propagateSplit)
void updateNearFarVertices ()
UV mgt.
void allocTileUv (TTileUvId id)
void buildTileFaces ()
void checkCreateFillTileVB (TTileUvId id)
void checkFillTileVB (TTileUvId id)
void copyTileUv (TTileUvId id, CTessFace *srcFace, TTileUvId srcId)
void deleteTileFaces ()
void deleteTileUv (TTileUvId id)
bool emptyTileFaces ()
void heritTileUv (CTessFace *baseFace)

Static Private Member Functions

bool sameTile (const CTessFace *a, const CTessFace *b)

Static Private Attributes

CTessFace CantMergeFace


Member Enumeration Documentation

enum NL3D::CTessFace::TTileUvId
 

Enumeration values:
IdUvBase 
IdUvLeft 
IdUvRight 

Definition at line 264 of file tessellation.h.


Constructor & Destructor Documentation

NL3D::CTessFace::CTessFace  ) 
 

Definition at line 161 of file tessellation.cpp.

References ErrorMetricDate, FBase, FLeft, FRight, NL3D_MAX_TILE_FACE, NL3D_PROFILE_LAND_ADD, NL3D::ProfNTessFace, RecursMarkCanMerge, RecursMarkForceMerge, ShadowMapTriId, sint, SonLeft, SonRight, TileFaces, VBase, VLeft, and VRight.

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         ShadowMapTriId= -1;
00188 }

NL3D::CTessFace::~CTessFace  ) 
 

Definition at line 192 of file tessellation.cpp.

References NL3D_PROFILE_LAND_ADD, nlassert, NL3D::ProfNTessFace, and ShadowMapTriId.

00193 {
00194         // Old Code. This is not sufficient to clear the CTessFace.
00195         // Vertices and Uvs must be correctly cleared too (but difficult because of sharing).
00196         /*
00197         Patch->getLandscape()->deleteTessFace(SonLeft);
00198         Patch->getLandscape()->deleteTessFace(SonRight);
00199 
00200         // update neighbors.
00201         if(FBase)       FBase->changeNeighbor(this, NULL);
00202         if(FLeft)       FLeft->changeNeighbor(this, NULL);
00203         if(FRight)      FRight->changeNeighbor(this, NULL);
00204 
00205         FBase=FLeft=FRight= NULL;
00206         */
00207 
00208         NL3D_PROFILE_LAND_ADD(ProfNTessFace, -1);
00209 
00210         // Ensure correclty removed from landscape ShadowMap.
00211         nlassert(ShadowMapTriId== -1);
00212 }


Member Function Documentation

void NL3D::CTessFace::allocTileUv TTileUvId  id  )  [private]
 

Definition at line 372 of file tessellation.cpp.

References NL3D::CPatch::appendNearVertexToRenderList(), NL3D::CPatch::getLandscape(), IdUvBase, IdUvLeft, IdUvRight, NL3D::CLandscape::newTessNearVertex(), NL3D_MAX_TILE_FACE, NL3D_TILE_PASS_RGB0, nlassert, nlstop, sint, NL3D::CTessNearVertex::Src, TileFaces, NL3D::CTileFace::V, VBase, VLeft, and VRight.

Referenced by computeTileMaterial(), and heritTileMaterial().

00373 {
00374         // TileFaces must have been build.
00375         nlassert(TileFaces[NL3D_TILE_PASS_RGB0]);
00376 
00377         // what src??
00378         CTessVertex             *vertexSrc;
00379         switch(id)
00380         {
00381                 case IdUvBase: vertexSrc= VBase; break;
00382                 case IdUvLeft: vertexSrc= VLeft; break;
00383                 case IdUvRight: vertexSrc= VRight; break;
00384                 default: nlstop;
00385         };
00386 
00387         // Do it for all possible pass
00388         for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
00389         {
00390                 if(TileFaces[i])
00391                 {
00392                         CTessNearVertex         *newNear= Patch->getLandscape()->newTessNearVertex();
00393                         newNear->Src= vertexSrc;
00394                         TileFaces[i]->V[id]= newNear;
00395                         Patch->appendNearVertexToRenderList(TileMaterial, newNear);
00396 
00397                         // May Allocate/Fill VB. Do it after allocTileUv, because UVs are not comuted yet.
00398                 }
00399         }
00400 }

void NL3D::CTessFacePListNode::appendPList CTessFacePListNode root  )  [inherited]
 

append a list just after this node. root is the root of the list. It is not inserted in the result. After this, the list pointed by "root" is empty.

Definition at line 88 of file tess_face_priority_list.cpp.

References NL3D::CTessFacePListNode::_NextTessFaceInPList, and NL3D::CTessFacePListNode::_PrecTessFaceInPList.

Referenced by NL3D::CLandscape::refine(), NL3D::CTessFacePriorityList::shift(), and NL3D::CTessFacePriorityList::CRollingTable::shiftEntries().

00089 {
00090         // If list to append is not empty.
00091         if( root._NextTessFaceInPList != &root )
00092         {
00093                 // If we are empty.
00094                 if( _NextTessFaceInPList==this )
00095                 {
00096                         // link the appendList to the root.
00097                         _PrecTessFaceInPList= root._PrecTessFaceInPList;
00098                         _NextTessFaceInPList= root._NextTessFaceInPList;
00099                         // link the root to the appendList.
00100                         _PrecTessFaceInPList->_NextTessFaceInPList= this;
00101                         _NextTessFaceInPList->_PrecTessFaceInPList= this;
00102                 }
00103                 // else bind first-last in the interval prec-next.
00104                 else
00105                 {
00106                         CTessFacePListNode              *first= root._NextTessFaceInPList;
00107                         CTessFacePListNode              *last= root._PrecTessFaceInPList;
00108                         CTessFacePListNode              *prec= this;
00109                         CTessFacePListNode              *next= _NextTessFaceInPList;
00110                         // insert the appendList in our list.
00111                         next->_PrecTessFaceInPList= last;
00112                         prec->_NextTessFaceInPList= first;
00113                         // insert our list in the appendList.
00114                         last->_NextTessFaceInPList= next;
00115                         first->_PrecTessFaceInPList= prec;
00116                 }
00117 
00118                 // clear input list.
00119                 root._PrecTessFaceInPList= &root;
00120                 root._NextTessFaceInPList= &root;
00121         }
00122 }

void NL3D::CTessFace::appendTessellationLeaves std::vector< const CTessFace * > &  leaves  )  const
 

Definition at line 3194 of file tessellation.cpp.

References isLeaf(), SonLeft, and SonRight.

Referenced by NL3D::CPatch::appendTessellationLeaves().

03195 {
03196         if(isLeaf())
03197                 leaves.push_back(this);
03198         else
03199         {
03200                 SonLeft->appendTessellationLeaves(leaves);
03201                 SonRight->appendTessellationLeaves(leaves);
03202         }
03203 }

void NL3D::CTessFace::averageTesselationVertices  ) 
 

Definition at line 2468 of file tessellation.cpp.

References CantMergeFace, NL3D::CPatch::computeVertex(), NL3D::CTessVertex::EndPos, FBase, FLeft, NL3D::CParamCoord::getS(), NL3D::CParamCoord::getT(), isLeaf(), isRectangular(), nlassert, Patch, PVBase, SonLeft, SonRight, and VBase.

Referenced by NL3D::CPatch::averageTesselationVertices().

02469 {
02470         // If we are not splitted, no-op.
02471         if(isLeaf())
02472                 return;
02473 
02474 
02475         CTessFace       *neighbor;
02476         // Normal square case.
02477         if(!isRectangular())
02478         {
02479                 neighbor= FBase;
02480         }
02481         // Special Rectangular case.
02482         else
02483         {
02484                 // NB: here, just need to compute average of myself with FLeft, because my neighbor FBase 
02485                 // is on same patch (see splitRectangular()), and is average with its FLeft neighbor is done 
02486                 // on an other branch of the recurs call.
02487                 neighbor= FLeft;
02488         }
02489 
02490 
02491         /* Try to average with neighbor.
02492                 - if no neighbor, no-op :).
02493                 - if neighbor is bind 1/N (CantMergeFace), no-op too, because the vertex is a BaseVertex, so don't modify.
02494                 - if my patch is same than my neighbor, then we are on a same patch :), and so no need to average.
02495         */
02496         if(neighbor!=NULL && neighbor!=&CantMergeFace && Patch!= neighbor->Patch)
02497         {
02498                 nlassert(neighbor->Patch);
02499                 nlassert(!neighbor->isLeaf());
02500                 // must compute average beetween me and my neighbor.
02501                 // NB: this work with both rectangular and square triangles (see split*()).
02502                 nlassert(SonLeft->VBase == neighbor->SonLeft->VBase);
02503 
02504                 CVector         v0= Patch->computeVertex(SonLeft->PVBase.getS(), SonLeft->PVBase.getT());
02505                 CVector         v1= neighbor->Patch->computeVertex(neighbor->SonLeft->PVBase.getS(), neighbor->SonLeft->PVBase.getT());
02506 
02507                 // And so set the average.
02508                 SonLeft->VBase->EndPos= (v0+v1)/2;
02509         }
02510 
02511 
02512         // Do same thing for sons. NB: see above, we are not a leaf.
02513         SonLeft->averageTesselationVertices();
02514         SonRight->averageTesselationVertices();
02515 }

void NL3D::CTessFace::buildTileFaces  )  [private]
 

Definition at line 511 of file tessellation.cpp.

References NL3D::CPatch::getLandscape(), IdUvBase, IdUvLeft, IdUvRight, NL3D::CLandscape::newTileFace(), NL3D_MAX_TILE_FACE, nlassert, NL3D::CTileMaterial::Pass, NL3D::CRdrTileId::PatchRdrPass, sint, TileFaces, and NL3D::CTileFace::V.

Referenced by computeTileMaterial(), and heritTileMaterial().

00512 {
00513         nlassert(TileMaterial);
00514 
00515         // Do nothgin for lightmap pass, of course.
00516         for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
00517         {
00518                 if(TileMaterial->Pass[i].PatchRdrPass)
00519                 {
00520                         TileFaces[i]= Patch->getLandscape()->newTileFace();
00521                         TileFaces[i]->V[IdUvBase]= NULL;
00522                         TileFaces[i]->V[IdUvLeft]= NULL;
00523                         TileFaces[i]->V[IdUvRight]= NULL;
00524                 }
00525         }
00526 }

bool NL3D::CTessFace::canMerge bool  testEm  )  [private]
 

Definition at line 1549 of file tessellation.cpp.

References CantMergeFace, ErrorMetric, FBase, FLeft, isLeaf(), isRectangular(), nlassert, RecursMarkCanMerge, SonLeft, SonRight, and updateErrorMetric().

Referenced by merge(), refineAll(), and updateRefineMerge().

01550 {
01551         if(this== &CantMergeFace)
01552                 return false;
01553 
01554         nlassert(!isLeaf());
01555 
01556         // Test diamond config (sons must be leaves).
01557         if(!SonLeft->isLeaf())
01558                 return false;
01559         if(!SonRight->isLeaf())
01560                 return false;
01561         // If Errormetric must be considered for this test.
01562         if(testEm)
01563         {
01564                 updateErrorMetric();
01565                 float   ps2= ErrorMetric;
01566                 ps2*= CLandscapeGlobals::OORefineThreshold;
01567                 if(ps2>=1.0f)
01568                         return false;
01569         }
01570 
01571         // Then test neighbors.
01572         RecursMarkCanMerge= true;
01573         bool    ok= true;
01574         if(!isRectangular())
01575         {
01576                 if(FBase && !FBase->RecursMarkCanMerge)
01577                 {
01578                         if(!FBase->canMerge(testEm))
01579                                 ok= false;
01580                 }
01581         }
01582         else
01583         {
01584                 // Rectangular case. May have a longer propagation...
01585                 if(FBase && !FBase->RecursMarkCanMerge)
01586                 {
01587                         if(!FBase->canMerge(testEm))
01588                                 ok= false;
01589                 }
01590                 if(ok && FLeft && !FLeft->RecursMarkCanMerge)
01591                 {
01592                         if(!FLeft->canMerge(testEm))
01593                                 ok= false;
01594                 }
01595         }
01596         // Must not return false in preceding tests, because must set RecursMarkCanMerge to false.
01597         RecursMarkCanMerge= false;
01598 
01599         return ok;
01600 }

void NL3D::CTessFace::changeNeighbor CTessFace from,
CTessFace to
[inline]
 

Definition at line 298 of file tessellation.h.

References FBase, FLeft, FRight, and from.

Referenced by doMerge(), split(), splitRectangular(), unbind(), and updateBindAndSplit().

00299         {
00300                 if(FBase==from) FBase=to;
00301                 if(FLeft==from) FLeft=to;
00302                 if(FRight==from) FRight=to;
00303         }

void NL3D::CTessFace::checkCreateFillTileVB TTileUvId  id  )  [private]
 

Definition at line 403 of file tessellation.cpp.

References NL3D::CPatch::checkCreateVertexVBNear(), NL3D::CPatch::checkFillVertexVBNear(), NL3D_MAX_TILE_FACE, NL3D_TILE_PASS_RGB0, nlassert, sint, TileFaces, and NL3D::CTileFace::V.

Referenced by computeTileMaterial(), and heritTileMaterial().

00404 {
00405         // TileFaces must have been build.
00406         nlassert(TileFaces[NL3D_TILE_PASS_RGB0]);
00407 
00408         for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
00409         {
00410                 if(TileFaces[i])
00411                 {
00412                         CTessNearVertex         *vertNear;
00413                         vertNear= TileFaces[i]->V[id];
00414 
00415                         // May Allocate/Fill VB.
00416                         Patch->checkCreateVertexVBNear(vertNear);
00417                         Patch->checkFillVertexVBNear(vertNear);
00418                 }
00419         }
00420 }

void NL3D::CTessFace::checkFillTileVB TTileUvId  id  )  [private]
 

Definition at line 424 of file tessellation.cpp.

References NL3D::CPatch::checkFillVertexVBNear(), NL3D_MAX_TILE_FACE, NL3D_TILE_PASS_RGB0, nlassert, sint, TileFaces, and NL3D::CTileFace::V.

Referenced by split(), and splitRectangular().

00425 {
00426         // TileFaces must have been build.
00427         nlassert(TileFaces[NL3D_TILE_PASS_RGB0]);
00428 
00429         for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
00430         {
00431                 if(TileFaces[i])
00432                 {
00433                         CTessNearVertex         *vertNear;
00434                         vertNear= TileFaces[i]->V[id];
00435 
00436                         // May Fill VB.
00437                         Patch->checkFillVertexVBNear(vertNear);
00438                 }
00439         }
00440 }

float NL3D::CTessFace::computeNearLimit  ) 
 

Definition at line 216 of file tessellation.cpp.

References nlassert, NL3D::CPatch::TileLimitLevel, and uint.

Referenced by computeTileErrorMetric(), split(), splitRectangular(), unbind(), updateRefineMerge(), and updateRefineSplit().

00217 {
00218         // General formula for Level, function of Size, treshold etc...:
00219         // WantedLevel= log2(BaseSize / sqrdist / RefineThreshold);
00220         // <=> WantedLevel= log2( CurSize*2^Level / sqrdist / RefineThreshold).
00221         // <=> WantedLevel= log2( ProjectedSize* 2^Level / RefineThreshold).
00222         // <=> 2^WantedLevel= ProjectedSize* 2^Level / RefineThreshold.
00223         // <=> ProjectedSize= (2^WantedLevel) * RefineThreshold / (2^Level);
00224         // <=> ProjectedSize= (1<<WantedLevel) * RefineThreshold / (1<<Level);
00225         // UnOptimised formula: limit= (1<<Patch->TileLimitLevel) / (1<<Level);
00226         nlassert(Level<=20);
00227         static const uint       BigValue= 1<<20;
00228         static const float      OOBigValue= 1.0f / BigValue;
00229         return (1<<Patch->TileLimitLevel) * (OOBigValue*(BigValue>>Level));
00230 }

void NL3D::CTessFace::computeSplitPoint  ) 
 

compute the SplitPoint. VBase / VLeft and VRight must be valid. Also compute MaxDistToSplitPoint.

Definition at line 345 of file tessellation.cpp.

References NL3D::CTessVertex::EndPos, isRectangular(), MaxDistToSplitPoint, SplitPoint, NLMISC::CVector::sqrnorm(), VBase, VLeft, and VRight.

Referenced by NL3D::CPatch::bind(), NL3D::CPatch::makeRoots(), split(), splitRectangular(), and updateBindAndSplit().

00346 {
00347         if(isRectangular())
00348         {
00349                 // If it is a rectangular triangle, it will be splitted on the middle of VBase/VLeft.
00350                 // see splitRectangular() conventions.
00351                 // So for good geomorph compute per vertex, we must have this SplitPoint on this middle.
00352                 SplitPoint= (VLeft->EndPos + VBase->EndPos)/2;
00353         }
00354         else
00355         {
00356                 // If it is a square triangle, it will be splitted on middle of VLeft/VRight. 
00357                 // So for good geomorph compute per vertex, we must have this SplitPoint on this middle.
00358                 SplitPoint= (VLeft->EndPos + VRight->EndPos)/2;
00359         }
00360 
00361         // compute MaxDistToSplitPoint
00362         float   d0= (VBase->EndPos - SplitPoint).sqrnorm();
00363         float   d1= (VLeft->EndPos - SplitPoint).sqrnorm();
00364         float   d2= (VRight->EndPos - SplitPoint).sqrnorm();
00365         MaxDistToSplitPoint= max(d0, d1);
00366         MaxDistToSplitPoint= max(MaxDistToSplitPoint, d2);
00367         // Get the distance.
00368         MaxDistToSplitPoint= sqrtf(MaxDistToSplitPoint);
00369 }

void NL3D::CTessFace::computeTesselatedPos const CUV uv,
CVector ret
[private]
 

Definition at line 3156 of file tessellation.cpp.

References NL3D::CTessVertex::computeGeomPos(), NLMISC::CTriangle::computeGradient(), NL3D::CParamCoord::getS(), NL3D::CParamCoord::getT(), NL3D::CTessVertex::Pos, PVBase, PVLeft, PVRight, NLMISC::CVector::set(), NLMISC::CUV::U, NLMISC::CUV::V, NLMISC::CTriangle::V0, NLMISC::CTriangle::V1, NLMISC::CTriangle::V2, VBase, VLeft, VRight, NLMISC::CVector::x, NLMISC::CVector::y, and NLMISC::CVector::z.

Referenced by getTesselatedPos().

03157 {
03158         CVector         uvPos(uv.U, uv.V, 0);
03159 
03160         // compute the UV triangle of this face.
03161         CTriangle       uvTri;
03162         uvTri.V0.set( PVBase.getS(), PVBase.getT(), 0);
03163         uvTri.V1.set( PVLeft.getS(), PVLeft.getT(), 0);
03164         uvTri.V2.set( PVRight.getS(), PVRight.getT(), 0);
03165 
03166         // must interpolate the position with given UV, so compute XYZ gradients.
03167         CVector         Gx;
03168         CVector         Gy;
03169         CVector         Gz;
03170         // If VertexProgram activated
03171         if( CLandscapeGlobals::VertexProgramEnabled )
03172         {
03173                 // then Must update geomorphed position because not done !!
03174                 VBase->computeGeomPos();
03175                 VLeft->computeGeomPos();
03176                 VRight->computeGeomPos();
03177         }
03178         // NB: take geomorphed position.
03179         uvTri.computeGradient(VBase->Pos.x, VLeft->Pos.x, VRight->Pos.x, Gx);
03180         uvTri.computeGradient(VBase->Pos.y, VLeft->Pos.y, VRight->Pos.y, Gy);
03181         uvTri.computeGradient(VBase->Pos.z, VLeft->Pos.z, VRight->Pos.z, Gz);
03182 
03183         // Compute interpolated position.
03184         ret= VBase->Pos;
03185         uvPos-= uvTri.V0;
03186         ret.x+= Gx*uvPos;
03187         ret.y+= Gy*uvPos;
03188         ret.z+= Gz*uvPos;
03189 
03190 }

float NL3D::CTessFace::computeTileEMForUpdateRefine float  distSplitPoint,
float  distMinFace,
float  nearLimit
[inline, private]
 

Definition at line 312 of file tessellation.cpp.

References NLMISC::sqr().

Referenced by updateRefineMerge(), and updateRefineSplit().

00313 {
00314         float   ema;
00315         // Normal ErrorMetric simulation.
00316         ema= Size / sqr(distSplitPoint);
00317 
00318         // TileErrorMetric simulation.
00319         if(distMinFace < CLandscapeGlobals::TileDistFar)
00320         {
00321                 // If we are not so subdivided.
00322                 if( ema<nearLimit )
00323                 {
00324                         if( distMinFace< CLandscapeGlobals::TileDistNear)
00325                         {
00326                                 ema= nearLimit;
00327                         }
00328                         else
00329                         {
00330                                 // Smooth transition to the nearLimit of tesselation.
00331                                 float   f= ( CLandscapeGlobals::TileDistFarSqr - sqr(distMinFace) ) * CLandscapeGlobals::OOTileDistDeltaSqr;
00332                                 // sqr gives better result, by smoothing more the start of transition.
00333                                 f= sqr(f);
00334                                 f= sqr(f);
00335                                 ema= ema + (nearLimit-ema)*f;
00336                         }
00337                 }
00338         }
00339 
00340         return ema * CLandscapeGlobals::OORefineThreshold;
00341 }

void NL3D::CTessFace::computeTileErrorMetric  )  [private]
 

Definition at line 234 of file tessellation.cpp.

References computeNearLimit(), NL3D::CTessVertex::EndPos, ErrorMetric, NLMISC::sqr(), VBase, VLeft, and VRight.

Referenced by updateErrorMetric().

00235 {
00236         // We must take a more correct errometric here: We must have sons face which have
00237         // lower projectedsize than father. This is not the case if Center of face is taken (but when not in
00238         // tile mode this is nearly the case). So take the min dist from 3 points.
00239         float   s0= (VBase->EndPos - CLandscapeGlobals::RefineCenter).sqrnorm();
00240         float   s1= (VLeft->EndPos - CLandscapeGlobals::RefineCenter).sqrnorm();
00241         float   s2= (VRight->EndPos - CLandscapeGlobals::RefineCenter).sqrnorm();
00242         float   sqrdist= minof(s0, s1, s2);
00243         // It is also VERY important to take the min of 3, to ensure the split in TileMode when Far1 vertex begin
00244         // to blend (see Patch::renderFar1() render).
00245 
00246         // NB: VertexProgram geomorph take sqrdist= (SplitPoint - RefineCenter).sqrnorm();
00247         // It's OK because geomorph will start "far" after the split.
00248 
00249         if(sqrdist< CLandscapeGlobals::TileDistFarSqr)
00250         {
00251                 float   nearLimit;
00252                 nearLimit= CLandscapeGlobals::RefineThreshold * computeNearLimit();
00253                 // If we are not so subdivided.
00254                 if(ErrorMetric<nearLimit)
00255                 {
00256                         if(sqrdist< CLandscapeGlobals::TileDistNearSqr)
00257                         {
00258                                 ErrorMetric=nearLimit;
00259                         }
00260                         else
00261                         {
00262                                 // Smooth transition to the nearLimit of tesselation.
00263                                 float   f= ( CLandscapeGlobals::TileDistFarSqr - sqrdist ) * CLandscapeGlobals::OOTileDistDeltaSqr;
00264                                 // sqr gives better result, by smoothing more the start of transition.
00265                                 f= sqr(f);
00266                                 f= sqr(f);
00267                                 ErrorMetric= ErrorMetric + (nearLimit-ErrorMetric)*f;
00268 
00269                                 // If threshold is big like 0.5, transition is still hard, and pops occurs. But The goal is 
00270                                 // 0.005 and less, so don't bother. 
00271                         }
00272                 }
00273         }
00274 }

void NL3D::CTessFace::computeTileMaterial  ) 
 

Definition at line 675 of file tessellation.cpp.

References allocTileUv(), buildTileFaces(), checkCreateFillTileVB(), copyTileUv(), FBase, IdUvBase, IdUvLeft, IdUvRight, initTileUvDLM(), initTileUvLightmap(), initTileUvRGBA(), Level, NL3D_MAX_TILE_FACE, NL3D_MAX_TILE_PASS, NL3D_TILE_PASS_ADD, NL3D_TILE_PASS_LIGHTMAP, NL3D_TILE_PASS_RGB0, NL3D_TILE_PASS_RGB1, NL3D_TILE_PASS_RGB2, nlassert, NL3D::CPatch::OrderS, NL3D::CPatch::OrderT, NL3D::CTileMaterial::Pass, Patch, NL3D::CRdrTileId::PatchRdrPass, PVBase, PVLeft, PVRight, NL3D::CParamCoord::S, sint, NL3D::CParamCoord::T, TileFaces, TileId, NL3D::CPatch::TileLimitLevel, NL3D::CRdrTileId::TileMaterial, TileMaterial, NL3D::CTileMaterial::TileS, and NL3D::CTileMaterial::TileT.

Referenced by recreateTileUvs(), and split().

00676 {
00677         // 0. Compute TileId.
00678         //-------------------
00679         // Square Order Patch assumption: assume that when a CTessFace become a tile, his base can ONLY be diagonal...
00680         /* a Patch:
00681                 A ________
00682                 |\      /|
00683                 | \    / |
00684            C|__\B_/  |
00685                 |  /  \  |
00686                 | /    \ |
00687                 |/______\|
00688 
00689                 Here, if OrderS*OrderT=2*2, ABC is a new CTessFace of a Tile, and AB is the diagonal of the tile.
00690                 Hence the middle of the tile is the middle of AB.
00691 
00692                 C must be created, but A and B may be created or copied from neighbor.
00693         */
00694         CParamCoord     middle(PVLeft,PVRight);
00695         sint ts= ((sint)middle.S * (sint)Patch->OrderS) / 0x8000;
00696         sint tt= ((sint)middle.T * (sint)Patch->OrderT) / 0x8000;
00697         TileId= tt*Patch->OrderS + ts;
00698 
00699 
00700         // 1. Compute Tile Material.
00701         //--------------------------
00702         // if base neighbor is already at TileLimitLevel just ptr-copy, else create the TileMaterial...
00703         nlassert(!FBase || FBase->Patch!=Patch || FBase->Level<=Patch->TileLimitLevel);
00704         bool    copyFromBase;
00705         copyFromBase= (FBase && FBase->Patch==Patch);
00706         copyFromBase= copyFromBase && (FBase->Level==Patch->TileLimitLevel && FBase->TileMaterial!=NULL);
00707         // NB: because of delete/recreateTileUvs(), FBase->TileMaterial may be NULL, even if face is at good TileLimitLevel.
00708         if(copyFromBase)
00709         {
00710                 TileMaterial= FBase->TileMaterial;
00711                 nlassert(FBase->TileId== TileId);
00712         }
00713         else
00714         {
00715                 sint    i;
00716                 TileMaterial= Patch->getLandscape()->newTileMaterial();
00717                 TileMaterial->TileS= ts;
00718                 TileMaterial->TileT= tt;
00719 
00720                 // Add this new material to the render list.
00721                 Patch->appendTileMaterialToRenderList(TileMaterial);
00722 
00723                 // First, get a lightmap for this tile. NB: important to do this after appendTileMaterialToRenderList(), 
00724                 // because use TessBlocks.
00725                 Patch->getTileLightMap(ts, tt, TileMaterial->Pass[NL3D_TILE_PASS_LIGHTMAP].PatchRdrPass);
00726 
00727                 // Fill pass of multi pass material.
00728                 for(i=0;i<NL3D_MAX_TILE_PASS;i++)
00729                 {
00730                         // Get the correct render pass, according to the tile number, and the pass.
00731                         if(i!=NL3D_TILE_PASS_LIGHTMAP)
00732                                 TileMaterial->Pass[i].PatchRdrPass= Patch->getTileRenderPass(TileId, i);
00733                 }
00734 
00735                 // Fill Pass Info.
00736                 for(i=0;i<NL3D_MAX_TILE_PASS;i++)
00737                 {
00738                         TileMaterial->Pass[i].TileMaterial= TileMaterial;
00739                 }
00740 
00741                 // Do not append this tile to each RenderPass, done in preRender().
00742         }
00743 
00744 
00745         // 2. Compute Uvs.
00746         //----------------
00747         // NB: TileMaterial is already setup. Usefull for initTileUvLightmap() and initTileUvRGBA().
00748 
00749         // First, must create The TileFaces, according to the TileMaterial passes.
00750         buildTileFaces();
00751 
00752         // Must allocate the Base, and insert into list.
00753         allocTileUv(IdUvBase);
00754 
00755 
00756         // Init LightMap UV, in RGB0 pass, UV1..
00757         initTileUvLightmap(PVBase, middle, TileFaces[NL3D_TILE_PASS_RGB0]->V[IdUvBase]->PUv1);
00758         // Init DLM Uv, in RGB0 pass, UV2.
00759         initTileUvDLM(PVBase, TileFaces[NL3D_TILE_PASS_RGB0]->V[IdUvBase]->PUv2);
00760 
00761         // Init UV RGBA, for all pass (but lightmap).
00762         for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
00763         {
00764                 nlassert(i!=NL3D_TILE_PASS_LIGHTMAP);
00765                 // If pass is valid
00766                 if( TileMaterial->Pass[i].PatchRdrPass)
00767                 {
00768                         // Face must exist.
00769                         nlassert(TileFaces[i]);
00770                         // Compute RGB UV in UV0.
00771                         initTileUvRGBA(i, false, PVBase, middle, TileFaces[i]->V[IdUvBase]->PUv0);
00772                         // If transition tile, compute alpha UV in UV1. 
00773                         // Do it also for Additive, because may have Transition
00774                         if(i== NL3D_TILE_PASS_RGB1 || i==NL3D_TILE_PASS_RGB2 || i==NL3D_TILE_PASS_ADD)
00775                                 initTileUvRGBA(i, true, PVBase, middle, TileFaces[i]->V[IdUvBase]->PUv1);
00776                 }
00777         }
00778 
00779         // UVs are computed, may create and fill VB.
00780         checkCreateFillTileVB(IdUvBase);
00781 
00782 
00783         // if base neighbor is already at TileLimitLevel just ptr-copy, else create the left/right TileUvs...
00784         if(copyFromBase)
00785         {
00786                 // Just cross-copy the pointers.
00787                 // Make Left near vertices be the Right vertices of FBase
00788                 copyTileUv(IdUvLeft, FBase, IdUvRight);
00789                 // Make Right near vertices be the Left vertices of FBase
00790                 copyTileUv(IdUvRight, FBase, IdUvLeft);
00791         }
00792         else
00793         {
00794                 // Must allocate the left/right uv (and insert into list).
00795                 allocTileUv(IdUvLeft);
00796                 allocTileUv(IdUvRight);
00797 
00798 
00799                 // Init LightMap UV, in UvPass 0, UV1..
00800                 initTileUvLightmap(PVLeft, middle, TileFaces[NL3D_TILE_PASS_RGB0]->V[IdUvLeft]->PUv1);
00801                 initTileUvLightmap(PVRight, middle, TileFaces[NL3D_TILE_PASS_RGB0]->V[IdUvRight]->PUv1);
00802                 // Init DLM Uv, in RGB0 pass, UV2.
00803                 initTileUvDLM(PVLeft, TileFaces[NL3D_TILE_PASS_RGB0]->V[IdUvLeft]->PUv2);
00804                 initTileUvDLM(PVRight, TileFaces[NL3D_TILE_PASS_RGB0]->V[IdUvRight]->PUv2);
00805 
00806                 // Init UV RGBA!
00807                 for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
00808                 {
00809                         nlassert(i!=NL3D_TILE_PASS_LIGHTMAP);
00810                         // If pass is valid
00811                         if(TileMaterial->Pass[i].PatchRdrPass)
00812                         {
00813                                 // Face must exist.
00814                                 nlassert(TileFaces[i]);
00815                                 // Compute RGB UV in UV0.
00816                                 initTileUvRGBA(i, false, PVLeft, middle, TileFaces[i]->V[IdUvLeft]->PUv0);
00817                                 initTileUvRGBA(i, false, PVRight, middle, TileFaces[i]->V[IdUvRight]->PUv0);
00818                                 // If transition tile, compute alpha UV in UV1.
00819                                 // Do it also for Additive, because may have Transition
00820                                 if(i== NL3D_TILE_PASS_RGB1 || i==NL3D_TILE_PASS_RGB2 || i==NL3D_TILE_PASS_ADD)
00821                                 {
00822                                         initTileUvRGBA(i, true, PVLeft, middle, TileFaces[i]->V[IdUvLeft]->PUv1);
00823                                         initTileUvRGBA(i, true, PVRight, middle, TileFaces[i]->V[IdUvRight]->PUv1);
00824                                 }
00825                         }
00826                 }
00827 
00828                 // UVs are computed, may create and fill VB.
00829                 checkCreateFillTileVB(IdUvLeft);
00830                 checkCreateFillTileVB(IdUvRight);
00831         }
00832 
00833 }

void NL3D::CTessFace::copyTileUv TTileUvId  id,
CTessFace srcFace,
TTileUvId  srcId
[private]
 

Definition at line 466 of file tessellation.cpp.

References NL3D_MAX_TILE_FACE, NL3D_TILE_PASS_RGB0, nlassert, sint, TileFaces, and NL3D::CTileFace::V.

Referenced by computeTileMaterial(), and heritTileMaterial().

00467 {
00468         // TileFaces must have been build.
00469         nlassert(TileFaces[NL3D_TILE_PASS_RGB0]);
00470 
00471         // Since this a ptr-copy, no need to add/remove the renderlist of near vertices.
00472 
00473         for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
00474         {
00475                 if(TileFaces[i])
00476                 {
00477                         // The srcface should have the same tileFaces enabled.
00478                         nlassert(srcFace->TileFaces[i]);
00479 
00480                         // copy from src.
00481                         CTessNearVertex         *copyNear;
00482                         copyNear= srcFace->TileFaces[i]->V[srcId];
00483 
00484                         // copy to dst.
00485                         TileFaces[i]->V[dstId]=  copyNear;
00486                 }
00487         }
00488 }

void NL3D::CTessFace::deleteTileFaces  )  [private]
 

Definition at line 528 of file tessellation.cpp.

References NL3D::CLandscape::deleteTileFace(), NL3D::CPatch::getLandscape(), NL3D_MAX_TILE_FACE, nlassert, NL3D::CTileMaterial::Pass, NL3D::CRdrTileId::PatchRdrPass, sint, and TileFaces.

Referenced by deleteTileUvs(), doMerge(), and releaseTileMaterial().

00529 {
00530         nlassert(TileMaterial);
00531 
00532         // Do nothgin for lightmap pass, of course.
00533         for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
00534         {
00535                 if(TileMaterial->Pass[i].PatchRdrPass)
00536                 {
00537                         nlassert(TileFaces[i]);
00538                         Patch->getLandscape()->deleteTileFace(TileFaces[i]);
00539                         TileFaces[i]= NULL;
00540                 }
00541                 else
00542                 {
00543                         nlassert(TileFaces[i]==NULL);
00544                 }
00545         }
00546 }

void NL3D::CTessFace::deleteTileUv TTileUvId  id  )  [private]
 

Definition at line 444 of file tessellation.cpp.

References NL3D::CPatch::checkDeleteVertexVBNear(), NL3D::CLandscape::deleteTessNearVertex(), NL3D::CPatch::getLandscape(), NL3D_MAX_TILE_FACE, NL3D_TILE_PASS_RGB0, nlassert, NL3D::CPatch::removeNearVertexFromRenderList(), sint, TileFaces, and NL3D::CTileFace::V.

Referenced by deleteTileUvs(), doMerge(), and releaseTileMaterial().

00445 {
00446         // TileFaces must still exist.
00447         nlassert(TileFaces[NL3D_TILE_PASS_RGB0]);
00448 
00449         for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
00450         {
00451                 if(TileFaces[i])
00452                 {
00453                         CTessNearVertex         *oldNear;
00454                         oldNear= TileFaces[i]->V[id];
00455                         TileFaces[i]->V[id]=NULL;
00456 
00457                         // May delete this vertex from VB.
00458                         Patch->checkDeleteVertexVBNear(oldNear);
00459 
00460                         Patch->removeNearVertexFromRenderList(TileMaterial, oldNear);
00461                         Patch->getLandscape()->deleteTessNearVertex(oldNear);
00462                 }
00463         }
00464 }

void NL3D::CTessFace::deleteTileUvs  ) 
 

Definition at line 2969 of file tessellation.cpp.

References deleteTileFaces(), deleteTileUv(), emptyTileFaces(), FBase, IdUvBase, isLeaf(), Level, nlassert, releaseTileMaterial(), NL3D::CPatch::removeFaceFromTileRenderList(), sameTile(), SonLeft, SonRight, NL3D::CPatch::TileLimitLevel, and TileMaterial.

Referenced by NL3D::CPatch::deleteTileUvs().

02970 {
02971         // NB: NearVertices are removed from renderlist with deleteTileUv (called in releaseTileMaterial()).
02972 
02973         if(!isLeaf())
02974         {
02975                 // Must delete the materials of leaves first.
02976                 SonLeft->deleteTileUvs();
02977                 SonRight->deleteTileUvs();
02978                 if(SonLeft->Level== Patch->TileLimitLevel)
02979                 {
02980                         // Square patch assumption: the sons are not of the same TileId/Patch.
02981                         nlassert(!sameTile(SonLeft, SonRight));
02982                         // release tiles.
02983                         SonLeft->releaseTileMaterial();
02984                         SonRight->releaseTileMaterial();
02985                 }
02986                 else if(SonLeft->Level > Patch->TileLimitLevel)
02987                 {
02988                         nlassert(!FBase || !FBase->isLeaf());
02989 
02990                         // Delete Uv, only if not already done by the neighbor (ie neighbor has yet TileFaces!!).
02991                         // But Always delete if neighbor exist and has not same tile as me.
02992                         // NB: this work with rectangular neigbor patch, since sameTile() will return false if different patch.
02993                         if(!FBase || !FBase->SonLeft->emptyTileFaces() || !sameTile(this, FBase))
02994                         {
02995                                 SonLeft->deleteTileUv(IdUvBase);
02996                         }
02997                         // In all case, must delete the tilefaces of those face.
02998                         SonLeft->deleteTileFaces();
02999                         SonRight->deleteTileFaces();
03000                         // For createTileUvs, it is important to mark those faces as NO TileMaterial.
03001                         SonLeft->TileMaterial= NULL;
03002                         SonRight->TileMaterial= NULL;
03003                 }
03004         }
03005         else
03006         {
03007                 // NB: this is done always BELOW tile creation (see above).
03008                 // Do this only for tiles.
03009                 if(TileMaterial)
03010                         Patch->removeFaceFromTileRenderList(this);
03011         }
03012 
03013 }

void NL3D::CTessFace::doMerge  )  [private]
 

Definition at line 1604 of file tessellation.cpp.

References NL3D::CLandscape::_MergePriorityList, NL3D::CLandscape::_SplitPriorityList, NL3D::CPatch::appendFaceToRenderList(), changeNeighbor(), NL3D::CPatch::checkDeleteVertexVBFar(), NL3D::CLandscape::deleteTessFace(), NL3D::CLandscape::deleteTessFarVertex(), NL3D::CLandscape::deleteTessVertex(), deleteTileFaces(), deleteTileUv(), FBase, FLeft, FRight, FVBase, NL3D::CPatch::getLandscape(), IdUvBase, NL3D::CTessFacePriorityList::insert(), isLeaf(), isRectangular(), Level, nlassert, Patch, releaseTileMaterial(), NL3D::CPatch::removeFaceFromRenderList(), NL3D::CPatch::removeFarVertexFromRenderList(), sameTile(), SonLeft, SonRight, NL3D::CPatch::TileLimitLevel, and VBase.

Referenced by merge().

01605 {
01606         // Assume that canMerge() return true.
01607         // And Assume that !isLeaf().
01608         nlassert(!isLeaf());
01609 
01610         if(!isRectangular())
01611         {
01612                 // 1. Let's merge vertex.
01613                 //-----------------------
01614                 // Delete vertex, only if not already done by the neighbor (ie neighbor not already merged to a leaf).
01615                 // NB: this work even if neigbor is rectnagular.
01616                 if(!FBase || !FBase->isLeaf())
01617                         Patch->getLandscape()->deleteTessVertex(SonLeft->VBase);
01618 
01619                 // Delete Far Vertex. Idem, but test too if != patch...
01620                 if(!FBase || !FBase->isLeaf() || FBase->Patch!=Patch)
01621                 {
01622                         // May delete this vertex from VB.
01623                         Patch->checkDeleteVertexVBFar(SonLeft->FVBase);
01624 
01625                         Patch->removeFarVertexFromRenderList(SonLeft->FVBase);
01626                         Patch->getLandscape()->deleteTessFarVertex(SonLeft->FVBase);
01627                 }
01628 
01629 
01630                 // 2. Must remove sons from rdr list, and insert father.
01631                 //------------------------------------------------------
01632                 // Must do it BEFORE the TileFaces are released.
01633                 // UGLY REFCOUNT SIDE EFFECT: do the append first.
01634                 Patch->appendFaceToRenderList(this);
01635                 Patch->removeFaceFromRenderList(SonLeft);
01636                 Patch->removeFaceFromRenderList(SonRight);
01637 
01638                 
01639                 // 3. Let's merge Uv.
01640                 //-------------------
01641                 // Delete Uv.
01642                 // Must do it for this and FBase separately, since they may not have same tile level (if != patch).
01643                 if(SonLeft->Level== Patch->TileLimitLevel)
01644                 {
01645                         // Square patch assumption: the sons are not of the same TileId/Patch.
01646                         nlassert(!sameTile(SonLeft, SonRight));
01647                         // release tiles: NearVertices, TileFaces, and TileMaterial.
01648                         SonLeft->releaseTileMaterial();
01649                         SonRight->releaseTileMaterial();
01650                 }
01651                 else if(SonLeft->Level > Patch->TileLimitLevel)
01652                 {
01653                         // Delete Uv, only if not already done by the neighbor (ie neighbor not already merged to a leaf).
01654                         // But Always delete if neighbor exist and has not same tile as me.
01655                         // NB: this work with rectangular neigbor patch, since sameTile() will return false if different patch.
01656                         if(!FBase || !FBase->isLeaf() || !sameTile(this, FBase))
01657                         {
01658                                 SonLeft->deleteTileUv(IdUvBase);
01659                         }
01660                         // In all case, must delete the tilefaces of those face.
01661                         SonLeft->deleteTileFaces();
01662                         SonRight->deleteTileFaces();
01663                 }
01664 
01665 
01666                 // 4. Let's merge Face.
01667                 //-------------------
01668                 // Change father 's neighbor pointers.
01669                 FLeft= SonLeft->FBase;
01670                 if(FLeft)       FLeft->changeNeighbor(SonLeft, this);
01671                 FRight= SonRight->FBase;
01672                 if(FRight)      FRight->changeNeighbor(SonRight, this);
01673                 // delete sons.
01674                 Patch->getLandscape()->deleteTessFace(SonLeft);
01675                 Patch->getLandscape()->deleteTessFace(SonRight);
01676                 SonLeft=NULL;
01677                 SonRight=NULL;
01678 
01679                 // If not already done, merge the neighbor.
01680                 if(FBase!=NULL && !FBase->isLeaf())
01681                 {
01682                         FBase->doMerge();
01683                 }
01684 
01685         }
01686         else
01687         {
01688                 // Rectangular case.
01689                 // Since minimum Order is 2, Sons of rectangular face are NEVER at TileLimitLevel. => no Uv merge to do.
01690                 nlassert(SonLeft->Level< Patch->TileLimitLevel);
01691                 nlassert(FBase);
01692 
01693                 // 1. Let's merge vertex.
01694                 //-----------------------
01695                 // Delete vertex, only if not already done by the neighbor (ie neighbor not already merged to a leaf).
01696                 // NB: this work even if neigbor is rectangular (see tesselation rules in splitRectangular()).
01697                 if(!FLeft || !FLeft->isLeaf())
01698                         Patch->getLandscape()->deleteTessVertex(SonLeft->VBase);
01699 
01700                 // Delete Far Vertex. Rect patch: neightb must be of a != pathc as me => must delete FarVertex.
01701                 nlassert(!FLeft || FLeft->Patch!=Patch);
01702                 // May delete this vertex from VB.
01703                 Patch->checkDeleteVertexVBFar(SonLeft->FVBase);
01704 
01705                 Patch->removeFarVertexFromRenderList(SonLeft->FVBase);
01706                 Patch->getLandscape()->deleteTessFarVertex(SonLeft->FVBase);
01707 
01708 
01709                 // 2. Must remove sons from rdr list, and insert father.
01710                 //------------------------------------------------------
01711                 // UGLY REFCOUNT SIDE EFFECT: do the append first.
01712                 Patch->appendFaceToRenderList(this);
01713                 Patch->removeFaceFromRenderList(SonLeft);
01714                 Patch->removeFaceFromRenderList(SonRight);
01715 
01716 
01717                 // 3. Let's merge Face.
01718                 //-------------------
01719                 // Change father 's neighbor pointers (see splitRectangular()).
01720                 FRight= SonRight->FRight;
01721                 if(FRight)      FRight->changeNeighbor(SonRight, this);
01722                 // delete sons.
01723                 Patch->getLandscape()->deleteTessFace(SonLeft);
01724                 Patch->getLandscape()->deleteTessFace(SonRight);
01725                 SonLeft=NULL;
01726                 SonRight=NULL;
01727 
01728                 // First, do it for my rectangular co-worker FBase (if not already done).
01729                 if(!FBase->isLeaf())
01730                 {
01731                         FBase->doMerge();
01732                 }
01733                 // If not already done, merge the neighbor.
01734                 if(FLeft!=NULL && !FLeft->isLeaf())
01735                 {
01736                         FLeft->doMerge();
01737                 }
01738         }
01739 
01740 
01741         // Update priority list.
01742         //------------------------------------------------------
01743         // Since we are freshly merged, unlink from any list, and link to the SplitPriorityList, because must look 
01744         // now when we should split again.
01745         Patch->getLandscape()->_SplitPriorityList.insert(0, 0, this);
01746 
01747         // since we are now merged maybe re-insert father in priority list.
01748         if(Father)
01749         {
01750                 nlassert(!Father->isLeaf());
01751                 // If sons of father are both leaves (ie this, and the other (complexe case if rectangle) )
01752                 if( Father->SonLeft->isLeaf() && Father->SonRight->isLeaf() )
01753                 {
01754                         Patch->getLandscape()->_MergePriorityList.insert(0, 0, Father);
01755                 }
01756         }
01757 
01758 }

bool NL3D::CTessFace::emptyTileFaces  )  [private]
 

Definition at line 549 of file tessellation.cpp.

References NL3D_MAX_TILE_FACE, sint, and TileFaces.

Referenced by deleteTileUvs().

00550 {
00551         // Do nothgin for lightmap pass, of course.
00552         for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
00553         {
00554                 // Some TileFace exist??
00555                 if(TileFaces[i])
00556                         return false;
00557         }
00558 
00559         return true;
00560 }

void NL3D::CTessFace::forceMerge  ) 
 

Definition at line 2412 of file tessellation.cpp.

References CantMergeFace, FBase, FLeft, isLeaf(), isRectangular(), merge(), RecursMarkForceMerge, SonLeft, and SonRight.

Referenced by forceMergeAtTileLevel(), and NL3D::CPatch::unbind().

02413 {
02414         if(this== &CantMergeFace)
02415                 return;
02416 
02417         if(!isLeaf())
02418         {
02419                 // First, force merge of Sons and neighbor sons, to have a diamond configuration.
02420                 SonLeft->forceMerge();
02421                 SonRight->forceMerge();
02422 
02423                 // forceMerge of necessary neighbors.
02424                 RecursMarkForceMerge=true;
02425                 if(!isRectangular())
02426                 {
02427                         if(FBase && !FBase->RecursMarkForceMerge)
02428                                 FBase->forceMerge();
02429                 }
02430                 else
02431                 {
02432                         // Rectangular case. May have a longer propagation...
02433                         if(FBase && !FBase->RecursMarkForceMerge)
02434                                 FBase->forceMerge();
02435                         if(FLeft && !FLeft->RecursMarkForceMerge)
02436                                 FLeft->forceMerge();
02437                 }
02438                 RecursMarkForceMerge=false;
02439 
02440                 // If still a parent, merge.
02441                 if(!isLeaf())
02442                         merge();
02443         }
02444 }

void NL3D::CTessFace::forceMergeAtTileLevel  ) 
 

Definition at line 2448 of file tessellation.cpp.

References CantMergeFace, forceMerge(), isLeaf(), SonLeft, SonRight, and NL3D::CPatch::TileLimitLevel.

Referenced by NL3D::CPatch::forceMergeAtTileLevel().

02449 {
02450         if(this== &CantMergeFace)
02451                 return;
02452 
02453         if(!isLeaf())
02454         {
02455                 SonLeft->forceMergeAtTileLevel();
02456                 SonRight->forceMergeAtTileLevel();
02457         }
02458         else
02459         {
02460                 // If we are at tile subdivision, we must force our sons to merge.
02461                 if(Level==Patch->TileLimitLevel)
02462                         forceMerge();
02463         }
02464 }

void NL3D::CTessFace::getTesselatedPos const CUV uv,
bool  verifInclusion,
CVector ret
 

Definition at line 3101 of file tessellation.cpp.

References computeTesselatedPos(), NL3D::CParamCoord::getS(), NL3D::CParamCoord::getT(), isLeaf(), isRectangular(), PVBase, PVLeft, PVRight, NLMISC::CVector::set(), sint, SonLeft, SonRight, NLMISC::CUV::U, NLMISC::CUV::V, NLMISC::CVector::x, and NLMISC::CVector::y.

Referenced by NL3D::CPatch::getTesselatedPos().

03102 {
03103         CVector         uvPos(uv.U, uv.V, 0);
03104 
03105         // may verif if uv is In this triangle. supposed true if rectangular branch.
03106         if(verifInclusion && !(isRectangular() && !isLeaf()) )
03107         {
03108                 CVector         uvs[3];
03109                 uvs[0].set( PVBase.getS(), PVBase.getT(), 0);
03110                 uvs[1].set( PVLeft.getS(), PVLeft.getT(), 0);
03111                 uvs[2].set( PVRight.getS(), PVRight.getT(), 0);
03112                 for(sint i=0; i<3; i++)
03113                 {
03114                         CVector         dUv= uvs[(i+1)%3] - uvs[i];
03115                         CVector         normalUv(dUv.y, -dUv.x, 0);
03116                         // if out this 2D plane, uv is out this triangle
03117                         if(normalUv * (uvPos-uvs[i]) <0)
03118                                 return;
03119                 }
03120         }
03121 
03122         // compute tesselated pos in this face.
03123         if(isLeaf())
03124                 // ok, no more sons, let's do it.
03125                 computeTesselatedPos(uv, ret);
03126         else
03127         {
03128                 // must subdivide.
03129                 // if we are rectangular (strange tesselation), must test in both leaves, else, choose only one.
03130                 if(isRectangular())
03131                 {
03132                         SonLeft->getTesselatedPos(uv, true, ret);
03133                         SonRight->getTesselatedPos(uv, true, ret);
03134                 }
03135                 else
03136                 {
03137                         // Compute the uv plane which separate the 2 leaves.
03138                         CVector         uvBase, uvMiddle;
03139                         uvBase.set  ( PVBase.getS(), PVBase.getT(), 0);
03140                         uvMiddle.set( SonLeft->PVBase.getS(), SonLeft->PVBase.getT(), 0);
03141                         CVector         dUv= uvMiddle - uvBase;
03142                         CVector         normalUv(dUv.y, -dUv.x, 0);
03143                         // choose what leaf to recurs.
03144                         if(normalUv * (uvPos - uvBase) <0)
03145                                 SonLeft->getTesselatedPos(uv, false, ret);
03146                         else
03147                                 SonRight->getTesselatedPos(uv, false, ret);
03148 
03149                 }
03150         }
03151 
03152 }

bool NL3D::CTessFace::hasEdge CTessVertex v0,
CTessVertex v1
const [inline]
 

Definition at line 297 of file tessellation.h.

References hasVertex().

00297 {return hasVertex(v0) && hasVertex(v1);}

bool NL3D::CTessFace::hasVertex CTessVertex v  )  const [inline]
 

Definition at line 296 of file tessellation.h.

References v, VBase, VLeft, and VRight.

Referenced by hasEdge().

00296 {return VBase==v || VLeft==v || VRight==v;}

void NL3D::CTessFace::heritTileMaterial  )  [private]
 

Definition at line 3053 of file tessellation.cpp.

References allocTileUv(), buildTileFaces(), checkCreateFillTileVB(), copyTileUv(), FBase, heritTileUv(), IdUvBase, IdUvLeft, IdUvRight, isLeaf(), sameTile(), SonLeft, SonRight, TileId, and TileMaterial.

Referenced by recreateTileUvs(), and split().

03054 {
03055         SonLeft->TileMaterial= TileMaterial;
03056         SonLeft->TileId= TileId;
03057         SonLeft->buildTileFaces();
03058         SonLeft->copyTileUv(IdUvLeft, this, IdUvBase);
03059         SonLeft->copyTileUv(IdUvRight, this, IdUvLeft);
03060 
03061         SonRight->TileMaterial= TileMaterial;
03062         SonRight->TileId= TileId;
03063         SonRight->buildTileFaces();
03064         SonRight->copyTileUv(IdUvLeft, this, IdUvRight);
03065         SonRight->copyTileUv(IdUvRight, this, IdUvBase);
03066 
03067         // Create, or link to the tileUv.
03068         // Try to link to a neighbor TileUv.
03069         // Can only work iff exist, and iff FBase is same patch, and same TileId.
03070         if(FBase!=NULL && !FBase->isLeaf() && FBase->SonLeft->TileMaterial!=NULL && sameTile(this, FBase) )
03071         {
03072                 // Ok!! link to the (existing) TileUv.
03073                 // FBase->SonLeft!=NULL since FBase->isLeaf()==false.
03074                 SonLeft->copyTileUv(IdUvBase, FBase->SonLeft, IdUvBase);
03075                 SonRight->copyTileUv(IdUvBase, FBase->SonLeft, IdUvBase);
03076         }
03077         else
03078         {
03079                 // Allocate a new vertex, and copy it to SonLeft and SonRight.
03080                 SonLeft->allocTileUv(IdUvBase);
03081                 SonRight->copyTileUv(IdUvBase, SonLeft, IdUvBase);
03082 
03083                 // Fill the new near vertex, with middle of Left/Right father.
03084                 SonLeft->heritTileUv(this);
03085 
03086                 // UVs are computed, may create and fill VB.
03087                 SonLeft->checkCreateFillTileVB(IdUvBase);
03088         }
03089 
03090 }

void NL3D::CTessFace::heritTileUv CTessFace baseFace  )  [private]
 

Definition at line 490 of file tessellation.cpp.

References IdUvBase, IdUvLeft, IdUvRight, NL3D::CTessNearVertex::initMiddleUv(), NL3D_MAX_TILE_FACE, NL3D_TILE_PASS_RGB0, nlassert, sint, TileFaces, and NL3D::CTileFace::V.

Referenced by heritTileMaterial().

00491 {
00492         // TileFaces must have been build.
00493         nlassert(TileFaces[NL3D_TILE_PASS_RGB0]);
00494 
00495         for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
00496         {
00497                 if(TileFaces[i])
00498                 {
00499                         // The baseface should have the same tileFaces enabled.
00500                         nlassert(baseFace->TileFaces[i]);
00501                         // VBase should be allocated.
00502                         nlassert(TileFaces[i]->V[IdUvBase]);
00503                         TileFaces[i]->V[IdUvBase]->initMiddleUv(
00504                                 *baseFace->TileFaces[i]->V[IdUvLeft], *baseFace->TileFaces[i]->V[IdUvRight]);
00505                 }
00506         }
00507 }

void NL3D::CTessFace::initTileUvDLM CParamCoord  pointCoord,
CUV uv
[private]
 

Definition at line 655 of file tessellation.cpp.

References NL3D::CPatch::_DLMContext, NL3D::CPatchDLMContext::DLMUBias, NL3D::CPatchDLMContext::DLMUScale, NL3D::CPatchDLMContext::DLMVBias, NL3D::CPatchDLMContext::DLMVScale, NL3D::CParamCoord::getS(), NL3D::CParamCoord::getT(), nlassert, NLMISC::CUV::U, and NLMISC::CUV::V.

Referenced by computeTileMaterial().

00656 {
00657         // get the dlm context from the patch.
00658         CPatchDLMContext        *dlmCtx= Patch->_DLMContext;
00659         // mmust exist at creation of the tile.
00660         nlassert(dlmCtx);
00661 
00662         // get coord in 0..1 range, along the patch.
00663         uv.U= pointCoord.getS();
00664         uv.V= pointCoord.getT();
00665 
00666         // ScaleBias according to the context.
00667         uv.U*= dlmCtx->DLMUScale;
00668         uv.V*= dlmCtx->DLMVScale;
00669         uv.U+= dlmCtx->DLMUBias;
00670         uv.V+= dlmCtx->DLMVBias;
00671 }

void NL3D::CTessFace::initTileUvLightmap CParamCoord  pointCoord,
CParamCoord  middleCoord,
CUV uv
[private]
 

Definition at line 636 of file tessellation.cpp.

References NL3D::CPatch::getTileLightMapUvInfo(), NL3D::CParamCoord::S, NL3D::CParamCoord::T, NL3D::CTileMaterial::TileS, NL3D::CTileMaterial::TileT, NLMISC::CUV::U, NLMISC::CUV::V, NLMISC::CVector::x, NLMISC::CVector::y, and NLMISC::CVector::z.

Referenced by computeTileMaterial().

00637 {
00638         // Get good coordinate according to patch orientation.
00639         uv.U= pointCoord.S<=middle.S? 0.0f: 1.0f;
00640         uv.V= pointCoord.T<=middle.T? 0.0f: 1.0f;
00641         
00642         // Get Tile Lightmap Uv info: bias and scale.
00643         CVector         uvScaleBias;
00644         Patch->getTileLightMapUvInfo(TileMaterial->TileS, TileMaterial->TileT, uvScaleBias);
00645 
00646         // Scale the UV.
00647         uv.U*= uvScaleBias.z;
00648         uv.V*= uvScaleBias.z;
00649         uv.U+= uvScaleBias.x;
00650         uv.V+= uvScaleBias.y;
00651 }

void NL3D::CTessFace::initTileUvRGBA sint  pass,
bool  alpha,
CParamCoord  pointCoord,
CParamCoord  middleCoord,
CUV uv
[private]
 

Definition at line 565 of file tessellation.cpp.

References alpha, NL3D::CPatch::getTileUvInfo(), NL3D::CParamCoord::S, sint, NL3D::CParamCoord::T, TileId, NLMISC::CUV::U, uint8, v, NLMISC::CUV::V, NLMISC::CVector::x, NLMISC::CVector::y, and NLMISC::CVector::z.

Referenced by computeTileMaterial().

00566 {
00567         // Get good coordinate according to patch orientation.
00568         uv.U= pointCoord.S<=middle.S? 0.0f: 1.0f;
00569         uv.V= pointCoord.T<=middle.T? 0.0f: 1.0f;
00570         
00571         // Get Tile Uv info: orientation and scale.
00572         uint8           orient;
00573         CVector         uvScaleBias;
00574         bool            is256;
00575         uint8           uvOff;
00576         Patch->getTileUvInfo(TileId, pass, alpha, orient, uvScaleBias, is256, uvOff);
00577 
00578         // Orient the UV.
00579         float   u= uv.U;
00580         float   v= uv.V;
00581         // Speed rotation.
00582         switch(orient)
00583         {
00584                 case 0: 
00585                         uv.U= u;
00586                         uv.V= v;
00587                         break;
00588                 case 1: 
00589                         uv.U= 1-v;
00590                         uv.V= u;
00591                         break;
00592                 case 2: 
00593                         uv.U= 1-u;
00594                         uv.V= 1-v;
00595                         break;
00596                 case 3: 
00597                         uv.U= v;
00598                         uv.V= 1-u;
00599                         break;
00600         }
00601 
00602         // Do the 256x256.
00603         if(is256)
00604         {
00605                 uv*= 0.5;
00606                 if(uvOff==2 || uvOff==3)
00607                         uv.U+= 0.5;
00608                 if(uvOff==1 || uvOff==2)
00609                         uv.V+= 0.5;
00610         }
00611 
00612 
00613         // Do the HalfPixel scale bias.
00614         float   hBiasXY, hBiasZ;
00615         if(is256)
00616         {
00617                 hBiasXY= CLandscapeGlobals::TilePixelBias256;
00618                 hBiasZ = CLandscapeGlobals::TilePixelScale256;
00619         }
00620         else
00621         {
00622                 hBiasXY= CLandscapeGlobals::TilePixelBias128;
00623                 hBiasZ = CLandscapeGlobals::TilePixelScale128;
00624         }
00625 
00626 
00627         // Scale the UV.
00628         uv.U*= uvScaleBias.z*hBiasZ;
00629         uv.V*= uvScaleBias.z*hBiasZ;
00630         uv.U+= uvScaleBias.x+hBiasXY;
00631         uv.V+= uvScaleBias.y+hBiasXY;
00632 }

bool NL3D::CTessFace::isLeaf  )  const [inline]
 

Definition at line 294 of file tessellation.h.

References SonLeft.

Referenced by appendTessellationLeaves(), averageTesselationVertices(), NL3D::CPatch::bind(), canMerge(), deleteTileUvs(), doMerge(), forceMerge(), forceMergeAtTileLevel(), getTesselatedPos(), heritTileMaterial(), linkTessFaceWithEdge(), merge(), recreateTileUvs(), refineAll(), refreshTesselationGeometry(), NL3D::CPatch::release(), split(), splitRectangular(), unbind(), NL3D::CPatch::unbind(), updateBind(), updateBindAndSplit(), updateBindEdge(), updateRefineMerge(), and updateRefineSplit().

00294 {return SonLeft==NULL;}

bool NL3D::CTessFace::isRectangular  )  const
 

Definition at line 2954 of file tessellation.cpp.

References NL3D::CPatch::SquareLimitLevel.

Referenced by averageTesselationVertices(), canMerge(), computeSplitPoint(), doMerge(), forceMerge(), getTesselatedPos(), split(), splitRectangular(), unbind(), updateBindAndSplit(), and updateBindEdge().

02955 {
02956         return Level<Patch->SquareLimitLevel;
02957 }

void NL3D::CTessFacePListNode::linkInPList CTessFacePListNode root  )  [inherited]
 

unlinkInPList, then link this node to the root of a list.

Definition at line 49 of file tess_face_priority_list.cpp.

References NL3D::CTessFacePListNode::_NextTessFaceInPList, and NL3D::CTessFacePListNode::_PrecTessFaceInPList.

Referenced by NL3D::CLandscape::newTessFace().

00050 {
00051         // unlink old list from me.
00052         _PrecTessFaceInPList->_NextTessFaceInPList= _NextTessFaceInPList;
00053         _NextTessFaceInPList->_PrecTessFaceInPList= _PrecTessFaceInPList;
00054 
00055         // link me to the list.
00056         _PrecTessFaceInPList= &root;
00057         _NextTessFaceInPList= root._NextTessFaceInPList;
00058         // link the list to me.
00059         root._NextTessFaceInPList->_PrecTessFaceInPList= this;
00060         root._NextTessFaceInPList= this;
00061         /*
00062                 NB if list was empty (this, this), then
00063                         _PrecTessFaceInPList= &root
00064                         _NextTessFaceInPList= root._NextTessFaceInPList= &root !
00065                         root._NextTessFaceInPList->_PrecTessFaceInPList= this;  => root._PrecTessFaceInPList= this
00066                         root._NextTessFaceInPList= this
00067         */
00068 }

CTessFace * NL3D::CTessFace::linkTessFaceWithEdge const NLMISC::CVector2f uv0,
const NLMISC::CVector2f uv1,
CTessFace linkTo
 

Definition at line 2904 of file tessellation.cpp.

References FBase, FLeft, FRight, NL3D::CParamCoord::getS(), NL3D::CParamCoord::getT(), isLeaf(), NL3D::matchEdge(), nlassert, PVBase, PVLeft, PVRight, SonLeft, and SonRight.

Referenced by NL3D::CPatch::linkTessFaceWithEdge().

02905 {
02906         // Compute 0,1 coords of 3 patch coords.
02907         CVector2f       vb( PVBase.getS(), PVBase.getT() );
02908         CVector2f       vl( PVLeft.getS(), PVLeft.getT() );
02909         CVector2f       vr( PVRight.getS(), PVRight.getT() );
02910 
02911         // Search if one of the 3 edges of this triangle match the wanted edge.
02912         // Base Edge
02913         if(matchEdge(uv0, uv1, vl, vr))
02914         {
02915                 // If leaf, check if unbound (else ptr is invalid)
02916                 nlassert(FBase==NULL || !isLeaf());
02917                 FBase= linkTo;
02918                 return this;
02919         }
02920         // Left Edge
02921         if(matchEdge(uv0, uv1, vb, vl))
02922         {
02923                 // If leaf, check if unbound (else ptr is invalid)
02924                 nlassert(FLeft==NULL || !isLeaf());
02925                 FLeft= linkTo;
02926                 return this;
02927         }
02928         // Right Edge
02929         if(matchEdge(uv0, uv1, vb, vr))
02930         {
02931                 // If leaf, check if unbound (else ptr is invalid)
02932                 nlassert(FRight==NULL || !isLeaf());
02933                 FRight= linkTo;
02934                 return this;
02935         }
02936 
02937 
02938         // If not found here, recurs to children
02939         CTessFace       *ret= NULL;
02940         if( !isLeaf() )
02941         {
02942                 ret= SonLeft->linkTessFaceWithEdge(uv0, uv1, linkTo);
02943                 // if no found in this branch, recusr right branch.
02944                 if(!ret)
02945                         ret= SonRight->linkTessFaceWithEdge(uv0, uv1, linkTo);
02946         }
02947         
02948         // return the result from subBranchs
02949         return ret;
02950 }

bool NL3D::CTessFace::merge  ) 
 

Definition at line 1762 of file tessellation.cpp.

References canMerge(), doMerge(), isLeaf(), NL3D_PROFILE_LAND_ADD, nlassert, and NL3D::ProfNMerges.

Referenced by forceMerge(), refineAll(), and updateRefineMerge().

01763 {
01764         // Must not be a leaf.
01765         nlassert(!isLeaf());
01766 
01767         // 0. Verify if merge is posible.
01768         //----------------------------
01769         if(!canMerge(false))
01770                 return false;
01771 
01772         NL3D_PROFILE_LAND_ADD(ProfNMerges, 1);
01773 
01774         // 1. Let's merge the face.
01775         //-----------------------
01776         // Propagation is done in doMerge().
01777         doMerge();
01778 
01779         return true;
01780 }

CTessFacePListNode* NL3D::CTessFacePListNode::nextInPList  )  const [inline, inherited]
 

Definition at line 84 of file tess_face_priority_list.h.

References NL3D::CTessFacePListNode::_NextTessFaceInPList.

Referenced by NL3D::CTessFacePriorityList::CRollingTable::clearRollTableEntry(), and NL3D::CLandscape::refine().

00084 {return _NextTessFaceInPList;}

CTessFacePListNode* NL3D::CTessFacePListNode::precInPList  )  const [inline, inherited]
 

get next ptr. next==this if list empty.

Definition at line 83 of file tess_face_priority_list.h.

References NL3D::CTessFacePListNode::_PrecTessFaceInPList.

00083 {return _PrecTessFaceInPList;}

void NL3D::CTessFace::recreateTileUvs  ) 
 

Definition at line 3017 of file tessellation.cpp.

References NL3D::CPatch::appendFaceToTileRenderList(), computeTileMaterial(), heritTileMaterial(), isLeaf(), Level, SonLeft, SonRight, and NL3D::CPatch::TileLimitLevel.

Referenced by NL3D::CPatch::recreateTileUvs().

03018 {
03019         // NB: NearVertices are append to renderlist with allocTileUv (called in computeTileMaterial()/heritTileMaterial()).
03020 
03021         if(!isLeaf())
03022         {
03023                 // Must recreate the materials of parent first.
03024 
03025                 // There is no problem with rectangular patch, since tiles are always squares.
03026                 // If new tile ....
03027                 if(SonLeft->Level==Patch->TileLimitLevel)
03028                 {
03029                         SonLeft->computeTileMaterial();
03030                         SonRight->computeTileMaterial();
03031                 }
03032                 // else Tile herit.
03033                 else if(SonLeft->Level > Patch->TileLimitLevel)
03034                 {
03035                         heritTileMaterial();
03036                 }
03037 
03038                 SonLeft->recreateTileUvs();
03039                 SonRight->recreateTileUvs();
03040         }
03041         else
03042         {
03043                 // NB: this is done always AFTER tile creation (see above).
03044                 // Do this only for tiles.
03045                 if(TileMaterial)
03046                         Patch->appendFaceToTileRenderList(this);
03047         }
03048 }

void NL3D::CTessFace::refineAll  ) 
 

refine the node, and his sons. Refine all nodes.

Definition at line 1783 of file tessellation.cpp.

References canMerge(), ErrorMetric, isLeaf(), merge(), NL3D_PROFILE_LAND_ADD, NL3D::ProfNRefineComputeFaces, NL3D::ProfNRefineFaces, NL3D::ProfNRefineLeaves, SonLeft, SonRight, split(), NL3D::CPatch::TileLimitLevel, and updateErrorMetric().

Referenced by NL3D::CPatch::refineAll().

01784 {
01785         NL3D_PROFILE_LAND_ADD(ProfNRefineFaces, 1);
01786         NL3D_PROFILE_LAND_ADD(ProfNRefineLeaves, isLeaf()?1:0);
01787 
01788         /*
01789                 if(ps<RefineThreshold), the face must be merged (ie have no leaves).
01790                 if(ps E [RefineThreshold, RefineTreshold*2]), the face must be splitted (ave leaves), and is geomorphed.
01791                 if(ps>RefineThreshold*2), the face is fully splitted/geomoprhed (tests reported on sons...).
01792         */
01793 
01794         // Test for Split or merge.
01795         //-----------------------
01796         {
01797                 NL3D_PROFILE_LAND_ADD(ProfNRefineComputeFaces, 1);
01798 
01799                 updateErrorMetric();
01800                 float   ps=ErrorMetric;
01801                 ps*= CLandscapeGlobals::OORefineThreshold;
01802                 // 1.0f is the point of split().
01803                 // 2.0f is the end of geomorph.
01804 
01805 
01806                 // Test split/merge.
01807                 //---------------------
01808                 // If wanted, not already done, and limit not reached, split().
01809                 if(isLeaf())
01810                 {
01811                         if(ps>1.0f && Level< (Patch->TileLimitLevel + CLandscapeGlobals::TileMaxSubdivision) )
01812                                 split();
01813                 }
01814                 else
01815                 {
01816                         // Else, if splitted, must merge (if not already the case).
01817                         if(ps<1.0f)
01818                         {
01819                                 // Merge only if agree, and neighbors agree.
01820                                 // canMerge() test all the good thing: FBase==CantMergeFace, or this is rectangular etc...
01821                                 // The test is propagated to neighbors.
01822                                 if(canMerge(true))
01823                                 {
01824                                         merge();
01825                                 }
01826                         }
01827                 }
01828         }
01829 
01830         // Recurs.
01831         //-----------------------
01832         if(SonLeft)
01833         {
01834                 SonLeft->refineAll();
01835                 SonRight->refineAll();
01836         }
01837 
01838 }

void NL3D::CTessFace::refreshTesselationGeometry  ) 
 

Definition at line 2519 of file tessellation.cpp.

References NL3D::CPatch::computeVertex(), NL3D::CTessVertex::EndPos, NL3D::CPatch::extendTessBlockWithEndPos(), NL3D::CParamCoord::getS(), NL3D::CParamCoord::getT(), isLeaf(), NL3D::CTessVertex::Pos, PVBase, SonLeft, SonRight, and VBase.

Referenced by NL3D::CPatch::refreshTesselationGeometry().

02520 {
02521         // must enlarge the little tessBlock (if any), for clipping.
02522         Patch->extendTessBlockWithEndPos(this);
02523 
02524         // If we are not splitted, no-op.
02525         if(isLeaf())
02526                 return;
02527 
02528 
02529         /* NB: rectangular case: just need to take SonLeft->VBase, because my neighbor on FBase will compute his son
02530                 on an other branch of the recurs call.
02531         */
02532         // re-compute this position (maybe with new noise geometry in Tile Edition).
02533         SonLeft->VBase->EndPos= Patch->computeVertex(SonLeft->PVBase.getS(), SonLeft->PVBase.getT());
02534         // overwrite cur Pos (NB: specialy hardcoded for Tile edition).
02535         SonLeft->VBase->Pos= SonLeft->VBase->EndPos;
02536 
02537         // Do same thing for sons. NB: see above, we are not a leaf.
02538         SonLeft->refreshTesselationGeometry();
02539         SonRight->refreshTesselationGeometry();
02540 }

void NL3D::CTessFace::releaseTileMaterial  ) 
 

Definition at line 835 of file tessellation.cpp.

References deleteTileFaces(), NL3D::CLandscape::deleteTileMaterial(), deleteTileUv(), FBase, NL3D::CPatch::getLandscape(), IdUvBase, IdUvLeft, IdUvRight, Level, nlassert, NL3D::CPatch::releaseTileLightMap(), NL3D::CPatch::removeTileMaterialFromRenderList(), NL3D::CPatch::TileLimitLevel, TileMaterial, NL3D::CTileMaterial::TileS, and NL3D::CTileMaterial::TileT.

Referenced by deleteTileUvs(), and doMerge().

00836 {
00837         // Hence, must release the tile. TileUvBase is differnet for each of leaves.
00838         deleteTileUv(IdUvBase);
00839 
00840         nlassert(!FBase || FBase->Level<=Patch->TileLimitLevel);
00841         if(FBase && FBase->Level==Patch->TileLimitLevel && FBase->TileMaterial!=NULL)
00842         {
00843                 // Do not release Uvs, since neighbor need it...
00844                 // But release faces.
00845                 deleteTileFaces();
00846                 // Do not release TileMaterial, since neighbor need it...
00847                 TileMaterial= NULL;
00848         }
00849         else
00850         {
00851                 // release Uvs.
00852                 deleteTileUv(IdUvLeft);
00853                 deleteTileUv(IdUvRight);
00854 
00855                 // After, release Tile faces.
00856                 deleteTileFaces();
00857 
00858                 // Release the tile lightmap part. Do it before removeTileMaterialFromRenderList().
00859                 Patch->releaseTileLightMap(TileMaterial->TileS, TileMaterial->TileT);
00860 
00861                 // Remove this material from the render list. DO it before deletion of course :).
00862                 // NB: TileS/TileT still valid.
00863                 Patch->removeTileMaterialFromRenderList(TileMaterial);
00864 
00865                 Patch->getLandscape()->deleteTileMaterial(TileMaterial);
00866                 TileMaterial= NULL;
00867         }
00868 }

bool NL3D::CTessFace::sameTile const CTessFace a,
const CTessFace b
[inline, static, private]
 

Definition at line 368 of file tessellation.h.

References Patch, and TileId.

Referenced by deleteTileUvs(), doMerge(), and heritTileMaterial().

00369         {
00370                 // WE CANNOT do this test, testing TileMaterial, because this one may be releleased by releaseMaterial() !!
00371                 return (a->Patch==b->Patch && a->TileId==b->TileId);
00372         }

void NL3D::CTessFace::split bool  propagateSplit = true  ) 
 

Definition at line 1283 of file tessellation.cpp.

References NL3D::CLandscape::_MergePriorityList, NL3D::CPatch::appendFaceToRenderList(), NL3D::CPatch::appendFarVertexToRenderList(), changeNeighbor(), NL3D::CPatch::checkCreateVertexVBFar(), checkFillTileVB(), NL3D::CPatch::checkFillVertexVBFar(), computeNearLimit(), computeSplitPoint(), computeTileMaterial(), NL3D::CPatch::computeVertex(), NL3D::CTessVertex::EndPos, Father, FBase, FLeft, FRight, FVBase, FVLeft, FVRight, NL3D::CPatch::getLandscape(), NL3D::CParamCoord::getS(), NL3D::CParamCoord::getT(), heritTileMaterial(), IdUvBase, NL3D::CTessFacePriorityList::insert(), isLeaf(), isRectangular(), Level, NL3D::CTessVertex::MaxFaceSize, NL3D::CTessVertex::MaxNearLimit, NL3D::CLandscape::newTessFace(), NL3D::CLandscape::newTessFarVertex(), NL3D::CLandscape::newTessVertex(), NL3D_PROFILE_LAND_ADD, nlassert, Patch, NL3D::CTessFarVertex::PCoord, NL3D::CTessVertex::Pos, NL3D::ProfNSplits, PVBase, PVLeft, PVRight, NL3D::CPatch::removeFaceFromRenderList(), Size, SonLeft, SonRight, splitRectangular(), NL3D::CTessFarVertex::Src, NL3D::CTessVertex::StartPos, NL3D::CPatch::TileLimitLevel, NL3D::CTessFacePListNode::unlinkInPList(), VBase, VLeft, and VRight.

Referenced by refineAll(), splitRectangular(), updateBindAndSplit(), and updateRefineSplit().

01284 {
01285 
01286         // 0. Some easy ending.
01287         //---------------------
01288         // Already splitted??
01289         if(!isLeaf())
01290                 return;
01291         // Don't do this!!!
01292         //if(Level>=LS_MAXLEVEL)
01293         //      return;
01294         // since split() may reach LS_MAXLEVEL, but enforce splits which outpass this stage!!
01295 
01296         NL3D_PROFILE_LAND_ADD(ProfNSplits, 1);
01297 
01298 
01299         // Special Rectangular case.
01300         if(isRectangular())
01301         {
01302                 splitRectangular(propagateSplit);
01303                 return;
01304         }
01305 
01306         // 1. Create sons, and update links.
01307         //----------------------------------
01308 
01309         // create and bind Sons.
01310         SonLeft= Patch->getLandscape()->newTessFace();
01311         SonRight= Patch->getLandscape()->newTessFace();
01312 
01313         // subdivision left.
01314         SonLeft->Patch= Patch;
01315         SonLeft->Father= this;
01316         SonLeft->Level= Level+1;
01317         SonLeft->Size= Size*0.5f;
01318         // subdivision right.
01319         SonRight->Patch= Patch;
01320         SonRight->Father= this;
01321         SonRight->Level= Level+1;
01322         SonRight->Size= Size*0.5f;
01323 
01324 
01325         // link Left Son.
01326         // link neighbor face.
01327         SonLeft->FBase= FLeft;
01328         if(FLeft)       FLeft->changeNeighbor(this, SonLeft);
01329         SonLeft->FLeft= SonRight;
01330         SonLeft->FRight= NULL;          // Temporary. updated later.
01331         // link neighbor vertex.
01332         SonLeft->VLeft= VBase;
01333         SonLeft->VRight= VLeft;
01334         // link neighbor Far vertex.
01335         SonLeft->FVLeft= FVBase;
01336         SonLeft->FVRight= FVLeft;
01337         // Patch coordinates.
01338         SonLeft->PVBase= CParamCoord(PVLeft, PVRight);
01339         SonLeft->PVLeft= PVBase;
01340         SonLeft->PVRight= PVLeft;
01341 
01342         // linkRight Son.
01343         // link neighbor face.
01344         SonRight->FBase= FRight;
01345         if(FRight)      FRight->changeNeighbor(this, SonRight);
01346         SonRight->FLeft= NULL;          // Temporary. updated later.
01347         SonRight->FRight= SonLeft;
01348         // link neighbor vertex.
01349         SonRight->VLeft= VRight;
01350         SonRight->VRight= VBase;
01351         // link neighbor Far vertex.
01352         SonRight->FVLeft= FVRight;
01353         SonRight->FVRight= FVBase;
01354         // Patch coordinates.
01355         SonRight->PVBase= CParamCoord(PVLeft, PVRight);
01356         SonRight->PVLeft= PVRight;
01357         SonRight->PVRight= PVBase;
01358 
01359 
01360         // FBase->FBase==this. Must Doesn't change this. Used and Updated in section 5. ...
01361 
01362 
01363         // 2. Update/Create Vertex infos.
01364         //-------------------------------
01365 
01366         // Must create/link *->VBase.
01367         if(FBase==NULL || FBase->isLeaf())
01368         {
01369                 // The base neighbor is a leaf or NULL. So must create the new vertex.
01370                 CTessVertex     *newVertex= Patch->getLandscape()->newTessVertex();
01371                 SonRight->VBase= newVertex;
01372                 SonLeft->VBase= newVertex;
01373 
01374                 // Compute pos.
01375                 newVertex->StartPos= (VLeft->EndPos + VRight->EndPos)/2;
01376                 newVertex->EndPos= Patch->computeVertex(SonLeft->PVBase.getS(), SonLeft->PVBase.getT());
01377 
01378                 // Init Pos= InitialPos. Important in the case of enforced split.
01379                 newVertex->Pos= newVertex->StartPos;
01380 
01381                 // For geomorph (VertexProgram or soft), compute MaxFaceSize and MaxNearLimit.
01382                 newVertex->MaxFaceSize= Size;
01383                 newVertex->MaxNearLimit= computeNearLimit();
01384         }
01385         else
01386         {
01387                 // Else, get from neighbor.
01388                 // NB: since *FBase is not a leaf, FBase->SonLeft!=NULL...
01389                 // NB: this work with both rectangular and square triangles (see splitRectangular()).
01390                 SonRight->VBase= FBase->SonLeft->VBase;
01391                 SonLeft->VBase= FBase->SonLeft->VBase;
01392 
01393                 // For geomorph (VertexProgram or soft), compute MaxFaceSize and MaxNearLimit.
01394                 SonLeft->VBase->MaxFaceSize= max( SonLeft->VBase->MaxFaceSize, Size);
01395                 SonLeft->VBase->MaxNearLimit= max( SonLeft->VBase->MaxNearLimit, computeNearLimit());
01396         }
01397 
01398 
01399         // Must create/link *->FVBase.
01400         // HERE, we must create a FarVertex too if the neighbor is not of the same patch as me.
01401         if(FBase==NULL || FBase->isLeaf() || FBase->Patch!=Patch)
01402         {
01403                 // The base neighbor is a leaf or NULL. So must create the new far vertex.
01404                 CTessFarVertex  *newFar= Patch->getLandscape()->newTessFarVertex();
01405                 SonRight->FVBase= newFar;
01406                 SonLeft->FVBase= newFar;
01407 
01408                 // Compute.
01409                 newFar->Src= SonLeft->VBase;
01410                 newFar->PCoord= SonLeft->PVBase;
01411 
01412                 // Append.
01413                 Patch->appendFarVertexToRenderList(newFar);
01414 
01415                 // May Allocate/Fill VB.
01416                 // NB: SonLeft->VBase->Pos is well computed and ready for the fill in VB.
01417                 Patch->checkCreateVertexVBFar(newFar);
01418                 Patch->checkFillVertexVBFar(newFar);
01419 
01420                 // For VertexProgram only, must refill the Far vertex of neighbor, 
01421                 // because MaxFaceSize, and MaxNearLimit may have change.
01422                 if( CLandscapeGlobals::VertexProgramEnabled && ! (FBase==NULL || FBase->isLeaf()) )
01423                         FBase->Patch->checkFillVertexVBFar(FBase->SonLeft->FVBase);
01424         }
01425         else
01426         {
01427                 // Else, get from neighbor.
01428                 // NB: since *FBase is not a leaf, FBase->SonLeft!=NULL...
01429                 // NB: this work with both rectangular and square triangles (see splitRectangular()).
01430                 SonRight->FVBase= FBase->SonLeft->FVBase;
01431                 SonLeft->FVBase= FBase->SonLeft->FVBase;
01432 
01433                 // NB For VertexProgram only: no need to refill the Far vertex of neighbor, because neighbor is of same Patch
01434                 // So MaxNearLimit and MaxFaceSize should be the same.
01435         }
01436 
01437 
01438         // 3. Update Tile infos.
01439         //----------------------
01440         // NB: must do it before appendFaceToRenderList().
01441         // NB: must do it after compute of SonLeft->VBase->Pos for good filling in VBuffer.
01442         // There is no problem with rectangular patch, since tiles are always squares.
01443         // If new tile ....
01444         if(SonLeft->Level==Patch->TileLimitLevel)
01445         {
01446                 SonLeft->computeTileMaterial();
01447                 SonRight->computeTileMaterial();
01448         }
01449         // else Tile herit.
01450         else if(SonLeft->Level > Patch->TileLimitLevel)
01451         {
01452                 heritTileMaterial();
01453         }
01454 
01455         // For Vertex program only
01456         if( CLandscapeGlobals::VertexProgramEnabled )
01457         {
01458                 // if neighbor face splitted, and if 2 different patchs, we must update the Tile vertices
01459                 // because MaxFaceSize and MaxNearLimit may have changed.
01460                 if( FBase!=NULL && !FBase->isLeaf() && FBase->Patch!=Patch )
01461                 {
01462                         // If neighbors sons at tile level, must update their Tile vertices.
01463                         if( FBase->SonLeft->Level >= FBase->Patch->TileLimitLevel )
01464                         {
01465                                 FBase->SonLeft->checkFillTileVB(IdUvBase);
01466                                 FBase->SonRight->checkFillTileVB(IdUvBase);
01467                         }
01468                 }
01469         }
01470 
01471 
01472         // 4. Compute centers.
01473         //--------------------
01474         SonRight->computeSplitPoint();
01475         SonLeft->computeSplitPoint();
01476 
01477 
01478         // 5. Propagate, or link sons of base.
01479         //------------------------------------
01480         // If current face and FBase has sons, just links.
01481         if(FBase==NULL)
01482         {
01483                 // Just update sons neighbors.
01484                 SonLeft->FRight= NULL;
01485                 SonRight->FLeft= NULL;
01486         }
01487         else if(!FBase->isLeaf())
01488         {
01489                 CTessFace       *toLeft, *toRight;
01490                 CTessFace       *fl, *fr;
01491                 fl= SonLeft;
01492                 fr= SonRight;
01493                 toLeft= FBase->SonLeft;
01494                 toRight= FBase->SonRight;
01495                 // Cross connection of sons.
01496                 if(!FBase->isRectangular())
01497                 {
01498                         // Case neigbhor is square.
01499                         fl->FRight= toRight;
01500                         fr->FLeft= toLeft;
01501                         toLeft->FRight= fr;
01502                         toRight->FLeft= fl;
01503                 }
01504                 else
01505                 {
01506                         // Case neigbhor is rectangular.
01507                         fl->FRight= toLeft;
01508                         fr->FLeft= toRight;
01509                         toLeft->FLeft= fl;
01510                         toRight->FLeft= fr;
01511                 }
01512         }
01513         else if (propagateSplit)
01514         {
01515                 // Warning: at each iteration, the pointer of FBase may change (because of split() which can change the neighbor 
01516                 // and so "this").
01517                 while(FBase->isLeaf())
01518                         FBase->split();
01519 
01520                 // There is a possible bug here (maybe easily patched). Sons may have be propagated splitted.
01521                 // And problems may arise because this face hasn't yet good connectivity.
01522                 nlassert(SonLeft->isLeaf() && SonRight->isLeaf());
01523         }
01524 
01525 
01526         // 6. Must remove father from rdr list, and insert sons.
01527         //------------------------------------------------------
01528         // UGLY REFCOUNT SIDE EFFECT: do the append first.
01529         Patch->appendFaceToRenderList(SonLeft);
01530         Patch->appendFaceToRenderList(SonRight);
01531         Patch->removeFaceFromRenderList(this);
01532 
01533 
01534         // 7. Update priority list.
01535         //------------------------------------------------------
01536         // Since we are freshly splitted, unlink from any list, and link to the MergePriorityList, because must look 
01537         // now when should merge.
01538         Patch->getLandscape()->_MergePriorityList.insert(0, 0, this);
01539 
01540         // Since we are split, no need to test father for merge, because it cannot!
01541         if(Father)
01542         {
01543                 // remove father from any priority list.
01544                 Father->unlinkInPList();
01545         }
01546 }

void NL3D::CTessFace::splitRectangular bool  propagateSplit  )  [private]
 

Definition at line 911 of file tessellation.cpp.

References NL3D::CLandscape::_MergePriorityList, NL3D::CPatch::appendFaceToRenderList(), NL3D::CPatch::appendFarVertexToRenderList(), changeNeighbor(), NL3D::CPatch::checkCreateVertexVBFar(), checkFillTileVB(), NL3D::CPatch::checkFillVertexVBFar(), computeNearLimit(), computeSplitPoint(), NL3D::CPatch::computeVertex(), NL3D::CTessVertex::EndPos, Father, FBase, FLeft, FRight, FVBase, FVLeft, FVRight, NL3D::CPatch::getLandscape(), NL3D::CParamCoord::getS(), NL3D::CParamCoord::getT(), IdUvBase, NL3D::CTessFacePriorityList::insert(), isLeaf(), isRectangular(), Level, NL3D::CTessVertex::MaxFaceSize, NL3D::CTessVertex::MaxNearLimit, NL3D::CLandscape::newTessFace(), NL3D::CLandscape::newTessFarVertex(), NL3D::CLandscape::newTessVertex(), nlassert, Patch, NL3D::CTessFarVertex::PCoord, NL3D::CTessVertex::Pos, PVBase, PVLeft, PVRight, NL3D::CPatch::removeFaceFromRenderList(), sint, Size, SonLeft, SonRight, split(), NL3D::CTessFarVertex::Src, NL3D::CTessVertex::StartPos, NL3D::CPatch::TileLimitLevel, NL3D::CTessFacePListNode::unlinkInPList(), VBase, VLeft, and VRight.

Referenced by split().

00912 {
00913         CTessFace       *f0= this;
00914         CTessFace       *f1= FBase;
00915         // Rectangular case: FBase must exist.
00916         nlassert(f1);
00917 
00918         // In rectangular case, we split at the same time this and FBase (f0 and f1).
00919 
00920 
00921         /*
00922                 Tesselation is:
00923         
00924        lt                    rt        lt        top         rt
00925                 ---------------------           ---------------------
00926                 |----               |           |\        |\        |
00927                 |    ----      f1   |           |  \  f1l |  \  f1r |
00928                 |        ----       |    -->    |    \    |    \    |
00929                 |   f0       ----   |           | f0r  \  | f0l  \  |
00930                 |                ---|           |        \|        \|
00931                 ---------------------           ---------------------
00932            lb                    rb        lb        bot         rb
00933 
00934                 Why? For symetry and bind/split reasons: FBase->SonLeft->VBase is always the good vertex to take 
00935                 (see vertex binding).
00936         */
00937         CParamCoord             pclt= f1->PVLeft;
00938         CParamCoord             pclb= f0->PVBase;
00939         CParamCoord             pcrt= f1->PVBase;
00940         CParamCoord             pcrb= f1->PVRight;
00941         CTessVertex             *vlt= f1->VLeft;
00942         CTessVertex             *vlb= f0->VBase;
00943         CTessVertex             *vrt= f1->VBase;
00944         CTessVertex             *vrb= f1->VRight;
00945 
00946         CTessFarVertex  *farvlt= f1->FVLeft;
00947         CTessFarVertex  *farvlb= f0->FVBase;
00948         CTessFarVertex  *farvrt= f1->FVBase;
00949         CTessFarVertex  *farvrb= f1->FVRight;
00950 
00951 
00952         // 1. create new vertices.
00953         //------------------------
00954 
00955         // Create splitted vertices.
00956         CParamCoord             pctop(f1->PVBase, f1->PVLeft);
00957         CParamCoord             pcbot(f0->PVBase, f0->PVLeft);
00958         CTessVertex             *vtop= NULL;
00959         CTessVertex             *vbot= NULL;
00960         // Compute top.
00961         if(f1->FLeft==NULL || f1->FLeft->isLeaf())
00962         {
00963                 // The base neighbor is a leaf or NULL. So must create the new vertex.
00964                 vtop= Patch->getLandscape()->newTessVertex();
00965 
00966                 // Compute pos.
00967                 vtop->StartPos= (f1->VLeft->EndPos + f1->VBase->EndPos)/2;
00968                 vtop->EndPos= f1->Patch->computeVertex(pctop.getS(), pctop.getT());
00969                 // Init Pos= InitialPos. Important in the case of enforced split.
00970                 vtop->Pos= vtop->StartPos;
00971 
00972                 // For geomorph (VertexProgram or soft), compute MaxFaceSize and MaxNearLimit.
00973                 vtop->MaxFaceSize= f1->Size;
00974                 vtop->MaxNearLimit= f1->computeNearLimit();
00975         }
00976         else
00977         {
00978                 // Else, get from neighbor.
00979                 // NB: since *FLeft is not a leaf, FBase->SonLeft!=NULL...
00980                 // NB: this work with both rectangular and square triangles.
00981                 vtop= f1->FLeft->SonLeft->VBase;
00982 
00983                 // For geomorph (VertexProgram or soft), compute MaxFaceSize and MaxNearLimit.
00984                 vtop->MaxFaceSize= max( vtop->MaxFaceSize, f1->Size);
00985                 vtop->MaxNearLimit= max( vtop->MaxNearLimit, f1->computeNearLimit());
00986         }
00987         // Compute bot.
00988         if(f0->FLeft==NULL || f0->FLeft->isLeaf())
00989         {
00990                 // The base neighbor is a leaf or NULL. So must create the new vertex.
00991                 vbot= Patch->getLandscape()->newTessVertex();
00992 
00993                 // Compute pos.
00994                 vbot->StartPos= (f0->VLeft->EndPos + f0->VBase->EndPos)/2;
00995                 vbot->EndPos= Patch->computeVertex(pcbot.getS(), pcbot.getT());
00996                 // Init Pos= InitialPos. Important in the case of enforced split.
00997                 vbot->Pos= vbot->StartPos;
00998 
00999                 // For geomorph (VertexProgram or soft), compute MaxFaceSize and MaxNearLimit.
01000                 vbot->MaxFaceSize= f0->Size;
01001                 vbot->MaxNearLimit= f0->computeNearLimit();
01002         }
01003         else
01004         {
01005                 // Else, get from neighbor.
01006                 // NB: since *FLeft is not a leaf, FBase->SonLeft!=NULL...
01007                 // NB: this work with both rectangular and square triangles.
01008                 vbot= f0->FLeft->SonLeft->VBase;
01009 
01010                 // For geomorph (VertexProgram or soft), compute MaxFaceSize and MaxNearLimit.
01011                 vbot->MaxFaceSize= max( vbot->MaxFaceSize, f0->Size);
01012                 vbot->MaxNearLimit= max( vbot->MaxNearLimit, f0->computeNearLimit());
01013         }
01014 
01015         // In all case, must create new FarVertices, since rect split occurs on border!!
01016         CTessFarVertex  *farvtop= Patch->getLandscape()->newTessFarVertex();
01017         CTessFarVertex  *farvbot= Patch->getLandscape()->newTessFarVertex();
01018         farvtop->Src= vtop;
01019         farvbot->Src= vbot;
01020         farvtop->PCoord= pctop;
01021         farvbot->PCoord= pcbot;
01022         Patch->appendFarVertexToRenderList(farvtop);
01023         Patch->appendFarVertexToRenderList(farvbot);
01024         // May Allocate/Fill VB.
01025         // NB: vtop / vbot are well computed  and ready for the fill in VB.
01026         Patch->checkCreateVertexVBFar(farvtop);
01027         Patch->checkFillVertexVBFar(farvtop);
01028         Patch->checkCreateVertexVBFar(farvbot);
01029         Patch->checkFillVertexVBFar(farvbot);
01030 
01031         // For VertexProgram only, must refill the Far vertex of neighbor(s), 
01032         // because MaxFaceSize, and MaxNearLimit may have change.
01033         if( CLandscapeGlobals::VertexProgramEnabled )
01034         {
01035                 // f0
01036                 if( ! (f0->FLeft==NULL || f0->FLeft->isLeaf()) )
01037                         f0->FLeft->Patch->checkFillVertexVBFar(f0->FLeft->SonLeft->FVBase);
01038                 // f1
01039                 if( ! (f1->FLeft==NULL || f1->FLeft->isLeaf()) )
01040                         f1->FLeft->Patch->checkFillVertexVBFar(f1->FLeft->SonLeft->FVBase);
01041         }
01042 
01043         
01044         // 2. Create sons, and update links.
01045         //----------------------------------
01046 
01047         CTessFace       *f0l, *f0r;
01048         CTessFace       *f1l, *f1r;
01049 
01050         // create and bind Sons.
01051         f0l= f0->SonLeft= Patch->getLandscape()->newTessFace();
01052         f0r= f0->SonRight= Patch->getLandscape()->newTessFace();
01053         f1l= f1->SonLeft= Patch->getLandscape()->newTessFace();
01054         f1r= f1->SonRight= Patch->getLandscape()->newTessFace();
01055 
01056         // subdivision left.
01057         f0l->Patch= f0->Patch;
01058         f0l->Father= f0;
01059         f0l->Level= f0->Level+1;
01060         f0l->Size= f0->Size*0.5f;
01061         // subdivision right.
01062         f0r->Patch= f0->Patch;
01063         f0r->Father= f0;
01064         f0r->Level= f0->Level+1;
01065         f0r->Size= f0->Size*0.5f;
01066         // subdivision left.
01067         f1l->Patch= f1->Patch;
01068         f1l->Father= f1;
01069         f1l->Level= f1->Level+1;
01070         f1l->Size= f1->Size*0.5f;
01071         // subdivision right.
01072         f1r->Patch= f1->Patch;
01073         f1r->Father= f1;
01074         f1r->Level= f1->Level+1;
01075         f1r->Size= f1->Size*0.5f;
01076 
01077         // Patch coordinates.
01078         f0r->PVRight= pclt;
01079         f0r->PVBase= pclb;
01080         f0r->PVLeft= pcbot;
01081         f1l->PVBase= pctop;
01082         f1l->PVLeft= f0r->PVRight;
01083         f1l->PVRight= f0r->PVLeft;
01084 
01085         f0l->PVRight= pctop;
01086         f0l->PVBase= pcbot;
01087         f0l->PVLeft= pcrb;
01088         f1r->PVBase= pcrt;
01089         f1r->PVLeft= f0l->PVRight;
01090         f1r->PVRight= f0l->PVLeft;
01091 
01092         // link existing vertex.
01093         f0r->VRight= vlt;
01094         f0r->VBase= vlb;
01095         f0r->VLeft= vbot;
01096         f1l->VBase= vtop;
01097         f1l->VLeft= f0r->VRight;
01098         f1l->VRight= f0r->VLeft;
01099 
01100         f0l->VRight= vtop;
01101         f0l->VBase= vbot;
01102         f0l->VLeft= vrb;
01103         f1r->VBase= vrt;
01104         f1r->VLeft= f0l->VRight;
01105         f1r->VRight= f0l->VLeft;
01106 
01107         // link Far vertices.
01108         f0r->FVRight= farvlt;
01109         f0r->FVBase= farvlb;
01110         f0r->FVLeft= farvbot;
01111         f1l->FVBase= farvtop;
01112         f1l->FVLeft= f0r->FVRight;
01113         f1l->FVRight= f0r->FVLeft;
01114 
01115         f0l->FVRight= farvtop;
01116         f0l->FVBase= farvbot;
01117         f0l->FVLeft= farvrb;
01118         f1r->FVBase= farvrt;
01119         f1r->FVLeft= f0l->FVRight;
01120         f1r->FVRight= f0l->FVLeft;
01121 
01122         // link neigbhor faces.
01123         f0r->FBase= f1l;
01124         f1l->FBase= f0r;
01125         f0l->FBase= f1r;
01126         f1r->FBase= f0l;
01127         f1l->FRight= f0l;
01128         f0l->FRight= f1l;
01129         f0r->FRight= f0->FRight;
01130         if(f0->FRight)
01131                 f0->FRight->changeNeighbor(f0, f0r);
01132         f1r->FRight= f1->FRight;
01133         if(f1->FRight)
01134                 f1->FRight->changeNeighbor(f1, f1r);
01135         // 4 links (all FLeft sons ) are stil invalid here.
01136         f0l->FLeft= NULL;
01137         f0r->FLeft= NULL;
01138         f1l->FLeft= NULL;
01139         f1r->FLeft= NULL;
01140 
01141         // Neigbors pointers of undetermined splitted face are not changed. Must Doesn't change this. 
01142         // Used and Updated in section 5. ...
01143 
01144 
01145         // 3. Update Tile infos.
01146         //----------------------
01147         // There is no update tileinfo with rectangular patch, since tiles are always squares. (TileLimitLevel>SquareLimitLevel).
01148 
01149         // NB: but must test update of tile info for neighboring, ie 2 faces around the splits.
01150         // For Vertex program only
01151         if( CLandscapeGlobals::VertexProgramEnabled )
01152         {
01153                 // if neighbor face splitted, and if 2 different patchs, we must update the Tile vertices
01154                 // because MaxFaceSize and MaxNearLimit may have changed.
01155                 if( f0->FLeft!=NULL && !f0->FLeft->isLeaf() && f0->FLeft->Patch!=Patch )
01156                 {
01157                         // If neighbors sons at tile level, must update their Tile vertices.
01158                         if( f0->FLeft->SonLeft->Level >= f0->FLeft->Patch->TileLimitLevel )
01159                         {
01160                                 f0->FLeft->SonLeft->checkFillTileVB(IdUvBase);
01161                                 f0->FLeft->SonRight->checkFillTileVB(IdUvBase);
01162                         }
01163                 }
01164                 // idem for f1.
01165                 if( f1->FLeft!=NULL && !f1->FLeft->isLeaf() && f1->FLeft->Patch!=Patch )
01166                 {
01167                         // If neighbors sons at tile level, must update their Tile vertices.
01168                         if( f1->FLeft->SonLeft->Level >= f1->FLeft->Patch->TileLimitLevel )
01169                         {
01170                                 f1->FLeft->SonLeft->checkFillTileVB(IdUvBase);
01171                                 f1->FLeft->SonRight->checkFillTileVB(IdUvBase);
01172                         }
01173                 }
01174         }
01175 
01176 
01177         // 4. Compute centers.
01178         //--------------------
01179         f0r->computeSplitPoint();
01180         f0l->computeSplitPoint();
01181         f1r->computeSplitPoint();
01182         f1l->computeSplitPoint();
01183 
01184 
01185         // 5. Propagate, or link sons of base.
01186         //------------------------------------
01187         for(sint i=0;i<2;i++)
01188         {
01189                 CTessFace       *f, *fl, *fr;
01190                 // TOP face.
01191                 if(i==0)
01192                 {
01193                         f= f1;
01194                         fl= f1l;
01195                         fr= f1r;
01196                 }
01197                 // then BOT face.
01198                 else
01199                 {
01200                         f= f0;
01201                         fl= f0l;
01202                         fr= f0r;
01203                 }
01204 
01205                 // If current face and FBase has sons, just links.
01206                 if(f->FLeft==NULL)
01207                 {
01208                         // Just update sons neighbors.
01209                         fl->FLeft= NULL;
01210                         fr->FLeft= NULL;
01211                 }
01212                 else if(!f->FLeft->isLeaf())
01213                 {
01214                         CTessFace       *toLeft, *toRight;
01215                         toLeft= f->FLeft->SonLeft;
01216                         toRight= f->FLeft->SonRight;
01217                         // Cross connection of sons.
01218                         if( !f->FLeft->isRectangular() )
01219                         {
01220                                 // Case neigbhor is square.
01221                                 fl->FLeft= toLeft;
01222                                 fr->FLeft= toRight;
01223                                 toLeft->FRight= fl;
01224                                 toRight->FLeft= fr;
01225                         }
01226                         else
01227                         {
01228                                 // Case neigbhor is rectangle.
01229                                 fl->FLeft= toRight;
01230                                 fr->FLeft= toLeft;
01231                                 toLeft->FLeft= fr;
01232                                 toRight->FLeft= fl;
01233                         }
01234                 }
01235                 else if (propagateSplit)
01236                 {
01237                         // Warning: at each iteration, the pointer of FLeft may change (because of split() which can change the neighbor 
01238                         // and so f).
01239                         while(f->FLeft->isLeaf())
01240                                 f->FLeft->split();
01241 
01242                         // There is a possible bug here (maybe easily patched). Sons may have be propagated splitted.
01243                         // And problems may arise because this face hasn't yet good connectivity (especially for rectangles!! :) ).
01244                         nlassert(fl->isLeaf() && fr->isLeaf());
01245                 }
01246         }
01247 
01248         
01249         // 6. Must remove father from rdr list, and insert sons.
01250         //------------------------------------------------------
01251         // UGLY REFCOUNT SIDE EFFECT: do the append first.
01252         Patch->appendFaceToRenderList(f0l);
01253         Patch->appendFaceToRenderList(f0r);
01254         Patch->appendFaceToRenderList(f1l);
01255         Patch->appendFaceToRenderList(f1r);
01256         Patch->removeFaceFromRenderList(f0);
01257         Patch->removeFaceFromRenderList(f1);
01258 
01259 
01260         // 7. Update priority list.
01261         //------------------------------------------------------
01262         // Since we are freshly splitted, unlink from any list, and link to the MergePriorityList, because must look 
01263         // now when should merge.
01264         Patch->getLandscape()->_MergePriorityList.insert(0, 0, f0);
01265         Patch->getLandscape()->_MergePriorityList.insert(0, 0, f1);
01266 
01267         // Since we are split, no need to test father for merge, because it cannot!
01268         if(f0->Father)
01269         {
01270                 // remove father from any priority list.
01271                 f0->Father->unlinkInPList();
01272         }
01273         if(f1->Father)
01274         {
01275                 // remove father from any priority list.
01276                 f1->Father->unlinkInPList();
01277         }
01278 
01279 }

void NL3D::CTessFace::unbind  ) 
 

Definition at line 2274 of file tessellation.cpp.

References changeNeighbor(), computeNearLimit(), FBase, FLeft, FRight, NL3D::CPatch::getLandscape(), isLeaf(), isRectangular(), NL3D::CTessVertex::MaxFaceSize, NL3D::CTessVertex::MaxNearLimit, NL3D::CLandscape::newTessVertex(), nlassert, Patch, Size, SonLeft, SonRight, updateNearFarVertices(), VBase, VLeft, and VRight.

Referenced by NL3D::CPatch::unbind().

02275 {
02276         // NB: since CantMergeFace has a NULL patch ptr, it is unbound too.
02277 
02278         // Square case.
02279         //=============
02280         if(!isRectangular())
02281         {
02282                 // Change Left/Right neighbors.
02283                 if(isLeaf())
02284                 {
02285                         // FLeft and FRight pointers are only valid in Leaves nodes.
02286                         if(FLeft && FLeft->Patch!=Patch)
02287                         {
02288                                 FLeft->changeNeighbor(this, NULL);
02289                                 FLeft= NULL;
02290                         }
02291                         if(FRight && FRight->Patch!=Patch)
02292                         {
02293                                 FRight->changeNeighbor(this, NULL);
02294                                 FRight= NULL;
02295                         }
02296                 }
02297                 // Change Base neighbors.
02298                 if(FBase && FBase->Patch!=Patch)
02299                 {
02300                         CTessFace       *oldNeigbhorFace= FBase;
02301 
02302                         FBase->changeNeighbor(this, NULL);
02303                         FBase= NULL;
02304                         if(!isLeaf())
02305                         {
02306                                 // Duplicate the VBase of sons, so the unbind is correct and no vertices are shared.
02307                                 CTessVertex     *old= SonLeft->VBase;
02308                                 SonLeft->VBase= Patch->getLandscape()->newTessVertex();
02309                                 *(SonLeft->VBase)= *old;
02310                                 SonRight->VBase= SonLeft->VBase;
02311 
02312                                 // For geomorph (VertexProgram or soft), compute good MaxFaceSize and MaxNearLimit (change since unbinded)
02313                                 // update us.
02314                                 SonLeft->VBase->MaxFaceSize= Size;
02315                                 SonLeft->VBase->MaxNearLimit= computeNearLimit();
02316                                 // update our neigbhor, only if not a multiple patch face.
02317                                 if(oldNeigbhorFace->Patch)
02318                                 {
02319                                         old->MaxFaceSize= oldNeigbhorFace->Size;
02320                                         old->MaxNearLimit= oldNeigbhorFace->computeNearLimit();
02321                                 }
02322                         }
02323                 }
02324         }
02325         // Rectangular case.
02326         //==================
02327         else
02328         {
02329                 // Doens't need to test FBase, since must be same patch.
02330                 // In rectangular, FLeft has the behavior of FBase in square case.
02331                 if(FLeft && FLeft->Patch!=Patch)
02332                 {
02333                         CTessFace       *oldNeigbhorFace= FLeft;
02334 
02335                         FLeft->changeNeighbor(this, NULL);
02336                         FLeft= NULL;
02337                         if(!isLeaf())
02338                         {
02339                                 // Duplicate the VBase of sons, so the unbind is correct and no vertices are shared.
02340                                 // NB: this code is a bit different from square case.
02341                                 CTessVertex     *old= SonLeft->VBase;
02342                                 SonLeft->VBase= Patch->getLandscape()->newTessVertex();
02343                                 *(SonLeft->VBase)= *old;
02344                                 // This is the difference:  (see rectangle tesselation rules).
02345                                 SonRight->VLeft= SonLeft->VBase;
02346                                 // Yoyo_patch_himself (12/02/2001): I forgot this one!!
02347                                 nlassert(FBase && FBase->SonLeft);
02348                                 FBase->SonLeft->VRight= SonLeft->VBase;
02349 
02350 
02351                                 // For geomorph (VertexProgram or soft), compute good MaxFaceSize and MaxNearLimit (change since unbinded)
02352                                 // update us.
02353                                 SonLeft->VBase->MaxFaceSize= Size;
02354                                 SonLeft->VBase->MaxNearLimit= computeNearLimit();
02355                                 // update our neigbhor, only if not a multiple patch face.
02356                                 if(oldNeigbhorFace->Patch)
02357                                 {
02358                                         old->MaxFaceSize= oldNeigbhorFace->Size;
02359                                         old->MaxNearLimit= oldNeigbhorFace->computeNearLimit();
02360                                 }
02361                         }
02362                 }
02363                 // But FRight still valid in leaves nodes only.
02364                 if(isLeaf())
02365                 {
02366                         if(FRight && FRight->Patch!=Patch)
02367                         {
02368                                 FRight->changeNeighbor(this, NULL);
02369                                 FRight= NULL;
02370                         }
02371                 }
02372         }
02373 
02374         // Propagate unbind.
02375         //==================
02376         if(!isLeaf())
02377         {
02378                 // update sons vertex pointers (since they may have been updated by me or my grandfathers).
02379                 if(!isRectangular())
02380                 {
02381                         SonLeft->VLeft= VBase;
02382                         SonLeft->VRight= VLeft;
02383                         SonRight->VLeft= VRight;
02384                         SonRight->VRight= VBase;
02385                 }
02386                 else
02387                 {
02388                         // Rectangular case. Update only ptrs which may have changed.
02389                         SonLeft->VLeft= VLeft;
02390                         SonRight->VBase= VBase;
02391                         SonRight->VRight= VRight;
02392                 }
02393 
02394                 // Must re-create good Vertex links for Far and Near Vertices!!!
02395                 SonLeft->updateNearFarVertices();
02396                 SonRight->updateNearFarVertices();
02397                 if(isRectangular())
02398                 {
02399                         //NB: must do this for Base neighbor (see unbind() rectangular case...).
02400                         nlassert(FBase && FBase->SonLeft && FBase->SonRight);
02401                         FBase->SonLeft->updateNearFarVertices();
02402                         FBase->SonRight->updateNearFarVertices();
02403                 }
02404 
02405                 // unbind the sons.
02406                 SonLeft->unbind();
02407                 SonRight->unbind();
02408         }
02409 
02410 }

void NL3D::CTessFacePListNode::unlinkInPList  )  [inherited]
 

if linked, unlink this node from his list.

Definition at line 71 of file tess_face_priority_list.cpp.

References NL3D::CTessFacePListNode::_NextTessFaceInPList, and NL3D::CTessFacePListNode::_PrecTessFaceInPList.

Referenced by NL3D::CTessFacePriorityList::CRollingTable::clearRollTableEntry(), NL3D::CLandscape::deleteTessFace(), NL3D::CTessFacePriorityList::shift(), NL3D::CTessFacePriorityList::shiftAll(), split(), splitRectangular(), updateRefineSplit(), and NL3D::CTessFacePListNode::~CTessFacePListNode().

00072 {
00073         /*
00074                 NB: if this node was empty (this, this), this is a No-Op.
00075                 If this node was the last of a list, then the root correctly get (&root, &root) after this.
00076         */
00077         // unlink old list from me.
00078         _PrecTessFaceInPList->_NextTessFaceInPList= _NextTessFaceInPList;
00079         _NextTessFaceInPList->_PrecTessFaceInPList= _PrecTessFaceInPList;
00080 
00081         // reset to empty node.
00082         _PrecTessFaceInPList= this;
00083         _NextTessFaceInPList= this;
00084 }

void NL3D::CTessFace::updateBind  ) 
 

Definition at line 2860 of file tessellation.cpp.

References FBase, FLeft, FRight, isLeaf(), SonLeft, SonRight, updateBindAndSplit(), and updateBindEdge().

Referenced by NL3D::CPatch::bind().

02861 {
02862         /*
02863                 Remind that updateBind() is called ONLY on the patch which is binded (not the neighbors).
02864                 Since updateBind() is called on the bintree, and that precedent propagated split may have occur, we may not
02865                 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
02866                 sons).
02867                 Also, since we are splitted, and correctly linked (this may not be the case in updateBindAndSplit()), FBase IS
02868                 correct. His FBase neighbor and him form a diamond. So we don't need to update him.
02869 
02870                 Same remarks for rectangular patchs.
02871         */
02872         if(isLeaf())
02873         {
02874                 bool    splitWanted= false;
02875                 while(!updateBindEdge(FBase, splitWanted));
02876                 // FLeft and FRight pointers are only valid in Leaves nodes.
02877                 while(!updateBindEdge(FLeft, splitWanted));
02878                 while(!updateBindEdge(FRight, splitWanted));
02879                 if(splitWanted)
02880                         updateBindAndSplit();
02881         }
02882 
02883 
02884         // Recurse to sons.
02885         if(!isLeaf())
02886         {
02887                 // Update bind of sons.
02888                 SonLeft->updateBind();
02889                 SonRight->updateBind();
02890         }
02891 }

void NL3D::CTessFace::updateBindAndSplit  ) 
 

Definition at line 2643 of file tessellation.cpp.

References CantMergeFace, changeNeighbor(), computeSplitPoint(), NL3D::CLandscape::deleteTessVertex(), NL3D::CTessVertex::EndPos, FBase, FLeft, FRight, NL3D::CPatch::getLandscape(), isLeaf(), isRectangular(), nlassert, Patch, NL3D::CTessVertex::Pos, sint, SonLeft, SonRight, split(), NL3D::CTessVertex::StartPos, updateBindEdge(), updateNearFarVertices(), VBase, and VRight.

Referenced by updateBind().

02644 {
02645         bool    splitWanted= false;
02646         CTessFace       *f0= NULL;
02647         CTessFace       *f1= NULL;
02648         /*
02649                 Look at the callers, and you'll see that "this" is always a leaf.
02650                 Therefore, FBase, FLeft and FRight are good pointers, and *FLeft and *FRight should be Ok too.
02651         */
02652         nlassert(isLeaf());
02653         while(!updateBindEdge(FBase, splitWanted));
02654         // FLeft and FRight pointers are only valid in Leaves nodes.
02655         while(!updateBindEdge(FLeft, splitWanted));
02656         while(!updateBindEdge(FRight, splitWanted));
02657         // In rectangular case, we MUST also update edges of FBase.
02658         // Because splitRectangular() split those two faces at the same time.
02659         if(isRectangular())
02660         {
02661                 f0= this;
02662                 f1= FBase;
02663                 nlassert(FBase);
02664                 nlassert(FBase->isLeaf());
02665                 // Doesn't need to update FBase->FBase, since it's me!
02666                 // FLeft and FRight pointers are only valid in Leaves nodes.
02667                 while(!FBase->updateBindEdge(FBase->FLeft, splitWanted));
02668                 while(!FBase->updateBindEdge(FBase->FRight, splitWanted));
02669         }
02670 
02671 
02672 
02673         CTessFace       *fmult= NULL;
02674         CTessFace       *fmult0= NULL;
02675         CTessFace       *fmult1= NULL;
02676         // If multipatch face case.
02677         //=========================
02678         if(!isRectangular())
02679         {
02680                 // multipatch face case are detected when face->Patch==NULL !!!
02681                 if(FBase && FBase->Patch==NULL)
02682                 {
02683                         fmult= FBase;
02684                         // First, trick: FBase is NULL, so during the split. => no ptr problem.
02685                         FBase= NULL;
02686                 }
02687         }
02688         else
02689         {
02690                 // multipatch face case are detected when face->Patch==NULL !!!
02691                 if(f0->FLeft && f0->FLeft->Patch==NULL)
02692                 {
02693                         fmult0= f0->FLeft;
02694                         // First, trick: neighbor is NULL, so during the split. => no ptr problem.
02695                         f0->FLeft= NULL;
02696                 }
02697                 // multipatch face case are detected when face->Patch==NULL !!!
02698                 if(f1->FLeft && f1->FLeft->Patch==NULL)
02699                 {
02700                         fmult1= f1->FLeft;
02701                         // First, trick: neighbor is NULL, so during the split. => no ptr problem.
02702                         f1->FLeft= NULL;
02703                 }
02704         }
02705 
02706         // Then split, and propagate.
02707         //===========================
02708         split(false);
02709         if(!isRectangular())
02710         {
02711                 if(FBase)
02712                 {
02713                         while(FBase->isLeaf())
02714                                 FBase->updateBindAndSplit();
02715                 }
02716                 // There is a possible bug here (maybe easily patched). Sons may have be propagated splitted.
02717                 // And problems may arise because this face hasn't yet good connectivity.
02718                 nlassert(SonLeft->isLeaf() && SonRight->isLeaf());
02719         }
02720         else
02721         {
02722                 if(f0->FLeft)
02723                 {
02724                         while(f0->FLeft->isLeaf())
02725                                 f0->FLeft->updateBindAndSplit();
02726                 }
02727                 if(f1->FLeft)
02728                 {
02729                         while(f1->FLeft->isLeaf())
02730                                 f1->FLeft->updateBindAndSplit();
02731                 }
02732                 // There is a possible bug here (maybe easily patched). Sons may have be propagated splitted.
02733                 // And problems may arise because this face hasn't yet good connectivity.
02734                 nlassert(f0->SonLeft->isLeaf() && f0->SonRight->isLeaf());
02735                 nlassert(f1->SonLeft->isLeaf() && f1->SonRight->isLeaf());
02736         }
02737 
02738 
02739         // If multipatch face case, update neighbors.
02740         //===========================================
02741         if(!isRectangular() && fmult)
02742         {
02743                 // Update good Face neighbors.
02744                 //============================
02745                 SonLeft->FRight= fmult->SonRight;
02746                 fmult->SonRight->changeNeighbor(&CTessFace::MultipleBindFace, SonLeft);
02747 
02748                 SonRight->FLeft= fmult->SonLeft;
02749                 fmult->SonLeft->changeNeighbor(&CTessFace::MultipleBindFace, SonRight);
02750 
02751                 // NB: this work auto with 1/2 or 1/4. See CPatch::bind(), to understand.
02752                 // In 1/4 case, fmult->SonLeft and fmult->SonRight are themselves MultiPatch face. So it will recurse.
02753 
02754                 // Update good vertex pointer.
02755                 //============================
02756                 CTessVertex     *vert= fmult->VBase;
02757 
02758                 // Copy the good coordinate: those splitted (because of noise).
02759                 vert->Pos= vert->StartPos= vert->EndPos= SonLeft->VBase->EndPos;
02760                 // But delete the pointer.
02761                 Patch->getLandscape()->deleteTessVertex(SonLeft->VBase);
02762                 // And update sons pointers, to good vertex.
02763                 SonLeft->VBase= vert;
02764                 SonRight->VBase= vert;
02765                 // Compute correct centers.
02766                 SonRight->computeSplitPoint();
02767                 SonLeft->computeSplitPoint();
02768 
02769 
02770                 // Update good Far vertex pointer.
02771                 //================================
02772                 // Because *->VBase may have been merged to the multiple bind face, Near/FarVertices which pointed on it must
02773                 // be setup.
02774                 // We do not have to propagate this vertex ptr change since sons are leaves!!
02775                 nlassert(SonLeft->isLeaf() && SonRight->isLeaf());
02776                 // update pointers on vertex.
02777                 SonLeft->updateNearFarVertices();
02778                 SonRight->updateNearFarVertices();
02779 
02780 
02781                 // Bind FBase to a false face which indicate a bind 1/N.
02782                 // This face prevent for "this" face to be merged...
02783                 FBase= &CantMergeFace;
02784 
02785                 // Therefore, the vertex will be never deleted (since face not merged).
02786                 // The only way to do this, is to unbind the patch from all (then the vertex is cloned), then the merge will be Ok.
02787         }
02788         // Else if rectangular.
02789         else if(fmult0 || fmult1)
02790         {
02791                 CTessFace       *f;
02792                 sint            i;
02793 
02794                 // Same reasoning for rectangular patchs, as above.
02795                 for(i=0;i<2;i++)
02796                 {
02797                         if(i==0)
02798                                 f= f0, fmult= fmult0;
02799                         else
02800                                 f= f1, fmult= fmult1;
02801                         if(fmult)
02802                         {
02803                                 // Update good Face neighbors (when I am a rectangle).
02804                                 //============================
02805                                 // Consider the fmult face as a square face.
02806                                 CTessFace       *toLeft, *toRight;
02807                                 CTessFace       *fl=f->SonLeft, *fr=f->SonRight;
02808                                 toLeft= fmult->SonLeft;
02809                                 toRight= fmult->SonRight;
02810                                 // Cross connection of sons.
02811                                 fl->FLeft= toLeft;
02812                                 fr->FLeft= toRight;
02813                                 toLeft->changeNeighbor(&CTessFace::MultipleBindFace, fl);
02814                                 toRight->changeNeighbor(&CTessFace::MultipleBindFace, fr);
02815 
02816                                 // Update good vertex pointer.
02817                                 //============================
02818                                 CTessVertex     *vert= fmult->VBase;
02819 
02820                                 // Copy the good coordinate: those splitted (because of noise).
02821                                 // NB: this work too with rectangular patch (see tesselation rules).
02822                                 vert->Pos= vert->StartPos= vert->EndPos= fl->VBase->EndPos;
02823                                 // But delete the pointer.
02824                                 Patch->getLandscape()->deleteTessVertex(fl->VBase);
02825                                 // And update sons pointers, to good vertex (rectangular case, see tesselation rules).
02826                                 fl->VBase= vert;
02827                                 fr->VLeft= vert;
02828                                 f->FBase->SonLeft->VRight= vert;
02829 
02830                                 // Point to a bind 1/N indicator.
02831                                 f->FLeft= &CantMergeFace;
02832                         }
02833                 }
02834                 // After all updates done. recompute centers of both sons 's faces, and update far vertices pointers.
02835                 for(i=0;i<2;i++)
02836                 {
02837                         if(i==0)
02838                                 f= f0;
02839                         else
02840                                 f= f1;
02841                         // Compute correct centers.
02842                         f->SonRight->computeSplitPoint();
02843                         f->SonLeft->computeSplitPoint();
02844 
02845                         // Update good Far vertex pointer.
02846                         //================================
02847                         // Because *->VBase may have been merged to the multiple bind face, Near/FarVertices which pointed on it must
02848                         // be setup.
02849                         // We do not have to propagate this vertex ptr change, since sons are leaves!!
02850                         nlassert(f->SonLeft->isLeaf() && f->SonRight->isLeaf());
02851                         // update pointers on vertex.
02852                         f->SonLeft->updateNearFarVertices();
02853                         f->SonRight->updateNearFarVertices();
02854                 }
02855         }
02856 }

bool NL3D::CTessFace::updateBindEdge CTessFace *&  edgeFace,
bool &  splitWanted
 

Definition at line 2544 of file tessellation.cpp.

References FBase, FLeft, FRight, isLeaf(), isRectangular(), nlstop, Patch, SonLeft, and SonRight.

Referenced by updateBind(), and updateBindAndSplit().

02545 {
02546         // Return true, when the bind should be Ok, or if a split has occured.
02547         // Return false only if pointers are updated, without splits.
02548 
02549         if(edgeFace==NULL)
02550                 return true;
02551 
02552         if(edgeFace->isLeaf())
02553                 return true;
02554 
02555         /*
02556                 Look at the callers, and you'll see that "this" is always a leaf.
02557                 Therefore, edgeFace is a valid pointer (either if it is FLeft, FRight or FBase).
02558         */
02559 
02560         // MultiPatch face case.
02561         //======================
02562         // If neighbor is a multiple face.
02563         if(edgeFace->Patch==NULL && edgeFace->FBase==this)
02564         {
02565                 splitWanted= true;
02566                 return true;
02567         }
02568 
02569 
02570         // neighbor is a "Square face" case.
02571         //==================================
02572         if(!edgeFace->isRectangular())
02573         {
02574                 // NB: this code works either if I AM a rectangular face or a square face.
02575 
02576                 // If the neighbor is splitted  on ourself, split...
02577                 if(edgeFace->FBase==this)
02578                 {
02579                         splitWanted= true;
02580                         return true;
02581                 }
02582                 else
02583                 {
02584                         // Just update pointers...
02585                         if(edgeFace->FLeft==this)
02586                         {
02587                                 CTessFace       *sonLeft= edgeFace->SonLeft;
02588                                 sonLeft->FBase= this;
02589                                 edgeFace= sonLeft;
02590                         }
02591                         else if(edgeFace->FRight==this)
02592                         {
02593                                 CTessFace       *sonRight= edgeFace->SonRight;
02594                                 sonRight->FBase= this;
02595                                 edgeFace= sonRight;
02596                         }
02597                         else
02598                         {
02599                                 // Look at the callers, and you'll see that "this" is always a leaf.
02600                                 // Therefore, we should never be here.
02601                                 nlstop;
02602                         }
02603                 }
02604         }
02605         // neighbor is a "Rectangle face" case.
02606         //=====================================
02607         else
02608         {
02609                 // NB: this code works either if I AM a rectangular face or a square face.
02610 
02611                 // If the neighbor is splitted  on ourself, split...
02612                 // Test FLeft because of rectangular case... :)
02613                 // FBase should be tested too. If edgeFace->FBase==this, I should be myself a rectangular face.
02614                 if(edgeFace->FLeft==this || edgeFace->FBase==this)
02615                 {
02616                         splitWanted= true;
02617                         return true;
02618                 }
02619                 else
02620                 {
02621                         if(edgeFace->FRight==this)
02622                         {
02623                                 // See rectangular tesselation rules, too know why we do this.
02624                                 CTessFace       *sonRight= edgeFace->SonRight;
02625                                 sonRight->FRight= this;
02626                                 edgeFace= sonRight;
02627                         }
02628                         else
02629                         {
02630                                 // Look at the callers, and you'll see that "this" is always a leaf.
02631                                 // Therefore, we should never be here.
02632                                 nlstop;
02633                         }
02634                 }
02635         }
02636 
02637         return false;
02638 }

void NL3D::CTessFace::updateErrorMetric  ) 
 

Definition at line 278 of file tessellation.cpp.

References computeTileErrorMetric(), ErrorMetric, ErrorMetricDate, MaxDistToSplitPoint, SplitPoint, NLMISC::sqr(), NLMISC::CVector::sqrnorm(), and NL3D::CPatch::TileLimitLevel.

Referenced by canMerge(), refineAll(), updateRefineMerge(), and updateRefineSplit().

00279 {
00280         // If already updated for this pass...
00281         if(ErrorMetricDate>= CLandscapeGlobals::CurrentDate)
00282                 return;
00283 
00284         CVector viewdir= SplitPoint - CLandscapeGlobals::RefineCenter;
00285         float   sqrdist= viewdir.sqrnorm();
00286 
00287         // trivial formula.
00288         //-----------------
00289         ErrorMetric= Size/ sqrdist;
00290 
00291 
00292         // Hoppe97 formula:  k²= a² * ("v-e"² - ((v-e).n)²) / "v-e"^4.
00293         //-----------------
00294         // Can't do it because geomorph is made on Graphic card, so the simplier is the better.
00295 
00296 
00297         // TileMode Impact.
00298         //-----------------
00299         /* TileMode Impact. We must split at least at TileLimitLevel, but only if the triangle
00300                 has a chance to enter in the TileDistFar sphere.
00301         */
00302         if( Level<Patch->TileLimitLevel && sqrdist < sqr(CLandscapeGlobals::TileDistFar+MaxDistToSplitPoint) )
00303         {
00304                 computeTileErrorMetric();
00305         }
00306 
00307         ErrorMetricDate= CLandscapeGlobals::CurrentDate;
00308 }

void NL3D::CTessFace::updateNearFarVertices  )  [private]
 

Definition at line 873 of file tessellation.cpp.

References NL3D::CPatch::checkFillVertexVBFar(), NL3D::CPatch::checkFillVertexVBNear(), FVBase, FVLeft, FVRight, IdUvBase, IdUvLeft, IdUvRight, NL3D_MAX_TILE_FACE, nlassert, PVBase, PVLeft, PVRight, sint, NL3D::CTessNearVertex::Src, TileFaces, NL3D::CTileFace::V, VBase, VLeft, and VRight.

Referenced by unbind(), and updateBindAndSplit().

00874 {
00875         nlassert(VBase && FVBase);
00876         nlassert(VLeft && FVLeft);
00877         nlassert(VRight && FVRight);
00878 
00879         FVBase->Src= VBase;
00880         FVLeft->Src= VLeft;
00881         FVRight->Src= VRight;
00882         FVBase->PCoord= PVBase;
00883         FVLeft->PCoord= PVLeft;
00884         FVRight->PCoord= PVRight;
00885 
00886         // Update VB for far vertices (if needed)
00887         Patch->checkFillVertexVBFar(FVBase);
00888         Patch->checkFillVertexVBFar(FVLeft);
00889         Patch->checkFillVertexVBFar(FVRight);
00890 
00891         // Near Vertices update (Src only).
00892         for(sint i=0; i<NL3D_MAX_TILE_FACE; i++)
00893         {
00894                 if(TileFaces[i])
00895                 {
00896                         TileFaces[i]->V[IdUvBase]->Src= VBase;
00897                         TileFaces[i]->V[IdUvLeft]->Src= VLeft;
00898                         TileFaces[i]->V[IdUvRight]->Src= VRight;
00899 
00900                         // Update VB for near vertices (if needed)
00901                         Patch->checkFillVertexVBNear(TileFaces[i]->V[IdUvBase]);
00902                         Patch->checkFillVertexVBNear(TileFaces[i]->V[IdUvLeft]);
00903                         Patch->checkFillVertexVBNear(TileFaces[i]->V[IdUvRight]);
00904                 }
00905         }
00906 
00907 }

void NL3D::CTessFace::updateRefineMerge  ) 
 

TileDistFar to +oo.

TileDistNear to TileDistFar.

0 to TileDistNear.

Definition at line 2108 of file tessellation.cpp.

References NL3D::CLandscape::_MergePriorityList, canMerge(), computeNearLimit(), computeTileEMForUpdateRefine(), NL3D::CTessVertex::EndPos, ErrorMetric, NL3D::CPatch::getLandscape(), NL3D::CTessFacePriorityList::insert(), isLeaf(), merge(), min, NL3D_PROFILE_LAND_ADD, NL3D_REFINE_MERGE_THRESHOLD, nlassert, NL3D::ProfNRefineFaces, NL3D::ProfNRefineInTileTransition, SplitPoint, NL3D::CPatch::TileLimitLevel, uint, updateErrorMetric(), VBase, VLeft, and VRight.

Referenced by NL3D::CLandscape::refine().

02109 {
02110         NL3D_PROFILE_LAND_ADD(ProfNRefineFaces, 1);
02111 
02112         nlassert(Patch);
02113         // The face must be splitted, because tested for merge.
02114         nlassert(!isLeaf());
02115 
02116         /*
02117                 NB: see above for some updateRefine*** doc.
02118         */
02119 
02120         // Test for merge.
02121         //-----------------------
02122         bool    merged= false;
02123         {
02124                 updateErrorMetric();
02125                 float   ps=ErrorMetric;
02126                 ps*= CLandscapeGlobals::OORefineThreshold;
02127                 // 1.0f is the point of split().
02128                 // 2.0f is the end of geomorph.
02129 
02130 
02131                 // Test merge.
02132                 //---------------------
02133                 // Else, must merge ??
02134                 if(ps<1.0f)
02135                 {
02136                         // Merge only if agree, and neighbors agree.
02137                         // canMerge() test all the good thing: FBase==CantMergeFace, or this is rectangular etc...
02138                         // The test is propagated to neighbors.
02139                         if(canMerge(true))
02140                         {
02141                                 merge();
02142 
02143                                 // NB: here, merge() is not propagated to fathers (supposed to be not very usefull).
02144 
02145                                 if(isLeaf())
02146                                 {
02147                                         merged= true;
02148                                 }
02149                         }
02150                 }
02151         }
02152 
02153 
02154         // Insert the face in the priority list.
02155         //-----------------------
02156         // If merged, then insertion in Landscape->SplitPriorityList at 0 has been done. so nothing to update.
02157         // Else, must compute when whe should re-test.
02158         if(!merged)
02159         {
02160                 // the face is splitted here.
02161                 nlassert(!isLeaf());
02162 
02163                 float   minDeltaDistToUpdate;
02164 
02165 
02166                 // The distance of SplitPoint to center.
02167                 float   distSplitPoint= (SplitPoint - CLandscapeGlobals::RefineCenter).norm();
02168                 // Compute distance from refineCenter to normal split/merge (ie without tile transition).
02169                 float   distNormalSplitMerge= (float)sqrt(Size*CLandscapeGlobals::OORefineThreshold);
02170 
02171 
02172                 // If the face is at its max subdivision
02173                 if(Level>=Patch->TileLimitLevel+CLandscapeGlobals::TileMaxSubdivision)
02174                 {
02175                         // since the face is splitted, then must test always this face, because we must merge it (as soon as it is possible).
02176                         minDeltaDistToUpdate= 0;
02177                 }
02178                 else if(Level>=Patch->TileLimitLevel)
02179                 {
02180                         // Always normal ErrorMetric. Because Faces at Tile level decide to split or merge their sons independently 
02181                         // of "Tile ErrorMetric".
02182                         // since splitted, compute distance to merge.
02183                         minDeltaDistToUpdate= distNormalSplitMerge - distSplitPoint;
02184                         // NB: it is possible that minDeltaDistToUpdate<0. A good example is when we are enforced split.
02185                         // Then, distSplitMerge may be < distSplitPoint, meaning we should have not split, but a neigbhor has enforced us.
02186                         // So now, must test every frame if we can merge....
02187                         minDeltaDistToUpdate= max( 0.f, minDeltaDistToUpdate );
02188                 }
02189                 else
02190                 {
02191                         // Compute Distance of the face from RefineCenter. It is the min of the 3 points, as in computeTileErrorMetric().
02192                         float   s0= (VBase->EndPos - CLandscapeGlobals::RefineCenter).sqrnorm();
02193                         float   s1= (VLeft->EndPos - CLandscapeGlobals::RefineCenter).sqrnorm();
02194                         float   s2= (VRight->EndPos - CLandscapeGlobals::RefineCenter).sqrnorm();
02195                         float   distMinFace= (float)sqrt( minof(s0, s1, s2) );
02196 
02197                         // compute the delta distance to the normal split point. See above for doc.
02198                         float   normalEMDeltaDist;
02199                         normalEMDeltaDist= distNormalSplitMerge - distSplitPoint;
02200                         normalEMDeltaDist= max( 0.f, normalEMDeltaDist );
02201 
02202 
02203                         /* 
02204                         There is 3 possibles cases, according to level, and the distances minFaceDist:
02205                         */
02207                         if( distMinFace > CLandscapeGlobals::TileDistFar )
02208                         {
02209                                 // normal geomorph. Any face compute the distance to the SplitPoint, and take min with distance to
02210                                 // the TileDistFar sphere. 
02211                                 minDeltaDistToUpdate= normalEMDeltaDist;
02212 
02213                                 // We must know when we enter in TileErrorMetric zone, because the computing is different.
02214                                 minDeltaDistToUpdate= min(minDeltaDistToUpdate, distMinFace - CLandscapeGlobals::TileDistFar);
02215                         }
02217                         else if( distMinFace > CLandscapeGlobals::TileDistNear )
02218                         {
02219                                 // Profile
02220                                 NL3D_PROFILE_LAND_ADD(ProfNRefineInTileTransition, 1);
02221 
02222 
02223                                 // Compute distance to split/Merge in TileTransition
02224                                 float   distTileTransSplitMerge;
02225                                 float   maxDeltaDist= 8;
02226                                 float   minDeltaDist= 0;
02227                                 uint    nbRecurs= 6;
02228                                 float   nearLimit;
02229                                 nearLimit= CLandscapeGlobals::RefineThreshold * computeNearLimit();
02230                                 // Since splitted, compute distance to merge.
02231                                 // search the distance recursively.
02232                                 for(uint i=0; i< nbRecurs; i++)
02233                                 {
02234                                         float   pivotDeltaDist= (maxDeltaDist-minDeltaDist)/2;
02235                                         // If the em computed with this distance is still >1 (ie splitted), then we can move further.
02236                                         if ( computeTileEMForUpdateRefine(distSplitPoint+pivotDeltaDist, distMinFace+pivotDeltaDist, nearLimit ) > 1)
02237                                                 minDeltaDist= pivotDeltaDist;
02238                                         // else we must move not as far
02239                                         else
02240                                                 maxDeltaDist= pivotDeltaDist;
02241                                 }
02242                                 // And so take the minimum resulting delta distance
02243                                 distTileTransSplitMerge= minDeltaDist;
02244                                 
02245                                 // take the min with distance of distMinFace to the TileDistNear and TileDistFar sphere, because formula change at
02246                                 // those limits.
02247                                 minDeltaDistToUpdate= min(distTileTransSplitMerge, CLandscapeGlobals::TileDistFar - distMinFace );
02248                                 minDeltaDistToUpdate= min(minDeltaDistToUpdate, distMinFace - CLandscapeGlobals::TileDistNear);
02249                         }
02251                         else
02252                         {
02253                                 // because the face is not a Tile Level (ie Level<Patch->TileLimitLevel), it should be splitted, 
02254                                 // and won't merge until reaching at least the TileDistNear sphere.
02255                                 // Since splitted, Must enter in TileErrorMetric area to know when to merge.
02256                                 minDeltaDistToUpdate= CLandscapeGlobals::TileDistNear - distMinFace;
02257                         }
02258 
02259                 }
02260 
02261                 // Merge Refine Threshold: because of enforced splits, we have lot of faces whit minDeltaDistToUpdate<0, because
02262                 // they alwayas want to merge. To avoid this, add a delta, which delay the test for merge.
02263                 // The caveat is that faces which do not need this may merge later. But 2 meters won't add too many faces.
02264                 minDeltaDistToUpdate+= NL3D_REFINE_MERGE_THRESHOLD;
02265 
02266                 // insert in the Merge priority list.
02267                 // Until the RefineCenter move under minDeltaDistToUpdate, we don't need to test face.
02268                 Patch->getLandscape()->_MergePriorityList.insert(0, minDeltaDistToUpdate, this);
02269         }
02270 }

void NL3D::CTessFace::updateRefineSplit  ) 
 

TileDistFar to +oo.

TileDistNear to TileDistFar.

0 to TileDistNear.

Definition at line 1900 of file tessellation.cpp.

References NL3D::CLandscape::_SplitPriorityList, computeNearLimit(), computeTileEMForUpdateRefine(), NL3D::CTessVertex::EndPos, ErrorMetric, NL3D::CPatch::getLandscape(), NL3D::CTessFacePriorityList::getQuadrantDirection(), NL3D::CTessFacePriorityList::insert(), isLeaf(), min, NL3D_PROFILE_LAND_ADD, NL3D_TESS_USE_QUADRANT_THRESHOLD, nlassert, NLMISC::CVector::norm(), NL3D::ProfNRefineFaces, NL3D::ProfNRefineInTileTransition, NL3D::ProfNRefineWithLowDistance, NL3D::CTessFacePriorityList::selectQuadrant(), split(), SplitPoint, NLMISC::CVector::sqrnorm(), NL3D::CPatch::TileLimitLevel, uint, NL3D::CTessFacePListNode::unlinkInPList(), updateErrorMetric(), VBase, VLeft, and VRight.

Referenced by NL3D::CLandscape::refine().

01901 {
01902         NL3D_PROFILE_LAND_ADD(ProfNRefineFaces, 1);
01903 
01904         nlassert(Patch);
01905         // The face must be not splitted, because tested for split.
01906         nlassert(isLeaf());
01907 
01908         /*
01909                 NB: see above for some updateRefine*** doc.
01910         */
01911 
01912         // Test for Split.
01913         //-----------------------
01914         bool    splitted= false;
01915         {
01916                 updateErrorMetric();
01917                 float   ps=ErrorMetric;
01918                 ps*= CLandscapeGlobals::OORefineThreshold;
01919                 // 1.0f is the point of split().
01920                 // 2.0f is the end of geomorph.
01921 
01922 
01923                 // Test split.
01924                 //---------------------
01925                 // If wanted and limit not reached, split().
01926                 if(ps>1.0f && Level< (Patch->TileLimitLevel + CLandscapeGlobals::TileMaxSubdivision) )
01927                 {
01928                         split();
01929 
01930                         // if split ok
01931                         if(!isLeaf())
01932                         {
01933                                 splitted= true;
01934                         }
01935                 }
01936         }
01937 
01938 
01939         // Insert the face in the priority list.
01940         //-----------------------
01941         // If splitted, then insertion in Landscape->MergePriorityList at 0 has been done. so nothing to update.
01942         // Else, must compute when whe should re-test.
01943         if(!splitted)
01944         {
01945                 // the face is not splitted here.
01946                 nlassert(isLeaf());
01947 
01948                 float   minDeltaDistToUpdate;
01949 
01950                 // by default insert in the quadrant-less rolling table.
01951                 uint    quadrantId= 0;
01952 
01953 
01954                 CVector         dirToSplitPoint= SplitPoint - CLandscapeGlobals::RefineCenter;
01955                 // The distance of SplitPoint to center.
01956                 float           distSplitPoint= dirToSplitPoint.norm();
01957                 // The distance where we should split/merge. see updateRefin() doc.
01958                 float           distNormalSplitMerge= (float)sqrt(Size*CLandscapeGlobals::OORefineThreshold);
01959 
01960 
01961                 // If the face is at its max subdivision
01962                 if(Level>=Patch->TileLimitLevel+CLandscapeGlobals::TileMaxSubdivision)
01963                 {
01964                         // special case: the face do not need to be tested for splitting, because Max subdivision reached.
01965                         // Hence just unlink from any list, and return.
01966                         unlinkInPList();
01967                         return;
01968                 }
01969                 else if(Level>=Patch->TileLimitLevel)
01970                 {
01971                         // Always normal ErrorMetric. Because Faces at Tile level decide to split or merge their sons independently 
01972                         // of "Tile ErrorMetric".
01973 
01974                         // The test is "when do we enter in the Split area?", so we can use Quadrant PriorityList
01975                         quadrantId= Patch->getLandscape()->_SplitPriorityList.selectQuadrant(dirToSplitPoint);
01976 
01977                         // compute distance to split as default "No Quadrant"
01978                         minDeltaDistToUpdate= distSplitPoint - distNormalSplitMerge;
01979 
01980                         // If a quadrant is  selected, try to use it
01981                         if(quadrantId>0)
01982                         {
01983                                 const CVector   &quadrantDir= Patch->getLandscape()->_SplitPriorityList.getQuadrantDirection(quadrantId);
01984 
01985                                 // We must not approach the SplitPoint at distNormalSplitMerge
01986                                 float   dMin= quadrantDir*dirToSplitPoint - distNormalSplitMerge;
01987 
01988                                 // If the dist with quadrant is too small then use the std way (without quadrant).
01989                                 if( dMin<NL3D_TESS_USE_QUADRANT_THRESHOLD )
01990                                         quadrantId= 0;
01991                                 // else ok, use quadrant behavior
01992                                 else
01993                                         minDeltaDistToUpdate= dMin;
01994                         }
01995                 }
01996                 else
01997                 {
01998                         // Compute Distance of the face from RefineCenter. It is the min of the 3 points, as in computeTileErrorMetric().
01999                         CVector dirToV0= VBase->EndPos - CLandscapeGlobals::RefineCenter;
02000                         CVector dirToV1= VLeft->EndPos - CLandscapeGlobals::RefineCenter;
02001                         CVector dirToV2= VRight->EndPos - CLandscapeGlobals::RefineCenter;
02002                         float   s0= dirToV0.sqrnorm();
02003                         float   s1= dirToV1.sqrnorm();
02004                         float   s2= dirToV2.sqrnorm();
02005                         float   distMinFace= (float)sqrt( minof(s0, s1, s2) );
02006 
02007                         // compute the delta distance to the normal split point. See above for doc.
02008                         float   normalEMDeltaDist;
02009                         normalEMDeltaDist= distSplitPoint - distNormalSplitMerge;
02010 
02011 
02012                         /* 
02013                         There is 3 possibles cases, according to level, and the distances minFaceDist:
02014                         */
02016                         if( distMinFace > CLandscapeGlobals::TileDistFar )
02017                         {
02018                                 // The test is "when do we enter in the Split area OR in TileDistFar area?", so we can use Quadrant PriorityList
02019                                 quadrantId= Patch->getLandscape()->_SplitPriorityList.selectQuadrant(dirToSplitPoint);
02020 
02021                                 // compute deltaDist as default "Direction less quadrant"
02022                                 minDeltaDistToUpdate= normalEMDeltaDist;
02023                                 // We must know when we enter in TileErrorMetric zone, because the computing is different.
02024                                 minDeltaDistToUpdate= min(minDeltaDistToUpdate, distMinFace - CLandscapeGlobals::TileDistFar);
02025 
02026                                 // try with quadrant if > 0.
02027                                 if(quadrantId>0)                                
02028                                 {
02029                                         const CVector   &quadrantDir= Patch->getLandscape()->_SplitPriorityList.getQuadrantDirection(quadrantId);
02030 
02031                                         // We must not approach the SplitPoint at distNormalSplitMerge
02032                                         float   dMin= quadrantDir*dirToSplitPoint - distNormalSplitMerge;
02033                                         // and we must not reach one of the 3 sphere (Vi, TileDistFar).
02034                                         float   d0 = quadrantDir*dirToV0 - CLandscapeGlobals::TileDistFar;
02035                                         float   d1 = quadrantDir*dirToV1 - CLandscapeGlobals::TileDistFar;
02036                                         float   d2 = quadrantDir*dirToV2 - CLandscapeGlobals::TileDistFar;
02037                                         // take min dist
02038                                         dMin= minof(dMin, d0, d1, d2);
02039 
02040                                         // If the dist with quadrant is too small then use the std way (without quadrant).
02041                                         if( dMin<NL3D_TESS_USE_QUADRANT_THRESHOLD )
02042                                                 quadrantId= 0;
02043                                         // else ok, use quadrant behavior
02044                                         else
02045                                                 minDeltaDistToUpdate= dMin;
02046                                 }
02047                         }
02049                         else if( distMinFace > CLandscapeGlobals::TileDistNear )
02050                         {
02051                                 // NB: can't use quadrant behavior here. Leave quadrantId at 0.
02052 
02053                                 // Profile
02054                                 NL3D_PROFILE_LAND_ADD(ProfNRefineInTileTransition, 1);
02055 
02056                                 // Compute distance to split/Merge in TileTransition
02057                                 float   distTileTransSplitMerge;
02058                                 float   maxDeltaDist= 8;
02059                                 float   minDeltaDist= 0;
02060                                 uint    nbRecurs= 6;
02061                                 float   nearLimit;
02062                                 nearLimit= CLandscapeGlobals::RefineThreshold * computeNearLimit();
02063                                 // search the distance to split recursively.
02064                                 for(uint i=0; i< nbRecurs; i++)
02065                                 {
02066                                         float   pivotDeltaDist= (maxDeltaDist-minDeltaDist)/2;
02067                                         // If the em computed with this distance is still <1 (ie merged), then we can move further.
02068                                         if ( computeTileEMForUpdateRefine(distSplitPoint-pivotDeltaDist, distMinFace-pivotDeltaDist, nearLimit ) < 1)
02069                                                 minDeltaDist= pivotDeltaDist;
02070                                         // else we must move not as far
02071                                         else
02072                                                 maxDeltaDist= pivotDeltaDist;
02073                                 }
02074                                 // And so take the minimum resulting delta distance
02075                                 distTileTransSplitMerge= minDeltaDist;
02076                                 
02077                                 // take the min with distance of distMinFace to the TileDistNear and TileDistFar sphere, because formula change at
02078                                 // those limits.
02079                                 minDeltaDistToUpdate= min(distTileTransSplitMerge, CLandscapeGlobals::TileDistFar - distMinFace );
02080                                 minDeltaDistToUpdate= min(minDeltaDistToUpdate, distMinFace - CLandscapeGlobals::TileDistNear);
02081                         }
02083                         else
02084                         {
02085                                 // because the face is not a Tile Level (ie Level<Patch->TileLimitLevel), it should be splitted, 
02086                                 // and won't merge until reaching at least the TileDistNear sphere.
02087                                 // if not splited (should not arise), force the split next time.
02088                                 minDeltaDistToUpdate= 0;
02089                         }
02090 
02091                 }
02092 
02093                 // Profile.
02094                 if(minDeltaDistToUpdate<0.0625)
02095                 {
02096                         NL3D_PROFILE_LAND_ADD(ProfNRefineWithLowDistance, 1);
02097                 }
02098 
02099 
02100                 // insert in the Split priority list.
02101                 // Until the RefineCenter move under minDeltaDistToUpdate, we don't need to test face.
02102                 Patch->getLandscape()->_SplitPriorityList.insert(quadrantId, minDeltaDistToUpdate, this);
02103         }
02104 }


Field Documentation

CTessFace NL3D::CTessFace::CantMergeFace [static, private]
 

Definition at line 156 of file tessellation.cpp.

Referenced by averageTesselationVertices(), canMerge(), forceMerge(), forceMergeAtTileLevel(), and updateBindAndSplit().

float NL3D::CTessFace::ErrorMetric
 

Definition at line 276 of file tessellation.h.

Referenced by canMerge(), computeTileErrorMetric(), refineAll(), updateErrorMetric(), updateRefineMerge(), and updateRefineSplit().

sint NL3D::CTessFace::ErrorMetricDate
 

Definition at line 273 of file tessellation.h.

Referenced by CTessFace(), and updateErrorMetric().

CTessFace* NL3D::CTessFace::Father
 

Definition at line 243 of file tessellation.h.

Referenced by split(), and splitRectangular().

CTessFace* NL3D::CTessFace::FBase
 

Definition at line 242 of file tessellation.h.

Referenced by averageTesselationVertices(), NL3D::CPatch::bind(), canMerge(), changeNeighbor(), computeTileMaterial(), CTessFace(), deleteTileUvs(), doMerge(), forceMerge(), heritTileMaterial(), linkTessFaceWithEdge(), NL3D::CPatch::makeRoots(), releaseTileMaterial(), split(), splitRectangular(), unbind(), updateBind(), updateBindAndSplit(), and updateBindEdge().

CTessFace * NL3D::CTessFace::FLeft
 

Definition at line 242 of file tessellation.h.

Referenced by averageTesselationVertices(), NL3D::CPatch::bind(), canMerge(), NL3D::CPatch::changeEdgeNeighbor(), changeNeighbor(), CTessFace(), doMerge(), forceMerge(), linkTessFaceWithEdge(), NL3D::CPatch::makeRoots(), NL3D::CPatch::release(), split(), splitRectangular(), unbind(), NL3D::CPatch::unbind(), updateBind(), updateBindAndSplit(), and updateBindEdge().

CTessFace * NL3D::CTessFace::FRight
 

Definition at line 242 of file tessellation.h.

Referenced by NL3D::CPatch::bind(), NL3D::CPatch::changeEdgeNeighbor(), changeNeighbor(), CTessFace(), doMerge(), linkTessFaceWithEdge(), NL3D::CPatch::makeRoots(), NL3D::CPatch::release(), split(), splitRectangular(), unbind(), NL3D::CPatch::unbind(), updateBind(), updateBindAndSplit(), and updateBindEdge().

CTessFarVertex* NL3D::CTessFace::FVBase
 

Definition at line 282 of file tessellation.h.

Referenced by NL3D::CPatch::bind(), doMerge(), NL3D::CPatch::makeRoots(), NL3D::CTessBlock::refillFaceVectorFar0(), NL3D::CTessBlock::refillFaceVectorFar1(), split(), splitRectangular(), and updateNearFarVertices().

CTessFarVertex * NL3D::CTessFace::FVLeft
 

Definition at line 282 of file tessellation.h.

Referenced by NL3D::CPatch::bind(), NL3D::CPatch::makeRoots(), NL3D::CTessBlock::refillFaceVectorFar0(), NL3D::CTessBlock::refillFaceVectorFar1(), split(), splitRectangular(), and updateNearFarVertices().

CTessFarVertex * NL3D::CTessFace::FVRight
 

Definition at line 282 of file tessellation.h.

Referenced by NL3D::CPatch::bind(), NL3D::CPatch::makeRoots(), NL3D::CTessBlock::refillFaceVectorFar0(), NL3D::CTessBlock::refillFaceVectorFar1(), split(), splitRectangular(), and updateNearFarVertices().

uint8 NL3D::CTessFace::Level
 

Definition at line 247 of file tessellation.h.

Referenced by NL3D::CPatch::appendFaceToRenderList(), computeTileMaterial(), deleteTileUvs(), doMerge(), NL3D::CPatch::extendTessBlockWithEndPos(), NL3D::CPatch::makeRoots(), recreateTileUvs(), releaseTileMaterial(), NL3D::CPatch::removeFaceFromRenderList(), split(), and splitRectangular().

float NL3D::CTessFace::MaxDistToSplitPoint
 

Definition at line 277 of file tessellation.h.

Referenced by computeSplitPoint(), and updateErrorMetric().

CTessFace NL3D::CTessFace::MultipleBindFace [static]
 

Definition at line 157 of file tessellation.cpp.

CTessNodeList* NL3D::CTessNodeList::Next [inherited]
 

Definition at line 44 of file tess_list.h.

Referenced by NL3D::CVegetableManager::addInstance(), NL3D::CLandscape::computeDynamicLighting(), NL3D::CPatch::computeGeomorphAlphaFar1VertexListVB(), NL3D::CPatch::computeGeomorphFar0VertexListVB(), NL3D::CPatch::computeGeomorphTileVertexListVB(), NL3D::CPatch::computeGeomorphVertexList(), NL3D::CPatch::debugAllocationMarkIndicesFarList(), NL3D::CPatch::debugAllocationMarkIndicesNearList(), NL3D::CPatch::fillFar0DLMUvOnlyVertexListVB(), NL3D::CPatch::fillFar0VertexListVB(), NL3D::CPatch::fillFar1DLMUvOnlyVertexListVB(), NL3D::CPatch::fillFar1VertexListVB(), NL3D::CPatch::fillTileVertexListVB(), NL3D::CLandscape::getDynamicLightingMemoryLoad(), NL3D::CTessBlock::refillFaceVectorFar0(), NL3D::CTessBlock::refillFaceVectorFar1(), NL3D::CTessBlock::refillFaceVectorTile(), NL3D::CLandscape::refine(), NL3D::CVegetableManager::render(), NL3D::CLandscape::render(), NL3D::CPatch::updateFar0VBAlloc(), NL3D::CPatch::updateFar1VBAlloc(), NL3D::CVegetableSortBlock::updateSortBlock(), and NL3D::CPatch::updateTileVBAlloc().

CPatch* NL3D::CTessFace::Patch
 

Definition at line 240 of file tessellation.h.

Referenced by averageTesselationVertices(), NL3D::CZoneLighter::buildZoneInformation(), computeTileMaterial(), doMerge(), NL3D::CPatch::makeRoots(), sameTile(), split(), splitRectangular(), unbind(), updateBindAndSplit(), and updateBindEdge().

CTessNodeList* NL3D::CTessNodeList::Prec [inherited]
 

Definition at line 43 of file tess_list.h.

Referenced by NL3D::CTessNodeList::CTessNodeList().

CParamCoord NL3D::CTessFace::PVBase
 

Definition at line 245 of file tessellation.h.

Referenced by NL3D::CZoneLighter::addTriangles(), averageTesselationVertices(), NL3D::CZoneLighter::buildZoneInformation(), computeTesselatedPos(), computeTileMaterial(), NL3D::CPatch::getNumTessBlock(), getTesselatedPos(), linkTessFaceWithEdge(), NL3D::CPatch::makeRoots(), refreshTesselationGeometry(), split(), splitRectangular(), and updateNearFarVertices().

CParamCoord NL3D::CTessFace::PVLeft
 

Definition at line 245 of file tessellation.h.

Referenced by NL3D::CZoneLighter::addTriangles(), NL3D::CZoneLighter::buildZoneInformation(), computeTesselatedPos(), computeTileMaterial(), NL3D::CPatch::getNumTessBlock(), getTesselatedPos(), linkTessFaceWithEdge(), NL3D::CPatch::makeRoots(), split(), splitRectangular(), and updateNearFarVertices().

CParamCoord NL3D::CTessFace::PVRight
 

Definition at line 245 of file tessellation.h.

Referenced by NL3D::CZoneLighter::addTriangles(), NL3D::CZoneLighter::buildZoneInformation(), computeTesselatedPos(), computeTileMaterial(), NL3D::CPatch::getNumTessBlock(), getTesselatedPos(), linkTessFaceWithEdge(), NL3D::CPatch::makeRoots(), split(), splitRectangular(), and updateNearFarVertices().

bool NL3D::CTessFace::RecursMarkCanMerge
 

Definition at line 249 of file tessellation.h.

Referenced by canMerge(), and CTessFace().

bool NL3D::CTessFace::RecursMarkForceMerge
 

Definition at line 250 of file tessellation.h.

Referenced by CTessFace(), and forceMerge().

sint NL3D::CTessFace::ShadowMapTriId
 

Definition at line 286 of file tessellation.h.

Referenced by NL3D::CLandscape::appendToShadowPolyReceiver(), CTessFace(), NL3D::CLandscape::removeFromShadowPolyReceiver(), and ~CTessFace().

float NL3D::CTessFace::Size
 

Definition at line 274 of file tessellation.h.

Referenced by NL3D::CPatch::makeRoots(), split(), splitRectangular(), and unbind().

CTessFace * NL3D::CTessFace::SonLeft
 

Definition at line 243 of file tessellation.h.

Referenced by appendTessellationLeaves(), averageTesselationVertices(), NL3D::CPatch::bind(), canMerge(), CTessFace(), deleteTileUvs(), doMerge(), forceMerge(), forceMergeAtTileLevel(), getTesselatedPos(), heritTileMaterial(), isLeaf(), linkTessFaceWithEdge(), recreateTileUvs(), refineAll(), refreshTesselationGeometry(), split(), splitRectangular(), unbind(), updateBind(), updateBindAndSplit(), and updateBindEdge().

CTessFace * NL3D::CTessFace::SonRight
 

Definition at line 243 of file tessellation.h.

Referenced by appendTessellationLeaves(), averageTesselationVertices(), NL3D::CPatch::bind(), canMerge(), CTessFace(), deleteTileUvs(), doMerge(), forceMerge(), forceMergeAtTileLevel(), getTesselatedPos(), heritTileMaterial(), linkTessFaceWithEdge(), recreateTileUvs(), refineAll(), refreshTesselationGeometry(), split(), splitRectangular(), unbind(), updateBind(), updateBindAndSplit(), and updateBindEdge().

CVector NL3D::CTessFace::SplitPoint
 

Definition at line 275 of file tessellation.h.

Referenced by computeSplitPoint(), updateErrorMetric(), updateRefineMerge(), and updateRefineSplit().

CTileFace* NL3D::CTessFace::TileFaces[NL3D_MAX_TILE_FACE]
 

Definition at line 261 of file tessellation.h.

Referenced by allocTileUv(), NL3D::CPatch::appendFaceToTileRenderList(), buildTileFaces(), checkCreateFillTileVB(), checkFillTileVB(), computeTileMaterial(), copyTileUv(), CTessFace(), deleteTileFaces(), deleteTileUv(), emptyTileFaces(), heritTileUv(), NL3D::CPatch::removeFaceFromTileRenderList(), and updateNearFarVertices().

uint8 NL3D::CTessFace::TileId
 

Definition at line 257 of file tessellation.h.

Referenced by computeTileMaterial(), heritTileMaterial(), initTileUvRGBA(), and sameTile().

CTileMaterial* NL3D::CTessFace::TileMaterial
 

Definition at line 259 of file tessellation.h.

Referenced by NL3D::CPatch::appendFaceToTileRenderList(), computeTileMaterial(), deleteTileUvs(), heritTileMaterial(), releaseTileMaterial(), and NL3D::CPatch::removeFaceFromTileRenderList().

CTessVertex* NL3D::CTessFace::VBase
 

Definition at line 241 of file tessellation.h.

Referenced by NL3D::CZoneLighter::addTriangles(), NL3D::CInstanceLighter::addTriangles(), allocTileUv(), NL3D::CPatch::appendFaceToRenderList(), NL3D::CLandscape::appendToShadowPolyReceiver(), averageTesselationVertices(), NL3D::CPatch::bind(), NL3D::CZoneLighter::buildZoneInformation(), computeSplitPoint(), computeTesselatedPos(), computeTileErrorMetric(), CTessFace(), doMerge(), NL3D::CPatch::extendTessBlockWithEndPos(), NL3D::CPatch::getRootVertexForEdge(), hasVertex(), NL3D::CPatch::makeRoots(), refreshTesselationGeometry(), split(), splitRectangular(), unbind(), updateBindAndSplit(), updateNearFarVertices(), updateRefineMerge(), and updateRefineSplit().

CTessVertex * NL3D::CTessFace::VLeft
 

Definition at line 241 of file tessellation.h.

Referenced by NL3D::CZoneLighter::addTriangles(), NL3D::CInstanceLighter::addTriangles(), allocTileUv(), NL3D::CPatch::appendFaceToRenderList(), NL3D::CLandscape::appendToShadowPolyReceiver(), NL3D::CZoneLighter::buildZoneInformation(), computeSplitPoint(), computeTesselatedPos(), computeTileErrorMetric(), CTessFace(), NL3D::CPatch::extendTessBlockWithEndPos(), NL3D::CPatch::getRootVertexForEdge(), hasVertex(), NL3D::CPatch::makeRoots(), split(), splitRectangular(), unbind(), updateNearFarVertices(), updateRefineMerge(), and updateRefineSplit().

CTessVertex * NL3D::CTessFace::VRight
 

Definition at line 241 of file tessellation.h.

Referenced by NL3D::CZoneLighter::addTriangles(), NL3D::CInstanceLighter::addTriangles(), allocTileUv(), NL3D::CPatch::appendFaceToRenderList(), NL3D::CLandscape::appendToShadowPolyReceiver(), NL3D::CZoneLighter::buildZoneInformation(), computeSplitPoint(), computeTesselatedPos(), computeTileErrorMetric(), CTessFace(), NL3D::CPatch::extendTessBlockWithEndPos(), NL3D::CPatch::getRootVertexForEdge(), hasVertex(), NL3D::CPatch::makeRoots(), split(), splitRectangular(), unbind(), updateBindAndSplit(), updateNearFarVertices(), updateRefineMerge(), and updateRefineSplit().


The documentation for this class was generated from the following files:
Generated on Tue Mar 16 07:48:38 2004 for NeL by doxygen 1.3.6