Linux multi-monitor fullscreen support
[ryzomcore.git] / nel / src / 3d / landscape.cpp
blobb02a36958c1fbd55afb60234bbffb794b8839500
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "std3d.h"
23 #include "nel/3d/landscape.h"
24 #include "nel/3d/landscape_model.h"
25 #include "nel/misc/bsphere.h"
26 #include "nel/3d/texture_file.h"
27 #include "nel/3d/texture_far.h"
28 #include "nel/3d/landscape_profile.h"
29 #include "nel/3d/height_map.h"
30 #include "nel/3d/tile_noise_map.h"
31 #include "nel/3d/vegetable_manager.h"
32 #include "nel/3d/vegetable.h"
33 #include "nel/3d/landscape_vegetable_block.h"
34 #include "nel/misc/fast_floor.h"
35 #include "nel/3d/tile_vegetable_desc.h"
36 #include "nel/3d/texture_dlm.h"
37 #include "nel/3d/patchdlm_context.h"
38 #include "nel/misc/hierarchical_timer.h"
39 #include "nel/3d/scene.h"
42 #include "nel/3d/vertex_program.h"
44 using namespace NLMISC;
45 using namespace std;
47 #ifdef DEBUG_NEW
48 #define new DEBUG_NEW
49 #endif
52 namespace NL3D
56 // ***************************************************************************
58 Target is 20K faces in frustum.
59 So 80K faces at same time
60 So 160K elements (bin tree).
61 A good BlockSize (in my opinion) is EstimatedMaxSize / 10, to have less memory leak as possible,
62 and to make not so many system allocation.
64 NL3D_TESSRDR_ALLOC_BLOCKSIZE is 2 times less, because elements are in Far zone or in Near zone only
65 (approx same size...)
67 #define NL3D_TESS_ALLOC_BLOCKSIZE 16000
68 #define NL3D_TESSRDR_ALLOC_BLOCKSIZE 8000
71 // ***************************************************************************
72 // This value is important for the precision of the priority list
73 #define NL3D_REFINE_PLIST_DIST_STEP 0.0625
74 /* This value is important, because faces will be inserted at maximum at this entry in the priority list.
75 If not so big (eg 50 meters), a big bunch of faces may be inserted in this entry, which may cause slow down
76 sometimes, when all this bunch comes to 0 in the priority list.
77 To avoid such a thing, see CTessFacePriorityList::init(), and use of NL3D_REFINE_PLIST_DIST_MAX_MOD.
78 Here, distMax= 2048*0.0625= 128
80 #define NL3D_REFINE_PLIST_NUM_ENTRIES 2048
81 #define NL3D_REFINE_PLIST_DIST_MAX_MOD 0.7f
82 // For the Split priority list only, numbers of quadrants. MergeList has 0 quadrants.
83 #define NL3D_REFINE_PLIST_SPLIT_NUMQUADRANT 16
87 OverHead size of one RollingTable of priority list is 8 * (NL3D_REFINE_PLIST_NUM_ENTRIES)
88 So here, it is "only" 16K.
90 Since we have 2 Priority list and 16 quadrants for the split one, the total overhead is 18*12.8= 288K
94 // ***************************************************************************
95 // Size (in cases) of the quadgrid. must be e power of 2.
96 const uint CLandscape::_PatchQuadGridSize= 128;
97 // Size of a case of the quadgrid.
98 const float CLandscape::_PatchQuadGridEltSize= 16;
101 // ***************************************************************************
103 // Bitmap Cross
105 class CTextureCross : public ITexture
107 public:
109 * Generate the texture
110 * \author Stephane Coutelas
111 * \date 2000
113 virtual void doGenerate(bool /* async */)
115 // Resize
116 resize (16, 16);
118 // Cross
119 static const uint32 cross[16*16]=
121 // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
122 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
123 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
124 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
125 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
126 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
127 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
128 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
129 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
130 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
131 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
132 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
133 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
134 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
135 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
136 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
137 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
140 // Null
141 memcpy (&_Data[0][0], cross, 16*16*4);
144 // Dummy serial...
145 virtual void serial(NLMISC::IStream &/* f */) { nlstop; }
146 NLMISC_DECLARE_CLASS(CTextureCross);
150 // ***************************************************************************
151 const char *EBadBind::what() const throw()
153 sint numErr= 0;
154 const sint NErrByLines= 4;
156 _Output= "Landscape Bind Error in (3DSMax indices!! (+1) ): ";
158 std::list<CBindError>::const_iterator it;
159 for(it= BindErrors.begin();it!=BindErrors.end(); it++, numErr++)
161 char tmp[256];
162 sint x= it->ZoneId & 255;
163 sint y= it->ZoneId >> 8;
164 sprintf(tmp, "zone%3d_%c%c.patch%3d; ", y+1, (char)('A'+(x/26)), (char)('A'+(x%26)), it->PatchId+1);
165 if( (numErr%NErrByLines) == 0)
166 _Output+= "\n";
167 _Output+= tmp;
169 return _Output.c_str();
173 // ***************************************************************************
174 // Init BlockAllcoator with standard BlockMemory.
175 CLandscape::CLandscape() :
176 TessFaceAllocator(NL3D_TESS_ALLOC_BLOCKSIZE),
177 TessVertexAllocator(NL3D_TESS_ALLOC_BLOCKSIZE),
178 TessNearVertexAllocator(NL3D_TESSRDR_ALLOC_BLOCKSIZE),
179 TessFarVertexAllocator(NL3D_TESSRDR_ALLOC_BLOCKSIZE),
180 TileMaterialAllocator(NL3D_TESSRDR_ALLOC_BLOCKSIZE),
181 TileFaceAllocator(NL3D_TESSRDR_ALLOC_BLOCKSIZE),
182 _Far0VB(CLandscapeVBAllocator::Far0, "LandscapeFar0VB"),
183 _Far1VB(CLandscapeVBAllocator::Far1, "LandscapeFar1VB"),
184 _TileVB(CLandscapeVBAllocator::Tile, "LandscapeTileVB")
186 OwnerModel = NULL;
188 // Init the Tile Infos with Max TileId
189 TileInfos.resize(NL3D::NbTilesMax, NULL);
191 // Far texture not initialized till initTileBanks is not called
192 _FarInitialized=false;
194 // Init far lighting with White/black
195 setupStaticLight (CRGBA(255,255,255), CRGBA(0,0,0), 1.f);
196 // Default material for pointLights
197 _PointLightDiffuseMaterial= CRGBA::White;
199 _FarTransition= 10; // 10 meters.
200 _TileDistNear=100.f;
201 _Threshold= 0.001f;
202 _RefineMode=true;
204 _TileMaxSubdivision= 0;
206 _NFreeLightMaps= 0;
208 // By default Automatic light comes from up.
209 _AutomaticLighting = false;
210 _AutomaticLightDir= -CVector::K;
212 // By default, noise is enabled.
213 _NoiseEnabled= true;
215 // By default, we compute Geomorph and Alpha in software.
216 _VertexShaderOk= false;
217 _VPThresholdChange= false;
219 _RenderMustRefillVB= false;
221 // priority list.
222 _MustRefineAllAtNextRefine= true;
223 _SplitPriorityList.init(NL3D_REFINE_PLIST_DIST_STEP, NL3D_REFINE_PLIST_NUM_ENTRIES, NL3D_REFINE_PLIST_DIST_MAX_MOD, NL3D_REFINE_PLIST_SPLIT_NUMQUADRANT);
224 // See updateRefine* Doc in tesselation.cpp for why the merge list do not need quadrants.
225 _MergePriorityList.init(NL3D_REFINE_PLIST_DIST_STEP, NL3D_REFINE_PLIST_NUM_ENTRIES, NL3D_REFINE_PLIST_DIST_MAX_MOD, 0);
226 // just for getTesselatedPos to work properly.
227 _OldRefineCenter= CVector::Null;
229 // create / Init the vegetable manager.
230 _VegetableManager= new CVegetableManager(NL3D_LANDSCAPE_VEGETABLE_MAX_AGP_VERTEX_UNLIT, NL3D_LANDSCAPE_VEGETABLE_MAX_AGP_VERTEX_LIGHTED);
232 // Init vegetable setup.
233 _VegetableManagerEnabled= false;
234 _DriverOkForVegetable= false;
235 // default global vegetable color, used for dynamic lighting only (arbitrary).
236 _DLMGlobalVegetableColor.set(180, 180, 180);
238 _PZBModelPosition= CVector::Null;
241 // Default: no updateLighting.
242 _ULFrequency= 0;
243 _ULPrecTimeInit= false;
244 // Default: no textureFar created.
245 _ULTotalFarPixels= 0;
246 _ULFarPixelsToUpdate= 0;
247 _ULRootTextureFar= NULL;
248 // Default: no patch created
249 _ULTotalNearPixels= 0;
250 _ULNearPixelsToUpdate= 0;
251 _ULRootNearPatch= NULL;
252 _ULNearCurrentTessBlockId= 0;
255 // Dynamic Lighting.
256 _TextureDLM= new CTextureDLM(NL3D_LANDSCAPE_DLM_WIDTH, NL3D_LANDSCAPE_DLM_HEIGHT);
257 _PatchDLMContextList= new CPatchDLMContextList;
258 _DLMMaxAttEnd= 30.f;
260 CLandscapeGlobals::PassTriArray.setFormat(NL_LANDSCAPE_INDEX_FORMAT);
262 // Alloc some global space for tri rendering.
263 if( CLandscapeGlobals::PassTriArray.getNumIndexes() < 1000 )
264 CLandscapeGlobals::PassTriArray.setNumIndexes( 1000 );
266 // set volatile index buffer to avoid stalls
267 CLandscapeGlobals::PassTriArray.setPreferredMemory(CIndexBuffer::RAMVolatile, false);
269 _LockCount = 0;
271 _TextureTileCategory= new ITexture::CTextureCategory("LANDSCAPE TILES");
272 _TextureFarCategory= new ITexture::CTextureCategory("LANDSCAPE FAR");
273 _TextureNearCategory= new ITexture::CTextureCategory("LANDSCAPE LIGHTMAP NEAR");
276 // ***************************************************************************
277 CLandscape::~CLandscape()
279 clear();
281 // release the VegetableManager.
282 delete _VegetableManager;
283 _VegetableManager= NULL;
285 // Dynamic Lighting.
286 // smartPtr delete
287 _TextureDLM= NULL;
288 delete _PatchDLMContextList;
289 _PatchDLMContextList= NULL;
293 // ***************************************************************************
294 void CLandscape::init()
296 // Fill Far mat.
297 // Must init his BlendFunction here!!! becaus it switch between blend on/off during rendering.
298 FarMaterial.initUnlit();
299 FarMaterial.setSrcBlend(CMaterial::srcalpha);
300 FarMaterial.setDstBlend(CMaterial::invsrcalpha);
302 // FarMaterial: pass trhough Alpha from diffuse.
303 FarMaterial.texEnvOpAlpha(0, CMaterial::Replace);
304 FarMaterial.texEnvArg0Alpha(0, CMaterial::Diffuse, CMaterial::SrcAlpha);
305 FarMaterial.texEnvOpAlpha(1, CMaterial::Replace);
306 FarMaterial.texEnvArg0Alpha(1, CMaterial::Diffuse, CMaterial::SrcAlpha);
307 // FarMaterial: Add RGB from static lightmap and dynamic lightmap
308 FarMaterial.texEnvOpRGB(0, CMaterial::Replace);
309 FarMaterial.texEnvArg0RGB(0, CMaterial::Texture, CMaterial::SrcColor);
310 FarMaterial.texEnvOpRGB(1, CMaterial::Add);
311 FarMaterial.texEnvArg0RGB(1, CMaterial::Texture, CMaterial::SrcColor);
312 FarMaterial.texEnvArg1RGB(1, CMaterial::Previous, CMaterial::SrcColor);
315 // Init material for tile.
316 TileMaterial.initUnlit();
318 // init quadGrid.
319 _PatchQuadGrid.create(_PatchQuadGridSize, _PatchQuadGridEltSize);
323 // ***************************************************************************
324 void CLandscape::setThreshold (float thre)
326 thre= max(thre, 0.f);
327 if(thre != _Threshold)
329 _Threshold= thre;
330 _VPThresholdChange= true;
331 // force refine all at next refine
332 _MustRefineAllAtNextRefine= true;
337 // ***************************************************************************
338 void CLandscape::setTileNear (float tileNear)
340 tileNear= max(tileNear, _FarTransition);
342 if(tileNear!=_TileDistNear)
344 _TileDistNear= tileNear;
345 resetRenderFarAndDeleteVBFV();
346 // force refine all at next refine
347 _MustRefineAllAtNextRefine= true;
353 // ***************************************************************************
354 void CLandscape::setTileMaxSubdivision (uint tileDiv)
356 nlassert(tileDiv<=4);
358 if(tileDiv!=_TileMaxSubdivision)
360 _TileMaxSubdivision= tileDiv;
361 // Force at Tile==0. Nex refine will split correctly.
362 forceMergeAtTileLevel();
365 // ***************************************************************************
366 uint CLandscape::getTileMaxSubdivision ()
368 return _TileMaxSubdivision;
372 // ***************************************************************************
373 void CLandscape::resetRenderFarAndDeleteVBFV()
375 // For all patch of all zones.
376 for(ItZoneMap it= Zones.begin();it!=Zones.end();it++)
378 ((*it).second)->resetRenderFarAndDeleteVBFV();
383 // ***************************************************************************
384 void CLandscape::forceMergeAtTileLevel()
386 // For all patch of all zones.
387 for(ItZoneMap it= Zones.begin();it!=Zones.end();it++)
389 ((*it).second)->forceMergeAtTileLevel();
394 // ***************************************************************************
395 bool CLandscape::addZone(const CZone &newZone)
397 // -1. Update globals
398 updateGlobalsAndLockBuffers (CVector::Null);
399 // NB: adding a zone may add vertices in VB in visible patchs (because of binds)=> buffers are locked.
401 uint16 zoneId= newZone.getZoneId();
403 if(Zones.find(zoneId)!=Zones.end())
405 unlockBuffers();
406 return false;
408 CZone *zone= new CZone;
410 // copy zone.
411 zone->build(newZone);
413 // Affect the current lighting of pointLight to the zone.
414 if (OwnerModel)
416 CScene *scene = OwnerModel->getOwnerScene();
417 zone->_PointLightArray.initAnimatedLightIndex(*scene);
418 zone->_PointLightArray.setPointLightFactor(*scene);
421 // apply the landscape heightField, modifying BBoxes.
422 zone->applyHeightField(*this);
424 // compile the zone for this landscape.
425 zone->compile(this, Zones);
427 // For test of _PatchQuadGrid erase.
428 CAABBox zoneBBForErase= zone->getZoneBB().getAABBox();
429 // Avoid precision problems by enlarging a little bbox size of zone for erase
430 zoneBBForErase.setHalfSize( zoneBBForErase.getHalfSize() * 1.1f);
432 // add patchs of this zone to the quadgrid.
433 for(sint i= 0; i<zone->getNumPatchs(); i++)
435 const CPatch *pa= ((const CZone*)zone)->getPatch(i);
436 CPatchIdentEx paId;
437 paId.ZoneId= zoneId;
438 paId.PatchId= uint16(i);
439 paId.Patch= pa;
440 CAABBox bb= pa->buildBBox();
441 _PatchQuadGrid.insert(bb.getMin(), bb.getMax(), paId);
442 // NB: the bbox of zone is used to remove patch. Hence it is VERY important that zoneBBox includes
443 // all patchs bbox (else some patchs entries may not be deleted in removeZone()).
444 nlassert(zoneBBForErase.include(bb));
447 // Must realase VB Buffers
448 unlockBuffers();
450 // Because bind may add faces in other (visible) zones because of enforced split, we must check
451 // and update any FaceVector.
452 updateTessBlocksFaceVector();
454 return true;
456 // ***************************************************************************
457 bool CLandscape::removeZone(uint16 zoneId)
459 // -1. Update globals
460 updateGlobalsAndLockBuffers (CVector::Null);
461 // NB: remove a zone may change vertices in VB in visible patchs => buffers are locked.
463 // find the zone.
464 if(Zones.find(zoneId)==Zones.end())
466 unlockBuffers();
467 return false;
469 CZone *zone= Zones[zoneId];
472 // delete patchs from this zone to the quadgrid.
473 // use the quadgrid itself to find where patch are. do this using bbox of zone.
474 CAABBox zoneBBForErase= zone->getZoneBB().getAABBox();
475 // Avoid precision problems by enlarging a little bbox size of zone for erase
476 zoneBBForErase.setHalfSize( zoneBBForErase.getHalfSize() * 1.1f);
477 // select iterators in the area of this zone.
478 _PatchQuadGrid.clearSelection();
479 _PatchQuadGrid.select(zoneBBForErase.getMin(), zoneBBForErase.getMax());
480 // for each patch, remove it if from deleted zone.
481 CQuadGrid<CPatchIdentEx>::CIterator it;
482 sint nPatchRemoved= 0;
483 for(it= _PatchQuadGrid.begin(); it!= _PatchQuadGrid.end();)
485 // if the patch belong to the zone to remove
486 if( (*it).ZoneId== zone->getZoneId() )
488 // remove from the quadgrid.
489 it= _PatchQuadGrid.erase(it);
490 nPatchRemoved++;
492 else
493 it++;
495 // verify we have removed all patch in the quadGrid for this zone
496 nlassert(nPatchRemoved==zone->getNumPatchs());
499 // remove the zone.
500 zone->release(Zones);
501 delete zone;
503 // Must realase VB Buffers
504 unlockBuffers();
506 // because of forceMerge() at unbind, removeZone() can cause change in faces in other (visible) zones.
507 updateTessBlocksFaceVector();
509 return true;
511 // ***************************************************************************
512 void CLandscape::getZoneList(std::vector<uint16> &zoneIds) const
514 zoneIds.clear();
515 zoneIds.reserve(Zones.size());
516 std::map<uint16, CZone*>::const_iterator it;
517 for(it= Zones.begin();it!=Zones.end();it++)
519 zoneIds.push_back((*it).first);
522 // ***************************************************************************
523 void CLandscape::buildZoneName(sint zoneId, std::string &zoneName)
525 char tmp[256];
526 sint x= zoneId & 255;
527 sint y= zoneId >> 8;
528 sprintf(tmp, "%d_%c%c", y+1, (char)('A'+(x/26)), (char)('A'+(x%26)));
529 zoneName= tmp;
531 // ***************************************************************************
532 void CLandscape::clear()
534 // Build the list of zoneId.
535 vector<uint16> zoneIds;
536 getZoneList(zoneIds);
538 // Remove each zone one by one.
539 sint i;
540 for(i=0;i<(sint)zoneIds.size();i++)
542 nlverify(removeZone(zoneIds[i]));
545 // ensure the quadgrid is empty.
546 _PatchQuadGrid.clear();
548 releaseAllTiles();
550 // If not done, delete all VBhards allocated.
551 _Far0VB.clear();
552 _Far1VB.clear();
553 _TileVB.clear();
556 // Reset All Far Texture and unlink _ULRootTextureFar ciruclarList.
557 ItSPRenderPassVector itFar= _TextureFars.begin();
558 // unitl set is empty
559 while( itFar != _TextureFars.end() )
561 // erase with link update.
562 clearFarRenderPass(*itFar);
563 itFar++;
565 // delete all
566 _TextureFars.clear();
569 // reset driver.
570 _Driver= NULL;
573 // ***************************************************************************
574 void CLandscape::setDriver(IDriver *drv)
576 nlassert(drv);
577 if (_Driver != drv)
579 _Driver= drv;
581 // Does the driver support VertexShader???
582 // only if VP supported by GPU.
583 _VertexShaderOk = (!_Driver->isVertexProgramEmulated() && (
584 _Driver->supportVertexProgram(CVertexProgram::nelvp)
585 // || _Driver->supportVertexProgram(CVertexProgram::glsl330v) // TODO_VP_GLSL
589 // Does the driver has sufficient requirements for Vegetable???
590 // only if VP supported by GPU, and Only if max vertices allowed.
591 _DriverOkForVegetable = _VertexShaderOk && (_Driver->getMaxVerticesByVertexBufferHard()>=(uint)NL3D_LANDSCAPE_VEGETABLE_MAX_AGP_VERTEX_MAX);
595 // ***************************************************************************
596 void CLandscape::clip(const CVector &refineCenter, const std::vector<CPlane> &pyramid)
598 // -1. Update globals
599 updateGlobalsAndLockBuffers (refineCenter);
600 // NB: clip may add/remove vertices in VB in visible patchs => buffers are locked.
603 for(ItZoneMap it= Zones.begin();it!=Zones.end();it++)
605 (*it).second->clip(pyramid);
608 // Must realase VB Buffers
609 unlockBuffers();
611 // clip() should not cause change in faces in visible patchs.
612 // It should not happens, but check for security.
613 nlassert(_TessBlockModificationRoot.getNextToModify()==NULL);
614 updateTessBlocksFaceVector();
617 // ***************************************************************************
618 void CLandscape::refine(const CVector &refineCenter)
620 NL3D_PROFILE_LAND_SET(ProfNRefineFaces, 0);
621 NL3D_PROFILE_LAND_SET(ProfNRefineComputeFaces, 0);
622 NL3D_PROFILE_LAND_SET(ProfNRefineLeaves, 0);
623 NL3D_PROFILE_LAND_SET(ProfNSplits, 0);
624 NL3D_PROFILE_LAND_SET(ProfNMerges, 0);
625 NL3D_PROFILE_LAND_SET(ProfNRefineInTileTransition, 0);
626 NL3D_PROFILE_LAND_SET(ProfNRefineWithLowDistance, 0);
627 NL3D_PROFILE_LAND_SET(ProfNSplitsPass, 0);
629 if(!_RefineMode)
630 return;
632 // Update the priority list.
633 // ==========================
634 CTessFacePListNode rootSplitTessFaceToUpdate;
635 CTessFacePListNode rootMergeTessFaceToUpdate;
636 if( _MustRefineAllAtNextRefine )
638 // ok, first pass done, setup OldRefineCetner
639 _MustRefineAllAtNextRefine= false;
640 _OldRefineCenter= refineCenter;
642 // then shift all faces
643 _SplitPriorityList.shiftAll(rootSplitTessFaceToUpdate);
644 _MergePriorityList.shiftAll(rootMergeTessFaceToUpdate);
646 else
648 // else, compute delta between positions
649 CVector diff= refineCenter - _OldRefineCenter;
650 _OldRefineCenter= refineCenter;
652 // and shift according to distance of deplacement.
653 _SplitPriorityList.shift(diff, rootSplitTessFaceToUpdate);
654 _MergePriorityList.shift(diff, rootMergeTessFaceToUpdate);
658 // Refine Faces which may need it.
659 // ==========================
660 // Update globals
661 updateGlobalsAndLockBuffers (refineCenter);
662 // NB: refine may change vertices in VB in visible patchs => buffers are locked.
664 // Increment the update date.
665 CLandscapeGlobals::CurrentDate++;
667 // Because CTessFacePriorityList::insert use it.
668 NLMISC::OptFastFloorBegin();
670 /* While there is still face in list, update them
671 NB: updateRefine() always insert the face in _***PriorityList, so face is removed from
672 root***TessFaceToUpdate list.
673 NB: it is possible ( with enforced merge() ) that faces dissapears from root***TessFaceToUpdate list
674 before they are traversed here. It is why we must use a Circular list system, and not an array of elements.
675 Basically. TessFaces are ALWAYS in a list, either in one of the entry list in _***PriorityList, or in
676 root***TessFaceToUpdate list.
678 It is newTessFace() and deleteTessFace() which insert/remove the nodes in the list.
680 // Update the Merge priority list.
681 while( rootMergeTessFaceToUpdate.nextInPList() != &rootMergeTessFaceToUpdate )
683 // Get the face.
684 CTessFace *face= static_cast<CTessFace*>(rootMergeTessFaceToUpdate.nextInPList());
686 // update the refine of this face. This may lead in deletion (merge) of other faces which are still in
687 // root***TessFaceToUpdate, but it's work.
688 face->updateRefineMerge();
692 // Update the Split priority list.
695 NL3D_PROFILE_LAND_ADD(ProfNSplitsPass, 1);
697 // Append the new leaves, to the list of triangles to update
698 rootSplitTessFaceToUpdate.appendPList(_RootNewLeaves);
700 // While triangle to test for split exists
701 while( rootSplitTessFaceToUpdate.nextInPList() != &rootSplitTessFaceToUpdate )
703 // Get the face.
704 CTessFace *face= static_cast<CTessFace*>(rootSplitTessFaceToUpdate.nextInPList());
706 // update the refine of this face.
707 face->updateRefineSplit();
711 // do it until we are sure no more split is needed, ie no more faces are created
712 while( _RootNewLeaves.nextInPList() != &_RootNewLeaves );
714 // Because CTessFacePriorityList::insert use it.
715 NLMISC::OptFastFloorEnd();
718 // Before unlockBuffers, test for vegetable IG creation.
720 H_AUTO( NL3D_Vegetable_Update );
722 // Because CLandscapeVegetableBlock::update() use OptFastFloor..
723 NLMISC::OptFastFloorBegin();
725 // For each vegetableBlock, test IG creation
726 CLandscapeVegetableBlock *vegetBlock= _VegetableBlockList.begin();
727 for(;vegetBlock!=NULL; vegetBlock= (CLandscapeVegetableBlock*)vegetBlock->Next)
729 vegetBlock->update(refineCenter, _VegetableManager);
732 // update lighting for vegetables
733 _VegetableManager->updateLighting();
735 // Stop fastFloor optim.
736 NLMISC::OptFastFloorEnd();
740 // Must realase VB Buffers
741 unlockBuffers();
743 // refine() may cause change in faces in visible patchs.
744 updateTessBlocksFaceVector();
749 // ***************************************************************************
750 void CLandscape::refineAll(const CVector &refineCenter)
752 // -1. Update globals
753 updateGlobalsAndLockBuffers (refineCenter);
754 // NB: refineAll may change vertices in VB in visible patchs => buffers are locked.
756 // Increment the update date.
757 CLandscapeGlobals::CurrentDate++;
759 for(ItZoneMap it= Zones.begin();it!=Zones.end();it++)
761 (*it).second->refineAll();
764 // Must realase VB Buffers
765 unlockBuffers();
767 // refineAll() may cause change in faces in visible patchs.
768 updateTessBlocksFaceVector();
772 // ***************************************************************************
773 void CLandscape::excludePatchFromRefineAll(sint zoneId, uint patch, bool exclude)
775 ItZoneMap it= Zones.find(uint16(zoneId));
776 if(it!=Zones.end())
778 it->second->excludePatchFromRefineAll(patch, exclude);
784 // ***************************************************************************
785 void CLandscape::averageTesselationVertices()
787 // -1. Update globals
788 updateGlobalsAndLockBuffers (CVector::Null);
789 // NB: averageTesselationVertices may change vertices in VB in visible patchs => buffers are locked.
791 // Increment the update date.
792 CLandscapeGlobals::CurrentDate++;
794 for(ItZoneMap it= Zones.begin();it!=Zones.end();it++)
796 (*it).second->averageTesselationVertices();
799 // Must realase VB Buffers
800 unlockBuffers();
802 // averageTesselationVertices() should not cause change in faces in any patchs.
803 // It should not happens, but check for security.
804 nlassert(_TessBlockModificationRoot.getNextToModify()==NULL);
805 updateTessBlocksFaceVector();
811 // ***************************************************************************
812 void CLandscape::updateGlobalsAndLockBuffers (const CVector &refineCenter)
814 // Setup CLandscapeGlobals static members...
816 // Far limits.
817 CLandscapeGlobals::FarTransition= _FarTransition;
819 // Tile subdivsion part.
820 CLandscapeGlobals::TileMaxSubdivision= _TileMaxSubdivision;
821 CLandscapeGlobals::TileDistNear = _TileDistNear;
822 CLandscapeGlobals::TileDistFar = CLandscapeGlobals::TileDistNear+20;
823 CLandscapeGlobals::TileDistNearSqr = sqr(CLandscapeGlobals::TileDistNear);
824 CLandscapeGlobals::TileDistFarSqr = sqr(CLandscapeGlobals::TileDistFar);
825 CLandscapeGlobals::OOTileDistDeltaSqr = 1.0f / (CLandscapeGlobals::TileDistFarSqr - CLandscapeGlobals::TileDistNearSqr);
827 // Tile Pixel size part.
828 // \todo yoyo: choose according to wanted tile pixel size.
829 CLandscapeGlobals::TilePixelSize= 128.0f;
830 CLandscapeGlobals::TilePixelBias128= 0.5f/CLandscapeGlobals::TilePixelSize;
831 CLandscapeGlobals::TilePixelScale128= 1-1/CLandscapeGlobals::TilePixelSize;
832 CLandscapeGlobals::TilePixelBias256= 0.5f/(CLandscapeGlobals::TilePixelSize*2);
833 CLandscapeGlobals::TilePixelScale256= 1-1/(CLandscapeGlobals::TilePixelSize*2);
835 // RefineThreshold.
836 CLandscapeGlobals::RefineThreshold= _Threshold;
838 if (_Threshold == 0.0f)
839 CLandscapeGlobals::OORefineThreshold = FLT_MAX;
840 else
841 CLandscapeGlobals::OORefineThreshold = 1.0f / CLandscapeGlobals::RefineThreshold;
843 // Refine Center*.
844 CLandscapeGlobals::RefineCenter= refineCenter;
845 CLandscapeGlobals::TileFarSphere.Center= CLandscapeGlobals::RefineCenter;
846 CLandscapeGlobals::TileFarSphere.Radius= CLandscapeGlobals::TileDistFar;
847 CLandscapeGlobals::TileNearSphere.Center= CLandscapeGlobals::RefineCenter;
848 CLandscapeGlobals::TileNearSphere.Radius= CLandscapeGlobals::TileDistNear;
850 // PZBModelPosition
851 CLandscapeGlobals::PZBModelPosition= _PZBModelPosition;
853 // VB Allocators.
854 CLandscapeGlobals::CurrentFar0VBAllocator= &_Far0VB;
855 CLandscapeGlobals::CurrentFar1VBAllocator= &_Far1VB;
856 CLandscapeGlobals::CurrentTileVBAllocator= &_TileVB;
858 if(_Driver)
859 lockBuffers ();
863 // ***************************************************************************
864 void CLandscape::lockBuffers ()
866 // Already locked
867 if ((_LockCount++) == 0)
869 // Must check driver, and create VB infos,locking buffers.
870 if(_Driver)
872 _Far0VB.updateDriver(_Driver);
873 _Far1VB.updateDriver(_Driver);
874 _TileVB.updateDriver(_Driver);
876 // must do the same for _VegetableManager.
877 if(_DriverOkForVegetable)
878 _VegetableManager->updateDriver(_Driver);
881 _Far0VB.lockBuffer(CLandscapeGlobals::CurrentFar0VBInfo);
882 _Far1VB.lockBuffer(CLandscapeGlobals::CurrentFar1VBInfo);
883 _TileVB.lockBuffer(CLandscapeGlobals::CurrentTileVBInfo);
885 // lock buffer of the vegetable manager.
886 _VegetableManager->lockBuffers();
888 // VertexProgrma mode???
889 CLandscapeGlobals::VertexProgramEnabled= _VertexShaderOk;
894 // ***************************************************************************
895 void CLandscape::unlockBuffers(bool force)
897 // Already locked
898 if ((_LockCount == 1) || force)
900 _Far0VB.unlockBuffer();
901 _Far1VB.unlockBuffer();
902 _TileVB.unlockBuffer();
904 // unlock buffer of the vegetable manager.
905 _VegetableManager->unlockBuffers();
906 _LockCount = 0;
909 if (_LockCount > 0)
910 _LockCount--;
913 // ***************************************************************************
914 void CLandscape::updateTessBlocksFaceVector()
916 // while some tessBlock to update remains.
917 CTessBlock *tb;
918 while( (tb=_TessBlockModificationRoot.getNextToModify()) !=NULL )
920 // Get the patch which owns this TessBlock.
921 CPatch *patch= tb->getPatch();
923 // If this patch is visible, recreate faceVector for his tessBlock.
924 patch->recreateTessBlockFaceVector(*tb);
926 // remove from list.
927 tb->removeFromModifyList();
934 // ***************************************************************************
935 static inline void initPassTriArray(CPatchRdrPass &/* pass */, uint32 numIndex)
938 //uint numIndices= pass.getMaxRenderedFaces()*3;
939 // realloc if necessary
940 // We use
941 /*if( CLandscapeGlobals::PassTriArray.getNumIndexes() < numIndices )
942 CLandscapeGlobals::PassTriArray.setNumIndexes( numIndices );*/
943 CLandscapeGlobals::PassTriArray.setFormat(NL_LANDSCAPE_INDEX_FORMAT);
944 CLandscapeGlobals::PassTriArray.setNumIndexes(numIndex);
945 // reset ptr.
946 nlassert (!CLandscapeGlobals::PassTriArray.isLocked());
947 CLandscapeGlobals::PassTriArray.lock (CLandscapeGlobals::PassTriArrayIBA);
948 NL3D_LandscapeGlobals_PassTriCurPtr= CLandscapeGlobals::PassTriArrayIBA.getPtr();
949 NL3D_LandscapeGlobals_PassTriFormat = CLandscapeGlobals::PassTriArrayIBA.getFormat();
954 // ***************************************************************************
955 static
956 #ifndef NL_DEBUG
957 inline
958 #endif
959 void drawPassTriArray(CMaterial &mat)
961 nlassert (CLandscapeGlobals::PassTriArray.isLocked());
962 CLandscapeGlobals::PassTriArrayIBA.unlock();
963 if(NL3D_LandscapeGlobals_PassNTri>0)
965 //mat.setZFunc(CMaterial::ZFunc::greaterequal);
966 CLandscapeGlobals::PatchCurrentDriver->setupMaterial(mat);
967 CLandscapeGlobals::PatchCurrentDriver->activeIndexBuffer(CLandscapeGlobals::PassTriArray);
968 CLandscapeGlobals::PatchCurrentDriver->renderSimpleTriangles(0, NL3D_LandscapeGlobals_PassNTri);
969 NL3D_LandscapeGlobals_PassNTri= 0;
974 // ***************************************************************************
975 static inline uint32 countNumWantedIndex(CRdrTileId *tileToRdr, uint rdrPass)
977 uint32 numIndex = 0;
978 while(tileToRdr)
980 if(tileToRdr->TileMaterial->Pass[rdrPass].PatchRdrPass)
982 // renderSimpleTriangles() with the material setuped.
983 numIndex += *(tileToRdr->TileMaterial->TileFaceVectors[rdrPass]);
985 tileToRdr= (CRdrTileId*)tileToRdr->getNext();
987 return 3 * numIndex;
990 // ***************************************************************************
991 static inline uint32 countNumWantedIndexFar0(CPatch *patch)
993 uint32 numTri = 0;
994 while(patch)
996 // renderSimpleTriangles() with the material setuped.
997 numTri += patch->countNumTriFar0();
998 patch = patch->getNextFar0ToRdr();
1000 return 3 * numTri;
1003 // ***************************************************************************
1004 static inline uint32 countNumWantedIndexFar1(CPatch *patch)
1006 uint32 numTri = 0;
1007 while(patch)
1009 numTri += patch->countNumTriFar1();
1010 patch = patch ->getNextFar1ToRdr();
1012 return 3 * numTri;
1017 // ***************************************************************************
1018 void CLandscape::render(const CVector &refineCenter, const CVector &frontVector, const CPlane pyramid[NL3D_TESSBLOCK_NUM_CLIP_PLANE], bool doTileAddPass)
1020 IDriver *driver= _Driver;
1021 nlassert(driver);
1023 // values in Stencil Buffer which match with landscape are replace by 128
1024 // rest of Stencil is replace by 0.
1025 CScene *scene = NULL;
1026 if (OwnerModel)
1028 scene = OwnerModel->getOwnerScene();
1029 if(scene->getLandscapePolyDrawingCallback())
1031 scene->getLandscapePolyDrawingCallback()->beginPolyDrawing();
1035 // Increment the update date for preRender.
1036 CLandscapeGlobals::CurrentRenderDate++;
1039 ItZoneMap it;
1040 sint i;
1041 ItTileRdrPassSet itTile;
1042 ItSPRenderPassVector itFar;
1044 // Yoyo: profile.
1045 NL3D_PROFILE_LAND_SET(ProfNRdrFar0, 0);
1046 NL3D_PROFILE_LAND_SET(ProfNRdrFar1, 0);
1047 NL3D_PROFILE_LAND_SET(ProfNPatchRdrFar0, 0);
1048 NL3D_PROFILE_LAND_SET(ProfNPatchRdrFar1, 0);
1049 for(i=0;i<NL3D_MAX_TILE_PASS;i++)
1051 NL3D_PROFILE_LAND_SET(ProfNRdrTile[i], 0);
1055 // -2. Update globals
1056 //====================
1057 updateGlobalsAndLockBuffers (refineCenter);
1058 // NB: render may change vertices in VB in visible patchs => buffers are locked.
1061 // -1. clear all PatchRenderPass renderList
1062 //===================
1064 H_BEFORE( NL3D_Landscape_Render_Clear );
1066 // Fars.
1067 for(itFar= _TextureFars.begin(); itFar!= _TextureFars.end(); itFar++)
1069 CPatchRdrPass &pass= **itFar;
1070 // clear list.
1071 pass.clearAllRenderList();
1074 // Tiles.
1075 for(itTile= TileRdrPassSet.begin(); itTile!= TileRdrPassSet.end(); itTile++)
1077 CPatchRdrPass &pass= const_cast<CPatchRdrPass&>(*itTile);
1078 // clear list.
1079 pass.clearAllRenderList();
1082 // Lightmaps.
1083 for(sint lightRdrPass=0; lightRdrPass<(sint)_TextureNears.size(); lightRdrPass++)
1085 CPatchRdrPass &pass= *_TextureNears[lightRdrPass];
1086 // clear list.
1087 pass.clearAllRenderList();
1090 H_AFTER( NL3D_Landscape_Render_Clear );
1092 // 0. preRender pass.
1093 //===================
1095 H_BEFORE( NL3D_Landscape_Render_PreRender );
1097 // change Far0 / Far1.
1098 // Clip TessBlocks against pyramid and Far Limit.
1099 for(i=0; i<NL3D_TESSBLOCK_NUM_CLIP_PLANE; i++)
1101 CTessBlock::CurrentPyramid[i]= pyramid[i];
1103 // Update VB with change of Far0 / Far1.
1104 for(it= Zones.begin();it!=Zones.end();it++)
1106 (*it).second->preRender();
1109 H_AFTER( NL3D_Landscape_Render_PreRender );
1110 H_BEFORE( NL3D_Landscape_Render_Refill );
1112 // Check if the vertex buffers must be refilled
1113 _Far0VB.checkVertexBuffersResident();
1114 _Far1VB.checkVertexBuffersResident();
1115 _TileVB.checkVertexBuffersResident();
1117 // Reallocation Mgt. If any of the VB is reallocated, we must refill it entirely.
1118 // NB: all VBs are refilled entirely. It is not optimal (maybe 3* too slow), but reallocation are supposed
1119 // to be very rare.
1120 if( _Far0VB.reallocationOccurs() || _Far1VB.reallocationOccurs() || _TileVB.reallocationOccurs() )
1121 _RenderMustRefillVB= true;
1123 // VertexProgram dependency on RefineThreshold Management. If VertexShader, and if the refineThreshold has
1124 // changed since the last time, we must refill All the VB, because data are out of date.
1125 if( _VertexShaderOk && _VPThresholdChange )
1127 _VPThresholdChange= false;
1128 _RenderMustRefillVB= true;
1131 // If we must refill the VB (for any reason).
1132 if(_RenderMustRefillVB )
1134 // Ok, ok, we refill All the VB with good data.
1135 _RenderMustRefillVB= false;
1137 // First reset the flag, so fillVB() will effectively fill the VB.
1138 _Far0VB.resetReallocation();
1139 _Far1VB.resetReallocation();
1140 _TileVB.resetReallocation();
1142 // Then recompute good VBInfo (those in CurrentVBInfo are false!!).
1143 // Do it by unlocking then re-locking Buffers.
1144 unlockBuffers(true);
1145 lockBuffers();
1147 // Finally, fill the VB for all patchs visible.
1148 for(it= Zones.begin();it!=Zones.end();it++)
1150 if((*it).second->ClipResult==CZone::ClipOut)
1151 continue;
1152 for(sint i=0;i<(*it).second->getNumPatchs(); i++)
1154 CPatch *patch= (*it).second->getPatch(i);
1155 patch->fillVBIfVisible();
1160 H_AFTER( NL3D_Landscape_Render_Refill );
1161 H_BEFORE( NL3D_Landscape_Render_SoftGeomorph );
1163 // If software GeoMorph / Alpha Transition (no VertexShader), do it now.
1164 if(!_VertexShaderOk)
1166 // For all patch visible, compute geomoprh and alpha in software.
1167 for(it= Zones.begin();it!=Zones.end();it++)
1169 if((*it).second->ClipResult==CZone::ClipOut)
1170 continue;
1171 for(sint i=0;i<(*it).second->getNumPatchs(); i++)
1173 CPatch *patch= (*it).second->getPatch(i);
1174 // If visible, compute Geomorph And Alpha
1175 patch->computeSoftwareGeomorphAndAlpha();
1180 Optim note: here, lot of vertices are
1181 1/ geomorphed twice (vertices on edges of patchs)
1182 2/ vertices are geomorphed, but not used (because o the Tessblock clip),
1183 because lot of vertices used by faces in small TessBlocks are still in MasterBlock.
1185 Some tries have been made to solve this, but result are even worse (2 times or more), because:
1187 - does not really matter edges of patchs (and corner) because the majority is in interior of patch.
1188 - in this case, we need to reset all the flags which is very costly (reparse all zones...) .
1189 2/ Except for the old CTessBlockEdge management which not solve all the thing, the other solution is
1190 to test all faces not clipped (on a per TessBlock basis), to compute only vertices needed.
1191 But in this cases, result are worse, maybe because there is 6 times more tests, and with bad BTB cache.
1195 H_AFTER( NL3D_Landscape_Render_SoftGeomorph );
1197 // Must realase VB Buffers Now!! The VBuffers are now OK!
1198 // NB: no parallelism is made between 3dCard and Fill of vertices.
1199 // We Suppose Fill of vertices is rare, and so do not need to be parallelized.
1200 unlockBuffers(true);
1203 // If VertexShader enabled, setup VertexProgram Constants.
1204 if (_VertexShaderOk)
1206 bool uprogstate = driver->isUniformProgramState();
1207 uint nbvp = uprogstate ? CLandscapeVBAllocator::MaxVertexProgram : 1;
1208 for (uint i = 0; i < nbvp; ++i)
1210 CVertexProgramLandscape *program = _TileVB.getVP(i);
1211 if (program)
1213 // activate the program to set the uniforms in the program state for all programs
1214 // note: when uniforms are driver state, the indices must be the same across programs
1215 _TileVB.activateVP(i);
1217 // c[0..3] take the ModelViewProjection Matrix.
1218 driver->setUniformMatrix(IDriver::VertexProgram, program->getUniformIndex(CProgramIndex::ModelViewProjection), IDriver::ModelViewProjection, IDriver::Identity);
1219 // c[4] take useful constants.
1220 driver->setUniform4f(IDriver::VertexProgram, program->idx().ProgramConstants0, 0, 1, 0.5f, 0);
1221 // c[5] take RefineCenter
1222 driver->setUniform3f(IDriver::VertexProgram, program->idx().RefineCenter, refineCenter);
1223 // c[6] take info for Geomorph trnasition to TileNear.
1224 driver->setUniform2f(IDriver::VertexProgram, program->idx().TileDist, CLandscapeGlobals::TileDistFarSqr, CLandscapeGlobals::OOTileDistDeltaSqr);
1225 // c[10] take the fog vector.
1226 driver->setUniformFog(IDriver::VertexProgram, program->getUniformIndex(CProgramIndex::Fog));
1227 // c[12] take the current landscape Center / delta Pos to apply
1228 driver->setUniform3f(IDriver::VertexProgram, program->idx().PZBModelPosition, _PZBModelPosition);
1234 // 1. TileRender pass.
1235 //====================
1237 // Yoyo: profile
1238 NL3D_PROFILE_LAND_SET(ProfNTileSetupMaterial, driver->profileSetupedMaterials() );
1239 H_BEFORE( NL3D_Landscape_Render_Tile );
1241 // First, update Dynamic Lighting for Near, ie multiply Dynamic Lightmap with UserColor, and upload to texture.
1242 // ==================
1243 CPatchDLMContext *dlmCtxPtr= _PatchDLMContextList->begin();
1244 while(dlmCtxPtr!=NULL)
1246 // do it only if the patch has some Near stuff to render, and if it is visible
1247 if(dlmCtxPtr->getPatch()->getFar0() == 0
1248 && !dlmCtxPtr->getPatch()->isRenderClipped() )
1250 // upload lightmap into textureDLM, modulating before with patch TileColor.
1251 // NB: no-op if both src and dst are already full black.
1252 dlmCtxPtr->compileLighting(CPatchDLMContext::ModulateTileColor);
1255 // next
1256 dlmCtxPtr= (CPatchDLMContext*)dlmCtxPtr->Next;
1260 // Active VB.
1261 // ==================
1263 // Active the good VB, and maybe activate the VertexProgram Nb 0.
1264 _TileVB.activate(0);
1267 // Render.
1268 // ==================
1269 // Before any render call. Set the global driver used to render.
1270 CLandscapeGlobals::PatchCurrentDriver= driver;
1272 // bkup the original fog color
1273 CRGBA fogColor= driver->getFogColor();
1275 // Render Order. Must "invert", since initial order is NOT the render order. This is done because the lightmap pass
1276 // DO NOT have to do any renderTile(), since it is computed in RGB0 pass.
1277 nlassert(NL3D_MAX_TILE_PASS==5);
1278 static sint RenderOrder[NL3D_MAX_TILE_PASS]= {NL3D_TILE_PASS_RGB0, NL3D_TILE_PASS_RGB1, NL3D_TILE_PASS_RGB2,
1279 NL3D_TILE_PASS_LIGHTMAP, NL3D_TILE_PASS_ADD};
1280 // For ALL pass..
1281 for(i=0; i<NL3D_MAX_TILE_PASS; i++)
1283 sint passOrder= RenderOrder[i];
1286 // If VertexShader enabled, and if lightmap or post Add pass, must setup good VertexProgram
1287 if(_VertexShaderOk)
1289 if(passOrder == NL3D_TILE_PASS_LIGHTMAP)
1291 // Must activate the vertexProgram to take TexCoord2 to stage0
1292 _TileVB.activate(1);
1294 else if(passOrder == NL3D_TILE_PASS_ADD)
1296 // Must re-activate the standard VertexProgram
1297 _TileVB.activate(0);
1302 // Do add pass???
1303 if((passOrder==NL3D_TILE_PASS_ADD) && !doTileAddPass)
1304 continue;
1307 // Setup common material for this pass.
1308 //=============================
1309 // Default: Replace envmode.
1310 TileMaterial.texEnvOpRGB(0, CMaterial::Replace);
1311 TileMaterial.texEnvArg0RGB(0, CMaterial::Texture, CMaterial::SrcColor);
1312 TileMaterial.texEnvOpAlpha(0, CMaterial::Replace);
1313 TileMaterial.texEnvArg0Alpha(0, CMaterial::Texture, CMaterial::SrcAlpha);
1314 // NB: important to set Replace and not modulate, because in case of VerexProgram enabled,
1315 // Diffuse o[COL0] is undefined.
1317 // Copy from stage 0 to stage 1.
1318 TileMaterial.setTexEnvMode(1, TileMaterial.getTexEnvMode(0));
1320 // setup multitex / blending.
1321 if(passOrder==NL3D_TILE_PASS_RGB0)
1323 // first pass, no blend.
1324 TileMaterial.setBlend(false);
1326 else
1328 TileMaterial.setBlend(true);
1329 switch(passOrder)
1331 case NL3D_TILE_PASS_RGB1:
1332 case NL3D_TILE_PASS_RGB2:
1333 // alpha blending.
1334 TileMaterial.setBlendFunc(CMaterial::srcalpha, CMaterial::invsrcalpha);
1336 // Must use a special envmode for stage1: "separateAlpha"!!.
1337 // keep the color from previous stage.
1338 TileMaterial.texEnvOpRGB(1, CMaterial::Replace);
1339 TileMaterial.texEnvArg0RGB(1, CMaterial::Previous, CMaterial::SrcColor);
1340 // take the alpha from current stage.
1341 TileMaterial.texEnvOpAlpha(1, CMaterial::Replace);
1342 TileMaterial.texEnvArg0Alpha(1, CMaterial::Texture, CMaterial::SrcAlpha);
1343 break;
1344 case NL3D_TILE_PASS_LIGHTMAP:
1345 // modulate alpha blending.
1346 TileMaterial.setBlendFunc(CMaterial::zero, CMaterial::srccolor);
1348 // Setup the material envCombine so DynamicLightmap (stage 0) is added to static lightmap.
1349 TileMaterial.texEnvOpRGB(1, CMaterial::Add);
1350 TileMaterial.texEnvArg0RGB(1, CMaterial::Texture, CMaterial::SrcColor);
1351 TileMaterial.texEnvArg1RGB(1, CMaterial::Previous, CMaterial::SrcColor);
1353 break;
1354 case NL3D_TILE_PASS_ADD:
1355 // Use srcalpha for src (and not ONE), since additive are blended with alpha Cte/AlphaTexture
1356 TileMaterial.setBlendFunc(CMaterial::srcalpha, CMaterial::one);
1358 // for MAYBE LATER smooth night transition, setup Alpha cte of stage0, and setup alpha stage.
1359 TileMaterial.texEnvOpAlpha(0, CMaterial::Replace);
1360 TileMaterial.texEnvArg0Alpha(0, CMaterial::Constant, CMaterial::SrcAlpha);
1361 // Temp, just setup alpha to 1.
1362 TileMaterial.texConstantColor(0, CRGBA(255, 255, 255, 255));
1364 // Must use a special envmode for stage1: "separateAlpha"!!.
1365 // NB: it still works if The RdrPass has no texture.
1366 // keep the color from previous stage.
1367 TileMaterial.texEnvOpRGB(1, CMaterial::Replace);
1368 TileMaterial.texEnvArg0RGB(1, CMaterial::Previous, CMaterial::SrcColor);
1369 // modulate the alpha of current stage with previous
1370 TileMaterial.texEnvOpAlpha(1, CMaterial::Modulate);
1371 TileMaterial.texEnvArg0Alpha(1, CMaterial::Texture, CMaterial::SrcAlpha);
1372 TileMaterial.texEnvArg1Alpha(1, CMaterial::Previous, CMaterial::SrcAlpha);
1374 break;
1375 default:
1376 nlstop;
1379 // Reset the textures (so there is none in Addtive pass or in Lightmap).
1380 TileMaterial.setTexture(0, NULL);
1381 TileMaterial.setTexture(1, NULL);
1382 TileMaterial.setTexture(2, NULL);
1385 // Render All material RdrPass.
1386 //=============================
1387 // Special code for Lightmap and RGB0, for faster render.
1388 if(passOrder==NL3D_TILE_PASS_RGB0)
1390 // for RGB0 pass, setup the normal fogColor
1391 driver->setupFog(driver->getFogStart(), driver->getFogEnd(), fogColor);
1393 // RGB0 pass.
1394 ItTileRdrPassSet itTile;
1395 for(itTile= TileRdrPassSet.begin(); itTile!= TileRdrPassSet.end(); itTile++)
1397 // Get a ref on the render pass. Const cast work because we only modify attribut from CPatchRdrPass
1398 // that don't affect the operator< of this class
1399 CPatchRdrPass &pass= const_cast<CPatchRdrPass&>(*itTile);
1400 // Enlarge PassTriArray as needed
1401 CRdrTileId *tileToRdr= pass.getRdrTileRoot(passOrder);
1402 uint32 numWantedIndex = countNumWantedIndex(tileToRdr, NL3D_TILE_PASS_RGB0);
1403 if (numWantedIndex)
1405 initPassTriArray(pass, numWantedIndex);
1406 // Setup Diffuse texture of the tile.
1407 TileMaterial.setTexture(0, pass.TextureDiffuse);
1408 // Add triangles to array
1409 while(tileToRdr)
1411 // renderSimpleTriangles() with the material setuped.
1412 tileToRdr->TileMaterial->renderTilePassRGB0();
1413 tileToRdr= (CRdrTileId*)tileToRdr->getNext();
1416 // Render triangles.
1417 drawPassTriArray(TileMaterial);
1421 else if(passOrder==NL3D_TILE_PASS_LIGHTMAP)
1423 // for Lightmap pass (modulate blend), setup a White fogColor. This is not
1424 // mathematically correct but works fine
1425 driver->setupFog(driver->getFogStart(), driver->getFogEnd(), CRGBA::White);
1427 // Lightmap Pass.
1428 /* \todo yoyo: TODO_CLOUD: setup stage2, and setup texcoord generation. COMPLEX because of interaction
1429 with Dynamic LightMap
1432 // Setup the Dynamic Lightmap into stage 0.
1433 TileMaterial.setTexture(0, _TextureDLM);
1435 // if vertex shader not used.
1436 if(!_VertexShaderOk)
1438 // special setup such that stage0 takes Uv2.
1439 driver->mapTextureStageToUV(0, 2);
1441 // else VertexProgram map itself the good vertex Attribute to UV0.
1444 // Render All the lightmaps.
1445 for(sint lightRdrPass=0; lightRdrPass<(sint)_TextureNears.size(); lightRdrPass++)
1447 CPatchRdrPass &pass= *_TextureNears[lightRdrPass];
1449 // Enlarge PassTriArray as needed
1450 CRdrTileId *tileToRdr= pass.getRdrTileRoot(passOrder);
1451 uint32 numWantedIndex = countNumWantedIndex(tileToRdr, NL3D_TILE_PASS_RGB0);
1452 if (numWantedIndex)
1454 initPassTriArray(pass, numWantedIndex);
1455 // Setup Lightmap into stage1. Because we share UV with pass RGB0. So we use UV1.
1456 // Also, now stage0 is used for DynamicLightmap
1457 TileMaterial.setTexture(1, pass.TextureDiffuse);
1458 // Add triangles to array
1459 while(tileToRdr)
1461 // renderSimpleTriangles() with the material setuped.
1462 tileToRdr->TileMaterial->renderTilePassLightmap();
1463 tileToRdr= (CRdrTileId*)tileToRdr->getNext();
1465 // Render triangles.
1466 drawPassTriArray(TileMaterial);
1470 // if vertex shader not used.
1471 if(!_VertexShaderOk)
1473 // Reset special stage/UV setup to normal behavior
1474 driver->mapTextureStageToUV(0, 0);
1477 else
1479 // RGB1, RGB2, and ADD pass.
1480 // for ADD pass (additive blend), setup a Black fogColor
1481 if(passOrder==NL3D_TILE_PASS_ADD)
1482 driver->setupFog(driver->getFogStart(), driver->getFogEnd(), CRGBA::Black);
1483 // else setup the standard color (std blend)
1484 else
1485 driver->setupFog(driver->getFogStart(), driver->getFogEnd(), fogColor);
1487 // Render Base, Transitions or Additives.
1488 ItTileRdrPassSet itTile;
1489 for(itTile= TileRdrPassSet.begin(); itTile!= TileRdrPassSet.end(); itTile++)
1491 // Get a ref on the render pass. Const cast work because we only modify attribut from CPatchRdrPass
1492 // that don't affect the operator< of this class
1493 CPatchRdrPass &pass= const_cast<CPatchRdrPass&>(*itTile);
1495 // Enlarge PassTriArray as needed
1496 CRdrTileId *tileToRdr= pass.getRdrTileRoot(passOrder);
1497 uint32 numWantedIndex = countNumWantedIndex(tileToRdr, passOrder);
1498 if (numWantedIndex)
1500 initPassTriArray(pass, numWantedIndex);
1502 // Add triangles to array
1503 while(tileToRdr)
1505 // renderSimpleTriangles() with the material setuped.
1506 tileToRdr->TileMaterial->renderTile(passOrder);
1507 tileToRdr= (CRdrTileId*)tileToRdr->getNext();
1510 // Pass not empty ?
1511 if(NL3D_LandscapeGlobals_PassNTri>0)
1513 // Setup material.
1514 // Setup Diffuse texture of the tile.
1515 TileMaterial.setTexture(0, pass.TextureDiffuse);
1517 // If transition tile, must enable the alpha for this pass.
1518 // NB: Additive pass may have pass.TextureAlpha==NULL
1519 TileMaterial.setTexture(1, pass.TextureAlpha);
1522 // Render triangles.
1523 drawPassTriArray(TileMaterial);
1529 // restore old fog color
1530 driver->setupFog(driver->getFogStart(), driver->getFogEnd(), fogColor);
1532 // Yoyo: profile
1533 NL3D_PROFILE_LAND_SET(ProfNTileSetupMaterial, driver->profileSetupedMaterials()-ProfNTileSetupMaterial );
1534 H_AFTER( NL3D_Landscape_Render_Tile );
1536 // 2. Far0Render pass.
1537 //====================
1539 // Yoyo: profile
1540 NL3D_PROFILE_LAND_SET(ProfNFar0SetupMaterial, driver->profileSetupedMaterials() );
1541 H_BEFORE( NL3D_Landscape_Render_DLM );
1543 // First, update Dynamic Lighting for Far, ie multiply Dynamic Lightmap with TextureFar, and upload to texture.
1544 // ==================
1545 dlmCtxPtr= _PatchDLMContextList->begin();
1546 while(dlmCtxPtr!=NULL)
1548 // do it only if the patch has some Far stuff to render, and if it is visible
1549 if( (dlmCtxPtr->getPatch()->getFar0()>0 || dlmCtxPtr->getPatch()->getFar1()>0)
1550 && !dlmCtxPtr->getPatch()->isRenderClipped() )
1552 // upload lightmap into textureDLM, modulating before with patch TextureFar.
1553 // NB: no-op if both src and dst are already full black.
1554 dlmCtxPtr->compileLighting(CPatchDLMContext::ModulateTextureFar);
1557 // next
1558 dlmCtxPtr= (CPatchDLMContext*)dlmCtxPtr->Next;
1561 H_AFTER( NL3D_Landscape_Render_DLM );
1562 H_BEFORE( NL3D_Landscape_Render_Far0 );
1564 // Active VB.
1565 // ==================
1567 // Active the good VB, and maybe activate the std VertexProgram.
1568 _Far0VB.activate(0);
1571 // Render.
1572 // ==================
1574 // Setup common material.
1575 FarMaterial.setBlend(false);
1576 // set the DLM texture.
1577 FarMaterial.setTexture(1, _TextureDLM);
1579 // Render All material RdrPass0.
1580 itFar=_TextureFars.begin();
1581 while (itFar!=_TextureFars.end())
1583 CPatchRdrPass &pass= **itFar;
1585 // Enlarge PassTriArray as needed
1586 CPatch *patchToRdr= pass.getRdrPatchFar0();
1587 if (patchToRdr)
1589 uint32 numWantedIndex = countNumWantedIndexFar0(patchToRdr);
1590 if (numWantedIndex)
1592 initPassTriArray(pass, numWantedIndex);
1593 // Setup the material.
1594 FarMaterial.setTexture(0, pass.TextureDiffuse);
1595 // If the texture need to be updated, do it now.
1596 if(pass.TextureDiffuse && pass.TextureDiffuse->touched())
1597 driver->setupTexture(*pass.TextureDiffuse);
1598 // Add triangles to array
1599 while(patchToRdr)
1601 // renderSimpleTriangles() with the material setuped.
1602 patchToRdr->renderFar0();
1603 patchToRdr= patchToRdr->getNextFar0ToRdr();
1605 // Render triangles.
1606 drawPassTriArray(FarMaterial);
1609 // Next render pass
1610 itFar++;
1613 // Yoyo: profile
1614 NL3D_PROFILE_LAND_SET(ProfNFar0SetupMaterial, driver->profileSetupedMaterials()-ProfNFar0SetupMaterial );
1615 H_AFTER( NL3D_Landscape_Render_Far0 );
1618 // 3. Far1Render pass.
1619 //====================
1621 // Yoyo: profile
1622 NL3D_PROFILE_LAND_SET(ProfNFar1SetupMaterial, driver->profileSetupedMaterials() );
1623 H_BEFORE( NL3D_Landscape_Render_Far1 );
1625 // Active VB.
1626 // ==================
1628 // Active the good VB, and maybe activate the std VertexProgram.
1629 _Far1VB.activate(0);
1632 // Render
1633 // ==================
1635 // Setup common material.
1636 FarMaterial.setBlend(true);
1637 // set the DLM texture.
1638 FarMaterial.setTexture(1, _TextureDLM);
1641 // Render All material RdrPass1.
1642 itFar=_TextureFars.begin();
1643 while (itFar!=_TextureFars.end())
1645 CPatchRdrPass &pass= **itFar;
1647 // Enlarge PassTriArray as needed
1648 CPatch *patchToRdr= pass.getRdrPatchFar1();
1649 if (patchToRdr)
1651 //uint32 numWantedIndex = countNumWantedIndexFar1(patchToRdr);
1652 uint32 numWantedIndex = countNumWantedIndexFar1(patchToRdr);
1653 if (numWantedIndex)
1655 initPassTriArray(pass, numWantedIndex);
1657 // Setup the material.
1658 FarMaterial.setTexture(0, pass.TextureDiffuse);
1659 // If the texture need to be updated, do it now.
1660 if(pass.TextureDiffuse && pass.TextureDiffuse->touched())
1661 driver->setupTexture(*pass.TextureDiffuse);
1663 // Add triangles to array
1664 while(patchToRdr)
1666 // renderSimpleTriangles() with the material setuped.
1667 patchToRdr->renderFar1();
1668 patchToRdr= patchToRdr->getNextFar1ToRdr();
1671 // Render triangles.
1672 drawPassTriArray(FarMaterial);
1675 // Next render pass
1676 itFar++;
1679 // Yoyo: profile
1680 NL3D_PROFILE_LAND_SET(ProfNFar1SetupMaterial, driver->profileSetupedMaterials()-ProfNFar1SetupMaterial );
1681 H_AFTER( NL3D_Landscape_Render_Far1 );
1684 // 4. "Release" texture materials.
1685 //================================
1686 FarMaterial.setTexture(0, NULL);
1687 FarMaterial.setTexture(1, NULL);
1688 FarMaterial.setTexture(2, NULL);
1689 FarMaterial.setTexture(3, NULL);
1690 TileMaterial.setTexture(0, NULL);
1691 TileMaterial.setTexture(1, NULL);
1692 TileMaterial.setTexture(2, NULL);
1693 TileMaterial.setTexture(3, NULL);
1695 // To ensure no use but in render()..
1696 CLandscapeGlobals::PatchCurrentDriver= NULL;
1698 // Desactive the vertex program (if anyone)
1699 if(_VertexShaderOk)
1700 driver->activeVertexProgram (NULL);
1703 // 5. Vegetable Management.
1704 //================================
1705 if(scene && scene->getLandscapePolyDrawingCallback())
1707 scene->getLandscapePolyDrawingCallback()->endPolyDrawing();
1710 // First, update Dynamic Lighting for Vegetable, ie just copy.
1711 // ==================
1712 if(isVegetableActive())
1714 /* Actually we modulate the DLM with an arbitrary constant for this reason:
1715 Color of vegetable (ie their material) are NOT modulated with DLM.
1716 Doing this without using PixelShader / additional UVs seems to be impossible.
1717 And add new UVs (+700K in AGP) just for this is not worth the effort.
1719 We prefer using a constant to simulate the "global vegetable color", which is a big trick.
1721 Additionally, the vegetable take the diffuse lighting of landscape, which is
1722 false because it replaces the diffuse lighting it should have (ie with his own Normal and
1723 his own "global vegetable color")
1725 We can't do anything for "correct normal vegetable", but it is possible to replace landscape
1726 material with vegetable material, by dividing _DLMGlobalVegetableColor by LandscapeDiffuseMaterial.
1727 This is a very approximate result because of CRGBA clamp, but it is acceptable.
1729 CRGBA vegetDLMCte;
1730 // the constant is _DLMGlobalVegetableColor / PointLightDiffuseMaterial
1731 uint v;
1732 v= (_DLMGlobalVegetableColor.R*256) / (_PointLightDiffuseMaterial.R+1);
1733 vegetDLMCte.R= (uint8)min(v, 255U);
1734 v= (_DLMGlobalVegetableColor.G*256) / (_PointLightDiffuseMaterial.G+1);
1735 vegetDLMCte.G= (uint8)min(v, 255U);
1736 v= (_DLMGlobalVegetableColor.B*256) / (_PointLightDiffuseMaterial.B+1);
1737 vegetDLMCte.B= (uint8)min(v, 255U);
1739 // Parse all patch which have some vegetables
1740 dlmCtxPtr= _PatchDLMContextList->begin();
1741 while(dlmCtxPtr!=NULL)
1743 // do it only if the patch has some vegetable stuff to render, and if it is visible
1744 // NB: we may have some vegetable stuff to render if the patch has some TileMaterial created.
1745 if(dlmCtxPtr->getPatch()->getTileMaterialRefCount()>0
1746 && !dlmCtxPtr->getPatch()->isRenderClipped() )
1748 // NB: no-op if both src and dst are already full black.
1749 dlmCtxPtr->compileLighting(CPatchDLMContext::ModulateConstant, vegetDLMCte);
1752 // next
1753 dlmCtxPtr= (CPatchDLMContext*)dlmCtxPtr->Next;
1758 // profile.
1759 _VegetableManager->resetNumVegetableFaceRendered();
1761 // render all vegetables, only if driver support VertexProgram.
1762 // ==================
1763 if(isVegetableActive())
1765 // Use same plane as TessBlock for faster clipping.
1766 vector<CPlane> vegetablePyramid;
1767 vegetablePyramid.resize(NL3D_TESSBLOCK_NUM_CLIP_PLANE);
1768 for(i=0;i<NL3D_TESSBLOCK_NUM_CLIP_PLANE;i++)
1770 vegetablePyramid[i]= pyramid[i];
1772 _VegetableManager->render(refineCenter, frontVector, vegetablePyramid, _TextureDLM, driver);
1777 // ***************************************************************************
1778 // ***************************************************************************
1779 // Tile mgt.
1780 // ***************************************************************************
1781 // ***************************************************************************
1784 // ***************************************************************************
1785 ITexture *CLandscape::findTileTexture(const std::string &textName, bool clamp)
1787 ITexture *text;
1788 text= TileTextureMap[textName];
1789 // If just inserted, RefPtr is NULL!! :)
1790 // This test too if the RefPtr is NULL... (tile released)
1791 // The object is not owned by this map. It will be own by the multiple RdrPass via CSmartPtr.
1792 // They will destroy it when no more points to them.
1793 if(!text)
1795 TileTextureMap[textName]= text= new CTextureFile(textName);
1796 text->setWrapS(clamp?ITexture::Clamp:ITexture::Repeat);
1797 text->setWrapT(clamp?ITexture::Clamp:ITexture::Repeat);
1798 text->setUploadFormat(ITexture::DXTC5);
1799 text->setTextureCategory(_TextureTileCategory);
1801 return text;
1805 // ***************************************************************************
1806 CPatchRdrPass *CLandscape::findTileRdrPass(const CPatchRdrPass &pass)
1808 ItTileRdrPassSet it;
1809 // If already here, find it, else insert.
1810 it= (TileRdrPassSet.insert(pass)).first;
1812 return const_cast<CPatchRdrPass*>(&(*it));
1816 // ***************************************************************************
1817 void CLandscape::loadTile(uint16 tileId)
1819 CTile *tile;
1820 CTileInfo *tileInfo;
1821 string textName;
1823 // Retrieve or create texture.
1824 // ===========================
1825 // Tile Must exist.
1826 // nlassert(tileId==0xFFFF || tileId<TileBank.getTileCount());
1827 if(tileId<TileBank.getTileCount())
1828 tile= TileBank.getTile(tileId);
1829 else
1830 tile= NULL;
1831 // TileInfo must not exist.
1832 nlassert(TileInfos[tileId]==NULL);
1833 TileInfos[tileId]= tileInfo= new CTileInfo;
1835 // Fill additive part.
1836 // ===================
1837 if(tile)
1838 textName= tile->getRelativeFileName(CTile::additive);
1839 else
1840 textName.clear();
1841 // If no additive for this tile, rdrpass is NULL.
1842 if(textName.empty())
1843 tileInfo->AdditiveRdrPass= NULL;
1844 else
1846 // Fill rdrpass.
1847 CPatchRdrPass pass;
1848 // Avoid using Clamp for diffuse, because of recent NVidia GL drivers Bugs in 77.72
1849 pass.TextureDiffuse= findTileTexture(TileBank.getAbsPath()+textName, false);
1851 // We may have an alpha part for additive.
1852 textName= tile->getRelativeFileName (CTile::alpha);
1853 if(!textName.empty())
1854 // Must Use clamp for alpha (although NVidia drivers are buggy), because the texture doesn't tile at all
1855 pass.TextureAlpha= findTileTexture(TileBank.getAbsPath()+textName, true);
1857 // Fill tileInfo.
1858 tileInfo->AdditiveRdrPass= findTileRdrPass(pass);
1859 // Fill UV Info.
1860 // NB: for now, One Tile== One Texture, so UVScaleBias is simple.
1861 tileInfo->AdditiveUvScaleBias.x= 0;
1862 tileInfo->AdditiveUvScaleBias.y= 0;
1863 tileInfo->AdditiveUvScaleBias.z= 1;
1867 // Fill diffuse part.
1868 // =======================
1869 // Fill rdrpass.
1870 CPatchRdrPass pass;
1871 // The diffuse part for a tile is inevitable.
1872 if(tile)
1874 textName= tile->getRelativeFileName(CTile::diffuse);
1875 if(!textName.empty())
1876 // Avoid using Clamp for diffuse, because of recent NVidia GL drivers Bugs in 77.72
1877 pass.TextureDiffuse= findTileTexture(TileBank.getAbsPath()+textName, false);
1878 else
1880 pass.TextureDiffuse= new CTextureCross;
1881 nldebug("Missing Tile diffuse texname: %d", tileId);
1884 else
1885 pass.TextureDiffuse= new CTextureCross;
1886 if(tile)
1888 textName= tile->getRelativeFileName (CTile::alpha);
1889 if(!textName.empty())
1890 // Must Use clamp for alpha (although NVidia drivers are buggy), because the texture doesn't tile at all
1891 pass.TextureAlpha= findTileTexture(TileBank.getAbsPath()+textName, true);
1895 // Fill tileInfo.
1896 tileInfo->DiffuseRdrPass= findTileRdrPass(pass);
1897 // Fill UV Info.
1898 // NB: for now, One Tile== One Texture, so UVScaleBias is simple.
1899 tileInfo->DiffuseUvScaleBias.x= 0;
1900 tileInfo->DiffuseUvScaleBias.y= 0;
1901 tileInfo->DiffuseUvScaleBias.z= 1;
1902 tileInfo->AlphaUvScaleBias.x= 0;
1903 tileInfo->AlphaUvScaleBias.y= 0;
1904 tileInfo->AlphaUvScaleBias.z= 1;
1905 // Retrieve the good rot alpha decal.
1906 if(tile)
1907 tileInfo->RotAlpha= tile->getRotAlpha();
1908 else
1909 tileInfo->RotAlpha= 0;
1912 // Increment RefCount of RenderPart.
1913 // =================================
1914 if(tileInfo->AdditiveRdrPass)
1915 tileInfo->AdditiveRdrPass->RefCount++;
1916 if(tileInfo->DiffuseRdrPass)
1917 tileInfo->DiffuseRdrPass->RefCount++;
1922 // ***************************************************************************
1923 void CLandscape::releaseTile(uint16 tileId)
1925 CTileInfo *tileInfo;
1926 tileInfo= TileInfos[tileId];
1927 nlassert(tileInfo!=NULL);
1929 // "Release" the rdr pass.
1930 if(tileInfo->AdditiveRdrPass)
1931 tileInfo->AdditiveRdrPass->RefCount--;
1932 if(tileInfo->DiffuseRdrPass)
1933 tileInfo->DiffuseRdrPass->RefCount--;
1935 delete tileInfo;
1936 TileInfos[tileId]= NULL;
1940 // ***************************************************************************
1941 CPatchRdrPass *CLandscape::getTileRenderPass(uint16 tileId, bool additiveRdrPass)
1943 CTileInfo *tile= TileInfos[tileId];
1945 // If not here, create it.
1946 //========================
1947 if(tile==NULL)
1949 // Force loading of tile.
1950 loadTile(tileId);
1952 tile= TileInfos[tileId];
1953 nlassert(tile!=NULL);
1956 // Retrieve.
1957 //========================
1958 if(additiveRdrPass)
1960 // NB: additive pass is not lighted by the lightmap, so there is no lighted version of this rednerpass.
1961 return tile->AdditiveRdrPass;
1963 else
1965 return tile->DiffuseRdrPass;
1970 // ***************************************************************************
1971 void CLandscape::getTileUvScaleBiasRot(uint16 tileId, CTile::TBitmap bitmapType, CVector &uvScaleBias, uint8 &rotAlpha)
1973 CTileInfo *tile= TileInfos[tileId];
1974 // tile should not be NULL.
1975 // Because load of tiles are always done in getTileRenderPass(), and this insertion always succeed.
1976 nlassert(tile);
1978 rotAlpha= 0;
1979 switch(bitmapType)
1981 case CTile::diffuse:
1982 uvScaleBias= tile->DiffuseUvScaleBias; break;
1983 case CTile::additive:
1984 uvScaleBias= tile->AdditiveUvScaleBias; break;
1985 case CTile::alpha:
1986 uvScaleBias= tile->AlphaUvScaleBias;
1987 rotAlpha= tile->RotAlpha;
1988 break;
1989 default: break;
1994 // ***************************************************************************
1995 NLMISC::CSmartPtr<ITexture> CLandscape::getTileTexture(uint16 tileId, CTile::TBitmap bitmapType, CVector &uvScaleBias)
1997 CPatchRdrPass *pass;
1998 if(bitmapType== CTile::additive)
1999 pass= getTileRenderPass(tileId, true);
2000 else
2001 pass= getTileRenderPass(tileId, false);
2002 if(!pass)
2003 return NULL;
2004 uint8 dummy;
2005 getTileUvScaleBiasRot(tileId, bitmapType, uvScaleBias, dummy);
2007 // return the wanted texture.
2008 if(bitmapType==CTile::diffuse || bitmapType==CTile::additive)
2009 return pass->TextureDiffuse;
2010 else
2011 return pass->TextureAlpha;
2015 // ***************************************************************************
2016 CTileElement *CLandscape::getTileElement(const CPatchIdent &patchId, const CUV &uv)
2018 // \todo yoyo: TODO_ZONEID: change ZoneId in 32 bits...
2019 std::map<uint16, CZone*>::const_iterator it= Zones.find((uint16)patchId.ZoneId);
2020 if(it!=Zones.end())
2022 sint N= (*it).second->getNumPatchs();
2023 // patch must exist in the zone.
2024 nlassert(patchId.PatchId<N);
2025 CPatch *pa= const_cast<CZone*>((*it).second)->getPatch(patchId.PatchId);
2026 return pa->getTileElement (uv);
2028 else
2029 // Return not found
2030 return NULL;
2034 // ***************************************************************************
2035 void CLandscape::flushTiles(IDriver *drv, uint32 tileStart, uint32 nbTiles)
2037 nlassert(nbTiles<=65536);
2038 nlassert(tileStart+nbTiles<=65536);
2040 // Load tile rdrpass, force setup the texture.
2041 for(sint tileId= tileStart; tileId<(sint)(tileStart+nbTiles); tileId++)
2043 CTileInfo *tile= TileInfos[tileId];
2044 if(tile==NULL)
2046 loadTile(uint16(tileId));
2047 CTileInfo *tile= TileInfos[tileId];
2048 nlassert(tile);
2049 if(tile->DiffuseRdrPass)
2051 const CPatchRdrPass &pass= *tile->DiffuseRdrPass;
2052 // If present and not already setuped...
2053 if(pass.TextureDiffuse && !pass.TextureDiffuse->setupedIntoDriver())
2054 drv->setupTexture(*pass.TextureDiffuse);
2055 // If present and not already setuped...
2056 if(pass.TextureAlpha && !pass.TextureAlpha->setupedIntoDriver())
2057 drv->setupTexture(*pass.TextureAlpha);
2059 if(tile->AdditiveRdrPass)
2061 const CPatchRdrPass &pass= *tile->AdditiveRdrPass;
2062 // If present and not already setuped...
2063 if(pass.TextureDiffuse && !pass.TextureDiffuse->setupedIntoDriver())
2064 drv->setupTexture(*pass.TextureDiffuse);
2065 // If present and not already setuped...
2066 if(pass.TextureAlpha && !pass.TextureAlpha->setupedIntoDriver())
2067 drv->setupTexture(*pass.TextureAlpha);
2074 // ***************************************************************************
2075 void CLandscape::releaseTiles(uint32 tileStart, uint32 nbTiles)
2077 nlassert(nbTiles<=65536);
2078 nlassert(tileStart+nbTiles<=65536);
2080 // release tiles.
2081 for(sint tileId= tileStart; tileId<(sint)(tileStart+nbTiles); tileId++)
2083 CTileInfo *tile= TileInfos[tileId];
2084 if(tile!=NULL)
2086 releaseTile(uint16(tileId));
2090 // For all rdrpass, release one that are no more referenced.
2091 ItTileRdrPassSet it;
2092 for(it= TileRdrPassSet.begin(); it!=TileRdrPassSet.end();)
2094 // If no more tile access the rdrpass, delete it.
2095 if((*it).RefCount==0)
2097 ItTileRdrPassSet itDel=it++;
2098 TileRdrPassSet.erase(itDel);
2100 else
2101 it++;
2104 // Textures are automaticly deleted by smartptr, but not their entry int the map (TileTextureMap).
2105 // => doesn't matter since findTileTexture() manages this case.
2106 // And the memory overhead is not a problem (we talk about pointers).
2110 // ***************************************************************************
2111 uint CLandscape::getTileLightMap(CRGBA map[NL_TILE_LIGHTMAP_SIZE*NL_TILE_LIGHTMAP_SIZE], CPatchRdrPass *&lightmapRdrPass)
2113 sint textNum;
2114 uint lightMapId;
2116 NB: TextureNear are a grow only Array... TextureNear are never deleted. Why? :
2117 2/ Unused near texture may be uncahced by opengl (and maybe by windows, to disk).
2119 (old reason, no longer valid, since lightmaps are unlinked from tiles.
2120 1/ There is an important issue with releasing texture nears: tiles may acces them (see getTileRenderPass())
2123 // 0. Alloc Near Texture if necessary.
2124 //====================================
2125 if(_NFreeLightMaps==0)
2127 CTextureNear *text= new CTextureNear(TextureNearSize);
2128 TSPRenderPass newPass= new CPatchRdrPass;
2129 text->setTextureCategory(_TextureNearCategory);
2131 newPass->TextureDiffuse= text;
2133 _TextureNears.push_back(newPass);
2134 _NFreeLightMaps+= text->getNbAvailableTiles();
2137 // 1. Search the first texture which has a free tile.
2138 //==================================================
2139 CTextureNear *nearText= NULL;
2140 CPatchRdrPass *nearRdrPass= NULL;
2141 for(textNum=0;textNum<(sint)_TextureNears.size();textNum++)
2143 nearRdrPass= _TextureNears[textNum];
2144 nearText= (CTextureNear*)(ITexture*)nearRdrPass->TextureDiffuse;
2145 if(nearText->getNbAvailableTiles()!=0)
2146 break;
2148 nlassert(textNum<(sint)_TextureNears.size());
2149 // A empty space has been found.
2150 _NFreeLightMaps--;
2152 // 2. Fill the texture with the data, and updaterect.
2153 //===================================================
2154 lightMapId= nearText->getTileAndFillRect(map);
2155 // Compute the Id.
2156 lightMapId= textNum*NbTileLightMapByTexture + lightMapId;
2159 // 3. updateLighting
2160 //===================================================
2161 // Increment number of pixels to update for near.
2162 _ULTotalNearPixels+= NL_TILE_LIGHTMAP_SIZE*NL_TILE_LIGHTMAP_SIZE;
2165 // Result:
2166 lightmapRdrPass= nearRdrPass;
2167 return lightMapId;
2169 // ***************************************************************************
2170 void CLandscape::getTileLightMapUvInfo(uint tileLightMapId, CVector &uvScaleBias)
2172 uint id, s,t;
2174 // Scale.
2175 static const float scale10= (float)NL_TILE_LIGHTMAP_SIZE/TextureNearSize;
2176 static const float scale4= 4.f/TextureNearSize;
2177 static const float scale1= 1.f/TextureNearSize;
2178 // The size of a minilightmap, mapped onto the polygon, is still 4 pixels.
2179 uvScaleBias.z= scale4;
2181 // Get the id local in the texture.
2182 id= tileLightMapId%NbTileLightMapByTexture;
2184 // Commpute UVBias.
2185 // Get the coordinate of the tile, in tile number.
2186 s= id%NbTileLightMapByLine;
2187 t= id/NbTileLightMapByLine;
2188 // But the real size of a minilightmap is 10 pixels, and we must reach the pixel 1,1.
2189 uvScaleBias.x= s*scale10 + scale1;
2190 uvScaleBias.y= t*scale10 + scale1;
2192 // ***************************************************************************
2193 void CLandscape::releaseTileLightMap(uint tileLightMapId)
2195 uint id, textNum;
2197 // Get the id local in the texture.
2198 textNum= tileLightMapId / NbTileLightMapByTexture;
2199 id= tileLightMapId % NbTileLightMapByTexture;
2200 nlassert(textNum<_TextureNears.size());
2202 // Release the tile in this texture.
2203 CPatchRdrPass *nearRdrPass= _TextureNears[textNum];
2204 CTextureNear *nearText= (CTextureNear*)(ITexture*)nearRdrPass->TextureDiffuse;
2205 nearText->releaseTile(id);
2206 _NFreeLightMaps++;
2208 // updateLighting
2209 // Decrement number of pixels to update for near.
2210 _ULTotalNearPixels-= NL_TILE_LIGHTMAP_SIZE*NL_TILE_LIGHTMAP_SIZE;
2214 // ***************************************************************************
2215 void CLandscape::refillTileLightMap(uint tileLightMapId, CRGBA map[NL_TILE_LIGHTMAP_SIZE*NL_TILE_LIGHTMAP_SIZE])
2217 uint id, textNum;
2219 // Get the id local in the texture.
2220 textNum= tileLightMapId / NbTileLightMapByTexture;
2221 id= tileLightMapId % NbTileLightMapByTexture;
2222 nlassert(textNum<_TextureNears.size());
2224 // get a ptr on the texture.
2225 CPatchRdrPass *nearRdrPass= _TextureNears[textNum];
2226 CTextureNear *nearText= (CTextureNear*)(ITexture*)nearRdrPass->TextureDiffuse;
2228 // refill this tile
2229 nearText->refillRect(id, map);
2234 // ***************************************************************************
2235 // ***************************************************************************
2236 // Far.
2237 // ***************************************************************************
2238 // ***************************************************************************
2241 // ***************************************************************************
2242 CPatchRdrPass* CLandscape::getFarRenderPass(CPatch* pPatch, uint farIndex, float& farUScale, float& farVScale, float& farUBias, float& farVBias, bool& bRot)
2244 // Check args
2245 nlassert (farIndex>0);
2247 // Get size of the far texture
2248 uint width=(pPatch->getOrderS ()*NL_NUM_PIXELS_ON_FAR_TILE_EDGE)>>(farIndex-1);
2249 uint height=(pPatch->getOrderT ()*NL_NUM_PIXELS_ON_FAR_TILE_EDGE)>>(farIndex-1);
2251 // For updateLighting: increment total of pixels to update.
2252 _ULTotalFarPixels+= width*height;
2254 // Try to allocate in every textures
2255 uint i;
2256 sint bestRdrPass= -1;
2257 sint bestSplit= INT_MAX;
2258 for(i=0;i<_TextureFars.size();i++)
2260 CTextureFar *pTextureFar=(CTextureFar*)(&*(_TextureFars[i]->TextureDiffuse));
2262 sint splitRes= pTextureFar->tryAllocatePatch(pPatch, farIndex);
2263 // if found with no split, ok, stop!
2264 if(splitRes==0)
2266 bestRdrPass= i;
2267 break;
2269 // else if found, but with split
2270 else if(splitRes > 0)
2272 // Then must take the small split possible along all the texture fars.
2273 if (splitRes<bestSplit)
2275 bestRdrPass= i;
2276 bestSplit= splitRes;
2281 // If no one found, must allocate a new render pass.
2282 if(bestRdrPass==-1)
2284 bestRdrPass= (sint)_TextureFars.size();
2286 // add a new render pass
2287 CPatchRdrPass *pass=new CPatchRdrPass;
2289 // Fill the render pass
2290 CTextureFar *pTextureFar=new CTextureFar;
2291 pTextureFar->setTextureCategory(_TextureFarCategory);
2293 // Append this textureFar to the list of TextureFar to updateLighting.
2294 if(_ULRootTextureFar==NULL)
2295 _ULRootTextureFar= pTextureFar;
2296 else
2297 pTextureFar->linkBeforeUL(_ULRootTextureFar);
2299 // Set the bank
2300 pTextureFar->_Bank=&TileFarBank;
2302 // Set as diffuse texture for this renderpass
2303 pass->TextureDiffuse=pTextureFar;
2305 // Add the render pass to the list
2306 _TextureFars.push_back(pass);
2310 // Ok, add the patch to the best render pass in the _TextureFars
2311 TSPRenderPass pass= _TextureFars[bestRdrPass];
2313 // Get a pointer on the diffuse far texture
2314 CTextureFar *pTextureFar=(CTextureFar*)(&*(pass->TextureDiffuse));
2316 // Allocate really in it (must success since tryAllocate() has succeed)
2317 pTextureFar->allocatePatch(pPatch, farIndex, farUScale, farVScale, farUBias, farVBias, bRot);
2319 // Return the renderpass
2320 return pass;
2324 // ***************************************************************************
2325 void CLandscape::freeFarRenderPass (CPatch* pPatch, CPatchRdrPass* pass, uint farIndex)
2327 // Get size of the far texture
2328 uint width=(pPatch->getOrderS ()*NL_NUM_PIXELS_ON_FAR_TILE_EDGE)>>(farIndex-1);
2329 uint height=(pPatch->getOrderT ()*NL_NUM_PIXELS_ON_FAR_TILE_EDGE)>>(farIndex-1);
2331 // For updateLighting: decrement total of pixels to update.
2332 _ULTotalFarPixels-= width*height;
2333 nlassert(_ULTotalFarPixels>=0);
2335 // Get a pointer on the diffuse far texture
2336 CTextureFar *pTextureFar=(CTextureFar*)(&*(pass->TextureDiffuse));
2338 // Remove from the patch from the texture if empty
2339 pTextureFar->removePatch (pPatch, farIndex);
2343 // ***************************************************************************
2344 void CLandscape::clearFarRenderPass (CPatchRdrPass* pass)
2346 // Before deleting, must remove TextureFar from UpdateLighting list.
2348 // Get a pointer on the diffuse far texture
2349 CTextureFar *pTextureFar=(CTextureFar*)(&*(pass->TextureDiffuse));
2351 // If I delete the textureFar which is the current root
2352 if(_ULRootTextureFar==pTextureFar)
2354 // switch to next
2355 _ULRootTextureFar= pTextureFar->getNextUL();
2356 // if still the same, it means that the circular list is now empty
2357 if(_ULRootTextureFar==pTextureFar)
2358 _ULRootTextureFar= NULL;
2361 // unlink the texture from list
2362 pTextureFar->unlinkUL();
2366 // ***************************************************************************
2367 // ***************************************************************************
2368 // Misc.
2369 // ***************************************************************************
2370 // ***************************************************************************
2373 // ***************************************************************************
2374 CZone* CLandscape::getZone (sint zoneId)
2376 TZoneMap::iterator it;
2377 it= Zones.find(uint16(zoneId));
2378 if (it!=Zones.end())
2379 return (*it).second;
2380 else
2381 return NULL;
2385 // ***************************************************************************
2386 const CZone* CLandscape::getZone (sint zoneId) const
2388 TZoneMap::const_iterator it;
2390 it= Zones.find(uint16(zoneId));
2391 if (it!=Zones.end())
2392 return (*it).second;
2393 else
2394 return NULL;
2399 // ***************************************************************************
2400 void CLandscape::checkZoneBinds(CZone &curZone, EBadBind &bindError)
2402 for(sint i=0;i<curZone.getNumPatchs();i++)
2404 const CZone::CPatchConnect &pa= *curZone.getPatchConnect(i);
2406 // Check the bindInfos.
2407 for(sint j=0;j<4;j++)
2409 const CPatchInfo::CBindInfo &bd=pa.BindEdges[j];
2410 // Just 1/1 for now.
2411 if(bd.NPatchs==1)
2413 CZone *oZone= getZone(bd.ZoneId);
2414 // If loaded zone.
2415 if(oZone)
2417 const CZone::CPatchConnect &po= *(oZone->getPatchConnect(bd.Next[0]));
2418 const CPatchInfo::CBindInfo &bo= po.BindEdges[bd.Edge[0]];
2419 if(bo.NPatchs!=1 || bo.Next[0]!=i || bo.Edge[0]!=j)
2420 bindError.BindErrors.push_back( EBadBind::CBindError(curZone.getZoneId(), i));
2428 // ***************************************************************************
2429 void CLandscape::checkBinds()
2431 EBadBind bindError;
2433 for(ItZoneMap it= Zones.begin();it!=Zones.end();it++)
2435 CZone &curZone= *(*it).second;
2436 checkZoneBinds(curZone, bindError);
2439 if(!bindError.BindErrors.empty())
2440 throw bindError;
2444 // ***************************************************************************
2445 void CLandscape::checkBinds(uint16 zoneId)
2447 EBadBind bindError;
2449 ItZoneMap it= Zones.find(zoneId);
2450 if(it!= Zones.end())
2452 CZone &curZone= *(*it).second;
2453 checkZoneBinds(curZone, bindError);
2454 if(!bindError.BindErrors.empty())
2455 throw bindError;
2461 // ***************************************************************************
2462 void CLandscape::addTrianglesInBBox(const CPatchIdentEx &paIdEx, const CAABBox &bbox, std::vector<CTrianglePatch> &triangles, uint8 tileTessLevel) const
2464 // No clear here, just add triangles to the array.
2465 const CPatch *pa= paIdEx.Patch;
2467 CPatchIdent paId;
2468 paId.ZoneId= paIdEx.ZoneId;
2469 paId.PatchId= paIdEx.PatchId;
2470 pa->addTrianglesInBBox(paId, bbox, triangles, tileTessLevel);
2474 // ***************************************************************************
2475 void CLandscape::buildTrianglesInBBox(const CAABBox &bbox, std::vector<CTrianglePatch> &triangles, uint8 tileTessLevel)
2477 // clear selection.
2478 triangles.clear();
2480 // search path of interest.
2481 _PatchQuadGrid.clearSelection();
2482 _PatchQuadGrid.select(bbox.getMin(), bbox.getMax());
2483 CQuadGrid<CPatchIdentEx>::CIterator it;
2485 // for each patch, add triangles to the array.
2486 for(it= _PatchQuadGrid.begin(); it!= _PatchQuadGrid.end(); it++)
2488 addTrianglesInBBox((*it), bbox, triangles, tileTessLevel);
2494 // ***************************************************************************
2495 void CLandscape::addPatchBlocksInBBox(const CPatchIdentEx &paIdEx, const CAABBox &bbox, std::vector<CPatchBlockIdent> &paBlockIds)
2497 // No clear here, just add blocks to the array.
2498 const CPatch *pa= paIdEx.Patch;
2500 CPatchIdent paId;
2501 paId.ZoneId= paIdEx.ZoneId;
2502 paId.PatchId= paIdEx.PatchId;
2503 pa->addPatchBlocksInBBox(paId, bbox, paBlockIds);
2507 // ***************************************************************************
2508 void CLandscape::buildPatchBlocksInBBox(const CAABBox &bbox, std::vector<CPatchBlockIdent> &paBlockIds)
2510 // clear selection.
2511 paBlockIds.clear();
2513 // search path of interest.
2514 _PatchQuadGrid.clearSelection();
2515 _PatchQuadGrid.select(bbox.getMin(), bbox.getMax());
2516 CQuadGrid<CPatchIdentEx>::CIterator it;
2518 // for each patch, add blocks to the array.
2519 for(it= _PatchQuadGrid.begin(); it!= _PatchQuadGrid.end(); it++)
2521 addPatchBlocksInBBox((*it), bbox, paBlockIds);
2526 // ***************************************************************************
2527 void CLandscape::fillPatchQuadBlock(CPatchQuadBlock &quadBlock) const
2529 sint zoneId= quadBlock.PatchBlockId.PatchId.ZoneId;
2530 sint patchId= quadBlock.PatchBlockId.PatchId.PatchId;
2531 std::map<uint16, CZone*>::const_iterator it= Zones.find(uint16(zoneId));
2532 if(it!=Zones.end())
2534 sint N= (*it).second->getNumPatchs();
2535 // patch must exist in the zone.
2536 nlassert(patchId>=0);
2537 nlassert(patchId<N);
2539 const CPatch *pa= const_cast<const CZone*>((*it).second)->getPatch(patchId);
2540 pa->fillPatchQuadBlock(quadBlock);
2547 // ***************************************************************************
2548 void CLandscape::buildCollideFaces(const CAABBoxExt &bbox, vector<CTriangle> &faces, bool faceClip)
2550 CBSphere bsWanted(bbox.getCenter(), bbox.getRadius());
2552 faces.clear();
2553 // For all zones.
2554 for(ItZoneMap it= Zones.begin();it!=Zones.end();it++)
2556 const CAABBoxExt &bb= (*it).second->getZoneBB();
2557 CBSphere bs(bb.getCenter(), bb.getRadius());
2558 // If zone intersect the wanted area.
2559 //===================================
2560 if(bs.intersect(bsWanted))
2562 // Then trace all patch.
2563 sint N= (*it).second->getNumPatchs();
2564 for(sint i=0;i<N;i++)
2566 const CPatch *pa= const_cast<const CZone*>((*it).second)->getPatch(i);
2568 // If patch in wanted area....
2569 //============================
2570 if(bsWanted.intersect((*it).second->getPatchBSphere(i)))
2572 // 0. Build the faces.
2573 //====================
2574 sint ordS= pa->getOrderS();
2575 sint ordT= pa->getOrderT();
2576 sint x,y,j;
2577 vector<CTriangle> tmpFaces;
2578 tmpFaces.reserve(ordS*ordT);
2579 float OOS= 1.0f/ordS;
2580 float OOT= 1.0f/ordT;
2581 for(y=0;y<ordT;y++)
2583 for(x=0;x<ordS;x++)
2585 CTriangle f;
2586 f.V0= pa->computeVertex(x*OOS, y*OOT);
2587 f.V1= pa->computeVertex(x*OOS, (y+1)*OOT);
2588 f.V2= pa->computeVertex((x+1)*OOS, (y+1)*OOT);
2589 tmpFaces.push_back(f);
2590 f.V0= pa->computeVertex(x*OOS, y*OOT);
2591 f.V1= pa->computeVertex((x+1)*OOS, (y+1)*OOT);
2592 f.V2= pa->computeVertex((x+1)*OOS, y*OOT);
2593 tmpFaces.push_back(f);
2597 // 1. Clip the faces.
2598 //===================
2599 if(faceClip)
2601 // Insert only faces which are In the area.
2602 for(j=0;j<(sint)tmpFaces.size();j++)
2604 CTriangle &f= tmpFaces[j];
2605 if(bbox.intersect(f.V0, f.V1, f.V2))
2607 faces.push_back(f);
2611 else
2613 // Else insert ALL.
2614 faces.insert(faces.end(), tmpFaces.begin(), tmpFaces.end());
2623 // ***************************************************************************
2624 void CLandscape::buildCollideFaces(sint zoneId, sint patch, std::vector<CTriangle> &faces)
2626 faces.clear();
2628 ItZoneMap it= Zones.find(uint16(zoneId));
2629 if(it!=Zones.end())
2631 // Then trace all patch.
2632 sint N= (*it).second->getNumPatchs();
2633 nlassert(patch>=0);
2634 nlassert(patch<N);
2635 const CPatch *pa= const_cast<const CZone*>((*it).second)->getPatch(patch);
2637 // Build the faces.
2638 //=================
2639 sint ordS= pa->getOrderS();
2640 sint ordT= pa->getOrderT();
2641 sint x,y;
2642 float OOS= 1.0f/ordS;
2643 float OOT= 1.0f/ordT;
2644 for(y=0;y<ordT;y++)
2646 for(x=0;x<ordS;x++)
2648 CTriangle f;
2649 f.V0= pa->computeVertex(x*OOS, y*OOT);
2650 f.V1= pa->computeVertex(x*OOS, (y+1)*OOT);
2651 f.V2= pa->computeVertex((x+1)*OOS, (y+1)*OOT);
2652 faces.push_back(f);
2653 f.V0= pa->computeVertex(x*OOS, y*OOT);
2654 f.V1= pa->computeVertex((x+1)*OOS, (y+1)*OOT);
2655 f.V2= pa->computeVertex((x+1)*OOS, y*OOT);
2656 faces.push_back(f);
2663 // ***************************************************************************
2664 CVector CLandscape::getTesselatedPos(const CPatchIdent &patchId, const CUV &uv) const
2666 // First, must update globals, for CTessFace::computeTesselatedPos() to work properly.
2668 // VertexProgrma mode???
2669 CLandscapeGlobals::VertexProgramEnabled= _VertexShaderOk;
2671 // If VertexProgram enabled
2672 if( CLandscapeGlobals::VertexProgramEnabled )
2674 /* because VertexProgram enabled, CTessVertex::Pos (geomorphed Pos) are not computed each frame
2675 Hence, CTessFace::computeTesselatedPos() will call CTessVertex::computeGeomPos() to have correct
2676 CTessVertex::Pos. ThereFore we must setup globals so CTessVertex::computeGeomPos() works properly.
2679 // see copy in updateGlobalsAndLockBuffers(). NB: Just copy what needed here!!!!
2681 // Tile subdivsion part.
2682 CLandscapeGlobals::TileDistNear = _TileDistNear;
2683 CLandscapeGlobals::TileDistFar = CLandscapeGlobals::TileDistNear+20;
2684 CLandscapeGlobals::TileDistNearSqr = sqr(CLandscapeGlobals::TileDistNear);
2685 CLandscapeGlobals::TileDistFarSqr = sqr(CLandscapeGlobals::TileDistFar);
2686 CLandscapeGlobals::OOTileDistDeltaSqr = 1.0f / (CLandscapeGlobals::TileDistFarSqr - CLandscapeGlobals::TileDistNearSqr);
2688 // RefineThreshold.
2689 CLandscapeGlobals::RefineThreshold= _Threshold;
2690 CLandscapeGlobals::OORefineThreshold= 1.0f / CLandscapeGlobals::RefineThreshold;
2692 // Refine Center*.
2693 // NB: setup the last setuped refineCenter.
2694 CLandscapeGlobals::RefineCenter= _OldRefineCenter;
2698 // \todo yoyo: TODO_ZONEID: change ZoneId in 32 bits...
2699 std::map<uint16, CZone*>::const_iterator it= Zones.find((uint16)patchId.ZoneId);
2700 if(it!=Zones.end())
2702 sint N= (*it).second->getNumPatchs();
2703 // patch must exist in the zone.
2704 nlassert(patchId.PatchId<N);
2705 const CPatch *pa= const_cast<const CZone*>((*it).second)->getPatch(patchId.PatchId);
2707 return pa->getTesselatedPos(uv);
2709 else
2710 return CVector::Null;
2714 #define NL_TILE_FAR_SIZE_ORDER0 (NL_NUM_PIXELS_ON_FAR_TILE_EDGE*NL_NUM_PIXELS_ON_FAR_TILE_EDGE)
2715 #define NL_TILE_FAR_SIZE_ORDER1 ((NL_NUM_PIXELS_ON_FAR_TILE_EDGE>>1)*(NL_NUM_PIXELS_ON_FAR_TILE_EDGE>>1))
2716 #define NL_TILE_FAR_SIZE_ORDER2 ((NL_NUM_PIXELS_ON_FAR_TILE_EDGE>>2)*(NL_NUM_PIXELS_ON_FAR_TILE_EDGE>>2))
2718 // ***************************************************************************
2719 // internal use
2720 bool CLandscape::eraseTileFarIfNotGood (uint tileNumber, uint sizeOrder0, uint sizeOrder1, uint sizeOrder2)
2722 // The same tiles ?
2723 bool bSame=true;
2725 // It is the same tile ?
2726 if (TileFarBank.getTile (tileNumber)->isFill (CTileFarBank::diffuse))
2728 // Good diffuse size ?
2729 if (
2730 (TileFarBank.getTile (tileNumber)->getSize (CTileFarBank::diffuse, CTileFarBank::order0) != sizeOrder0) ||
2731 (TileFarBank.getTile (tileNumber)->getSize (CTileFarBank::diffuse, CTileFarBank::order1) != sizeOrder1) ||
2732 (TileFarBank.getTile (tileNumber)->getSize (CTileFarBank::diffuse, CTileFarBank::order2) != sizeOrder2)
2735 TileFarBank.getTile (tileNumber)->erasePixels (CTileFarBank::diffuse);
2736 bSame=false;
2740 // It is the same tile ?
2741 if (TileFarBank.getTile (tileNumber)->isFill (CTileFarBank::additive))
2743 // Good additive size ?
2744 if (
2745 (TileFarBank.getTile (tileNumber)->getSize (CTileFarBank::additive, CTileFarBank::order0) != sizeOrder0) ||
2746 (TileFarBank.getTile (tileNumber)->getSize (CTileFarBank::additive, CTileFarBank::order1) != sizeOrder1) ||
2747 (TileFarBank.getTile (tileNumber)->getSize (CTileFarBank::additive, CTileFarBank::order2) != sizeOrder2)
2750 TileFarBank.getTile (tileNumber)->erasePixels (CTileFarBank::additive);
2751 bSame=false;
2755 // Return true if the tiles seem to be the sames
2756 return bSame;
2759 // ***************************************************************************
2760 bool CLandscape::initTileBanks ()
2762 // *** Check the two banks are OK
2763 _FarInitialized=false;
2765 // Compatibility check
2766 bool bCompatibility=true;
2768 // Same number of tiles
2769 if (TileBank.getTileCount()==TileFarBank.getNumTile())
2771 // Same tileSet
2772 for (int tileSet=0; tileSet<TileBank.getTileSetCount(); tileSet++)
2774 // Same tile128
2775 int tile;
2776 for (tile=0; tile<TileBank.getTileSet(tileSet)->getNumTile128(); tile++)
2778 // tile number
2779 uint tileNumber=TileBank.getTileSet(tileSet)->getTile128(tile);
2781 // erase the tiles if not good
2782 bCompatibility&=eraseTileFarIfNotGood (tileNumber, NL_TILE_FAR_SIZE_ORDER0, NL_TILE_FAR_SIZE_ORDER1, NL_TILE_FAR_SIZE_ORDER2);
2785 // Same tile256
2786 for (tile=0; tile<TileBank.getTileSet(tileSet)->getNumTile256(); tile++)
2788 // tile number
2789 uint tileNumber=TileBank.getTileSet(tileSet)->getTile256(tile);
2791 // erase the tiles if not good
2792 bCompatibility&=eraseTileFarIfNotGood (tileNumber, NL_TILE_FAR_SIZE_ORDER0<<2, NL_TILE_FAR_SIZE_ORDER1<<2, NL_TILE_FAR_SIZE_ORDER2<<2);
2795 // Same transition
2796 for (tile=0; tile<CTileSet::count; tile++)
2798 // tile number
2799 uint tileNumber=TileBank.getTileSet(tileSet)->getTransition(tile)->getTile();
2801 // erase the tiles if not good
2802 bCompatibility&=eraseTileFarIfNotGood (tileNumber, NL_TILE_FAR_SIZE_ORDER0, NL_TILE_FAR_SIZE_ORDER1, NL_TILE_FAR_SIZE_ORDER2);
2806 // Far actived!
2807 _FarInitialized=true;
2810 // Register / Load the vegetables.
2811 TileBank.initTileVegetableDescs(_VegetableManager);
2813 return bCompatibility;
2817 // ***************************************************************************
2818 void CLandscape::setupStaticLight (const CRGBA &diffuse, const CRGBA &ambiant, float multiply)
2820 sint nMultiply=(sint)(256.f*multiply);
2821 for (int i=0; i<256; i++)
2823 sint max=0;
2824 sint r=(((nMultiply*diffuse.R*i)>>8)+ambiant.R*(256-i))>>8;
2825 if (r>max)
2826 max=r;
2827 sint g=(((nMultiply*diffuse.G*i)>>8)+ambiant.G*(256-i))>>8;
2828 if (g>max)
2829 max=g;
2830 sint b=(((nMultiply*diffuse.B*i)>>8)+ambiant.B*(256-i))>>8;
2831 if (b>max)
2832 max=b;
2833 // Not << 8 but << 7 because the _LightValue color table represent a ramp from 0 to 512
2834 r <<= 7;
2835 g <<= 7;
2836 b <<= 7;
2837 max=std::max(max, 256);
2838 r/=max;
2839 g/=max;
2840 b/=max;
2841 clamp (r, 0, 255);
2842 clamp (g, 0, 255);
2843 clamp (b, 0, 255);
2844 _LightValue[i].R=uint8(r);
2845 _LightValue[i].G=uint8(g);
2846 _LightValue[i].B=uint8(b);
2847 _LightValue[i].A=255;
2851 // ***************************************************************************
2852 void CLandscape::enableAutomaticLighting(bool enable)
2854 _AutomaticLighting= enable;
2857 // ***************************************************************************
2858 void CLandscape::setupAutomaticLightDir(const CVector &lightDir)
2860 _AutomaticLightDir= lightDir;
2861 _AutomaticLightDir.normalize();
2865 // ***************************************************************************
2866 CVector CLandscape::getHeightFieldDeltaZ(float x, float y) const
2868 if(_HeightField.ZPatchs.empty())
2869 return CVector::Null;
2871 // map to _HeightField coordinates.
2872 x-= _HeightField.OriginX;
2873 y-= _HeightField.OriginY;
2874 x*= _HeightField.OOSizeX;
2875 y*= _HeightField.OOSizeY;
2876 // get patch on the grid.
2877 sint ix, iy;
2878 ix= (sint)floor(x);
2879 iy= (sint)floor(y);
2880 // out of the grid?
2881 if( ix<0 || ix>=(sint)_HeightField.Width || iy<0 || iy>=(sint)_HeightField.Height)
2882 return CVector::Null;
2884 // get patch.
2885 const CBezierPatchZ &paz= _HeightField.ZPatchs[iy*_HeightField.Width + ix];
2887 // compute result.
2888 CVector ret=CVector::Null;
2889 ret.x= 0;
2890 ret.y= 0;
2891 ret.z= paz.eval(x-ix, y-iy);
2893 return ret;
2898 // ***************************************************************************
2899 void CLandscape::CBezierPatchZ::makeInteriors()
2901 float &a = Vertices[0];
2902 float &b = Vertices[1];
2903 float &c = Vertices[2];
2904 float &d = Vertices[3];
2905 Interiors[0] = Tangents[7] + Tangents[0] - a;
2906 Interiors[1] = Tangents[1] + Tangents[2] - b;
2907 Interiors[2] = Tangents[3] + Tangents[4] - c;
2908 Interiors[3] = Tangents[5] + Tangents[6] - d;
2910 // ***************************************************************************
2911 float CLandscape::CBezierPatchZ::eval(float ps, float pt) const
2913 float p;
2915 float ps2 = ps * ps;
2916 float ps1 = 1.0f - ps;
2917 float ps12 = ps1 * ps1;
2918 float s0 = ps12 * ps1;
2919 float s1 = 3.0f * ps * ps12;
2920 float s2 = 3.0f * ps2 * ps1;
2921 float s3 = ps2 * ps;
2922 float pt2 = pt * pt;
2923 float pt1 = 1.0f - pt;
2924 float pt12 = pt1 * pt1;
2925 float t0 = pt12 * pt1;
2926 float t1 = 3.0f * pt * pt12;
2927 float t2 = 3.0f * pt2 * pt1;
2928 float t3 = pt2 * pt;
2930 p = Vertices[0] * s0 * t0 +
2931 Tangents[7] * s1 * t0 +
2932 Tangents[6] * s2 * t0 +
2933 Vertices[3] * s3 * t0;
2934 p+= Tangents[0] * s0 * t1 +
2935 Interiors[0]* s1 * t1 +
2936 Interiors[3]* s2 * t1 +
2937 Tangents[5] * s3 * t1;
2938 p+= Tangents[1] * s0 * t2 +
2939 Interiors[1]* s1 * t2 +
2940 Interiors[2]* s2 * t2 +
2941 Tangents[4] * s3 * t2;
2942 p+= Vertices[1] * s0 * t3 +
2943 Tangents[2] * s1 * t3 +
2944 Tangents[3] * s2 * t3 +
2945 Vertices[2] * s3 * t3;
2947 return p;
2951 // ***************************************************************************
2952 void CLandscape::setHeightField(const CHeightMap &hf)
2954 if(hf.getWidth()<2)
2955 return;
2956 if(hf.getHeight()<2)
2957 return;
2959 // Fill basics.
2960 _HeightField.OriginX= hf.OriginX;
2961 _HeightField.OriginY= hf.OriginY;
2962 _HeightField.SizeX= hf.SizeX;
2963 _HeightField.SizeY= hf.SizeY;
2964 _HeightField.OOSizeX= 1/hf.SizeX;
2965 _HeightField.OOSizeY= 1/hf.SizeY;
2966 uint w= hf.getWidth()-1;
2967 uint h= hf.getHeight()-1;
2968 _HeightField.Width= w;
2969 _HeightField.Height= h;
2970 _HeightField.ZPatchs.resize(w * h);
2972 // compute patchs
2973 sint x,y;
2975 // compute vertices / tangents on each patch
2976 for(y=0;y<(sint)h;y++)
2978 for(x=0;x<(sint)w;x++)
2980 CBezierPatchZ &paz= _HeightField.ZPatchs[y*w+x];
2981 // vertices.
2982 paz.Vertices[0]= hf.getZ(x, y);
2983 paz.Vertices[1]= hf.getZ(x, y+1);
2984 paz.Vertices[2]= hf.getZ(x+1, y+1);
2985 paz.Vertices[3]= hf.getZ(x+1, y);
2989 // compute tangents
2990 for(y=0;y<(sint)h;y++)
2992 for(x=0;x<(sint)w;x++)
2994 CBezierPatchZ &paz= _HeightField.ZPatchs[y*w+x];
2995 sint tg;
2996 // For each tangent, what vertex (relative to x,y) we must take.
2997 struct CDeltaPos
2999 sint ox,oy;
3000 sint dx1,dy1;
3001 sint dx2,dy2;
3003 static CDeltaPos deltas[8]= {
3004 {0,0, 0,1, 0,-1} ,
3005 {0,1, 0,0, 0,2} ,
3006 {0,1, 1,1, -1,1} ,
3007 {1,1, 0,1, 2,1} ,
3008 {1,1, 1,0, 1,2} ,
3009 {1,0, 1,1, 1,-1} ,
3010 {1,0, 0,0, 2,0} ,
3011 {0,0, 1,0, -1,0} ,
3014 // compute each tangent of this patch.
3015 for(tg=0; tg<8;tg++)
3017 sint x0,y0;
3018 sint x1,y1;
3019 sint x2,y2;
3020 x0= x+deltas[tg].ox; y0= y+deltas[tg].oy;
3021 x1= x+deltas[tg].dx1; y1= y+deltas[tg].dy1;
3022 x2= x+deltas[tg].dx2; y2= y+deltas[tg].dy2;
3024 // borders case.
3025 if(x2<0 || x2>=(sint)hf.getWidth() || y2<0 || y2>=(sint)hf.getHeight())
3027 float v,dv;
3028 // base of tangents.
3029 v= hf.getZ(x0,y0);
3030 // target tangents.
3031 dv= hf.getZ(x1,y1) - v;
3032 // result of tangent.
3033 paz.Tangents[tg]= v+dv/3;
3035 // middle case.
3036 else
3038 float v,dv;
3039 // base of tangents.
3040 v= hf.getZ(x0,y0);
3041 // target tangents.
3042 dv= hf.getZ(x1,y1) - v;
3043 // add mirror target tangent.
3044 dv+= -(hf.getZ(x2,y2) - v);
3045 dv/=2;
3046 // result of tangent.
3047 paz.Tangents[tg]= v+dv/3;
3053 // compute interiors.
3054 for(y=0;y<(sint)h;y++)
3056 for(x=0;x<(sint)w;x++)
3058 CBezierPatchZ &paz= _HeightField.ZPatchs[y*w+x];
3059 paz.makeInteriors();
3066 // ***************************************************************************
3067 void CLandscape::getTessellationLeaves(std::vector<const CTessFace*> &leaves) const
3069 leaves.clear();
3071 std::map<uint16, CZone*>::const_iterator it;
3072 for(it= Zones.begin();it!=Zones.end();it++)
3074 // Then trace all patch.
3075 sint N= (*it).second->getNumPatchs();
3076 for(sint i=0;i<N;i++)
3078 const CPatch *pa= const_cast<const CZone*>((*it).second)->getPatch(i);
3080 pa->appendTessellationLeaves(leaves);
3087 // ***************************************************************************
3088 void CLandscape::setPZBModelPosition(const CVector &pos)
3090 _PZBModelPosition= pos;
3094 // ***************************************************************************
3095 class CTextureFarLevelInfo
3097 public:
3098 uint NumUsedPatchs;
3099 uint NumTextures;
3100 CTextureFarLevelInfo()
3102 NumUsedPatchs= 0;
3103 NumTextures= 0;
3107 void CLandscape::profileRender()
3109 // TODO yoyo: new Far mgt profile
3111 std::map<CVector2f, CTextureFarLevelInfo > levelFarMap;
3113 nlinfo("***** Landscape TextureFar Profile. NumTextureFar= %d", _TextureFars.size());
3114 // Profile Texture Allocate
3115 ItSPRenderPassVector itFar;
3116 uint totalMemUsage= 0;
3117 for(itFar= _TextureFars.begin(); itFar!= _TextureFars.end(); itFar++)
3119 CPatchRdrPass &pass= **itFar;
3120 CTextureFar *textureFar= safe_cast<CTextureFar*>((ITexture*)pass.TextureDiffuse);
3122 // Info
3123 uint memUsage= textureFar->getPatchWidth()*textureFar->getPatchHeight()*NL_NUM_FAR_PATCHES_BY_TEXTURE*2;
3124 nlinfo(" * Patch Texture Size: (%d,%d) => :%d bytes for %d patchs",
3125 textureFar->getPatchWidth(), textureFar->getPatchHeight(),
3126 memUsage, NL_NUM_FAR_PATCHES_BY_TEXTURE);
3127 totalMemUsage+= memUsage;
3129 // Profile Texture Far Allocated
3130 nlinfo(" * NumberOf Patch in the texture:%d", textureFar->getPatchCount());
3132 // Profile currently used Patchs
3133 uint numRdrPatch= 0;
3134 CPatch *pa= pass.getRdrPatchFar0();
3135 while(pa)
3137 numRdrPatch++;
3138 pa= pa->getNextFar0ToRdr();
3140 pa= pass.getRdrPatchFar1();
3141 while(pa)
3143 numRdrPatch++;
3144 pa= pa->getNextFar1ToRdr();
3146 nlinfo(" * NumberOf Patch in frustum for this texture (Far0+Far1):%d", numRdrPatch);
3148 // regroup by level
3149 CVector2f sizeLevel;
3150 sizeLevel.x= (float)textureFar->getPatchWidth();
3151 sizeLevel.y= (float)textureFar->getPatchHeight();
3152 levelFarMap[sizeLevel].NumUsedPatchs+= textureFar->getPatchCount();
3153 levelFarMap[sizeLevel].NumTextures++;
3156 nlinfo("***** Landscape TextureFar Level Profile. TotalVideoMemory= %d", totalMemUsage);
3157 std::map<CVector2f, CTextureFarLevelInfo >::iterator itLevelFar= levelFarMap.begin();
3158 while(itLevelFar!=levelFarMap.end())
3160 nlinfo(" * Level PatchSize: (%d, %d). Total NumberOf Patch: %d. Use Percentage: %d %%",
3161 (uint)itLevelFar->first.x, (uint)itLevelFar->first.y, itLevelFar->second.NumUsedPatchs,
3162 100*itLevelFar->second.NumUsedPatchs/(itLevelFar->second.NumTextures*NL_NUM_FAR_PATCHES_BY_TEXTURE) );
3164 itLevelFar++;
3170 // ***************************************************************************
3171 // ***************************************************************************
3172 // Allocators.
3173 // ***************************************************************************
3174 // ***************************************************************************
3177 // ***************************************************************************
3178 CTessFace *CLandscape::newTessFace()
3180 // allcoate the face.
3181 CTessFace *face= TessFaceAllocator.allocate();
3183 // for refine() mgt, append the face to the list of newLeaves, so they will be tested in refine()
3184 face->linkInPList(_RootNewLeaves);
3186 return face;
3189 // ***************************************************************************
3190 CTessVertex *CLandscape::newTessVertex()
3192 return TessVertexAllocator.allocate();
3195 // ***************************************************************************
3196 CTessNearVertex *CLandscape::newTessNearVertex()
3198 return TessNearVertexAllocator.allocate();
3201 // ***************************************************************************
3202 CTessFarVertex *CLandscape::newTessFarVertex()
3204 return TessFarVertexAllocator.allocate();
3207 // ***************************************************************************
3208 CTileMaterial *CLandscape::newTileMaterial()
3210 return TileMaterialAllocator.allocate();
3213 // ***************************************************************************
3214 CTileFace *CLandscape::newTileFace()
3216 return TileFaceAllocator.allocate();
3219 // ***************************************************************************
3220 void CLandscape::deleteTessFace(CTessFace *f)
3222 // for refine() mgt, must remove from refine priority list, or from the temp rootTessFaceToUpdate list.
3223 f->unlinkInPList();
3225 TessFaceAllocator.freeBlock(f);
3228 // ***************************************************************************
3229 void CLandscape::deleteTessVertex(CTessVertex *v)
3231 TessVertexAllocator.freeBlock(v);
3234 // ***************************************************************************
3235 void CLandscape::deleteTessNearVertex(CTessNearVertex *v)
3237 TessNearVertexAllocator.freeBlock(v);
3240 // ***************************************************************************
3241 void CLandscape::deleteTessFarVertex(CTessFarVertex *v)
3243 TessFarVertexAllocator.freeBlock(v);
3246 // ***************************************************************************
3247 void CLandscape::deleteTileMaterial(CTileMaterial *tm)
3249 TileMaterialAllocator.freeBlock(tm);
3252 // ***************************************************************************
3253 void CLandscape::deleteTileFace(CTileFace *tf)
3255 TileFaceAllocator.freeBlock(tf);
3260 // ***************************************************************************
3261 // ***************************************************************************
3262 // Noise
3263 // ***************************************************************************
3264 // ***************************************************************************
3267 // ***************************************************************************
3268 void CLandscape::setNoiseMode(bool enable)
3270 _NoiseEnabled= enable;
3273 // ***************************************************************************
3274 bool CLandscape::getNoiseMode() const
3276 return _NoiseEnabled;
3280 // ***************************************************************************
3281 // ***************************************************************************
3282 // Micro vegetation
3283 // ***************************************************************************
3284 // ***************************************************************************
3287 // ***************************************************************************
3288 void CLandscape::enableVegetable(bool enable)
3290 _VegetableManagerEnabled= enable;
3292 // if false, delete all Vegetable IGs.
3293 if(!_VegetableManagerEnabled)
3295 // Landscape always create ClipBlokcs, but IGs/addInstances() are created only if isVegetableActive().
3296 // For all zones.
3297 for(ItZoneMap it= Zones.begin();it!=Zones.end();it++)
3299 // for all patch.
3300 sint N= (*it).second->getNumPatchs();
3301 for(sint i=0;i<N;i++)
3303 // delete vegetable Igs of this patch
3304 CPatch *pa= ((*it).second)->getPatch(i);
3305 pa->deleteAllVegetableIgs();
3310 // if true
3311 else
3313 // reload all Shapes (actually load only new shapes)
3314 TileBank.initTileVegetableDescs(_VegetableManager);
3316 // And recreate vegetable igs.
3317 // Landscape always create ClipBlokcs, but IGs/addInstances() are created only if isVegetableActive().
3318 // For all zones.
3319 for(ItZoneMap it= Zones.begin();it!=Zones.end();it++)
3321 // for all patch.
3322 sint N= (*it).second->getNumPatchs();
3323 for(sint i=0;i<N;i++)
3325 // recreate vegetable Igs of this patch
3326 CPatch *pa= ((*it).second)->getPatch(i);
3327 pa->recreateAllVegetableIgs();
3335 // ***************************************************************************
3336 bool CLandscape::isVegetableActive() const
3338 return _VegetableManagerEnabled && _DriverOkForVegetable;
3341 // ***************************************************************************
3342 void CLandscape::loadVegetableTexture(const string &textureFileName)
3344 // load the texture in the manager
3345 _VegetableManager->loadTexture(textureFileName);
3348 // ***************************************************************************
3349 void CLandscape::setupVegetableLighting(const CRGBA &ambient, const CRGBA &diffuse, const CVector &directionalLight)
3351 // set the directional light to the manager
3352 _VegetableManager->setDirectionalLight(ambient, diffuse, directionalLight);
3355 // ***************************************************************************
3356 void CLandscape::setVegetableWind(const CVector &windDir, float windFreq, float windPower, float windBendMin)
3358 // setup vegetable manager
3359 _VegetableManager->setWind(windDir, windFreq, windPower, windBendMin);
3363 // ***************************************************************************
3364 void CLandscape::setVegetableTime(double time)
3366 // setup vegetable manager
3367 _VegetableManager->setTime(time);
3370 // ***************************************************************************
3371 void CLandscape::setVegetableUpdateLightingTime(double time)
3373 // setup vegetable manager
3374 _VegetableManager->setUpdateLightingTime(time);
3378 // ***************************************************************************
3379 uint CLandscape::getNumVegetableFaceRendered() const
3381 return _VegetableManager->getNumVegetableFaceRendered();
3385 // ***************************************************************************
3386 const CTileVegetableDesc &CLandscape::getTileVegetableDesc(uint16 tileId)
3388 return TileBank.getTileVegetableDesc(tileId);
3392 // ***************************************************************************
3393 void CLandscape::createVegetableBlendLayersModels(CScene *scene)
3395 _VegetableManager->createVegetableBlendLayersModels(scene);
3399 // ***************************************************************************
3400 void CLandscape::setVegetableUpdateLightingFrequency(float freq)
3402 _VegetableManager->setUpdateLightingFrequency(freq);
3405 // ***************************************************************************
3406 void CLandscape::setupColorsFromTileFlags(const NLMISC::CRGBA colors[4])
3408 for (TZoneMap::iterator it = Zones.begin(); it != Zones.end(); ++it)
3410 it->second->setupColorsFromTileFlags(colors);
3414 // ***************************************************************************
3415 void CLandscape::setVegetableDensity(float density)
3417 // if the density is really different from what actually setuped
3418 if(density!=_VegetableManager->getGlobalDensity())
3420 _VegetableManager->setGlobalDensity(density);
3422 // must recreate all vegetables IGs
3423 for(ItZoneMap it= Zones.begin();it!=Zones.end();it++)
3425 // for all patch.
3426 sint N= (*it).second->getNumPatchs();
3427 for(sint i=0;i<N;i++)
3429 // delete vegetable Igs of this patch
3430 CPatch *pa= ((*it).second)->getPatch(i);
3431 pa->deleteAllVegetableIgs();
3432 // then recreate vegetable Igs of this patch
3433 pa->recreateAllVegetableIgs();
3441 // ***************************************************************************
3442 float CLandscape::getVegetableDensity() const
3444 return _VegetableManager->getGlobalDensity();
3447 // ***************************************************************************
3448 // ***************************************************************************
3449 // Lightmap Get interface.
3450 // ***************************************************************************
3451 // ***************************************************************************
3454 // ***************************************************************************
3455 uint8 CLandscape::getLumel(const CPatchIdent &patchId, const CUV &uv) const
3457 // \todo yoyo: TODO_ZONEID: change ZoneId in 32 bits...
3458 std::map<uint16, CZone*>::const_iterator it= Zones.find((uint16)patchId.ZoneId);
3459 if(it!=Zones.end())
3461 sint N= (*it).second->getNumPatchs();
3462 // patch must exist in the zone.
3463 nlassert(patchId.PatchId<N);
3464 const CPatch *pa= const_cast<const CZone*>((*it).second)->getPatch(patchId.PatchId);
3466 return pa->getLumel(uv);
3468 else
3469 // Return full sun contribution as default
3470 return 255;
3473 // ***************************************************************************
3474 void CLandscape::appendTileLightInfluences(const CPatchIdent &patchId, const CUV &uv,
3475 std::vector<CPointLightInfluence> &pointLightList) const
3477 // \todo yoyo: TODO_ZONEID: change ZoneId in 32 bits...
3478 std::map<uint16, CZone*>::const_iterator it= Zones.find((uint16)patchId.ZoneId);
3479 if(it!=Zones.end())
3481 sint N= (*it).second->getNumPatchs();
3482 // patch must exist in the zone.
3483 nlassert(patchId.PatchId<N);
3484 const CPatch *pa= const_cast<const CZone*>((*it).second)->getPatch(patchId.PatchId);
3486 pa->appendTileLightInfluences(uv, pointLightList);
3491 // ***************************************************************************
3492 // ***************************************************************************
3493 // Lighting
3494 // ***************************************************************************
3495 // ***************************************************************************
3498 // ***************************************************************************
3499 void CLandscape::removeAllPointLights()
3501 for(ItZoneMap it= Zones.begin();it!=Zones.end();it++)
3503 // for all patch.
3504 sint N= (*it).second->getNumPatchs();
3505 for(sint i=0;i<N;i++)
3507 // Clear TileLightInfluences
3508 CPatch *pa= ((*it).second)->getPatch(i);
3509 pa->resetTileLightInfluences();
3512 // Remove all PointLights.
3513 (*it).second->_PointLightArray.clear();
3519 // ***************************************************************************
3520 void CLandscape::setPointLightFactor(const CScene &scene)
3522 // Affect currently added zones.
3523 for(ItZoneMap it= Zones.begin();it!=Zones.end();it++)
3525 (*it).second->_PointLightArray.setPointLightFactor(scene);
3530 // ***************************************************************************
3531 void CLandscape::updateLighting(double time)
3533 _ULTime= time;
3535 // first time in this method??
3536 if(!_ULPrecTimeInit)
3538 _ULPrecTimeInit= true;
3539 _ULPrecTime= _ULTime;
3541 // compute delta time from last update.
3542 float dt= float(_ULTime - _ULPrecTime);
3543 _ULPrecTime= _ULTime;
3546 // If not disabled
3547 if(_ULFrequency)
3549 // Do it for near and far in 2 distinct ways.
3550 updateLightingTextureFar(dt * _ULFrequency);
3551 updateLightingTextureNear(dt * _ULFrequency);
3557 // ***************************************************************************
3558 void CLandscape::updateLightingAll()
3560 // Do it for near and far in 2 distinct ways.
3561 //================
3562 updateLightingTextureFar(1);
3563 updateLightingTextureNear(1);
3566 // update lighting for vegetables
3567 //================
3569 // Must lock buffers for update Lighting of vegetables.
3570 updateGlobalsAndLockBuffers (CVector::Null);
3572 // Because updateLighting() may use OptFastFloor..
3573 NLMISC::OptFastFloorBegin();
3575 // update ALL lighting for vegetables
3576 _VegetableManager->updateLightingAll();
3578 // Stop fastFloor optim.
3579 NLMISC::OptFastFloorEnd();
3581 // Must realase VB Buffers
3582 unlockBuffers();
3586 // ***************************************************************************
3587 void CLandscape::setUpdateLightingFrequency(float freq)
3589 freq= max(freq, 0.f);
3590 _ULFrequency= freq;
3594 // ***************************************************************************
3595 void CLandscape::linkPatchToNearUL(CPatch *patch)
3597 // Append this patch to the list of patch to updateLighting.
3598 if(_ULRootNearPatch==NULL)
3599 _ULRootNearPatch= patch;
3600 else
3601 patch->linkBeforeNearUL(_ULRootNearPatch);
3604 // ***************************************************************************
3605 void CLandscape::unlinkPatchFromNearUL(CPatch *patch)
3607 // If I unlink the patch which is the current root
3608 if(_ULRootNearPatch==patch)
3610 // switch to next
3611 _ULRootNearPatch= patch->getNextNearUL();
3612 // if still the same, it means that the circular list is now empty
3613 if(_ULRootNearPatch==patch)
3614 _ULRootNearPatch= NULL;
3615 // reset tessBlock counter.
3616 _ULNearCurrentTessBlockId= 0;
3619 // unlink the patch from list
3620 patch->unlinkNearUL();
3624 // ***************************************************************************
3625 void CLandscape::updateLightingTextureFar(float ratio)
3627 // compute number of pixels to update.
3628 _ULFarPixelsToUpdate+= ratio * _ULTotalFarPixels;
3629 // maximize, so at max, it computes all patchs, just one time.
3630 _ULFarPixelsToUpdate= min(_ULFarPixelsToUpdate, (float)_ULTotalFarPixels);
3632 // Test Profile Yoyo
3633 /*extern bool YOYO_LandULTest;
3634 if(YOYO_LandULTest)
3636 nlinfo("YOYO_UL Far: %dK, %dK", (sint)_ULFarPixelsToUpdate/1024, (sint)_ULTotalFarPixels/1024);
3639 // while there is still some pixels to update.
3640 while(_ULFarPixelsToUpdate > 0 && _ULRootTextureFar)
3642 // update patch (if not null) in the textureFar.
3643 _ULFarPixelsToUpdate-= _ULRootTextureFar->touchPatchULAndNext();
3645 // last patch in the texture??
3646 if( _ULRootTextureFar->endPatchULTouch() )
3648 // yes, go to next texture.
3649 _ULRootTextureFar= _ULRootTextureFar->getNextUL();
3650 // reset to 0th patch.
3651 _ULRootTextureFar->startPatchULTouch();
3655 // Now, _ULFarPixelsToUpdate should be <=0. (most of the time < 0)
3659 // ***************************************************************************
3660 void CLandscape::updateLightingTextureNear(float ratio)
3662 // compute number of pixels to update.
3663 _ULNearPixelsToUpdate+= ratio * _ULTotalNearPixels;
3664 // maximize, so at max, it computes all patchs, just one time.
3665 _ULNearPixelsToUpdate= min(_ULNearPixelsToUpdate, (float)_ULTotalNearPixels);
3668 // while there is still some pixels to update.
3669 while(_ULNearPixelsToUpdate > 0 && _ULRootNearPatch)
3671 // update tessBlock (if lightmap exist for this tessBlock) in the patch.
3672 _ULNearPixelsToUpdate-= _ULRootNearPatch->updateTessBlockLighting(_ULNearCurrentTessBlockId);
3673 // Next tessBlock to process.
3674 _ULNearCurrentTessBlockId++;
3676 // last tessBlock in the patch??
3677 if(_ULNearCurrentTessBlockId>=_ULRootNearPatch->getNumNearTessBlocks())
3679 // yes, go to next patch.
3680 _ULRootNearPatch= _ULRootNearPatch->getNextNearUL();
3681 // reset to 0th tessBlock.
3682 _ULNearCurrentTessBlockId=0;
3689 // ***************************************************************************
3690 void CLandscape::computeDynamicLighting(const std::vector<CPointLight*> &pls)
3692 uint i;
3694 // Update globals, and lock buffers
3695 //====================
3696 updateGlobalsAndLockBuffers (CVector::Null);
3697 // NB: averageTesselationVertices may change vertices in VB in visible patchs => buffers are locked.
3700 // Run all DLM Context create, to init Lighting process.
3701 //===============
3702 CPatchDLMContext *ctxPtr= _PatchDLMContextList->begin();
3703 while(ctxPtr!=NULL)
3705 // init lighting process, do differential from last computeDynamicLighting()
3706 ctxPtr->getPatch()->beginDLMLighting();
3708 // next
3709 ctxPtr= (CPatchDLMContext*)ctxPtr->Next;
3713 // compile all pointLights
3714 //===============
3715 static vector<CPatchDLMPointLight> dlmPls;
3716 dlmPls.resize(pls.size());
3717 for(i=0;i<dlmPls.size();i++)
3719 // compile the pl.
3720 dlmPls[i].compile(*pls[i], _PointLightDiffuseMaterial, _DLMMaxAttEnd);
3724 // For all pointLight, intersect patch.
3725 //===============
3726 for(i=0;i<dlmPls.size();i++)
3728 CPatchDLMPointLight &pl= dlmPls[i];
3730 // search patchs of interest: those which interssect the pointLight
3731 _PatchQuadGrid.clearSelection();
3732 _PatchQuadGrid.select(pl.BBox.getMin(), pl.BBox.getMax());
3733 CQuadGrid<CPatchIdentEx>::CIterator it;
3735 // for each patch, light it with the light.
3736 for(it= _PatchQuadGrid.begin(); it!= _PatchQuadGrid.end(); it++)
3738 // get the patch
3739 const CPatch *pa= (*it).Patch;
3741 // More precise clipping:
3742 if( pa->getZone()->getPatchBSphere(pa->getPatchId()).intersect( pl.BSphere ) )
3744 // Ok, light the patch with this spotLight
3745 const_cast<CPatch*>(pa)->processDLMLight(pl);
3752 // Run all DLM Context create, to end Lighting process.
3753 //===============
3754 ctxPtr= _PatchDLMContextList->begin();
3755 while(ctxPtr!=NULL)
3757 // get enxt now, because the DLM itself may be deleted in endDLMLighting()
3758 CPatchDLMContext *next= (CPatchDLMContext*)ctxPtr->Next;
3760 // delete the DLM if no more needed (near don't use nor pointLights)
3761 ctxPtr->getPatch()->endDLMLighting();
3763 // next
3764 ctxPtr= next;
3768 // Must realase VB Buffers
3769 //====================
3770 unlockBuffers();
3775 // ***************************************************************************
3776 void CLandscape::setDynamicLightingMaxAttEnd(float maxAttEnd)
3778 maxAttEnd= max(maxAttEnd, 1.f);
3779 _DLMMaxAttEnd= maxAttEnd;
3783 // ***************************************************************************
3784 uint CLandscape::getDynamicLightingMemoryLoad() const
3786 uint mem= 0;
3787 // First, set size of global texture overhead.
3788 mem= NL3D_LANDSCAPE_DLM_WIDTH * NL3D_LANDSCAPE_DLM_HEIGHT * sizeof(CRGBA);
3790 // Then, for each patchContext created
3791 CPatchDLMContext *ctxPtr= _PatchDLMContextList->begin();
3792 while(ctxPtr!=NULL)
3794 // add its memory load.
3795 mem+= ctxPtr->getMemorySize();
3797 // next
3798 ctxPtr= (CPatchDLMContext*)ctxPtr->Next;
3801 return mem;
3805 // ***************************************************************************
3806 void CLandscape::setDLMGlobalVegetableColor(CRGBA gvc)
3808 _DLMGlobalVegetableColor= gvc;
3812 // ***************************************************************************
3813 void CLandscape::setPointLightDiffuseMaterial(CRGBA diffuse)
3815 _PointLightDiffuseMaterial= diffuse;
3819 // ***************************************************************************
3820 void CLandscape::initAnimatedLightIndex(const CScene &scene)
3822 // Affect currently added zones.
3823 for(ItZoneMap it= Zones.begin();it!=Zones.end();it++)
3825 (*it).second->_PointLightArray.initAnimatedLightIndex(scene);
3829 // ***************************************************************************
3830 void CLandscape::releaseAllTiles()
3832 nlassert(Zones.empty());
3833 releaseTiles (0, (uint32)TileInfos.size());
3837 // ***************************************************************************
3838 // ***************************************************************************
3839 // Dynamic ShadowMaping
3840 // ***************************************************************************
3841 // ***************************************************************************
3844 // ***************************************************************************
3845 void CLandscape::appendToShadowPolyReceiver(CTessFace *face)
3847 CTriangle tri;
3848 tri.V0= face->VBase->EndPos;
3849 tri.V1= face->VLeft->EndPos;
3850 tri.V2= face->VRight->EndPos;
3851 // Add and store id for remove
3852 face->ShadowMapTriId= _ShadowPolyReceiver.addTriangle(tri);
3855 // ***************************************************************************
3856 void CLandscape::removeFromShadowPolyReceiver(CTessFace *face)
3858 if(face->ShadowMapTriId!=-1)
3860 _ShadowPolyReceiver.removeTriangle(face->ShadowMapTriId);
3861 // set NULL Id.
3862 face->ShadowMapTriId=-1;
3867 // ***************************************************************************
3868 void CLandscape::receiveShadowMap(IDriver *drv, CShadowMap *shadowMap, const CVector &casterPos, const CMaterial &shadowMat, const CVector &pzb)
3870 /* substract the PZB from all coordinates.
3872 Must add a small zbias because
3873 The rendered Triangles may be computed with VertexProgram, but _ShadowPolyReceiver
3874 does not. => there is a small float difference at the end
3875 Even if same vertex is produced in theory, VertexProgram may cause 2 precision problems:
3876 1/ On NVidia, even with a simple matrix mul VP, the precision result is not the same
3877 2/ Our Landscape VP is not a simple matrix mul. Lot of vertex mul/add are done fpr geomorphs
3879 CMaterial &sm= const_cast<CMaterial&>(shadowMat);
3880 float oldZBias= sm.getZBias();
3881 sm.setZBias(-0.02f);
3882 _ShadowPolyReceiver.render(drv, sm, shadowMap, casterPos, -pzb);
3883 sm.setZBias(oldZBias);
3886 // ***************************************************************************
3887 void CLandscape::setZFunc(CMaterial::ZFunc val)
3889 TileMaterial.setZFunc(val);
3890 FarMaterial.setZFunc(val);
3893 // ***************************************************************************
3894 void CLandscape::invalidateAllTiles()
3897 updateGlobalsAndLockBuffers(CVector::Null);
3898 for(TZoneMap::iterator it = Zones.begin(); it != Zones.end(); ++it)
3900 if (it->second->Compiled)
3902 for(uint k = 0; k < it->second->Patchs.size(); ++k)
3904 it->second->Patchs[k].deleteTileUvs();
3905 it->second->Patchs[k].recreateTileUvs();
3909 unlockBuffers();
3910 updateTessBlocksFaceVector();
3913 // ***************************************************************************
3914 float CLandscape::getCameraCollision(const CVector &start, const CVector &end, float radius, bool cone)
3916 return _ShadowPolyReceiver.getCameraCollision(start, end,
3917 cone?CShadowPolyReceiver::CameraColCone:CShadowPolyReceiver::CameraColCylinder, radius);
3920 // ***************************************************************************
3921 float CLandscape::getRayCollision(const CVector &start, const CVector &end)
3923 return _ShadowPolyReceiver.getCameraCollision(start, end,
3924 CShadowPolyReceiver::CameraColSimpleRay, 0.f);
3927 // ***************************************************************************
3928 bool CLandscape::isTileCallback(ULandscapeTileCallback *cb) const
3930 return std::find(_TileCallbacks.begin(), _TileCallbacks.end(), cb) != _TileCallbacks.end();
3933 // ***************************************************************************
3934 void CLandscape::addTileCallback(ULandscapeTileCallback *cb)
3936 nlassert(cb);
3937 nlassert(!isTileCallback(cb)); // callback added twice
3938 _TileCallbacks.push_back(cb);
3941 // ***************************************************************************
3942 void CLandscape::removeTileCallback(ULandscapeTileCallback *cb)
3944 nlassert(cb);
3945 std::vector<ULandscapeTileCallback *>::iterator it = std::find(_TileCallbacks.begin(), _TileCallbacks.end(), cb);
3946 nlassert(it != _TileCallbacks.end());
3947 _TileCallbacks.erase(it);
3952 } // NL3D