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