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

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 
+
+ + +
                                                                                                                                                                    +
+ + -- cgit v1.2.1