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
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
20 * @file SkySceneManager.cpp
22 * Implementation of the singleton class SkySceneManager, which manages objects,
23 * instances, scene update, visibility, culling, and rendering.
26 // warning for truncation of template name for browse info
27 #pragma warning( disable : 4786)
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"
39 #include "camutils.hpp"
42 //------------------------------------------------------------------------------
43 // Function : SkySceneManager::SkySceneManager
45 //------------------------------------------------------------------------------
47 * @fn SkySceneManager::SkySceneManager()
50 SkySceneManager::SkySceneManager()
57 _wireframeMaterial.SetColorMaterialMode(GL_DIFFUSE);
58 _wireframeMaterial.EnableColorMaterial(true);
59 _wireframeMaterial.EnableLighting(false);
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);
69 //------------------------------------------------------------------------------
70 // Function : SkySceneManager::~SkySceneManager
72 //------------------------------------------------------------------------------
74 * @fn SkySceneManager::~SkySceneManager()
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
82 SkySceneManager::~SkySceneManager()
85 for (oi = _objects.begin(); oi != _objects.end(); ++oi)
90 for (ci = _clouds.begin(); ci != _clouds.end(); ++ci)
95 for (ii = _instances.begin(); ii != _instances.end(); ++ii)
99 CloudInstanceIterator cii;
100 for (cii = _cloudInstances.begin(); cii != _cloudInstances.end(); ++cii)
102 _cloudInstances.clear();
104 ContainerSetIterator cni;
105 for (cni = _containerClouds.begin(); cni != _containerClouds.end(); ++cni)
106 SAFE_DELETE(cni->second);
107 _containerClouds.clear();
110 for (mi = _materials.begin(); mi != _materials.end(); ++mi)
111 SAFE_DELETE(mi->second);
115 for (li = _lights.begin(); li!= _lights.end(); ++li)
116 SAFE_DELETE(li->second);
119 //SAFE_DELETE(_pSkyBox);
120 //SAFE_DELETE(_pTerrain);
123 //------------------------------------------------------------------------------
124 // Function : SkySceneManager::AddObject
126 //------------------------------------------------------------------------------
128 * @fn SkySceneManager::AddObject(SkyRenderable *pObject)
129 * @brief Add a new SkyRenderable object to the manager.
131 SKYRESULT SkySceneManager::AddObject(SkyRenderable *pObject)
133 // Check for null object
136 FAIL_RETURN_MSG(SKYRESULT_FAIL,
137 "SkySceneManager::AddObject(): Attempting to add NULL Renderable Object.");
140 _objects.push_back(pObject);
146 //------------------------------------------------------------------------------
147 // Function : SkySceneManager::AddInstance
149 //------------------------------------------------------------------------------
151 * @fn SkySceneManager::AddInstance(SkyRenderableInstance *pInstance, bool bTransparent)
152 * @brief Add a new SkyRenderableInstance to the manager.
154 SKYRESULT SkySceneManager::AddInstance(SkyRenderableInstance *pInstance, bool bTransparent /* = false */)
156 // Check for null instance
157 if (NULL == pInstance)
159 FAIL_RETURN_MSG(SKYRESULT_FAIL,
160 "SkySceneManager::AddObject(): Attempting to add NULL Renderable Instance.");
164 _instances.push_back(pInstance);
166 _transparentInstances.push_back(pInstance);
172 //------------------------------------------------------------------------------
173 // Function : SkySceneManager::AddCloud
175 //------------------------------------------------------------------------------
177 * @fn SkySceneManager::AddCloud(SkyCloud *pCloud)
178 * @brief Add a new cloud object to the manager.
180 * @todo <WRITE EXTENDED SkySceneManager::AddCloud FUNCTION DOCUMENTATION>
182 SKYRESULT SkySceneManager::AddCloud(SkyCloud *pCloud)
186 FAIL_RETURN_MSG(SKYRESULT_FAIL,
187 "SkySceneManager::AddObject(): Attempting to add NULL SkyCloud Object.");
190 _clouds.push_back(pCloud);
197 //------------------------------------------------------------------------------
198 // Function : SkySceneManager::AddCloudInstance
200 //------------------------------------------------------------------------------
202 * @fn SkySceneManager::AddCloudInstance(SkyRenderableInstanceCloud *pInstance)
203 * @brief Add a new instance of a cloud to the manager.
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.
210 SKYRESULT SkySceneManager::AddCloudInstance(SkyRenderableInstanceCloud *pInstance)
212 // Check for null instance
213 if (NULL == pInstance)
215 FAIL_RETURN_MSG(SKYRESULT_FAIL,
216 "SkySceneManager::AddObject(): Attempting to add NULL SkyCloud Instance.");
219 pInstance->SetID(_cloudInstances.size());
221 _cloudInstances.push_back(pInstance);
223 SkyContainerCloud *pContainer = new SkyContainerCloud(pInstance);
224 _containerClouds.insert(std::make_pair(pInstance->GetID(), pContainer));
226 RebuildCloudBVTree();
232 //------------------------------------------------------------------------------
233 // Function : SkySceneManager::AddMaterial
235 //------------------------------------------------------------------------------
237 * @fn SkySceneManager::AddMaterial(SkyMaterial *pMaterial)
238 * @brief Adds a material to the scene.
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.
243 * @see GetMaterial, SkyMaterial
245 SKYRESULT SkySceneManager::AddMaterial(SkyMaterial *pMaterial)
247 // Check for null instance
248 if (NULL == pMaterial)
250 FAIL_RETURN_MSG(SKYRESULT_FAIL,
251 "SkySceneMananger::AddMaterial(): Attempting to add NULL Material to Scene Manager");
254 _materials.insert(std::make_pair(pMaterial->GetMaterialID(), pMaterial));
260 //------------------------------------------------------------------------------
261 // Function : SkySceneManager::GetMaterial
263 //------------------------------------------------------------------------------
265 * @fn SkySceneManager::GetMaterial(int iMaterialID)
266 * @brief Returns the material with ID @a iMaterialID.
268 * If the material is not found, returns NULL.
270 * @see AddMaterial, SkyMaterial
272 SkyMaterial* SkySceneManager::GetMaterial(int iMaterialID)
274 MaterialIterator mi = _materials.find(iMaterialID);
275 if (_materials.end() == mi)
277 SkyTrace("SkySceneManager::GetMaterial: Error: invalid material ID");
285 //------------------------------------------------------------------------------
286 // Function : SkySceneManager::ActivateMaterial
288 //------------------------------------------------------------------------------
290 * @fn SkySceneManager::ActivateMaterial(int iMaterialID)
291 * @brief Makes the specified material active, setting the appropriate rendering state.
293 * @todo <WRITE EXTENDED SkySceneManager::ActivateMaterial FUNCTION DOCUMENTATION>
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)
300 FAIL_RETURN_MSG(SKYRESULT_FAIL,
301 "SkySceneManager::ActivateMaterial: Error: invalid material ID.");
305 FAIL_RETURN_MSG(mi->second->Activate(),
306 "SkySceneManager::ActivateMaterial: Error: failed to activate.");
313 //------------------------------------------------------------------------------
314 // Function : SkySceneManager::AddLight
316 //------------------------------------------------------------------------------
318 * @fn SkySceneManager::AddLight(SkyLight *pLight)
319 * @brief @todo <WRITE BRIEF SkySceneManager::AddLight DOCUMENTATION>
321 * @todo <WRITE EXTENDED SkySceneManager::AddLight FUNCTION DOCUMENTATION>
323 SKYRESULT SkySceneManager::AddLight(SkyLight *pLight)
325 // Check for null instance
328 FAIL_RETURN_MSG(SKYRESULT_FAIL,
329 "SkySceneMananger::AddLight(): Attempting to add NULL Light to Scene Manager");
332 _lights.insert(std::make_pair(_lights.size(), pLight));
337 //------------------------------------------------------------------------------
338 // Function : SkySceneManager::GetLight
340 //------------------------------------------------------------------------------
342 * @fn SkySceneManager::GetLight(int iLightID)
343 * @brief @todo <WRITE BRIEF SkySceneManager::GetLight DOCUMENTATION>
345 * @todo <WRITE EXTENDED SkySceneManager::GetLight FUNCTION DOCUMENTATION>
347 SkyLight* SkySceneManager::GetLight(int iLightID)
349 LightIterator li = _lights.find(iLightID);
350 if (_lights.end() == li)
352 SkyTrace("SkySceneManager::GetLight: Error: Invalid light ID");
360 //------------------------------------------------------------------------------
363 //------------------------------------------------------------------------------
365 * @fn Alive(SkyRenderableInstance* pInstance)
366 * @brief A predicate to determine if an object is dead or not.
368 bool Alive(SkyRenderableInstance* pInstance)
370 return (pInstance->IsAlive());
374 //------------------------------------------------------------------------------
375 // Function : SkySceneManager::Update
377 //------------------------------------------------------------------------------
379 * @fn SkySceneManager::Update(const Camera &cam)
380 * @brief Iterate through all SkyRenderableInstances and update them.
382 SKYRESULT SkySceneManager::Update(const Camera &cam)
384 _ResolveVisibility(cam);
390 //------------------------------------------------------------------------------
391 // Function : SkySceneManager::Display
393 //------------------------------------------------------------------------------
395 * @fn SkySceneManager::Display(const Camera &cam)
396 * @brief Iterate through all SkyRenderableInstances and display them.
398 SKYRESULT SkySceneManager::Display( const Camera &cam )
401 _clearMaterial.Activate();
402 //glClear(GL_DEPTH_BUFFER_BIT);
404 // set lights (only lights that have changed will be passed to GL).
405 for (LightIterator li = _lights.begin(); li != _lights.end(); ++li)
407 li->second->Activate(li->first);
409 //li->second->Display();
412 //if (_bDrawTree)
\r// force the issue and draw
413 _VisualizeCloudBVTree(cam, _cloudBVTree.GetRoot());
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);
431 // draw all container clouds and "free" objects not in clouds.
433 for (InstanceIterator iter = _visibleInstances.begin(); iter != _visibleInstances.end(); ++iter)
435 FAIL_RETURN_MSG((*iter)->Display(),
436 "SkySceneManager::Display(): instance display failed.");
439 //cout << "There are " << i << " visible clouds\n";
445 //------------------------------------------------------------------------------
446 // Function : SkySceneManager::RebuildCloudBVTree
448 //------------------------------------------------------------------------------
450 * @fn SkySceneManager::RebuildCloudBVTree()
451 * @brief Builds an AABB tree of the cloud bounding volumes.
453 SKYRESULT SkySceneManager::RebuildCloudBVTree()
455 CloudInstanceIterator cii;
458 _cloudBVTree.BeginTree();
459 for (cii = _cloudInstances.begin(); cii != _cloudInstances.end(); ++cii)
461 bbox = (*cii)->GetWorldSpaceBounds();
462 _cloudBVTree.AddObject(*cii, bbox);
464 _cloudBVTree.EndTree();
470 //------------------------------------------------------------------------------
471 // Function : SkySceneManager::ShadeClouds
473 //------------------------------------------------------------------------------
475 * @fn SkySceneManager::ShadeClouds()
476 * @brief @todo <WRITE BRIEF SkySceneManager::ShadeClouds DOCUMENTATION>
478 * @todo <WRITE EXTENDED SkySceneManager::ShadeClouds FUNCTION DOCUMENTATION>
480 SKYRESULT SkySceneManager::ShadeClouds()
481 {
\rcout << "SkySceneManager::ShadeClouds()\n";
484 for (CloudInstanceIterator cii = _cloudInstances.begin(); cii != _cloudInstances.end(); ++cii)
486 for (LightIterator li = _lights.begin(); li != _lights.end(); ++li)
489 if (SkyLight::SKY_LIGHT_DIRECTIONAL == li->second->GetType())
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 );
496 _bReshadeClouds = false;
501 //------------------------------------------------------------------------------
502 // Function : SkySceneManager::LoadClouds
504 //------------------------------------------------------------------------------
506 * @fn SkySceneManager::LoadClouds(SkyArchive& cloudArchive, float rScale)
507 * @brief @todo <WRITE BRIEF SkySceneManager::LoadClouds DOCUMENTATION>
509 * @todo <WRITE EXTENDED SkySceneManager::LoadClouds FUNCTION DOCUMENTATION>
511 SKYRESULT SkySceneManager::LoadClouds(SkyArchive& cloudArchive, float rScale /* = 1.0f */)
513 unsigned int iNumClouds = 0;
514 cloudArchive.FindUInt32("CldNumClouds", &iNumClouds);
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);
525 AddCloudInstance(pInstance);
527 RebuildCloudBVTree();
531 //------------------------------------------------------------------------------
532 // Function : SkySceneManager::_SortClouds
534 //------------------------------------------------------------------------------
536 * @fn SkySceneManager::_SortClouds(CloudInstanceArray& clouds, const Vec3f& vecSortPoint)
537 * @brief @todo <WRITE BRIEF SkySceneManager::_SortClouds DOCUMENTATION>
539 * @todo <WRITE EXTENDED SkySceneManager::_SortClouds FUNCTION DOCUMENTATION>
541 void SkySceneManager::_SortClouds(CloudInstanceArray& clouds, const Vec3f& vecSortPoint)
543 static InstanceComparator comparator;
545 for (CloudInstanceIterator cii = clouds.begin(); cii != clouds.end(); ++cii)
547 Vec3f vecPos = (*cii)->GetPosition();
548 vecPos -= vecSortPoint;
549 (*cii)->SetSquareSortDistance(vecPos.LengthSqr());
552 std::sort(clouds.begin(), clouds.end(), comparator);
556 //------------------------------------------------------------------------------
557 // Function : SkySceneManager::_SortInstances
559 //------------------------------------------------------------------------------
561 * @fn SkySceneManager::SortInstances(InstanceArray& instances, const Vec3f& vecSortPoint)
562 * @brief @todo <WRITE BRIEF SkySceneManager::_SortInstances DOCUMENTATION>
564 * @todo <WRITE EXTENDED SkySceneManager::_SortInstances FUNCTION DOCUMENTATION>
566 void SkySceneManager::SortInstances(InstanceArray& instances, const Vec3f& vecSortPoint)
568 static InstanceComparator comparator;
570 for (InstanceIterator ii = instances.begin(); ii != instances.end(); ++ii)
572 Vec3f vecPos = (*ii)->GetPosition();
573 vecPos -= vecSortPoint;
574 (*ii)->SetSquareSortDistance(vecPos.LengthSqr());
577 std::sort(instances.begin(), instances.end(), comparator);
581 //------------------------------------------------------------------------------
582 // Function : SkySceneManager::_ViewFrustumCullClouds
584 //------------------------------------------------------------------------------
586 * @fn SkySceneManager::_ViewFrustumCullClouds(const Camera& cam, const CloudBVTree::Node *pNode)
587 * @brief @todo <WRITE BRIEF SkySceneManager::_ViewFrustumCullClouds DOCUMENTATION>
589 * @todo <WRITE EXTENDED SkySceneManager::_ViewFrustumCullClouds FUNCTION DOCUMENTATION>
591 void SkySceneManager::_ViewFrustumCullClouds(const Camera& cam, const CloudBVTree::Node *pNode)
597 int iResult = CamMinMaxBoxOverlap(&cam, pNode->GetNodeBV().GetMin(), pNode->GetNodeBV().GetMax());
599 \r //iResult = COMPLETEIN; // just a hack to force the issue
600 if (COMPLETEIN == iResult)
602 // trivially add all instances
603 for (i = 0; i < pNode->GetNumObjs(); ++i)
605 SkyRenderableInstanceCloud* pInstance =
606 const_cast<SkyRenderableInstanceCloud*>(pNode->GetObj(i));
607 _visibleCloudInstances.push_back(pInstance);
610 else if ((PARTIAL == iResult) && pNode->IsLeaf())
614 // check each instance in this node against camera
615 for (i = 0; i < pNode->GetNumObjs(); ++i)
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);
624 pInstance->ReleaseImpostorTextures();
627 else if (PARTIAL == iResult)
629 _ViewFrustumCullClouds(cam, pNode->GetLeftChild());
630 _ViewFrustumCullClouds(cam, pNode->GetRightChild());
632 else // the node is completely out. All of its child clouds should release their textures.
634 for (i = 0; i < pNode->GetNumObjs(); ++i)
636 SkyRenderableInstanceCloud* pInstance =
637 const_cast<SkyRenderableInstanceCloud*>(pNode->GetObj(i));
638 pInstance->ReleaseImpostorTextures();
644 //------------------------------------------------------------------------------
645 // Function : SkySceneManager::_VisualizeCloudBVTree
647 //------------------------------------------------------------------------------
649 * @fn SkySceneManager::_VisualizeCloudBVTree(const Camera& cam, const CloudBVTree::Node *pNode)
650 * @brief @todo <WRITE BRIEF SkySceneManager::_VisualizeCloudBVTree DOCUMENTATION>
652 * @todo <WRITE EXTENDED SkySceneManager::_VisualizeCloudBVTree FUNCTION DOCUMENTATION>
654 void SkySceneManager::_VisualizeCloudBVTree(const Camera& cam, const CloudBVTree::Node *pNode)
656 // set display state.
657 _wireframeMaterial.Activate();
659 int iResult = CamMinMaxBoxOverlap(&cam, pNode->GetNodeBV().GetMin(), pNode->GetNodeBV().GetMax());
661 if (COMPLETEIN == iResult)
663 // draw this node's bounding box in green.
665 pNode->GetNodeBV().Display();
667 else if (PARTIAL == iResult)
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();
679 for (i = 0; i < pNode->GetNumObjs(); ++i)
681 SkyRenderableInstanceCloud* pInstance =
682 const_cast<SkyRenderableInstanceCloud*>(pNode->GetObj(i));
683 bbox = pInstance->GetWorldSpaceBounds();
684 iResult = CamMinMaxBoxOverlap(&cam, bbox.GetMin(), bbox.GetMax());
686 if (COMPLETEIN == iResult)
688 // draw the box in green
692 else if (PARTIAL == iResult)
694 // draw the box in yellow
702 _VisualizeCloudBVTree(cam, pNode->GetLeftChild());
703 _VisualizeCloudBVTree(cam, pNode->GetRightChild());
708 // draw the node's bbox in red.
709 // This should NEVER be visible from the camera from which it was culled!
711 pNode->GetNodeBV().Display();
716 //------------------------------------------------------------------------------
717 // Function : SkySceneManager::_ResolveVisibility
719 //------------------------------------------------------------------------------
721 * @fn SkySceneManager::_ResolveVisibility(const Camera &cam)
722 * @brief @todo <WRITE BRIEF SkySceneManager::_ResolveRenderingOrder DOCUMENTATION>
724 * @todo <WRITE EXTENDED SkySceneManager::_ResolveRenderingOrder FUNCTION DOCUMENTATION>
726 SKYRESULT SkySceneManager::_ResolveVisibility(const Camera &cam)
730 // clear the free instance array
731 _visibleInstances.clear();
733 // clear the contained instance arrays
734 ContainerSetIterator csi;
735 for (csi = _containerClouds.begin(); csi != _containerClouds.end(); ++csi)
737 csi->second->containedOpaqueInstances.clear();
738 csi->second->containedTransparentInstances.clear();
741 // clear the visible cloud array.
742 _visibleCloudInstances.clear();
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
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())
758 // first update this instance.
759 FAIL_RETURN_MSG((*ii)->Update(cam), "SkySceneManager::_ResolveVisibility(): instance update failed.");
761 if (!_TestInsertInstanceIntoClouds(cam, _cloudBVTree.GetRoot(), *ii, false))
762 _visibleInstances.push_back(*ii);
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())
773 // first update this instance.
774 FAIL_RETURN_MSG((*ii)->Update(cam), "SkySceneManager::Update(): instance update failed.");
776 if (!_TestInsertInstanceIntoClouds(cam, _cloudBVTree.GetRoot(), *ii, true))
777 _visibleInstances.push_back(*ii);
781 // view frustum cull the clouds
782 _ViewFrustumCullClouds(cam, _cloudBVTree.GetRoot());
784 // Clouds must be rendered in sorted order.
785 //_SortClouds(_visibleCloudInstances, cam.Orig);
787 // reshade the clouds if necessary.
790 printf("ReShading clouds\n");
791 FAIL_RETURN(ShadeClouds());
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();
800 // get the container corresponding to this cloud
801 ContainerSetIterator csi = _containerClouds.find((*cii)->GetID());
803 if (csi == _containerClouds.end())
805 SkyTrace("Error: SkySceneManager::_ResolveVisibility(): Invalid cloud instance %d.",
807 return SKYRESULT_FAIL;
810 if (csi->second->containedOpaqueInstances.size() > 0 ||
811 csi->second->containedTransparentInstances.size() > 0)
813 SortInstances(csi->second->containedOpaqueInstances, cam.Orig);
814 SortInstances(csi->second->containedTransparentInstances, cam.Orig);
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;
822 // find the closest contained instance to the camera
823 if (pOpaque && pTransparent)
825 if (*pOpaque < *pTransparent)
826 (*cii)->SetSplitPoint(pOpaque->GetPosition());
828 (*cii)->SetSplitPoint(pTransparent->GetPosition());
831 (*cii)->SetSplitPoint(pOpaque->GetPosition());
832 else if (pTransparent)
833 (*cii)->SetSplitPoint(pTransparent->GetPosition());
835 (*cii)->SetSplit(false);
838 (*cii)->SetSplit(false);
840 // add the container to the list of visiblie clouds to be rendered this frame.
841 _visibleInstances.push_back(csi->second);
843 // now update the impostors
844 FAIL_RETURN_MSG((*cii)->Update(cam),
845 "SkySceneManager::_ResolveVisibility(): cloud instance update failed.");
848 SortInstances(_visibleInstances, cam.Orig);
854 //------------------------------------------------------------------------------
855 // Function : SkySceneManager::_TestInsertInstanceIntoClouds
857 //------------------------------------------------------------------------------
859 * @fn SkySceneManager::_TestInsertInstanceIntoClouds(const Camera &cam, const CloudBVTree::Node *pNode, SkyRenderableInstance *pInstanceToInsert, bool bTransparent)
860 * @brief @todo <WRITE BRIEF SkySceneManager::_TestInsertInstanceIntoClouds DOCUMENTATION>
862 * @todo <WRITE EXTENDED SkySceneManager::_TestInsertInstanceIntoClouds FUNCTION DOCUMENTATION>
864 bool SkySceneManager::_TestInsertInstanceIntoClouds(const Camera &cam,
865 const CloudBVTree::Node *pNode,
866 SkyRenderableInstance *pInstanceToInsert,
869 if (_clouds.size() <= 0)
872 if (pNode->GetNodeBV().PointInBBox(pInstanceToInsert->GetPosition()))
879 // check the instance against each cloud in this leaf node.
880 for (i = 0; i < pNode->GetNumObjs(); ++i)
882 SkyRenderableInstanceCloud* pCloud =
883 const_cast<SkyRenderableInstanceCloud*>(pNode->GetObj(i));
884 bbox = pCloud->GetWorldSpaceBounds();
885 if (bbox.PointInBBox(pInstanceToInsert->GetPosition()))
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())
892 "Error: SkySceneManager::_TestInsertInstanceIntoClouds(): Invalid cloud instance %d.",
896 else // this instance is inside a cloud. Set up for split cloud rendering.
899 csi->second->containedOpaqueInstances.push_back(pInstanceToInsert);
901 csi->second->containedTransparentInstances.push_back(pInstanceToInsert);
902 csi->second->pCloud->SetSplit(true);
911 if (!_TestInsertInstanceIntoClouds(cam, pNode->GetLeftChild(), pInstanceToInsert, bTransparent))
912 return _TestInsertInstanceIntoClouds(cam, pNode->GetRightChild(), pInstanceToInsert, bTransparent);