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/landscape_8cpp-source.html | 3621 +++++++++++++++++++++++++++ 1 file changed, 3621 insertions(+) create mode 100644 docs/doxygen/nel/landscape_8cpp-source.html (limited to 'docs/doxygen/nel/landscape_8cpp-source.html') diff --git a/docs/doxygen/nel/landscape_8cpp-source.html b/docs/doxygen/nel/landscape_8cpp-source.html new file mode 100644 index 00000000..f8e7e02f --- /dev/null +++ b/docs/doxygen/nel/landscape_8cpp-source.html @@ -0,0 +1,3621 @@ + + + + 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  
+

landscape.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/landscape.h"
+00030 #include "nel/misc/bsphere.h"
+00031 #include "3d/texture_file.h"
+00032 #include "3d/texture_far.h"
+00033 #include "3d/landscape_profile.h"
+00034 #include "nel/3d/height_map.h"
+00035 #include "3d/tile_noise_map.h"
+00036 #include "3d/vegetable_manager.h"
+00037 #include "3d/vegetable.h"
+00038 #include "3d/landscape_vegetable_block.h"
+00039 #include "3d/fast_floor.h"
+00040 #include "3d/tile_vegetable_desc.h"
+00041 #include "3d/texture_dlm.h"
+00042 #include "3d/patchdlm_context.h"
+00043 #include "nel/misc/hierarchical_timer.h"
+00044 
+00045 
+00046 #include "3d/vertex_program.h"
+00047 
+00048 
+00049 
+00050 using namespace NLMISC;
+00051 using namespace std;
+00052 
+00053 
+00054 namespace NL3D 
+00055 {
+00056 
+00057 
+00058 // ***************************************************************************
+00059 /* 
+00060         Target is 20K faces  in frustum.
+00061         So 80K faces at same time
+00062         So 160K elements (bin tree).
+00063         A good BlockSize (in my opinion) is EstimatedMaxSize / 10, to have less memory leak as possible,
+00064         and to make not so many system allocation.
+00065 
+00066         NL3D_TESSRDR_ALLOC_BLOCKSIZE is 2 times less, because elements are in Far zone or in Near zone only
+00067         (approx same size...)
+00068 */
+00069 #define NL3D_TESS_ALLOC_BLOCKSIZE               16000
+00070 #define NL3D_TESSRDR_ALLOC_BLOCKSIZE    8000
+00071 
+00072 
+00073 // ***************************************************************************
+00074 // This value is important for the precision of the priority list
+00075 #define NL3D_REFINE_PLIST_DIST_STEP             0.0625
+00076 /* This value is important, because faces will be inserted at maximum at this entry in the priority list.
+00077         If not so big (eg 50 meters), a big bunch of faces may be inserted in this entry, which may cause slow down
+00078         sometimes, when all this bunch comes to 0 in the priority list.
+00079         To avoid such a thing, see CTessFacePriorityList::init(), and use of NL3D_REFINE_PLIST_DIST_MAX_MOD.
+00080         Here, distMax= 2048*0.0625= 128
+00081 */
+00082 #define NL3D_REFINE_PLIST_NUM_ENTRIES                   2048
+00083 #define NL3D_REFINE_PLIST_DIST_MAX_MOD                  0.7f
+00084 // For the Split priority list only, numbers of quadrants. MergeList has 0 quadrants.
+00085 #define NL3D_REFINE_PLIST_SPLIT_NUMQUADRANT             16
+00086 
+00087 
+00088 /*
+00089         OverHead size of one RollingTable of priority list is 8 * (NL3D_REFINE_PLIST_NUM_ENTRIES)
+00090         So here, it is "only" 16K.
+00091 
+00092         Since we have 2 Priority list and 16 quadrants for the split one, the total overhead is 18*12.8= 288K
+00093 */
+00094 
+00095 
+00096 // ***************************************************************************
+00097 // Size (in cases) of the quadgrid. must be e power of 2.
+00098 const uint                      CLandscape::_PatchQuadGridSize= 128;
+00099 // Size of a case of the quadgrid.
+00100 const float                     CLandscape::_PatchQuadGridEltSize= 16;
+00101 
+00102 
+00103 // ***************************************************************************
+00104 
+00105 // Bitmap Cross
+00106 
+00107 class CTextureCross : public ITexture
+00108 {
+00109 public:
+00115         virtual void doGenerate()
+00116         {
+00117                 // Resize
+00118                 resize (16, 16);
+00119 
+00120                 // Cross
+00121                 static const uint32 cross[16*16]=
+00122                 {
+00123                         //  0                   1                       2                       3                       4                       5                       6                       7                       8                       9                       10                      11                      12                      13                      14                      15
+00124                         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+00125                         0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 
+00126                         0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 
+00127                         0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 
+00128                         0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 
+00129                         0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 
+00130                         0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 
+00131                         0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 
+00132                         0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 
+00133                         0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 
+00134                         0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 
+00135                         0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 
+00136                         0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 
+00137                         0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 
+00138                         0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 
+00139                         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+00140                 };
+00141 
+00142                 // Null
+00143                 memcpy (&_Data[0][0], cross, 16*16*4);
+00144         }
+00145 
+00146         // Dummy serial...
+00147         virtual void    serial(NLMISC::IStream &f)  throw(NLMISC::EStream) {nlstop;}
+00148         NLMISC_DECLARE_CLASS(CTextureCross);
+00149 };
+00150 
+00151 
+00152 // ***************************************************************************
+00153 const char      *EBadBind::what() const throw()
+00154 {
+00155         sint                    numErr= 0;
+00156         const   sint    NErrByLines= 4;
+00157 
+00158         _Output= "Landscape Bind Error in (3DSMax indices!! (+1) ): ";
+00159 
+00160         std::list<CBindError>::const_iterator           it;
+00161         for(it= BindErrors.begin();it!=BindErrors.end(); it++, numErr++)
+00162         {
+00163                 char    tmp[256];
+00164                 sint    x= it->ZoneId & 255;
+00165                 sint    y= it->ZoneId >> 8;
+00166                 sprintf(tmp, "zone%3d_%c%c.patch%3d;   ", y+1, (char)('A'+(x/26)), (char)('A'+(x%26)), it->PatchId+1);
+00167                 if( (numErr%NErrByLines) == 0)
+00168                         _Output+= "\n";
+00169                 _Output+= tmp;
+00170         }
+00171         return _Output.c_str(); 
+00172 }
+00173 
+00174 
+00175 // ***************************************************************************
+00176 // Init BlockAllcoator with standard BlockMemory.
+00177 CLandscape::CLandscape() : 
+00178         TessFaceAllocator(NL3D_TESS_ALLOC_BLOCKSIZE), 
+00179         TessVertexAllocator(NL3D_TESS_ALLOC_BLOCKSIZE), 
+00180         TessNearVertexAllocator(NL3D_TESSRDR_ALLOC_BLOCKSIZE), 
+00181         TessFarVertexAllocator(NL3D_TESSRDR_ALLOC_BLOCKSIZE), 
+00182         TileMaterialAllocator(NL3D_TESSRDR_ALLOC_BLOCKSIZE), 
+00183         TileFaceAllocator(NL3D_TESSRDR_ALLOC_BLOCKSIZE),
+00184         _Far0VB(CLandscapeVBAllocator::Far0),
+00185         _Far1VB(CLandscapeVBAllocator::Far1),
+00186         _TileVB(CLandscapeVBAllocator::Tile)
+00187 {
+00188         TileInfos.resize(NL3D::NbTilesMax);
+00189 
+00190         // Resize the vectors of sert of render pass for the far texture
+00191         _FarRdrPassSetVectorFree.resize (getRdrPassIndexWithSize (NL_MAX_SIZE_OF_TEXTURE_EDGE, NL_MAX_SIZE_OF_TEXTURE_EDGE)+1);
+00192 
+00193         // Far texture not initialized till initTileBanks is not called
+00194         _FarInitialized=false;
+00195         
+00196         // Init far lighting with White/black
+00197         setupStaticLight (CRGBA(255,255,255), CRGBA(0,0,0), 1.f);
+00198         // Default material for pointLights
+00199         _PointLightDiffuseMaterial= CRGBA::White;
+00200 
+00201 
+00202         fill(TileInfos.begin(), TileInfos.end(), (CTileInfo*)NULL);
+00203 
+00204         _FarTransition= 10;             // 10 meters.
+00205         _TileDistNear=100.f;
+00206         _Threshold= 0.001f;
+00207         _RefineMode=true;
+00208 
+00209         _TileMaxSubdivision= 0;
+00210 
+00211         _NFreeLightMaps= 0;
+00212 
+00213         // By default Automatic light comes from up.
+00214         _AutomaticLighting = false;
+00215         _AutomaticLightDir= -CVector::K;
+00216 
+00217         // By default, noise is enabled.
+00218         _NoiseEnabled= true;
+00219 
+00220         // By default, we compute Geomorph and Alpha in software.
+00221         _VertexShaderOk= false;
+00222         _VPThresholdChange= false;
+00223 
+00224         _RenderMustRefillVB= false;
+00225 
+00226         // priority list.
+00227         _OldRefineCenterSetuped= false;
+00228         _SplitPriorityList.init(NL3D_REFINE_PLIST_DIST_STEP, NL3D_REFINE_PLIST_NUM_ENTRIES, NL3D_REFINE_PLIST_DIST_MAX_MOD, NL3D_REFINE_PLIST_SPLIT_NUMQUADRANT);
+00229         // See updateRefine* Doc in tesselation.cpp for why the merge list do not need quadrants.
+00230         _MergePriorityList.init(NL3D_REFINE_PLIST_DIST_STEP, NL3D_REFINE_PLIST_NUM_ENTRIES, NL3D_REFINE_PLIST_DIST_MAX_MOD, 0);
+00231         // just for getTesselatedPos to work properly.
+00232         _OldRefineCenter= CVector::Null;
+00233 
+00234         // create / Init the vegetable manager.
+00235         _VegetableManager= new CVegetableManager(NL3D_LANDSCAPE_VEGETABLE_MAX_AGP_VERTEX_UNLIT, NL3D_LANDSCAPE_VEGETABLE_MAX_AGP_VERTEX_LIGHTED);
+00236 
+00237         // Init vegetable  setup.
+00238         _VegetableManagerEnabled= false;
+00239         _DriverOkForVegetable= false;
+00240         // default global vegetable color, used for dynamic lighting only (arbitrary).
+00241         _DLMGlobalVegetableColor.set(180, 180, 180);
+00242 
+00243         _PZBModelPosition= CVector::Null;
+00244 
+00245 
+00246         // Default: no updateLighting.
+00247         _ULFrequency= 0;
+00248         _ULPrecTimeInit= false;
+00249         // Default: no textureFar created.
+00250         _ULTotalFarPixels= 0;
+00251         _ULFarPixelsToUpdate= 0;
+00252         _ULRootTextureFar= NULL;
+00253         _ULFarCurrentPatchId= 0;
+00254         // Default: no patch created
+00255         _ULTotalNearPixels= 0;
+00256         _ULNearPixelsToUpdate= 0;
+00257         _ULRootNearPatch= NULL;
+00258         _ULNearCurrentTessBlockId= 0;
+00259 
+00260 
+00261         // Dynamic Lighting.
+00262         _TextureDLM= new CTextureDLM(NL3D_LANDSCAPE_DLM_WIDTH, NL3D_LANDSCAPE_DLM_HEIGHT);
+00263         _PatchDLMContextList= new CPatchDLMContextList;
+00264         _DLMMaxAttEnd= 30.f;
+00265 
+00266 
+00267         // Alloc some global space for tri rendering.
+00268         if( CLandscapeGlobals::PassTriArray.size() < 1000 )
+00269                 CLandscapeGlobals::PassTriArray.resize( 1000 );
+00270 
+00271 }
+00272 // ***************************************************************************
+00273 CLandscape::~CLandscape()
+00274 {
+00275         clear();
+00276 
+00277         // release the VegetableManager.
+00278         delete _VegetableManager;
+00279         _VegetableManager= NULL;
+00280 
+00281         // Dynamic Lighting.
+00282         // smartPtr delete
+00283         _TextureDLM= NULL;
+00284         delete _PatchDLMContextList;
+00285         _PatchDLMContextList= NULL;
+00286 }
+00287 
+00288 
+00289 // ***************************************************************************
+00290 void                    CLandscape::init()
+00291 {
+00292         // Fill Far mat.
+00293         // Must init his BlendFunction here!!! becaus it switch between blend on/off during rendering.
+00294         FarMaterial.initUnlit();
+00295         FarMaterial.setSrcBlend(CMaterial::srcalpha);
+00296         FarMaterial.setDstBlend(CMaterial::invsrcalpha);
+00297 
+00298         // FarMaterial: pass trhough Alpha from diffuse.
+00299         FarMaterial.texEnvOpAlpha(0, CMaterial::Replace);
+00300         FarMaterial.texEnvArg0Alpha(0, CMaterial::Diffuse, CMaterial::SrcAlpha);
+00301         FarMaterial.texEnvOpAlpha(1, CMaterial::Replace);
+00302         FarMaterial.texEnvArg0Alpha(1, CMaterial::Diffuse, CMaterial::SrcAlpha);
+00303         // FarMaterial: Add RGB from static lightmap and dynamic lightmap
+00304         FarMaterial.texEnvOpRGB(0, CMaterial::Replace);
+00305         FarMaterial.texEnvArg0RGB(0, CMaterial::Texture, CMaterial::SrcColor);
+00306         FarMaterial.texEnvOpRGB(1, CMaterial::Add);
+00307         FarMaterial.texEnvArg0RGB(1, CMaterial::Texture, CMaterial::SrcColor);
+00308         FarMaterial.texEnvArg1RGB(1, CMaterial::Previous, CMaterial::SrcColor);
+00309 
+00310 
+00311         // Init material for tile.
+00312         TileMaterial.initUnlit();
+00313 
+00314         // init quadGrid.
+00315         _PatchQuadGrid.create(_PatchQuadGridSize, _PatchQuadGridEltSize);
+00316 }
+00317 
+00318 
+00319 // ***************************************************************************
+00320 void                    CLandscape::setThreshold (float thre)
+00321 {
+00322         thre= max(thre, 0.f);
+00323         if(thre != _Threshold)
+00324         {
+00325                 _Threshold= thre;
+00326                 _VPThresholdChange= true;
+00327         }
+00328 }
+00329 
+00330 
+00331 // ***************************************************************************
+00332 void                    CLandscape::setTileNear (float tileNear)
+00333 {
+00334         tileNear= max(tileNear, _FarTransition);
+00335 
+00336         if(tileNear!=_TileDistNear)
+00337         {
+00338                 _TileDistNear= tileNear;
+00339                 resetRenderFarAndDeleteVBFV();
+00340         }
+00341 
+00342 }
+00343 
+00344 
+00345 // ***************************************************************************
+00346 void                    CLandscape::setTileMaxSubdivision (uint tileDiv)
+00347 {
+00348         nlassert(tileDiv>=0 && tileDiv<=4);
+00349 
+00350         if(tileDiv!=_TileMaxSubdivision)
+00351         {
+00352                 _TileMaxSubdivision= tileDiv;
+00353                 // Force at Tile==0. Nex refine will split correctly.
+00354                 forceMergeAtTileLevel();
+00355         }
+00356 }
+00357 // ***************************************************************************
+00358 uint                    CLandscape::getTileMaxSubdivision ()
+00359 {
+00360         return _TileMaxSubdivision;
+00361 }
+00362 
+00363 
+00364 // ***************************************************************************
+00365 void                    CLandscape::resetRenderFarAndDeleteVBFV()
+00366 {
+00367         // For all patch of all zones.
+00368         for(ItZoneMap it= Zones.begin();it!=Zones.end();it++)
+00369         {
+00370                 ((*it).second)->resetRenderFarAndDeleteVBFV();
+00371         }
+00372 }
+00373 
+00374 
+00375 // ***************************************************************************
+00376 void                    CLandscape::forceMergeAtTileLevel()
+00377 {
+00378         // For all patch of all zones.
+00379         for(ItZoneMap it= Zones.begin();it!=Zones.end();it++)
+00380         {
+00381                 ((*it).second)->forceMergeAtTileLevel();
+00382         }
+00383 }
+00384 
+00385 
+00386 // ***************************************************************************
+00387 bool                    CLandscape::addZone(const CZone &newZone)
+00388 {
+00389         // -1. Update globals
+00390         updateGlobalsAndLockBuffers (CVector::Null);
+00391         // NB: adding a zone may add vertices in VB in visible patchs (because of binds)=> buffers are locked.
+00392 
+00393         uint16  zoneId= newZone.getZoneId();
+00394 
+00395         if(Zones.find(zoneId)!=Zones.end())
+00396         {
+00397                 unlockBuffers();
+00398                 return false;
+00399         }
+00400         CZone   *zone= new CZone;
+00401 
+00402         // copy zone.
+00403         zone->build(newZone);
+00404 
+00405         // Affect the current lighting of pointLight to the zone.
+00406         ItLightGroupColorMap    itLGC= _LightGroupColorMap.begin();
+00407         while( itLGC != _LightGroupColorMap.end() )
+00408         {
+00409                 zone->_PointLightArray.setPointLightFactor(itLGC->first, itLGC->second);
+00410                 itLGC++;
+00411         }
+00412 
+00413 
+00414         // apply the landscape heightField, modifying BBoxes.
+00415         zone->applyHeightField(*this);
+00416 
+00417         // compile the zone for this landscape.
+00418         zone->compile(this, Zones);
+00419 
+00420         // For test of _PatchQuadGrid erase.
+00421         CAABBox zoneBBForErase= zone->getZoneBB().getAABBox();
+00422         // Avoid precision problems by enlarging a little bbox size of zone for erase
+00423         zoneBBForErase.setHalfSize( zoneBBForErase.getHalfSize() * 1.1f);
+00424 
+00425         // add patchs of this zone to the quadgrid.
+00426         for(sint i= 0; i<zone->getNumPatchs(); i++)
+00427         {
+00428                 const CPatch *pa= ((const CZone*)zone)->getPatch(i);
+00429                 CPatchIdentEx   paId;
+00430                 paId.ZoneId= zoneId;
+00431                 paId.PatchId= i;
+00432                 paId.Patch= pa;
+00433                 CAABBox         bb= pa->buildBBox();
+00434                 _PatchQuadGrid.insert(bb.getMin(), bb.getMax(), paId);
+00435                 // NB: the bbox of zone is used to remove patch. Hence it is VERY important that zoneBBox includes
+00436                 // all patchs bbox (else some patchs entries may not be deleted in removeZone()).
+00437                 nlassert(zoneBBForErase.include(bb));
+00438         }
+00439 
+00440         // Must realase VB Buffers
+00441         unlockBuffers();
+00442 
+00443         // Because bind may add faces in other (visible) zones because of enforced split, we must check
+00444         // and update any FaceVector.
+00445         updateTessBlocksFaceVector();
+00446 
+00447         return true;
+00448 }
+00449 // ***************************************************************************
+00450 bool                    CLandscape::removeZone(uint16 zoneId)
+00451 {
+00452         // -1. Update globals
+00453         updateGlobalsAndLockBuffers (CVector::Null);
+00454         // NB: remove a zone may change vertices in VB in visible patchs => buffers are locked.
+00455 
+00456         // find the zone.
+00457         if(Zones.find(zoneId)==Zones.end())
+00458         {
+00459                 unlockBuffers();
+00460                 return false;
+00461         }
+00462         CZone   *zone= Zones[zoneId];
+00463 
+00464 
+00465         // delete patchs from this zone to the quadgrid.
+00466         // use the quadgrid itself to find where patch are. do this using bbox of zone.
+00467         CAABBox zoneBBForErase= zone->getZoneBB().getAABBox();
+00468         // Avoid precision problems by enlarging a little bbox size of zone for erase
+00469         zoneBBForErase.setHalfSize( zoneBBForErase.getHalfSize() * 1.1f);
+00470         // select iterators in the area of this zone.
+00471         _PatchQuadGrid.clearSelection();
+00472         _PatchQuadGrid.select(zoneBBForErase.getMin(), zoneBBForErase.getMax());
+00473         // for each patch, remove it if from deleted zone.
+00474         CQuadGrid<CPatchIdentEx>::CIterator     it;
+00475         sint    nPatchRemoved= 0;
+00476         for(it= _PatchQuadGrid.begin(); it!= _PatchQuadGrid.end();)
+00477         {
+00478                 // if the patch belong to the zone to remove
+00479                 if( (*it).ZoneId== zone->getZoneId() )
+00480                 {
+00481                         // remove from the quadgrid.
+00482                         it= _PatchQuadGrid.erase(it);
+00483                         nPatchRemoved++;
+00484                 }
+00485                 else
+00486                         it++;
+00487         }
+00488         // verify we have removed all patch in the quadGrid for this zone
+00489         nlassert(nPatchRemoved==zone->getNumPatchs());
+00490 
+00491 
+00492         // remove the zone.
+00493         zone->release(Zones);
+00494         delete zone;
+00495 
+00496         // Must realase VB Buffers
+00497         unlockBuffers();
+00498 
+00499         // because of forceMerge() at unbind, removeZone() can cause change in faces in other (visible) zones.
+00500         updateTessBlocksFaceVector();
+00501 
+00502         return true;
+00503 }
+00504 // ***************************************************************************
+00505 void                    CLandscape::getZoneList(std::vector<uint16>     &zoneIds) const
+00506 {
+00507         zoneIds.clear();
+00508         zoneIds.reserve(Zones.size());
+00509         std::map<uint16, CZone*>::const_iterator        it;
+00510         for(it= Zones.begin();it!=Zones.end();it++)
+00511         {
+00512                 zoneIds.push_back((*it).first);
+00513         }
+00514 }
+00515 // ***************************************************************************
+00516 void                    CLandscape::buildZoneName(sint zoneId, std::string &zoneName)
+00517 {
+00518         char    tmp[256];
+00519         sint    x= zoneId & 255;
+00520         sint    y= zoneId >> 8;
+00521         sprintf(tmp, "%d_%c%c", y+1, (char)('A'+(x/26)), (char)('A'+(x%26)));
+00522         zoneName= tmp;
+00523 }
+00524 // ***************************************************************************
+00525 void                    CLandscape::clear()
+00526 {
+00527         // Build the list of zoneId.
+00528         vector<uint16>  zoneIds;
+00529         getZoneList(zoneIds);
+00530 
+00531         // Remove each zone one by one.
+00532         sint i;
+00533         for(i=0;i<(sint)zoneIds.size();i++)
+00534         {
+00535                 nlverify(removeZone(zoneIds[i]));
+00536         }
+00537 
+00538         // ensure the quadgrid is empty.
+00539         _PatchQuadGrid.clear();
+00540 
+00541 
+00542         // If not done, delete all VBhards allocated.
+00543         _Far0VB.clear();
+00544         _Far1VB.clear();
+00545         _TileVB.clear();
+00546 
+00547 
+00548         // Reset All Far Texture and unlink _ULRootTextureFar ciruclarList.
+00549         // First "free" the Free list. 
+00550         for(i=0;i<(sint)_FarRdrPassSetVectorFree.size();i++)
+00551         {
+00552                 _FarRdrPassSetVectorFree[i].clear();
+00553         }
+00554         // Then free all Far RdrPass.
+00555         ItSPRenderPassSet       itFar;
+00556         // unitl set is empty
+00557         while( (itFar= _FarRdrPassSet.begin()) != _FarRdrPassSet.end())
+00558         {
+00559                 // erase with link update.
+00560                 eraseFarRenderPassFromSet(*itFar);
+00561         }
+00562 
+00563 
+00564         // reset driver.
+00565         _Driver= NULL;
+00566 }
+00567 
+00568 // ***************************************************************************
+00569 void                    CLandscape::setDriver(IDriver *drv)
+00570 {
+00571         nlassert(drv);
+00572         if(_Driver != drv)
+00573         {
+00574                 _Driver= drv;
+00575 
+00576                 // Does the driver support VertexShader???
+00577                 // only if VP supported by GPU.
+00578                 _VertexShaderOk= (_Driver->isVertexProgramSupported() && !_Driver->isVertexProgramEmulated());
+00579 
+00580 
+00581                 // Does the driver has sufficient requirements for Vegetable???
+00582                 // only if VP supported by GPU, and Only if max vertices allowed.
+00583                 _DriverOkForVegetable= _VertexShaderOk && (_Driver->getMaxVerticesByVertexBufferHard()>=(uint)NL3D_LANDSCAPE_VEGETABLE_MAX_AGP_VERTEX_MAX);
+00584 
+00585         }
+00586 }
+00587 
+00588 // ***************************************************************************
+00589 void                    CLandscape::clip(const CVector &refineCenter, const std::vector<CPlane> &pyramid)
+00590 {
+00591         // -1. Update globals
+00592         updateGlobalsAndLockBuffers (refineCenter);
+00593         // NB: clip may add/remove vertices in VB in visible patchs => buffers are locked.
+00594 
+00595 
+00596         for(ItZoneMap it= Zones.begin();it!=Zones.end();it++)
+00597         {
+00598                 (*it).second->clip(pyramid);
+00599         }
+00600 
+00601         // Must realase VB Buffers
+00602         unlockBuffers();
+00603 
+00604         // clip() should not cause change in faces in visible patchs.
+00605         // It should not happens, but check for security.
+00606         nlassert(_TessBlockModificationRoot.getNextToModify()==NULL);
+00607         updateTessBlocksFaceVector();
+00608 
+00609 }
+00610 // ***************************************************************************
+00611 void                    CLandscape::refine(const CVector &refineCenter)
+00612 {
+00613         NL3D_PROFILE_LAND_SET(ProfNRefineFaces, 0);
+00614         NL3D_PROFILE_LAND_SET(ProfNRefineComputeFaces, 0);
+00615         NL3D_PROFILE_LAND_SET(ProfNRefineLeaves, 0);
+00616         NL3D_PROFILE_LAND_SET(ProfNSplits, 0);
+00617         NL3D_PROFILE_LAND_SET(ProfNMerges, 0);
+00618         NL3D_PROFILE_LAND_SET(ProfNRefineInTileTransition, 0);
+00619         NL3D_PROFILE_LAND_SET(ProfNRefineWithLowDistance, 0);
+00620         NL3D_PROFILE_LAND_SET(ProfNSplitsPass, 0);
+00621 
+00622         if(!_RefineMode)
+00623                 return;
+00624 
+00625         // Update the priority list.
+00626         // ==========================
+00627         CTessFacePListNode              rootSplitTessFaceToUpdate;
+00628         CTessFacePListNode              rootMergeTessFaceToUpdate;
+00629         if( !_OldRefineCenterSetuped )
+00630         {
+00631                 // If never refine, and setup OldRefineCetner
+00632                 _OldRefineCenterSetuped= true;
+00633                 _OldRefineCenter= refineCenter;
+00634 
+00635                 // then shift all faces
+00636                 _SplitPriorityList.shiftAll(rootSplitTessFaceToUpdate);
+00637                 _MergePriorityList.shiftAll(rootMergeTessFaceToUpdate);
+00638         }
+00639         else
+00640         {
+00641                 // else, compute delta between positions
+00642                 CVector         diff= refineCenter - _OldRefineCenter;
+00643                 _OldRefineCenter= refineCenter;
+00644 
+00645                 // and shift according to distance of deplacement.
+00646                 _SplitPriorityList.shift(diff, rootSplitTessFaceToUpdate);
+00647                 _MergePriorityList.shift(diff, rootMergeTessFaceToUpdate);
+00648         }
+00649 
+00650 
+00651         // Refine Faces which may need it.
+00652         // ==========================
+00653         // Update globals
+00654         updateGlobalsAndLockBuffers (refineCenter);
+00655         // NB: refine may change vertices in VB in visible patchs => buffers are locked.
+00656 
+00657         // Increment the update date.
+00658         CLandscapeGlobals::CurrentDate++;
+00659 
+00660         // Because CTessFacePriorityList::insert use it.
+00661         OptFastFloorBegin();
+00662 
+00663         /* While there is still face in list, update them
+00664                 NB: updateRefine() always insert the face in _***PriorityList, so face is removed from 
+00665                 root***TessFaceToUpdate list.
+00666                 NB: it is possible ( with enforced merge() ) that faces dissapears from root***TessFaceToUpdate list 
+00667                 before they are traversed here. It is why we must use a Circular list system, and not an array of elements.
+00668                 Basically. TessFaces are ALWAYS in a list, either in one of the entry list in _***PriorityList, or in
+00669                 root***TessFaceToUpdate list.
+00670 
+00671                 It is newTessFace() and deleteTessFace() which insert/remove the nodes in the list.
+00672         */
+00673         // Update the Merge priority list.
+00674         while( rootMergeTessFaceToUpdate.nextInPList() != &rootMergeTessFaceToUpdate )
+00675         {
+00676                 // Get the face.
+00677                 CTessFace       *face= static_cast<CTessFace*>(rootMergeTessFaceToUpdate.nextInPList());
+00678 
+00679                 // update the refine of this face. This may lead in deletion (merge) of other faces which are still in 
+00680                 // root***TessFaceToUpdate, but it's work.
+00681                 face->updateRefineMerge();
+00682         }
+00683 
+00684 
+00685         // Update the Split priority list.
+00686         do
+00687         {
+00688                 NL3D_PROFILE_LAND_ADD(ProfNSplitsPass, 1);
+00689 
+00690                 // Append the new leaves, to the list of triangles to update
+00691                 rootSplitTessFaceToUpdate.appendPList(_RootNewLeaves);
+00692 
+00693                 // While triangle to test for split exists
+00694                 while( rootSplitTessFaceToUpdate.nextInPList() != &rootSplitTessFaceToUpdate )
+00695                 {
+00696                         // Get the face.
+00697                         CTessFace       *face= static_cast<CTessFace*>(rootSplitTessFaceToUpdate.nextInPList());
+00698 
+00699                         // update the refine of this face.
+00700                         face->updateRefineSplit();
+00701                 }
+00702 
+00703         }
+00704         // do it until we are sure no more split is needed, ie no more faces are created
+00705         while( _RootNewLeaves.nextInPList() != &_RootNewLeaves );
+00706 
+00707         // Because CTessFacePriorityList::insert use it.
+00708         OptFastFloorEnd();
+00709 
+00710 
+00711         // Before unlockBuffers, test for vegetable IG creation.
+00712         {
+00713                 H_AUTO( NL3D_Vegetable_Update );
+00714 
+00715                 // Because CLandscapeVegetableBlock::update() use OptFastFloor..
+00716                 OptFastFloorBegin();
+00717 
+00718                 // For each vegetableBlock, test IG creation
+00719                 CLandscapeVegetableBlock        *vegetBlock= _VegetableBlockList.begin();
+00720                 for(;vegetBlock!=NULL; vegetBlock= (CLandscapeVegetableBlock*)vegetBlock->Next)
+00721                 {
+00722                         vegetBlock->update(refineCenter, _VegetableManager);
+00723                 }
+00724 
+00725                 // update lighting for vegetables
+00726                 _VegetableManager->updateLighting();
+00727 
+00728                 // Stop fastFloor optim.
+00729                 OptFastFloorEnd();
+00730         }
+00731 
+00732 
+00733         // Must realase VB Buffers
+00734         unlockBuffers();
+00735 
+00736         // refine() may cause change in faces in visible patchs.
+00737         updateTessBlocksFaceVector();
+00738 
+00739 }
+00740 
+00741 
+00742 // ***************************************************************************
+00743 void                    CLandscape::refineAll(const CVector &refineCenter)
+00744 {
+00745         // -1. Update globals
+00746         updateGlobalsAndLockBuffers (refineCenter);
+00747         // NB: refineAll may change vertices in VB in visible patchs => buffers are locked.
+00748 
+00749         // Increment the update date.
+00750         CLandscapeGlobals::CurrentDate++;
+00751 
+00752         for(ItZoneMap it= Zones.begin();it!=Zones.end();it++)
+00753         {
+00754                 (*it).second->refineAll();
+00755         }
+00756 
+00757         // Must realase VB Buffers
+00758         unlockBuffers();
+00759 
+00760         // refineAll() may cause change in faces in visible patchs.
+00761         updateTessBlocksFaceVector();
+00762 }
+00763 
+00764 
+00765 // ***************************************************************************
+00766 void                    CLandscape::excludePatchFromRefineAll(sint zoneId, uint patch, bool exclude)
+00767 {
+00768         ItZoneMap it= Zones.find(zoneId);
+00769         if(it!=Zones.end())
+00770         {
+00771                 it->second->excludePatchFromRefineAll(patch, exclude);
+00772         }
+00773 
+00774 }
+00775 
+00776 
+00777 // ***************************************************************************
+00778 void                    CLandscape::averageTesselationVertices()
+00779 {
+00780         // -1. Update globals
+00781         updateGlobalsAndLockBuffers (CVector::Null);
+00782         // NB: averageTesselationVertices may change vertices in VB in visible patchs => buffers are locked.
+00783 
+00784         // Increment the update date.
+00785         CLandscapeGlobals::CurrentDate++;
+00786 
+00787         for(ItZoneMap it= Zones.begin();it!=Zones.end();it++)
+00788         {
+00789                 (*it).second->averageTesselationVertices();
+00790         }
+00791 
+00792         // Must realase VB Buffers
+00793         unlockBuffers();
+00794 
+00795         // averageTesselationVertices() should not cause change in faces in any patchs.
+00796         // It should not happens, but check for security.
+00797         nlassert(_TessBlockModificationRoot.getNextToModify()==NULL);
+00798         updateTessBlocksFaceVector();
+00799 
+00800 }
+00801 
+00802 
+00803 
+00804 // ***************************************************************************
+00805 void                    CLandscape::updateGlobalsAndLockBuffers (const CVector &refineCenter)
+00806 {
+00807         // Setup CLandscapeGlobals static members...
+00808 
+00809         // Far limits.
+00810         CLandscapeGlobals::FarTransition= _FarTransition;
+00811 
+00812         // Tile subdivsion part.
+00813         CLandscapeGlobals::TileMaxSubdivision= _TileMaxSubdivision;
+00814         CLandscapeGlobals::TileDistNear = _TileDistNear;
+00815         CLandscapeGlobals::TileDistFar = CLandscapeGlobals::TileDistNear+20;
+00816         CLandscapeGlobals::TileDistNearSqr = sqr(CLandscapeGlobals::TileDistNear);
+00817         CLandscapeGlobals::TileDistFarSqr = sqr(CLandscapeGlobals::TileDistFar);
+00818         CLandscapeGlobals::OOTileDistDeltaSqr = 1.0f / (CLandscapeGlobals::TileDistFarSqr - CLandscapeGlobals::TileDistNearSqr);
+00819 
+00820         // Tile Pixel size part.
+00821         // \todo yoyo: choose according to wanted tile pixel size.
+00822         CLandscapeGlobals::TilePixelSize= 128.0f;
+00823         CLandscapeGlobals::TilePixelBias128= 0.5f/CLandscapeGlobals::TilePixelSize;
+00824         CLandscapeGlobals::TilePixelScale128= 1-1/CLandscapeGlobals::TilePixelSize;
+00825         CLandscapeGlobals::TilePixelBias256= 0.5f/(CLandscapeGlobals::TilePixelSize*2);
+00826         CLandscapeGlobals::TilePixelScale256= 1-1/(CLandscapeGlobals::TilePixelSize*2);
+00827 
+00828         // RefineThreshold.
+00829         CLandscapeGlobals::RefineThreshold= _Threshold;
+00830 
+00831         if (_Threshold == 0.0f)
+00832                 CLandscapeGlobals::OORefineThreshold = FLT_MAX;
+00833         else
+00834                 CLandscapeGlobals::OORefineThreshold = 1.0f / CLandscapeGlobals::RefineThreshold;
+00835 
+00836         // Refine Center*.
+00837         CLandscapeGlobals::RefineCenter= refineCenter;
+00838         CLandscapeGlobals::TileFarSphere.Center= CLandscapeGlobals::RefineCenter;
+00839         CLandscapeGlobals::TileFarSphere.Radius= CLandscapeGlobals::TileDistFar;
+00840         CLandscapeGlobals::TileNearSphere.Center= CLandscapeGlobals::RefineCenter;
+00841         CLandscapeGlobals::TileNearSphere.Radius= CLandscapeGlobals::TileDistNear;
+00842 
+00843         // PZBModelPosition
+00844         CLandscapeGlobals::PZBModelPosition= _PZBModelPosition;
+00845 
+00846         // VB Allocators.
+00847         CLandscapeGlobals::CurrentFar0VBAllocator= &_Far0VB;
+00848         CLandscapeGlobals::CurrentFar1VBAllocator= &_Far1VB;
+00849         CLandscapeGlobals::CurrentTileVBAllocator= &_TileVB;
+00850 
+00851         // Must check driver, and create VB infos,locking buffers.
+00852         if(_Driver)
+00853         {
+00854                 _Far0VB.updateDriver(_Driver);
+00855                 _Far1VB.updateDriver(_Driver);
+00856                 _TileVB.updateDriver(_Driver);
+00857 
+00858                 // must do the same for _VegetableManager.
+00859                 if(_DriverOkForVegetable)
+00860                         _VegetableManager->updateDriver(_Driver);
+00861 
+00862                 lockBuffers ();
+00863         }
+00864 }
+00865 
+00866 
+00867 // ***************************************************************************
+00868 void                    CLandscape::lockBuffers ()
+00869 {
+00870         _Far0VB.lockBuffer(CLandscapeGlobals::CurrentFar0VBInfo);
+00871         _Far1VB.lockBuffer(CLandscapeGlobals::CurrentFar1VBInfo);
+00872         _TileVB.lockBuffer(CLandscapeGlobals::CurrentTileVBInfo);
+00873 
+00874         // lock buffer of the vegetable manager.
+00875         _VegetableManager->lockBuffers();
+00876 
+00877         // VertexProgrma mode???
+00878         CLandscapeGlobals::VertexProgramEnabled= _VertexShaderOk;
+00879 }
+00880 
+00881 
+00882 // ***************************************************************************
+00883 void                    CLandscape::unlockBuffers()
+00884 {
+00885         _Far0VB.unlockBuffer();
+00886         _Far1VB.unlockBuffer();
+00887         _TileVB.unlockBuffer();
+00888 
+00889         // unlock buffer of the vegetable manager.
+00890         _VegetableManager->unlockBuffers();
+00891 }
+00892 
+00893 // ***************************************************************************
+00894 void                    CLandscape::synchronizeATIVBHards()
+00895 {
+00896         _Far0VB.synchronizeATIVBHard();
+00897         _Far1VB.synchronizeATIVBHard();
+00898         _TileVB.synchronizeATIVBHard();
+00899 }
+00900 
+00901 // ***************************************************************************
+00902 void                    CLandscape::updateTessBlocksFaceVector()
+00903 {
+00904         // while some tessBlock to update remains.
+00905         CTessBlock      *tb;
+00906         while( (tb=_TessBlockModificationRoot.getNextToModify()) !=NULL )
+00907         {
+00908                 // Get the patch which owns this TessBlock.
+00909                 CPatch  *patch= tb->getPatch();
+00910 
+00911                 // If this patch is visible, recreate faceVector for his tessBlock.
+00912                 patch->recreateTessBlockFaceVector(*tb);
+00913 
+00914                 // remove from list.
+00915                 tb->removeFromModifyList();
+00916         }
+00917 }
+00918 
+00919 
+00920 // ***************************************************************************
+00921 static inline void      initPassTriArray(CPatchRdrPass &pass)
+00922 {
+00923         uint    numIndices= pass.getMaxRenderedFaces()*3;
+00924         // realloc if necessary
+00925         if( CLandscapeGlobals::PassTriArray.size() < numIndices )
+00926                 CLandscapeGlobals::PassTriArray.resize( numIndices );
+00927         // reset ptr.
+00928         NL3D_LandscapeGlobals_PassTriCurPtr= &CLandscapeGlobals::PassTriArray[0];
+00929 }
+00930 
+00931 
+00932 // ***************************************************************************
+00933 static inline void      drawPassTriArray(CMaterial &mat)
+00934 {
+00935         if(NL3D_LandscapeGlobals_PassNTri>0)
+00936         {
+00937                 CLandscapeGlobals::PatchCurrentDriver->setupMaterial(mat);
+00938                 CLandscapeGlobals::PatchCurrentDriver->renderSimpleTriangles(&CLandscapeGlobals::PassTriArray[0], NL3D_LandscapeGlobals_PassNTri);
+00939                 NL3D_LandscapeGlobals_PassNTri= 0;
+00940         }
+00941 }
+00942 
+00943 
+00944 // ***************************************************************************
+00945 void                    CLandscape::render(const CVector &refineCenter, const CVector &frontVector, const CPlane        pyramid[NL3D_TESSBLOCK_NUM_CLIP_PLANE], bool doTileAddPass)
+00946 {
+00947         IDriver *driver= _Driver;
+00948         nlassert(driver);
+00949 
+00950         // Increment the update date for preRender.
+00951         CLandscapeGlobals::CurrentRenderDate++;
+00952 
+00953 
+00954         ItZoneMap       it;
+00955         sint            i;
+00956         ItTileRdrPassSet        itTile;
+00957         ItSPRenderPassSet       itFar;
+00958 
+00959         // Yoyo: profile.
+00960         NL3D_PROFILE_LAND_SET(ProfNRdrFar0, 0);
+00961         NL3D_PROFILE_LAND_SET(ProfNRdrFar1, 0);
+00962         for(i=0;i<NL3D_MAX_TILE_PASS;i++)
+00963         {
+00964                 NL3D_PROFILE_LAND_SET(ProfNRdrTile[i], 0);
+00965         }
+00966 
+00967 
+00968         // -2. Update globals
+00969         //====================
+00970         updateGlobalsAndLockBuffers (refineCenter);
+00971         // NB: render may change vertices in VB in visible patchs => buffers are locked.
+00972 
+00973 
+00974         // -1. clear all PatchRenderPass renderList
+00975         //===================
+00976 
+00977         // Fars.
+00978         for(itFar= _FarRdrPassSet.begin(); itFar!= _FarRdrPassSet.end(); itFar++)
+00979         {
+00980                 CPatchRdrPass   &pass= **itFar;
+00981                 // clear list.
+00982                 pass.clearAllRenderList();
+00983         }
+00984 
+00985         // Tiles.
+00986         for(itTile= TileRdrPassSet.begin(); itTile!= TileRdrPassSet.end(); itTile++)
+00987         {
+00988                 CPatchRdrPass   &pass= const_cast<CPatchRdrPass&>(*itTile);
+00989                 // clear list.
+00990                 pass.clearAllRenderList();
+00991         }
+00992 
+00993         // Lightmaps.
+00994         for(sint lightRdrPass=0; lightRdrPass<(sint)_TextureNears.size(); lightRdrPass++)
+00995         {
+00996                 CPatchRdrPass   &pass= *_TextureNears[lightRdrPass];
+00997                 // clear list.
+00998                 pass.clearAllRenderList();
+00999         }
+01000 
+01001         // 0. preRender pass.
+01002         //===================
+01003 
+01004         // change Far0 / Far1.
+01005         // Clip TessBlocks against pyramid and Far Limit.
+01006         for(i=0; i<NL3D_TESSBLOCK_NUM_CLIP_PLANE; i++)
+01007         {
+01008                 CTessBlock::CurrentPyramid[i]= pyramid[i];
+01009         }
+01010         // Update VB with change of Far0 / Far1.
+01011         for(it= Zones.begin();it!=Zones.end();it++)
+01012         {
+01013                 (*it).second->preRender();
+01014         }
+01015 
+01016 
+01017         // Reallocation Mgt. If any of the VB is reallocated, we must refill it entirely.
+01018         // NB: all VBs are refilled entirely. It is not optimal (maybe 3* too slow), but reallocation are supposed
+01019         // to be very rare.
+01020         if( _Far0VB.reallocationOccurs() || _Far1VB.reallocationOccurs() || _TileVB.reallocationOccurs() )
+01021                 _RenderMustRefillVB= true;
+01022 
+01023         // VertexProgram dependency on RefineThreshold Management. If VertexShader, and if the refineThreshold has
+01024         // changed since the last time, we must refill All the VB, because data are out of date.
+01025         if( _VertexShaderOk && _VPThresholdChange )
+01026         {
+01027                 _VPThresholdChange= false;
+01028                 _RenderMustRefillVB= true;
+01029         }
+01030 
+01031         // If we must refill the VB (for any reason).
+01032         if(_RenderMustRefillVB )
+01033         {
+01034                 // Ok, ok, we refill All the VB with good data.
+01035                 _RenderMustRefillVB= false;
+01036 
+01037                 // First reset the flag, so fillVB() will effectively fill the VB.
+01038                 _Far0VB.resetReallocation();
+01039                 _Far1VB.resetReallocation();
+01040                 _TileVB.resetReallocation();
+01041 
+01042                 // Then recompute good VBInfo (those in CurrentVBInfo are false!!).
+01043                 // Do it by unlocking then re-locking Buffers.
+01044                 unlockBuffers();
+01045                 lockBuffers();
+01046 
+01047                 // Finally, fill the VB for all patchs visible.
+01048                 for(it= Zones.begin();it!=Zones.end();it++)
+01049                 {
+01050                         if((*it).second->ClipResult==CZone::ClipOut)
+01051                                 continue;
+01052                         for(sint i=0;i<(*it).second->getNumPatchs(); i++)
+01053                         {
+01054                                 CPatch  *patch= (*it).second->getPatch(i);
+01055                                 patch->fillVBIfVisible();
+01056                         }
+01057                 }
+01058         }
+01059 
+01060 
+01061         // If software GeoMorph / Alpha Transition (no VertexShader), do it now.
+01062         if(!_VertexShaderOk)
+01063         {
+01064                 // For all patch visible, compute geomoprh and alpha in software.
+01065                 for(it= Zones.begin();it!=Zones.end();it++)
+01066                 {
+01067                         if((*it).second->ClipResult==CZone::ClipOut)
+01068                                 continue;
+01069                         for(sint i=0;i<(*it).second->getNumPatchs(); i++)
+01070                         {
+01071                                 CPatch  *patch= (*it).second->getPatch(i);
+01072                                 // If visible, compute Geomorph And Alpha
+01073                                 patch->computeSoftwareGeomorphAndAlpha();
+01074                         }
+01075                 }
+01076 
+01077                 /*
+01078                         Optim note: here, lot of vertices are 
+01079                                 1/ geomorphed twice (vertices on edges of patchs)
+01080                                 2/ vertices are geomorphed, but not used (because o the Tessblock clip), 
+01081                                         because lot of vertices used by faces in small TessBlocks are still in MasterBlock.
+01082 
+01083                         Some tries have been made to solve this, but result are even worse (2 times or more), because:
+01084                                 1/
+01085                                         - does not really matter edges of patchs (and corner) because the majority is in interior of patch.
+01086                                         - in this case, we need to reset all the flags which is very costly (reparse all zones...) .
+01087                                 2/ Except for the old CTessBlockEdge management which not solve all the thing, the other solution is
+01088                                         to test all faces not clipped (on a per TessBlock basis), to compute only vertices needed.
+01089                                         But in this cases, result are worse, maybe because there is 6 times more tests, and with bad BTB cache.
+01090                 */
+01091         }
+01092 
+01093 
+01094         // Must realase VB Buffers Now!! The VBuffers are now OK!
+01095         // NB: no parallelism is made between 3dCard and Fill of vertices.
+01096         // We Suppose Fill of vertices is rare, and so do not need to be parallelized.
+01097         unlockBuffers();
+01098 
+01099 
+01100         // Special for ATI: only copy all VBs to VBHard one time per frame
+01101         synchronizeATIVBHards();
+01102 
+01103 
+01104         // If VertexShader enabled, setup VertexProgram Constants.
+01105         if(_VertexShaderOk)
+01106         {
+01107                 // c[0..3] take the ModelViewProjection Matrix.
+01108                 driver->setConstantMatrix(0, IDriver::ModelViewProjection, IDriver::Identity);
+01109                 // c[4] take usefull constants.
+01110                 driver->setConstant(4, 0, 1, 0.5f, 0);
+01111                 // c[5] take RefineCenter
+01112                 driver->setConstant(5, refineCenter);
+01113                 // c[6] take info for Geomorph trnasition to TileNear.
+01114                 driver->setConstant(6, CLandscapeGlobals::TileDistFarSqr, CLandscapeGlobals::OOTileDistDeltaSqr, 0, 0);
+01115                 // c[8..11] take the ModelView Matrix.
+01116                 driver->setConstantMatrix(8, IDriver::ModelView, IDriver::Identity);
+01117                 // c[12] take the current landscape Center / delta Pos to apply
+01118                 driver->setConstant(12, _PZBModelPosition);
+01119         }
+01120 
+01121 
+01122         // 1. TileRender pass.
+01123         //====================
+01124 
+01125 
+01126         // First, update Dynamic Lighting for Near, ie multiply Dynamic Lightmap with UserColor, and upload to texture.
+01127         // ==================
+01128         CPatchDLMContext        *dlmCtxPtr= _PatchDLMContextList->begin();
+01129         while(dlmCtxPtr!=NULL)
+01130         {
+01131                 // do it only if the patch has some Near stuff to render, and if it is visible
+01132                 if(dlmCtxPtr->getPatch()->getFar0() == 0
+01133                          && !dlmCtxPtr->getPatch()->isRenderClipped() )
+01134                 {
+01135                         // upload lightmap into textureDLM, modulating before with patch TileColor.
+01136                         // NB: no-op if both src and dst are already full black.
+01137                         dlmCtxPtr->compileLighting(CPatchDLMContext::ModulateTileColor);
+01138                 }
+01139 
+01140                 // next
+01141                 dlmCtxPtr= (CPatchDLMContext*)dlmCtxPtr->Next;
+01142         }
+01143 
+01144 
+01145         // Active VB.
+01146         // ==================
+01147 
+01148         // Active the good VB, and maybe activate the VertexProgram N°0.
+01149         _TileVB.activate(0);
+01150 
+01151 
+01152         // Render.
+01153         // ==================
+01154         // Before any render call. Set the global driver used to render.
+01155         CLandscapeGlobals::PatchCurrentDriver= driver;
+01156 
+01157 
+01158         // Render Order. Must "invert", since initial order is NOT the render order. This is done because the lightmap pass
+01159         // DO NOT have to do any renderTile(), since it is computed in RGB0 pass.
+01160         nlassert(NL3D_MAX_TILE_PASS==5);
+01161         static  sint    RenderOrder[NL3D_MAX_TILE_PASS]= {NL3D_TILE_PASS_RGB0, NL3D_TILE_PASS_RGB1, NL3D_TILE_PASS_RGB2,
+01162                 NL3D_TILE_PASS_LIGHTMAP, NL3D_TILE_PASS_ADD};
+01163         // For ALL pass..
+01164         for(i=0; i<NL3D_MAX_TILE_PASS; i++)
+01165         {
+01166                 sint    passOrder= RenderOrder[i];
+01167 
+01168 
+01169                 // If VertexShader enabled, and if lightmap or post Add pass, must setup good VertexProgram
+01170                 if(_VertexShaderOk)
+01171                 {
+01172                         if(passOrder == NL3D_TILE_PASS_LIGHTMAP)
+01173                         {
+01174                                 // Must activate the vertexProgram to take TexCoord2 to stage0
+01175                                 _TileVB.activate(1);
+01176                         }
+01177                         else if(passOrder == NL3D_TILE_PASS_ADD)
+01178                         {
+01179                                 // Must re-activate the standard VertexProgram
+01180                                 _TileVB.activate(0);
+01181                         }
+01182                 }
+01183 
+01184 
+01185                 // Do add pass???
+01186                 if((passOrder==NL3D_TILE_PASS_ADD) && !doTileAddPass)
+01187                         continue;
+01188 
+01189 
+01190                 // Setup common material for this pass.
+01191                 //=============================
+01192                 // Default: Replace envmode.
+01193                 TileMaterial.texEnvOpRGB(0, CMaterial::Replace);
+01194                 TileMaterial.texEnvArg0RGB(0, CMaterial::Texture, CMaterial::SrcColor);
+01195                 TileMaterial.texEnvOpAlpha(0, CMaterial::Replace);
+01196                 TileMaterial.texEnvArg0Alpha(0, CMaterial::Texture, CMaterial::SrcAlpha);
+01197                 // NB: important to set Replace and not modulate, because in case of VerexProgram enabled, 
+01198                 // Diffuse o[COL0] is undefined.
+01199 
+01200                 // Copy from stage 0 to stage 1.
+01201                 TileMaterial.setTexEnvMode(1, TileMaterial.getTexEnvMode(0));
+01202 
+01203                 // setup multitex / blending.
+01204                 if(passOrder==NL3D_TILE_PASS_RGB0)
+01205                 {
+01206                         // first pass, no blend.
+01207                         TileMaterial.setBlend(false);
+01208                 }
+01209                 else
+01210                 {
+01211                         TileMaterial.setBlend(true);
+01212                         switch(passOrder)
+01213                         {
+01214                                 case NL3D_TILE_PASS_RGB1: 
+01215                                 case NL3D_TILE_PASS_RGB2: 
+01216                                         // alpha blending.
+01217                                         TileMaterial.setBlendFunc(CMaterial::srcalpha, CMaterial::invsrcalpha);
+01218 
+01219                                         // Must use a special envmode for stage1: "separateAlpha"!!.
+01220                                         // keep the color from previous stage.
+01221                                         TileMaterial.texEnvOpRGB(1, CMaterial::Replace);
+01222                                         TileMaterial.texEnvArg0RGB(1, CMaterial::Previous, CMaterial::SrcColor);
+01223                                         // take the alpha from current stage.
+01224                                         TileMaterial.texEnvOpAlpha(1, CMaterial::Replace);
+01225                                         TileMaterial.texEnvArg0Alpha(1, CMaterial::Texture, CMaterial::SrcAlpha);
+01226                                         break;
+01227                                 case NL3D_TILE_PASS_LIGHTMAP: 
+01228                                         // modulate alpha blending.
+01229                                         TileMaterial.setBlendFunc(CMaterial::zero, CMaterial::srccolor);
+01230 
+01231                                         // Setup the material envCombine so DynamicLightmap (stage 0) is added to static lightmap.
+01232                                         TileMaterial.texEnvOpRGB(1, CMaterial::Add);
+01233                                         TileMaterial.texEnvArg0RGB(1, CMaterial::Texture, CMaterial::SrcColor);
+01234                                         TileMaterial.texEnvArg1RGB(1, CMaterial::Previous, CMaterial::SrcColor);
+01235 
+01236                                         break;
+01237                                 case NL3D_TILE_PASS_ADD: 
+01238                                         // Use srcalpha for src (and not ONE), since additive are blended with alpha Cte/AlphaTexture
+01239                                         TileMaterial.setBlendFunc(CMaterial::srcalpha, CMaterial::one);
+01240 
+01241                                         // for MAYBE LATER smooth night transition, setup Alpha cte of stage0, and setup alpha stage.
+01242                                         TileMaterial.texEnvOpAlpha(0, CMaterial::Replace);
+01243                                         TileMaterial.texEnvArg0Alpha(0, CMaterial::Constant, CMaterial::SrcAlpha);
+01244                                         // Temp, just setup alpha to 1.
+01245                                         TileMaterial.texConstantColor(0, CRGBA(255, 255, 255, 255));
+01246 
+01247                                         // Must use a special envmode for stage1: "separateAlpha"!!.
+01248                                         // NB: it still works if The RdrPass has no texture.
+01249                                         // keep the color from previous stage.
+01250                                         TileMaterial.texEnvOpRGB(1, CMaterial::Replace);
+01251                                         TileMaterial.texEnvArg0RGB(1, CMaterial::Previous, CMaterial::SrcColor);
+01252                                         // modulate the alpha of current stage with previous
+01253                                         TileMaterial.texEnvOpAlpha(1, CMaterial::Modulate);
+01254                                         TileMaterial.texEnvArg0Alpha(1, CMaterial::Texture, CMaterial::SrcAlpha);
+01255                                         TileMaterial.texEnvArg1Alpha(1, CMaterial::Previous, CMaterial::SrcAlpha);
+01256 
+01257                                         break;
+01258                                 default: 
+01259                                         nlstop;
+01260                         };
+01261                 }
+01262                 // Reset the textures (so there is none in Addtive pass or in Lightmap).
+01263                 TileMaterial.setTexture(0, NULL);
+01264                 TileMaterial.setTexture(1, NULL);
+01265                 TileMaterial.setTexture(2, NULL);
+01266 
+01267 
+01268                 // Render All material RdrPass.
+01269                 //=============================
+01270                 // Special code for Lightmap and RGB0, for faster render.
+01271                 if(passOrder==NL3D_TILE_PASS_RGB0)
+01272                 {
+01273                         // RGB0 pass.
+01274                         ItTileRdrPassSet        itTile;
+01275                         for(itTile= TileRdrPassSet.begin(); itTile!= TileRdrPassSet.end(); itTile++)
+01276                         {
+01277                                 // Get a ref on the render pass. Const cast work because we only modify attribut from CPatchRdrPass 
+01278                                 // that don't affect the operator< of this class
+01279                                 CPatchRdrPass   &pass= const_cast<CPatchRdrPass&>(*itTile);
+01280 
+01281                                 // Enlarge PassTriArray as needed
+01282                                 initPassTriArray(pass);
+01283 
+01284                                 // Setup Diffuse texture of the tile.
+01285                                 TileMaterial.setTexture(0, pass.TextureDiffuse);
+01286 
+01287                                 // Add triangles to array
+01288                                 CRdrTileId              *tileToRdr= pass.getRdrTileRoot(passOrder);
+01289                                 while(tileToRdr)
+01290                                 {
+01291                                         // renderSimpleTriangles() with the material setuped.
+01292                                         tileToRdr->TileMaterial->renderTilePassRGB0();
+01293                                         tileToRdr= (CRdrTileId*)tileToRdr->getNext();
+01294                                 }
+01295                                 // Render triangles.
+01296                                 drawPassTriArray(TileMaterial);
+01297                         }
+01298                 }
+01299                 else if(passOrder==NL3D_TILE_PASS_LIGHTMAP)
+01300                 {
+01301                         // Lightmap Pass.
+01302                         /* \todo yoyo: TODO_CLOUD: setup stage2, and setup texcoord generation. COMPLEX because of interaction
+01303                          with Dynamic LightMap
+01304                         */
+01305 
+01306                         // Setup the Dynamic Lightmap into stage 0.
+01307                         TileMaterial.setTexture(0, _TextureDLM);
+01308 
+01309                         // if vertex shader not used.
+01310                         if(!_VertexShaderOk)
+01311                         {
+01312                                 // special setup  such that stage0 takes Uv2.
+01313                                 driver->mapTextureStageToUV(0, 2);
+01314                         }
+01315                         // else VertexProgram map itself the good vertex Attribute to UV0.
+01316 
+01317 
+01318                         // Render All the lightmaps.
+01319                         for(sint lightRdrPass=0; lightRdrPass<(sint)_TextureNears.size(); lightRdrPass++)
+01320                         {
+01321                                 CPatchRdrPass   &pass= *_TextureNears[lightRdrPass];
+01322 
+01323                                 // Enlarge PassTriArray as needed
+01324                                 initPassTriArray(pass);
+01325 
+01326                                 // Setup Lightmap into stage1. Because we share UV with pass RGB0. So we use UV1.
+01327                                 // Also, now stage0 is used for DynamicLightmap
+01328                                 TileMaterial.setTexture(1, pass.TextureDiffuse);
+01329 
+01330                                 // Add triangles to array
+01331                                 CRdrTileId              *tileToRdr= pass.getRdrTileRoot(passOrder);
+01332                                 while(tileToRdr)
+01333                                 {
+01334                                         // renderSimpleTriangles() with the material setuped.
+01335                                         tileToRdr->TileMaterial->renderTilePassLightmap();
+01336                                         tileToRdr= (CRdrTileId*)tileToRdr->getNext();
+01337                                 }
+01338                                 // Render triangles.
+01339                                 drawPassTriArray(TileMaterial);
+01340                         }
+01341 
+01342                         // if vertex shader not used.
+01343                         if(!_VertexShaderOk)
+01344                         {
+01345                                 // Reset special stage/UV setup to normal behavior
+01346                                 driver->mapTextureStageToUV(0, 0);
+01347                         }
+01348                 }
+01349                 else
+01350                 {
+01351                         // RGB1, RGB2, and ADD pass.
+01352 
+01353                         // Render Base, Transitions or Additives.
+01354 
+01355                         ItTileRdrPassSet        itTile;
+01356                         for(itTile= TileRdrPassSet.begin(); itTile!= TileRdrPassSet.end(); itTile++)
+01357                         {
+01358                                 // Get a ref on the render pass. Const cast work because we only modify attribut from CPatchRdrPass 
+01359                                 // that don't affect the operator< of this class
+01360                                 CPatchRdrPass   &pass= const_cast<CPatchRdrPass&>(*itTile);
+01361 
+01362                                 // Enlarge PassTriArray as needed
+01363                                 initPassTriArray(pass);
+01364 
+01365                                 // Add triangles to array
+01366                                 CRdrTileId              *tileToRdr= pass.getRdrTileRoot(passOrder);
+01367                                 while(tileToRdr)
+01368                                 {
+01369                                         // renderSimpleTriangles() with the material setuped.
+01370                                         tileToRdr->TileMaterial->renderTile(passOrder);
+01371                                         tileToRdr= (CRdrTileId*)tileToRdr->getNext();
+01372                                 }
+01373 
+01374                                 // Pass not empty ?
+01375                                 if(NL3D_LandscapeGlobals_PassNTri>0)
+01376                                 {
+01377                                         // Setup material.
+01378                                         // Setup Diffuse texture of the tile.
+01379                                         TileMaterial.setTexture(0, pass.TextureDiffuse);
+01380                                         
+01381                                         // If transition tile, must enable the alpha for this pass.
+01382                                         // NB: Additive pass may have pass.TextureAlpha==NULL
+01383                                         TileMaterial.setTexture(1, pass.TextureAlpha);
+01384                                 }
+01385 
+01386                                 // Render triangles.
+01387                                 drawPassTriArray(TileMaterial);
+01388                         }
+01389                 }
+01390         }
+01391 
+01392 
+01393         // 2. Far0Render pass.
+01394         //====================
+01395 
+01396 
+01397         // First, update Dynamic Lighting for Far, ie multiply Dynamic Lightmap with TextureFar, and upload to texture.
+01398         // ==================
+01399         dlmCtxPtr= _PatchDLMContextList->begin();
+01400         while(dlmCtxPtr!=NULL)
+01401         {
+01402                 // do it only if the patch has some Far stuff to render, and if it is visible
+01403                 if( (dlmCtxPtr->getPatch()->getFar0()>0 || dlmCtxPtr->getPatch()->getFar1()>0)
+01404                          && !dlmCtxPtr->getPatch()->isRenderClipped() )
+01405                 {
+01406                         // upload lightmap into textureDLM, modulating before with patch TextureFar.
+01407                         // NB: no-op if both src and dst are already full black.
+01408                         dlmCtxPtr->compileLighting(CPatchDLMContext::ModulateTextureFar);
+01409                 }
+01410 
+01411                 // next
+01412                 dlmCtxPtr= (CPatchDLMContext*)dlmCtxPtr->Next;
+01413         }
+01414 
+01415 
+01416         // Active VB.
+01417         // ==================
+01418 
+01419         // Active the good VB, and maybe activate the std VertexProgram.
+01420         _Far0VB.activate(0);
+01421 
+01422 
+01423         // Render.
+01424         // ==================
+01425 
+01426         // Setup common material.
+01427         FarMaterial.setBlend(false);
+01428         // set the DLM texture.
+01429         FarMaterial.setTexture(1, _TextureDLM);
+01430 
+01431         // Render All material RdrPass0.
+01432         itFar=_FarRdrPassSet.begin();
+01433         while (itFar!=_FarRdrPassSet.end())
+01434         {
+01435                 CPatchRdrPass   &pass= **itFar;
+01436 
+01437                 // Enlarge PassTriArray as needed
+01438                 initPassTriArray(pass);
+01439 
+01440                 // Setup the material.
+01441                 FarMaterial.setTexture(0, pass.TextureDiffuse);
+01442                 // If the texture need to be updated, do it now.
+01443                 if(pass.TextureDiffuse && pass.TextureDiffuse->touched())
+01444                         driver->setupTexture(*pass.TextureDiffuse);
+01445 
+01446                 // Add triangles to array
+01447                 CRdrPatchId             *patchToRdr= pass.getRdrPatchFar0();
+01448                 while(patchToRdr)
+01449                 {
+01450                         // renderSimpleTriangles() with the material setuped.
+01451                         patchToRdr->Patch->renderFar0();
+01452                         patchToRdr= (CRdrPatchId*)patchToRdr->getNext();
+01453                 }
+01454                 // Render triangles.
+01455                 drawPassTriArray(FarMaterial);
+01456 
+01457                 // Next render pass
+01458                 itFar++;
+01459         }
+01460 
+01461 
+01462 
+01463         // 3. Far1Render pass.
+01464         //====================
+01465 
+01466         // Active VB.
+01467         // ==================
+01468 
+01469         // Active the good VB, and maybe activate the std VertexProgram.
+01470         _Far1VB.activate(0);
+01471 
+01472 
+01473         // Render
+01474         // ==================
+01475 
+01476         // Setup common material.
+01477         FarMaterial.setBlend(true);
+01478         // set the DLM texture.
+01479         FarMaterial.setTexture(1, _TextureDLM);
+01480 
+01481 
+01482         // Render All material RdrPass1.
+01483         itFar=_FarRdrPassSet.begin();
+01484         while (itFar!=_FarRdrPassSet.end())
+01485         {
+01486                 CPatchRdrPass   &pass= **itFar;
+01487 
+01488                 // Enlarge PassTriArray as needed
+01489                 initPassTriArray(pass);
+01490 
+01491                 // Setup the material.
+01492                 FarMaterial.setTexture(0, pass.TextureDiffuse);
+01493                 // If the texture need to be updated, do it now.
+01494                 if(pass.TextureDiffuse && pass.TextureDiffuse->touched())
+01495                         driver->setupTexture(*pass.TextureDiffuse);
+01496 
+01497                 // Add triangles to array
+01498                 CRdrPatchId             *patchToRdr= pass.getRdrPatchFar1();
+01499                 while(patchToRdr)
+01500                 {
+01501                         // renderSimpleTriangles() with the material setuped.
+01502                         patchToRdr->Patch->renderFar1();
+01503                         patchToRdr= (CRdrPatchId*)patchToRdr->getNext();
+01504                 }
+01505                 // Render triangles.
+01506                 drawPassTriArray(FarMaterial);
+01507 
+01508                 // Next render pass
+01509                 itFar++;
+01510         }
+01511 
+01512 
+01513         // 4. "Release" texture materials.
+01514         //================================
+01515         FarMaterial.setTexture(0, NULL);
+01516         FarMaterial.setTexture(1, NULL);
+01517         FarMaterial.setTexture(2, NULL);
+01518         FarMaterial.setTexture(3, NULL);
+01519         TileMaterial.setTexture(0, NULL);
+01520         TileMaterial.setTexture(1, NULL);
+01521         TileMaterial.setTexture(2, NULL);
+01522         TileMaterial.setTexture(3, NULL);
+01523 
+01524         // To ensure no use but in render()..
+01525         CLandscapeGlobals::PatchCurrentDriver= NULL;
+01526 
+01527         // Desactive the vertex program (if anyone)
+01528         if(_VertexShaderOk)
+01529                 driver->activeVertexProgram (NULL);
+01530 
+01531 
+01532         // 5. Vegetable Management.
+01533         //================================
+01534 
+01535         // First, update Dynamic Lighting for Vegetable, ie just copy.
+01536         // ==================
+01537         if(isVegetableActive())
+01538         {
+01539                 /* Actually we modulate the DLM with an arbitrary constant for this reason:
+01540                         Color of vegetable (ie their material) are NOT modulated with DLM.
+01541                         Doing this without using PixelShader / additional UVs seems to be impossible.
+01542                         And add new UVs (+700K in AGP) just for this is not worth the effort.
+01543 
+01544                         We prefer using a constant to simulate the "global vegetable color", which is a big trick.
+01545 
+01546                         Additionally, the vegetable take the diffuse lighting of landscape, which is
+01547                         false because it replaces the diffuse lighting it should have (ie with his own Normal and 
+01548                         his own "global vegetable color")
+01549 
+01550                         We can't do anything for "correct normal vegetable", but it is possible to replace landscape
+01551                         material with vegetable material, by dividing _DLMGlobalVegetableColor by LandscapeDiffuseMaterial.
+01552                         This is a very approximate result because of CRGBA clamp, but it is acceptable.
+01553                 */
+01554                 CRGBA   vegetDLMCte;
+01555                 // the constant is _DLMGlobalVegetableColor / PointLightDiffuseMaterial
+01556                 uint    v;
+01557                 v= (_DLMGlobalVegetableColor.R*256) / (_PointLightDiffuseMaterial.R+1);
+01558                 vegetDLMCte.R= (uint8)min(v, 255U);
+01559                 v= (_DLMGlobalVegetableColor.G*256) / (_PointLightDiffuseMaterial.G+1);
+01560                 vegetDLMCte.G= (uint8)min(v, 255U);
+01561                 v= (_DLMGlobalVegetableColor.B*256) / (_PointLightDiffuseMaterial.B+1);
+01562                 vegetDLMCte.B= (uint8)min(v, 255U);
+01563 
+01564                 // Parse all patch which have some vegetables
+01565                 dlmCtxPtr= _PatchDLMContextList->begin();
+01566                 while(dlmCtxPtr!=NULL)
+01567                 {
+01568                         // do it only if the patch has some vegetable stuff to render, and if it is visible
+01569                         // NB: we may have some vegetable stuff to render if the patch has some TileMaterial created.
+01570                         if(dlmCtxPtr->getPatch()->getTileMaterialRefCount()>0
+01571                                  && !dlmCtxPtr->getPatch()->isRenderClipped() )
+01572                         {
+01573                                 // NB: no-op if both src and dst are already full black.
+01574                                 dlmCtxPtr->compileLighting(CPatchDLMContext::ModulateConstant, vegetDLMCte);
+01575                         }
+01576 
+01577                         // next
+01578                         dlmCtxPtr= (CPatchDLMContext*)dlmCtxPtr->Next;
+01579                 }
+01580         }
+01581 
+01582 
+01583         // profile.
+01584         _VegetableManager->resetNumVegetableFaceRendered();
+01585 
+01586         // render all vegetables, only if driver support VertexProgram.
+01587         // ==================
+01588         if(isVegetableActive())
+01589         {
+01590                 // Use same plane as TessBlock for faster clipping.
+01591                 vector<CPlane>          vegetablePyramid;
+01592                 vegetablePyramid.resize(NL3D_TESSBLOCK_NUM_CLIP_PLANE);
+01593                 for(i=0;i<NL3D_TESSBLOCK_NUM_CLIP_PLANE;i++)
+01594                 {
+01595                         vegetablePyramid[i]= pyramid[i];
+01596                 }
+01597                 _VegetableManager->render(refineCenter, frontVector, vegetablePyramid, _TextureDLM, driver);
+01598         }
+01599 
+01600 }
+01601 
+01602 
+01603 // ***************************************************************************
+01604 // ***************************************************************************
+01605 // Tile mgt.
+01606 // ***************************************************************************
+01607 // ***************************************************************************
+01608 
+01609 
+01610 // ***************************************************************************
+01611 ITexture                *CLandscape::findTileTexture(const std::string &textName)
+01612 {
+01613         ITexture        *text;
+01614         text= TileTextureMap[textName];
+01615         // If just inserted, RefPtr is NULL!!  :)
+01616         // This test too if the RefPtr is NULL... (tile released)
+01617         // The object is not owned by this map. It will be own by the multiple RdrPass via CSmartPtr.
+01618         // They will destroy it when no more points to them.
+01619         if(!text)
+01620         {
+01621                 TileTextureMap[textName]= text= new CTextureFile(textName);
+01622                 text->setWrapS(ITexture::Clamp);
+01623                 text->setWrapT(ITexture::Clamp);
+01624                 text->setUploadFormat(ITexture::DXTC5);
+01625         }
+01626         return text;
+01627 }
+01628 
+01629 
+01630 // ***************************************************************************
+01631 CPatchRdrPass   *CLandscape::findTileRdrPass(const CPatchRdrPass &pass)
+01632 {
+01633         ItTileRdrPassSet        it;
+01634         // If already here, find it, else insert.
+01635         it= (TileRdrPassSet.insert(pass)).first;
+01636 
+01637         return const_cast<CPatchRdrPass*>(&(*it));
+01638 }
+01639 
+01640 
+01641 // ***************************************************************************
+01642 void                    CLandscape::loadTile(uint16 tileId)
+01643 {
+01644         CTile           *tile;
+01645         CTileInfo       *tileInfo;
+01646         string          textName;
+01647 
+01648         // Retrieve or create texture.
+01649         // ===========================
+01650         // Tile Must exist.
+01651         // nlassert(tileId==0xFFFF || tileId<TileBank.getTileCount());
+01652         if(tileId<TileBank.getTileCount())
+01653                 tile= TileBank.getTile(tileId);
+01654         else
+01655                 tile= NULL;
+01656         // TileInfo must not exist.
+01657         nlassert(TileInfos[tileId]==NULL);
+01658         TileInfos[tileId]= tileInfo= new CTileInfo;
+01659 
+01660         // Fill additive part.
+01661         // ===================
+01662         if(tile)
+01663                 textName= tile->getRelativeFileName(CTile::additive);
+01664         else
+01665                 textName= "";
+01666         // If no additive for this tile, rdrpass is NULL.
+01667         if(textName=="")
+01668                 tileInfo->AdditiveRdrPass= NULL;
+01669         else
+01670         {
+01671                 // Fill rdrpass.
+01672                 CPatchRdrPass   pass;
+01673                 pass.TextureDiffuse= findTileTexture(TileBank.getAbsPath()+textName);
+01674 
+01675                 // We may have an alpha part for additive.
+01676                 textName= tile->getRelativeFileName (CTile::alpha);
+01677                 if(textName!="")
+01678                         pass.TextureAlpha= findTileTexture(TileBank.getAbsPath()+textName);
+01679 
+01680                 // Fill tileInfo.
+01681                 tileInfo->AdditiveRdrPass= findTileRdrPass(pass);
+01682                 // Fill UV Info.
+01683                 // NB: for now, One Tile== One Texture, so UVScaleBias is simple.
+01684                 tileInfo->AdditiveUvScaleBias.x= 0;
+01685                 tileInfo->AdditiveUvScaleBias.y= 0;
+01686                 tileInfo->AdditiveUvScaleBias.z= 1;
+01687         }
+01688 
+01689 
+01690         // Fill diffuse part.
+01691         // =======================
+01692         // Fill rdrpass.
+01693         CPatchRdrPass   pass;
+01694         // The diffuse part for a tile is inevitable.
+01695         if(tile)
+01696         {
+01697                 textName= tile->getRelativeFileName(CTile::diffuse);
+01698                 if(textName!="")
+01699                         pass.TextureDiffuse= findTileTexture(TileBank.getAbsPath()+textName);
+01700                 else
+01701                 {
+01702                         pass.TextureDiffuse= new CTextureCross;
+01703                         nldebug("Missing Tile diffuse texname: %d", tileId);
+01704                 }
+01705         }
+01706         else
+01707                 pass.TextureDiffuse= new CTextureCross;
+01708         if(tile)
+01709         {
+01710                 textName= tile->getRelativeFileName (CTile::alpha);
+01711                 if(textName!="")
+01712                         pass.TextureAlpha= findTileTexture(TileBank.getAbsPath()+textName);
+01713         }
+01714 
+01715 
+01716         // Fill tileInfo.
+01717         tileInfo->DiffuseRdrPass= findTileRdrPass(pass);
+01718         // Fill UV Info.
+01719         // NB: for now, One Tile== One Texture, so UVScaleBias is simple.
+01720         tileInfo->DiffuseUvScaleBias.x= 0;
+01721         tileInfo->DiffuseUvScaleBias.y= 0;
+01722         tileInfo->DiffuseUvScaleBias.z= 1;
+01723         tileInfo->AlphaUvScaleBias.x= 0;
+01724         tileInfo->AlphaUvScaleBias.y= 0;
+01725         tileInfo->AlphaUvScaleBias.z= 1;
+01726         // Retrieve the good rot alpha decal.
+01727         if(tile)
+01728                 tileInfo->RotAlpha= tile->getRotAlpha();
+01729         else
+01730                 tileInfo->RotAlpha= 0;
+01731 
+01732 
+01733         // Increment RefCount of RenderPart.
+01734         // =================================
+01735         if(tileInfo->AdditiveRdrPass)
+01736                 tileInfo->AdditiveRdrPass->RefCount++;
+01737         if(tileInfo->DiffuseRdrPass)
+01738                 tileInfo->DiffuseRdrPass->RefCount++;
+01739 
+01740 }
+01741 
+01742 
+01743 // ***************************************************************************
+01744 void                    CLandscape::releaseTile(uint16 tileId)
+01745 {
+01746         CTileInfo       *tileInfo;
+01747         tileInfo= TileInfos[tileId];
+01748         nlassert(tileInfo!=NULL);
+01749 
+01750         // "Release" the rdr pass.
+01751         if(tileInfo->AdditiveRdrPass)
+01752                 tileInfo->AdditiveRdrPass->RefCount--;
+01753         if(tileInfo->DiffuseRdrPass)
+01754                 tileInfo->DiffuseRdrPass->RefCount--;
+01755 
+01756         delete tileInfo;
+01757         TileInfos[tileId]= NULL;
+01758 }
+01759 
+01760 
+01761 // ***************************************************************************
+01762 CPatchRdrPass   *CLandscape::getTileRenderPass(uint16 tileId, bool additiveRdrPass)
+01763 {
+01764         CTileInfo       *tile= TileInfos[tileId];
+01765 
+01766         // If not here, create it.
+01767         //========================
+01768         if(tile==NULL)
+01769         {
+01770                 // Force loading of tile.
+01771                 loadTile(tileId);
+01772 
+01773                 tile= TileInfos[tileId];
+01774                 nlassert(tile!=NULL);
+01775         }
+01776 
+01777         // Retrieve.
+01778         //========================
+01779         if(additiveRdrPass)
+01780         {
+01781                 // NB: additive pass is not lighted by the lightmap, so there is no lighted version of this rednerpass.
+01782                 return tile->AdditiveRdrPass;
+01783         }
+01784         else
+01785         {
+01786                 return tile->DiffuseRdrPass;
+01787         }
+01788 }
+01789 
+01790 
+01791 // ***************************************************************************
+01792 void                    CLandscape::getTileUvScaleBiasRot(uint16 tileId, CTile::TBitmap bitmapType, CVector &uvScaleBias, uint8 &rotAlpha)
+01793 {
+01794         CTileInfo       *tile= TileInfos[tileId];
+01795         // tile should not be NULL.
+01796         // Because load of tiles are always done in getTileRenderPass(), and this insertion always succeed.
+01797         nlassert(tile);
+01798 
+01799         rotAlpha= 0;
+01800         switch(bitmapType)
+01801         {
+01802                 case CTile::diffuse:
+01803                         uvScaleBias= tile->DiffuseUvScaleBias; break;
+01804                 case CTile::additive:
+01805                         uvScaleBias= tile->AdditiveUvScaleBias; break;
+01806                 case CTile::alpha:
+01807                         uvScaleBias= tile->AlphaUvScaleBias; 
+01808                         rotAlpha= tile->RotAlpha;
+01809                         break;
+01810                 default: break;
+01811         }
+01812 }
+01813 
+01814 
+01815 // ***************************************************************************
+01816 NLMISC::CSmartPtr<ITexture>             CLandscape::getTileTexture(uint16 tileId, CTile::TBitmap bitmapType, CVector &uvScaleBias)
+01817 {
+01818         CPatchRdrPass   *pass;
+01819         if(bitmapType== CTile::additive)
+01820                 pass= getTileRenderPass(tileId, true);
+01821         else
+01822                 pass= getTileRenderPass(tileId, false);
+01823         if(!pass)
+01824                 return NULL;
+01825         uint8   dummy;
+01826         getTileUvScaleBiasRot(tileId, bitmapType, uvScaleBias, dummy);
+01827 
+01828         // return the wanted texture.
+01829         if(bitmapType==CTile::diffuse || bitmapType==CTile::additive)
+01830                 return pass->TextureDiffuse;
+01831         else
+01832                 return pass->TextureAlpha;
+01833 }
+01834 
+01835 
+01836 // ***************************************************************************
+01837 CTileElement *CLandscape::getTileElement(const CPatchIdent &patchId, const CUV &uv)
+01838 {
+01839         // \todo yoyo: TODO_ZONEID: change ZoneId in 32 bits...
+01840         std::map<uint16, CZone*>::const_iterator        it= Zones.find((uint16)patchId.ZoneId);
+01841         if(it!=Zones.end())
+01842         {
+01843                 sint    N= (*it).second->getNumPatchs();
+01844                 // patch must exist in the zone.
+01845                 nlassert(patchId.PatchId<N);
+01846                 CPatch  *pa= const_cast<CZone*>((*it).second)->getPatch(patchId.PatchId);
+01847                 return pa->getTileElement (uv);
+01848         }
+01849         else
+01850                 // Return not found
+01851                 return NULL;
+01852 }
+01853 
+01854 
+01855 // ***************************************************************************
+01856 void                    CLandscape::flushTiles(IDriver *drv, uint16 tileStart, uint16 nbTiles)
+01857 {
+01858         // Load tile rdrpass, force setup the texture.
+01859         for(sint tileId= tileStart; tileId<tileStart+nbTiles; tileId++)
+01860         {
+01861                 CTileInfo       *tile= TileInfos[tileId];
+01862                 if(tile==NULL)
+01863                 {
+01864                         loadTile(tileId);
+01865                 }
+01866         }
+01867 
+01868         // For all rdrpass, force setup the texture.
+01869         ItTileRdrPassSet        it;
+01870         for(it= TileRdrPassSet.begin(); it!=TileRdrPassSet.end(); it++)
+01871         {
+01872                 const CPatchRdrPass     &pass= *it;
+01873                 // If present and not already setuped...
+01874                 if(pass.TextureDiffuse && !pass.TextureDiffuse->setupedIntoDriver())
+01875                         drv->setupTexture(*pass.TextureDiffuse);
+01876                 // If present and not already setuped...
+01877                 if(pass.TextureAlpha && !pass.TextureAlpha->setupedIntoDriver())
+01878                         drv->setupTexture(*pass.TextureAlpha);
+01879         }
+01880 }
+01881 
+01882 
+01883 // ***************************************************************************
+01884 void                    CLandscape::releaseTiles(uint16 tileStart, uint16 nbTiles)
+01885 {
+01886         // release tiles.
+01887         for(sint tileId= tileStart; tileId<tileStart+nbTiles; tileId++)
+01888         {
+01889                 CTileInfo       *tile= TileInfos[tileId];
+01890                 if(tile!=NULL)
+01891                 {
+01892                         releaseTile(tileId);
+01893                 }
+01894         }
+01895 
+01896         // For all rdrpass, release one that are no more referenced.
+01897         ItTileRdrPassSet        it;
+01898         for(it= TileRdrPassSet.begin(); it!=TileRdrPassSet.end();)
+01899         {
+01900                 // If no more tile access the rdrpass, delete it.
+01901                 if((*it).RefCount==0)
+01902                 {
+01903                         ItTileRdrPassSet itDel=it++;
+01904                         TileRdrPassSet.erase(itDel);
+01905                 }
+01906                 else
+01907                         it++;
+01908         }
+01909 
+01910         // Textures are automaticly deleted by smartptr, but not their entry int the map (TileTextureMap). 
+01911         // => doesn't matter since findTileTexture() manages this case.
+01912         // And the memory overhead is not a problem (we talk about pointers).
+01913 }
+01914 
+01915 
+01916 // ***************************************************************************
+01917 uint            CLandscape::getTileLightMap(CRGBA  map[NL_TILE_LIGHTMAP_SIZE*NL_TILE_LIGHTMAP_SIZE], CPatchRdrPass *&lightmapRdrPass)
+01918 {
+01919         sint    textNum;
+01920         uint    lightMapId;
+01921         /* 
+01922                 NB: TextureNear are a grow only Array... TextureNear are never deleted. Why? :
+01923                 2/ Unused near texture may be uncahced by opengl (and maybe by windows, to disk).
+01924 
+01925           (old reason, no longer valid, since lightmaps are unlinked from tiles.
+01926                 1/ There is an important issue with releasing texture nears: tiles may acces them (see getTileRenderPass())
+01927           )
+01928         */
+01929         // 0. Alloc Near Texture if necessary.
+01930         //====================================
+01931         if(_NFreeLightMaps==0)
+01932         {
+01933                 CTextureNear    *text= new CTextureNear(TextureNearSize);
+01934                 TSPRenderPass   newPass= new CPatchRdrPass;
+01935 
+01936                 newPass->TextureDiffuse= text;
+01937 
+01938                 _TextureNears.push_back(newPass);
+01939                 _NFreeLightMaps+= text->getNbAvailableTiles();
+01940         }
+01941 
+01942         // 1. Search the first texture which has a free tile.
+01943         //==================================================
+01944         CTextureNear    *nearText= NULL;
+01945         CPatchRdrPass   *nearRdrPass= NULL;
+01946         for(textNum=0;textNum<(sint)_TextureNears.size();textNum++)
+01947         {
+01948                 nearRdrPass= _TextureNears[textNum];
+01949                 nearText= (CTextureNear*)(ITexture*)nearRdrPass->TextureDiffuse;
+01950                 if(nearText->getNbAvailableTiles()!=0)
+01951                         break;
+01952         }
+01953         nlassert(textNum<(sint)_TextureNears.size());
+01954         // A empty space has been found.
+01955         _NFreeLightMaps--;
+01956 
+01957         // 2. Fill the texture with the data, and updaterect.
+01958         //===================================================
+01959         lightMapId= nearText->getTileAndFillRect(map);
+01960         // Compute the Id.
+01961         lightMapId= textNum*NbTileLightMapByTexture + lightMapId;
+01962 
+01963 
+01964         // 3. updateLighting
+01965         //===================================================
+01966         // Increment number of pixels to update for near.
+01967         _ULTotalNearPixels+= NL_TILE_LIGHTMAP_SIZE*NL_TILE_LIGHTMAP_SIZE;
+01968 
+01969 
+01970         // Result:
+01971         lightmapRdrPass= nearRdrPass;
+01972         return lightMapId;
+01973 }
+01974 // ***************************************************************************
+01975 void            CLandscape::getTileLightMapUvInfo(uint tileLightMapId, CVector &uvScaleBias)
+01976 {
+01977         uint    id, s,t;
+01978 
+01979         // Scale.
+01980         static const float      scale10= (float)NL_TILE_LIGHTMAP_SIZE/TextureNearSize;
+01981         static const float      scale4= 4.f/TextureNearSize;
+01982         static const float      scale1= 1.f/TextureNearSize;
+01983         // The size of a minilightmap, mapped onto the polygon, is still 4 pixels.
+01984         uvScaleBias.z= scale4;
+01985 
+01986         // Get the id local in the texture.
+01987         id= tileLightMapId%NbTileLightMapByTexture;
+01988 
+01989         // Commpute UVBias.
+01990         // Get the coordinate of the tile, in tile number.
+01991         s= id%NbTileLightMapByLine;
+01992         t= id/NbTileLightMapByLine;
+01993         // But the real size of a minilightmap is 10 pixels, and we must reach the pixel 1,1.
+01994         uvScaleBias.x= s*scale10 + scale1;
+01995         uvScaleBias.y= t*scale10 + scale1;
+01996 }
+01997 // ***************************************************************************
+01998 void            CLandscape::releaseTileLightMap(uint tileLightMapId)
+01999 {
+02000         uint    id, textNum;
+02001 
+02002         // Get the id local in the texture.
+02003         textNum= tileLightMapId / NbTileLightMapByTexture;
+02004         id= tileLightMapId % NbTileLightMapByTexture;
+02005         nlassert(textNum>=0 && textNum<_TextureNears.size());
+02006 
+02007         // Release the tile in this texture.
+02008         CPatchRdrPass   *nearRdrPass= _TextureNears[textNum];
+02009         CTextureNear    *nearText= (CTextureNear*)(ITexture*)nearRdrPass->TextureDiffuse;
+02010         nearText->releaseTile(id);
+02011         _NFreeLightMaps++;
+02012 
+02013         // updateLighting
+02014         // Decrement number of pixels to update for near.
+02015         _ULTotalNearPixels-= NL_TILE_LIGHTMAP_SIZE*NL_TILE_LIGHTMAP_SIZE;
+02016 }
+02017 
+02018 
+02019 // ***************************************************************************
+02020 void            CLandscape::refillTileLightMap(uint tileLightMapId, CRGBA  map[NL_TILE_LIGHTMAP_SIZE*NL_TILE_LIGHTMAP_SIZE])
+02021 {
+02022         uint    id, textNum;
+02023 
+02024         // Get the id local in the texture.
+02025         textNum= tileLightMapId / NbTileLightMapByTexture;
+02026         id= tileLightMapId % NbTileLightMapByTexture;
+02027         nlassert(textNum>=0 && textNum<_TextureNears.size());
+02028 
+02029         // get a ptr on the texture.
+02030         CPatchRdrPass   *nearRdrPass= _TextureNears[textNum];
+02031         CTextureNear    *nearText= (CTextureNear*)(ITexture*)nearRdrPass->TextureDiffuse;
+02032 
+02033         // refill this tile
+02034         nearText->refillRect(id, map);
+02035 }
+02036 
+02037 
+02038 
+02039 // ***************************************************************************
+02040 // ***************************************************************************
+02041 // Far.
+02042 // ***************************************************************************
+02043 // ***************************************************************************
+02044 
+02045 
+02046 // ***************************************************************************
+02047 CPatchRdrPass*  CLandscape::getFarRenderPass(CPatch* pPatch, uint farIndex, float& farUScale, float& farVScale, float& farUBias, float& farVBias, bool& bRot)
+02048 {
+02049         // Check args
+02050         nlassert (farIndex>0);
+02051 
+02052         // Get size of the far texture
+02053         uint width=(pPatch->getOrderS ()*NL_NUM_PIXELS_ON_FAR_TILE_EDGE)>>(farIndex-1);
+02054         uint height=(pPatch->getOrderT ()*NL_NUM_PIXELS_ON_FAR_TILE_EDGE)>>(farIndex-1);
+02055 
+02056         // For updateLighting: increment total of pixels to update.
+02057         _ULTotalFarPixels+= width*height;
+02058 
+02059         // Render pass index
+02060         uint passIndex=getRdrPassIndexWithSize (width, height);
+02061 
+02062         // Look for a free render pass
+02063         if (_FarRdrPassSetVectorFree[passIndex].begin()==_FarRdrPassSetVectorFree[passIndex].end())
+02064         {
+02065                 // Empty, add a new render pass
+02066                 CPatchRdrPass   *pass=new CPatchRdrPass;
+02067 
+02068                 // Fill the render pass
+02069                 CTextureFar *pTextureFar=new CTextureFar;
+02070 
+02071                 // Append this textureFar to the list of TextureFar to updateLighting.
+02072                 if(_ULRootTextureFar==NULL)
+02073                         _ULRootTextureFar= pTextureFar;
+02074                 else
+02075                         pTextureFar->linkBeforeUL(_ULRootTextureFar);
+02076 
+02077                 // Set the bank
+02078                 pTextureFar->_Bank=&TileFarBank;
+02079 
+02080                 // Set as diffuse texture for this renderpass
+02081                 pass->TextureDiffuse=pTextureFar;
+02082 
+02083                 // Set the size for this texture
+02084                 pTextureFar->setSizeOfFarPatch (std::max (width, height), std::min (width, height));
+02085 
+02086                 // Add the render pass
+02087                 _FarRdrPassSetVectorFree[passIndex].insert (pass);
+02088                 _FarRdrPassSet.insert (pass);
+02089         }
+02090 
+02091         // Ok, add the patch to the first render pass in the free list
+02092         TSPRenderPass pass=*_FarRdrPassSetVectorFree[passIndex].begin();
+02093 
+02094         // Get a pointer on the diffuse far texture
+02095         CTextureFar *pTextureFar=(CTextureFar*)(&*(pass->TextureDiffuse));
+02096 
+02097         // Add the patch to the far texture
+02098         if (pTextureFar->addPatch (pPatch, farUScale, farVScale, farUBias, farVBias, bRot))
+02099         {
+02100                 // The render state is full, remove from the free list..
+02101                 _FarRdrPassSetVectorFree[passIndex].erase (pass);
+02102         }
+02103 
+02104         // Return the renderpass
+02105         return pass;
+02106 }
+02107 
+02108 
+02109 // ***************************************************************************
+02110 void            CLandscape::freeFarRenderPass (CPatch* pPatch, CPatchRdrPass* pass, uint farIndex)
+02111 {
+02112         // Get size of the far texture
+02113         uint width=(pPatch->getOrderS ()*NL_NUM_PIXELS_ON_FAR_TILE_EDGE)>>(farIndex-1);
+02114         uint height=(pPatch->getOrderT ()*NL_NUM_PIXELS_ON_FAR_TILE_EDGE)>>(farIndex-1);
+02115 
+02116         // For updateLighting: decrement total of pixels to update.
+02117         _ULTotalFarPixels-= width*height;
+02118         nlassert(_ULTotalFarPixels>=0);
+02119 
+02120         // Render pass index
+02121         uint passIndex=getRdrPassIndexWithSize (width, height);
+02122 
+02123         // Get a pointer on the diffuse far texture
+02124         CTextureFar *pTextureFar=(CTextureFar*)(&*(pass->TextureDiffuse));
+02125 
+02126         // Remove from the patch from the texture if empty
+02127         if (pTextureFar->removePatch (pPatch))
+02128         {
+02129                 // Free list empty ?
+02130                 if (_FarRdrPassSetVectorFree[passIndex].begin()==_FarRdrPassSetVectorFree[passIndex].end())
+02131                 {
+02132                         // Let this render pass in the free list
+02133                         _FarRdrPassSetVectorFree[passIndex].insert (pass);
+02134                 }
+02135                 else
+02136                 {
+02137                         // Release for good
+02138                         _FarRdrPassSetVectorFree[passIndex].erase (pass);
+02139 
+02140                         // update UL links, and Remove from draw list
+02141                         eraseFarRenderPassFromSet (pass);
+02142                 }
+02143         }
+02144         else
+02145         {
+02146                 // Insert in the free list
+02147                 _FarRdrPassSetVectorFree[passIndex].insert (pass);
+02148         }
+02149 }
+02150 
+02151 
+02152 // ***************************************************************************
+02153 void            CLandscape::eraseFarRenderPassFromSet (CPatchRdrPass* pass)
+02154 {
+02155         // Before deleting, must remove TextureFar from UpdateLighting list.
+02156 
+02157         // Get a pointer on the diffuse far texture
+02158         CTextureFar *pTextureFar=(CTextureFar*)(&*(pass->TextureDiffuse));
+02159 
+02160         // If I delete the textureFar which is the current root
+02161         if(_ULRootTextureFar==pTextureFar)
+02162         {
+02163                 // switch to next
+02164                 _ULRootTextureFar= pTextureFar->getNextUL();
+02165                 // if still the same, it means that the circular list is now empty
+02166                 if(_ULRootTextureFar==pTextureFar)
+02167                         _ULRootTextureFar= NULL;
+02168                 // reset patch counter.
+02169                 _ULFarCurrentPatchId= 0;
+02170         }
+02171 
+02172         // unlink the texture from list
+02173         pTextureFar->unlinkUL();
+02174 
+02175 
+02176         // Remove from draw list
+02177         _FarRdrPassSet.erase (pass);
+02178 }
+02179 
+02180 
+02181 // ***************************************************************************
+02182 // ***************************************************************************
+02183 // Misc.
+02184 // ***************************************************************************
+02185 // ***************************************************************************
+02186 
+02187 
+02188 // ***************************************************************************
+02189 CZone*                  CLandscape::getZone (sint zoneId)
+02190 {
+02191         TZoneMap::iterator      it;
+02192         it= Zones.find(zoneId);
+02193         if (it!=Zones.end())
+02194                 return (*it).second;
+02195         else
+02196                 return NULL;
+02197 }
+02198 
+02199 
+02200 // ***************************************************************************
+02201 const CZone*    CLandscape::getZone (sint zoneId) const
+02202 {
+02203         TZoneMap::const_iterator        it;
+02204 
+02205         it= Zones.find(zoneId);
+02206         if (it!=Zones.end())
+02207                 return (*it).second;
+02208         else
+02209                 return NULL;
+02210 }
+02211 
+02212 
+02213 
+02214 // ***************************************************************************
+02215 void                    CLandscape::checkZoneBinds(CZone &curZone, EBadBind &bindError)
+02216 {
+02217         for(sint i=0;i<curZone.getNumPatchs();i++)
+02218         {
+02219                 const CZone::CPatchConnect      &pa= *curZone.getPatchConnect(i);
+02220 
+02221                 // Check the bindInfos.
+02222                 for(sint j=0;j<4;j++)
+02223                 {
+02224                         const CPatchInfo::CBindInfo     &bd=pa.BindEdges[j];
+02225                         // Just 1/1 for now.
+02226                         if(bd.NPatchs==1)
+02227                         {
+02228                                 CZone   *oZone= getZone(bd.ZoneId);
+02229                                 // If loaded zone.
+02230                                 if(oZone)
+02231                                 {
+02232                                         const CZone::CPatchConnect      &po= *(oZone->getPatchConnect(bd.Next[0]));
+02233                                         const CPatchInfo::CBindInfo     &bo= po.BindEdges[bd.Edge[0]];
+02234                                         if(bo.NPatchs!=1 || bo.Next[0]!=i || bo.Edge[0]!=j)
+02235                                                 bindError.BindErrors.push_back( EBadBind::CBindError(curZone.getZoneId(), i));
+02236                                 }
+02237                         }
+02238                 }
+02239         }
+02240 }
+02241 
+02242 
+02243 // ***************************************************************************
+02244 void                    CLandscape::checkBinds() throw(EBadBind)
+02245 {
+02246         EBadBind        bindError;
+02247 
+02248         for(ItZoneMap it= Zones.begin();it!=Zones.end();it++)
+02249         {
+02250                 CZone   &curZone= *(*it).second;
+02251                 checkZoneBinds(curZone, bindError);
+02252         }
+02253 
+02254         if(!bindError.BindErrors.empty())
+02255                 throw bindError;
+02256 }
+02257 
+02258 
+02259 // ***************************************************************************
+02260 void                    CLandscape::checkBinds(uint16 zoneId) throw(EBadBind)
+02261 {
+02262         EBadBind        bindError;
+02263 
+02264         ItZoneMap it= Zones.find(zoneId);
+02265         if(it!= Zones.end())
+02266         {
+02267                 CZone   &curZone= *(*it).second;
+02268                 checkZoneBinds(curZone, bindError);
+02269                 if(!bindError.BindErrors.empty())
+02270                         throw bindError;
+02271         }
+02272 }
+02273 
+02274 
+02275 
+02276 // ***************************************************************************
+02277 void                    CLandscape::addTrianglesInBBox(const CPatchIdentEx &paIdEx, const CAABBox &bbox, std::vector<CTrianglePatch> &triangles, uint8 tileTessLevel) const
+02278 {
+02279         // No clear here, just add triangles to the array.
+02280         const CPatch    *pa= paIdEx.Patch;
+02281 
+02282         CPatchIdent             paId;
+02283         paId.ZoneId= paIdEx.ZoneId;
+02284         paId.PatchId= paIdEx.PatchId;
+02285         pa->addTrianglesInBBox(paId, bbox, triangles, tileTessLevel);
+02286 }
+02287 
+02288 
+02289 // ***************************************************************************
+02290 void                    CLandscape::buildTrianglesInBBox(const CAABBox &bbox, std::vector<CTrianglePatch> &triangles, uint8 tileTessLevel)
+02291 {
+02292         // clear selection.
+02293         triangles.clear();
+02294 
+02295         // search path of interest.
+02296         _PatchQuadGrid.clearSelection();
+02297         _PatchQuadGrid.select(bbox.getMin(), bbox.getMax());
+02298         CQuadGrid<CPatchIdentEx>::CIterator     it;
+02299 
+02300         // for each patch, add triangles to the array.
+02301         for(it= _PatchQuadGrid.begin(); it!= _PatchQuadGrid.end(); it++)
+02302         {
+02303                 addTrianglesInBBox((*it), bbox, triangles, tileTessLevel);
+02304         }
+02305 }
+02306 
+02307 
+02308 
+02309 // ***************************************************************************
+02310 void                    CLandscape::addPatchBlocksInBBox(const CPatchIdentEx &paIdEx, const CAABBox &bbox, std::vector<CPatchBlockIdent> &paBlockIds)
+02311 {
+02312         // No clear here, just add blocks to the array.
+02313         const CPatch    *pa= paIdEx.Patch;
+02314 
+02315         CPatchIdent             paId;
+02316         paId.ZoneId= paIdEx.ZoneId;
+02317         paId.PatchId= paIdEx.PatchId;
+02318         pa->addPatchBlocksInBBox(paId, bbox, paBlockIds);
+02319 }
+02320 
+02321 
+02322 // ***************************************************************************
+02323 void                    CLandscape::buildPatchBlocksInBBox(const CAABBox &bbox, std::vector<CPatchBlockIdent> &paBlockIds)
+02324 {
+02325         // clear selection.
+02326         paBlockIds.clear();
+02327 
+02328         // search path of interest.
+02329         _PatchQuadGrid.clearSelection();
+02330         _PatchQuadGrid.select(bbox.getMin(), bbox.getMax());
+02331         CQuadGrid<CPatchIdentEx>::CIterator     it;
+02332 
+02333         // for each patch, add blocks to the array.
+02334         for(it= _PatchQuadGrid.begin(); it!= _PatchQuadGrid.end(); it++)
+02335         {
+02336                 addPatchBlocksInBBox((*it), bbox, paBlockIds);
+02337         }
+02338 }
+02339 
+02340 
+02341 // ***************************************************************************
+02342 void                    CLandscape::fillPatchQuadBlock(CPatchQuadBlock &quadBlock) const
+02343 {
+02344         sint zoneId=  quadBlock.PatchBlockId.PatchId.ZoneId;
+02345         sint patchId= quadBlock.PatchBlockId.PatchId.PatchId;
+02346         std::map<uint16, CZone*>::const_iterator        it= Zones.find(zoneId);
+02347         if(it!=Zones.end())
+02348         {
+02349                 sint    N= (*it).second->getNumPatchs();
+02350                 // patch must exist in the zone.
+02351                 nlassert(patchId>=0);
+02352                 nlassert(patchId<N);
+02353 
+02354                 const CPatch    *pa= const_cast<const CZone*>((*it).second)->getPatch(patchId);
+02355                 pa->fillPatchQuadBlock(quadBlock);
+02356         }
+02357 }
+02358 
+02359 
+02360 
+02361 
+02362 // ***************************************************************************
+02363 void                    CLandscape::buildCollideFaces(const CAABBoxExt &bbox, vector<CTriangle> &faces, bool faceClip)
+02364 {
+02365         CBSphere        bsWanted(bbox.getCenter(), bbox.getRadius());
+02366 
+02367         faces.clear();
+02368         // For all zones.
+02369         for(ItZoneMap it= Zones.begin();it!=Zones.end();it++)
+02370         {
+02371                 const CAABBoxExt        &bb= (*it).second->getZoneBB();
+02372                 CBSphere        bs(bb.getCenter(), bb.getRadius());
+02373                 // If zone intersect the wanted area.
+02374                 //===================================
+02375                 if(bs.intersect(bsWanted))
+02376                 {
+02377                         // Then trace all patch.
+02378                         sint    N= (*it).second->getNumPatchs();
+02379                         for(sint i=0;i<N;i++)
+02380                         {
+02381                                 const CPatch    *pa= const_cast<const CZone*>((*it).second)->getPatch(i);
+02382 
+02383                                 // If patch in wanted area....
+02384                                 //============================
+02385                                 if(bsWanted.intersect(pa->getBSphere()))
+02386                                 {
+02387                                         // 0. Build the faces.
+02388                                         //====================
+02389                                         sint    ordS= pa->getOrderS();
+02390                                         sint    ordT= pa->getOrderT();
+02391                                         sint    x,y,j;
+02392                                         vector<CTriangle>       tmpFaces;
+02393                                         tmpFaces.reserve(ordS*ordT);
+02394                                         float   OOS= 1.0f/ordS;
+02395                                         float   OOT= 1.0f/ordT;
+02396                                         for(y=0;y<ordT;y++)
+02397                                         {
+02398                                                 for(x=0;x<ordS;x++)
+02399                                                 {
+02400                                                         CTriangle       f;
+02401                                                         f.V0= pa->computeVertex(x*OOS, y*OOT);
+02402                                                         f.V1= pa->computeVertex(x*OOS, (y+1)*OOT);
+02403                                                         f.V2= pa->computeVertex((x+1)*OOS, (y+1)*OOT);
+02404                                                         tmpFaces.push_back(f);
+02405                                                         f.V0= pa->computeVertex(x*OOS, y*OOT);
+02406                                                         f.V1= pa->computeVertex((x+1)*OOS, (y+1)*OOT);
+02407                                                         f.V2= pa->computeVertex((x+1)*OOS, y*OOT);
+02408                                                         tmpFaces.push_back(f);
+02409                                                 }
+02410                                         }
+02411 
+02412                                         // 1. Clip the faces.
+02413                                         //===================
+02414                                         if(faceClip)
+02415                                         {
+02416                                                 // Insert only faces which are In the area.
+02417                                                 for(j=0;j<(sint)tmpFaces.size();j++)
+02418                                                 {
+02419                                                         CTriangle       &f= tmpFaces[j];
+02420                                                         if(bbox.intersect(f.V0, f.V1, f.V2))
+02421                                                         {
+02422                                                                 faces.push_back(f);
+02423                                                         }
+02424                                                 }
+02425                                         }
+02426                                         else
+02427                                         {
+02428                                                 // Else insert ALL.
+02429                                                 faces.insert(faces.end(), tmpFaces.begin(), tmpFaces.end());
+02430                                         }
+02431                                 }
+02432                         }
+02433                 }
+02434         }
+02435 }
+02436 
+02437 
+02438 // ***************************************************************************
+02439 void                    CLandscape::buildCollideFaces(sint zoneId, sint patch, std::vector<CTriangle> &faces)
+02440 {
+02441         faces.clear();
+02442 
+02443         ItZoneMap it= Zones.find(zoneId);
+02444         if(it!=Zones.end())
+02445         {
+02446                 // Then trace all patch.
+02447                 sint    N= (*it).second->getNumPatchs();
+02448                 nlassert(patch>=0);
+02449                 nlassert(patch<N);
+02450                 const CPatch    *pa= const_cast<const CZone*>((*it).second)->getPatch(patch);
+02451 
+02452                 // Build the faces.
+02453                 //=================
+02454                 sint    ordS= pa->getOrderS();
+02455                 sint    ordT= pa->getOrderT();
+02456                 sint    x,y;
+02457                 float   OOS= 1.0f/ordS;
+02458                 float   OOT= 1.0f/ordT;
+02459                 for(y=0;y<ordT;y++)
+02460                 {
+02461                         for(x=0;x<ordS;x++)
+02462                         {
+02463                                 CTriangle       f;
+02464                                 f.V0= pa->computeVertex(x*OOS, y*OOT);
+02465                                 f.V1= pa->computeVertex(x*OOS, (y+1)*OOT);
+02466                                 f.V2= pa->computeVertex((x+1)*OOS, (y+1)*OOT);
+02467                                 faces.push_back(f);
+02468                                 f.V0= pa->computeVertex(x*OOS, y*OOT);
+02469                                 f.V1= pa->computeVertex((x+1)*OOS, (y+1)*OOT);
+02470                                 f.V2= pa->computeVertex((x+1)*OOS, y*OOT);
+02471                                 faces.push_back(f);
+02472                         }
+02473                 }
+02474         }
+02475 }
+02476 
+02477 
+02478 // ***************************************************************************
+02479 CVector                 CLandscape::getTesselatedPos(const CPatchIdent &patchId, const CUV &uv) const
+02480 {
+02481         // First, must update globals, for CTessFace::computeTesselatedPos() to work properly.
+02482 
+02483         // VertexProgrma mode???
+02484         CLandscapeGlobals::VertexProgramEnabled= _VertexShaderOk;
+02485 
+02486         // If VertexProgram enabled
+02487         if( CLandscapeGlobals::VertexProgramEnabled )
+02488         {
+02489                 /* because VertexProgram enabled, CTessVertex::Pos (geomorphed Pos) are not computed each frame
+02490                    Hence, CTessFace::computeTesselatedPos() will call CTessVertex::computeGeomPos() to have correct 
+02491                    CTessVertex::Pos. ThereFore we must setup globals so CTessVertex::computeGeomPos() works properly.
+02492                 */
+02493                 
+02494                 // see copy in updateGlobalsAndLockBuffers(). NB: Just copy what needed here!!!!
+02495 
+02496                 // Tile subdivsion part.
+02497                 CLandscapeGlobals::TileDistNear = _TileDistNear;
+02498                 CLandscapeGlobals::TileDistFar = CLandscapeGlobals::TileDistNear+20;
+02499                 CLandscapeGlobals::TileDistNearSqr = sqr(CLandscapeGlobals::TileDistNear);
+02500                 CLandscapeGlobals::TileDistFarSqr = sqr(CLandscapeGlobals::TileDistFar);
+02501                 CLandscapeGlobals::OOTileDistDeltaSqr = 1.0f / (CLandscapeGlobals::TileDistFarSqr - CLandscapeGlobals::TileDistNearSqr);
+02502 
+02503                 // RefineThreshold.
+02504                 CLandscapeGlobals::RefineThreshold= _Threshold;
+02505                 CLandscapeGlobals::OORefineThreshold= 1.0f / CLandscapeGlobals::RefineThreshold;
+02506 
+02507                 // Refine Center*.
+02508                 // NB: setup the last setuped refineCenter.
+02509                 CLandscapeGlobals::RefineCenter= _OldRefineCenter;
+02510         }
+02511 
+02512 
+02513         // \todo yoyo: TODO_ZONEID: change ZoneId in 32 bits...
+02514         std::map<uint16, CZone*>::const_iterator        it= Zones.find((uint16)patchId.ZoneId);
+02515         if(it!=Zones.end())
+02516         {
+02517                 sint    N= (*it).second->getNumPatchs();
+02518                 // patch must exist in the zone.
+02519                 nlassert(patchId.PatchId<N);
+02520                 const CPatch    *pa= const_cast<const CZone*>((*it).second)->getPatch(patchId.PatchId);
+02521 
+02522                 return pa->getTesselatedPos(uv);
+02523         }
+02524         else
+02525                 return CVector::Null;
+02526 }
+02527 
+02528 
+02529 // ***************************************************************************
+02530 uint                    CLandscape::getRdrPassIndexWithSize (uint width, uint height)
+02531 {
+02532         // Check no NULL size
+02533         nlassert (width);
+02534         nlassert (height);
+02535 
+02536         // Find width order
+02537         int orderWidth=0;
+02538         while (!(width&(1<<orderWidth)))
+02539                 orderWidth++;
+02540 
+02541         // Find heightorder
+02542         int orderHeight=0;
+02543         while (!(height&(1<<orderHeight)))
+02544                 orderHeight++;
+02545 
+02546         if (orderWidth>orderHeight)
+02547         {
+02548                 return NL_MAX_SIZE_OF_TEXTURE_EDGE_SHIFT*orderHeight+orderWidth;
+02549         }
+02550         else
+02551         {
+02552                 return NL_MAX_SIZE_OF_TEXTURE_EDGE_SHIFT*orderWidth+orderHeight;
+02553         }
+02554 }
+02555 
+02556 #define NL_TILE_FAR_SIZE_ORDER0 (NL_NUM_PIXELS_ON_FAR_TILE_EDGE*NL_NUM_PIXELS_ON_FAR_TILE_EDGE)
+02557 #define NL_TILE_FAR_SIZE_ORDER1 ((NL_NUM_PIXELS_ON_FAR_TILE_EDGE>>1)*(NL_NUM_PIXELS_ON_FAR_TILE_EDGE>>1))
+02558 #define NL_TILE_FAR_SIZE_ORDER2 ((NL_NUM_PIXELS_ON_FAR_TILE_EDGE>>2)*(NL_NUM_PIXELS_ON_FAR_TILE_EDGE>>2))
+02559 
+02560 // ***************************************************************************
+02561 // internal use
+02562 bool                    CLandscape::eraseTileFarIfNotGood (uint tileNumber, uint sizeOrder0, uint sizeOrder1, uint sizeOrder2)
+02563 {
+02564         // The same tiles ?
+02565         bool bSame=true;
+02566 
+02567         // It is the same tile ?
+02568         if (TileFarBank.getTile (tileNumber)->isFill (CTileFarBank::diffuse))
+02569         {
+02570                 // Good diffuse size ?
+02571                 if (
+02572                         (TileFarBank.getTile (tileNumber)->getSize (CTileFarBank::diffuse, CTileFarBank::order0) != sizeOrder0) ||
+02573                         (TileFarBank.getTile (tileNumber)->getSize (CTileFarBank::diffuse, CTileFarBank::order1) != sizeOrder1) ||
+02574                         (TileFarBank.getTile (tileNumber)->getSize (CTileFarBank::diffuse, CTileFarBank::order2) != sizeOrder2)
+02575                         )
+02576                 {
+02577                         TileFarBank.getTile (tileNumber)->erasePixels (CTileFarBank::diffuse);
+02578                         bSame=false;
+02579                 }
+02580         }
+02581 
+02582         // It is the same tile ?
+02583         if (TileFarBank.getTile (tileNumber)->isFill (CTileFarBank::additive))
+02584         {
+02585                 // Good additive size ?
+02586                 if (
+02587                         (TileFarBank.getTile (tileNumber)->getSize (CTileFarBank::additive, CTileFarBank::order0) != sizeOrder0) ||
+02588                         (TileFarBank.getTile (tileNumber)->getSize (CTileFarBank::additive, CTileFarBank::order1) != sizeOrder1) ||
+02589                         (TileFarBank.getTile (tileNumber)->getSize (CTileFarBank::additive, CTileFarBank::order2) != sizeOrder2)
+02590                         )
+02591                 {
+02592                         TileFarBank.getTile (tileNumber)->erasePixels (CTileFarBank::additive);
+02593                         bSame=false;
+02594                 }
+02595         }
+02596 
+02597         // Return true if the tiles seem to be the sames
+02598         return bSame;
+02599 }
+02600 
+02601 // ***************************************************************************
+02602 bool                    CLandscape::initTileBanks ()
+02603 {
+02604         // *** Check the two banks are OK
+02605         _FarInitialized=false;
+02606 
+02607         // Compatibility check
+02608         bool bCompatibility=true;
+02609 
+02610         // Same number of tiles
+02611         if (TileBank.getTileCount()==TileFarBank.getNumTile())
+02612         {
+02613                 // Same tileSet
+02614                 for (int tileSet=0; tileSet<TileBank.getTileSetCount(); tileSet++)
+02615                 {
+02616                         // Same tile128
+02617                         int tile;
+02618                         for (tile=0; tile<TileBank.getTileSet(tileSet)->getNumTile128(); tile++)
+02619                         {
+02620                                 // tile number
+02621                                 uint tileNumber=TileBank.getTileSet(tileSet)->getTile128(tile);
+02622 
+02623                                 // erase the tiles if not good
+02624                                 bCompatibility&=eraseTileFarIfNotGood (tileNumber, NL_TILE_FAR_SIZE_ORDER0, NL_TILE_FAR_SIZE_ORDER1, NL_TILE_FAR_SIZE_ORDER2);
+02625                         }
+02626 
+02627                         // Same tile256
+02628                         for (tile=0; tile<TileBank.getTileSet(tileSet)->getNumTile256(); tile++)
+02629                         {
+02630                                 // tile number
+02631                                 uint tileNumber=TileBank.getTileSet(tileSet)->getTile256(tile);
+02632 
+02633                                 // erase the tiles if not good
+02634                                 bCompatibility&=eraseTileFarIfNotGood (tileNumber, NL_TILE_FAR_SIZE_ORDER0<<2, NL_TILE_FAR_SIZE_ORDER1<<2, NL_TILE_FAR_SIZE_ORDER2<<2);
+02635                         }
+02636 
+02637                         // Same transition
+02638                         for (tile=0; tile<CTileSet::count; tile++)
+02639                         {
+02640                                 // tile number
+02641                                 uint tileNumber=TileBank.getTileSet(tileSet)->getTransition(tile)->getTile();
+02642 
+02643                                 // erase the tiles if not good
+02644                                 bCompatibility&=eraseTileFarIfNotGood (tileNumber, NL_TILE_FAR_SIZE_ORDER0, NL_TILE_FAR_SIZE_ORDER1, NL_TILE_FAR_SIZE_ORDER2);
+02645                         }
+02646                 }
+02647                 
+02648                 // Far actived!
+02649                 _FarInitialized=true;
+02650         }
+02651 
+02652         // Register / Load the vegetables.
+02653         TileBank.initTileVegetableDescs(_VegetableManager);
+02654 
+02655         return bCompatibility;
+02656 }
+02657 
+02658 
+02659 // ***************************************************************************
+02660 void                    CLandscape::setupStaticLight (const CRGBA &diffuse, const CRGBA &ambiant, float multiply)
+02661 {
+02662         sint nMultiply=(sint)(256.f*multiply);
+02663         for (int i=0; i<256; i++)
+02664         {
+02665                 sint max=0;
+02666                 sint r=(((nMultiply*diffuse.R*i)>>8)+ambiant.R*(256-i))>>8; 
+02667                 if (r>max)
+02668                         max=r;
+02669                 sint g=(((nMultiply*diffuse.G*i)>>8)+ambiant.G*(256-i))>>8;
+02670                 if (g>max)
+02671                         max=g;
+02672                 sint b=(((nMultiply*diffuse.B*i)>>8)+ambiant.B*(256-i))>>8;
+02673                 if (b>max)
+02674                         max=b;
+02675                 r<<=8;
+02676                 g<<=8;
+02677                 b<<=8;
+02678                 max=std::max(max, 256);
+02679                 r/=max;
+02680                 g/=max;
+02681                 b/=max;
+02682                 clamp (r, 0, 255);
+02683                 clamp (g, 0, 255);
+02684                 clamp (b, 0, 255);
+02685                 _LightValue[i].R=r;
+02686                 _LightValue[i].G=g;
+02687                 _LightValue[i].B=b;
+02688                 _LightValue[i].A=255;
+02689         }
+02690 }
+02691 
+02692 // ***************************************************************************
+02693 void                    CLandscape::enableAutomaticLighting(bool enable)
+02694 {
+02695         _AutomaticLighting= enable;
+02696 }
+02697 
+02698 // ***************************************************************************
+02699 void                    CLandscape::setupAutomaticLightDir(const CVector &lightDir)
+02700 {
+02701         _AutomaticLightDir= lightDir;
+02702         _AutomaticLightDir.normalize();
+02703 }
+02704 
+02705 
+02706 // ***************************************************************************
+02707 CVector         CLandscape::getHeightFieldDeltaZ(float x, float y) const
+02708 {
+02709         if(_HeightField.ZPatchs.size()==0)
+02710                 return CVector::Null;
+02711 
+02712         // map to _HeightField coordinates.
+02713         x-= _HeightField.OriginX;
+02714         y-= _HeightField.OriginY;
+02715         x*= _HeightField.OOSizeX;
+02716         y*= _HeightField.OOSizeY;
+02717         // get patch on the grid.
+02718         sint    ix, iy;
+02719         ix= (sint)floor(x);
+02720         iy= (sint)floor(y);
+02721         // out of the grid?
+02722         if( ix<0 || ix>=(sint)_HeightField.Width || iy<0 || iy>=(sint)_HeightField.Height)
+02723                 return CVector::Null;
+02724 
+02725         // get patch.
+02726         const CBezierPatchZ     &paz= _HeightField.ZPatchs[iy*_HeightField.Width + ix];
+02727 
+02728         // compute result.
+02729         CVector ret=CVector::Null;
+02730         ret.x= 0;
+02731         ret.y= 0;
+02732         ret.z= paz.eval(x-ix, y-iy);
+02733 
+02734         return ret;
+02735 }
+02736 
+02737 
+02738 
+02739 // ***************************************************************************
+02740 void            CLandscape::CBezierPatchZ::makeInteriors()
+02741 {
+02742         float           &a = Vertices[0];
+02743         float           &b = Vertices[1];
+02744         float           &c = Vertices[2];
+02745         float           &d = Vertices[3];
+02746         Interiors[0] = Tangents[7] + Tangents[0] - a;
+02747         Interiors[1] = Tangents[1] + Tangents[2] - b;
+02748         Interiors[2] = Tangents[3] + Tangents[4] - c;
+02749         Interiors[3] = Tangents[5] + Tangents[6] - d;
+02750 }
+02751 // ***************************************************************************
+02752 float           CLandscape::CBezierPatchZ::eval(float ps, float pt) const
+02753 {
+02754         float   p;
+02755 
+02756         float ps2 = ps * ps;
+02757         float ps1 = 1.0f - ps;
+02758         float ps12 = ps1 * ps1;
+02759         float s0 = ps12 * ps1;
+02760         float s1 = 3.0f * ps * ps12;
+02761         float s2 = 3.0f * ps2 * ps1;
+02762         float s3 = ps2 * ps;
+02763         float pt2 = pt * pt;
+02764         float pt1 = 1.0f - pt;
+02765         float pt12 = pt1 * pt1;
+02766         float t0 = pt12 * pt1;
+02767         float t1 = 3.0f * pt * pt12;
+02768         float t2 = 3.0f * pt2 * pt1;
+02769         float t3 = pt2 * pt;
+02770 
+02771         p = Vertices[0] * s0 * t0       + 
+02772                 Tangents[7] * s1 * t0   + 
+02773                 Tangents[6] * s2 * t0   + 
+02774                 Vertices[3] * s3 * t0;
+02775         p+= Tangents[0] * s0 * t1       + 
+02776                 Interiors[0]* s1 * t1   + 
+02777                 Interiors[3]* s2 * t1   + 
+02778                 Tangents[5] * s3 * t1;
+02779         p+=     Tangents[1] * s0 * t2   + 
+02780                 Interiors[1]* s1 * t2   + 
+02781                 Interiors[2]* s2 * t2   + 
+02782                 Tangents[4] * s3 * t2;
+02783         p+=     Vertices[1] * s0 * t3   + 
+02784                 Tangents[2] * s1 * t3   + 
+02785                 Tangents[3] * s2 * t3   + 
+02786                 Vertices[2] * s3 * t3;
+02787         
+02788         return p;
+02789 }
+02790 
+02791 
+02792 // ***************************************************************************
+02793 void            CLandscape::setHeightField(const CHeightMap &hf)
+02794 {
+02795         if(hf.getWidth()<2)
+02796                 return;
+02797         if(hf.getHeight()<2)
+02798                 return;
+02799 
+02800         // Fill basics.
+02801         _HeightField.OriginX= hf.OriginX;
+02802         _HeightField.OriginY= hf.OriginY;
+02803         _HeightField.SizeX= hf.SizeX;
+02804         _HeightField.SizeY= hf.SizeY;
+02805         _HeightField.OOSizeX= 1/hf.SizeX;
+02806         _HeightField.OOSizeY= 1/hf.SizeY;
+02807         uint    w= hf.getWidth()-1;
+02808         uint    h= hf.getHeight()-1;
+02809         _HeightField.Width= w;
+02810         _HeightField.Height= h;
+02811         _HeightField.ZPatchs.resize(w * h);
+02812 
+02813         // compute  patchs
+02814         sint    x,y;
+02815 
+02816         // compute vertices / tangents on each patch
+02817         for(y=0;y<(sint)h;y++)
+02818         {
+02819                 for(x=0;x<(sint)w;x++)
+02820                 {
+02821                         CBezierPatchZ   &paz= _HeightField.ZPatchs[y*w+x];
+02822                         // vertices.
+02823                         paz.Vertices[0]= hf.getZ(x, y);
+02824                         paz.Vertices[1]= hf.getZ(x, y+1);
+02825                         paz.Vertices[2]= hf.getZ(x+1, y+1);
+02826                         paz.Vertices[3]= hf.getZ(x+1, y);
+02827                 }
+02828         }
+02829 
+02830         // compute tangents
+02831         for(y=0;y<(sint)h;y++)
+02832         {
+02833                 for(x=0;x<(sint)w;x++)
+02834                 {
+02835                         CBezierPatchZ   &paz= _HeightField.ZPatchs[y*w+x];
+02836                         sint    tg;
+02837                         // For each tangent, what vertex (relative to x,y) we must take.
+02838                         struct  CDeltaPos
+02839                         {
+02840                                 sint    ox,oy;
+02841                                 sint    dx1,dy1;
+02842                                 sint    dx2,dy2;
+02843                         };
+02844                         static CDeltaPos        deltas[8]= {
+02845                                 {0,0, 0,1, 0,-1} ,
+02846                                 {0,1, 0,0, 0,2} ,
+02847                                 {0,1, 1,1, -1,1} ,
+02848                                 {1,1, 0,1, 2,1} ,
+02849                                 {1,1, 1,0, 1,2} ,
+02850                                 {1,0, 1,1, 1,-1} ,
+02851                                 {1,0, 0,0, 2,0} ,
+02852                                 {0,0, 1,0, -1,0} ,
+02853                                 };
+02854 
+02855                         // compute each tangent of this patch.
+02856                         for(tg=0; tg<8;tg++)
+02857                         {
+02858                                 sint    x0,y0;
+02859                                 sint    x1,y1;
+02860                                 sint    x2,y2;
+02861                                 x0= x+deltas[tg].ox; y0= y+deltas[tg].oy;
+02862                                 x1= x+deltas[tg].dx1; y1= y+deltas[tg].dy1;
+02863                                 x2= x+deltas[tg].dx2; y2= y+deltas[tg].dy2;
+02864 
+02865                                 // borders case.
+02866                                 if(x2<0 || x2>=(sint)hf.getWidth() || y2<0 || y2>=(sint)hf.getHeight())
+02867                                 {
+02868                                         float           v,dv;
+02869                                         // base of tangents.
+02870                                         v= hf.getZ(x0,y0);
+02871                                         // target tangents.
+02872                                         dv= hf.getZ(x1,y1) - v;
+02873                                         // result of tangent.
+02874                                         paz.Tangents[tg]= v+dv/3;
+02875                                 }
+02876                                 // middle case.
+02877                                 else
+02878                                 {
+02879                                         float           v,dv;
+02880                                         // base of tangents.
+02881                                         v= hf.getZ(x0,y0);
+02882                                         // target tangents.
+02883                                         dv= hf.getZ(x1,y1) - v;
+02884                                         // add mirror target tangent.
+02885                                         dv+= -(hf.getZ(x2,y2) - v);
+02886                                         dv/=2;
+02887                                         // result of tangent.
+02888                                         paz.Tangents[tg]= v+dv/3;
+02889                                 }
+02890                         }
+02891                 }
+02892         }
+02893 
+02894         // compute interiors.
+02895         for(y=0;y<(sint)h;y++)
+02896         {
+02897                 for(x=0;x<(sint)w;x++)
+02898                 {
+02899                         CBezierPatchZ   &paz= _HeightField.ZPatchs[y*w+x];
+02900                         paz.makeInteriors();
+02901                 }
+02902         }
+02903 
+02904 }
+02905 
+02906 
+02907 // ***************************************************************************
+02908 void            CLandscape::getTessellationLeaves(std::vector<const CTessFace*>  &leaves) const
+02909 {
+02910         leaves.clear();
+02911 
+02912         std::map<uint16, CZone*>::const_iterator        it;
+02913         for(it= Zones.begin();it!=Zones.end();it++)
+02914         {
+02915                 // Then trace all patch.
+02916                 sint    N= (*it).second->getNumPatchs();
+02917                 for(sint i=0;i<N;i++)
+02918                 {
+02919                         const CPatch    *pa= const_cast<const CZone*>((*it).second)->getPatch(i);
+02920 
+02921                         pa->appendTessellationLeaves(leaves);
+02922                 }
+02923         }
+02924 
+02925 }
+02926 
+02927 
+02928 // ***************************************************************************
+02929 void            CLandscape::setPZBModelPosition(const CVector &pos)
+02930 {
+02931         _PZBModelPosition= pos;
+02932 }
+02933 
+02934 
+02935 
+02936 // ***************************************************************************
+02937 // ***************************************************************************
+02938 // Allocators.
+02939 // ***************************************************************************
+02940 // ***************************************************************************
+02941 
+02942 
+02943 // ***************************************************************************
+02944 CTessFace                       *CLandscape::newTessFace()
+02945 {
+02946         // allcoate the face.
+02947         CTessFace               *face= TessFaceAllocator.allocate();
+02948 
+02949         // for refine() mgt, append the face to the list of newLeaves, so they will be tested in refine()
+02950         face->linkInPList(_RootNewLeaves);
+02951 
+02952         return face;
+02953 }
+02954 
+02955 // ***************************************************************************
+02956 CTessVertex                     *CLandscape::newTessVertex()
+02957 {
+02958         return TessVertexAllocator.allocate();
+02959 }
+02960 
+02961 // ***************************************************************************
+02962 CTessNearVertex         *CLandscape::newTessNearVertex()
+02963 {
+02964         return TessNearVertexAllocator.allocate();
+02965 }
+02966 
+02967 // ***************************************************************************
+02968 CTessFarVertex          *CLandscape::newTessFarVertex()
+02969 {
+02970         return TessFarVertexAllocator.allocate();
+02971 }
+02972 
+02973 // ***************************************************************************
+02974 CTileMaterial           *CLandscape::newTileMaterial()
+02975 {
+02976         return TileMaterialAllocator.allocate();
+02977 }
+02978 
+02979 // ***************************************************************************
+02980 CTileFace                       *CLandscape::newTileFace()
+02981 {
+02982         return TileFaceAllocator.allocate();
+02983 }
+02984 
+02985 // ***************************************************************************
+02986 void                            CLandscape::deleteTessFace(CTessFace *f)
+02987 {
+02988         // for refine() mgt, must remove from refine priority list, or from the temp rootTessFaceToUpdate list.
+02989         f->unlinkInPList();
+02990 
+02991         TessFaceAllocator.free(f);
+02992 }
+02993 
+02994 // ***************************************************************************
+02995 void                            CLandscape::deleteTessVertex(CTessVertex *v)
+02996 {
+02997         TessVertexAllocator.free(v);
+02998 }
+02999 
+03000 // ***************************************************************************
+03001 void                            CLandscape::deleteTessNearVertex(CTessNearVertex *v)
+03002 {
+03003         TessNearVertexAllocator.free(v);
+03004 }
+03005 
+03006 // ***************************************************************************
+03007 void                            CLandscape::deleteTessFarVertex(CTessFarVertex *v)
+03008 {
+03009         TessFarVertexAllocator.free(v);
+03010 }
+03011 
+03012 // ***************************************************************************
+03013 void                            CLandscape::deleteTileMaterial(CTileMaterial *tm)
+03014 {
+03015         TileMaterialAllocator.free(tm);
+03016 }
+03017 
+03018 // ***************************************************************************
+03019 void                            CLandscape::deleteTileFace(CTileFace *tf)
+03020 {
+03021         TileFaceAllocator.free(tf);
+03022 }
+03023 
+03024 
+03025 
+03026 // ***************************************************************************
+03027 // ***************************************************************************
+03028 // Noise
+03029 // ***************************************************************************
+03030 // ***************************************************************************
+03031 
+03032 
+03033 // ***************************************************************************
+03034 void                    CLandscape::setNoiseMode(bool enable)
+03035 {
+03036         _NoiseEnabled= enable;
+03037 }
+03038 
+03039 // ***************************************************************************
+03040 bool                    CLandscape::getNoiseMode() const
+03041 {
+03042         return _NoiseEnabled;
+03043 }
+03044 
+03045 
+03046 // ***************************************************************************
+03047 // ***************************************************************************
+03048 // Micro vegetation
+03049 // ***************************************************************************
+03050 // ***************************************************************************
+03051 
+03052 
+03053 // ***************************************************************************
+03054 void            CLandscape::enableVegetable(bool enable)
+03055 {
+03056         _VegetableManagerEnabled= enable;
+03057 
+03058         // if false, delete all Vegetable IGs.
+03059         if(!_VegetableManagerEnabled)
+03060         {
+03061                 // Landscape always create ClipBlokcs, but IGs/addInstances() are created only if isVegetableActive().
+03062                 // For all zones.
+03063                 for(ItZoneMap it= Zones.begin();it!=Zones.end();it++)
+03064                 {
+03065                         // for all patch.
+03066                         sint    N= (*it).second->getNumPatchs();
+03067                         for(sint i=0;i<N;i++)
+03068                         {
+03069                                 // delete vegetable Igs of this patch
+03070                                 CPatch  *pa= ((*it).second)->getPatch(i);
+03071                                 pa->deleteAllVegetableIgs();
+03072                         }
+03073 
+03074                 }
+03075         }
+03076         // if true
+03077         else
+03078         {
+03079                 //  reload all Shapes (actually load only new shapes)
+03080                 TileBank.initTileVegetableDescs(_VegetableManager);
+03081 
+03082                 // And recreate vegetable igs.
+03083                 // Landscape always create ClipBlokcs, but IGs/addInstances() are created only if isVegetableActive().
+03084                 // For all zones.
+03085                 for(ItZoneMap it= Zones.begin();it!=Zones.end();it++)
+03086                 {
+03087                         // for all patch.
+03088                         sint    N= (*it).second->getNumPatchs();
+03089                         for(sint i=0;i<N;i++)
+03090                         {
+03091                                 // recreate vegetable Igs of this patch
+03092                                 CPatch  *pa= ((*it).second)->getPatch(i);
+03093                                 pa->recreateAllVegetableIgs();
+03094                         }
+03095 
+03096                 }
+03097         }
+03098 
+03099 }
+03100 
+03101 // ***************************************************************************
+03102 bool            CLandscape::isVegetableActive() const
+03103 {
+03104         return _VegetableManagerEnabled && _DriverOkForVegetable;
+03105 }
+03106 
+03107 // ***************************************************************************
+03108 void            CLandscape::loadVegetableTexture(const string &textureFileName)
+03109 {
+03110         // load the texture in the manager
+03111         _VegetableManager->loadTexture(textureFileName);
+03112 }
+03113 
+03114 // ***************************************************************************
+03115 void            CLandscape::setupVegetableLighting(const CRGBA &ambient, const CRGBA &diffuse, const CVector &directionalLight)
+03116 {
+03117         // set the directional light to the manager
+03118         _VegetableManager->setDirectionalLight(ambient, diffuse, directionalLight);
+03119 }
+03120 
+03121 // ***************************************************************************
+03122 void            CLandscape::setVegetableWind(const CVector &windDir, float windFreq, float windPower, float windBendMin)
+03123 {
+03124         // setup vegetable manager
+03125         _VegetableManager->setWind(windDir, windFreq, windPower, windBendMin);
+03126 }
+03127 
+03128 
+03129 // ***************************************************************************
+03130 void            CLandscape::setVegetableTime(double time)
+03131 {
+03132         // setup vegetable manager
+03133         _VegetableManager->setTime(time);
+03134 }
+03135 
+03136 // ***************************************************************************
+03137 void            CLandscape::setVegetableUpdateLightingTime(double time)
+03138 {
+03139         // setup vegetable manager
+03140         _VegetableManager->setUpdateLightingTime(time);
+03141 }
+03142 
+03143 
+03144 // ***************************************************************************
+03145 uint            CLandscape::getNumVegetableFaceRendered() const
+03146 {
+03147         return _VegetableManager->getNumVegetableFaceRendered();
+03148 }
+03149 
+03150 
+03151 // ***************************************************************************
+03152 const CTileVegetableDesc        &CLandscape::getTileVegetableDesc(uint16 tileId)
+03153 {
+03154         return TileBank.getTileVegetableDesc(tileId);
+03155 }
+03156 
+03157 
+03158 // ***************************************************************************
+03159 void            CLandscape::createVegetableBlendLayersModels(CScene *scene)
+03160 {
+03161         _VegetableManager->createVegetableBlendLayersModels(scene);
+03162 }
+03163 
+03164 
+03165 // ***************************************************************************
+03166 void            CLandscape::setVegetableUpdateLightingFrequency(float freq)
+03167 {
+03168         _VegetableManager->setUpdateLightingFrequency(freq);
+03169 }
+03170 
+03171 // ***************************************************************************
+03172 void            CLandscape::setupColorsFromTileFlags(const NLMISC::CRGBA colors[4])
+03173 {
+03174         for (TZoneMap::iterator it = Zones.begin(); it != Zones.end(); ++it)
+03175         {
+03176                 it->second->setupColorsFromTileFlags(colors);
+03177         }
+03178 }
+03179 
+03180 // ***************************************************************************
+03181 // ***************************************************************************
+03182 // Lightmap Get interface.
+03183 // ***************************************************************************
+03184 // ***************************************************************************
+03185 
+03186 
+03187 // ***************************************************************************
+03188 uint8           CLandscape::getLumel(const CPatchIdent &patchId, const CUV &uv) const
+03189 {
+03190         // \todo yoyo: TODO_ZONEID: change ZoneId in 32 bits...
+03191         std::map<uint16, CZone*>::const_iterator        it= Zones.find((uint16)patchId.ZoneId);
+03192         if(it!=Zones.end())
+03193         {
+03194                 sint    N= (*it).second->getNumPatchs();
+03195                 // patch must exist in the zone.
+03196                 nlassert(patchId.PatchId<N);
+03197                 const CPatch    *pa= const_cast<const CZone*>((*it).second)->getPatch(patchId.PatchId);
+03198 
+03199                 return pa->getLumel(uv);
+03200         }
+03201         else
+03202                 // Return full sun contribution as default
+03203                 return 255;
+03204 }
+03205 
+03206 // ***************************************************************************
+03207 void            CLandscape::appendTileLightInfluences(const CPatchIdent &patchId, const CUV &uv, 
+03208         std::vector<CPointLightInfluence> &pointLightList) const
+03209 {
+03210         // \todo yoyo: TODO_ZONEID: change ZoneId in 32 bits...
+03211         std::map<uint16, CZone*>::const_iterator        it= Zones.find((uint16)patchId.ZoneId);
+03212         if(it!=Zones.end())
+03213         {
+03214                 sint    N= (*it).second->getNumPatchs();
+03215                 // patch must exist in the zone.
+03216                 nlassert(patchId.PatchId<N);
+03217                 const CPatch    *pa= const_cast<const CZone*>((*it).second)->getPatch(patchId.PatchId);
+03218 
+03219                 pa->appendTileLightInfluences(uv, pointLightList);
+03220         }
+03221 }
+03222 
+03223 
+03224 // ***************************************************************************
+03225 // ***************************************************************************
+03226 // Lighting
+03227 // ***************************************************************************
+03228 // ***************************************************************************
+03229 
+03230 
+03231 // ***************************************************************************
+03232 void                    CLandscape::removeAllPointLights()
+03233 {
+03234         for(ItZoneMap it= Zones.begin();it!=Zones.end();it++)
+03235         {
+03236                 // for all patch.
+03237                 sint    N= (*it).second->getNumPatchs();
+03238                 for(sint i=0;i<N;i++)
+03239                 {
+03240                         // Clear TileLightInfluences
+03241                         CPatch  *pa= ((*it).second)->getPatch(i);
+03242                         pa->resetTileLightInfluences();
+03243                 }
+03244 
+03245                 // Remove all PointLights.
+03246                 (*it).second->_PointLightArray.clear();
+03247         }
+03248 
+03249 }
+03250 
+03251 
+03252 // ***************************************************************************
+03253 void                    CLandscape::setPointLightFactor(const std::string &lightGroupName, NLMISC::CRGBA nFactor)
+03254 {
+03255         // Store the result in the map for addZone().
+03256         _LightGroupColorMap[lightGroupName]= nFactor;
+03257 
+03258         // Affect currently added zones.
+03259         for(ItZoneMap it= Zones.begin();it!=Zones.end();it++)
+03260         {
+03261                 (*it).second->_PointLightArray.setPointLightFactor(lightGroupName, nFactor);
+03262         }
+03263 }
+03264 
+03265 
+03266 // ***************************************************************************
+03267 void                    CLandscape::updateLighting(double time)
+03268 {
+03269         _ULTime= time;
+03270 
+03271         // first time in this method??
+03272         if(!_ULPrecTimeInit)
+03273         {
+03274                 _ULPrecTimeInit= true;
+03275                 _ULPrecTime= _ULTime;
+03276         }
+03277         // compute delta time from last update.
+03278         float dt= float(_ULTime - _ULPrecTime);
+03279         _ULPrecTime= _ULTime;
+03280 
+03281 
+03282         // If not disabled
+03283         if(_ULFrequency)
+03284         {
+03285                 // Do it for near and far in 2 distinct ways.
+03286                 updateLightingTextureFar(dt * _ULFrequency);
+03287                 updateLightingTextureNear(dt * _ULFrequency);
+03288         }
+03289 
+03290 }
+03291 
+03292 
+03293 // ***************************************************************************
+03294 void                    CLandscape::updateLightingAll()
+03295 {
+03296         // Do it for near and far in 2 distinct ways.
+03297         //================
+03298         updateLightingTextureFar(1);
+03299         updateLightingTextureNear(1);
+03300 
+03301 
+03302         // update lighting for vegetables
+03303         //================
+03304 
+03305         // Must lock buffers for update Lighting of vegetables.
+03306         updateGlobalsAndLockBuffers (CVector::Null);
+03307 
+03308         // Because updateLighting() may use OptFastFloor..
+03309         OptFastFloorBegin();
+03310 
+03311         // update ALL lighting for vegetables
+03312         _VegetableManager->updateLightingAll();
+03313 
+03314         // Stop fastFloor optim.
+03315         OptFastFloorEnd();
+03316 
+03317         // Must realase VB Buffers
+03318         unlockBuffers();
+03319 }
+03320 
+03321 
+03322 // ***************************************************************************
+03323 void                    CLandscape::setUpdateLightingFrequency(float freq)
+03324 {
+03325         freq= max(freq, 0.f);
+03326         _ULFrequency= freq;
+03327 }
+03328 
+03329 
+03330 // ***************************************************************************
+03331 void                    CLandscape::linkPatchToNearUL(CPatch *patch)
+03332 {
+03333         // Append this patch to the list of patch to updateLighting.
+03334         if(_ULRootNearPatch==NULL)
+03335                 _ULRootNearPatch= patch;
+03336         else
+03337                 patch->linkBeforeNearUL(_ULRootNearPatch);
+03338 }
+03339 
+03340 // ***************************************************************************
+03341 void                    CLandscape::unlinkPatchFromNearUL(CPatch *patch)
+03342 {
+03343         // If I unlink the patch which is the current root
+03344         if(_ULRootNearPatch==patch)
+03345         {
+03346                 // switch to next
+03347                 _ULRootNearPatch= patch->getNextNearUL();
+03348                 // if still the same, it means that the circular list is now empty
+03349                 if(_ULRootNearPatch==patch)
+03350                         _ULRootNearPatch= NULL;
+03351                 // reset tessBlock counter.
+03352                 _ULNearCurrentTessBlockId= 0;
+03353         }
+03354 
+03355         // unlink the patch from list
+03356         patch->unlinkNearUL();
+03357 }
+03358 
+03359 
+03360 // ***************************************************************************
+03361 void                    CLandscape::updateLightingTextureFar(float ratio)
+03362 {
+03363         // compute number of pixels to update.
+03364         _ULFarPixelsToUpdate+= ratio * _ULTotalFarPixels;
+03365         // maximize, so at max, it computes all patchs, just one time.
+03366         _ULFarPixelsToUpdate= min(_ULFarPixelsToUpdate, (float)_ULTotalFarPixels);
+03367 
+03368         // Test Profile Yoyo
+03369         /*extern bool YOYO_LandULTest;
+03370         if(YOYO_LandULTest)
+03371         {
+03372                 nlinfo("YOYO_UL Far: %dK, %dK", (sint)_ULFarPixelsToUpdate/1024, (sint)_ULTotalFarPixels/1024);
+03373         }*/
+03374 
+03375         // while there is still some pixels to update.
+03376         while(_ULFarPixelsToUpdate > 0 && _ULRootTextureFar)
+03377         {
+03378                 // update patch (if not null) in the textureFar.
+03379                 _ULFarPixelsToUpdate-= _ULRootTextureFar->touchPatch(_ULFarCurrentPatchId);
+03380                 // Next patch to process.
+03381                 _ULFarCurrentPatchId++;
+03382 
+03383                 // last patch in the texture??
+03384                 if(_ULFarCurrentPatchId>=NL_NUM_FAR_PATCHES_BY_TEXTURE)
+03385                 {
+03386                         // yes, go to next texture.
+03387                         _ULRootTextureFar= _ULRootTextureFar->getNextUL();
+03388                         // reset to 0th patch.
+03389                         _ULFarCurrentPatchId=0;
+03390                 }
+03391         }
+03392 
+03393         // Now, _ULFarPixelsToUpdate should be <=0. (most of the time < 0)
+03394 }
+03395 
+03396 
+03397 // ***************************************************************************
+03398 void                    CLandscape::updateLightingTextureNear(float ratio)
+03399 {
+03400         // compute number of pixels to update.
+03401         _ULNearPixelsToUpdate+= ratio * _ULTotalNearPixels;
+03402         // maximize, so at max, it computes all patchs, just one time.
+03403         _ULNearPixelsToUpdate= min(_ULNearPixelsToUpdate, (float)_ULTotalNearPixels);
+03404 
+03405 
+03406         // while there is still some pixels to update.
+03407         while(_ULNearPixelsToUpdate > 0 && _ULRootNearPatch)
+03408         {
+03409                 // update tessBlock (if lightmap exist for this tessBlock) in the patch.
+03410                 _ULNearPixelsToUpdate-= _ULRootNearPatch->updateTessBlockLighting(_ULNearCurrentTessBlockId);
+03411                 // Next tessBlock to process.
+03412                 _ULNearCurrentTessBlockId++;
+03413 
+03414                 // last tessBlock in the patch??
+03415                 if(_ULNearCurrentTessBlockId>=_ULRootNearPatch->getNumNearTessBlocks())
+03416                 {
+03417                         // yes, go to next patch.
+03418                         _ULRootNearPatch= _ULRootNearPatch->getNextNearUL();
+03419                         // reset to 0th tessBlock.
+03420                         _ULNearCurrentTessBlockId=0;
+03421                 }
+03422         }
+03423 
+03424 }
+03425 
+03426 
+03427 // ***************************************************************************
+03428 void                    CLandscape::computeDynamicLighting(const std::vector<CPointLight*>      &pls)
+03429 {
+03430         uint    i;
+03431 
+03432         // Update globals, and lock buffers
+03433         //====================
+03434         updateGlobalsAndLockBuffers (CVector::Null);
+03435         // NB: averageTesselationVertices may change vertices in VB in visible patchs => buffers are locked.
+03436 
+03437 
+03438         // Run all DLM Context create, to init Lighting process.
+03439         //===============
+03440         CPatchDLMContext        *ctxPtr= _PatchDLMContextList->begin();
+03441         while(ctxPtr!=NULL)
+03442         {
+03443                 // init lighting process, do differential from last computeDynamicLighting()
+03444                 ctxPtr->getPatch()->beginDLMLighting();
+03445 
+03446                 // next
+03447                 ctxPtr= (CPatchDLMContext*)ctxPtr->Next;
+03448         }
+03449 
+03450 
+03451         // compile all pointLights
+03452         //===============
+03453         static vector<CPatchDLMPointLight>      dlmPls;
+03454         dlmPls.resize(pls.size());
+03455         for(i=0;i<dlmPls.size();i++)
+03456         {
+03457                 // compile the pl.
+03458                 dlmPls[i].compile(*pls[i], _PointLightDiffuseMaterial, _DLMMaxAttEnd);
+03459         }
+03460 
+03461 
+03462         // For all pointLight, intersect patch.
+03463         //===============
+03464         for(i=0;i<dlmPls.size();i++)
+03465         {
+03466                 CPatchDLMPointLight     &pl= dlmPls[i];
+03467 
+03468                 // search patchs of interest: those which interssect the pointLight
+03469                 _PatchQuadGrid.clearSelection();
+03470                 _PatchQuadGrid.select(pl.BBox.getMin(), pl.BBox.getMax());
+03471                 CQuadGrid<CPatchIdentEx>::CIterator     it;
+03472 
+03473                 // for each patch, light it with the light.
+03474                 for(it= _PatchQuadGrid.begin(); it!= _PatchQuadGrid.end(); it++)
+03475                 {
+03476                         // get the patch
+03477                         const CPatch    *pa= (*it).Patch;
+03478 
+03479                         // More precise clipping: 
+03480                         if( pa->getBSphere().intersect( pl.BSphere ) )
+03481                         {
+03482                                 // Ok, light the patch with this spotLight
+03483                                 const_cast<CPatch*>(pa)->processDLMLight(pl);
+03484                         }
+03485                 }
+03486 
+03487         }
+03488 
+03489 
+03490         // Run all DLM Context create, to end Lighting process.
+03491         //===============
+03492         ctxPtr= _PatchDLMContextList->begin();
+03493         while(ctxPtr!=NULL)
+03494         {
+03495                 // get enxt now, because the DLM itself may be deleted in endDLMLighting()
+03496                 CPatchDLMContext        *next= (CPatchDLMContext*)ctxPtr->Next;
+03497 
+03498                 // delete the DLM if no more needed (near don't use nor pointLights)
+03499                 ctxPtr->getPatch()->endDLMLighting();
+03500 
+03501                 // next
+03502                 ctxPtr= next;
+03503         }
+03504 
+03505 
+03506         // Must realase VB Buffers
+03507         //====================
+03508         unlockBuffers();
+03509 
+03510 }
+03511 
+03512 
+03513 // ***************************************************************************
+03514 void                    CLandscape::setDynamicLightingMaxAttEnd(float maxAttEnd)
+03515 {
+03516         maxAttEnd= max(maxAttEnd, 1.f);
+03517         _DLMMaxAttEnd= maxAttEnd;
+03518 }
+03519 
+03520 
+03521 // ***************************************************************************
+03522 uint                    CLandscape::getDynamicLightingMemoryLoad() const
+03523 {
+03524         uint    mem= 0;
+03525         // First, set size of global texture overhead.
+03526         mem= NL3D_LANDSCAPE_DLM_WIDTH * NL3D_LANDSCAPE_DLM_HEIGHT * sizeof(CRGBA);
+03527 
+03528         // Then, for each patchContext created
+03529         CPatchDLMContext        *ctxPtr= _PatchDLMContextList->begin();
+03530         while(ctxPtr!=NULL)
+03531         {
+03532                 // add its memory load.
+03533                 mem+= ctxPtr->getMemorySize();
+03534 
+03535                 // next
+03536                 ctxPtr= (CPatchDLMContext*)ctxPtr->Next;
+03537         }
+03538 
+03539         return mem;
+03540 }
+03541 
+03542 
+03543 // ***************************************************************************
+03544 void                    CLandscape::setDLMGlobalVegetableColor(CRGBA gvc)
+03545 {
+03546         _DLMGlobalVegetableColor= gvc;
+03547 }
+03548 
+03549 
+03550 // ***************************************************************************
+03551 void                    CLandscape::setPointLightDiffuseMaterial(CRGBA diffuse)
+03552 {
+03553         _PointLightDiffuseMaterial= diffuse;
+03554 }
+03555 
+03556 
+03557 } // NL3D
+
+ + +
                                                                                                                                                                    +
+ + -- cgit v1.2.1