# 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