]> git.mxchange.org Git - simgear.git/blob - simgear/scene/sky/clouds3d/SkySceneManager.cpp
Tweak lib name.
[simgear.git] / simgear / scene / sky / clouds3d / SkySceneManager.cpp
1 //------------------------------------------------------------------------------
2 // File : SkySceneManager.cpp
3 //------------------------------------------------------------------------------
4 // SkyWorks : Copyright 2002 Mark J. Harris and
5 //                                              The University of North Carolina at Chapel Hill
6 //------------------------------------------------------------------------------
7 // Permission to use, copy, modify, distribute and sell this software and its 
8 // documentation for any purpose is hereby granted without fee, provided that 
9 // the above copyright notice appear in all copies and that both that copyright 
10 // notice and this permission notice appear in supporting documentation. 
11 // Binaries may be compiled with this software without any royalties or 
12 // restrictions. 
13 //
14 // The author(s) and The University of North Carolina at Chapel Hill make no 
15 // representations about the suitability of this software for any purpose. 
16 // It is provided "as is" without express or 
17 // implied warranty.
18
19 /**
20  * @file SkySceneManager.cpp
21  * 
22  * Implementation of the singleton class SkySceneManager, which manages objects,
23  * instances, scene update, visibility, culling, and rendering.
24  */
25
26 // warning for truncation of template name for browse info
27 #pragma warning( disable : 4786)
28
29 #include "SkySceneManager.hpp"
30 #include "SkyMaterial.hpp"
31 #include "SkyLight.hpp"
32 #include "SkyCloud.hpp"
33 #include "SkyRenderable.hpp"
34 #include "SkyRenderableInstance.hpp"
35 #include "SkyRenderableInstanceCloud.hpp"
36 //#include "SkyHeavens.hpp"
37 //#include "SkyHeightField.hpp"
38
39 #include "camutils.hpp"
40 #include <algorithm>
41
42 //------------------------------------------------------------------------------
43 // Function               : SkySceneManager::SkySceneManager
44 // Description      : 
45 //------------------------------------------------------------------------------
46 /**
47  * @fn SkySceneManager::SkySceneManager()
48  * @brief Constructor
49  */ 
50 SkySceneManager::SkySceneManager()
51 : /*_pSkyBox(NULL),
52   _pTerrain(NULL),\r*/
53   _bDrawLights(false),
54   _bDrawTree(false),
55   _bReshadeClouds(true)
56 {
57   _wireframeMaterial.SetColorMaterialMode(GL_DIFFUSE);
58   _wireframeMaterial.EnableColorMaterial(true);
59   _wireframeMaterial.EnableLighting(false);
60
61   // add the default material with ID -1 
62   // this should avoid errors caused by models without materials exported from MAX
63   // (because flexporter gives them the ID -1).
64   SkyMaterial *pDefaultMaterial = new SkyMaterial;
65   pDefaultMaterial->SetMaterialID(-1);
66   AddMaterial(pDefaultMaterial);
67 }
68
69 //------------------------------------------------------------------------------
70 // Function               : SkySceneManager::~SkySceneManager
71 // Description      : 
72 //------------------------------------------------------------------------------
73 /**
74  * @fn SkySceneManager::~SkySceneManager()
75  * @brief Destructor.
76  *
77  * This destructor deletes all renderables, instances (renderable instances, cloud instances, 
78  * and otherwise), materials, and lights that were added to the scene using the Add*() functions.
79  * In other words, the scene manager owns all entities added to the scene.  This eases cleanup 
80  * and shutdown.
81  */ 
82 SkySceneManager::~SkySceneManager()
83 {
84   ObjectIterator oi;
85   for (oi = _objects.begin(); oi != _objects.end(); ++oi)
86     SAFE_DELETE(*oi);
87   _objects.clear();
88
89   CloudIterator ci;
90   for (ci = _clouds.begin(); ci != _clouds.end(); ++ci)
91     SAFE_DELETE(*ci);
92   _clouds.clear();
93
94   InstanceIterator ii;
95   for (ii = _instances.begin(); ii != _instances.end(); ++ii)
96     SAFE_DELETE(*ii);
97   _instances.clear();
98
99   CloudInstanceIterator cii;
100   for (cii = _cloudInstances.begin(); cii != _cloudInstances.end(); ++cii)
101     SAFE_DELETE(*cii);
102   _cloudInstances.clear();
103
104   ContainerSetIterator cni;
105   for (cni = _containerClouds.begin(); cni != _containerClouds.end(); ++cni)
106     SAFE_DELETE(cni->second);
107   _containerClouds.clear();
108
109   MaterialIterator mi;
110   for (mi = _materials.begin(); mi != _materials.end(); ++mi)
111     SAFE_DELETE(mi->second);
112   _materials.clear();
113
114   LightIterator li;
115   for (li = _lights.begin(); li!= _lights.end(); ++li)
116     SAFE_DELETE(li->second);
117   _lights.clear();
118
119   //SAFE_DELETE(_pSkyBox);
120   //SAFE_DELETE(_pTerrain);
121 }
122
123 //------------------------------------------------------------------------------
124 // Function               : SkySceneManager::AddObject
125 // Description      : 
126 //------------------------------------------------------------------------------
127 /**
128  * @fn SkySceneManager::AddObject(SkyRenderable *pObject)
129  * @brief Add a new SkyRenderable object to the manager.
130  */ 
131 SKYRESULT SkySceneManager::AddObject(SkyRenderable *pObject)
132 {
133   // Check for null object
134   if (NULL == pObject)
135   {
136     FAIL_RETURN_MSG(SKYRESULT_FAIL, 
137                     "SkySceneManager::AddObject(): Attempting to add NULL Renderable Object.");
138   }
139
140   _objects.push_back(pObject);
141
142   return SKYRESULT_OK;
143 }
144
145
146 //------------------------------------------------------------------------------
147 // Function               : SkySceneManager::AddInstance
148 // Description      : 
149 //------------------------------------------------------------------------------
150 /**
151 * @fn SkySceneManager::AddInstance(SkyRenderableInstance *pInstance, bool bTransparent)
152 * @brief Add a new SkyRenderableInstance to the manager.
153 */ 
154 SKYRESULT SkySceneManager::AddInstance(SkyRenderableInstance *pInstance, bool bTransparent /* = false */)
155 {
156   // Check for null instance
157   if (NULL == pInstance)
158   {
159     FAIL_RETURN_MSG(SKYRESULT_FAIL, 
160       "SkySceneManager::AddObject(): Attempting to add NULL Renderable Instance.");
161   }
162   
163   if (!bTransparent)
164     _instances.push_back(pInstance);
165   else
166     _transparentInstances.push_back(pInstance);
167   
168   return SKYRESULT_OK;
169 }
170
171
172 //------------------------------------------------------------------------------
173 // Function               : SkySceneManager::AddCloud
174 // Description      : 
175 //------------------------------------------------------------------------------
176 /**
177  * @fn SkySceneManager::AddCloud(SkyCloud *pCloud)
178  * @brief Add a new cloud object to the manager.
179  * 
180  * @todo <WRITE EXTENDED SkySceneManager::AddCloud FUNCTION DOCUMENTATION>
181  */ 
182 SKYRESULT SkySceneManager::AddCloud(SkyCloud *pCloud)
183 {
184   if (NULL == pCloud)
185   {
186     FAIL_RETURN_MSG(SKYRESULT_FAIL, 
187       "SkySceneManager::AddObject(): Attempting to add NULL SkyCloud Object.");
188   }
189   
190   _clouds.push_back(pCloud);
191   
192   return SKYRESULT_OK;
193 }
194
195
196
197 //------------------------------------------------------------------------------
198 // Function               : SkySceneManager::AddCloudInstance
199 // Description      : 
200 //------------------------------------------------------------------------------
201 /**
202  * @fn SkySceneManager::AddCloudInstance(SkyRenderableInstanceCloud *pInstance)
203  * @brief Add a new instance of a cloud to the manager.
204  * 
205  * @todo Note that since cloud instances share shading information, if two instances
206  * of a cloud have different orientations, one of the instances will have incorrect
207  * lighting for the scene.  For this reason, I recommend that the number of clouds and 
208  * cloud instances is equal.
209  */ 
210 SKYRESULT SkySceneManager::AddCloudInstance(SkyRenderableInstanceCloud *pInstance)
211 {
212   // Check for null instance
213   if (NULL == pInstance)
214   {
215     FAIL_RETURN_MSG(SKYRESULT_FAIL, 
216       "SkySceneManager::AddObject(): Attempting to add NULL SkyCloud Instance.");
217   }
218   
219   pInstance->SetID(_cloudInstances.size());
220
221   _cloudInstances.push_back(pInstance);
222
223   SkyContainerCloud *pContainer = new SkyContainerCloud(pInstance);
224   _containerClouds.insert(std::make_pair(pInstance->GetID(), pContainer));
225
226   RebuildCloudBVTree();
227   
228   return SKYRESULT_OK;
229 }
230
231
232 //------------------------------------------------------------------------------
233 // Function               : SkySceneManager::AddMaterial
234 // Description      : 
235 //------------------------------------------------------------------------------
236 /**
237 * @fn SkySceneManager::AddMaterial(SkyMaterial *pMaterial)
238 * @brief Adds a material to the scene.
239
240 * Materials are kept in a map with their ID as key.  A material can be retrieved
241 * from the scene manager by passing its ID to GetMaterial.
242 *
243 * @see GetMaterial, SkyMaterial
244 */ 
245 SKYRESULT SkySceneManager::AddMaterial(SkyMaterial *pMaterial)
246 {
247   // Check for null instance
248   if (NULL == pMaterial)
249   {
250     FAIL_RETURN_MSG(SKYRESULT_FAIL, 
251       "SkySceneMananger::AddMaterial(): Attempting to add NULL Material to Scene Manager");
252   }
253   
254   _materials.insert(std::make_pair(pMaterial->GetMaterialID(), pMaterial));
255   return SKYRESULT_OK;
256 }
257
258
259
260 //------------------------------------------------------------------------------
261 // Function               : SkySceneManager::GetMaterial
262 // Description      : 
263 //------------------------------------------------------------------------------
264 /**
265  * @fn SkySceneManager::GetMaterial(int iMaterialID)
266  * @brief Returns the material with ID @a iMaterialID.
267  * 
268  * If the material is not found, returns NULL.
269  *
270  * @see AddMaterial, SkyMaterial
271  */ 
272 SkyMaterial* SkySceneManager::GetMaterial(int iMaterialID)
273 {
274   MaterialIterator mi = _materials.find(iMaterialID);
275   if (_materials.end() == mi)
276   {
277     SkyTrace("SkySceneManager::GetMaterial: Error: invalid material ID");
278     return NULL;
279   }
280   else
281     return mi->second;
282 }
283
284
285 //------------------------------------------------------------------------------
286 // Function               : SkySceneManager::ActivateMaterial
287 // Description      : 
288 //------------------------------------------------------------------------------
289 /**
290  * @fn SkySceneManager::ActivateMaterial(int iMaterialID)
291  * @brief Makes the specified material active, setting the appropriate rendering state.
292  * 
293  * @todo <WRITE EXTENDED SkySceneManager::ActivateMaterial FUNCTION DOCUMENTATION>
294  */ 
295 SKYRESULT SkySceneManager::ActivateMaterial(int iMaterialID)
296 {\rcout  << "Activating material\n"; char mm; cin >> mm;
297   MaterialIterator mi = _materials.find(iMaterialID);
298   if (_materials.end() == mi)
299   {
300     FAIL_RETURN_MSG(SKYRESULT_FAIL, 
301                     "SkySceneManager::ActivateMaterial: Error: invalid material ID.");
302   }
303   else
304   {
305     FAIL_RETURN_MSG(mi->second->Activate(), 
306                     "SkySceneManager::ActivateMaterial: Error: failed to activate.");
307   }
308
309   return SKYRESULT_OK;
310 }
311
312
313 //------------------------------------------------------------------------------
314 // Function               : SkySceneManager::AddLight
315 // Description      : 
316 //------------------------------------------------------------------------------
317 /**
318  * @fn SkySceneManager::AddLight(SkyLight *pLight)
319  * @brief @todo <WRITE BRIEF SkySceneManager::AddLight DOCUMENTATION>
320  * 
321  * @todo <WRITE EXTENDED SkySceneManager::AddLight FUNCTION DOCUMENTATION>
322  */ 
323 SKYRESULT SkySceneManager::AddLight(SkyLight *pLight)
324 {
325   // Check for null instance
326   if (NULL == pLight)
327   {
328     FAIL_RETURN_MSG(SKYRESULT_FAIL, 
329                     "SkySceneMananger::AddLight(): Attempting to add NULL Light to Scene Manager");
330   }
331   
332   _lights.insert(std::make_pair(_lights.size(), pLight));
333   return SKYRESULT_OK;
334 }
335
336
337 //------------------------------------------------------------------------------
338 // Function               : SkySceneManager::GetLight
339 // Description      : 
340 //------------------------------------------------------------------------------
341 /**
342  * @fn SkySceneManager::GetLight(int iLightID)
343  * @brief @todo <WRITE BRIEF SkySceneManager::GetLight DOCUMENTATION>
344  * 
345  * @todo <WRITE EXTENDED SkySceneManager::GetLight FUNCTION DOCUMENTATION>
346  */ 
347 SkyLight* SkySceneManager::GetLight(int iLightID)
348 {
349   LightIterator li = _lights.find(iLightID);
350   if (_lights.end() == li)
351   {
352     SkyTrace("SkySceneManager::GetLight: Error: Invalid light ID");
353     return NULL;
354   }
355   else
356     return li->second;
357 }
358
359
360 //------------------------------------------------------------------------------
361 // Function               : Alive
362 // Description      : 
363 //------------------------------------------------------------------------------
364 /**
365  * @fn Alive(SkyRenderableInstance* pInstance)
366  * @brief A predicate to determine if an object is dead or not.
367  */ 
368 bool Alive(SkyRenderableInstance* pInstance)
369 {
370   return (pInstance->IsAlive());
371 }
372
373
374 //------------------------------------------------------------------------------
375 // Function               : SkySceneManager::Update
376 // Description      : 
377 //------------------------------------------------------------------------------
378 /**
379 * @fn SkySceneManager::Update(const Camera &cam)
380 * @brief Iterate through all SkyRenderableInstances and update them.
381 */ 
382 SKYRESULT SkySceneManager::Update(const Camera &cam)
383 {
384   _ResolveVisibility(cam);
385   
386   return SKYRESULT_OK;
387 }
388
389
390 //------------------------------------------------------------------------------
391 // Function               : SkySceneManager::Display
392 // Description      : 
393 //------------------------------------------------------------------------------
394 /**
395 * @fn SkySceneManager::Display(const Camera &cam)
396 * @brief Iterate through all SkyRenderableInstances and display them.
397 */ 
398 SKYRESULT SkySceneManager::Display( const Camera &cam )
399
400 {
401   _clearMaterial.Activate();
402   //glClear(GL_DEPTH_BUFFER_BIT);
403
404   // set lights (only lights that have changed will be passed to GL).
405   for (LightIterator li = _lights.begin(); li != _lights.end(); ++li)
406   {
407     li->second->Activate(li->first);
408     //if (_bDrawLights)
409     //li->second->Display();
410   }
411  
412   //if (_bDrawTree)\r// force the issue and draw
413     _VisualizeCloudBVTree(cam, _cloudBVTree.GetRoot());
414     
415   glLineWidth(2.0);
416   glBegin(GL_LINES);
417   //  red is Cartesian y-axis
418   glColor3ub( 255, 0, 0 );
419   glVertex3f( 0.0,0.0,0.0 );
420   glVertex3f( 0.0, -104000.0, 0.0);
421   // yellow is Cartesian z-axis
422   glColor3ub( 255, 255, 0 );
423   glVertex3f( 0.0, 0.0, 0.0);
424   glVertex3f( 0.0, 0.0, 104000.0);
425   // blue is Cartesian x-axis
426   glColor3ub( 0, 0, 255 );
427   glVertex3f( 0.0, 0.0, 0.0);
428   glVertex3f( -104000.0, 0.0, 0.0);
429   glEnd();
430
431   // draw all container clouds and "free" objects not in clouds.
432   int i = 0;
433   for (InstanceIterator iter = _visibleInstances.begin(); iter != _visibleInstances.end(); ++iter)
434   {
435     FAIL_RETURN_MSG((*iter)->Display(),
436                   "SkySceneManager::Display(): instance display failed.");
437     i++;
438   }
439   //cout << "There are " << i << " visible clouds\n";
440  
441   return SKYRESULT_OK;
442 }
443
444
445 //------------------------------------------------------------------------------
446 // Function               : SkySceneManager::RebuildCloudBVTree
447 // Description      : 
448 //------------------------------------------------------------------------------
449 /**
450  * @fn SkySceneManager::RebuildCloudBVTree()
451  * @brief Builds an AABB tree of the cloud bounding volumes.  
452  */ 
453 SKYRESULT SkySceneManager::RebuildCloudBVTree()
454 {
455   CloudInstanceIterator cii;
456   SkyMinMaxBox bbox;
457
458   _cloudBVTree.BeginTree();
459   for (cii = _cloudInstances.begin(); cii != _cloudInstances.end(); ++cii)
460   {
461     bbox = (*cii)->GetWorldSpaceBounds();
462     _cloudBVTree.AddObject(*cii, bbox);
463   }
464   _cloudBVTree.EndTree();
465
466   return SKYRESULT_OK;
467 }
468
469
470 //------------------------------------------------------------------------------
471 // Function               : SkySceneManager::ShadeClouds
472 // Description      : 
473 //------------------------------------------------------------------------------
474 /**
475  * @fn SkySceneManager::ShadeClouds()
476  * @brief @todo <WRITE BRIEF SkySceneManager::ShadeClouds DOCUMENTATION>
477  * 
478  * @todo <WRITE EXTENDED SkySceneManager::ShadeClouds FUNCTION DOCUMENTATION>
479  */ 
480 SKYRESULT SkySceneManager::ShadeClouds()
481 {\rcout  <<  "SkySceneManager::ShadeClouds()\n";
482   int i=0;
483   
484   for (CloudInstanceIterator cii = _cloudInstances.begin(); cii != _cloudInstances.end(); ++cii)
485   {
486     for (LightIterator li = _lights.begin(); li != _lights.end(); ++li)
487     {
488       
489       if (SkyLight::SKY_LIGHT_DIRECTIONAL == li->second->GetType())
490       {
491         (*cii)->GetCloud()->Illuminate(li->second, *cii, li == _lights.begin());
492         printf("Shading Cloud %d of %d with light %d \n", i++, _cloudInstances.size(), *li );
493       }
494     }
495   }
496   _bReshadeClouds = false;
497   return SKYRESULT_OK;
498 }
499
500
501 //------------------------------------------------------------------------------
502 // Function               : SkySceneManager::LoadClouds
503 // Description      : 
504 //------------------------------------------------------------------------------
505 /**
506  * @fn SkySceneManager::LoadClouds(SkyArchive& cloudArchive, float rScale)
507  * @brief @todo <WRITE BRIEF SkySceneManager::LoadClouds DOCUMENTATION>
508  * 
509  * @todo <WRITE EXTENDED SkySceneManager::LoadClouds FUNCTION DOCUMENTATION>
510  */ 
511 SKYRESULT SkySceneManager::LoadClouds(SkyArchive& cloudArchive, float rScale /* = 1.0f */)
512 {
513   unsigned int iNumClouds = 0;
514   cloudArchive.FindUInt32("CldNumClouds", &iNumClouds);
515  
516   SkyArchive subArchive;
517         //iNumClouds = 5;  //set this value to reduce cloud field for debugging
518   for (int i = 0; i < iNumClouds; ++i)
519   {\rprintf("Loading # %d of %d clouds\n", i, iNumClouds);
520     cloudArchive.FindArchive("Cloud", &subArchive, i);
521     SkyCloud *pCloud = new SkyCloud();
522     pCloud->Load(subArchive, rScale);
523     SkyRenderableInstanceCloud *pInstance = new SkyRenderableInstanceCloud(pCloud, false);
524     AddCloud(pCloud);
525     AddCloudInstance(pInstance);
526   }
527   RebuildCloudBVTree();
528   return SKYRESULT_OK;
529 }
530
531 //------------------------------------------------------------------------------
532 // Function               : SkySceneManager::_SortClouds
533 // Description      : 
534 //------------------------------------------------------------------------------
535 /**
536  * @fn SkySceneManager::_SortClouds(CloudInstanceArray& clouds, const Vec3f& vecSortPoint)
537  * @brief @todo <WRITE BRIEF SkySceneManager::_SortClouds DOCUMENTATION>
538  * 
539  * @todo <WRITE EXTENDED SkySceneManager::_SortClouds FUNCTION DOCUMENTATION>
540  */ 
541 void SkySceneManager::_SortClouds(CloudInstanceArray& clouds, const Vec3f& vecSortPoint)
542 {
543   static InstanceComparator comparator;
544
545   for (CloudInstanceIterator cii = clouds.begin(); cii != clouds.end(); ++cii)
546   {
547     Vec3f vecPos = (*cii)->GetPosition();
548     vecPos -= vecSortPoint;
549     (*cii)->SetSquareSortDistance(vecPos.LengthSqr());
550   }
551
552   std::sort(clouds.begin(), clouds.end(), comparator);
553 }
554
555
556 //------------------------------------------------------------------------------
557 // Function               : SkySceneManager::_SortInstances
558 // Description      : 
559 //------------------------------------------------------------------------------
560 /**
561  * @fn SkySceneManager::SortInstances(InstanceArray& instances, const Vec3f& vecSortPoint)
562  * @brief @todo <WRITE BRIEF SkySceneManager::_SortInstances DOCUMENTATION>
563  * 
564  * @todo <WRITE EXTENDED SkySceneManager::_SortInstances FUNCTION DOCUMENTATION>
565  */ 
566 void SkySceneManager::SortInstances(InstanceArray& instances, const Vec3f& vecSortPoint)
567 {
568   static InstanceComparator comparator;
569
570   for (InstanceIterator ii = instances.begin(); ii != instances.end(); ++ii)
571   {
572     Vec3f vecPos = (*ii)->GetPosition();
573     vecPos -= vecSortPoint;
574     (*ii)->SetSquareSortDistance(vecPos.LengthSqr());
575   }
576   
577   std::sort(instances.begin(), instances.end(), comparator);
578 }
579
580
581 //------------------------------------------------------------------------------
582 // Function               : SkySceneManager::_ViewFrustumCullClouds
583 // Description      : 
584 //------------------------------------------------------------------------------
585 /**
586  * @fn SkySceneManager::_ViewFrustumCullClouds(const Camera& cam, const CloudBVTree::Node *pNode)
587  * @brief @todo <WRITE BRIEF SkySceneManager::_ViewFrustumCullClouds DOCUMENTATION>
588  * 
589  * @todo <WRITE EXTENDED SkySceneManager::_ViewFrustumCullClouds FUNCTION DOCUMENTATION>
590  */ 
591 void SkySceneManager::_ViewFrustumCullClouds(const Camera& cam, const CloudBVTree::Node *pNode)
592
593   if (!pNode)
594     return;
595
596   int i;
597   int iResult = CamMinMaxBoxOverlap(&cam, pNode->GetNodeBV().GetMin(), pNode->GetNodeBV().GetMax());
598   
599 \r //iResult = COMPLETEIN; // just a hack to force the issue
600   if (COMPLETEIN == iResult)
601   {
602     // trivially add all instances 
603     for (i = 0; i < pNode->GetNumObjs(); ++i)
604     {
605       SkyRenderableInstanceCloud* pInstance = 
606         const_cast<SkyRenderableInstanceCloud*>(pNode->GetObj(i));
607       _visibleCloudInstances.push_back(pInstance);
608     }
609   }
610   else if ((PARTIAL == iResult) && pNode->IsLeaf())
611   {
612     SkyMinMaxBox bbox;
613     
614     // check each instance in this node against camera
615     for (i = 0; i < pNode->GetNumObjs(); ++i)
616     {
617       SkyRenderableInstanceCloud* pInstance = 
618         const_cast<SkyRenderableInstanceCloud*>(pNode->GetObj(i));
619       bbox = pInstance->GetWorldSpaceBounds();
620       iResult = CamMinMaxBoxOverlap(&cam, bbox.GetMin(), bbox.GetMax());
621       if (COMPLETEOUT != iResult)
622         _visibleCloudInstances.push_back(pInstance);
623       else
624         pInstance->ReleaseImpostorTextures();
625     }
626   }
627   else if (PARTIAL == iResult)
628   {
629     _ViewFrustumCullClouds(cam, pNode->GetLeftChild());
630     _ViewFrustumCullClouds(cam, pNode->GetRightChild());
631   }
632   else // the node is completely out.  All of its child clouds should release their textures.
633   {
634     for (i = 0; i < pNode->GetNumObjs(); ++i)
635     {
636       SkyRenderableInstanceCloud* pInstance = 
637         const_cast<SkyRenderableInstanceCloud*>(pNode->GetObj(i));
638       pInstance->ReleaseImpostorTextures();
639     }
640   }
641 }
642
643
644 //------------------------------------------------------------------------------
645 // Function               : SkySceneManager::_VisualizeCloudBVTree
646 // Description      : 
647 //------------------------------------------------------------------------------
648 /**
649  * @fn SkySceneManager::_VisualizeCloudBVTree(const Camera& cam, const CloudBVTree::Node *pNode)
650  * @brief @todo <WRITE BRIEF SkySceneManager::_VisualizeCloudBVTree DOCUMENTATION>
651  * 
652  * @todo <WRITE EXTENDED SkySceneManager::_VisualizeCloudBVTree FUNCTION DOCUMENTATION>
653  */ 
654 void SkySceneManager::_VisualizeCloudBVTree(const Camera& cam, const CloudBVTree::Node *pNode)
655 {
656   // set display state.
657   _wireframeMaterial.Activate();
658
659   int iResult = CamMinMaxBoxOverlap(&cam, pNode->GetNodeBV().GetMin(), pNode->GetNodeBV().GetMax());
660
661   if (COMPLETEIN == iResult)
662   {
663     // draw this node's bounding box in green.
664     glColor3f(0, 1, 0);
665     pNode->GetNodeBV().Display();
666   }
667   else if (PARTIAL == iResult)
668   {
669     SkyMinMaxBox bbox;
670
671     if (pNode->IsLeaf())
672     {
673       // draw this node's bounding box and the boxes of all of its objects that are visible.
674       // draw this node's bbox in orange.
675       glColor3f(1, 0.5, 0);
676       pNode->GetNodeBV().Display();
677
678       int i;
679       for (i = 0; i < pNode->GetNumObjs(); ++i)
680       {
681         SkyRenderableInstanceCloud* pInstance = 
682           const_cast<SkyRenderableInstanceCloud*>(pNode->GetObj(i));
683         bbox = pInstance->GetWorldSpaceBounds();
684         iResult = CamMinMaxBoxOverlap(&cam, bbox.GetMin(), bbox.GetMax());
685
686         if (COMPLETEIN == iResult)
687         {
688           // draw the box in green
689           glColor3f(0, 1, 0);
690           bbox.Display();
691         }
692         else if (PARTIAL == iResult)
693         {
694           // draw the box in yellow
695           glColor3f(1, 1, 0);
696           bbox.Display();          
697         }
698       }
699     }
700     else
701     {
702       _VisualizeCloudBVTree(cam, pNode->GetLeftChild());
703       _VisualizeCloudBVTree(cam, pNode->GetRightChild());
704     }
705   }
706   else
707   {
708     // draw the node's bbox in red.  
709     // This should NEVER be visible from the camera from which it was culled!
710     glColor3f(1, 0, 0);
711     pNode->GetNodeBV().Display();
712   }
713 }
714
715
716 //------------------------------------------------------------------------------
717 // Function               : SkySceneManager::_ResolveVisibility
718 // Description      : 
719 //------------------------------------------------------------------------------
720 /**
721  * @fn SkySceneManager::_ResolveVisibility(const Camera &cam)
722  * @brief @todo <WRITE BRIEF SkySceneManager::_ResolveRenderingOrder DOCUMENTATION>
723  * 
724  * @todo <WRITE EXTENDED SkySceneManager::_ResolveRenderingOrder FUNCTION DOCUMENTATION>
725  */ 
726 SKYRESULT SkySceneManager::_ResolveVisibility(const Camera &cam)
727 {
728   InstanceIterator ii;
729
730   // clear the free instance array
731   _visibleInstances.clear();
732
733   // clear the contained instance arrays
734   ContainerSetIterator csi;
735   for (csi = _containerClouds.begin(); csi != _containerClouds.end(); ++csi)
736   {
737     csi->second->containedOpaqueInstances.clear();
738     csi->second->containedTransparentInstances.clear();
739   }
740
741   // clear the visible cloud array.
742   _visibleCloudInstances.clear();
743   
744   // Test each instance for containment inside a cloud's bounding volume.
745   // If the instance is inside a cloud, it is considered a "contained" instance, and will be 
746   // rendered with the cloud in which it is contained for correct visibility.  If the instance is
747   // not inside any cloud, then it is a "free" instance, and will be rendered after all contained
748   // instances.  Transparent instances of each type are rendered after opaque instances of each 
749   // type.
750
751   // opaque instances
752   for (ii = _instances.begin(); ii != _instances.end(); ++ii)
753   {\rcout <<  "Opague instance\n"; char zz; cin >> zz;
754     (*ii)->ViewFrustumCull(cam);  // First VFC then check if culled, some instances may
755     // manually set the culled flag, instead of using VFC  
756     if (!(*ii)->IsCulled())
757     {
758       // first update this instance.
759       FAIL_RETURN_MSG((*ii)->Update(cam), "SkySceneManager::_ResolveVisibility(): instance update failed.");
760       
761       if (!_TestInsertInstanceIntoClouds(cam, _cloudBVTree.GetRoot(), *ii, false))
762         _visibleInstances.push_back(*ii);
763     }
764   }
765
766   // transparent instances
767   for (ii = _transparentInstances.begin(); ii != _transparentInstances.end(); ++ii)
768   {\rcout << "Transparent instance\n"; char tt; cin >> tt;
769     (*ii)->ViewFrustumCull(cam);  // First VFC then check if culled, some instances may
770     // manually set the culled flag, instead of using VFC  
771     if (!(*ii)->IsCulled())
772     {
773       // first update this instance.
774       FAIL_RETURN_MSG((*ii)->Update(cam), "SkySceneManager::Update(): instance update failed.");
775       
776       if (!_TestInsertInstanceIntoClouds(cam, _cloudBVTree.GetRoot(), *ii, true))
777         _visibleInstances.push_back(*ii);
778     }
779   }
780
781   // view frustum cull the clouds
782   _ViewFrustumCullClouds(cam, _cloudBVTree.GetRoot());  
783
784   // Clouds must be rendered in sorted order.
785   //_SortClouds(_visibleCloudInstances, cam.Orig);
786
787   // reshade the clouds if necessary.
788   if (_bReshadeClouds)
789   {
790   printf("ReShading clouds\n");
791     FAIL_RETURN(ShadeClouds());
792   }
793
794   // Now process the visible clouds.  First, go through the container clouds corresponding to the
795   // clouds, calculate their split points, and update their impostors.
796   for (CloudInstanceIterator cii = _visibleCloudInstances.begin(); 
797        cii != _visibleCloudInstances.end(); 
798        ++cii)
799   {
800     // get the container corresponding to this cloud
801     ContainerSetIterator csi = _containerClouds.find((*cii)->GetID());
802    
803     if (csi == _containerClouds.end())
804     {
805       SkyTrace("Error: SkySceneManager::_ResolveVisibility(): Invalid cloud instance %d.", 
806                (*cii)->GetID());
807       return SKYRESULT_FAIL;
808     }
809     
810     if (csi->second->containedOpaqueInstances.size() > 0 ||
811         csi->second->containedTransparentInstances.size() > 0)
812     {
813       SortInstances(csi->second->containedOpaqueInstances, cam.Orig);
814       SortInstances(csi->second->containedTransparentInstances, cam.Orig);
815     
816     
817       SkyRenderableInstance *pOpaque = (csi->second->containedOpaqueInstances.size() > 0) ? 
818                                         csi->second->containedOpaqueInstances.back() : NULL;
819       SkyRenderableInstance *pTransparent = (csi->second->containedTransparentInstances.size() > 0) ? 
820                                              csi->second->containedTransparentInstances.back() : NULL;
821     
822       // find the closest contained instance to the camera
823       if (pOpaque && pTransparent)
824       {
825         if (*pOpaque < *pTransparent)
826           (*cii)->SetSplitPoint(pOpaque->GetPosition());
827         else
828           (*cii)->SetSplitPoint(pTransparent->GetPosition());
829       }
830       else if (pOpaque)
831         (*cii)->SetSplitPoint(pOpaque->GetPosition());
832       else if (pTransparent)
833         (*cii)->SetSplitPoint(pTransparent->GetPosition());
834       else
835         (*cii)->SetSplit(false);
836     }
837     else
838       (*cii)->SetSplit(false);
839     
840     // add the container to the list of visiblie clouds to be rendered this frame.
841     _visibleInstances.push_back(csi->second);
842
843     // now update the impostors
844     FAIL_RETURN_MSG((*cii)->Update(cam),
845       "SkySceneManager::_ResolveVisibility(): cloud instance update failed.");
846   } 
847
848   SortInstances(_visibleInstances, cam.Orig);
849
850   return SKYRESULT_OK;
851 }
852
853
854 //------------------------------------------------------------------------------
855 // Function               : SkySceneManager::_TestInsertInstanceIntoClouds
856 // Description      : 
857 //------------------------------------------------------------------------------
858 /**
859  * @fn SkySceneManager::_TestInsertInstanceIntoClouds(const Camera &cam, const CloudBVTree::Node *pNode, SkyRenderableInstance *pInstanceToInsert, bool bTransparent)
860  * @brief @todo <WRITE BRIEF SkySceneManager::_TestInsertInstanceIntoClouds DOCUMENTATION>
861  * 
862  * @todo <WRITE EXTENDED SkySceneManager::_TestInsertInstanceIntoClouds FUNCTION DOCUMENTATION>
863  */ 
864 bool SkySceneManager::_TestInsertInstanceIntoClouds(const Camera            &cam,
865                                                     const CloudBVTree::Node *pNode, 
866                                                     SkyRenderableInstance   *pInstanceToInsert,
867                                                     bool                    bTransparent)
868 {
869   if (_clouds.size() <= 0)
870     return false;
871
872   if (pNode->GetNodeBV().PointInBBox(pInstanceToInsert->GetPosition()))
873   {
874     if (pNode->IsLeaf())
875     {
876       SkyMinMaxBox bbox;
877       int i;
878
879       // check the instance against each cloud in this leaf node.
880       for (i = 0; i < pNode->GetNumObjs(); ++i)
881       {
882         SkyRenderableInstanceCloud* pCloud = 
883           const_cast<SkyRenderableInstanceCloud*>(pNode->GetObj(i));
884         bbox = pCloud->GetWorldSpaceBounds();
885         if (bbox.PointInBBox(pInstanceToInsert->GetPosition()))
886         {
887           // get the container cloud struct for this cloud instance, and add this instance.
888           ContainerSetIterator csi = _containerClouds.find(pCloud->GetID());
889           if (csi == _containerClouds.end())
890           {
891             SkyTrace(
892               "Error: SkySceneManager::_TestInsertInstanceIntoClouds(): Invalid cloud instance %d.", 
893               pCloud->GetID());
894             return false;
895           }
896           else // this instance is inside a cloud.  Set up for split cloud rendering.
897           {
898             if (!bTransparent)
899               csi->second->containedOpaqueInstances.push_back(pInstanceToInsert);
900             else
901               csi->second->containedTransparentInstances.push_back(pInstanceToInsert);
902             csi->second->pCloud->SetSplit(true);
903             return true;
904           }
905         }
906       }
907       return false;
908     }
909     else
910     {
911       if (!_TestInsertInstanceIntoClouds(cam, pNode->GetLeftChild(), pInstanceToInsert, bTransparent))
912         return _TestInsertInstanceIntoClouds(cam, pNode->GetRightChild(), pInstanceToInsert, bTransparent);
913       else
914         return true;
915     }
916   }
917   else
918     return false;
919 }