# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

patch.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2000 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
00024  */
00025 
00026 #include "std3d.h"
00027 
00028 
00029 #include "3d/patch.h"
00030 #include "3d/tessellation.h"
00031 #include "3d/bezier_patch.h"
00032 #include "3d/zone.h"
00033 #include "3d/landscape.h"
00034 #include "nel/misc/vector.h"
00035 #include "nel/misc/common.h"
00036 #include "3d/patchuv_locator.h"
00037 #include "3d/vegetable_manager.h"
00038 #include "3d/fast_floor.h"
00039 #include "3d/light_influence_interpolator.h"
00040 #include "3d/patchdlm_context.h"
00041 
00042 using   namespace       std;
00043 using   namespace       NLMISC;
00044 
00045 
00046 namespace NL3D 
00047 {
00048 
00049 
00050 // ***************************************************************************
00051 CBezierPatch    CPatch::CachePatch;
00052 const CPatch    *CPatch::LastPatch= NULL;
00053 uint32                  CPatch::_Version=7;
00054 
00055 
00056 // ***************************************************************************
00057 CPatch::CPatch()
00058 {
00059         Zone= NULL;
00060         OrderS=0;
00061         OrderT=0;
00062         Son0=NULL;
00063         Son1=NULL;
00064         TessBlockRefCount=0;
00065         Clipped=false;
00066         RenderClipped= true;
00067         OldRenderClipped= true;
00068         NumRenderableFaces= 0;
00069 
00070         // for Pacs process. By default, false.
00071         ExcludeFromRefineAll= false;
00072 
00073         // Init Passes.
00074         // DO NOT FILL Patch here, because of operator= problem. do it in compile().
00075         // By default, RdrPasses are NULL.
00076 
00077         // To force computation of texture info on next preRender().
00078         Far0= -1;
00079         Far1= -1;
00080 
00081         // Default: not binded.
00082         _BindZoneNeighbor[0]= NULL;
00083         _BindZoneNeighbor[1]= NULL;
00084         _BindZoneNeighbor[2]= NULL;
00085         _BindZoneNeighbor[3]= NULL;
00086         NoiseRotation= 0;
00087         // No smooth by default.
00088         _CornerSmoothFlag= 0;
00089 
00090         // MasterBlock never clipped.
00091         MasterBlock.resetClip();
00092 
00093         // Init UL circular list to NULL (not compiled)
00094         _ULNearPrec= NULL;
00095         _ULNearNext= NULL;
00096 
00097         // Dynamic LightMap
00098         _DLMContext= NULL;
00099         _DLMContextRefCount= 0;
00100 }
00101 // ***************************************************************************
00102 CPatch::~CPatch()
00103 {
00104         release();
00105 }
00106 
00107 // ***************************************************************************
00108 void                    CPatch::release()
00109 {
00110         if(Zone)
00111         {
00112                 // First, delete the VB if the zone was removed while the patch is visible.
00113                 if(!RenderClipped)
00114                 {
00115                         // release VertexBuffer.
00116                         deleteVBAndFaceVector();
00117 
00118                         // Flag.
00119                         RenderClipped= true;
00120                 }
00121 
00122                 // THIS PATCH MSUT BE UNBOUND FIRST!!!!!
00123                 nlassert(Son0 && Son1);
00124                 nlassert(Son0->isLeaf() && Son1->isLeaf());
00125                 nlassert(Son0->FLeft == NULL);
00126                 nlassert(Son0->FRight == NULL);
00127                 nlassert(Son1->FLeft == NULL);
00128                 nlassert(Son1->FRight == NULL);
00129 
00130                 // Free renderPass of landscape, and maybe force computation of texture info on next preRender().
00131                 // Must do it here, before deletion of Zone, OrderS/T etc...
00132                 resetRenderFar();
00133 
00134                 getLandscape()->deleteTessFace(Son0);
00135                 getLandscape()->deleteTessFace(Son1);
00136                 // Vertices are smartptr/deleted in zone.
00137         }
00138 
00139         // Flag the fact that this patch can't be rendered.
00140         Pass0.Patch= NULL;
00141         Pass1.Patch= NULL;
00142         OrderS=0;
00143         OrderT=0;
00144         Son0=NULL;
00145         Son1=NULL;
00146         clearTessBlocks();
00147         resetMasterBlock();
00148         Clipped=false;
00149         RenderClipped= true;
00150         OldRenderClipped= true;
00151 
00152         // the pathc is uncompiled. must do it after clearTessBlocks(), because may use it 
00153         // for vegetable manager, and for updateLighting
00154         Zone= NULL;
00155 
00156         // uncompile: reset UpdateLighting circular list to NULL.
00157         if(_ULNearPrec!= NULL)
00158         {
00159                 // verify the patch is correctly unlinked from any ciruclar list.
00160                 nlassert(_ULNearPrec==this && _ULNearNext==this);
00161         }
00162         _ULNearPrec= NULL;
00163         _ULNearNext= NULL;
00164 
00165         // DynamciLightMap: release the _DLMContext if still exist.
00166         if(_DLMContext)
00167                 delete _DLMContext;
00168         // reset
00169         _DLMContext= NULL;
00170         _DLMContextRefCount= 0;
00171 }
00172 
00173 
00174 // ***************************************************************************
00175 CBezierPatch    *CPatch::unpackIntoCache() const
00176 {
00177         if(LastPatch!=this)
00178         {
00179                 unpack(CachePatch);
00180                 LastPatch=this;
00181         }
00182         return &CachePatch;
00183 }
00184 // ***************************************************************************
00185 void                    CPatch::unpack(CBezierPatch     &p) const
00186 {
00187         sint    i;
00188         const   CVector &bias= Zone->getPatchBias();
00189         float   scale= Zone->getPatchScale();
00190 
00191         for(i=0;i<4;i++)
00192                 Vertices[i].unpack(p.Vertices[i], bias, scale);
00193         for(i=0;i<8;i++)
00194                 Tangents[i].unpack(p.Tangents[i], bias, scale);
00195         for(i=0;i<4;i++)
00196                 Interiors[i].unpack(p.Interiors[i], bias, scale);
00197 }
00198 // ***************************************************************************
00199 void                    CPatch::computeDefaultErrorSize()
00200 {
00201         CBezierPatch    &p= *unpackIntoCache();
00202         CVector                 &v0= p.Vertices[0];
00203         CVector                 &v1= p.Vertices[1];
00204         CVector                 &v2= p.Vertices[2];
00205 
00206         // \todo yoyo: TODO_NOISE: modulate this value with tangents (roundiness of patch), and with the displacement map.
00207         ErrorSize= ((v1 - v0)^(v2 - v0)).norm();
00208 
00209 }
00210 
00211 
00212 
00213 // ***************************************************************************
00214 void                    CPatch::buildBBoxFromBezierPatch(const CBezierPatch &p, CAABBox &ret) const
00215 {
00216         // Because of the structure of CAABBox, extend() is not fast enough for us. first compute bmin, bmax,
00217         // then compute the bbox.
00218         CVector         bmin= p.Vertices[0];
00219         CVector         bmax= bmin; 
00220 
00221         sint                    i;
00222         for(i=0;i<4;i++)
00223         {
00224                 bmin.minof(bmin, p.Vertices[i]);
00225                 bmax.maxof(bmax, p.Vertices[i]);
00226         }
00227         for(i=0;i<8;i++)
00228         {
00229                 bmin.minof(bmin, p.Tangents[i]);
00230                 bmax.maxof(bmax, p.Tangents[i]);
00231         }
00232         for(i=0;i<4;i++)
00233         {
00234                 bmin.minof(bmin, p.Interiors[i]);
00235                 bmax.maxof(bmax, p.Interiors[i]);
00236         }
00237 
00238         // Modulate with the maximum displacement map (usefull for patch clipping).
00239         static  CVector         vectorNoiseMax(NL3D_NOISE_MAX, NL3D_NOISE_MAX, NL3D_NOISE_MAX);
00240         bmin-= vectorNoiseMax;
00241         bmax+= vectorNoiseMax;
00242         // NB: this is not very optimal, since the BBox may be very too big. eg: patch 16mx16m => bbox 18mx18m.
00243         // But remind that tessblocks do not use this BBox, and are computed with the real geometry.
00244 
00245         ret.setMinMax(bmin, bmax);
00246 }
00247 
00248 
00249 // ***************************************************************************
00250 CAABBox                 CPatch::buildBBox() const
00251 {
00252         CBezierPatch    &p= *unpackIntoCache();
00253 
00254         // Compute Bounding Box. (easiest way...)
00255         CAABBox         ret;
00256         buildBBoxFromBezierPatch(p, ret);
00257 
00258         return ret;
00259 }
00260 
00261 
00262 // ***************************************************************************
00263 void            CPatch::addTrianglesInBBox(CPatchIdent paId, const CAABBox &bbox, std::vector<CTrianglePatch> &triangles, uint8 tileTessLevel) const
00264 {
00265         CBezierPatch    &bpatch= *unpackIntoCache();
00266 
00267         // call with the whole root patch.
00268         addTrianglesInBBoxRecurs(paId, bbox, triangles, tileTessLevel, bpatch, 0, OrderS, 0, OrderT);
00269 }
00270 
00271 
00272 // ***************************************************************************
00273 void            CPatch::addTrianglesInBBoxRecurs(CPatchIdent paId, const CAABBox &bbox, std::vector<CTrianglePatch> &triangles, uint8 tessLevel, 
00274                 const CBezierPatch &pa, uint8 s0, uint8 s1, uint8 t0, uint8 t1) const
00275 {
00276         uint8   lenS=s1-s0, lenT=t1-t0;
00277         nlassert(lenS>0);
00278         nlassert(lenT>0);
00279 
00280         // compute and compare bbox of the subdivision patch against request bbox.
00281         //========================
00282         // NB: this compute includes possible noise.
00283         CAABBox         paBBox;
00284         buildBBoxFromBezierPatch(pa, paBBox);
00285         // if do not intersect, stop here.
00286         if( !paBBox.intersect(bbox) )
00287                 return;
00288         // else if at tile level, then just computeTriangles.
00289         //========================
00290         else if( lenS==1 && lenT==1 )
00291         {
00292                 addTileTrianglesInBBox(paId, bbox, triangles, tessLevel, s0, t0);
00293         }
00294         // else subdiv and reccurs.
00295         //========================
00296         else
00297         {
00298                 // Subdivide along the bigger side.
00299                 if(lenS>lenT)
00300                 {
00301                         // subdivide.
00302                         CBezierPatch    left, right;
00303                         pa.subdivideS(left, right);
00304                         uint8   sMiddle= (uint8)( ((uint)s0+(uint)s1) /2 );
00305                         // recurs left.
00306                         addTrianglesInBBoxRecurs(paId, bbox, triangles, tessLevel, left, s0, sMiddle, t0, t1);
00307                         // recurs right.
00308                         addTrianglesInBBoxRecurs(paId, bbox, triangles, tessLevel, right, sMiddle, s1, t0, t1);
00309                 }
00310                 else
00311                 {
00312                         // subdivide.
00313                         CBezierPatch    top, bottom;
00314                         pa.subdivideT(top, bottom);
00315                         uint8   tMiddle= (uint8)( ((uint)t0+(uint)t1) /2 );
00316                         // recurs top.
00317                         addTrianglesInBBoxRecurs(paId, bbox, triangles, tessLevel, top, s0, s1, t0, tMiddle);
00318                         // recurs bottom.
00319                         addTrianglesInBBoxRecurs(paId, bbox, triangles, tessLevel, bottom, s0, s1, tMiddle, t1);
00320                 }
00321         }
00322 
00323 
00324 }
00325 
00326 
00327 // ***************************************************************************
00328 void            CPatch::addTileTrianglesInBBox(CPatchIdent paId, const CAABBox &bbox, std::vector<CTrianglePatch> &triangles, uint8 tessLevel, uint8 s0, uint8 t0) const
00329 {
00330         nlassert(s0<OrderS);
00331         nlassert(t0<OrderT);
00332         nlassert(tessLevel<=2);
00333         uint    tessLen= 1<<tessLevel;
00334 
00335         // some preca.
00336         float   startS0= (float)s0 / (float)(OrderS);
00337         float   startT0= (float)t0 / (float)(OrderT);
00338         float   ds= 1.0f/(float)(OrderS*tessLen);
00339         float   dt= 1.0f/(float)(OrderT*tessLen);
00340 
00341         // Parse all quads.
00342         uint    sl,tl;
00343         for(tl=0; tl<tessLen; tl++)
00344         {
00345                 float   fs0, fs1, ft0, ft1;
00346                 // compute t patch coordinates.
00347                 ft0= startT0 + (float)tl * dt ;
00348                 ft1= ft0 + dt;
00349                 for(sl=0; sl<tessLen; sl++)
00350                 {
00351                         // compute s patch coordinates.
00352                         fs0= startS0 + (float)sl * ds ;
00353                         fs1= fs0 + ds;
00354 
00355                         // Compute Quad vectors (in CCW).
00356                         CVector         p0, p1, p2, p3;
00357                         CUV                     uv0, uv1, uv2, uv3;
00358                         uv0.U= fs0; uv0.V= ft0;
00359                         uv1.U= fs0; uv1.V= ft1;
00360                         uv2.U= fs1; uv2.V= ft1;
00361                         uv3.U= fs1; uv3.V= ft0;
00362                         // evaluate patch (with noise). (NB: because of cache, patch decompression cost nothing).
00363                         p0= computeVertex(uv0.U, uv0.V);
00364                         p1= computeVertex(uv1.U, uv1.V);
00365                         p2= computeVertex(uv2.U, uv2.V);
00366                         p3= computeVertex(uv3.U, uv3.V);
00367 
00368                         // build the bbox of this quad, and test with request bbox.
00369                         CAABBox         quadBBox;
00370                         quadBBox.setCenter(p0);
00371                         quadBBox.extend(p1);
00372                         quadBBox.extend(p2);
00373                         quadBBox.extend(p3);
00374 
00375                         // insert only if intersect with the bbox.
00376                         if(quadBBox.intersect(bbox))
00377                         {
00378                                 // build triangles (in CCW).
00379                                 CTrianglePatch  tri;
00380                                 tri.PatchId= paId;
00381 
00382                                 // first tri.
00383                                 tri.V0= p0; tri.V1= p1; tri.V2= p2;
00384                                 tri.Uv0= uv0; tri.Uv1= uv1; tri.Uv2= uv2;
00385                                 triangles.push_back(tri);
00386 
00387                                 // second tri.
00388                                 tri.V0= p2; tri.V1= p3; tri.V2= p0;
00389                                 tri.Uv0= uv2; tri.Uv1= uv3; tri.Uv2= uv0;
00390                                 triangles.push_back(tri);
00391 
00392                                 // NB: this is not the same tesselation than in tesselation.cpp.
00393                                 // But this looks like Ben's NLPACS::CLocalRetriever tesselation.
00394                         }
00395                 }
00396         }
00397 
00398 }
00399 
00400 
00401 
00402 // ***************************************************************************
00403 void            CPatchQuadBlock::buildTileTriangles(uint8 quadId, CTrianglePatch  triangles[2]) const
00404 {
00405         // copute coordinate of the tile we want.
00406         uint    sd0= quadId&(NL_PATCH_BLOCK_MAX_QUAD-1);
00407         uint    td0= quadId/(NL_PATCH_BLOCK_MAX_QUAD);
00408         uint    sd1= sd0+1;
00409         uint    td1= td0+1;
00410         uint    s= PatchBlockId.S0+sd0;
00411         uint    t= PatchBlockId.T0+td0;
00412         nlassert(s<PatchBlockId.S1);
00413         nlassert(t<PatchBlockId.T1);
00414 
00415         // Compute UV coord.
00416         float   fs0= (float)s / (float)(PatchBlockId.OrderS);
00417         float   ft0= (float)t / (float)(PatchBlockId.OrderT);
00418         float   fs1= (float)(s+1) / (float)(PatchBlockId.OrderS);
00419         float   ft1= (float)(t+1) / (float)(PatchBlockId.OrderT);
00420         CUV                     uv0, uv1, uv2, uv3;
00421         uv0.U= fs0; uv0.V= ft0;
00422         uv1.U= fs0; uv1.V= ft1;
00423         uv2.U= fs1; uv2.V= ft1;
00424         uv3.U= fs1; uv3.V= ft0;
00425 
00426         // get vertex coord.
00427         const CVector   &p0= Vertices[sd0 + td0*NL_PATCH_BLOCK_MAX_VERTEX];
00428         const CVector   &p1= Vertices[sd0 + td1*NL_PATCH_BLOCK_MAX_VERTEX];
00429         const CVector   &p2= Vertices[sd1 + td1*NL_PATCH_BLOCK_MAX_VERTEX];
00430         const CVector   &p3= Vertices[sd1 + td0*NL_PATCH_BLOCK_MAX_VERTEX];
00431 
00432         // build triangles.
00433         // first tri.
00434         {
00435                 CTrianglePatch &tri= triangles[0];
00436                 tri.PatchId= PatchBlockId.PatchId;
00437                 tri.V0= p0; tri.V1= p1; tri.V2= p2;
00438                 tri.Uv0= uv0; tri.Uv1= uv1; tri.Uv2= uv2;
00439         }
00440 
00441         // second tri.
00442         {
00443                 CTrianglePatch &tri= triangles[1];
00444                 tri.PatchId= PatchBlockId.PatchId;
00445                 tri.V0= p2; tri.V1= p3; tri.V2= p0;
00446                 tri.Uv0= uv2; tri.Uv1= uv3; tri.Uv2= uv0;
00447         }
00448 
00449 }
00450 
00451 
00452 // ***************************************************************************
00453 void            CPatch::fillPatchQuadBlock(CPatchQuadBlock &quadBlock)  const
00454 {
00455         CPatchBlockIdent        &pbId= quadBlock.PatchBlockId;
00456         uint    lenS= pbId.S1-pbId.S0;
00457         uint    lenT= pbId.T1-pbId.T0;
00458         nlassert( pbId.OrderS==OrderS );
00459         nlassert( pbId.OrderT==OrderT );
00460         nlassert( pbId.S1<=OrderS );
00461         nlassert( pbId.T1<=OrderT );
00462         nlassert( pbId.S0<pbId.S1 );
00463         nlassert( pbId.T0<pbId.T1 );
00464         nlassert( lenS<=NL_PATCH_BLOCK_MAX_QUAD );
00465         nlassert( lenT<=NL_PATCH_BLOCK_MAX_QUAD );
00466 
00467         // Fill vertices.
00468         uint    s0= pbId.S0;
00469         uint    t0= pbId.T0;
00470         // some preca.
00471         float   startS0= (float)s0 / (float)(OrderS);
00472         float   startT0= (float)t0 / (float)(OrderT);
00473         float   ds= 1.0f/(float)(OrderS);
00474         float   dt= 1.0f/(float)(OrderT);
00475 
00476         // Parse all quads vertices corner.
00477         uint    sl,tl;
00478         for(tl=0; tl<lenT+1; tl++)
00479         {
00480                 float   fs, ft;
00481                 // compute t patch coordinates.
00482                 ft= startT0 + (float)tl * dt ;
00483                 for(sl=0; sl<lenS+1; sl++)
00484                 {
00485                         // compute s patch coordinates.
00486                         fs= startS0 + (float)sl * ds ;
00487 
00488                         // Must use computeContinousVertex, to ensure continous coordinate on patch edges
00489                         quadBlock.Vertices[sl + tl*NL_PATCH_BLOCK_MAX_VERTEX]= computeContinousVertex(fs, ft);
00490                 }
00491         }
00492 
00493 }
00494 
00495 
00496 // ***************************************************************************
00497 void            CPatch::addPatchBlocksInBBox(CPatchIdent paId, const CAABBox &bbox, std::vector<CPatchBlockIdent> &paBlockIds) const
00498 {
00499         CBezierPatch    &bpatch= *unpackIntoCache();
00500 
00501         // call with the whole root patch.
00502         addPatchBlocksInBBoxRecurs(paId, bbox, paBlockIds, bpatch, 0, OrderS, 0, OrderT);
00503 }
00504 
00505 
00506 // ***************************************************************************
00507 void            CPatch::addPatchBlocksInBBoxRecurs(CPatchIdent paId, const CAABBox &bbox, std::vector<CPatchBlockIdent> &paBlockIds, 
00508                 const CBezierPatch &pa, uint8 s0, uint8 s1, uint8 t0, uint8 t1) const
00509 {
00510         uint8   lenS=s1-s0, lenT=t1-t0;
00511         nlassert(lenS>0);
00512         nlassert(lenT>0);
00513 
00514         // compute and compare bbox of the subdivision patch against request bbox.
00515         //========================
00516         // NB: this compute includes possible noise.
00517         CAABBox         paBBox;
00518         buildBBoxFromBezierPatch(pa, paBBox);
00519         // if do not intersect, stop here.
00520         if( !paBBox.intersect(bbox) )
00521                 return;
00522         // else if at CPatchQuadBlock tile level, then just add this Id.
00523         //========================
00524         else if( lenS<=NL_PATCH_BLOCK_MAX_QUAD && lenT<=NL_PATCH_BLOCK_MAX_QUAD )
00525         {
00526                 // Add this PatchBlock desctiptor to the list.
00527                 CPatchBlockIdent        pbId;
00528                 // Fill struct from this and result of recursion.
00529                 pbId.PatchId= paId;
00530                 pbId.OrderS= OrderS;
00531                 pbId.OrderT= OrderT;
00532                 pbId.S0= s0;
00533                 pbId.S1= s1;
00534                 pbId.T0= t0;
00535                 pbId.T1= t1;
00536                 // Add to list.
00537                 paBlockIds.push_back(pbId);
00538         }
00539         // else subdiv and reccurs.
00540         //========================
00541         else
00542         {
00543                 // Subdivide along the bigger side.
00544                 if(lenS>lenT)
00545                 {
00546                         // subdivide.
00547                         CBezierPatch    left, right;
00548                         pa.subdivideS(left, right);
00549                         uint8   sMiddle= (uint8)( ((uint)s0+(uint)s1) /2 );
00550                         // recurs left.
00551                         addPatchBlocksInBBoxRecurs(paId, bbox, paBlockIds, left, s0, sMiddle, t0, t1);
00552                         // recurs right.
00553                         addPatchBlocksInBBoxRecurs(paId, bbox, paBlockIds, right, sMiddle, s1, t0, t1);
00554                 }
00555                 else
00556                 {
00557                         // subdivide.
00558                         CBezierPatch    top, bottom;
00559                         pa.subdivideT(top, bottom);
00560                         uint8   tMiddle= (uint8)( ((uint)t0+(uint)t1) /2 );
00561                         // recurs top.
00562                         addPatchBlocksInBBoxRecurs(paId, bbox, paBlockIds, top, s0, s1, t0, tMiddle);
00563                         // recurs bottom.
00564                         addPatchBlocksInBBoxRecurs(paId, bbox, paBlockIds, bottom, s0, s1, tMiddle, t1);
00565                 }
00566         }
00567 
00568 }
00569 
00570 
00571 // ***************************************************************************
00572 CVector         CPatch::getTesselatedPos(CUV uv) const
00573 {
00574         // clamp values.
00575         clamp(uv.U, 0, 1);
00576         clamp(uv.V, 0, 1);
00577         // recurs down the 2 sons.
00578         CVector         ret= CVector::Null;
00579         Son0->getTesselatedPos(uv, true, ret);
00580         Son1->getTesselatedPos(uv, true, ret);
00581 
00582         return ret;
00583 }
00584 
00585 
00586 // ***************************************************************************
00587 // ***************************************************************************
00588 // RENDER LIST.
00589 // ***************************************************************************
00590 // ***************************************************************************
00591 
00592 
00593 // ***************************************************************************
00594 void                    CPatch::addRefTessBlocks()
00595 {
00596         uint    i;
00597 
00598         TessBlockRefCount++;
00599         if(TessBlocks.size()==0)
00600         {
00601                 // Allocate the tessblocks.
00602                 //==========
00603 
00604                 nlassert(NL3D_TESSBLOCK_TILESIZE==4);
00605                 // A tessblock is 2*2 tiles.
00606                 sint os= OrderS>>1;
00607                 sint ot= OrderT>>1;
00608                 nlassert(os>0);
00609                 nlassert(ot>0);
00610                 TessBlocks.resize(os*ot);
00611                 // init all tessBlocks with the Patch ptr.
00612                 for(i=0; i<TessBlocks.size(); i++)
00613                         TessBlocks[i].init(this);
00614 
00615 
00616 
00617                 // Vegetable management
00618                 //==========
00619                 CVegetableManager       *vegetableManager= getLandscape()->_VegetableManager;
00620 
00621                 // Create ClipBlocks.
00622                 uint    nTbPerCb= NL3D_PATCH_VEGETABLE_NUM_TESSBLOCK_PER_CLIPBLOCK;
00623                 uint    wCB= (os + nTbPerCb-1) >> NL3D_PATCH_VEGETABLE_NUM_TESSBLOCK_PER_CLIPBLOCK_SHIFT;
00624                 uint    hCB= (ot + nTbPerCb-1) >> NL3D_PATCH_VEGETABLE_NUM_TESSBLOCK_PER_CLIPBLOCK_SHIFT;
00625                 VegetableClipBlocks.resize(wCB * hCB);
00626                 // allocate ClipBlocks
00627                 for(i=0; i<VegetableClipBlocks.size(); i++)
00628                 {
00629                         VegetableClipBlocks[i]= vegetableManager->createClipBlock();
00630                 }
00631 
00632 
00633                 // updateLighting management.
00634                 //==========
00635                 // append patch for Near updateLighting, since TessBlock lightmap may/will exist.
00636                 getLandscape()->linkPatchToNearUL(this);
00637         }
00638 }
00639 
00640 // ***************************************************************************
00641 void                    CPatch::decRefTessBlocks()
00642 {
00643         TessBlockRefCount--;
00644         // If no loinger need the tessblocks, delete them.
00645         if(TessBlockRefCount==0)
00646                 clearTessBlocks();
00647         nlassert(TessBlockRefCount>=0);
00648 }
00649 
00650 
00651 // ***************************************************************************
00652 void                    CPatch::clearTessBlocks()
00653 {
00654         uint    i;
00655 
00656         // Vegetable management
00657         //==========
00658         // if compiled.
00659         if(Zone)
00660         {
00661                 CVegetableManager       *vegetableManager= getLandscape()->_VegetableManager;
00662 
00663                 // delete still existing vegetable Igs.
00664                 deleteAllVegetableIgs();
00665 
00666                 // delete ClipBlocks.
00667                 for(i=0; i<VegetableClipBlocks.size(); i++)
00668                 {
00669                         vegetableManager->deleteClipBlock(VegetableClipBlocks[i]);
00670                 }
00671                 contReset(VegetableClipBlocks);
00672         }
00673 
00674 
00675         // updateLighting management.
00676         //==========
00677         if(Zone)
00678         {
00679                 // remove patch from Near updateLighting, since no more TessBlock lightmap can exist.
00680                 getLandscape()->unlinkPatchFromNearUL(this);
00681         }
00682 
00683 
00684         // Delete TessBlocks
00685         //==========
00686         TessBlockRefCount=0;
00687         contReset(TessBlocks);
00688 }
00689 
00690 
00691 // ***************************************************************************
00692 void                    CPatch::resetMasterBlock()
00693 {
00694         // We should be not visible so FaceVector no more exist.
00695         nlassert(RenderClipped);
00696 
00697         MasterBlock.FarVertexList.clear();
00698         MasterBlock.FarFaceList.clear();
00699         NumRenderableFaces= 0;
00700         // no tiles should be here!!
00701         nlassert(MasterBlock.NearVertexList.size()==0);
00702 }
00703 
00704 // ***************************************************************************
00705 uint                    CPatch::getNumTessBlock(CTessFace *face)
00706 {
00707         // To which tessBlocks link the face?
00708         // compute an approx middle of the face.
00709         CParamCoord     edgeMid(face->PVLeft, face->PVRight);
00710         CParamCoord     middle(edgeMid, face->PVBase);
00711         // Coordinate of the tessblock (2*2 a tile!! so the >>1).
00712         uint ts= ((uint)middle.S * (uint)(OrderS>>1)) / 0x8000;
00713         uint tt= ((uint)middle.T * (uint)(OrderT>>1)) / 0x8000;
00714         uint numtb= tt*(uint)(OrderS>>1) + ts;
00715 
00716         return numtb;
00717 }
00718 
00719 
00720 // ***************************************************************************
00721 void                    CPatch::getNumTessBlock(CParamCoord pc, TFarVertType &type, uint &numtb)
00722 {
00723         uint    tboS= (uint)(OrderS>>1);
00724         uint    tboT= (uint)(OrderT>>1);
00725 
00726         // Coordinate of the tessblock (2*2 a tile!! so the >>1).
00727         uint ts= ((uint)pc.S * tboS) / 0x8000;
00728         uint tt= ((uint)pc.T * tboT) / 0x8000;
00729         numtb= tt*tboS + ts;
00730 
00731         bool    edgeS= (ts*0x8000) == ((uint)pc.S * tboS);
00732         bool    edgeT= (tt*0x8000) == ((uint)pc.T * tboT);
00733 
00734         // Does this vertex lies on a corner of a TessBlock?
00735         if(edgeS && edgeT)
00736                 type= FVMasterBlock;
00737         // Does this vertex lies on a edge of a TessBlock?
00738         else if(edgeS || edgeT)
00739                 type= FVTessBlockEdge;
00740         // Else it lies exclusively IN a TessBlock.
00741         else
00742                 type= FVTessBlock;
00743 
00744 }
00745 
00746 
00747 
00748 // ***************************************************************************
00749 void                    CPatch::extendTessBlockWithEndPos(CTessFace *face)
00750 {
00751         if(face->Level>=TessBlockLimitLevel)
00752         {
00753                 // get the tessBlock of the face.
00754                 uint    numtb= getNumTessBlock(face);
00755 
00756                 // Must enlarge the BSphere of the tesblock!!
00757                 TessBlocks[numtb].extendSphereFirst(face->VBase->EndPos);
00758                 TessBlocks[numtb].extendSphereAdd(face->VLeft->EndPos);
00759                 TessBlocks[numtb].extendSphereAdd(face->VRight->EndPos);
00760                 TessBlocks[numtb].extendSphereCompile();
00761         }
00762 }
00763 
00764 
00765 // ***************************************************************************
00766 void                    CPatch::dirtTessBlockFaceVector(CTessBlock &tb)
00767 {
00768         // If patch is visible, block's faceVector should exist, but are no more valid.
00769         if(!RenderClipped)
00770         {
00771                 // If this tessBlock not already notified to modification.
00772                 if(!tb.isInModifyList())
00773                 {
00774                         // Then append, and delete all FaceVector.
00775                         // NB: delete FaceVector now, because the TessBlock himself may disapear soon.
00776                         tb.appendToModifyListAndDeleteFaceVector(getLandscape()->_TessBlockModificationRoot, getLandscape()->_FaceVectorManager);
00777                 }
00778         }
00779 }
00780 
00781 
00782 // ***************************************************************************
00783 void                    CPatch::appendFaceToRenderList(CTessFace *face)
00784 {
00785         // Update the number of renderable Faces
00786         NumRenderableFaces++;
00787 
00788         // Update Gnal render.
00789         //====================
00790         if(face->Level<TessBlockLimitLevel)
00791         {
00792                 MasterBlock.FarFaceList.append(face);
00793                 MasterBlock.FaceTileMaterialRefCount++;
00794 
00795                 // The facelist is modified, so we must update the faceVector, if visible.
00796                 dirtTessBlockFaceVector(MasterBlock);
00797         }
00798         else
00799         {
00800                 // Alloc if necessary the TessBlocks.
00801                 addRefTessBlocks();
00802 
00803                 // link the face to the good tessblock.
00804                 uint    numtb= getNumTessBlock(face);
00805                 TessBlocks[numtb].FarFaceList.append(face);
00806                 TessBlocks[numtb].FaceTileMaterialRefCount++;
00807 
00808                 // The facelist is modified, so we must update the faceVector, if visible.
00809                 dirtTessBlockFaceVector(TessBlocks[numtb]);
00810 
00811                 // Must enlarge the BSphere of the tesblock!!
00812                 // We must do it on a per-face approach, because of tessblocks 's corners which are outside of tessblocks.
00813                 TessBlocks[numtb].extendSphereFirst(face->VBase->EndPos);
00814                 TessBlocks[numtb].extendSphereAdd(face->VLeft->EndPos);
00815                 TessBlocks[numtb].extendSphereAdd(face->VRight->EndPos);
00816                 // I think this should be done too on StartPos, for geomorph (rare??...) problems.
00817                 // \todo yoyo: is this necessary???
00818                 TessBlocks[numtb].extendSphereAdd(face->VBase->StartPos);
00819                 TessBlocks[numtb].extendSphereAdd(face->VLeft->StartPos);
00820                 TessBlocks[numtb].extendSphereAdd(face->VRight->StartPos);
00821                 TessBlocks[numtb].extendSphereCompile();
00822 
00823 
00824                 // Update Tile render (no need to do it if face not at least at tessblock level).
00825                 appendFaceToTileRenderList(face);
00826         }
00827 }
00828 
00829 
00830 // ***************************************************************************
00831 void                    CPatch::removeFaceFromRenderList(CTessFace *face)
00832 {
00833         // Update the number of renderable Faces
00834         NumRenderableFaces--;
00835         nlassert(NumRenderableFaces>=0);
00836 
00837         // Update Gnal render.
00838         //====================
00839         if(face->Level<TessBlockLimitLevel)
00840         {
00841                 MasterBlock.FarFaceList.remove(face);
00842                 MasterBlock.FaceTileMaterialRefCount--;
00843 
00844                 // The facelist is modified, so we must update the faceVector, if visible.
00845                 dirtTessBlockFaceVector(MasterBlock);
00846         }
00847         else
00848         {
00849                 // link the face to the good tessblock.
00850                 uint    numtb= getNumTessBlock(face);
00851                 TessBlocks[numtb].FarFaceList.remove(face);
00852                 TessBlocks[numtb].FaceTileMaterialRefCount--;
00853 
00854                 // The facelist is modified, so we must update the faceVector, if visible.
00855                 dirtTessBlockFaceVector(TessBlocks[numtb]);
00856 
00857                 // Update Tile render (no need to do it if face not at least at tessblock level).
00858                 removeFaceFromTileRenderList(face);
00859 
00860                 // Destroy if necessary the TessBlocks.
00861                 decRefTessBlocks();
00862         }
00863 }
00864 
00865 
00866 // ***************************************************************************
00867 void                    CPatch::appendFaceToTileRenderList(CTessFace *face)
00868 {
00869         if(face->TileMaterial)
00870         {
00871                 // For all valid faces, update their links.
00872                 // Do not do this for lightmap, since it use same face from RGB0 pass.
00873                 for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
00874                 {
00875                         CPatchRdrPass   *tilePass= face->TileMaterial->Pass[i].PatchRdrPass;
00876                         // If tile i enabled.
00877                         if(tilePass)
00878                         {
00879                                 // a face should have created for this pass.
00880                                 nlassert(face->TileFaces[i]);
00881                                 face->TileMaterial->TileFaceList[i].append(face->TileFaces[i]);
00882                         }
00883                 }
00884 
00885                 // The facelist is modified, so we must update the faceVector, if visible.
00886                 uint    numtb= getNumTessBlock(face);
00887                 dirtTessBlockFaceVector(TessBlocks[numtb]);
00888         }
00889 }
00890 
00891 
00892 // ***************************************************************************
00893 void                    CPatch::removeFaceFromTileRenderList(CTessFace *face)
00894 {
00895         if(face->TileMaterial)
00896         {
00897                 // For all valid faces, update their links.
00898                 // Do not do this for lightmap, since it use same face from RGB0 pass.
00899                 for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
00900                 {
00901                         CPatchRdrPass   *tilePass= face->TileMaterial->Pass[i].PatchRdrPass;
00902                         // If tile i enabled.
00903                         if(tilePass)
00904                         {
00905                                 // a face should have created for this pass.
00906                                 nlassert(face->TileFaces[i]);
00907                                 face->TileMaterial->TileFaceList[i].remove(face->TileFaces[i]);
00908                         }
00909                 }
00910 
00911                 // The facelist is modified, so we must update the faceVector, if visible.
00912                 uint    numtb= getNumTessBlock(face);
00913                 dirtTessBlockFaceVector(TessBlocks[numtb]);
00914         }
00915 }
00916 
00917 
00918 // ***************************************************************************
00919 void                    CPatch::computeTbTm(uint &numtb, uint &numtm, uint ts, uint tt)
00920 {
00921         sint    is= ts&1;
00922         sint    it= tt&1;
00923         ts>>=1;
00924         tt>>=1;
00925         
00926         numtb= tt*(uint)(OrderS>>1) + ts;
00927         numtm= it*2+is;
00928 }
00929 
00930 
00931 // ***************************************************************************
00932 void                    CPatch::appendTileMaterialToRenderList(CTileMaterial *tm)
00933 {
00934         nlassert(tm);
00935 
00936         // Alloc if necessary the TessBlocks.
00937         addRefTessBlocks();
00938 
00939         uint    numtb, numtm;
00940         computeTbTm(numtb, numtm, tm->TileS, tm->TileT);
00941         TessBlocks[numtb].RdrTileRoot[numtm]= tm;
00942         TessBlocks[numtb].FaceTileMaterialRefCount++;
00943         TessBlocks[numtb].TileMaterialRefCount++;
00944         // The master block contains the whole patch TileMaterialRefCount
00945         MasterBlock.TileMaterialRefCount++;
00946 
00947         // DynamicLighting. When in near, must compute the context, to have good UVs.
00948         //==========
00949         // inc ref to the context, creating it if needed.
00950         addRefDLMContext();
00951         // NB: do it before creating the vegetableBlock, because vegetables use DLM Uvs.
00952 
00953         // if was no tiles before in this tessBlock, create a Vegetable block.
00954         //==========
00955         // one Tile <=> was 0 before
00956         if( TessBlocks[numtb].TileMaterialRefCount == 1 && getLandscape()->isVegetableActive() )
00957         {
00958                 createVegetableBlock(numtb, tm->TileS, tm->TileT);
00959         }
00960 
00961 }
00962 // ***************************************************************************
00963 void                    CPatch::removeTileMaterialFromRenderList(CTileMaterial *tm)
00964 {
00965         nlassert(tm);
00966 
00967         uint    numtb, numtm;
00968         computeTbTm(numtb, numtm, tm->TileS, tm->TileT);
00969         TessBlocks[numtb].RdrTileRoot[numtm]= NULL;
00970         TessBlocks[numtb].FaceTileMaterialRefCount--;
00971         TessBlocks[numtb].TileMaterialRefCount--;
00972         // The master block contains the whole patch TileMaterialRefCount
00973         MasterBlock.TileMaterialRefCount--;
00974 
00975         // if no more tiles in this tessBlock, delete the vegetable Block.
00976         //==========
00977         // if no more tiles in this tessBlock
00978         if( TessBlocks[numtb].TileMaterialRefCount==0 )
00979         {
00980                 // release the vegetableBlock (if any)
00981                 releaseVegetableBlock(numtb);
00982         }
00983 
00984         // Destroy if necessary the TessBlocks.
00985         decRefTessBlocks();
00986 
00987         // DynamicLighting. When in near, must compute the context, to have good UVs.
00988         //==========
00989         // dec ref the context, deleting it if needed.
00990         decRefDLMContext();
00991 }
00992 
00993 
00994 // ***************************************************************************
00995 void                    CPatch::appendFarVertexToRenderList(CTessFarVertex *fv)
00996 {
00997         TFarVertType    type;
00998         uint                    numtb;
00999         getNumTessBlock(fv->PCoord, type, numtb);
01000         
01001         
01002         if(type==FVMasterBlock || type==FVTessBlockEdge)
01003         {
01004                 fv->OwnerBlock= &MasterBlock;
01005                 MasterBlock.FarVertexList.append(fv);
01006         }
01007         else 
01008         {
01009                 // Alloc if necessary the TessBlocks.
01010                 addRefTessBlocks();
01011 
01012                 fv->OwnerBlock= &TessBlocks[numtb];
01013                 TessBlocks[numtb].FarVertexList.append(fv);
01014         }
01015 }
01016 // ***************************************************************************
01017 void                    CPatch::removeFarVertexFromRenderList(CTessFarVertex *fv)
01018 {
01019         TFarVertType    type;
01020         uint                    numtb;
01021         getNumTessBlock(fv->PCoord, type, numtb);
01022         
01023         
01024         if(type==FVMasterBlock || type==FVTessBlockEdge)
01025         {
01026                 MasterBlock.FarVertexList.remove(fv);
01027                 fv->OwnerBlock= NULL;
01028         }
01029         else 
01030         {
01031                 TessBlocks[numtb].FarVertexList.remove(fv);
01032                 fv->OwnerBlock= NULL;
01033 
01034                 // Destroy if necessary the TessBlocks.
01035                 decRefTessBlocks();
01036         }
01037 }
01038 
01039 
01040 // ***************************************************************************
01041 void                    CPatch::appendNearVertexToRenderList(CTileMaterial *tileMat, CTessNearVertex *nv)
01042 {
01043         nlassert(tileMat);
01044 
01045         // Alloc if necessary the TessBlocks.
01046         addRefTessBlocks();
01047 
01048         uint    numtb, numtm;
01049         computeTbTm(numtb, numtm, tileMat->TileS, tileMat->TileT);
01050         nv->OwnerBlock= &TessBlocks[numtb];
01051         TessBlocks[numtb].NearVertexList.append(nv);
01052 }
01053 // ***************************************************************************
01054 void                    CPatch::removeNearVertexFromRenderList(CTileMaterial *tileMat, CTessNearVertex *nv)
01055 {
01056         nlassert(tileMat);
01057 
01058         uint    numtb, numtm;
01059         computeTbTm(numtb, numtm, tileMat->TileS, tileMat->TileT);
01060         TessBlocks[numtb].NearVertexList.remove(nv);
01061         nv->OwnerBlock= NULL;
01062 
01063         // Destroy if necessary the TessBlocks.
01064         decRefTessBlocks();
01065 }
01066 
01067 
01068 
01069 // ***************************************************************************
01070 // ***************************************************************************
01071 // BASIC BUILD.
01072 // ***************************************************************************
01073 // ***************************************************************************
01074 
01075 
01076 
01077 
01078 // ***************************************************************************
01079 void                    CPatch::makeRoots()
01080 {
01081         CTessVertex *a= BaseVertices[0];
01082         CTessVertex *b= BaseVertices[1];
01083         CTessVertex *c= BaseVertices[2];
01084         CTessVertex *d= BaseVertices[3];
01085 
01086         // Set positions.
01087         a->Pos= a->StartPos= a->EndPos= computeVertex(0,0);
01088         b->Pos= b->StartPos= b->EndPos= computeVertex(0,1);
01089         c->Pos= c->StartPos= c->EndPos= computeVertex(1,1);
01090         d->Pos= d->StartPos= d->EndPos= computeVertex(1,0);
01091 
01092         // Init Far vetices.
01093         CTessFarVertex *fa= &BaseFarVertices[0];
01094         CTessFarVertex *fb= &BaseFarVertices[1];
01095         CTessFarVertex *fc= &BaseFarVertices[2];
01096         CTessFarVertex *fd= &BaseFarVertices[3];
01097         fa->Src= a;
01098         fa->PCoord.setST(0,0);
01099         fb->Src= b;
01100         fb->PCoord.setST(0,1);
01101         fc->Src= c;
01102         fc->PCoord.setST(1,1);
01103         fd->Src= d;
01104         fd->PCoord.setST(1,0);
01105 
01106         // We don't have to fill the Far vertices VB here, because this patch is still not visible.
01107         // NB: we can't because we don't have any driver here.
01108         nlassert(RenderClipped==true);
01109 
01110 
01111         // Make Roots.
01112         /*
01113                 Tesselation layout. For Square Face, and if OrderS>=OrderT.
01114 
01115                 A-------D
01116                 |\ Son1 |
01117                 |  \    |
01118                 |    \  |
01119                 | Son0 \|
01120                 B-------C
01121 
01122                 For rectangles whith OrderT>OrderS. It is VERY IMPORTANT, for splitRectangular() reasons.
01123 
01124                 A-------D
01125                 | Son0 /|
01126                 |    /  |
01127                 |  /    |
01128                 |/ Son1 |
01129                 B-------C
01130 
01131         */
01132         nlassert(Son0==NULL);
01133         nlassert(Son1==NULL);
01134         Son0= getLandscape()->newTessFace();
01135         Son1= getLandscape()->newTessFace();
01136 
01137         // Son0.
01138         Son0->Patch= this;
01139         Son0->Level= 0;
01140         if(OrderS>=OrderT)
01141         {
01142                 Son0->VBase= b;
01143                 Son0->VLeft= c;
01144                 Son0->VRight= a;
01145                 Son0->FVBase= fb;
01146                 Son0->FVLeft= fc;
01147                 Son0->FVRight= fa;
01148                 Son0->PVBase.setST(0, 1);
01149                 Son0->PVLeft.setST(1, 1);
01150                 Son0->PVRight.setST(0, 0);
01151         }
01152         else
01153         {
01154                 Son0->VBase= a;
01155                 Son0->VLeft= b;
01156                 Son0->VRight= d;
01157                 Son0->FVBase= fa;
01158                 Son0->FVLeft= fb;
01159                 Son0->FVRight= fd;
01160                 Son0->PVBase.setST(0, 0);
01161                 Son0->PVLeft.setST(0, 1);
01162                 Son0->PVRight.setST(1, 0);
01163         }
01164         Son0->FBase= Son1;
01165         Son0->FLeft= NULL;
01166         Son0->FRight= NULL;
01167         // No tile info.
01168         Son0->Size= ErrorSize/2;
01169         Son0->computeSplitPoint();
01170 
01171         // Son1.
01172         Son1->Patch= this;
01173         Son1->Level= 0;
01174         if(OrderS>=OrderT)
01175         {
01176                 Son1->VBase= d;
01177                 Son1->VLeft= a;
01178                 Son1->VRight= c;
01179                 Son1->FVBase= fd;
01180                 Son1->FVLeft= fa;
01181                 Son1->FVRight= fc;
01182                 Son1->PVBase.setST(1, 0);
01183                 Son1->PVLeft.setST(0, 0);
01184                 Son1->PVRight.setST(1, 1);
01185         }
01186         else
01187         {
01188                 Son1->VBase= c;
01189                 Son1->VLeft= d;
01190                 Son1->VRight= b;
01191                 Son1->FVBase= fc;
01192                 Son1->FVLeft= fd;
01193                 Son1->FVRight= fb;
01194                 Son1->PVBase.setST(1, 1);
01195                 Son1->PVLeft.setST(1, 0);
01196                 Son1->PVRight.setST(0, 1);
01197         }
01198         Son1->FBase= Son0;
01199         Son1->FLeft= NULL;
01200         Son1->FRight= NULL;
01201         // No tile info.
01202         Son1->Size= ErrorSize/2;
01203         Son1->computeSplitPoint();
01204 
01205 
01206         // Prepare the render list...
01207         clearTessBlocks();
01208         resetMasterBlock();
01209         appendFarVertexToRenderList(fa);
01210         appendFarVertexToRenderList(fb);
01211         appendFarVertexToRenderList(fc);
01212         appendFarVertexToRenderList(fd);
01213         appendFaceToRenderList(Son0);
01214         appendFaceToRenderList(Son1);
01215 
01216         // Usefull for geomorph: Init 2 root faces MaxNearLimit, and MaxFaceSize
01217         // NB: since no geomorph is made on endpoints (StartPos==EndPos) of patchs, this is not usefull.
01218         // but it is important to ensure the VP or software geomorph won't crash with bad float values.
01219         // Init MaxFaceSize.
01220         Son0->VBase->MaxFaceSize= 1;
01221         Son0->VLeft->MaxFaceSize= 1;
01222         Son0->VRight->MaxFaceSize= 1;
01223         Son1->VBase->MaxFaceSize= 1;
01224         Son1->VLeft->MaxFaceSize= 1;
01225         Son1->VRight->MaxFaceSize= 1;
01226         // Init MaxNearLimit.
01227         Son0->VBase->MaxNearLimit= 1;
01228         Son0->VLeft->MaxNearLimit= 1;
01229         Son0->VRight->MaxNearLimit= 1;
01230         Son1->VBase->MaxNearLimit= 1;
01231         Son1->VLeft->MaxNearLimit= 1;
01232         Son1->VRight->MaxNearLimit= 1;
01233 
01234 }
01235 
01236 
01237 // ***************************************************************************
01238 void                    CPatch::compile(CZone *z, uint patchId, uint8 orderS, uint8 orderT, CTessVertex *baseVertices[4], float errorSize)
01239 {
01240         nlassert(z);
01241         Zone= z;
01242 
01243         // For updateLighting, get the correct pointer now.
01244         // Init UL circular list to me
01245         _ULNearPrec= this;
01246         _ULNearNext= this;
01247 
01248 
01249         // Once the patch is inserted and compiled in a zone, it is ready to be rendered.
01250         // So now fill the Patch info in render pass.
01251         Pass0.Patch= this;
01252         Pass1.Patch= this;
01253 
01254         // init also the MasterBlock.
01255         MasterBlock.init(this);
01256 
01257         // only 65536 patch per zone allowed.
01258         nlassert(patchId<0x10000);
01259         PatchId= (uint16)patchId;
01260 
01261         if(errorSize==0)
01262                 computeDefaultErrorSize();
01263         else
01264                 ErrorSize= errorSize;
01265 
01266         nlassert(orderS==2 || orderS==4 || orderS==8 || orderS==16);
01267         nlassert(orderT==2 || orderT==4 || orderT==8 || orderT==16);
01268         nlassert (OrderS==orderS);
01269         nlassert (OrderT==orderT);
01270 
01271         // Compile additional infos.
01272         sint    ps= getPowerOf2(orderS) , pt= getPowerOf2(orderT);
01273         sint    pmin= min(ps,pt);
01274         sint    pmax= max(ps,pt);
01275         // Rectangular patch OK.
01276         // Work, since patch 1xX are illegal. => The TileLimitLevel is at least 2 level distant from the time where
01277         // the rectangular patch is said "un-rectangular-ed" (tesselation looks like square). Hence, there is no problem
01278         // with rectangular UV geomorph (well don't bother me, make a draw :) ).
01279         TileLimitLevel= pmin*2 + pmax-pmin;
01280         // A TessBlock is a 2*2 tile. This simple formula works because patch 1xX are illegal.
01281         TessBlockLimitLevel= TileLimitLevel-2;
01282         // This tell us when the tess face is "un-rectangular-ed" (to say a square). Before, it is a "rectangular" face, 
01283         // which has a strange fxxxxxg split.
01284         // If patch is square, then SquareLimitLevel=0 (ok!!).
01285         SquareLimitLevel= pmax-pmin;
01286 
01287         // Buil the BSPhere.
01288         CAABBox bb= buildBBox();
01289         BSphere.Center= bb.getCenter();
01290         BSphere.Radius= bb.getRadius();
01291 
01292         // Bind vertices, to zone base vertices.
01293         BaseVertices[0]= baseVertices[0];
01294         BaseVertices[1]= baseVertices[1];
01295         BaseVertices[2]= baseVertices[2];
01296         BaseVertices[3]= baseVertices[3];
01297 
01298         // build Sons.
01299         makeRoots();
01300 }
01301 // ***************************************************************************
01302 CVector                 CPatch::computeVertex(float s, float t) const
01303 {
01304         // \todo yoyo: TODO_UVCORRECT: use UV correction.
01305 
01306         if(getLandscape()->getNoiseMode())
01307         {
01308                 // compute displacement map to disturb result.
01309                 CVector         displace;
01310                 computeNoise(s,t, displace);
01311 
01312                 // return patch(s,t) + dispalcement result.
01313                 // unpack. Do it after computeNoise(), because this last may change the cache.
01314                 CBezierPatch    *patch= unpackIntoCache();
01315                 return patch->eval(s,t) + displace;
01316         }
01317         else
01318         {
01319                 // unpack and return patch(s,t).
01320                 CBezierPatch    *patch= unpackIntoCache();
01321                 return patch->eval(s,t);
01322         }
01323 }
01324 
01325 
01326 // ***************************************************************************
01327 CVector                 CPatch::computeContinousVertex(float s, float t) const
01328 {
01329         // must be compiled
01330         nlassert(Zone);
01331 
01332         // Test is on a edge/corner of the patch
01333         sint    edgeIdS= -1;
01334         sint    edgeIdT= -1;
01335         if(s==0)                edgeIdS= 0;
01336         else if(s==1)   edgeIdS= 2;
01337         if(t==0)                edgeIdT= 3;
01338         else if(t==1)   edgeIdT= 1;
01339 
01340         // test if on a corner
01341         if(edgeIdS>=0 && edgeIdT>=0)
01342         {
01343                 // return the baseVertex according to edge falgs
01344                 if(edgeIdS==0 && edgeIdT==3)    return BaseVertices[0]->EndPos;
01345                 if(edgeIdS==0 && edgeIdT==1)    return BaseVertices[1]->EndPos;
01346                 if(edgeIdS==2 && edgeIdT==1)    return BaseVertices[2]->EndPos;
01347                 if(edgeIdS==2 && edgeIdT==3)    return BaseVertices[3]->EndPos;
01348                 nlstop;
01349                 // Error, but Avoid warning
01350                 return CVector::Null;
01351         }
01352         // test if on an edge
01353         else if(edgeIdS>=0 || edgeIdT>=0)
01354         {
01355                 // Yes, must compute myslef
01356                 CVector         vertexOnMe= computeVertex(s,t);
01357 
01358                 // Then, must compute my neighbor.
01359                 sint    edgeId;
01360                 if(edgeIdS>=0)
01361                         edgeId= edgeIdS;
01362                 else
01363                         edgeId= edgeIdT;
01364 
01365                 // Get my neighbor, if any.
01366                 CBindInfo       bindInfo;
01367                 getBindNeighbor(edgeId, bindInfo);
01368                 // Fast reject: if no neighbor on the edge, just return my pos.
01369                 if(!bindInfo.Zone)
01370                 {
01371                         return vertexOnMe;
01372                 }
01373                 // else must get vertex pos of my neighbor, and average.
01374                 else
01375                 {
01376                         // use a CPatchUVLocator to get UV in neighbor patch
01377                         CPatchUVLocator         uvLocator;
01378                         uvLocator.build(this, edgeId, bindInfo);
01379 
01380                         // UVlocator use OrderS/OrderT coordinate system.
01381                         CVector2f       stTileIn, stTileOut;
01382                         stTileIn.x= s * getOrderS();
01383                         stTileIn.y= t * getOrderT();
01384 
01385                         // transform coordinate to get into the neigbhor patch
01386                         uint    pid= uvLocator.selectPatch(stTileIn);
01387                         CPatch  *nebPatch;
01388                         uvLocator.locateUV(stTileIn, pid, nebPatch, stTileOut);
01389 
01390                         // transform neigbhor coord in 0..1 coordinate space.
01391                         stTileOut.x/= nebPatch->getOrderS();
01392                         stTileOut.y/= nebPatch->getOrderT();
01393 
01394                         // and compute vertex. NB: if binded on 2 or 4 patch, it is then possible that stTileOut is on a
01395                         // a corner ( (0,0), (0,1) ...).
01396                         // In this case, we must use the precomputed Vertex pos, for completeness.
01397                         bool            onCorner;
01398                         CVector         vertexOnNeb= nebPatch->computeVertexButCorner(stTileOut.x, stTileOut.y, onCorner);
01399 
01400                         // If the neighbor is on a corner, then use its corner value.
01401                         if(onCorner)
01402                                 return vertexOnNeb;
01403                         else
01404                         {
01405                                 // Average the 2 and return this result.
01406                                 vertexOnMe+= vertexOnNeb;
01407                                 vertexOnMe/= 2;
01408                                 return vertexOnMe;
01409                         }
01410                 }
01411 
01412         }
01413         // else, std case
01414         else
01415                 return computeVertex(s, t);
01416 }
01417 
01418 
01419 // ***************************************************************************
01420 CVector                 CPatch::computeVertexButCorner(float s, float t, bool &onCorner) const
01421 {
01422         // must be compiled
01423         nlassert(Zone);
01424 
01425         // Test is on a edge/corner of the patch
01426         sint    edgeIdS= -1;
01427         sint    edgeIdT= -1;
01428         if(s==0)                edgeIdS= 0;
01429         else if(s==1)   edgeIdS= 2;
01430         if(t==0)                edgeIdT= 3;
01431         else if(t==1)   edgeIdT= 1;
01432 
01433         // test if on a corner
01434         if(edgeIdS>=0 && edgeIdT>=0)
01435         {
01436                 // indicate that yes, we are on a corner
01437                 onCorner= true;
01438                 // return the baseVertex according to edge falgs
01439                 if(edgeIdS==0 && edgeIdT==3)    return BaseVertices[0]->EndPos;
01440                 if(edgeIdS==0 && edgeIdT==1)    return BaseVertices[1]->EndPos;
01441                 if(edgeIdS==2 && edgeIdT==1)    return BaseVertices[2]->EndPos;
01442                 if(edgeIdS==2 && edgeIdT==3)    return BaseVertices[3]->EndPos;
01443                 nlstop;
01444                 // Error, but Avoid warning
01445                 return CVector::Null;
01446         }
01447         // else, std case
01448         else
01449         {
01450                 onCorner= false;
01451                 return computeVertex(s, t);
01452         }
01453 }
01454 
01455 
01456 // ***************************************************************************
01457 void                    CPatch::refineAll()
01458 {
01459         // refineAll.
01460         nlassert(Son0);
01461         nlassert(Son1);
01462         Son0->refineAll();
01463         Son1->refineAll();
01464 }
01465 
01466 
01467 
01468 // ***************************************************************************
01469 void                    CPatch::averageTesselationVertices()
01470 {
01471         nlassert(Son0);
01472         nlassert(Son1);
01473 
01474         // Recompute the BaseVertices. This is usefull for Pacs.
01475         // Because CLandscape::averageTesselationVertices() is made on a strict order for patchs (map of zones, then 
01476         // array of patchs), we are sure to overwrite BaseVertices in this order.
01477         CTessVertex *a= BaseVertices[0];
01478         CTessVertex *b= BaseVertices[1];
01479         CTessVertex *c= BaseVertices[2];
01480         CTessVertex *d= BaseVertices[3];
01481         // Set positions.
01482         a->Pos= a->StartPos= a->EndPos= computeVertex(0,0);
01483         b->Pos= b->StartPos= b->EndPos= computeVertex(0,1);
01484         c->Pos= c->StartPos= c->EndPos= computeVertex(1,1);
01485         d->Pos= d->StartPos= d->EndPos= computeVertex(1,0);
01486 
01487 
01488         // Average the tesselation of sons.
01489         Son0->averageTesselationVertices();
01490         Son1->averageTesselationVertices();
01491 }
01492 
01493 
01494 // ***************************************************************************
01495 void                    CPatch::refreshTesselationGeometry()
01496 {
01497         nlassert(Son0);
01498         nlassert(Son1);
01499 
01500         // Recompute the BaseVertices.
01501         CTessVertex *a= BaseVertices[0];
01502         CTessVertex *b= BaseVertices[1];
01503         CTessVertex *c= BaseVertices[2];
01504         CTessVertex *d= BaseVertices[3];
01505         // Set positions.
01506         a->Pos= a->StartPos= a->EndPos= computeVertex(0,0);
01507         b->Pos= b->StartPos= b->EndPos= computeVertex(0,1);
01508         c->Pos= c->StartPos= c->EndPos= computeVertex(1,1);
01509         d->Pos= d->StartPos= d->EndPos= computeVertex(1,0);
01510 
01511 
01512         // refresh the tesselation of sons.
01513         Son0->refreshTesselationGeometry();
01514         Son1->refreshTesselationGeometry();
01515 }
01516 
01517 
01518 
01519 // ***************************************************************************
01520 void                    CPatch::clip(const std::vector<CPlane>  &pyramid)
01521 {
01522         Clipped= false;
01523         for(sint i=0;i<(sint)pyramid.size();i++)
01524         {
01525                 // If entirely out.
01526                 if(!BSphere.clipBack(pyramid[i]))
01527                 {
01528                         Clipped= true;
01529                         break;
01530                 }
01531         }
01532 
01533         // A patch clipped is clipped to render too.
01534         RenderClipped= Clipped;
01535 }
01536 
01537 
01538 // ***************************************************************************
01539 void                    CPatch::resetRenderFar()
01540 {
01541         if (Pass0.PatchRdrPass)
01542         {
01543                 // free the render pass.
01544                 Zone->Landscape->freeFarRenderPass (this, Pass0.PatchRdrPass, Far0);
01545                 Pass0.PatchRdrPass= NULL;
01546         }
01547         if (Pass1.PatchRdrPass)
01548         {
01549                 // free the render pass.
01550                 Zone->Landscape->freeFarRenderPass (this, Pass1.PatchRdrPass, Far1);
01551                 Pass1.PatchRdrPass= NULL;
01552         }
01553 
01554         Far0= -1;
01555         Far1= -1;
01556 }
01557 
01558 
01559 // ***************************************************************************
01560 void                    CPatch::serial(NLMISC::IStream &f)
01561 {
01562         /*
01563         Version 7:
01564                 - remove unused information from CTileColor. just keep 565 color
01565         Version 6:
01566                 - default UnderWater flags for tileElements before version 6.
01567         Version 5:
01568                 - TileLightInfluences serialized.
01569         Version 4:
01570                 - Smooth flag serialized
01571         Version 3:
01572                 - NoiseRotation.
01573                 - NoiseSmooth.
01574         Version 2:
01575                 - Lumels.
01576         Version 1:
01577                 - Tile color.
01578         Version 0:
01579                 - base version.
01580         */
01581         uint    ver= f.serialVersion(_Version);
01582 
01583         // No more compatibility before version 2, because OrderS / OrderT not serialized in preceding version
01584         // Doens't matter since CZone::serial() do not support it too.
01585         if (ver<2)
01586         {
01587                 throw EOlderStream(f);
01588         }
01589 
01590         f.xmlSerial (Vertices[0], Vertices[1], Vertices[2], Vertices[3], "VERTICIES");
01591 
01592         f.xmlPush ("TANGENTS");
01593         f.serial (Tangents[0], Tangents[1], Tangents[2], Tangents[3]);
01594         f.serial (Tangents[4], Tangents[5], Tangents[6], Tangents[7]);
01595         f.xmlPop ();
01596         
01597         f.xmlSerial (Interiors[0], Interiors[1], Interiors[2], Interiors[3], "INTERIORS");
01598 
01599         f.xmlPush ("TILES");
01600         f.serialCont(Tiles);
01601         f.xmlPop ();
01602 
01603         if(ver>=1)
01604         {
01605                 // Read/Write TileColors.
01606                 if(ver<=6)
01607                 {
01608                         nlassert(f.isReading());
01609 
01610                         // read old version of tilesColors (ie with LightX/LightY/LightZ, which are deprecated now)
01611                         vector<CTileColorOldPatchVersion6>      tmpArray;
01612                         f.xmlPush ("TILE_COLORS");
01613                         f.serialCont(tmpArray);
01614                         f.xmlPop ();
01615 
01616                         // then just copy to TileColors.
01617                         TileColors.resize(tmpArray.size());
01618                         if(TileColors.size()>0)
01619                         {
01620                                 memcpy(&TileColors[0], &tmpArray[0], TileColors.size()*sizeof(CTileColor));
01621                         }
01622                 }
01623                 else
01624                 {
01625                         // version >=7, just serial array of TileColors (16 bits TileColor only)
01626                         f.xmlPush ("TILE_COLORS");
01627                         f.serialCont(TileColors);
01628                         f.xmlPop ();
01629                 }
01630         }
01631         if(ver>=2)
01632         {
01633                 f.xmlSerial (OrderS, "ORDER_S");
01634                 f.xmlSerial (OrderT, "ORDER_T");
01635 
01636                 f.xmlPush ("COMPRESSED_LUMELS");
01637                         f.serialCont(CompressedLumels);
01638                 f.xmlPop ();
01639         }
01640         // Else cannot create here the TileColors, because we need the OrderS/OrderT information... Done into CZone serial.
01641         if(ver>=3)
01642         {
01643                 f.xmlSerial (NoiseRotation, "NOISE_ROTATION");
01644                 f.xmlSerial (_CornerSmoothFlag, "CORNER_SMOOTH_FLAG");
01645         }
01646         else
01647         {
01648                 // No Rotation / not smooth by default.
01649                 NoiseRotation= 0;
01650                 _CornerSmoothFlag= 0;
01651         }
01652         if(ver>=4)
01653         {
01654                 f.xmlSerial(Flags, "FLAGS");
01655         }
01656         else
01657         {
01658                 Flags=NL_PATCH_SMOOTH_FLAG_MASK;
01659         }
01660 
01661         // Serialize TileLightInfluences
01662         if(ver>=5)
01663         {
01664                 f.xmlPush ("TILE_LIGHT_INFLUENCES");
01665                 f.serialCont(TileLightInfluences);
01666                 f.xmlPop ();
01667         }
01668         else
01669         {
01670                 if(f.isReading())
01671                 {
01672                         // Fill default.
01673                         resetTileLightInfluences();
01674                 }
01675         }
01676 
01677         // if read a too old version, 
01678         if(ver<6 && f.isReading())
01679         {
01680                 // reset tileElements vegetableState to AboveWater.
01681                 for(uint i=0; i<Tiles.size(); i++)
01682                 {
01683                         Tiles[i].setVegetableState(CTileElement::AboveWater);
01684                 }
01685         }
01686 
01687 
01688 }
01689 
01690 
01691 
01692 // ***************************************************************************
01693 // ***************************************************************************
01694 // Bind / UnBind.
01695 // ***************************************************************************
01696 // ***************************************************************************
01697 
01698 
01699 
01700 // ***************************************************************************
01701 void                    CPatch::unbind()
01702 {
01703         nlassert(Son0 && Son1);
01704 
01705         Son0->unbind();
01706         Son1->unbind();
01707         Son0->forceMerge();
01708         Son1->forceMerge();
01709         // forcemerge should have be completed.
01710         nlassert(Son0->isLeaf() && Son1->isLeaf());
01711         // unbind should have be completed.
01712         nlassert(Son0->FLeft == NULL);
01713         nlassert(Son0->FRight == NULL);
01714         nlassert(Son1->FLeft == NULL);
01715         nlassert(Son1->FRight == NULL);
01716 
01717 
01718         // unbind Noise.
01719         _BindZoneNeighbor[0]= NULL;
01720         _BindZoneNeighbor[1]= NULL;
01721         _BindZoneNeighbor[2]= NULL;
01722         _BindZoneNeighbor[3]= NULL;
01723 
01724 }
01725 
01726 
01727 // ***************************************************************************
01728 CTessFace               *CPatch::getRootFaceForEdge(sint edge) const
01729 {
01730         nlassert(edge>=0 && edge<=3);
01731 
01732         // See tessellation rules.
01733         if(OrderS>=OrderT)
01734         {
01735                 if(edge==0 || edge==1)
01736                         return Son0;
01737                 else
01738                         return Son1;
01739         }
01740         else
01741         {
01742                 if(edge==0 || edge==3)
01743                         return Son0;
01744                 else
01745                         return Son1;
01746         }
01747 }
01748 
01749 // ***************************************************************************
01750 CTessVertex             *CPatch::getRootVertexForEdge(sint edge) const
01751 {
01752         // Return the vertex which is the start of edge.
01753         nlassert(edge>=0 && edge<=3);
01754 
01755         // See tessellation rules.
01756         if(OrderS>=OrderT)
01757         {
01758                 switch(edge)
01759                 {
01760                         case 0: return Son0->VRight;
01761                         case 1: return Son0->VBase;
01762                         case 2: return Son0->VLeft;
01763                         case 3: return Son1->VBase;
01764                         default: return NULL;
01765                 }
01766         }
01767         else
01768         {
01769                 switch(edge)
01770                 {
01771                         case 0: return Son0->VBase;
01772                         case 1: return Son0->VLeft;
01773                         case 2: return Son1->VBase;
01774                         case 3: return Son0->VRight;
01775                         default: return NULL;
01776                 }
01777         }
01778 }
01779 
01780 
01781 // ***************************************************************************
01782 void                    CPatch::changeEdgeNeighbor(sint edge, CTessFace *to)
01783 {
01784         nlassert(edge>=0 && edge<=3);
01785 
01786         // See tessellation rules.
01787         if(OrderS>=OrderT)
01788         {
01789                 switch(edge)
01790                 {
01791                         case 0: Son0->FRight= to; break;
01792                         case 1: Son0->FLeft= to; break;
01793                         case 2: Son1->FRight= to; break;
01794                         case 3: Son1->FLeft= to; break;
01795                 }
01796         }
01797         else
01798         {
01799                 switch(edge)
01800                 {
01801                         case 0: Son0->FLeft= to; break;
01802                         case 1: Son1->FRight= to; break;
01803                         case 2: Son1->FLeft= to; break;
01804                         case 3: Son0->FRight= to; break;
01805                 }
01806         }
01807 }
01808 
01809 
01810 // ***************************************************************************
01811 CTessFace               *CPatch::linkTessFaceWithEdge(const CVector2f &uv0, const CVector2f &uv1, CTessFace *linkTo)
01812 {
01813         nlassert(Son0 && Son1);
01814         // Try to link with Root Son0
01815         CTessFace       *face= Son0->linkTessFaceWithEdge(uv0, uv1, linkTo);
01816         // if Failed Try to link with Root Son1
01817         if(!face)
01818                 face= Son1->linkTessFaceWithEdge(uv0, uv1, linkTo);
01819         return face;
01820 }
01821 
01822 
01823 // ***************************************************************************
01824 void                    CPatch::bind(CBindInfo  Edges[4], bool rebind)
01825 {
01826         // The multiple Patch Face.
01827         // By default, Patch==NULL, FLeft, FRight and FBase==NULL so ok!
01828         static  CTessFace       bind1_2[4];
01829         static  CTessFace       bind1_4[8];
01830 
01831 
01832         // THIS PATCH MUST BE UNBOUND FIRST!!!!!
01833         nlassert(Son0 && Son1);
01834         nlassert(Son0->isLeaf() && Son1->isLeaf());
01835         nlassert(Son0->FLeft == NULL);
01836         nlassert(Son0->FRight == NULL);
01837         nlassert(Son1->FLeft == NULL);
01838         nlassert(Son1->FRight == NULL);
01839 
01840 
01841         // bind the Realtime bind info here (before any computeVertex, and before bind too).
01842         sint    i;
01843         for(i=0;i<4;i++)
01844         {
01845                 // just Copy zone (if not NULL).
01846                 _BindZoneNeighbor[i]= Edges[i].Zone;
01847         }
01848 
01849 
01850         if(!rebind)
01851         {
01852                 // Just recompute base vertices.
01853                 CTessVertex *a= BaseVertices[0];
01854                 CTessVertex *b= BaseVertices[1];
01855                 CTessVertex *c= BaseVertices[2];
01856                 CTessVertex *d= BaseVertices[3];
01857                 // Set positions.
01858                 a->Pos= a->StartPos= a->EndPos= computeVertex(0,0);
01859                 b->Pos= b->StartPos= b->EndPos= computeVertex(0,1);
01860                 c->Pos= c->StartPos= c->EndPos= computeVertex(1,1);
01861                 d->Pos= d->StartPos= d->EndPos= computeVertex(1,0);
01862                 // NB: no propagation problem, since the patch has root only (since has to be unbound!!!)
01863                 // Recompute centers.
01864                 Son0->computeSplitPoint();
01865                 Son1->computeSplitPoint();
01866         }
01867         else
01868         {
01869                 // Keep old Vertices as computed from neighbors, but reFill the 4 FarVertices.
01870                 // NB: don't do it on NearVertices because suppose that Near is Off when a bind occurs (often far away).
01871                 checkFillVertexVBFar(Son0->FVBase);
01872                 checkFillVertexVBFar(Son0->FVLeft);
01873                 checkFillVertexVBFar(Son0->FVRight);
01874                 checkFillVertexVBFar(Son1->FVBase);
01875         }
01876 
01877 
01878         // Bind the roots.
01879         for(i=0;i<4;i++)
01880         {
01881                 CBindInfo       &bind= Edges[i];
01882 
01883                 nlassert(bind.NPatchs==0 || bind.NPatchs==1 || bind.NPatchs==2 || bind.NPatchs==4 || bind.NPatchs==5);
01884                 if(bind.NPatchs==1)
01885                 {
01886                         // Bind me on Next.
01887                         this->changeEdgeNeighbor(i, bind.Next[0]->getRootFaceForEdge(bind.Edge[0]));
01888                         // Bind Next on me.
01889                         bind.Next[0]->changeEdgeNeighbor(bind.Edge[0], this->getRootFaceForEdge(i));
01890                 }
01891                 else if(bind.NPatchs==2)
01892                 {
01893                         // Setup multiple bind.
01894                         this->changeEdgeNeighbor(i, bind1_2+i);
01895                         bind1_2[i].FBase= this->getRootFaceForEdge(i);
01896                         // Setup the multiple face.
01897                         // Follow the conventions! Make a draw for understand. Small Patchs are numbered in CCW.
01898                         bind1_2[i].SonRight= bind.Next[0]->getRootFaceForEdge(bind.Edge[0]);
01899                         bind1_2[i].SonLeft= bind.Next[1]->getRootFaceForEdge(bind.Edge[1]);
01900                         bind1_2[i].VBase= bind.Next[0]->getRootVertexForEdge(bind.Edge[0]);
01901                         // Set a "flag" to neighbors, so they know what edge is to be bind on me.
01902                         bind.Next[0]->changeEdgeNeighbor(bind.Edge[0], &CTessFace::MultipleBindFace);
01903                         bind.Next[1]->changeEdgeNeighbor(bind.Edge[1], &CTessFace::MultipleBindFace);
01904                 }
01905                 else if(bind.NPatchs==4)
01906                 {
01907                         // Setup multiple bind level 0.
01908                         this->changeEdgeNeighbor(i, bind1_2+i);
01909                         bind1_2[i].FBase= this->getRootFaceForEdge(i);
01910 
01911                         // Setup multiple bind level 1.
01912                         // Follow the conventions! Make a draw for understand. Small Patchs are numbered in CCW.
01913                         bind1_2[i].SonRight= bind1_4 + 2*i+0;
01914                         bind1_2[i].SonLeft= bind1_4 + 2*i+1;
01915                         bind1_2[i].VBase= bind.Next[1]->getRootVertexForEdge(bind.Edge[1]);
01916                         // Make first multiple face bind level1.
01917                         bind1_4[2*i+0].FBase= &CTessFace::MultipleBindFace;     // to link correctly when the root face will be splitted.
01918                         bind1_4[2*i+0].SonRight= bind.Next[0]->getRootFaceForEdge(bind.Edge[0]);
01919                         bind1_4[2*i+0].SonLeft= bind.Next[1]->getRootFaceForEdge(bind.Edge[1]);
01920                         bind1_4[2*i+0].VBase= bind.Next[0]->getRootVertexForEdge(bind.Edge[0]);
01921                         // Make second multiple face bind level1.
01922                         bind1_4[2*i+1].FBase= &CTessFace::MultipleBindFace;     // to link correctly when the root face will be splitted.
01923                         bind1_4[2*i+1].SonRight= bind.Next[2]->getRootFaceForEdge(bind.Edge[2]);
01924                         bind1_4[2*i+1].SonLeft= bind.Next[3]->getRootFaceForEdge(bind.Edge[3]);
01925                         bind1_4[2*i+1].VBase= bind.Next[2]->getRootVertexForEdge(bind.Edge[2]);
01926 
01927                         // Set a "flag" to neighbors, so they know what edge is to be bind on me.
01928                         bind.Next[0]->changeEdgeNeighbor(bind.Edge[0], &CTessFace::MultipleBindFace);
01929                         bind.Next[1]->changeEdgeNeighbor(bind.Edge[1], &CTessFace::MultipleBindFace);
01930                         bind.Next[2]->changeEdgeNeighbor(bind.Edge[2], &CTessFace::MultipleBindFace);
01931                         bind.Next[3]->changeEdgeNeighbor(bind.Edge[3], &CTessFace::MultipleBindFace);
01932                 }
01933                 else if(bind.NPatchs==5)
01934                 {
01935                         /* I am binded to a bigger patch and this one has already done the binding on me => 
01936                                 It must be correclty tesselated. Note also that bind 1/X are only possible on interior of zone.
01937                         */
01938 
01939                         // First, make the link with the face to which I must connect.
01940                         // -----------------
01941 
01942                         // Get the coordinate of the current edge of this patch
01943                         CVector2f       uvi0, uvi1;
01944                         switch(i)
01945                         {
01946                         case 0: uvi0.set(0,0); uvi1.set(0,1);  break;
01947                         case 1: uvi0.set(0,1); uvi1.set(1,1);  break;
01948                         case 2: uvi0.set(1,1); uvi1.set(1,0);  break;
01949                         case 3: uvi0.set(1,0); uvi1.set(0,0);  break;
01950                         };
01951                         // mul by OrderS/OrderT for CPatchUVLocator
01952                         uvi0.x*= OrderS;
01953                         uvi0.y*= OrderT;
01954                         uvi1.x*= OrderS;
01955                         uvi1.y*= OrderT;
01956                         // build a CPatchUVLocator to transpose coorindate ot this edge in coordinate on the bigger Neighbor patch.
01957                         CBindInfo       bindInfo;
01958                         getBindNeighbor(i, bindInfo);
01959                         nlassert(bindInfo.Zone!=NULL && bindInfo.NPatchs==1);
01960                         CPatchUVLocator         puvloc;
01961                         puvloc.build(this, i, bindInfo);
01962 
01963                         // transpose from this patch coord in neighbor patch coord.
01964                         CVector2f       uvo0, uvo1;
01965                         uint    pid;
01966                         CPatch  *patchNeighbor;
01967                         // Do it for uvi0
01968                         pid= puvloc.selectPatch(uvi0);
01969                         puvloc.locateUV(uvi0, pid, patchNeighbor, uvo0);
01970                         nlassert(patchNeighbor == bindInfo.Next[0]);
01971                         // Do it for uvi1
01972                         pid= puvloc.selectPatch(uvi1);
01973                         puvloc.locateUV(uvi1, pid, patchNeighbor, uvo1);
01974                         nlassert(patchNeighbor == bindInfo.Next[0]);
01975                         // Rescale to have uv in 0,1 basis.
01976                         uvo0.x/= patchNeighbor->OrderS;
01977                         uvo0.y/= patchNeighbor->OrderT;
01978                         uvo1.x/= patchNeighbor->OrderS;
01979                         uvo1.y/= patchNeighbor->OrderT;
01980 
01981                         // Now, traverse the tesselation and find the first CTessFace which use this edge.
01982                         CTessFace       *faceNeighbor;
01983                         faceNeighbor= patchNeighbor->linkTessFaceWithEdge(uvo0, uvo1, this->getRootFaceForEdge(i));
01984                         nlassert(faceNeighbor);
01985                         // Bind me on Next.
01986                         this->changeEdgeNeighbor(i, faceNeighbor);
01987                 }
01988 
01989         }
01990 
01991         // Propagate the binds to sons.
01992         Son0->updateBind();
01993         Son1->updateBind();
01994 
01995 }
01996 
01997 
01998 // ***************************************************************************
01999 void                    CPatch::forceMergeAtTileLevel()
02000 {
02001         nlassert(Son0 && Son1);
02002 
02003         Son0->forceMergeAtTileLevel();
02004         Son1->forceMergeAtTileLevel();
02005 }
02006 
02007 
02008 
02009 // ***************************************************************************
02010 // ***************************************************************************
02011 // Texturing.
02012 // ***************************************************************************
02013 // ***************************************************************************
02014 
02015 
02016 // ***************************************************************************
02017 CPatchRdrPass   *CPatch::getTileRenderPass(sint tileId, sint pass)
02018 {
02019         // All but lightmap.
02020         nlassert(pass==NL3D_TILE_PASS_RGB0 || pass==NL3D_TILE_PASS_RGB1 || pass==NL3D_TILE_PASS_RGB2 || 
02021                 pass==NL3D_TILE_PASS_ADD);
02022 
02023         bool    additive= (pass==NL3D_TILE_PASS_ADD);
02024         sint    passNum= pass-NL3D_TILE_PASS_RGB0;
02025         // If additive, take the additve tile of bigger existing pass.
02026         if(additive)
02027         {
02028                 // Default: take addtive of pass 0.
02029                 passNum= 0;
02030                 // If the pass1 is not empty, may take its tile.
02031                 if(Tiles[tileId].Tile[1]!=0xFFFF)
02032                 {
02033                         passNum= 1;
02034                         // If the pass2 is not empty, take its tile.
02035                         if(Tiles[tileId].Tile[2]!=0xFFFF)
02036                                 passNum= 2;
02037                 }
02038         }
02039 
02040         sint    tileNumber= Tiles[tileId].Tile[passNum];
02041         if(tileNumber==0xFFFF)
02042         {
02043                 // Display a "fake" only if pass 0.
02044                 if(pass==NL3D_TILE_PASS_RGB0)
02045                         return Zone->Landscape->getTileRenderPass(0xFFFF, false);
02046                 // Else, this tile do not have such a pass (not a transition).
02047                 return NULL;
02048         }
02049         else
02050         {
02051                 // return still may be NULL, in additive case.
02052                 return Zone->Landscape->getTileRenderPass(tileNumber, additive);
02053         }
02054 }
02055 
02056 // ***************************************************************************
02057 void                    CPatch::getTileUvInfo(sint tileId, sint pass, bool alpha, uint8 &orient, CVector &uvScaleBias, bool &is256x256, uint8 &uvOff)
02058 {
02059         // All but lightmap.
02060         nlassert(pass==NL3D_TILE_PASS_RGB0 || pass==NL3D_TILE_PASS_RGB1 || pass==NL3D_TILE_PASS_RGB2 || 
02061                 pass==NL3D_TILE_PASS_ADD);
02062 
02063         bool    additive= (pass==NL3D_TILE_PASS_ADD);
02064         sint    passNum= pass-NL3D_TILE_PASS_RGB0;
02065         // If additive, take the additve tile of bigger existing pass.
02066         if(additive)
02067         {
02068                 // Default: take addtive of pass 0.
02069                 passNum= 0;
02070                 // If the pass1 is not empty, may take its tile.
02071                 if(Tiles[tileId].Tile[1]!=0xFFFF)
02072                 {
02073                         passNum= 1;
02074                         // If the pass2 is not empty, take its tile.
02075                         if(Tiles[tileId].Tile[2]!=0xFFFF)
02076                                 passNum= 2;
02077                 }
02078         }
02079 
02080         sint    tileNumber= Tiles[tileId].Tile[passNum];
02081         if(tileNumber==0xFFFF)
02082         {
02083                 // dummy... Should not be called here.
02084                 orient= 0;
02085                 uvScaleBias.x=0;
02086                 uvScaleBias.y=0;
02087                 uvScaleBias.z=1;
02088                 is256x256=false;
02089                 uvOff=0;
02090         }
02091         else
02092         {
02093                 orient= Tiles[tileId].getTileOrient(passNum);
02094                 Tiles[tileId].getTile256Info(is256x256, uvOff);
02095                 CTile::TBitmap type;
02096                 // If alpha wanted, return its UV info (works either for Alpha in Diffuse Pass and Alpha in Additive Pass)
02097                 if(alpha)
02098                         type= CTile::alpha;
02099                 else
02100                 {
02101                         if(additive)
02102                                 type= CTile::additive;
02103                         else
02104                                 type= CTile::diffuse;
02105                 }
02106 
02107                 uint8   rotalpha;
02108                 Zone->Landscape->getTileUvScaleBiasRot(tileNumber, type, uvScaleBias, rotalpha);
02109 
02110                 // Add the special rotation of alpha.
02111                 if(alpha)
02112                         orient= (orient+rotalpha)&3;
02113         }
02114 
02115 }
02116 
02117 
02118 // ***************************************************************************
02119 void                    CPatch::deleteTileUvs()
02120 {
02121         Son0->deleteTileUvs();
02122         Son1->deleteTileUvs();
02123 }
02124 
02125 
02126 // ***************************************************************************
02127 void                    CPatch::recreateTileUvs()
02128 {
02129         // Reset the Tile rdr list.
02130         for(sint tb=0; tb<(sint)TessBlocks.size();tb++)
02131         {
02132                 // Vertices must all be reseted.
02133                 TessBlocks[tb].NearVertexList.clear();
02134                 for(sint i=0;i<NL3D_TESSBLOCK_TILESIZE;i++)
02135                 {
02136                         CTileMaterial   *tm= TessBlocks[tb].RdrTileRoot[i];
02137                         if(tm)
02138                         {
02139                                 for(sint pass=0;pass<NL3D_MAX_TILE_FACE;pass++)
02140                                 {
02141                                         tm->TileFaceList[pass].clear();
02142                                 }
02143                         }
02144                 }
02145         }
02146 
02147         Son0->recreateTileUvs();
02148         Son1->recreateTileUvs();
02149 }
02150 
02151 
02152 // ***************************************************************************
02153 void            CPatch::appendTessellationLeaves(std::vector<const CTessFace*>  &leaves) const
02154 {
02155         nlassert(Son0);
02156         nlassert(Son1);
02157         Son0->appendTessellationLeaves(leaves);
02158         Son1->appendTessellationLeaves(leaves);
02159 }
02160 
02161 
02162 // ***************************************************************************
02163 CLandscape              *CPatch::getLandscape () const
02164 {
02165         return Zone->getLandscape();
02166 }
02167 
02168 
02169 
02170 
02171 
02172 // ***************************************************************************
02173 uint8                   CPatch::getOrderForEdge(sint8 edge) const
02174 {
02175         uint    e= ((sint)edge + 256)&3;
02176         // If an horizontal edge.
02177         if( e&1 )       return OrderS;
02178         else            return OrderT;
02179 }
02180 
02181 
02182 // ***************************************************************************
02183 // ***************************************************************************
02184 // Realtime Bind info.
02185 // ***************************************************************************
02186 // ***************************************************************************
02187 
02188 
02189 // ***************************************************************************
02190 void    CPatch::getBindNeighbor(uint edge, CBindInfo &neighborEdge) const
02191 {
02192         nlassert(edge<4);
02193 
02194         if(_BindZoneNeighbor[edge]!=NULL)
02195         {
02196                 getZone()->buildBindInfo(PatchId, edge, _BindZoneNeighbor[edge], neighborEdge);
02197         }
02198         else
02199         {
02200                 neighborEdge.Zone= NULL;
02201                 neighborEdge.NPatchs= 0;
02202                 neighborEdge.MultipleBindNum= 0;
02203         }
02204 }
02205 
02206 // ***************************************************************************
02208 void CPatch::setupColorsFromTileFlags(const NLMISC::CRGBA colors[4])
02209 {
02210         for (uint s = 0; s <= OrderS; ++s)
02211         {
02212                 for (uint t = 0; t <= OrderT; ++t)
02213                 {
02214                         uint index = std::min(t, (uint) (OrderT - 1)) * OrderS 
02215                                          + std::min(s, (uint) (OrderS - 1));
02216                         TileColors[s + t * (OrderS + 1)].Color565 = colors[(uint) (Tiles[index].getVegetableState())].get565();                                 
02217                 }
02218         }
02219 }
02220 
02221 // ***************************************************************************
02222 void CPatch::copyTileFlagsFromPatch(const CPatch *src)
02223 {
02224         nlassert(OrderS == src->OrderS
02225                          && OrderT == src->OrderT);
02226 
02227         for (uint k = 0; k  < Tiles.size(); ++k)
02228         {
02229                 Tiles[k].copyFlagsFromOther(src->Tiles[k]);
02230         }
02231 }
02232 
02233 
02234 // ***************************************************************************
02235 // ***************************************************************************
02236 // Tiles get interface.
02237 // ***************************************************************************
02238 // ***************************************************************************
02239 
02240 
02241 // ***************************************************************************
02242 CTileElement *CPatch::getTileElement(const CUV &uv)
02243 {
02244         // compute tile coord and lumel coord.
02245         sint    ts, tt;
02246 
02247         // fastFloor: use a precision of 256 to avoid doing OptFastFloorBegin.
02248         // add 128, to round and get cneter of lumel.
02249         ts= OptFastFloor(uv.U* (OrderS<<8) + 128);      ts>>=8;
02250         tt= OptFastFloor(uv.V* (OrderT<<8) + 128);      tt>>=8;
02251         clamp(ts, 0, OrderS-1);
02252         clamp(tt, 0, OrderT-1);
02253 
02254         // get the lumel
02255         return &(Tiles[ts+tt*OrderS]);
02256 }
02257 
02258 
02259 } // NL3D
02260