Merge branch 'ryzom/ark-features' into main/gingo-test
[ryzomcore.git] / nel / src / 3d / scene.cpp
blob651837e2cb5d4267b249403fcbd5090d0c9addde
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-2020 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"
22 #include "nel/3d/scene.h"
23 #include "nel/3d/trav_scene.h"
24 #include "nel/3d/hrc_trav.h"
25 #include "nel/3d/clip_trav.h"
26 #include "nel/3d/light_trav.h"
27 #include "nel/3d/anim_detail_trav.h"
28 #include "nel/3d/load_balancing_trav.h"
29 #include "nel/3d/render_trav.h"
30 #include "nel/3d/transform.h"
31 #include "nel/3d/camera.h"
32 #include "nel/3d/landscape_model.h"
33 #include "nel/3d/driver.h"
34 #include "nel/3d/transform_shape.h"
35 #include "nel/3d/mesh_base.h"
36 #include "nel/3d/mesh_base_instance.h"
37 #include "nel/3d/mesh_instance.h"
38 #include "nel/3d/mesh_mrm_instance.h"
39 #include "nel/3d/mesh_mrm_skinned_instance.h"
40 #include "nel/3d/mesh_multi_lod_instance.h"
41 #include "nel/3d/shape_bank.h"
42 #include "nel/3d/skeleton_model.h"
43 #include "nel/3d/particle_system_model.h"
44 #include "nel/3d/coarse_mesh_manager.h"
45 #include "nel/3d/cluster.h"
46 #include "nel/3d/scene_group.h"
47 #include "nel/3d/flare_model.h"
48 #include "nel/3d/water_model.h"
49 #include "nel/3d/vegetable_blend_layer_model.h"
50 #include "nel/3d/root_model.h"
51 #include "nel/3d/point_light_model.h"
52 #include "nel/3d/animation.h"
53 #include "nel/3d/lod_character_manager.h"
54 #include "nel/3d/seg_remanence.h"
55 #include "nel/3d/async_texture_manager.h"
56 #include "nel/3d/water_env_map.h"
57 #include "nel/3d/skeleton_spawn_script.h"
60 #include <memory>
62 #include "nel/misc/time_nl.h"
63 #include "nel/misc/file.h"
64 #include "nel/misc/path.h"
67 #include "nel/misc/system_info.h"
69 using namespace std;
70 using namespace NLMISC;
72 #ifdef DEBUG_NEW
73 #define new DEBUG_NEW
74 #endif
76 #define NL3D_SCENE_COARSE_MANAGER_TEXTURE "nel_coarse_texture.tga"
79 // The manager is limited to a square of 3000m*3000m around the camera. Beyond, models are clipped individually (bad!!).
80 const float NL3D_QuadGridClipManagerRadiusMax= 1500;
81 const float NL3D_QuadGridClipClusterSize= 400;
82 const uint NL3D_QuadGridClipNumDist= 10;
83 const float NL3D_QuadGridClipMaxDist= 1000;
86 #define NL3D_SCENE_DEFAULT_SHADOW_MAP_SIZE 64
87 #define NL3D_SCENE_DEFAULT_SHADOW_MAP_BLUR_SIZE 2
88 #define NL3D_SCENE_DEFAULT_SHADOW_MAP_DIST_FADE_START 40
89 #define NL3D_SCENE_DEFAULT_SHADOW_MAP_DIST_FADE_END 50
90 #define NL3D_SCENE_DEFAULT_SHADOW_MAP_MAX_CASTER_IN_SCREEN 16
91 #define NL3D_SCENE_DEFAULT_SHADOW_MAP_MAX_CASTER_AROUND 64
94 namespace NL3D
97 // ***************************************************************************
98 // ***************************************************************************
99 // ***************************************************************************
102 void CScene::registerBasics()
104 CTransform::registerBasic();
105 CCamera::registerBasic();
106 CMeshBaseInstance::registerBasic();
107 CMeshInstance::registerBasic();
108 CMeshMRMInstance::registerBasic();
109 CMeshMRMSkinnedInstance::registerBasic();
110 CLandscapeModel::registerBasic();
111 CTransformShape::registerBasic();
112 CSkeletonModel::registerBasic();
113 CParticleSystemModel::registerBasic() ;
114 CMeshMultiLodInstance::registerBasic();
115 CCluster::registerBasic();
116 CFlareModel::registerBasic();
117 CWaterModel::registerBasic();
118 CWaveMakerModel::registerBasic();
119 CVegetableBlendLayerModel::registerBasic();
120 CRootModel::registerBasic();
121 CPointLightModel::registerBasic();
122 CSegRemanence::registerBasic();
123 CQuadGridClipManager::registerBasic();
127 // ***************************************************************************
128 // ***************************************************************************
129 // ***************************************************************************
131 // ***************************************************************************
132 CScene::CScene(bool bSmallScene) : LightTrav(bSmallScene)
134 HrcTrav.Scene= this;
135 ClipTrav.Scene= this;
136 LightTrav.Scene= this;
137 AnimDetailTrav.Scene= this;
138 LoadBalancingTrav.Scene= this;
139 RenderTrav.Scene= this;
141 _ShapeBank = NULL;
143 Root= NULL;
144 RootCluster= NULL;
145 SonsOfAncestorSkeletonModelGroup= NULL;
146 _QuadGridClipManager= NULL;
148 _CurrentTime = 0 ;
149 _EllapsedTime = 0 ;
150 _RealTime = 0 ;
151 _FirstAnimateCall = true ;
153 _LightingSystemEnabled= false;
154 _CoarseMeshLightingUpdate= 50;
156 _GlobalWindDirection.set(1,0,0);
157 // Default as Sithikt wants.
158 _GlobalWindPower= 0.2f;
160 // global manager (created in CDriverUser)
161 _LodCharacterManager= NULL;
162 _AsyncTextureManager= NULL;
164 _NumRender = 0;
166 _MaxSkeletonsInNotCLodForm= 20;
168 _FilterRenderFlags = std::numeric_limits<uint32>::max();
170 _NextRenderProfile= false;
172 // Init default _CoarseMeshManager
173 _CoarseMeshManager= new CCoarseMeshManager;
174 _CoarseMeshManager->setTextureFile (NL3D_SCENE_COARSE_MANAGER_TEXTURE);
176 // Update model list to NULL
177 _UpdateModelList= NULL;
179 _FlareContext = 0;
181 _ShadowMapTextureSize= NL3D_SCENE_DEFAULT_SHADOW_MAP_SIZE;
182 _ShadowMapBlurSize= NL3D_SCENE_DEFAULT_SHADOW_MAP_BLUR_SIZE;
183 _ShadowMapDistFadeStart= NL3D_SCENE_DEFAULT_SHADOW_MAP_DIST_FADE_START;
184 _ShadowMapDistFadeEnd= NL3D_SCENE_DEFAULT_SHADOW_MAP_DIST_FADE_END;
185 _ShadowMapMaxCasterInScreen= NL3D_SCENE_DEFAULT_SHADOW_MAP_MAX_CASTER_IN_SCREEN;
186 _ShadowMapMaxCasterAround= NL3D_SCENE_DEFAULT_SHADOW_MAP_MAX_CASTER_AROUND;
187 _VisualCollisionManagerForShadow= NULL;
189 _WaterCallback = NULL;
190 _PolyDrawingCallback = NULL;
191 _IsRendering = false;
193 _FirstFlare = NULL;
194 _RenderedPart = UScene::RenderNothing;
195 //_WaterEnvMapRdr = NULL;
196 //_WaterEnvMap = new CTextureCube;
198 _WaterEnvMap = NULL;
200 _GlobalSystemTime= 0.0;
202 _RequestParticlesAnimate = false;
204 // ***************************************************************************
205 void CScene::release()
207 // reset the _QuadGridClipManager, => unlink models, and delete clusters.
208 if( _QuadGridClipManager )
209 _QuadGridClipManager->reset();
211 // First, delete models.
212 set<CTransform*>::iterator it;
213 it= _Models.begin();
214 while( it!=_Models.end())
216 CTransform *tr= *it;
217 // Don't delete The Roots, because used, for instance in ~CSkeletonModel()
218 if(tr!=Root && tr!=RootCluster && tr!=SonsOfAncestorSkeletonModelGroup)
219 deleteModel(tr);
220 // temp erase from the list
221 else
222 _Models.erase(it);
223 // NB: important to take begin(), and not it++, cause ~CSkeletonModel() may delete ScriptSpawned models
224 it= _Models.begin();
227 // Then delete the roots
228 // reinsert
229 if(Root) _Models.insert(Root);
230 if(RootCluster) _Models.insert(RootCluster);
231 if(SonsOfAncestorSkeletonModelGroup) _Models.insert(SonsOfAncestorSkeletonModelGroup);
232 // delete in the reverse order of initDefaultRoots()
233 if(SonsOfAncestorSkeletonModelGroup)
235 deleteModel(SonsOfAncestorSkeletonModelGroup);
236 SonsOfAncestorSkeletonModelGroup= NULL;
238 if(RootCluster)
240 deleteModel(RootCluster);
241 RootCluster= NULL;
243 if(Root)
245 deleteModel(Root);
246 Root= NULL;
249 // No models at all.
250 _UpdateModelList= NULL;
252 // reset ptrs
253 _ShapeBank = NULL;
254 Root= NULL;
255 RootCluster= NULL;
256 SonsOfAncestorSkeletonModelGroup= NULL;
257 CurrentCamera= NULL;
258 _QuadGridClipManager= NULL;
259 ClipTrav.setQuadGridClipManager(NULL);
261 // DON'T reset the _LodCharacterManager, because it can be shared across scenes
263 if(_LodCharacterManager)
264 _LodCharacterManager->reset();
266 _LodCharacterManager= NULL;
268 // delete the coarseMeshManager
269 if(_CoarseMeshManager)
271 delete _CoarseMeshManager;
272 _CoarseMeshManager= NULL;
275 if(_GlobalInstanceGroup)
277 delete _GlobalInstanceGroup;
278 _GlobalInstanceGroup = NULL;
281 // delete the play list
282 _LMAnimsAuto.deleteAll();
284 // ***************************************************************************
285 CScene::~CScene()
287 release();
289 // ***************************************************************************
290 void CScene::initDefaultRoots()
292 // Create and set root the default models.
293 Root= static_cast<CTransform*>(createModel(TransformId));
295 // The root is always freezed (never move).
296 Root->freeze();
298 // Init the instance group that represent the world
299 _GlobalInstanceGroup = new CInstanceGroup;
300 RootCluster= (CCluster*)createModel (ClusterId);
301 // unlink from hrc.
302 RootCluster->hrcUnlink();
303 RootCluster->Name = "ClusterRoot";
304 RootCluster->Group = _GlobalInstanceGroup;
305 _GlobalInstanceGroup->addCluster (RootCluster);
307 // init the ClipTrav.RootCluster.
308 ClipTrav.RootCluster = RootCluster;
310 // Create a SonsOfAncestorSkeletonModelGroup, for models which have a skeleton ancestor
311 SonsOfAncestorSkeletonModelGroup= static_cast<CRootModel*>(createModel(RootModelId));
312 // must unlink it from all traversals, because special, only used in CClipTrav::traverse()
313 SonsOfAncestorSkeletonModelGroup->hrcUnlink();
314 Root->clipDelChild(SonsOfAncestorSkeletonModelGroup);
317 // ***************************************************************************
318 void CScene::initQuadGridClipManager ()
320 // Init clip features.
321 if( !_QuadGridClipManager )
323 // create the model
324 _QuadGridClipManager= static_cast<CQuadGridClipManager*>(createModel(QuadGridClipManagerId));
325 // unlink it from hrc, and link it only to RootCluster.
326 // NB: hence the quadGridClipManager may be clipped by the cluster system
327 _QuadGridClipManager->hrcUnlink();
328 _QuadGridClipManager->clipUnlinkFromAll();
329 RootCluster->clipAddChild(_QuadGridClipManager);
331 // init _QuadGridClipManager.
332 _QuadGridClipManager->init(NL3D_QuadGridClipClusterSize,
333 NL3D_QuadGridClipNumDist,
334 NL3D_QuadGridClipMaxDist,
335 NL3D_QuadGridClipManagerRadiusMax);
340 // ***************************************************************************
341 void CScene::render(bool doHrcPass)
343 beginPartRender();
344 renderPart(UScene::RenderAll, doHrcPass);
345 endPartRender();
349 // ***************************************************************************
350 void CScene::beginPartRender()
352 nlassert(!_IsRendering);
354 // Do not delete model during the rendering
355 // Also do not create model with CSkeletonSpawnScript model animation
356 _IsRendering = true;
357 _RenderedPart= UScene::RenderNothing;
362 // ***************************************************************************
363 void CScene::endPartRender(bool keepTrav)
365 nlassert(_IsRendering);
366 _IsRendering = false;
368 if (!keepTrav)
370 // Delete model deleted during the rendering
371 uint i;
372 for (i=0; i<_ToDelete.size(); i++)
373 deleteModel (_ToDelete[i]);
374 _ToDelete.clear ();
376 // Special for SkeletonSpawnScript animation. create models spawned now
377 flushSSSModelRequests();
379 // Particle system handling (remove the resources of those which are too far, as their clusters may not have been parsed).
380 // Note that only a few of them are tested at each call
381 _ParticleSystemManager.refreshModels(ClipTrav.WorldFrustumPyramid, ClipTrav.CamPos);
383 // Waiting Instance handling
384 double deltaT = _DeltaSystemTimeBetweenRender;
385 clamp (deltaT, 0.01, 0.1);
386 updateWaitingInstances(deltaT);
389 // Reset profiling
390 _NextRenderProfile= false;
392 IDriver *drv = getDriver();
393 drv->activeVertexProgram(NULL);
394 drv->activePixelProgram(NULL);
395 drv->activeGeometryProgram(NULL);
397 // Ensure nothing animates on subsequent renders
398 _EllapsedTime = 0.f;
401 uint64 total = PSStatsRegisterPSModelObserver +
402 PSStatsRemovePSModelObserver +
403 PSStatsUpdateOpacityInfos +
404 PSStatsUpdateLightingInfos +
405 PSStatsGetAABBox +
406 PSStatsReallocRsc +
407 PSStatsReleasePSPointer +
408 PSStatsRefreshRscDeletion +
409 PSStatsReleaseRsc +
410 PSStatsReleaseRscAndInvalidate +
411 PSStatsGetNumTriangles +
412 PSStatsCheckAgainstPyramid +
413 PSStatsTraverseAnimDetail +
414 PSStatsDoAnimate +
415 PSStatsTraverseRender +
416 PSStatsTraverseClip +
417 PSStatsCheckDestroyCondition +
418 PSStatsForceInstanciate +
419 PSStatsDoAnimatePart1 +
420 PSStatsDoAnimatePart2 +
421 PSStatsDoAnimatePart3 +
422 PSStatsTraverseAnimDetailPart1 +
423 PSStatsTraverseAnimDetailPart2 +
424 PSStatsTraverseAnimDetailPart3 +
425 PSStatsTraverseAnimDetailPart4 +
426 PSAnim1 +
427 PSAnim2+
428 PSAnim3+
429 PSAnim4+
430 PSAnim5+
431 PSAnim6+
432 PSAnim7+
433 PSAnim8+
434 PSAnim9+
435 PSAnim10+
436 PSAnim11;
439 if (((double) total / (double) NLMISC::CSystemInfo::getProcessorFrequency()) > 0.01)
441 nlinfo("***** PS STATS ****");
442 #define PS_STATS(var) \
443 nlinfo("time for " #var " = %.2f", (float) (1000 * ((double) var / (double) CSystemInfo::getProcessorFrequency())));
445 PS_STATS(PSStatsRegisterPSModelObserver)
446 PS_STATS(PSStatsRemovePSModelObserver)
447 PS_STATS(PSStatsUpdateOpacityInfos)
448 PS_STATS(PSStatsUpdateLightingInfos)
449 PS_STATS(PSStatsGetAABBox)
450 PS_STATS(PSStatsReallocRsc)
451 PS_STATS(PSStatsReleasePSPointer)
452 PS_STATS(PSStatsRefreshRscDeletion)
453 PS_STATS(PSStatsReleaseRsc)
454 PS_STATS(PSStatsReleaseRscAndInvalidate)
455 PS_STATS(PSStatsGetNumTriangles)
456 PS_STATS(PSStatsCheckAgainstPyramid)
457 PS_STATS(PSStatsTraverseAnimDetail)
458 PS_STATS(PSStatsDoAnimate)
459 PS_STATS(PSStatsTraverseRender)
460 PS_STATS(PSStatsTraverseClip)
461 PS_STATS(PSStatsClipSystemInstanciated);
462 PS_STATS(PSStatsClipSystemNotInstanciated);
463 PS_STATS(PSStatsClipSystemCheckAgainstPyramid);
464 PS_STATS(PSStatsInsertInVisibleList);
465 PS_STATS(PSStatsCheckDestroyCondition)
466 PS_STATS(PSStatsForceInstanciate)
467 PS_STATS(PSStatsDoAnimatePart1)
468 PS_STATS(PSStatsDoAnimatePart2)
469 PS_STATS(PSStatsDoAnimatePart3)
470 PS_STATS(PSStatsTraverseAnimDetailPart1)
471 PS_STATS(PSStatsTraverseAnimDetailPart2)
472 PS_STATS(PSStatsTraverseAnimDetailPart3)
473 PS_STATS(PSStatsTraverseAnimDetailPart4)
474 PS_STATS(PSAnim1)
475 PS_STATS(PSAnim2)
476 PS_STATS(PSAnim3)
477 PS_STATS(PSAnim4)
478 PS_STATS(PSAnim5)
479 PS_STATS(PSAnim6)
480 PS_STATS(PSAnim7)
481 PS_STATS(PSAnim8)
482 PS_STATS(PSAnim9)
483 PS_STATS(PSAnim10)
484 PS_STATS(PSAnim11)
485 PS_STATS(PSStatsZonePlane)
486 PS_STATS(PSStatsZoneSphere)
487 PS_STATS(PSStatsZoneDisc)
488 PS_STATS(PSStatsZoneRectangle)
489 PS_STATS(PSStatsZoneCylinder)
490 PS_STATS(PSMotion1)
491 PS_STATS(PSMotion2)
492 PS_STATS(PSMotion3)
493 PS_STATS(PSMotion4)
494 PS_STATS(PSStatCollision)
495 PS_STATS(PSStatEmit)
496 PS_STATS(PSStatRender)
499 nlinfo("num do animate = %d", (int) PSStatsNumDoAnimateCalls);
501 nlinfo("Max et = %.2f", PSMaxET);
502 nlinfo("Max ps nb pass = %d", (int) PSMaxNBPass);
504 PS_STATS(total)
508 PSStatsRegisterPSModelObserver = 0;
509 PSStatsRemovePSModelObserver = 0;
510 PSStatsUpdateOpacityInfos = 0;
511 PSStatsUpdateLightingInfos = 0;
512 PSStatsGetAABBox = 0;
513 PSStatsReallocRsc = 0;
514 PSStatsReleasePSPointer = 0;
515 PSStatsRefreshRscDeletion = 0;
516 PSStatsReleaseRsc = 0;
517 PSStatsReleaseRscAndInvalidate = 0;
518 PSStatsGetNumTriangles = 0;
519 PSStatsCheckAgainstPyramid = 0;
520 PSStatsTraverseAnimDetail = 0;
521 PSStatsDoAnimate = 0;
522 PSStatsTraverseRender = 0;
523 PSStatsTraverseClip = 0;
524 PSStatsCheckDestroyCondition = 0;
525 PSStatsForceInstanciate = 0;
526 PSStatsClipSystemInstanciated = 0;
527 PSStatsClipSystemNotInstanciated = 0;
528 PSStatsClipSystemCheckAgainstPyramid = 0;
529 PSStatsInsertInVisibleList = 0;
530 PSStatsDoAnimatePart1 = 0;
531 PSStatsDoAnimatePart2 = 0;
532 PSStatsDoAnimatePart3 = 0;
533 PSStatsTraverseAnimDetailPart1 = 0;
534 PSStatsTraverseAnimDetailPart2 = 0;
535 PSStatsTraverseAnimDetailPart3 = 0;
536 PSStatsTraverseAnimDetailPart4 = 0;
537 PSStatsNumDoAnimateCalls = 0;
538 PSAnim1 = 0;
539 PSAnim2 = 0;
540 PSAnim3 = 0;
541 PSAnim4 = 0;
542 PSAnim5 = 0;
543 PSAnim6 = 0;
544 PSAnim7 = 0;
545 PSAnim8 = 0;
546 PSAnim9 = 0;
547 PSAnim10 = 0;
548 PSAnim11 = 0;
549 PSMaxET = 0.f;
550 PSMaxNBPass = 0;
551 PSStatsZonePlane = 0;
552 PSStatsZoneSphere = 0;
553 PSStatsZoneDisc = 0;
554 PSStatsZoneRectangle = 0;
555 PSStatsZoneCylinder = 0;
556 PSMotion1 = 0;
557 PSMotion2 = 0;
558 PSMotion3 = 0;
559 PSMotion4 = 0;
560 PSStatCollision = 0;
561 PSStatEmit = 0;
562 PSStatRender = 0;
567 // ***************************************************************************
568 void CScene::renderPart(UScene::TRenderPart rp, bool doHrcPass, bool doTrav, bool keepTrav)
570 nlassert(_IsRendering);
572 // if nothing (????), abort
573 if(rp==UScene::RenderNothing)
574 return;
576 // If part asked already rendered, abort
577 nlassert((rp & _RenderedPart) == 0); // cannot render the same part twice during a render
579 // if first part to be rendered, do the start stuff
580 if (_RenderedPart == UScene::RenderNothing)
582 RenderTrav.clearWaterModelList();
584 if (doTrav)
586 // update water envmap
587 //updateWaterEnvmap();
588 _FirstFlare = NULL;
590 double fNewGlobalSystemTime = NLMISC::CTime::ticksToSecond(NLMISC::CTime::getPerformanceTime());
591 if(_GlobalSystemTime==0)
592 _DeltaSystemTimeBetweenRender= 0.020;
593 else
594 _DeltaSystemTimeBetweenRender= fNewGlobalSystemTime - _GlobalSystemTime;
595 _GlobalSystemTime = fNewGlobalSystemTime;
598 ++ _NumRender;
600 nlassert(CurrentCamera);
602 // update models.
603 updateModels();
605 // Use the camera to setup Clip / Render pass.
606 float left, right, bottom, top, znear, zfar;
607 CurrentCamera->getFrustum(left, right, bottom, top, znear, zfar);
609 // setup basic camera.
610 ClipTrav.setFrustum(left, right, bottom, top, znear, zfar, CurrentCamera->isPerspective());
612 RenderTrav.setFrustum (left, right, bottom, top, znear, zfar, CurrentCamera->isPerspective());
613 RenderTrav.setViewport (_Viewport);
615 LoadBalancingTrav.setFrustum (left, right, bottom, top, znear, zfar, CurrentCamera->isPerspective());
618 // Set Infos for cliptrav.
619 ClipTrav.Camera = CurrentCamera;
620 ClipTrav.setQuadGridClipManager (_QuadGridClipManager);
623 // **** For all render traversals, traverse them (except the Hrc one), in ascending order.
624 if( doHrcPass )
625 HrcTrav.traverse();
626 else
627 HrcTrav._MovingObjects.clear();
629 // Set Cam World Matrix for all trav that need it
630 ClipTrav.setCamMatrix(CurrentCamera->getWorldMatrix());
631 RenderTrav.setCamMatrix (CurrentCamera->getWorldMatrix());
632 LoadBalancingTrav.setCamMatrix (CurrentCamera->getWorldMatrix());
634 // clip
635 ClipTrav.traverse();
637 // animDetail
638 AnimDetailTrav.traverse();
640 // loadBalance
641 LoadBalancingTrav.traverse();
643 if (doTrav)
646 if (_RequestParticlesAnimate)
648 _ParticleSystemManager.processAnimate(_EllapsedTime); // deals with permanently animated particle systems
649 _RequestParticlesAnimate = false;
653 // Light
654 LightTrav.traverse();
657 // render
658 RenderTrav.traverse(rp, (_RenderedPart == UScene::RenderNothing), doTrav);
659 if (!keepTrav)
661 // Always must clear shadow caster (if render did not work because of IDriver::isLost())
662 RenderTrav.getShadowMapManager().clearAllShadowCasters();
665 // render flare
666 if (rp & UScene::RenderFlare)
668 if (doTrav)
670 if (_FirstFlare)
672 IDriver *drv = getDriver();
673 CFlareModel::updateOcclusionQueryBegin(drv);
674 CFlareModel *currFlare = _FirstFlare;
677 currFlare->updateOcclusionQuery(drv);
678 currFlare = currFlare->Next;
680 while(currFlare);
681 CFlareModel::updateOcclusionQueryEnd(drv);
684 else
686 _FirstFlare = NULL;
689 _RenderedPart = (UScene::TRenderPart) (_RenderedPart | rp);
692 // ***************************************************************************
693 void CScene::updateWaitingInstances(double systemTimeEllapsed)
695 // First set up max AGP upload
696 double fMaxBytesToUp = 100 * 256 * 256 * systemTimeEllapsed;
697 _ShapeBank->setMaxBytesToUpload ((uint32)fMaxBytesToUp);
698 // Parse all the waiting instance
699 _ShapeBank->processWaitingShapes (); // Process waiting shapes load shape, texture, and lightmaps
700 // and upload all maps to VRAM pieces by pieces
701 TWaitingInstancesMMap::iterator wimmIt = _WaitingInstances.begin();
702 while( wimmIt != _WaitingInstances.end() )
704 CShapeBank::TShapeState st = _ShapeBank->getPresentState (wimmIt->first);
705 if (st == CShapeBank::AsyncLoad_Error)
707 // Delete the waiting instance - Nobody can be informed of that...
708 TWaitingInstancesMMap::iterator itDel= wimmIt;
709 ++wimmIt;
710 _WaitingInstances.erase(itDel);
712 else if (st == CShapeBank::Present)
714 // Then create a reference to the shape
715 *(wimmIt->second) = _ShapeBank->addRef(wimmIt->first)->createInstance (*this);
716 // Delete the waiting instance
717 TWaitingInstancesMMap::iterator itDel= wimmIt;
718 ++wimmIt;
719 _WaitingInstances.erase(itDel);
721 else // st == CShapeBank::NotPresent or loading
723 ++wimmIt;
728 // ***************************************************************************
729 void CScene::setDriver(IDriver *drv)
731 RenderTrav.setDriver(drv);
734 // ***************************************************************************
735 IDriver *CScene::getDriver() const
737 return (const_cast<CScene*>(this))->RenderTrav.getDriver();
741 // ***************************************************************************
742 // ***************************************************************************
743 // Shape mgt.
744 // ***************************************************************************
745 // ***************************************************************************
747 // ***************************************************************************
749 void CScene::setShapeBank(CShapeBank*pShapeBank)
751 _ShapeBank = pShapeBank;
754 // ***************************************************************************
756 CTransformShape *CScene::createInstance(const string &shapeName)
758 // We must attach a bank to the scene (a ShapeBank handle the shape caches and
759 // the creation/deletion of the instances)
760 nlassert( _ShapeBank != NULL );
762 // If the shape is not present in the bank
763 if (_ShapeBank->getPresentState( shapeName ) != CShapeBank::Present)
765 // Load it from file
766 _ShapeBank->load( shapeName );
767 if (_ShapeBank->getPresentState( shapeName ) != CShapeBank::Present)
769 return NULL;
772 // Then create a reference to the shape
773 CTransformShape *pTShp = _ShapeBank->addRef( shapeName )->createInstance(*this);
774 if (pTShp) pTShp->setDistMax(pTShp->Shape->getDistMax());
776 // Look if this instance get lightmap information
777 #if defined(__GNUC__) && __GNUC__ < 3
778 CMeshBase *pMB = pTShp ? (CMeshBase*)((IShape*)(pTShp->Shape)) : NULL;
779 #else // not GNUC
780 CMeshBase *pMB = pTShp ? dynamic_cast<CMeshBase*>((IShape*)(pTShp->Shape)) : NULL;
781 #endif // not GNUC
782 CMeshBaseInstance *pMBI = dynamic_cast<CMeshBaseInstance*>( pTShp );
783 if( ( pMB != NULL ) && ( pMBI != NULL ) )
785 // Init lightmap information
786 pMBI->initAnimatedLightIndex (*this);
788 // Auto animations
789 //==========================
791 if (_AutomaticAnimationSet)
793 if (pMB->getAutoAnim())
796 std::string animName = toLowerAscii(CFile::getFilenameWithoutExtension(shapeName));
797 uint animID = _AutomaticAnimationSet->getAnimationIdByName(animName);
798 if (animID != CAnimationSet::NotFound)
800 CChannelMixer *chanMix = new CChannelMixer;
801 chanMix->setAnimationSet((CAnimationSet *) _AutomaticAnimationSet);
802 chanMix->setSlotAnimation(0, animID);
804 pMBI->registerToChannelMixer(chanMix, "");
805 // Gives this object ownership of the channel mixer so we don't need to keep track of it
806 pMBI->setChannelMixerOwnerShip(true);
812 CLandscapeModel *pLM = dynamic_cast<CLandscapeModel*>( pTShp );
813 if( pLM != NULL )
815 // Init lightmap information
816 pLM->Landscape.initAnimatedLightIndex (*this);
819 return pTShp;
822 // ***************************************************************************
824 void CScene::createInstanceAsync(const string &shapeName, CTransformShape **pInstance, const NLMISC::CVector &position, uint selectedTexture)
826 // We must attach a bank to the scene (a ShapeBank handle the shape caches and
827 // the creation/deletion of the instances)
828 nlassert( _ShapeBank != NULL );
829 *pInstance = NULL;
830 // Add the instance request
831 _WaitingInstances.insert(TWaitingInstancesMMap::value_type(shapeName,pInstance));
832 // If the shape is not present in the bank
833 if (_ShapeBank->getPresentState( shapeName ) != CShapeBank::Present)
835 // Load it from file asynchronously
836 _ShapeBank->loadAsync( toLowerAscii(shapeName), getDriver(), position, NULL, selectedTexture);
840 // ***************************************************************************
841 void CScene::deleteInstance(CTransformShape *pTrfmShp)
843 IShape *pShp = NULL;
844 if( pTrfmShp == NULL )
845 return;
847 pShp = pTrfmShp->Shape;
849 deleteModel( pTrfmShp );
851 if (pShp)
853 // Even if model already deleted by smarptr the release function works
854 _ShapeBank->release( pShp );
859 // ***************************************************************************
860 void CScene::animate( TGlobalAnimationTime atTime )
862 // todo hulud remove
863 if (_FirstAnimateCall)
865 _InitTime = atTime;
866 _RealTime = atTime;
867 // dummy value for first frame
868 _EllapsedTime = 0.01f ;
869 _FirstAnimateCall = false ;
871 else
873 _EllapsedTime = (float) (atTime - _RealTime);
874 //nlassert(_EllapsedTime >= 0);
875 if (_EllapsedTime < 0.0f) // NT WorkStation PATCH (Yes you are not dreaming
876 _EllapsedTime = 0.01f; // deltaTime can be less than zero!!)
877 _EllapsedTime = fabsf(_EllapsedTime);
878 _RealTime = atTime ;
879 _CurrentTime += _EllapsedTime;
882 _LMAnimsAuto.animate( atTime );
884 // Change PointLightFactors of all pointLights in registered Igs.
885 //----------------
887 // First list all current AnimatedLightmaps (for faster vector iteration per ig)
888 const uint count = (uint)_AnimatedLightPtr.size ();
889 uint i;
890 for (i=0; i<count; i++)
892 // Blend final colors
893 _AnimatedLightPtr[i]->updateGroupColors (*this);
896 // For all registered igs.
897 ItAnimatedIgSet itAnIgSet;
898 for(itAnIgSet= _AnimatedIgSet.begin(); itAnIgSet!=_AnimatedIgSet.end(); itAnIgSet++)
900 CInstanceGroup *ig= *itAnIgSet;
902 // Set the light factor
903 ig->setPointLightFactor(*this);
906 // Rendered part are invalidate
907 _RenderedPart = UScene::RenderNothing;
909 // Particles are animated later due to dependencies
910 _RequestParticlesAnimate = true;
914 // ***************************************************************************
915 float CScene::getNbFaceAsked () const
917 return LoadBalancingTrav.getNbFaceAsked ();
921 // ***************************************************************************
922 void CScene::setGroupLoadMaxPolygon(const std::string &group, uint nFaces)
924 nFaces= max(nFaces, (uint)1);
925 LoadBalancingTrav.setGroupNbFaceWanted(group, nFaces);
927 // ***************************************************************************
928 uint CScene::getGroupLoadMaxPolygon(const std::string &group)
930 return LoadBalancingTrav.getGroupNbFaceWanted(group);
932 // ***************************************************************************
933 float CScene::getGroupNbFaceAsked (const std::string &group) const
935 return LoadBalancingTrav.getGroupNbFaceAsked(group);
940 // ***************************************************************************
941 void CScene::setPolygonBalancingMode(TPolygonBalancingMode polBalMode)
943 LoadBalancingTrav.PolygonBalancingMode= (CLoadBalancingGroup::TPolygonBalancingMode)(uint)polBalMode;
947 // ***************************************************************************
948 CScene::TPolygonBalancingMode CScene::getPolygonBalancingMode() const
950 return (CScene::TPolygonBalancingMode)(uint)LoadBalancingTrav.PolygonBalancingMode;
953 // ***************************************************************************
954 void CScene::setLayersRenderingOrder(bool directOrder /*= true*/)
956 RenderTrav.setLayersRenderingOrder(directOrder);
959 // ***************************************************************************
960 bool CScene::getLayersRenderingOrder() const
962 return RenderTrav.getLayersRenderingOrder();
965 // ***************************************************************************
966 CParticleSystemManager &CScene::getParticleSystemManager()
968 return _ParticleSystemManager;
971 // ***************************************************************************
972 void CScene::enableElementRender(UScene::TRenderFilter elt, bool state)
974 if(state)
975 _FilterRenderFlags|= (uint32)elt;
976 else
977 _FilterRenderFlags&= ~(uint32)elt;
981 // ***************************************************************************
982 // ***************************************************************************
983 // Lighting Mgt.
984 // ***************************************************************************
985 // ***************************************************************************
988 // ***************************************************************************
989 void CScene::enableLightingSystem(bool enable)
991 _LightingSystemEnabled= enable;
993 // Set to RenderTrav and LightTrav
994 RenderTrav.LightingSystemEnabled= _LightingSystemEnabled;
995 LightTrav.LightingSystemEnabled= _LightingSystemEnabled;
999 // ***************************************************************************
1000 void CScene::setAmbientGlobal(NLMISC::CRGBA ambient)
1002 RenderTrav.AmbientGlobal= ambient;
1004 void CScene::setSunAmbient(NLMISC::CRGBA ambient)
1006 RenderTrav.SunAmbient= ambient;
1008 void CScene::setSunDiffuse(NLMISC::CRGBA diffuse)
1010 RenderTrav.SunDiffuse= diffuse;
1012 void CScene::setSunSpecular(NLMISC::CRGBA specular)
1014 RenderTrav.SunSpecular= specular;
1016 void CScene::setSunDirection(const NLMISC::CVector &direction)
1018 RenderTrav.setSunDirection(direction);
1022 // ***************************************************************************
1023 NLMISC::CRGBA CScene::getAmbientGlobal() const
1025 return RenderTrav.AmbientGlobal;
1027 NLMISC::CRGBA CScene::getSunAmbient() const
1029 return RenderTrav.SunAmbient;
1031 NLMISC::CRGBA CScene::getSunDiffuse() const
1033 return RenderTrav.SunDiffuse;
1035 NLMISC::CRGBA CScene::getSunSpecular() const
1037 return RenderTrav.SunSpecular;
1039 NLMISC::CVector CScene::getSunDirection() const
1041 return RenderTrav.getSunDirection();
1045 // ***************************************************************************
1046 void CScene::setMaxLightContribution(uint nlights)
1048 LightTrav.LightingManager.setMaxLightContribution(nlights);
1050 uint CScene::getMaxLightContribution() const
1052 return LightTrav.LightingManager.getMaxLightContribution();
1055 void CScene::setLightTransitionThreshold(float lightTransitionThreshold)
1057 LightTrav.LightingManager.setLightTransitionThreshold(lightTransitionThreshold);
1059 float CScene::getLightTransitionThreshold() const
1061 return LightTrav.LightingManager.getLightTransitionThreshold();
1065 // ***************************************************************************
1066 void CScene::addInstanceGroupForLightAnimation(CInstanceGroup *ig)
1068 nlassert( ig );
1069 nlassert( _AnimatedIgSet.find(ig) == _AnimatedIgSet.end() );
1070 _AnimatedIgSet.insert(ig);
1073 // ***************************************************************************
1074 void CScene::removeInstanceGroupForLightAnimation(CInstanceGroup *ig)
1076 nlassert( ig );
1077 ItAnimatedIgSet itIg= _AnimatedIgSet.find(ig);
1078 if ( itIg != _AnimatedIgSet.end() )
1079 _AnimatedIgSet.erase(itIg);
1083 // ***************************************************************************
1084 void CScene::setCoarseMeshLightingUpdate(uint8 period)
1086 _CoarseMeshLightingUpdate= max((uint8)1, period);
1090 // ***************************************************************************
1091 // ***************************************************************************
1092 /// Weather mgt
1093 // ***************************************************************************
1094 // ***************************************************************************
1096 // ***************************************************************************
1097 void CScene::setGlobalWindPower(float gwp)
1099 _GlobalWindPower= gwp;
1101 // ***************************************************************************
1102 void CScene::setGlobalWindDirection(const CVector &gwd)
1104 _GlobalWindDirection= gwd;
1105 _GlobalWindDirection.z= 0;
1106 _GlobalWindDirection.normalize();
1110 // ***************************************************************************
1111 // ***************************************************************************
1112 /// Private
1113 // ***************************************************************************
1114 // ***************************************************************************
1116 // ***************************************************************************
1117 CScene::ItSkeletonModelList CScene::appendSkeletonModelToList(CSkeletonModel *skel)
1119 _SkeletonModelList.push_front(skel);
1120 return _SkeletonModelList.begin();
1123 // ***************************************************************************
1124 void CScene::eraseSkeletonModelToList(CScene::ItSkeletonModelList it)
1126 _SkeletonModelList.erase(it);
1129 // ***************************************************************************
1130 void CScene::registerShadowCasterToList(CTransform *sc)
1132 nlassert(sc);
1133 _ShadowCasterList.push_front(sc);
1134 sc->_ItShadowCasterInScene= _ShadowCasterList.begin();
1137 // ***************************************************************************
1138 void CScene::unregisterShadowCasterToList(CTransform *sc)
1140 nlassert(sc);
1141 _ShadowCasterList.erase(sc->_ItShadowCasterInScene);
1145 // ***************************************************************************
1146 // ***************************************************************************
1147 // Old CMOT integrated methods
1148 // ***************************************************************************
1149 // ***************************************************************************
1152 // ***************************************************************************
1153 set<CScene::CModelEntry> CScene::_RegModels;
1156 // ***************************************************************************
1157 void CScene::registerModel(const CClassId &idModel, const CClassId &idModelBase, CTransform* (*creator)())
1159 nlassert(idModel!=CClassId::Null);
1160 nlassert(creator);
1161 // idModelBase may be Null...
1163 CModelEntry e;
1164 e.BaseModelId= idModelBase;
1165 e.ModelId= idModel;
1166 e.Creator= creator;
1168 // Insert/replace e.
1169 _RegModels.erase(e);
1170 _RegModels.insert(e);
1174 // ***************************************************************************
1175 CTransform *CScene::createModel(const CClassId &idModel)
1177 nlassert(idModel!=CClassId::Null);
1179 CModelEntry e;
1180 e.ModelId= idModel;
1181 set<CModelEntry>::iterator itModel;
1182 itModel= _RegModels.find(e);
1184 if(itModel==_RegModels.end())
1186 nlstop; // Warning, CScene::registerBasics () has not been called !
1187 return NULL;
1189 else
1191 CTransform *m= (*itModel).Creator();
1192 if(!m) return NULL;
1194 // Set the owner for the model.
1195 m->_OwnerScene= this;
1197 // link model to Root in HRC and in clip. NB: if exist!! (case for the Root and RootCluster :) )
1198 if(Root)
1200 Root->hrcLinkSon(m);
1201 Root->clipAddChild(m);
1204 // Insert the model into the set.
1205 _Models.insert(m);
1207 // By default the model is update() in CScene::updateModels().
1208 m->linkToUpdateList();
1210 // Once the model is correclty created, finish init him.
1211 m->initModel();
1213 // Ensure all the Traversals has enough space for visible list.
1214 ClipTrav.reserveVisibleList((uint)_Models.size());
1215 AnimDetailTrav.reserveVisibleList((uint)_Models.size());
1216 LoadBalancingTrav.reserveVisibleList((uint)_Models.size());
1217 LightTrav.reserveLightedList((uint)_Models.size());
1218 RenderTrav.reserveRenderList((uint)_Models.size());
1220 return m;
1223 // ***************************************************************************
1224 void CScene::deleteModel(CTransform *model)
1226 if(model==NULL)
1227 return;
1229 // No model delete during the render
1230 if (_IsRendering)
1232 // add ot list of object to delete
1233 _ToDelete.push_back (model);
1234 // remove this object from the RenderTrav, hence it won't be displayed
1235 // still animDetail/Light/LoadBalance it. This is useless, but very rare
1236 // and I prefer doing like this than to add a NULL ptr Test in each Traversal (which I then must do in CRenderTrav)
1237 RenderTrav.removeRenderModel(model);
1239 // standard delete
1240 else
1242 set<CTransform*>::iterator it= _Models.find(model);
1243 if(it!=_Models.end())
1245 delete *it;
1246 _Models.erase(it);
1252 // ***************************************************************************
1253 void CScene::updateModels()
1255 // check all the models which must be checked.
1256 CTransform *model= _UpdateModelList;
1257 CTransform *next;
1258 while( model )
1260 // next to update. get next now, because model->update() may remove model from the list.
1261 next= model->_NextModelToUpdate;
1263 // update the model.
1264 model->update();
1266 // next.
1267 model= next;
1272 // ***************************************************************************
1273 void CScene::setLightGroupColor(uint lightmapGroup, NLMISC::CRGBA color)
1275 // If too small, resize with white
1276 if (lightmapGroup >= _LightGroupColor.size ())
1278 _LightGroupColor.resize (lightmapGroup+1, CRGBA::White);
1281 // Set the color
1282 _LightGroupColor[lightmapGroup] = color;
1286 // ***************************************************************************
1287 sint CScene::getAnimatedLightNameToIndex (const std::string &name) const
1289 std::map<std::string, uint>::const_iterator ite = _AnimatedLightNameToIndex.find (name);
1290 if (ite != _AnimatedLightNameToIndex.end ())
1291 return (sint)ite->second;
1292 else
1293 return -1;
1297 // ***************************************************************************
1298 void CScene::setAutomaticAnimationSet(CAnimationSet *as)
1300 // Backup the animation set
1301 _AutomaticAnimationSet = as;
1303 // Delete all auto lightmap animations
1304 _LMAnimsAuto.deleteAll();
1305 _AnimatedLightNameToIndex.clear();
1306 _AnimatedLight.clear();
1307 _AnimatedLightPtr.clear();
1308 _LightGroupColor.clear();
1310 // Register each animation as lightmap
1311 const uint count = _AutomaticAnimationSet->getNumAnimation();
1312 uint i;
1313 for (i=0; i<count; i++)
1315 // Pointer on the animation
1316 CAnimation *pAnim = _AutomaticAnimationSet->getAnimation(i);
1318 /* uint nAnimNb;
1319 // Reset the automatic animation if no animation wanted
1320 if( pAnim == NULL )
1322 _AnimatedLight.clear();
1323 _AnimatedLightPtr.clear();
1324 _AnimatedLightNameToIndex.clear();
1325 nAnimNb = _LightmapAnimations.getAnimationIdByName("Automatic");
1326 if( nAnimNb != CAnimationSet::NotFound )
1328 CAnimation *anim = _LightmapAnimations.getAnimation( nAnimNb );
1329 delete anim;
1331 _LightmapAnimations.reset();
1332 _LMAnimsAuto.deleteAll();
1333 return;
1337 set<string> setTrackNames;
1338 pAnim->getTrackNames( setTrackNames );
1340 // nAnimNb = _LightmapAnimations.addAnimation( "Automatic", pAnim );
1341 // _LightmapAnimations.build();
1343 set<string>::iterator itSel = setTrackNames.begin();
1344 while ( itSel != setTrackNames.end() )
1346 string ate = *itSel;
1347 if( strncmp( itSel->c_str(), "LightmapController.", 19 ) == 0 )
1349 // The light name
1350 const char *lightName = strrchr ((*itSel).c_str (), '.')+1;
1352 // Light animation doesn't exist ?
1353 if (_AnimatedLightNameToIndex.find (lightName) == _AnimatedLightNameToIndex.end())
1355 // Channel mixer for light anim
1356 CChannelMixer *cm = new CChannelMixer();
1357 cm->setAnimationSet( _AutomaticAnimationSet );
1359 // Add an automatic animation
1360 _AnimatedLight.push_back ( CAnimatedLightmap ((uint)_LightGroupColor.size ()) );
1361 _AnimatedLightPtr.push_back ( &_AnimatedLight.back () );
1362 _AnimatedLightNameToIndex.insert ( std::map<std::string, uint>::value_type (lightName, (uint32)_AnimatedLightPtr.size ()-1 ) );
1363 CAnimatedLightmap &animLM = _AnimatedLight.back ();
1364 animLM.setName( *itSel );
1366 cm->addChannel( animLM.getName(), &animLM, animLM.getValue(CAnimatedLightmap::FactorValue),
1367 animLM.getDefaultTrack(CAnimatedLightmap::FactorValue), CAnimatedLightmap::FactorValue,
1368 CAnimatedLightmap::OwnerBit, false);
1370 // Animated lightmap playlist
1371 CAnimationPlaylist *pl = new CAnimationPlaylist();
1372 pl->setAnimation( 0, i );
1373 pl->setWrapMode( 0, CAnimationPlaylist::Repeat );
1374 _LMAnimsAuto.addPlaylist(pl,cm);
1377 ++itSel;
1383 // ***************************************************************************
1384 // ***************************************************************************
1385 /// Misc
1386 // ***************************************************************************
1387 // ***************************************************************************
1389 // ***************************************************************************
1390 void CScene::profileNextRender()
1392 _NextRenderProfile= true;
1394 // Reset All Stats.
1395 BenchRes.reset();
1399 // ***************************************************************************
1400 void CScene::setShadowMapTextureSize(uint size)
1402 size= max(size, 2U);
1403 size= raiseToNextPowerOf2(size);
1404 _ShadowMapTextureSize= size;
1407 // ***************************************************************************
1408 void CScene::setShadowMapBlurSize(uint bs)
1410 _ShadowMapBlurSize= bs;
1413 // ***************************************************************************
1414 void CScene::enableShadowPolySmooth(bool enable)
1416 RenderTrav.getShadowMapManager().enableShadowPolySmooth(enable);
1419 // ***************************************************************************
1420 bool CScene::getEnableShadowPolySmooth() const
1422 return RenderTrav.getShadowMapManager().getEnableShadowPolySmooth();
1426 // ***************************************************************************
1427 void CScene::setShadowMapDistFadeStart(float dist)
1429 _ShadowMapDistFadeStart= max(0.f, dist);
1431 // ***************************************************************************
1432 void CScene::setShadowMapDistFadeEnd(float dist)
1434 _ShadowMapDistFadeEnd= max(0.f, dist);
1436 // ***************************************************************************
1437 void CScene::setShadowMapMaxCasterInScreen(uint num)
1439 _ShadowMapMaxCasterInScreen= num;
1441 // ***************************************************************************
1442 void CScene::setShadowMapMaxCasterAround(uint num)
1444 _ShadowMapMaxCasterAround= num;
1447 // ***************************************************************************
1448 CInstanceGroup *CScene::findCameraClusterSystemFromRay(CInstanceGroup *startClusterSystem,
1449 const NLMISC::CVector &startPos, NLMISC::CVector &endPos)
1451 CInstanceGroup *resultCS= NULL;
1453 CClipTrav &clipTrav= getClipTrav();
1455 // **** Search all cluster where the startPos is in
1456 static vector<CCluster*> vCluster;
1457 vCluster.clear();
1459 bool bInWorld = true;
1460 clipTrav.Accel.select (startPos, startPos);
1461 CQuadGrid<CCluster*>::CIterator itAcc = clipTrav.Accel.begin();
1462 while (itAcc != clipTrav.Accel.end())
1464 CCluster *pCluster = *itAcc;
1465 if( pCluster->Group == startClusterSystem &&
1466 pCluster->isIn (startPos) )
1468 vCluster.push_back (pCluster);
1469 bInWorld = false;
1471 ++itAcc;
1473 if (bInWorld)
1475 vCluster.push_back (RootCluster);
1478 // **** Do a traverse starting from each start cluser, clipping the ray instead of the camera pyramid
1479 uint i;
1480 static vector<CCluster*> vClusterVisited;
1481 vClusterVisited.clear();
1482 for(i=0;i<vCluster.size();i++)
1484 vCluster[i]->cameraRayClip(startPos, endPos, vClusterVisited);
1487 // **** From each cluster, select possible clusterSystem
1488 static vector<CInstanceGroup*> possibleClusterSystem;
1489 possibleClusterSystem.clear();
1490 for(i=0;i<vClusterVisited.size();i++)
1492 // select only cluster where the EndPos lies in. Important else in landscape, we'll always say
1493 // that we are in a Son Cluster.
1494 if(vClusterVisited[i]->isIn(endPos))
1496 CInstanceGroup *cs= vClusterVisited[i]->Group;
1497 // insert if not exist (NB: 1,2 possible clusterSystem so O(N2) is OK)
1498 uint j;
1499 for(j=0;j<possibleClusterSystem.size();j++)
1501 if(possibleClusterSystem[j]==cs)
1502 break;
1504 if(j==possibleClusterSystem.size())
1505 possibleClusterSystem.push_back(cs);
1509 // If no cluster found, then we may be in a "Data Error case".
1510 // In this case, ensure the Camera position in a cluster
1511 if(possibleClusterSystem.empty())
1513 CCluster *bestCluster= NULL;
1514 float shortDist= FLT_MAX;
1516 for(i=0;i<vClusterVisited.size();i++)
1518 // if the ray is at least partially in this cluster
1519 CVector a= startPos;
1520 CVector b= endPos;
1521 if(vClusterVisited[i]->clipSegment(a, b))
1523 float dist= (endPos - b).norm();
1524 if(dist<shortDist)
1526 bestCluster= vClusterVisited[i];
1527 shortDist= dist;
1532 // if found
1533 if(bestCluster)
1535 // append the best one to the possible Cluster System
1536 possibleClusterSystem.push_back(bestCluster->Group);
1538 // and modify endPos, so the camera will really lies into this cluster
1539 const float threshold= 0.05f;
1540 shortDist+= threshold;
1541 // must not goes more than startPos!
1542 float rayDist= (startPos - endPos).norm();
1543 shortDist= min(shortDist, rayDist);
1544 endPos+= (startPos - endPos).normed() * shortDist;
1548 // NB: still possible that the possibleClusterSystem is empty, if not in any cluster for instance :)
1551 // **** From each possible clusterSystem, select the one that is the lower in hierarchy
1552 // common case
1553 if(possibleClusterSystem.empty())
1554 resultCS= NULL;
1555 else if(possibleClusterSystem.size()==1)
1557 // if it is the rootCluster set NULL (should have the same behavior but do like standard case)
1558 if(possibleClusterSystem[0]==RootCluster->getClusterSystem())
1559 resultCS= NULL;
1560 // set this cluster system
1561 else
1562 resultCS= possibleClusterSystem[0];
1564 // conflict case
1565 else
1567 // compute the hierarchy level of each cluster system, take the highest
1568 CInstanceGroup *highest= NULL;
1569 uint highestLevel= 0;
1570 for(i=0;i<possibleClusterSystem.size();i++)
1572 uint level= 0;
1573 CInstanceGroup *ig= possibleClusterSystem[i];
1574 while(ig)
1576 ig= ig->getParentClusterSystem();
1577 level++;
1579 if(level>=highestLevel)
1581 highestLevel= level;
1582 highest= possibleClusterSystem[i];
1586 // set the highest cluster system
1587 resultCS= highest;
1590 return resultCS;
1593 // ***************************************************************************
1594 void CScene::renderOcclusionTestMeshsWithCurrMaterial()
1596 for(std::set<CTransform*>::iterator it = _Models.begin(); it != _Models.end(); ++it)
1598 if ((*it)->isFlare())
1600 CFlareModel *flare = NLMISC::safe_cast<CFlareModel *>(*it);
1601 flare->renderOcclusionTestMesh(*RenderTrav.getDriver());
1606 // ***************************************************************************
1607 void CScene::renderOcclusionTestMeshs()
1609 nlassert(RenderTrav.getDriver());
1610 RenderTrav.getDriver()->setupViewport(RenderTrav.getViewport());
1611 RenderTrav.getDriver()->activeVertexProgram(NULL);
1612 RenderTrav.getDriver()->activePixelProgram(NULL);
1613 RenderTrav.getDriver()->activeGeometryProgram(NULL);
1614 IDriver::TPolygonMode oldPolygonMode = RenderTrav.getDriver()->getPolygonMode();
1615 CMaterial m;
1616 m.initUnlit();
1617 m.setColor(CRGBA(255, 255, 255, 127));
1618 m.setBlend(true);
1619 m.setDstBlend(CMaterial::invsrcalpha);
1620 m.setSrcBlend(CMaterial::srcalpha);
1621 m.setZWrite(false);
1622 RenderTrav.getDriver()->setupMaterial(m);
1623 getDriver()->setPolygonMode(IDriver::Filled);
1624 renderOcclusionTestMeshsWithCurrMaterial();
1625 m.setColor(CRGBA::Black);
1626 RenderTrav.getDriver()->setupMaterial(m);
1627 getDriver()->setPolygonMode(IDriver::Line);
1628 renderOcclusionTestMeshsWithCurrMaterial();
1629 getDriver()->setPolygonMode(oldPolygonMode);
1633 // ***************************************************************************
1634 void CScene::updateWaterEnvMaps(TGlobalAnimationTime time)
1636 IDriver *drv = getDriver();
1637 nlassert(drv);
1638 if (_WaterEnvMap)
1640 _WaterEnvMap->update(time, *drv);
1645 // ***************************************************************************
1646 void CScene::addSSSModelRequest(const class CSSSModelRequest &req)
1648 _SSSModelRequests.push_back(req);
1651 // ***************************************************************************
1652 void CScene::flushSSSModelRequests()
1654 for(uint i=0;i<_SSSModelRequests.size();i++)
1656 _SSSModelRequests[i].execute();
1658 _SSSModelRequests.clear();
1662 } // NL3D