Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

OgreSceneManager.cpp

Go to the documentation of this file.
00001 /*
00002 -----------------------------------------------------------------------------
00003 This source file is part of OGRE
00004     (Object-oriented Graphics Rendering Engine)
00005 For the latest info, see http://ogre.sourceforge.net/
00006 
00007 Copyright © 2000-2002 The OGRE Team
00008 Also see acknowledgements in Readme.html
00009 
00010 This program is free software; you can redistribute it and/or modify it under
00011 the terms of the GNU Lesser General Public License as published by the Free Software
00012 Foundation; either version 2 of the License, or (at your option) any later
00013 version.
00014 
00015 This program is distributed in the hope that it will be useful, but WITHOUT
00016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00017 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
00018 
00019 You should have received a copy of the GNU Lesser General Public License along with
00020 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
00021 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
00022 http://www.gnu.org/copyleft/lesser.txt.
00023 -----------------------------------------------------------------------------
00024 */
00025 #include "OgreStableHeaders.h"
00026 
00027 #include "OgreSceneManager.h"
00028 
00029 #include "OgreCamera.h"
00030 #include "OgreRenderSystem.h"
00031 #include "OgreMeshManager.h"
00032 #include "OgreMesh.h"
00033 #include "OgreSubMesh.h"
00034 #include "OgreEntity.h"
00035 #include "OgreSubEntity.h"
00036 #include "OgreLight.h"
00037 #include "OgreMath.h"
00038 #include "OgreControllerManager.h"
00039 #include "OgreMaterialManager.h"
00040 #include "OgreAnimation.h"
00041 #include "OgreAnimationTrack.h"
00042 #include "OgreRenderQueueSortingGrouping.h"
00043 #include "OgreOverlay.h"
00044 #include "OgreOverlayManager.h"
00045 #include "OgreStringConverter.h"
00046 #include "OgreRenderQueueListener.h"
00047 #include "OgreBillboardSet.h"
00048 #include "OgrePass.h"
00049 #include "OgreTechnique.h"
00050 #include "OgreTextureUnitState.h"
00051 #include "OgreException.h"
00052 #include "OgreLogManager.h"
00053 #include "OgreHardwareBufferManager.h"
00054 #include "OgreRoot.h"
00055 #include "OgreSpotShadowFadePng.h"
00056 #include "OgreGpuProgramManager.h"
00057 #include "OgreGpuProgram.h"
00058 #include "OgreShadowVolumeExtrudeProgram.h"
00059 
00060 // This class implements the most basic scene manager
00061 
00062 #include <cstdio>
00063 
00064 namespace Ogre {
00065 
00066     SceneManager::SceneManager()
00067     {
00068         // Root scene node
00069         mSceneRoot = new SceneNode(this, "root node");
00070         mRenderQueue = 0;
00071 
00072         // No sky by default
00073         mSkyPlaneEnabled = false;
00074         mSkyBoxEnabled = false;
00075         mSkyDomeEnabled = false;
00076 
00077         // init sky
00078         mSkyPlaneEntity = 0;
00079         size_t i;
00080         for (i = 0; i < 6; ++i)
00081         {
00082             mSkyBoxEntity[i] = 0;
00083         }
00084         for (i = 0; i < 5; ++i)
00085         {
00086             mSkyDomeEntity[i] = 0;
00087         }
00088         mSkyPlaneNode = 0;
00089         mSkyDomeNode = 0;
00090         mSkyBoxNode = 0;
00091 
00092 
00093         // No fog
00094         mFogMode = FOG_NONE;
00095 
00096         mDisplayNodes = false;
00097 
00098         mShowBoundingBoxes = false;
00099         mShadowTechnique = SHADOWTYPE_NONE;
00100         mDebugShadows = false;
00101         mShadowDebugPass = 0;
00102         mShadowStencilPass = 0;
00103         mShadowModulativePass = 0;
00104         mShadowCasterPlainBlackPass = 0;
00105         mShadowReceiverPass = 0;
00106         mFullScreenQuad = 0;
00107         mShadowCasterSphereQuery = 0;
00108         mShadowCasterAABBQuery = 0;
00109         mShadowDirLightExtrudeDist = 10000;
00110         mIlluminationStage = IRS_NONE;
00111         mShadowFarDist = 0;
00112         mShadowFarDistSquared = 0;
00113         mShadowIndexBufferSize = 51200;
00114         mShadowTextureSize = 512;
00115         mShadowTextureCount = 1;
00116         mShadowColour = ColourValue(0.25, 0.25, 0.25);
00117         mShadowTextureOffset = 0.6; 
00118         mShadowTextureFadeStart = 0.7; 
00119         mShadowTextureFadeEnd = 0.9; 
00120         mShadowUseInfiniteFarPlane = true;
00121 
00122 
00123     }
00124 
00125     SceneManager::~SceneManager()
00126     {
00127         clearScene();
00128         removeAllCameras();
00129         delete mSceneRoot;
00130         delete mFullScreenQuad;
00131         delete mShadowCasterSphereQuery;
00132         delete mShadowCasterAABBQuery;
00133         delete mRenderQueue;
00134     }
00135     //-----------------------------------------------------------------------
00136     RenderQueue* SceneManager::getRenderQueue(void)
00137     {
00138         if (!mRenderQueue)
00139         {
00140             initRenderQueue();
00141         }
00142         return mRenderQueue;
00143     }
00144     //-----------------------------------------------------------------------
00145     void SceneManager::initRenderQueue(void)
00146     {
00147         mRenderQueue = new RenderQueue();
00148         // init render queues that do not need shadows
00149         mRenderQueue->getQueueGroup(RENDER_QUEUE_BACKGROUND)->setShadowsEnabled(false);
00150         mRenderQueue->getQueueGroup(RENDER_QUEUE_OVERLAY)->setShadowsEnabled(false);
00151         mRenderQueue->getQueueGroup(RENDER_QUEUE_SKIES_EARLY)->setShadowsEnabled(false);
00152         mRenderQueue->getQueueGroup(RENDER_QUEUE_SKIES_LATE)->setShadowsEnabled(false);
00153     }
00154     //-----------------------------------------------------------------------
00155     Camera* SceneManager::createCamera(const String& name)
00156     {
00157         Camera *c = new Camera(name, this);
00158         mCameras.insert(CameraList::value_type(name, c));
00159 
00160 
00161         return c;
00162     }
00163 
00164     //-----------------------------------------------------------------------
00165     Camera* SceneManager::getCamera(const String& name)
00166     {
00167         CameraList::iterator i = mCameras.find(name);
00168         if (i == mCameras.end())
00169         {
00170             return 0;
00171         }
00172         else
00173         {
00174             return i->second;
00175         }
00176     }
00177 
00178     //-----------------------------------------------------------------------
00179     void SceneManager::removeCamera(Camera *cam)
00180     {
00181         // Find in list
00182         CameraList::iterator i = mCameras.begin();
00183         for (; i != mCameras.end(); ++i)
00184         {
00185             if (i->second == cam)
00186             {
00187                 mCameras.erase(i);
00188                 // notify render targets
00189                 mDestRenderSystem->_notifyCameraRemoved(cam);
00190                 delete cam;
00191                 break;
00192             }
00193         }
00194 
00195     }
00196 
00197     //-----------------------------------------------------------------------
00198     void SceneManager::removeCamera(const String& name)
00199     {
00200         // Find in list
00201         CameraList::iterator i = mCameras.find(name);
00202         if (i != mCameras.end())
00203         {
00204             // Notify render system
00205             mDestRenderSystem->_notifyCameraRemoved(i->second);
00206             delete i->second;
00207             mCameras.erase(i);
00208         }
00209 
00210     }
00211 
00212     //-----------------------------------------------------------------------
00213     void SceneManager::removeAllCameras(void)
00214     {
00215 
00216         CameraList::iterator i = mCameras.begin();
00217         for (; i != mCameras.end(); ++i)
00218         {
00219             // Notify render system
00220             mDestRenderSystem->_notifyCameraRemoved(i->second);
00221             delete i->second;
00222         }
00223         mCameras.clear();
00224     }
00225 
00226     //-----------------------------------------------------------------------
00227     Light* SceneManager::createLight(const String& name)
00228     {
00229         Light *l = new Light(name);
00230         mLights.insert(SceneLightList::value_type(name, l));
00231         return l;
00232     }
00233 
00234     //-----------------------------------------------------------------------
00235     Light* SceneManager::getLight(const String& name)
00236     {
00237         SceneLightList::iterator i = mLights.find(name);
00238         if (i == mLights.end())
00239         {
00240             return 0;
00241         }
00242         else
00243         {
00244             return i->second;
00245         }
00246     }
00247 
00248     //-----------------------------------------------------------------------
00249     void SceneManager::removeLight(Light *l)
00250     {
00251         // Find in list
00252         SceneLightList::iterator i = mLights.begin();
00253         for (; i != mLights.end(); ++i)
00254         {
00255             if (i->second == l)
00256             {
00257                 mLights.erase(i);
00258                 delete l;
00259                 break;
00260             }
00261         }
00262 
00263     }
00264 
00265     //-----------------------------------------------------------------------
00266     void SceneManager::removeLight(const String& name)
00267     {
00268         // Find in list
00269         SceneLightList::iterator i = mLights.find(name);
00270         if (i != mLights.end())
00271         {
00272             delete i->second;
00273             mLights.erase(i);
00274         }
00275 
00276     }
00277 
00278     //-----------------------------------------------------------------------
00279     void SceneManager::removeAllLights(void)
00280     {
00281 
00282         SceneLightList::iterator i = mLights.begin();
00283         for (; i != mLights.end(); ++i)
00284         {
00285             delete i->second;
00286         }
00287         mLights.clear();
00288     }
00289     //-----------------------------------------------------------------------
00290     bool SceneManager::lightLess::operator()(const Light* a, const Light* b) const
00291     {
00292         return a->tempSquareDist < b->tempSquareDist;
00293     }
00294     //-----------------------------------------------------------------------
00295     void SceneManager::_populateLightList(const Vector3& position, LightList& destList)
00296     {
00297         // Really basic trawl of the lights, then sort
00298         destList.clear();
00299 
00300         SceneLightList::iterator i, iend;
00301         iend = mLights.end();
00302         for (i = mLights.begin(); i != iend; ++i)
00303         {
00304             Light* lt = i->second;
00305             if (lt->isVisible())
00306             {
00307                 if (lt->getType() == Light::LT_DIRECTIONAL)
00308                 {
00309                     // No distance
00310                     lt->tempSquareDist = 0.0f;
00311                     destList.push_back(lt);
00312                 }
00313                 else
00314                 {
00315                     // Calc squared distance
00316                     lt->tempSquareDist = (lt->getDerivedPosition() - position).squaredLength();
00317                     // only add in-range lights
00318                     Real range = lt->getAttenuationRange();
00319                     if (lt->tempSquareDist <= (range * range))
00320                     {
00321                         destList.push_back(lt);
00322                     }
00323                 }
00324             }
00325         }
00326 
00327         // Sort
00328         std::sort(destList.begin(), destList.end(), lightLess());
00329 
00330 
00331     }
00332     //-----------------------------------------------------------------------
00333     Entity* SceneManager::createEntity(const String& entityName, PrefabType ptype)
00334     {
00335         switch (ptype)
00336         {
00337         case PT_PLANE:
00338             return createEntity(entityName, "Prefab_Plane");
00339 
00340             break;
00341         }
00342 
00343         return 0;
00344     }
00345 
00346     //-----------------------------------------------------------------------
00347     Entity* SceneManager::createEntity(
00348         const String& entityName,
00349         const String& meshName )
00350     {
00351         // Check name not used
00352         EntityList::iterator it = mEntities.find( entityName );
00353         if( it != mEntities.end() )
00354         {
00355             Except(
00356                 Exception::ERR_DUPLICATE_ITEM,
00357                 "An entity with the name " + entityName + " already exists",
00358                 "SceneManager::createEntity" );
00359         }
00360 
00361         // Get mesh (load if required)
00362         Mesh* pMesh = MeshManager::getSingleton().load( meshName );
00363 
00364         // Create entity
00365         Entity* e = new Entity( entityName, pMesh, this );
00366 
00367         // Add to internal list
00368         mEntities[entityName] = e; //.insert(EntityList::value_type(entityName, e));
00369 
00370         return e;
00371     }
00372 
00373     //-----------------------------------------------------------------------
00374     Entity* SceneManager::getEntity(const String& name)
00375     {
00376         EntityList::iterator i = mEntities.find(name);
00377         if (i == mEntities.end())
00378         {
00379             return 0;
00380         }
00381         else
00382         {
00383             return i->second;
00384         }
00385     }
00386 
00387     //-----------------------------------------------------------------------
00388     void SceneManager::removeEntity(Entity *cam)
00389     {
00390         // Find in list
00391         EntityList::iterator i = mEntities.begin();
00392         for (; i != mEntities.end(); ++i)
00393         {
00394             if (i->second == cam)
00395             {
00396                 mEntities.erase(i);
00397                 delete cam;
00398                 break;
00399             }
00400         }
00401 
00402     }
00403 
00404     //-----------------------------------------------------------------------
00405     void SceneManager::removeEntity(const String& name)
00406     {
00407         // Find in list
00408         EntityList::iterator i = mEntities.find(name);
00409         if (i != mEntities.end())
00410         {
00411             delete i->second;
00412             mEntities.erase(i);
00413         }
00414 
00415     }
00416 
00417     //-----------------------------------------------------------------------
00418     void SceneManager::removeAllEntities(void)
00419     {
00420 
00421         EntityList::iterator i = mEntities.begin();
00422         for (; i != mEntities.end(); ++i)
00423         {
00424             delete i->second;
00425         }
00426         mEntities.clear();
00427     }
00428 
00429     //-----------------------------------------------------------------------
00430     void SceneManager::removeAllBillboardSets(void)
00431     {
00432         // Delete all BillboardSets
00433         for (BillboardSetList::iterator bi = mBillboardSets.begin();
00434             bi != mBillboardSets.end(); ++bi)
00435         {
00436             delete bi->second;
00437         }
00438         mBillboardSets.clear();
00439     }
00440     //-----------------------------------------------------------------------
00441     void SceneManager::clearScene(void)
00442     {
00443         // Delete all SceneNodes, except root that is
00444         for (SceneNodeList::iterator i = mSceneNodes.begin();
00445             i != mSceneNodes.end(); ++i)
00446         {
00447             delete i->second;
00448         }
00449         mSceneNodes.clear();
00450         mAutoTrackingSceneNodes.clear();
00451 
00452         // Clear root node of all children
00453         mSceneRoot->removeAllChildren();
00454         mSceneRoot->detachAllObjects();
00455 
00456         removeAllEntities();
00457         removeAllBillboardSets();
00458         removeAllLights();
00459 
00460         // Clear animations
00461         destroyAllAnimations();
00462 
00463         // Remove sky nodes since they've been deleted
00464         mSkyBoxNode = mSkyPlaneNode = mSkyDomeNode = 0;
00465         mSkyBoxEnabled = mSkyPlaneEnabled = mSkyDomeEnabled = false; 
00466 
00467     }
00468 
00469     //-----------------------------------------------------------------------
00470     Material* SceneManager::createMaterial(const String& name)
00471     {
00472         // Create using MaterialManager
00473         Material* m = (Material*)MaterialManager::getSingleton().create(name);
00474 
00475 
00476         return m;
00477     }
00478     //-----------------------------------------------------------------------
00479     Material* SceneManager::getDefaultMaterialSettings(void)
00480     {
00481         return Material::mDefaultSettings;
00482     }
00483     //-----------------------------------------------------------------------
00484     Material* SceneManager::getMaterial(const String& name)
00485     {
00486         return (Material*)MaterialManager::getSingleton().getByName(name);
00487     }
00488 
00489     //-----------------------------------------------------------------------
00490     Material* SceneManager::getMaterial(int handle)
00491     {
00492         return static_cast<Material*>(
00493             MaterialManager::getSingleton().getByHandle(handle));
00494     }
00495     //-----------------------------------------------------------------------
00496     SceneNode* SceneManager::createSceneNode(void)
00497     {
00498         SceneNode* sn = new SceneNode(this);
00499         mSceneNodes[sn->getName()] = sn;
00500         return sn;
00501     }
00502     //-----------------------------------------------------------------------
00503     SceneNode* SceneManager::createSceneNode(const String& name)
00504     {
00505         SceneNode* sn = new SceneNode(this, name);
00506         mSceneNodes[sn->getName()] = sn;
00507         return sn;
00508     }
00509     //-----------------------------------------------------------------------
00510     void SceneManager::destroySceneNode(const String& name)
00511     {
00512         SceneNodeList::iterator i = mSceneNodes.find(name);
00513 
00514         if (i == mSceneNodes.end())
00515         {
00516             Except(Exception::ERR_ITEM_NOT_FOUND, "SceneNode '" + name + "' not found.",
00517                 "SceneManager::destroySceneNode");
00518         }
00519 
00520         // Find any scene nodes which are tracking this node, and turn them off
00521         AutoTrackingSceneNodes::iterator ai, aiend;
00522         aiend = mAutoTrackingSceneNodes.end();
00523         for (ai = mAutoTrackingSceneNodes.begin(); ai != aiend; ++ai)
00524         {
00525             SceneNode* n = *ai;
00526             // Tracking this node
00527             if (n->getAutoTrackTarget() == i->second)
00528             {
00529                 // turn off, this will notify SceneManager to remove
00530                 n->setAutoTracking(false);
00531                 // no need to reset iterator since set erase does not invalidate
00532             }
00533             // node is itself a tracker
00534             else if (n == i->second)
00535             {
00536                 mAutoTrackingSceneNodes.erase(ai);
00537             }
00538         }
00539 
00540         delete i->second;
00541         mSceneNodes.erase(i);
00542     }
00543     //-----------------------------------------------------------------------
00544     SceneNode* SceneManager::getRootSceneNode(void) const
00545     {
00546         return mSceneRoot;
00547     }
00548     //-----------------------------------------------------------------------
00549     SceneNode* SceneManager::getSceneNode(const String& name) const
00550     {
00551         SceneNodeList::const_iterator i = mSceneNodes.find(name);
00552 
00553         if (i == mSceneNodes.end())
00554         {
00555             Except(Exception::ERR_ITEM_NOT_FOUND, "SceneNode '" + name + "' not found.",
00556                 "SceneManager::getSceneNode");
00557         }
00558 
00559         return i->second;
00560         
00561     }
00562     //-----------------------------------------------------------------------
00563     Pass* SceneManager::setPass(Pass* pass)
00564     {
00565         static bool lastUsedVertexProgram = false;
00566         static bool lastUsedFragmentProgram = false;
00567 
00568         if (mIlluminationStage == IRS_RENDER_TO_TEXTURE)
00569         {
00570             // Derive a special shadow caster pass from this one
00571             pass = deriveShadowCasterPass(pass);
00572         }
00573         else if (mIlluminationStage == IRS_RENDER_MODULATIVE_PASS)
00574         {
00575             pass = deriveShadowReceiverPass(pass);
00576         }
00577 
00578         // TEST
00579         /*
00580         LogManager::getSingleton().logMessage("BEGIN PASS " + StringConverter::toString(pass->getIndex()) + 
00581             " of " + pass->getParent()->getParent()->getName());
00582         */
00583 
00584         if (pass->hasVertexProgram())
00585         {
00586             mDestRenderSystem->bindGpuProgram(pass->getVertexProgram()->_getBindingDelegate());
00587             // bind parameters later since they can be per-object
00588             lastUsedVertexProgram = true;
00589         }
00590         else
00591         {
00592             // Unbind program?
00593             if (lastUsedVertexProgram)
00594             {
00595                 mDestRenderSystem->unbindGpuProgram(GPT_VERTEX_PROGRAM);
00596                 lastUsedVertexProgram = false;
00597             }
00598             // Set fixed-function vertex parameters
00599 
00600             // Set surface reflectance properties, only valid if lighting is enabled
00601             if (pass->getLightingEnabled())
00602             {
00603                 mDestRenderSystem->_setSurfaceParams( 
00604                     pass->getAmbient(), 
00605                     pass->getDiffuse(), 
00606                     pass->getSpecular(), 
00607                     pass->getSelfIllumination(), 
00608                     pass->getShininess() );
00609             }
00610 
00611             // Dynamic lighting enabled?
00612             mDestRenderSystem->setLightingEnabled(pass->getLightingEnabled());
00613         }
00614 
00615         // Using a fragment program?
00616         if (pass->hasFragmentProgram())
00617         {
00618             mDestRenderSystem->bindGpuProgram(
00619                 pass->getFragmentProgram()->_getBindingDelegate());
00620             // bind parameters later since they can be per-object
00621             lastUsedFragmentProgram = true;
00622         }
00623         else
00624         {
00625             // Unbind program?
00626             if (lastUsedFragmentProgram)
00627             {
00628                 mDestRenderSystem->unbindGpuProgram(GPT_FRAGMENT_PROGRAM);
00629                 lastUsedFragmentProgram = false;
00630             }
00631 
00632             // Set fixed-function fragment settings
00633 
00634             // Fog (assumes we want pixel fog which is the usual)
00635             // New fog params can either be from scene or from material
00636             FogMode newFogMode;
00637             ColourValue newFogColour;
00638             Real newFogStart, newFogEnd, newFogDensity;
00639             if (pass->getFogOverride())
00640             {
00641                 // New fog params from material
00642                 newFogMode = pass->getFogMode();
00643                 newFogColour = pass->getFogColour();
00644                 newFogStart = pass->getFogStart();
00645                 newFogEnd = pass->getFogEnd();
00646                 newFogDensity = pass->getFogDensity();
00647             }
00648             else
00649             {
00650                 // New fog params from scene
00651                 newFogMode = mFogMode;
00652                 newFogColour = mFogColour;
00653                 newFogStart = mFogStart;
00654                 newFogEnd = mFogEnd;
00655                 newFogDensity = mFogDensity;
00656             }
00657             mDestRenderSystem->_setFog(
00658                 newFogMode, newFogColour, newFogDensity, newFogStart, newFogEnd);
00659 
00660         }
00661 
00662         // The rest of the settings are the same no matter whether we use programs or not
00663 
00664         // Set scene blending
00665         mDestRenderSystem->_setSceneBlending(
00666             pass->getSourceBlendFactor(), pass->getDestBlendFactor());
00667 
00668 
00669         // Texture unit settings
00670         
00671         Pass::TextureUnitStateIterator texIter =  pass->getTextureUnitStateIterator();
00672         size_t unit = 0;
00673         while(texIter.hasMoreElements())
00674         {
00675             TextureUnitState* pTex = texIter.getNext();
00676             mDestRenderSystem->_setTextureUnitSettings(unit, *pTex);
00677             ++unit;
00678         }
00679         // Disable remaining texture units
00680         mDestRenderSystem->_disableTextureUnitsFrom(pass->getNumTextureUnitStates());
00681 
00682         // Set up non-texture related material settings
00683         // Depth buffer settings
00684         mDestRenderSystem->_setDepthBufferFunction(pass->getDepthFunction());
00685         mDestRenderSystem->_setDepthBufferCheckEnabled(pass->getDepthCheckEnabled());
00686         mDestRenderSystem->_setDepthBufferWriteEnabled(pass->getDepthWriteEnabled());
00687         mDestRenderSystem->_setDepthBias(pass->getDepthBias());
00688         // Set colour write mode
00689         // Right now we only use on/off, not per-channel
00690         bool colWrite = pass->getColourWriteEnabled();
00691         mDestRenderSystem->_setColourBufferWriteEnabled(colWrite, colWrite, colWrite, colWrite);
00692         // Culling mode
00693         mDestRenderSystem->_setCullingMode(pass->getCullingMode());
00694         // Shading
00695         mDestRenderSystem->setShadingType(pass->getShadingMode());
00696 
00697         return pass;
00698     }
00699     //-----------------------------------------------------------------------
00700     void SceneManager::_renderScene(Camera* camera, Viewport* vp, bool includeOverlays)
00701     {
00702         Root::getSingleton()._setCurrentSceneManager(this);
00703         // Prep Pass for use in debug shadows
00704         initShadowVolumeMaterials();
00705         // Perform a quick pre-check to see whether we should override far distance
00706         // When using stencil volumes we have to use infinite far distance
00707         // to prevent dark caps getting clipped
00708         if ((mShadowTechnique == SHADOWTYPE_STENCIL_ADDITIVE ||
00709             mShadowTechnique == SHADOWTYPE_STENCIL_MODULATIVE) && 
00710             camera->getFarClipDistance() != 0 && 
00711             mDestRenderSystem->getCapabilities()->hasCapability(RSC_INFINITE_FAR_PLANE) && 
00712             mShadowUseInfiniteFarPlane)
00713         {
00714             // infinite far distance
00715             camera->setFarClipDistance(0);
00716         }
00717 
00718         mCameraInProgress = camera;
00719         mCamChanged = true;
00720 
00721 
00722         // Update the scene, only do this once per frame
00723         static unsigned long lastFrameNumber = 0;
00724         unsigned long thisFrameNumber = Root::getSingleton().getCurrentFrameNumber();
00725         if (thisFrameNumber != lastFrameNumber)
00726         {
00727             // Update animations
00728             _applySceneAnimations();
00729             // Update controllers 
00730             ControllerManager::getSingleton().updateAllControllers();
00731             lastFrameNumber = thisFrameNumber;
00732         }
00733         
00734         // Update scene graph for this camera (can happen multiple times per frame)
00735         _updateSceneGraph(camera);
00736 
00737         // Auto-track nodes
00738         AutoTrackingSceneNodes::iterator atsni, atsniend;
00739         atsniend = mAutoTrackingSceneNodes.end();
00740         for (atsni = mAutoTrackingSceneNodes.begin(); atsni != atsniend; ++atsni)
00741         {
00742             (*atsni)->_autoTrack();
00743         }
00744         // Auto-track camera if required
00745         camera->_autoTrack();
00746 
00747 
00748         // Are we using any shadows at all?
00749         if (mShadowTechnique != SHADOWTYPE_NONE && 
00750             mIlluminationStage != IRS_RENDER_TO_TEXTURE)
00751         {
00752             // Locate any lights which could be affecting the frustum
00753             findLightsAffectingFrustum(camera);
00754             if (mShadowTechnique == SHADOWTYPE_TEXTURE_MODULATIVE 
00755                 /* || mShadowTechnique == SHADOWTYPE_TEXTURE_SHADOWMAP */)
00756             {
00757                 // *******
00758                 // WARNING
00759                 // *******
00760                 // This call will result in re-entrant calls to this method
00761                 // therefore anything which comes before this is NOT 
00762                 // guaranteed persistent. Make sure that anything which 
00763                 // MUST be specific to this camera / target is done 
00764                 // AFTER THIS POINT
00765                 prepareShadowTextures(camera, vp);
00766                 // reset the cameras because of the re-entrant call
00767                 mCameraInProgress = camera;
00768                 mCamChanged = true;
00769             }
00770         }
00771         
00772         // Invert vertex winding?
00773         if (camera->isReflected())
00774         {
00775             mDestRenderSystem->setInvertVertexWinding(true);
00776         }
00777         else
00778         {
00779             mDestRenderSystem->setInvertVertexWinding(false);
00780         }
00781 
00782         // Set the viewport
00783         setViewport(vp);
00784 
00785         // Tell params about camera
00786         mAutoParamDataSource.setCurrentCamera(camera);
00787         // Set autoparams for finite dir light extrusion
00788         mAutoParamDataSource.setShadowDirLightExtrusionDistance(mShadowDirLightExtrudeDist);
00789 
00790         // Tell params about current ambient light
00791         mAutoParamDataSource.setAmbientLightColour(mAmbientLight);
00792 
00793         // Tell params about render target
00794         mAutoParamDataSource.setCurrentRenderTarget(vp->getTarget());
00795 
00796 
00797         // Set camera window clipping planes (if any)
00798         if (mDestRenderSystem->getCapabilities()->hasCapability(RSC_USER_CLIP_PLANES))
00799         {
00800             if (camera->isWindowSet())  
00801             {
00802                 const std::vector<Plane>& planeList = 
00803                     camera->getWindowPlanes();
00804                 for (ushort i = 0; i < 4; ++i)
00805                 {
00806                     mDestRenderSystem->enableClipPlane(i, true);
00807                     mDestRenderSystem->setClipPlane(i, planeList[i]);
00808                 }
00809             }
00810             else
00811             {
00812                 for (ushort i = 0; i < 4; ++i)
00813                 {
00814                     mDestRenderSystem->enableClipPlane(i, false);
00815                 }
00816             }
00817         }
00818 
00819         // Clear the render queue
00820         getRenderQueue()->clear();
00821 
00822         // Parse the scene and tag visibles
00823         _findVisibleObjects(camera, 
00824             mIlluminationStage == IRS_RENDER_TO_TEXTURE? true : false);
00825         // Add overlays, if viewport deems it
00826         if (vp->getOverlaysEnabled())
00827         {
00828             OverlayManager::getSingleton()._queueOverlaysForRendering(camera, getRenderQueue(), vp);
00829         }
00830         // Queue skies
00831         _queueSkiesForRendering(camera);
00832 
00833 
00834         // Don't do view / proj here anymore
00835         // Checked per renderable now, although only changed when required
00836         //mDestRenderSystem->_setViewMatrix(camera->getViewMatrix());
00837         //mDestRenderSystem->_setProjectionMatrix(camera->getProjectionMatrix());
00838 
00839         mDestRenderSystem->_beginGeometryCount();
00840         // Begin the frame
00841         mDestRenderSystem->_beginFrame();
00842 
00843         // Set rasterisation mode
00844         mDestRenderSystem->_setRasterisationMode(camera->getDetailLevel());
00845 
00846         // Render scene content 
00847         _renderVisibleObjects();
00848 
00849         // End frame
00850         mDestRenderSystem->_endFrame();
00851 
00852         // Notify camera or vis faces
00853         camera->_notifyRenderedFaces(mDestRenderSystem->_getFaceCount());
00854 
00855 
00856 
00857     }
00858 
00859 
00860     //-----------------------------------------------------------------------
00861     void SceneManager::_setDestinationRenderSystem(RenderSystem* sys)
00862     {
00863         mDestRenderSystem = sys;
00864 
00865     }
00866 
00867 
00868     //-----------------------------------------------------------------------
00869     void SceneManager::setWorldGeometry(const String& filename)
00870     {
00871         // This default implementation cannot handle world geometry
00872         Except(Exception::ERR_INVALIDPARAMS,
00873             "World geometry is not supported by the generic SceneManager.",
00874             "SceneManager::setWorldGeometry");
00875     }
00876 
00877     //-----------------------------------------------------------------------
00878     bool SceneManager::materialLess::operator() (const Material* x, const Material* y) const
00879     {
00880         // If x transparent and y not, x > y (since x has to overlap y)
00881         if (x->isTransparent() && !y->isTransparent())
00882         {
00883             return false;
00884         }
00885         // If y is transparent and x not, x < y
00886         else if (!x->isTransparent() && y->isTransparent())
00887         {
00888             return true;
00889         }
00890         else
00891         {
00892             // Otherwise don't care (both transparent or both solid)
00893             // Just arbitrarily use pointer
00894             return x < y;
00895         }
00896 
00897     }
00898 
00899     //-----------------------------------------------------------------------
00900     void SceneManager::setSkyPlane(
00901         bool enable,
00902         const Plane& plane,
00903         const String& materialName,
00904         Real gscale,
00905         Real tiling,
00906         bool drawFirst,
00907         Real bow)
00908     {
00909         mSkyPlaneEnabled = enable;
00910         if (enable)
00911         {
00912             String meshName = "SkyPlane";
00913             mSkyPlane = plane;
00914 
00915             Material* m = getMaterial(materialName);
00916             if (!m)
00917             {
00918                 Except(Exception::ERR_INVALIDPARAMS, 
00919                     "Sky plane material '" + materialName + "' not found.",
00920                     "SceneManager::setSkyPlane");
00921             }
00922             // Make sure the material doesn't update the depth buffer
00923             m->setDepthWriteEnabled(false);
00924             // Ensure loaded
00925             m->load();
00926 
00927             mSkyPlaneDrawFirst = drawFirst;
00928 
00929             // Set up the plane
00930             Mesh* planeMesh = (Mesh*)MeshManager::getSingleton().getByName(meshName);
00931             if (planeMesh)
00932             {
00933                 // Destroy the old one
00934                 MeshManager::getSingleton().unload(planeMesh);
00935                 delete planeMesh;
00936             }
00937 
00938             // Create up vector
00939             Vector3 up = plane.normal.crossProduct(Vector3::UNIT_X);
00940             if (up == Vector3::ZERO)
00941                 up = plane.normal.crossProduct(-Vector3::UNIT_Z);
00942 
00943             // Create skyplane
00944             if( bow > 0 )
00945             {
00946                 // Build a curved skyplane
00947                 planeMesh = MeshManager::getSingleton().createCurvedPlane(meshName, plane, gscale * 100, gscale * 100, gscale * bow * 100, 6, 6, false, 1, tiling, tiling, up);
00948             }
00949             else
00950             {
00951                 planeMesh = MeshManager::getSingleton().createPlane(meshName, plane, gscale * 100, gscale * 100, 1, 1, false, 1, tiling, tiling, up);
00952             }
00953 
00954             // Create entity 
00955             if (mSkyPlaneEntity)
00956             {
00957                 // destroy old one, do it by name for speed
00958                 removeEntity(meshName);
00959             }
00960             // Create, use the same name for mesh and entity
00961             mSkyPlaneEntity = createEntity(meshName, meshName);
00962             mSkyPlaneEntity->setMaterialName(materialName);
00963             mSkyPlaneEntity->setCastShadows(false);
00964 
00965             // Create node and attach
00966             if (!mSkyPlaneNode)
00967             {
00968                 mSkyPlaneNode = createSceneNode(meshName + "Node");
00969             }
00970             else
00971             {
00972                 mSkyPlaneNode->detachAllObjects();
00973             }
00974             mSkyPlaneNode->attachObject(mSkyPlaneEntity);
00975 
00976         }
00977     }
00978     //-----------------------------------------------------------------------
00979     void SceneManager::setSkyBox(
00980         bool enable,
00981         const String& materialName,
00982         Real distance,
00983         bool drawFirst,
00984         const Quaternion& orientation )
00985     {
00986         mSkyBoxEnabled = enable;
00987         if (enable)
00988         {
00989             Material* m = getMaterial(materialName);
00990             if (!m)
00991             {
00992                 Except(Exception::ERR_INVALIDPARAMS, 
00993                     "Sky box material '" + materialName + " not found.",
00994                     "SceneManager::setSkyBox");
00995             }
00996             // Make sure the material doesn't update the depth buffer
00997             m->setDepthWriteEnabled(false);
00998             // Ensure loaded
00999             m->load();
01000             // Also clamp texture, don't wrap (otherwise edges can get filtered)
01001             m->getBestTechnique()->getPass(0)->getTextureUnitState(0)->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
01002 
01003 
01004             mSkyBoxDrawFirst = drawFirst;
01005 
01006             // Create node 
01007             if (!mSkyBoxNode)
01008             {
01009                 mSkyBoxNode = createSceneNode("SkyBoxNode");
01010             }
01011             else
01012             {
01013                 mSkyBoxNode->detachAllObjects();
01014             }
01015 
01016             MaterialManager& matMgr = MaterialManager::getSingleton();
01017             // Set up the box (6 planes)
01018             for (int i = 0; i < 6; ++i)
01019             {
01020                 Mesh* planeMesh = createSkyboxPlane((BoxPlane)i, distance, orientation);
01021                 String entName = "SkyBoxPlane" + StringConverter::toString(i);
01022 
01023                 // Create entity 
01024                 if (mSkyBoxEntity[i])
01025                 {
01026                     // destroy old one, do it by name for speed
01027                     removeEntity(entName);
01028                 }
01029                 mSkyBoxEntity[i] = createEntity(entName, planeMesh->getName());
01030                 mSkyBoxEntity[i]->setCastShadows(false);
01031                 // Have to create 6 materials, one for each frame
01032                 // Used to use combined material but now we're using queue we can't split to change frame
01033                 // This doesn't use much memory because textures aren't duplicated
01034                 Material* boxMat = (Material*)matMgr.getByName(entName);
01035                 if (!boxMat)
01036                 {
01037                     // Create new by clone
01038                     boxMat = m->clone(entName);
01039                     boxMat->load();
01040                 }
01041                 else
01042                 {
01043                     // Copy over existing
01044                     m->copyDetailsTo(boxMat);
01045                     boxMat->load();
01046                 }
01047                 // Set active frame
01048                 boxMat->getBestTechnique()->getPass(0)->getTextureUnitState(0)
01049                     ->setCurrentFrame(i);
01050 
01051                 mSkyBoxEntity[i]->setMaterialName(boxMat->getName());
01052 
01053                 // Attach to node
01054                 mSkyBoxNode->attachObject(mSkyBoxEntity[i]);
01055             } // for each plane
01056 
01057         }
01058 
01059     }
01060     //-----------------------------------------------------------------------
01061     void SceneManager::setSkyDome(
01062         bool enable,
01063         const String& materialName,
01064         Real curvature,
01065         Real tiling,
01066         Real distance,
01067         bool drawFirst,
01068         const Quaternion& orientation )
01069     {
01070         mSkyDomeEnabled = enable;
01071         if (enable)
01072         {
01073             Material* m = getMaterial(materialName);
01074             if (!m)
01075             {
01076                 Except(Exception::ERR_INVALIDPARAMS, 
01077                     "Sky dome material '" + materialName + " not found.",
01078                     "SceneManager::setSkyDome");
01079             }
01080             // Make sure the material doesn't update the depth buffer
01081             m->setDepthWriteEnabled(false);
01082             // Ensure loaded
01083             m->load();
01084 
01085             mSkyDomeDrawFirst = drawFirst;
01086 
01087             // Create node 
01088             if (!mSkyDomeNode)
01089             {
01090                 mSkyDomeNode = createSceneNode("SkyDomeNode");
01091             }
01092             else
01093             {
01094                 mSkyDomeNode->detachAllObjects();
01095             }
01096 
01097             // Set up the dome (5 planes)
01098             for (int i = 0; i < 5; ++i)
01099             {
01100                 Mesh* planeMesh = createSkydomePlane((BoxPlane)i, curvature, tiling, distance, orientation);
01101 
01102                 String entName = "SkyDomePlane" + StringConverter::toString(i);
01103 
01104                 // Create entity 
01105                 if (mSkyDomeEntity[i])
01106                 {
01107                     // destroy old one, do it by name for speed
01108                     removeEntity(entName);
01109                 }
01110                 mSkyDomeEntity[i] = createEntity(entName, planeMesh->getName());
01111                 mSkyDomeEntity[i]->setMaterialName(m->getName());
01112                 mSkyDomeEntity[i]->setCastShadows(false);
01113 
01114                 // Attach to node
01115                 mSkyDomeNode->attachObject(mSkyDomeEntity[i]);
01116             } // for each plane
01117 
01118         }
01119     }
01120     //-----------------------------------------------------------------------
01121     Mesh* SceneManager::createSkyboxPlane(
01122         BoxPlane bp,
01123         Real distance,
01124         const Quaternion& orientation )
01125     {
01126         Plane plane;
01127         String meshName;
01128         Vector3 up;
01129 
01130         meshName = "SkyBoxPlane_";
01131         // Set up plane equation
01132         plane.d = distance;
01133         switch(bp)
01134         {
01135         case BP_FRONT:
01136             plane.normal = Vector3::UNIT_Z;
01137             up = Vector3::UNIT_Y;
01138             meshName += "Front";
01139             break;
01140         case BP_BACK:
01141             plane.normal = -Vector3::UNIT_Z;
01142             up = Vector3::UNIT_Y;
01143             meshName += "Back";
01144             break;
01145         case BP_LEFT:
01146             plane.normal = Vector3::UNIT_X;
01147             up = Vector3::UNIT_Y;
01148             meshName += "Left";
01149             break;
01150         case BP_RIGHT:
01151             plane.normal = -Vector3::UNIT_X;
01152             up = Vector3::UNIT_Y;
01153             meshName += "Right";
01154             break;
01155         case BP_UP:
01156             plane.normal = -Vector3::UNIT_Y;
01157             up = Vector3::UNIT_Z;
01158             meshName += "Up";
01159             break;
01160         case BP_DOWN:
01161             plane.normal = Vector3::UNIT_Y;
01162             up = -Vector3::UNIT_Z;
01163             meshName += "Down";
01164             break;
01165         }
01166         // Modify by orientation
01167         plane.normal = orientation * plane.normal;
01168         up = orientation * up;
01169 
01170 
01171         // Check to see if existing plane
01172         MeshManager& mm = MeshManager::getSingleton();
01173         Mesh* planeMesh = (Mesh*)mm.getByName(meshName);
01174         if(planeMesh)
01175         {
01176             // destroy existing
01177             mm.unload(planeMesh);
01178             delete planeMesh;
01179         }
01180         // Create new
01181         Real planeSize = distance * 2;
01182         const int BOX_SEGMENTS = 1;
01183         planeMesh = mm.createPlane(meshName, plane, planeSize, planeSize, BOX_SEGMENTS, BOX_SEGMENTS, false, 1, 1, 1, up);
01184 
01185         //planeMesh->_dumpContents(meshName);
01186 
01187         return planeMesh;
01188 
01189     }
01190     //-----------------------------------------------------------------------
01191     Mesh* SceneManager::createSkydomePlane(
01192         BoxPlane bp,
01193         Real curvature,
01194         Real tiling,
01195         Real distance,
01196         const Quaternion& orientation )
01197     {
01198 
01199         Plane plane;
01200         String meshName;
01201         Vector3 up;
01202 
01203         meshName = "SkyDomePlane_";
01204         // Set up plane equation
01205         plane.d = distance;
01206         switch(bp)
01207         {
01208         case BP_FRONT:
01209             plane.normal = Vector3::UNIT_Z;
01210             up = Vector3::UNIT_Y;
01211             meshName += "Front";
01212             break;
01213         case BP_BACK:
01214             plane.normal = -Vector3::UNIT_Z;
01215             up = Vector3::UNIT_Y;
01216             meshName += "Back";
01217             break;
01218         case BP_LEFT:
01219             plane.normal = Vector3::UNIT_X;
01220             up = Vector3::UNIT_Y;
01221             meshName += "Left";
01222             break;
01223         case BP_RIGHT:
01224             plane.normal = -Vector3::UNIT_X;
01225             up = Vector3::UNIT_Y;
01226             meshName += "Right";
01227             break;
01228         case BP_UP:
01229             plane.normal = -Vector3::UNIT_Y;
01230             up = Vector3::UNIT_Z;
01231             meshName += "Up";
01232             break;
01233         case BP_DOWN:
01234             // no down
01235             return 0;
01236         }
01237         // Modify by orientation
01238         plane.normal = orientation * plane.normal;
01239         up = orientation * up;
01240 
01241         // Check to see if existing plane
01242         MeshManager& mm = MeshManager::getSingleton();
01243         Mesh* planeMesh = (Mesh*)mm.getByName(meshName);
01244         if(planeMesh)
01245         {
01246             // destroy existing
01247             mm.unload(planeMesh);
01248             delete planeMesh;
01249         }
01250         // Create new
01251         Real planeSize = distance * 2;
01252         const int BOX_SEGMENTS = 16;
01253         planeMesh = mm.createCurvedIllusionPlane(meshName, plane, planeSize, planeSize, curvature, 
01254             BOX_SEGMENTS, BOX_SEGMENTS, false, 1, tiling, tiling, up, orientation, HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, HardwareBuffer::HBU_STATIC_WRITE_ONLY, 
01255             false, false);
01256 
01257         //planeMesh->_dumpContents(meshName);
01258 
01259         return planeMesh;
01260 
01261     }
01262 
01263 
01264     //-----------------------------------------------------------------------
01265     void SceneManager::_updateSceneGraph(Camera* cam)
01266     {
01267         // Cascade down the graph updating transforms & world bounds
01268         // In this implementation, just update from the root
01269         // Smarter SceneManager subclasses may choose to update only
01270         //   certain scene graph branches
01271         mSceneRoot->_update(true, false);
01272 
01273 
01274     }
01275     //-----------------------------------------------------------------------
01276     void SceneManager::_findVisibleObjects(Camera* cam, bool onlyShadowCasters)
01277     {
01278         // Tell nodes to find, cascade down all nodes
01279         mSceneRoot->_findVisibleObjects(cam, getRenderQueue(), true, 
01280             mDisplayNodes, onlyShadowCasters);
01281 
01282     }
01283     //-----------------------------------------------------------------------
01284     void SceneManager::_renderVisibleObjects(void)
01285     {
01286         // Render each separate queue
01287         RenderQueue::QueueGroupIterator queueIt = getRenderQueue()->_getQueueGroupIterator();
01288 
01289         // NB only queues which have been created are rendered, no time is wasted
01290         //   parsing through non-existent queues (even though there are 10 available)
01291 
01292         while (queueIt.hasMoreElements())
01293         {
01294             // Get queue group id
01295             RenderQueueGroupID qId = queueIt.peekNextKey();
01296             RenderQueueGroup* pGroup = queueIt.getNext();
01297 
01298 
01299             bool repeatQueue = false;
01300             do // for repeating queues
01301             {
01302                 // Fire queue started event
01303                 if (fireRenderQueueStarted(qId))
01304                 {
01305                     // Someone requested we skip this queue
01306                     continue;
01307                 }
01308 
01309                 renderQueueGroupObjects(pGroup);
01310             
01311                 // Fire queue ended event
01312                 if (fireRenderQueueEnded(qId))
01313                 {
01314                     // Someone requested we repeat this queue
01315                     repeatQueue = true;
01316                 }
01317                 else
01318                 {
01319                     repeatQueue = false;
01320                 }
01321             } while (repeatQueue);
01322 
01323         } // for each queue group
01324 
01325     }
01326     //-----------------------------------------------------------------------
01327     void SceneManager::renderAdditiveStencilShadowedQueueGroupObjects(RenderQueueGroup* pGroup)
01328     {
01329         RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator();
01330         LightList lightList;
01331 
01332         while (groupIt.hasMoreElements())
01333         {
01334             RenderPriorityGroup* pPriorityGrp = groupIt.getNext();
01335 
01336             // Sort the queue first
01337             pPriorityGrp->sort(mCameraInProgress);
01338 
01339             // Clear light list
01340             lightList.clear();
01341 
01342             // Render all the ambient passes first, no light iteration, no lights
01343             mIlluminationStage = IRS_AMBIENT;
01344             renderObjects(pPriorityGrp->_getSolidPasses(), false, &lightList);
01345             // Also render any objects which have receive shadows disabled
01346             renderObjects(pPriorityGrp->_getSolidPassesNoShadow(), true);
01347 
01348 
01349             // Now iterate per light
01350             mIlluminationStage = IRS_PER_LIGHT;
01351 
01352             // Iterate over lights, render all volumes to stencil
01353             LightList::const_iterator li, liend;
01354             liend = mLightsAffectingFrustum.end();
01355 
01356             for (li = mLightsAffectingFrustum.begin(); li != liend; ++li)
01357             {
01358                 Light* l = *li;
01359                 // Set light state
01360 
01361                 if (l->getCastShadows())
01362                 {
01363                     // Clear stencil
01364                     mDestRenderSystem->clearFrameBuffer(FBT_STENCIL);
01365                     renderShadowVolumesToStencil(l, mCameraInProgress);
01366                     // turn stencil check on
01367                     mDestRenderSystem->setStencilCheckEnabled(true);
01368                     // NB we render where the stencil is equal to zero to render lit areas
01369                     mDestRenderSystem->setStencilBufferParams(CMPF_EQUAL, 0);
01370                 }
01371 
01372                 // render lighting passes for this light
01373                 if (lightList.empty())
01374                     lightList.push_back(l);
01375                 else
01376                     lightList[0] = l;
01377                 renderObjects(pPriorityGrp->_getSolidPassesDiffuseSpecular(), false, &lightList);
01378 
01379                 // Reset stencil params
01380                 mDestRenderSystem->setStencilBufferParams();
01381                 mDestRenderSystem->setStencilCheckEnabled(false);
01382                 mDestRenderSystem->_setDepthBufferParams();
01383 
01384             }// for each light
01385 
01386 
01387             // Now render decal passes, no need to set lights as lighting will be disabled
01388             mIlluminationStage = IRS_DECAL;
01389             renderObjects(pPriorityGrp->_getSolidPassesDecal(), false);
01390 
01391 
01392         }// for each priority
01393 
01394         // reset lighting stage
01395         mIlluminationStage = IRS_NONE;
01396 
01397         // Iterate again - variable name changed to appease gcc.
01398         RenderQueueGroup::PriorityMapIterator groupIt2 = pGroup->getIterator();
01399         while (groupIt2.hasMoreElements())
01400         {
01401             RenderPriorityGroup* pPriorityGrp = groupIt2.getNext();
01402 
01403             // Do transparents
01404             renderObjects(pPriorityGrp->_getTransparentPasses(), true);
01405 
01406         }// for each priority
01407 
01408 
01409     }
01410     //-----------------------------------------------------------------------
01411     void SceneManager::renderModulativeStencilShadowedQueueGroupObjects(RenderQueueGroup* pGroup)
01412     {
01413         /* For each light, we need to render all the solids from each group, 
01414         then do the modulative shadows, then render the transparents from
01415         each group.
01416         Now, this means we are going to reorder things more, but that it required
01417         if the shadows are to look correct. The overall order is preserved anyway,
01418         it's just that all the transparents are at the end instead of them being
01419         interleaved as in the normal rendering loop. 
01420         */
01421         // Iterate through priorities
01422         RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator();
01423 
01424         while (groupIt.hasMoreElements())
01425         {
01426             RenderPriorityGroup* pPriorityGrp = groupIt.getNext();
01427 
01428             // Sort the queue first
01429             pPriorityGrp->sort(mCameraInProgress);
01430 
01431             // Do (shadowable) solids
01432             renderObjects(pPriorityGrp->_getSolidPasses(), true);
01433         }
01434 
01435 
01436         // Iterate over lights, render all volumes to stencil
01437         LightList::const_iterator li, liend;
01438         liend = mLightsAffectingFrustum.end();
01439 
01440         for (li = mLightsAffectingFrustum.begin(); li != liend; ++li)
01441         {
01442             Light* l = *li;
01443             if (l->getCastShadows())
01444             {
01445                 // Clear stencil
01446                 mDestRenderSystem->clearFrameBuffer(FBT_STENCIL);
01447                 renderShadowVolumesToStencil(l, mCameraInProgress);
01448                 // render full-screen shadow modulator for all lights
01449                 setPass(mShadowModulativePass);
01450                 // turn stencil check on
01451                 mDestRenderSystem->setStencilCheckEnabled(true);
01452                 // NB we render where the stencil is not equal to zero to render shadows, not lit areas
01453                 mDestRenderSystem->setStencilBufferParams(CMPF_NOT_EQUAL, 0);
01454                 renderSingleObject(mFullScreenQuad, mShadowModulativePass, false);
01455                 // Reset stencil params
01456                 mDestRenderSystem->setStencilBufferParams();
01457                 mDestRenderSystem->setStencilCheckEnabled(false);
01458                 mDestRenderSystem->_setDepthBufferParams();
01459             }
01460 
01461         }// for each light
01462 
01463         // Iterate again - variable name changed to appease gcc.
01464         RenderQueueGroup::PriorityMapIterator groupIt2 = pGroup->getIterator();
01465         while (groupIt2.hasMoreElements())
01466         {
01467             RenderPriorityGroup* pPriorityGrp = groupIt2.getNext();
01468 
01469             // Do non-shadowable solids
01470             renderObjects(pPriorityGrp->_getSolidPassesNoShadow(), true);
01471 
01472         }// for each priority
01473 
01474 
01475         // Iterate again - variable name changed to appease gcc.
01476         RenderQueueGroup::PriorityMapIterator groupIt3 = pGroup->getIterator();
01477         while (groupIt3.hasMoreElements())
01478         {
01479             RenderPriorityGroup* pPriorityGrp = groupIt3.getNext();
01480 
01481             // Do transparents
01482             renderObjects(pPriorityGrp->_getTransparentPasses(), true);
01483 
01484         }// for each priority
01485 
01486     }
01487     //-----------------------------------------------------------------------
01488     void SceneManager::renderTextureShadowCasterQueueGroupObjects(RenderQueueGroup* pGroup)
01489     {
01490         static LightList nullLightList;
01491         // This is like the basic group render, except we skip all transparents
01492         // and we also render any non-shadowed objects
01493         // Note that non-shadow casters will have already been eliminated during
01494         // _findVisibleObjects
01495 
01496         // Iterate through priorities
01497         RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator();
01498 
01499         // Override auto param ambient to force vertex programs and fixed function to 
01500         // use shadow colour
01501         mAutoParamDataSource.setAmbientLightColour(mShadowColour);
01502         mDestRenderSystem->setAmbientLight(mShadowColour.r, mShadowColour.g, mShadowColour.b);
01503 
01504         while (groupIt.hasMoreElements())
01505         {
01506             RenderPriorityGroup* pPriorityGrp = groupIt.getNext();
01507 
01508             // Sort the queue first
01509             pPriorityGrp->sort(mCameraInProgress);
01510 
01511             // Do solids, override light list incase any vertex programs use them
01512             renderObjects(pPriorityGrp->_getSolidPasses(), false, &nullLightList);
01513             renderObjects(pPriorityGrp->_getSolidPassesNoShadow(), false, &nullLightList);
01514 
01515         }// for each priority
01516         
01517         // reset ambient light
01518         mAutoParamDataSource.setAmbientLightColour(mAmbientLight);
01519         mDestRenderSystem->setAmbientLight(mAmbientLight.r, mAmbientLight.g, mAmbientLight.b);
01520     }
01521     //-----------------------------------------------------------------------
01522     void SceneManager::renderModulativeTextureShadowedQueueGroupObjects(RenderQueueGroup* pGroup)
01523     {
01524         /* For each light, we need to render all the solids from each group, 
01525         then do the modulative shadows, then render the transparents from
01526         each group.
01527         Now, this means we are going to reorder things more, but that it required
01528         if the shadows are to look correct. The overall order is preserved anyway,
01529         it's just that all the transparents are at the end instead of them being
01530         interleaved as in the normal rendering loop. 
01531         */
01532         // Iterate through priorities
01533         RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator();
01534 
01535         while (groupIt.hasMoreElements())
01536         {
01537             RenderPriorityGroup* pPriorityGrp = groupIt.getNext();
01538 
01539             // Sort the queue first
01540             pPriorityGrp->sort(mCameraInProgress);
01541 
01542             // Do solids
01543             renderObjects(pPriorityGrp->_getSolidPasses(), true);
01544             renderObjects(pPriorityGrp->_getSolidPassesNoShadow(), true);
01545         }
01546 
01547 
01548         // Iterate over lights, render received shadows
01549         // only perform this if we're in the 'normal' render stage, to avoid
01550         // doing it during the render to texture
01551         if (mIlluminationStage == IRS_NONE)
01552         {
01553             mIlluminationStage = IRS_RENDER_MODULATIVE_PASS;
01554 
01555             LightList::iterator i, iend;
01556             ShadowTextureList::iterator si, siend;
01557             iend = mLightsAffectingFrustum.end();
01558             siend = mShadowTextures.end();
01559             for (i = mLightsAffectingFrustum.begin(), si = mShadowTextures.begin();
01560                 i != iend && si != siend; ++i)
01561             {
01562                 Light* l = *i;
01563 
01564                 if (!l->getCastShadows())
01565                     continue;
01566 
01567                 mCurrentShadowTexture = *si;
01568                 // Hook up receiver texture
01569                 mShadowReceiverPass->getTextureUnitState(0)->setTextureName(
01570                     mCurrentShadowTexture->getName());
01571                 // Hook up projection frustum
01572                 mShadowReceiverPass->getTextureUnitState(0)->setProjectiveTexturing(
01573                     true, mCurrentShadowTexture->getViewport(0)->getCamera());
01574                 mAutoParamDataSource.setTextureProjector(
01575                     mCurrentShadowTexture->getViewport(0)->getCamera());
01576                 // if this light is a spotlight, we need to add the spot fader layer
01577                 if (l->getType() == Light::LT_SPOTLIGHT)
01578                 {
01579                     // Add spot fader if not present already
01580                     if (mShadowReceiverPass->getNumTextureUnitStates() == 1)
01581                     {
01582                         TextureUnitState* t = 
01583                             mShadowReceiverPass->createTextureUnitState("spot_shadow_fade.png");
01584                         t->setProjectiveTexturing(
01585                             true, mCurrentShadowTexture->getViewport(0)->getCamera());
01586                         t->setColourOperation(LBO_ADD);
01587                         t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
01588                     }
01589                     else
01590                     {
01591                         // Just set projector
01592                         TextureUnitState* t = 
01593                             mShadowReceiverPass->getTextureUnitState(1);
01594                         t->setProjectiveTexturing(
01595                             true, mCurrentShadowTexture->getViewport(0)->getCamera());
01596                     }
01597                 }
01598                 else if (mShadowReceiverPass->getNumTextureUnitStates() > 1)
01599                 {
01600                     // remove spot fader layer
01601                     mShadowReceiverPass->removeTextureUnitState(1);
01602 
01603                 }
01604                 mShadowReceiverPass->_load();
01605 
01606                 if (l->getCastShadows() && pGroup->getShadowsEnabled())
01607                 {
01608                     renderTextureShadowReceiverQueueGroupObjects(pGroup);
01609                 }
01610 
01611                 ++si;
01612 
01613             }// for each light
01614 
01615             mIlluminationStage = IRS_NONE;
01616 
01617         }
01618 
01619         // Iterate again - variable name changed to appease gcc.
01620         RenderQueueGroup::PriorityMapIterator groupIt3 = pGroup->getIterator();
01621         while (groupIt3.hasMoreElements())
01622         {
01623             RenderPriorityGroup* pPriorityGrp = groupIt3.getNext();
01624 
01625             // Do transparents
01626             renderObjects(pPriorityGrp->_getTransparentPasses(), true);
01627 
01628         }// for each priority
01629 
01630     }
01631     //-----------------------------------------------------------------------
01632     void SceneManager::renderTextureShadowReceiverQueueGroupObjects(RenderQueueGroup* pGroup)
01633     {
01634         static LightList nullLightList;
01635 
01636         // Iterate through priorities
01637         RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator();
01638 
01639         // Override auto param ambient to force vertex programs to go full-bright
01640         mAutoParamDataSource.setAmbientLightColour(ColourValue::White);
01641         mDestRenderSystem->setAmbientLight(1, 1, 1);
01642 
01643         while (groupIt.hasMoreElements())
01644         {
01645             RenderPriorityGroup* pPriorityGrp = groupIt.getNext();
01646 
01647             // Do solids, override light list incase any vertex programs use them
01648             renderObjects(pPriorityGrp->_getSolidPasses(), false, &nullLightList);
01649 
01650             // Don't render transparents or passes which have shadow receipt disabled
01651 
01652         }// for each priority
01653 
01654         // reset ambient
01655         mAutoParamDataSource.setAmbientLightColour(mAmbientLight);
01656         mDestRenderSystem->setAmbientLight(mAmbientLight.r, mAmbientLight.g, mAmbientLight.b);
01657 
01658     }
01659     //-----------------------------------------------------------------------
01660     bool SceneManager::validatePassForRendering(Pass* pass)
01661     {
01662         // Bypass if we're doing a texture shadow render and 
01663         // this pass is after the first (only 1 pass needed for shadow texture)
01664         if ((mIlluminationStage == IRS_RENDER_TO_TEXTURE ||
01665             mIlluminationStage == IRS_RENDER_MODULATIVE_PASS) && 
01666             pass->getIndex() > 0)
01667         {
01668             return false;
01669         }
01670 
01671         return true;
01672     }
01673     //-----------------------------------------------------------------------
01674     bool SceneManager::validateRenderableForRendering(Pass* pass, Renderable* rend)
01675     {
01676         // Skip this renderable if we're doing texture shadows, it casts shadows
01677         // and we're doing the render receivers pass
01678         if (mShadowTechnique == SHADOWTYPE_TEXTURE_MODULATIVE && 
01679             mIlluminationStage == IRS_RENDER_MODULATIVE_PASS && 
01680             rend->getCastsShadows())
01681         {
01682             return false;
01683         }
01684 
01685         return true;
01686 
01687     }
01688     //-----------------------------------------------------------------------
01689     void SceneManager::renderObjects(
01690         const RenderPriorityGroup::SolidRenderablePassMap& objs, bool doLightIteration, 
01691         const LightList* manualLightList)
01692     {
01693         // ----- SOLIDS LOOP -----
01694         RenderPriorityGroup::SolidRenderablePassMap::const_iterator ipass, ipassend;
01695         ipassend = objs.end();
01696         for (ipass = objs.begin(); ipass != ipassend; ++ipass)
01697         {
01698             // Fast bypass if this group is now empty
01699             if (ipass->second->empty()) continue;
01700 
01701             // Give SM a chance to eliminate this pass
01702             if (!validatePassForRendering(ipass->first))
01703                 continue;
01704 
01705             // For solids, we try to do each pass in turn
01706             Pass* usedPass = setPass(ipass->first);
01707             RenderPriorityGroup::RenderableList* rendList = ipass->second;
01708             RenderPriorityGroup::RenderableList::const_iterator irend, irendend;
01709             irendend = rendList->end();
01710             for (irend = rendList->begin(); irend != irendend; ++irend)
01711             {
01712                 // Give SM a chance to eliminate
01713                 if (!validateRenderableForRendering(ipass->first, *irend))
01714                     continue;
01715                 // Render a single object, this will set up auto params if required
01716                 renderSingleObject(*irend, usedPass, doLightIteration, manualLightList);
01717             }
01718         } 
01719     }
01720     //-----------------------------------------------------------------------
01721     void SceneManager::renderObjects(
01722         const RenderPriorityGroup::TransparentRenderablePassList& objs, bool doLightIteration,
01723         const LightList* manualLightList)
01724     {
01725         // ----- TRANSPARENT LOOP -----
01726         // This time we render by Z, not by pass
01727         // The mTransparentObjects set needs to be ordered first
01728         // Render each non-transparent entity in turn, grouped by material
01729         RenderPriorityGroup::TransparentRenderablePassList::const_iterator itrans, itransend;
01730 
01731         itransend = objs.end();
01732         for (itrans = objs.begin(); 
01733             itrans != itransend; ++itrans)
01734         {
01735             // For transparents, we have to accept that we can't sort entirely by pass
01736             setPass(itrans->pass);
01737             renderSingleObject(itrans->renderable, itrans->pass, doLightIteration, 
01738                 manualLightList);
01739         }
01740 
01741     }
01742     //-----------------------------------------------------------------------
01743     void SceneManager::renderQueueGroupObjects(RenderQueueGroup* pGroup)
01744     {
01745         if (pGroup->getShadowsEnabled() && 
01746             mShadowTechnique == SHADOWTYPE_STENCIL_ADDITIVE)
01747         {
01748             // Additive stencil shadows in use
01749             renderAdditiveStencilShadowedQueueGroupObjects(pGroup);
01750         }
01751         else if (pGroup->getShadowsEnabled() && 
01752             mShadowTechnique == SHADOWTYPE_STENCIL_MODULATIVE)
01753         {
01754             // Modulative stencil shadows in use
01755             renderModulativeStencilShadowedQueueGroupObjects(pGroup);
01756         }
01757         else if (mShadowTechnique == SHADOWTYPE_TEXTURE_MODULATIVE)
01758         {
01759             // Modulative texture shadows in use
01760             if (mIlluminationStage == IRS_RENDER_TO_TEXTURE)
01761             {
01762                 // Shadow caster pass
01763                 if (pGroup->getShadowsEnabled())
01764                     renderTextureShadowCasterQueueGroupObjects(pGroup);
01765             }
01766             else
01767             {
01768                 // Ordinary pass
01769                 renderModulativeTextureShadowedQueueGroupObjects(pGroup);
01770             }
01771         }
01772         else
01773         {
01774             // No shadows, ordinary pass
01775             renderBasicQueueGroupObjects(pGroup);
01776         }
01777 
01778 
01779     }
01780     //-----------------------------------------------------------------------
01781     void SceneManager::renderBasicQueueGroupObjects(RenderQueueGroup* pGroup)
01782     {
01783         // Basic render loop
01784         // Iterate through priorities
01785         RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator();
01786 
01787         while (groupIt.hasMoreElements())
01788         {
01789             RenderPriorityGroup* pPriorityGrp = groupIt.getNext();
01790 
01791             // Sort the queue first
01792             pPriorityGrp->sort(mCameraInProgress);
01793 
01794             // Do solids
01795             renderObjects(pPriorityGrp->_getSolidPasses(), true);
01796             // Do transparents
01797             renderObjects(pPriorityGrp->_getTransparentPasses(), true);
01798 
01799 
01800         }// for each priority
01801     }
01802     //-----------------------------------------------------------------------
01803     void SceneManager::renderSingleObject(Renderable* rend, Pass* pass, 
01804         bool doLightIteration, const LightList* manualLightList)
01805     {
01806         static Matrix4 xform[256];
01807         unsigned short numMatrices;
01808         static bool normalisedNormals = false;
01809         static SceneDetailLevel camDetailLevel = mCameraInProgress->getDetailLevel();
01810         static SceneDetailLevel lastDetailLevel = camDetailLevel;
01811         static RenderOperation ro;
01812         static LightList localLightList;
01813 
01814         if (pass->isProgrammable())
01815         {
01816             // Tell auto params object about the renderable change
01817             mAutoParamDataSource.setCurrentRenderable(rend);
01818             pass->_updateAutoParamsNoLights(mAutoParamDataSource);
01819         }
01820         
01821         // Set world transformation
01822         rend->getWorldTransforms(xform);
01823         numMatrices = rend->getNumWorldTransforms();
01824         if (numMatrices > 1)
01825         {
01826             mDestRenderSystem->_setWorldMatrices(xform, numMatrices);
01827         }
01828         else
01829         {
01830             mDestRenderSystem->_setWorldMatrix(*xform);
01831         }
01832 
01833         // Issue view / projection changes if any
01834         useRenderableViewProjMode(rend);
01835 
01836         // Reissue any texture gen settings which are dependent on view matrix
01837         Pass::TextureUnitStateIterator texIter =  pass->getTextureUnitStateIterator();
01838         size_t unit = 0;
01839         while(texIter.hasMoreElements())
01840         {
01841             TextureUnitState* pTex = texIter.getNext();
01842             if (pTex->hasViewRelativeTextureCoordinateGeneration())
01843             {
01844                 mDestRenderSystem->_setTextureUnitSettings(unit, *pTex);
01845             }
01846             ++unit;
01847         }
01848 
01849 
01850         // Sort out normalisation
01851         bool thisNormalise = rend->getNormaliseNormals();
01852         if (thisNormalise != normalisedNormals)
01853         {
01854             mDestRenderSystem->setNormaliseNormals(thisNormalise);
01855             normalisedNormals = thisNormalise;
01856         }
01857 
01858         // Set up the solid / wireframe override
01859         SceneDetailLevel reqDetail = rend->getRenderDetail();
01860         if (reqDetail != lastDetailLevel || reqDetail != camDetailLevel)
01861         {
01862             if (reqDetail > camDetailLevel)
01863             {
01864                 // only downgrade detail; if cam says wireframe we don't go up to solid
01865                 reqDetail = camDetailLevel;
01866             }
01867             mDestRenderSystem->_setRasterisationMode(reqDetail);
01868             lastDetailLevel = reqDetail;
01869 
01870         }
01871 
01872         mDestRenderSystem->setClipPlanes(rend->getClipPlanes());
01873 
01874         // Set up rendering operation
01875         rend->getRenderOperation(ro);
01876         ro.srcRenderable = rend;
01877 
01878         if (doLightIteration)
01879         {
01880             // Here's where we issue the rendering operation to the render system
01881             // Note that we may do this once per light, therefore it's in a loop
01882             // and the light parameters are updated once per traversal through the
01883             // loop
01884             const LightList& rendLightList = rend->getLights();
01885             bool iteratePerLight = pass->getRunOncePerLight();
01886             size_t numIterations = iteratePerLight ? rendLightList.size() : 1;
01887             const LightList* pLightListToUse;
01888             for (size_t i = 0; i < numIterations; ++i)
01889             {
01890                 // Determine light list to use
01891                 if (iteratePerLight)
01892                 {
01893                     // Change the only element of local light list to be
01894                     // the light at index i
01895                     localLightList.clear();
01896                     // Check whether we need to filter this one out
01897                     if (pass->getRunOnlyForOneLightType() && 
01898                         pass->getOnlyLightType() != rendLightList[i]->getType())
01899                     {
01900                         // Skip
01901                         continue;
01902                     }
01903 
01904                     localLightList.push_back(rendLightList[i]);
01905                     pLightListToUse = &localLightList;
01906                 }
01907                 else
01908                 {
01909                     // Use complete light list
01910                     pLightListToUse = &rendLightList;
01911                 }
01912 
01913                 // Do we need to update GPU program parameters?
01914                 if (pass->isProgrammable())
01915                 {
01916                     // Update any automatic gpu params for lights
01917                     // Other bits of information will have to be looked up
01918                     mAutoParamDataSource.setCurrentLightList(pLightListToUse);
01919                     pass->_updateAutoParamsLightsOnly(mAutoParamDataSource);
01920                     // NOTE: We MUST bind parameters AFTER updating the autos
01921                     // TEST
01922                     if (pass->hasVertexProgram())
01923                     {
01924                         mDestRenderSystem->bindGpuProgramParameters(GPT_VERTEX_PROGRAM, 
01925                             pass->getVertexProgramParameters());
01926                     }
01927                     if (pass->hasFragmentProgram())
01928                     {
01929                         mDestRenderSystem->bindGpuProgramParameters(GPT_FRAGMENT_PROGRAM, 
01930                             pass->getFragmentProgramParameters());
01931                     }
01932                 }
01933                 // Do we need to update light states? 
01934                 // Only do this if fixed-function vertex lighting applies
01935                 if (pass->getLightingEnabled() && !pass->hasVertexProgram())
01936                 {
01937                     mDestRenderSystem->_useLights(*pLightListToUse, pass->getMaxSimultaneousLights());
01938                 }
01939                 // issue the render op      
01940                 mDestRenderSystem->_render(ro);
01941             } // possibly iterate per light
01942         }
01943         else // no automatic light processing
01944         {
01945             // Do we need to update GPU program parameters?
01946             if (pass->isProgrammable())
01947             {
01948                 // Do we have a manual light list?
01949                 if (manualLightList)
01950                 {
01951                     // Update any automatic gpu params for lights
01952                     mAutoParamDataSource.setCurrentLightList(manualLightList);
01953                     pass->_updateAutoParamsLightsOnly(mAutoParamDataSource);
01954                 }
01955 
01956                 if (pass->hasVertexProgram())
01957                 {
01958                     mDestRenderSystem->bindGpuProgramParameters(GPT_VERTEX_PROGRAM, 
01959                         pass->getVertexProgramParameters());
01960                 }
01961                 if (pass->hasFragmentProgram())
01962                 {
01963                     mDestRenderSystem->bindGpuProgramParameters(GPT_FRAGMENT_PROGRAM, 
01964                         pass->getFragmentProgramParameters());
01965                 }
01966             }
01967 
01968             // Use manual lights if present, and not using vertex programs
01969             if (manualLightList && 
01970                 pass->getLightingEnabled() && !pass->hasVertexProgram())
01971             {
01972                 mDestRenderSystem->_useLights(*manualLightList, pass->getMaxSimultaneousLights());
01973             }
01974             // issue the render op      
01975             mDestRenderSystem->_render(ro);
01976         }
01977     }
01978     //-----------------------------------------------------------------------
01979     void SceneManager::setAmbientLight(const ColourValue& colour)
01980     {
01981         mAmbientLight = colour;
01982         mDestRenderSystem->setAmbientLight(colour.r, colour.g, colour.b);
01983     }
01984     //-----------------------------------------------------------------------
01985     const ColourValue& SceneManager::getAmbientLight(void) const
01986     {
01987         return mAmbientLight;
01988     }
01989     //-----------------------------------------------------------------------
01990     ViewPoint SceneManager::getSuggestedViewpoint(bool random)
01991     {
01992         // By default return the origin
01993         ViewPoint vp;
01994         vp.position = Vector3::ZERO;
01995         vp.orientation = Quaternion::IDENTITY;
01996         return vp;
01997     }
01998     //-----------------------------------------------------------------------
01999     void SceneManager::setFog(FogMode mode, const ColourValue& colour, Real density, Real start, Real end)
02000     {
02001         mFogMode = mode;
02002         mFogColour = colour;
02003         mFogStart = start;
02004         mFogEnd = end;
02005         mFogDensity = density;
02006     }
02007     //-----------------------------------------------------------------------
02008     FogMode SceneManager::getFogMode(void) const
02009     {
02010         return mFogMode;
02011     }
02012     //-----------------------------------------------------------------------
02013     const ColourValue& SceneManager::getFogColour(void) const
02014     {
02015         return mFogColour;
02016     }
02017     //-----------------------------------------------------------------------
02018     Real SceneManager::getFogStart(void) const
02019     {
02020         return mFogStart;
02021     }
02022     //-----------------------------------------------------------------------
02023     Real SceneManager::getFogEnd(void) const
02024     {
02025         return mFogEnd;
02026     }
02027     //-----------------------------------------------------------------------
02028     Real SceneManager::getFogDensity(void) const
02029     {
02030         return mFogDensity;
02031     }
02032     //-----------------------------------------------------------------------
02033     BillboardSet* SceneManager::createBillboardSet(const String& name, unsigned int poolSize)
02034     {
02035         BillboardSet* set = new BillboardSet( name, poolSize );
02036         mBillboardSets[name] = set;//.insert(BillboardSetList::value_type(name, set));
02037 
02038         return set;
02039     }
02040     //-----------------------------------------------------------------------
02041     BillboardSet* SceneManager::getBillboardSet(const String& name)
02042     {
02043         BillboardSetList::iterator i = mBillboardSets.find(name);
02044         if (i == mBillboardSets.end())
02045         {
02046             return 0;
02047         }
02048         else
02049         {
02050             return i->second;
02051         }
02052     }
02053     //-----------------------------------------------------------------------
02054     void SceneManager::removeBillboardSet(BillboardSet* set)
02055     {
02056         // Find in list
02057         BillboardSetList::iterator i = mBillboardSets.begin();
02058         for (; i != mBillboardSets.end(); ++i)
02059         {
02060             if (i->second == set)
02061             {
02062                 mBillboardSets.erase(i);
02063                 delete set;
02064                 break;
02065             }
02066         }
02067 
02068     }
02069     //-----------------------------------------------------------------------
02070     void SceneManager::removeBillboardSet(const String& name)
02071     {
02072         // Find in list
02073         BillboardSetList::iterator i = mBillboardSets.find(name);
02074         if (i != mBillboardSets.end())
02075         {
02076             delete i->second;
02077             mBillboardSets.erase(i);
02078         }
02079     }
02080     //-----------------------------------------------------------------------
02081     void SceneManager::setDisplaySceneNodes(bool display)
02082     {
02083         mDisplayNodes = display;
02084     }
02085     //-----------------------------------------------------------------------
02086     Animation* SceneManager::createAnimation(const String& name, Real length)
02087     {
02088         Animation* pAnim = new Animation(name, length);
02089         mAnimationsList[name] = pAnim;
02090         return pAnim;
02091     }
02092     //-----------------------------------------------------------------------
02093     Animation* SceneManager::getAnimation(const String& name) const
02094     {
02095         AnimationList::const_iterator i = mAnimationsList.find(name);
02096         if (i == mAnimationsList.end())
02097         {
02098             Except(Exception::ERR_ITEM_NOT_FOUND, 
02099                 "Cannot find animation with name " + name, 
02100                 "SceneManager::getAnimation");
02101         }
02102         return i->second;
02103     }
02104     //-----------------------------------------------------------------------
02105     void SceneManager::destroyAnimation(const String& name)
02106     {
02107         // Also destroy any animation states referencing this animation
02108         AnimationStateSet::iterator si, siend;
02109         siend = mAnimationStates.end();
02110         for (si = mAnimationStates.begin(); si != siend; )
02111         {
02112             if (si->second.getAnimationName() == name)
02113             {
02114                 // erase, post increment to avoid the invalidated iterator
02115                 mAnimationStates.erase(si++);
02116             }
02117             else
02118             {
02119                 ++si;
02120             }
02121         }
02122 
02123         AnimationList::iterator i = mAnimationsList.find(name);
02124         if (i == mAnimationsList.end())
02125         {
02126             Except(Exception::ERR_ITEM_NOT_FOUND, 
02127                 "Cannot find animation with name " + name, 
02128                 "SceneManager::getAnimation");
02129         }
02130 
02131         // Free memory
02132         delete i->second;
02133 
02134         mAnimationsList.erase(i);
02135 
02136 
02137     }
02138     //-----------------------------------------------------------------------
02139     void SceneManager::destroyAllAnimations(void)
02140     {
02141         // Destroy all states too, since they cannot reference destroyed animations
02142         destroyAllAnimationStates();
02143 
02144         AnimationList::iterator i;
02145         for (i = mAnimationsList.begin(); i != mAnimationsList.end(); ++i)
02146         {
02147             // destroy
02148             delete i->second;
02149         }
02150         mAnimationsList.clear();
02151     }
02152     //-----------------------------------------------------------------------
02153     AnimationState* SceneManager::createAnimationState(const String& animName)
02154     {
02155         if (mAnimationStates.find(animName) != mAnimationStates.end())
02156         {
02157             Except(Exception::ERR_DUPLICATE_ITEM, 
02158                 "Cannot create, AnimationState already exists: "+animName, 
02159                 "SceneManager::createAnimationState");
02160         }
02161 
02162         // Get animation, this will throw an exception if not found
02163         Animation* anim = getAnimation(animName);
02164 
02165         // Create new state
02166         AnimationState newState(animName, 0, anim->getLength());
02167 
02168         // Record it
02169         std::pair<AnimationStateSet::iterator, bool> retPair = 
02170             mAnimationStates.insert(AnimationStateSet::value_type(animName, newState));
02171 
02172         // Check boolean return
02173         if (retPair.second)
02174         {
02175             // insert was OK
02176             // Get pointer from iterator in pair
02177             return &(retPair.first->second);
02178         }
02179         else
02180         {
02181             // Problem
02182             // Not because of duplicate item, that's checked for above
02183             Except(Exception::ERR_INTERNAL_ERROR, "Unexpected error creating new animation state.",
02184                 "SceneManager::createAnimationState");
02185         }
02186 
02187 
02188     }
02189     //-----------------------------------------------------------------------
02190     AnimationState* SceneManager::getAnimationState(const String& animName) 
02191     {
02192         AnimationStateSet::iterator i = mAnimationStates.find(animName);
02193 
02194         if (i == mAnimationStates.end())
02195         {
02196             Except(Exception::ERR_ITEM_NOT_FOUND, 
02197                 "Cannot locate animation state for animation " + animName,
02198                 "SceneManager::getAnimationState");
02199         }
02200 
02201         return &(i->second);
02202 
02203     }
02204     //-----------------------------------------------------------------------
02205     void SceneManager::destroyAnimationState(const String& name)
02206     {
02207         AnimationStateSet::iterator i = mAnimationStates.find(name);
02208 
02209         if (i == mAnimationStates.end())
02210         {
02211             Except(Exception::ERR_ITEM_NOT_FOUND, 
02212                 "Cannot locate animation state for animation " + name,
02213                 "SceneManager::destroyAnimationState");
02214         }
02215 
02216         mAnimationStates.erase(i);
02217 
02218 
02219     }
02220     //-----------------------------------------------------------------------
02221     void SceneManager::destroyAllAnimationStates(void)
02222     {
02223         mAnimationStates.clear();
02224     }
02225     //-----------------------------------------------------------------------
02226     void SceneManager::_applySceneAnimations(void)
02227     {
02228         AnimationStateSet::const_iterator i, iend;
02229 
02230         i = mAnimationStates.begin();
02231         iend = mAnimationStates.end();
02232     
02233         for (;i != iend; ++i)
02234         {
02235             if (i->second.getEnabled())
02236             {
02237                 Animation* anim = getAnimation(i->second.getAnimationName());
02238 
02239                 // Reset any nodes involved
02240                 // NB this excludes blended animations
02241                 const Animation::TrackList& trackList = anim->_getTrackList();
02242                 Animation::TrackList::const_iterator ti, tend;
02243                 ti = trackList.begin();
02244                 tend = trackList.end();
02245                 for (;ti != tend; ++ti)
02246                 {
02247                     Node* nd = ti->second->getAssociatedNode();
02248                     nd->resetToInitialState();
02249                 }
02250 
02251 
02252                 // Apply the animation
02253                 anim->apply(i->second.getTimePosition(), i->second.getWeight());
02254             }
02255         }
02256 
02257 
02258     }
02259     //---------------------------------------------------------------------
02260     void SceneManager::manualRender(RenderOperation* rend, 
02261         Pass* pass, Viewport* vp, const Matrix4& worldMatrix, 
02262         const Matrix4& viewMatrix, const Matrix4& projMatrix, 
02263         bool doBeginEndFrame) 
02264     {
02265         mDestRenderSystem->_setViewport(vp);
02266         mDestRenderSystem->_setWorldMatrix(worldMatrix);
02267         mDestRenderSystem->_setViewMatrix(viewMatrix);
02268         mDestRenderSystem->_setProjectionMatrix(projMatrix);
02269 
02270         if (doBeginEndFrame)
02271             mDestRenderSystem->_beginFrame();
02272 
02273         setPass(pass);
02274         mDestRenderSystem->_render(*rend);
02275 
02276         if (doBeginEndFrame)
02277             mDestRenderSystem->_endFrame();
02278         
02279     }
02280     //---------------------------------------------------------------------
02281     Overlay* SceneManager::createOverlay(const String& name, ushort zorder)
02282     {
02283         /*
02284         // check not existing
02285         OverlayList::iterator i = mOverlays.find(name);
02286         if (i != mOverlays.end())
02287         {
02288             Except(Exception::ERR_DUPLICATE_ITEM, 
02289                 "An overlay named " + name + " already exists.",
02290                 "SceneManager::createOverlay");
02291         }
02292         Overlay *newOverlay = new Overlay(name, zorder);
02293 
02294         mOverlays.insert(OverlayList::value_type(name, newOverlay));
02295         return newOverlay;
02296         */
02297 
02298         Overlay* newOverlay = (Overlay*)OverlayManager::getSingleton().create(name);
02299         newOverlay->setZOrder(zorder);
02300         return newOverlay;
02301 
02302 
02303 
02304     }
02305     //---------------------------------------------------------------------
02306     Overlay* SceneManager::getOverlay(const String& name)
02307     {
02308         /*
02309         OverlayList::iterator i = mOverlays.find(name);
02310         if (i == mOverlays.end())
02311         {
02312             Except(Exception::ERR_ITEM_NOT_FOUND, 
02313                 "An overlay named " + name + " cannot be found.",
02314                 "SceneManager::getOverlay");
02315         }
02316 
02317         return i->second;
02318         */
02319         Overlay* ret = (Overlay*)OverlayManager::getSingleton().getByName(name);
02320         if (!ret)
02321         {
02322             Except(Exception::ERR_ITEM_NOT_FOUND, 
02323                 "An overlay named " + name + " cannot be found.",
02324                 "SceneManager::getOverlay");
02325         }
02326 
02327         return ret;
02328 
02329     }
02330     //---------------------------------------------------------------------
02331     void SceneManager::destroyOverlay(const String& name)
02332     {
02333         /*
02334         OverlayList::iterator i = mOverlays.find(name);
02335         if (i == mOverlays.end())
02336         {
02337             Except(Exception::ERR_ITEM_NOT_FOUND, 
02338                 "An overlay named " + name + " cannot be found.",
02339                 "SceneManager::destroyOverlay");
02340         }
02341 
02342         delete i->second;
02343         mOverlays.erase(i);
02344         */
02345         Overlay* pOver = (Overlay*)OverlayManager::getSingleton().getByName(name);
02346         if (!pOver)
02347         {
02348             Except(Exception::ERR_ITEM_NOT_FOUND, 
02349                 "An overlay named " + name + " cannot be found.",
02350                 "SceneManager::destroyOverlay");
02351         }
02352         OverlayManager::getSingleton().unload(pOver);
02353         delete pOver;
02354 
02355     }
02356     //---------------------------------------------------------------------
02357     void SceneManager::destroyAllOverlays(void)
02358     {
02359         /*
02360         OverlayList::iterator i, iend;
02361         iend = mOverlays.end();
02362         for (i = mOverlays.begin(); i != iend; ++i)
02363         {
02364             delete i->second;
02365         }
02366         mOverlays.clear();
02367         */
02368         OverlayManager::getSingleton().unloadAndDestroyAll();
02369 
02370 
02371     }
02372     //---------------------------------------------------------------------
02373     void SceneManager::useRenderableViewProjMode(Renderable* pRend)
02374     {
02375         // Check view matrix
02376         static bool lastViewWasIdentity = false;
02377         bool useIdentityView = pRend->useIdentityView();
02378         if (useIdentityView && (mCamChanged || !lastViewWasIdentity))
02379         {
02380             // Using identity view now, change it
02381             mDestRenderSystem->_setViewMatrix(Matrix4::IDENTITY);
02382             lastViewWasIdentity = true;
02383         }
02384         else if (!useIdentityView && (mCamChanged || lastViewWasIdentity))
02385         {
02386             // Coming back to normal from identity view
02387             mDestRenderSystem->_setViewMatrix(mCameraInProgress->getViewMatrix());
02388             lastViewWasIdentity = false;
02389         }
02390         
02391         static bool lastProjWasIdentity = false;
02392         bool useIdentityProj = pRend->useIdentityProjection();
02393 
02394         if (useIdentityProj && (mCamChanged || !lastProjWasIdentity))
02395         {
02396             mDestRenderSystem->_setProjectionMatrix(Matrix4::IDENTITY);
02397 
02398             lastProjWasIdentity = true;
02399         }
02400         else if (!useIdentityProj && (mCamChanged || lastProjWasIdentity))
02401         {
02402             // Coming back from flat projection
02403             mDestRenderSystem->_setProjectionMatrix(mCameraInProgress->getProjectionMatrix());
02404             lastProjWasIdentity = false;
02405         }
02406 
02407         mCamChanged = false;
02408 
02409     }
02410 
02411     //---------------------------------------------------------------------
02412     void SceneManager::_queueSkiesForRendering(Camera* cam)
02413     {
02414         // Update nodes
02415         // Translate the box by the camera position (constant distance)
02416         if (mSkyPlaneNode)
02417         {
02418             // The plane position relative to the camera has already been set up
02419             mSkyPlaneNode->setPosition(cam->getDerivedPosition());
02420         }
02421 
02422         if (mSkyBoxNode)
02423         {
02424             mSkyBoxNode->setPosition(cam->getDerivedPosition());
02425         }
02426 
02427         if (mSkyDomeNode)
02428         {
02429             mSkyDomeNode->setPosition(cam->getDerivedPosition());
02430         }
02431 
02432         RenderQueueGroupID qid;
02433         if (mSkyPlaneEnabled)
02434         {
02435             qid = mSkyPlaneDrawFirst? 
02436                         RENDER_QUEUE_SKIES_EARLY : RENDER_QUEUE_SKIES_LATE;
02437             getRenderQueue()->addRenderable(mSkyPlaneEntity->getSubEntity(0), qid, RENDERABLE_DEFAULT_PRIORITY);
02438         }
02439 
02440         uint plane;
02441         if (mSkyBoxEnabled)
02442         {
02443             qid = mSkyBoxDrawFirst? 
02444                         RENDER_QUEUE_SKIES_EARLY : RENDER_QUEUE_SKIES_LATE;
02445 
02446             for (plane = 0; plane < 6; ++plane)
02447             {
02448                 getRenderQueue()->addRenderable(
02449                     mSkyBoxEntity[plane]->getSubEntity(0), qid, RENDERABLE_DEFAULT_PRIORITY);
02450             }
02451         }
02452 
02453         if (mSkyDomeEnabled)
02454         {
02455             qid = mSkyDomeDrawFirst? 
02456                         RENDER_QUEUE_SKIES_EARLY : RENDER_QUEUE_SKIES_LATE;
02457 
02458             for (plane = 0; plane < 5; ++plane)
02459             {
02460                 getRenderQueue()->addRenderable(
02461                     mSkyDomeEntity[plane]->getSubEntity(0), qid, RENDERABLE_DEFAULT_PRIORITY);
02462             }
02463         }
02464     }
02465     //---------------------------------------------------------------------
02466     void SceneManager::addRenderQueueListener(RenderQueueListener* newListener)
02467     {
02468         mRenderQueueListeners.push_back(newListener);
02469     }
02470     //---------------------------------------------------------------------
02471     void SceneManager::removeRenderQueueListener(RenderQueueListener* delListener)
02472     {
02473         RenderQueueListenerList::iterator i, iend;
02474         iend = mRenderQueueListeners.end();
02475         for (i = mRenderQueueListeners.begin(); i != iend; ++i)
02476         {
02477             if (*i == delListener)
02478             {
02479                 mRenderQueueListeners.erase(i);
02480                 break;
02481             }
02482         }
02483 
02484     }
02485     //---------------------------------------------------------------------
02486     bool SceneManager::fireRenderQueueStarted(RenderQueueGroupID id)
02487     {
02488         RenderQueueListenerList::iterator i, iend;
02489         bool skip = false;
02490 
02491         iend = mRenderQueueListeners.end();
02492         for (i = mRenderQueueListeners.begin(); i != iend; ++i)
02493         {
02494             (*i)->renderQueueStarted(id, skip);
02495         }
02496         return skip;
02497     }
02498     //---------------------------------------------------------------------
02499     bool SceneManager::fireRenderQueueEnded(RenderQueueGroupID id)
02500     {
02501         RenderQueueListenerList::iterator i, iend;
02502         bool repeat = false;
02503 
02504         iend = mRenderQueueListeners.end();
02505         for (i = mRenderQueueListeners.begin(); i != iend; ++i)
02506         {
02507             (*i)->renderQueueEnded(id, repeat);
02508         }
02509         return repeat;
02510     }
02511     //---------------------------------------------------------------------
02512     void SceneManager::setViewport(Viewport* vp)
02513     {
02514         mCurrentViewport = vp;
02515         // Set viewport in render system
02516         mDestRenderSystem->_setViewport(vp);
02517     }
02518     //---------------------------------------------------------------------
02519     void SceneManager::showBoundingBoxes(bool bShow) 
02520     {
02521         mShowBoundingBoxes = bShow;
02522     }
02523     //---------------------------------------------------------------------
02524     bool SceneManager::getShowBoundingBoxes() const
02525     {
02526         return mShowBoundingBoxes;
02527     }
02528     //---------------------------------------------------------------------
02529     void SceneManager::_notifyAutotrackingSceneNode(SceneNode* node, bool autoTrack)
02530     {
02531         if (autoTrack)
02532         {
02533             mAutoTrackingSceneNodes.insert(node);
02534         }
02535         else
02536         {
02537             mAutoTrackingSceneNodes.erase(node);
02538         }
02539     }
02540     //---------------------------------------------------------------------
02541     void SceneManager::setShadowTechnique(ShadowTechnique technique)
02542     {
02543         mShadowTechnique = technique;
02544         if (technique == SHADOWTYPE_STENCIL_ADDITIVE || 
02545             technique == SHADOWTYPE_STENCIL_MODULATIVE)
02546         {
02547             // Firstly check that we  have a stencil
02548             // Otherwise forget it
02549             if (!mDestRenderSystem->getCapabilities()->hasCapability(RSC_HWSTENCIL))
02550             {
02551                 LogManager::getSingleton().logMessage(
02552                     "WARNING: Stencil shadows were requested, but this device does not "
02553                     "have a hardware stencil. Shadows disabled.");
02554                 mShadowTechnique = SHADOWTYPE_NONE;
02555             }
02556             else if (mShadowIndexBuffer.isNull())
02557             {
02558                 // Create an estimated sized shadow index buffer
02559                 mShadowIndexBuffer = HardwareBufferManager::getSingleton().
02560                     createIndexBuffer(HardwareIndexBuffer::IT_16BIT, 
02561                         mShadowIndexBufferSize, 
02562                         HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, 
02563                         false);
02564                 // tell all meshes to prepare shadow volumes
02565                 MeshManager::getSingleton().setPrepareAllMeshesForShadowVolumes(true);
02566             }
02567         }
02568 
02569         if (mShadowTechnique == SHADOWTYPE_STENCIL_ADDITIVE)
02570         {
02571             // Additive stencil, we need to split everything by illumination stage
02572             getRenderQueue()->setSplitPassesByLightingType(true);
02573         }
02574         else
02575         {
02576             getRenderQueue()->setSplitPassesByLightingType(false);
02577         }
02578 
02579         if (mShadowTechnique != SHADOWTYPE_NONE)
02580         {
02581             // Tell render queue to split off non-shadowable materials
02582             getRenderQueue()->setSplitNoShadowPasses(true);
02583         }
02584         else
02585         {
02586             getRenderQueue()->setSplitNoShadowPasses(false);
02587         }
02588 
02589         if (mShadowTechnique == SHADOWTYPE_TEXTURE_MODULATIVE 
02590             /* || mShadowTechnique == SHADOWTYPE_TEXTURE_SHADOWMAP */)
02591         {
02592             createShadowTextures(mShadowTextureSize, mShadowTextureCount);
02593         }
02594 
02595     }
02596     //---------------------------------------------------------------------
02597     void SceneManager::findLightsAffectingFrustum(const Camera* camera)
02598     {
02599         // Basic iteration for this SM
02600         mLightsAffectingFrustum.clear();
02601         SceneLightList::iterator i, iend;
02602         iend = mLights.end();
02603         Sphere sphere;
02604         for (i = mLights.begin(); i != iend; ++i)
02605         {
02606             Light* l = i->second;
02607             if (l->getType() == Light::LT_DIRECTIONAL)
02608             {
02609                 // Always visible
02610                 mLightsAffectingFrustum.push_back(l);
02611             }
02612             else
02613             {
02614                 // NB treating spotlight as point for simplicity
02615                 // Just see if the lights attenuation range is within the frustum
02616                 sphere.setCenter(l->getDerivedPosition());
02617                 sphere.setRadius(l->getAttenuationRange());
02618                 if (camera->isVisible(sphere))
02619                 {
02620                     mLightsAffectingFrustum.push_back(l);
02621                 }
02622                 
02623             }
02624         }
02625 
02626     }
02627     //---------------------------------------------------------------------
02628     bool SceneManager::ShadowCasterSceneQueryListener::queryResult(
02629         MovableObject* object)
02630     {
02631         if (object->getCastShadows() && object->isVisible())
02632         {
02633             if (mFarDistSquared)
02634             {
02635                 // Check object is within the shadow far distance
02636                 Vector3 toObj = object->getParentNode()->_getDerivedPosition() 
02637                     - mCamera->getDerivedPosition();
02638                 Real radius = object->getWorldBoundingSphere().getRadius();
02639                 Real dist =  toObj.squaredLength();               
02640                 if (dist - (radius * radius) > mFarDistSquared)
02641                 {
02642                     // skip, beyond max range
02643                     return true;
02644                 }
02645             }
02646 
02647             // If the object is in the frustum, we can always see the shadow
02648             if (mCamera->isVisible(object->getWorldBoundingBox()))
02649             {
02650                 mCasterList->push_back(object);
02651                 return true;
02652             }
02653 
02654             // Otherwise, object can only be casting a shadow into our view if
02655             // the light is outside the frustum (or it's a directional light, 
02656             // which are always outside), and the object is intersecting
02657             // on of the volumes formed between the edges of the frustum and the
02658             // light
02659             if (!mIsLightInFrustum || mLight->getType() == Light::LT_DIRECTIONAL)
02660             {
02661                 // Iterate over volumes
02662                 PlaneBoundedVolumeList::const_iterator i, iend;
02663                 iend = mLightClipVolumeList->end();
02664                 for (i = mLightClipVolumeList->begin(); i != iend; ++i)
02665                 {
02666                     if (i->intersects(object->getWorldBoundingBox()))
02667                     {
02668                         mCasterList->push_back(object);
02669                         return true;
02670                     }
02671 
02672                 }
02673 
02674             }
02675         }
02676         return true;
02677     }
02678     //---------------------------------------------------------------------
02679     bool SceneManager::ShadowCasterSceneQueryListener::queryResult(
02680         SceneQuery::WorldFragment* fragment)
02681     {
02682         // don't deal with world geometry
02683         return true;
02684     }
02685     //---------------------------------------------------------------------
02686     const SceneManager::ShadowCasterList& SceneManager::findShadowCastersForLight(
02687         const Light* light, const Camera* camera)
02688     {
02689         mShadowCasterList.clear();
02690 
02691         if (light->getType() == Light::LT_DIRECTIONAL)
02692         {
02693             // Basic AABB query encompassing the frustum and the extrusion of it
02694             AxisAlignedBox aabb;
02695             const Vector3* corners = camera->getWorldSpaceCorners();
02696             Vector3 min, max;
02697             Vector3 extrude = light->getDirection() * -mShadowDirLightExtrudeDist;
02698             // do first corner
02699             min = max = corners[0];
02700             min.makeFloor(corners[0] + extrude);
02701             max.makeCeil(corners[0] + extrude);
02702             for (size_t c = 1; c < 8; ++c)
02703             {
02704                 min.makeFloor(corners[c]);
02705                 max.makeCeil(corners[c]);
02706                 min.makeFloor(corners[c] + extrude);
02707                 max.makeCeil(corners[c] + extrude);
02708             }
02709             aabb.setExtents(min, max);
02710 
02711             if (!mShadowCasterAABBQuery)
02712                 mShadowCasterAABBQuery = createAABBQuery(aabb);
02713             else
02714                 mShadowCasterAABBQuery->setBox(aabb);
02715             // Execute, use callback
02716             mShadowCasterQueryListener.prepare(false, 
02717                 &(light->_getFrustumClipVolumes(camera)), 
02718                 light, camera, &mShadowCasterList, mShadowFarDistSquared);
02719             mShadowCasterAABBQuery->execute(&mShadowCasterQueryListener);
02720 
02721 
02722         }
02723         else
02724         {
02725             Sphere s(light->getPosition(), light->getAttenuationRange());
02726             // eliminate early if camera cannot see light sphere
02727             if (camera->isVisible(s))
02728             {
02729                 if (!mShadowCasterSphereQuery)
02730                     mShadowCasterSphereQuery = createSphereQuery(s);
02731                 else
02732                     mShadowCasterSphereQuery->setSphere(s);
02733 
02734                 // Determine if light is inside or outside the frustum
02735                 bool lightInFrustum = camera->isVisible(light->getDerivedPosition());
02736                 const PlaneBoundedVolumeList* volList = 0;
02737                 if (!lightInFrustum)
02738                 {
02739                     // Only worth building an external volume list if
02740                     // light is outside the frustum
02741                     volList = &(light->_getFrustumClipVolumes(camera));
02742                 }
02743 
02744                 // Execute, use callback
02745                 mShadowCasterQueryListener.prepare(lightInFrustum, 
02746                     volList, light, camera, &mShadowCasterList, mShadowFarDistSquared);
02747                 mShadowCasterSphereQuery->execute(&mShadowCasterQueryListener);
02748 
02749             }
02750 
02751         }
02752 
02753 
02754         return mShadowCasterList;
02755     }
02756     //---------------------------------------------------------------------
02757     void SceneManager::initShadowVolumeMaterials(void)
02758     {
02759         bool compileStencilDebugPass = false;
02760         bool compileStencilPass = false;
02761 
02762         Material* matDebug = static_cast<Material*>(
02763             MaterialManager::getSingleton().getByName("Ogre/Debug/ShadowVolumes"));
02764         if (!matDebug)
02765         {
02766             // Create
02767             matDebug = static_cast<Material*>(
02768                 MaterialManager::getSingleton().create("Ogre/Debug/ShadowVolumes"));
02769             mShadowDebugPass = matDebug->getTechnique(0)->getPass(0);
02770             mShadowDebugPass->setSceneBlending(SBT_ADD); 
02771             mShadowDebugPass->setLightingEnabled(false);
02772             mShadowDebugPass->setDepthWriteEnabled(false);
02773             TextureUnitState* t = mShadowDebugPass->createTextureUnitState();
02774             t->setColourOperationEx(LBX_MODULATE, LBS_MANUAL, LBS_CURRENT, 
02775                 ColourValue(0.7, 0.0, 0.2));
02776             mShadowDebugPass->setCullingMode(CULL_NONE);
02777             compileStencilDebugPass = true;
02778 
02779         }
02780 
02781         Material* matStencil = static_cast<Material*>(
02782             MaterialManager::getSingleton().getByName("Ogre/StencilShadowVolumes"));
02783         if (!matStencil)
02784         {
02785             // Init
02786             matStencil = static_cast<Material*>(
02787                 MaterialManager::getSingleton().create("Ogre/StencilShadowVolumes"));
02788             mShadowStencilPass = matStencil->getTechnique(0)->getPass(0);
02789             compileStencilPass = true;
02790             // Nothing else, we don't use this like a 'real' pass anyway,
02791             // it's more of a placeholder
02792         }
02793 
02794 
02795 
02796         if (mDestRenderSystem->getCapabilities()->hasCapability(RSC_VERTEX_PROGRAM))
02797         {
02798             ShadowVolumeExtrudeProgram::initialise();
02799 
02800             
02801             // Enable the (infinite) point light extruder for now, just to get some params
02802             mShadowDebugPass->setVertexProgram(
02803                 ShadowVolumeExtrudeProgram::programNames[ShadowVolumeExtrudeProgram::POINT_LIGHT]);
02804             mInfiniteExtrusionParams = 
02805                 mShadowDebugPass->getVertexProgramParameters();
02806             mInfiniteExtrusionParams->setAutoConstant(0, 
02807                 GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
02808             mInfiniteExtrusionParams->setAutoConstant(4, 
02809                 GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE);
02810 
02811             // Enable the finite point light extruder for now, just to get some params
02812             mShadowStencilPass->setVertexProgram(
02813                 ShadowVolumeExtrudeProgram::programNames[ShadowVolumeExtrudeProgram::POINT_LIGHT_FINITE]);
02814             mFiniteExtrusionParams = 
02815                 mShadowStencilPass->getVertexProgramParameters();
02816             mFiniteExtrusionParams->setAutoConstant(0, 
02817                 GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
02818             mFiniteExtrusionParams->setAutoConstant(4, 
02819                 GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE);
02820             // Note extra parameter
02821             mFiniteExtrusionParams->setAutoConstant(5, 
02822                 GpuProgramParameters::ACT_SHADOW_EXTRUSION_DISTANCE);
02823 
02824         }
02825 
02826 
02827         if (compileStencilDebugPass)
02828         {
02829             matDebug->compile();
02830         }
02831 
02832         if (compileStencilPass)
02833         {
02834             matStencil->compile();
02835         }
02836 
02837 
02838 
02839         Material* matModStencil = static_cast<Material*>(
02840             MaterialManager::getSingleton().getByName("Ogre/StencilShadowModulationPass"));
02841         if (!matModStencil)
02842         {
02843             // Init
02844             matModStencil = static_cast<Material*>(
02845                 MaterialManager::getSingleton().create("Ogre/StencilShadowModulationPass"));
02846             mShadowModulativePass = matModStencil->getTechnique(0)->getPass(0);
02847             mShadowModulativePass->setSceneBlending(SBF_DEST_COLOUR, SBF_ZERO); 
02848             mShadowModulativePass->setLightingEnabled(false);
02849             mShadowModulativePass->setDepthWriteEnabled(false);
02850             mShadowModulativePass->setDepthCheckEnabled(false);
02851             TextureUnitState* t = mShadowModulativePass->createTextureUnitState();
02852             t->setColourOperationEx(LBX_MODULATE, LBS_MANUAL, LBS_CURRENT, 
02853                 mShadowColour);
02854 
02855         }
02856 
02857         // Also init full screen quad while we're at it
02858         if (!mFullScreenQuad)
02859         {
02860             mFullScreenQuad = new Rectangle2D();
02861             mFullScreenQuad->setCorners(-1,1,1,-1);
02862         }
02863 
02864         // Also init shadow caster material for texture shadows
02865         Material* matPlainBlack = static_cast<Material*>(
02866             MaterialManager::getSingleton().getByName("Ogre/TextureShadowCaster"));
02867         if (!matPlainBlack)
02868         {
02869             matPlainBlack = static_cast<Material*>(
02870                 MaterialManager::getSingleton().create("Ogre/TextureShadowCaster"));
02871             mShadowCasterPlainBlackPass = matPlainBlack->getTechnique(0)->getPass(0);
02872             // Lighting has to be on, because we need shadow coloured objects
02873             // Note that because we can't predict vertex programs, we'll have to
02874             // bind light values to those, and so we bind White to ambient
02875             // reflectance, and we'll set the ambient colour to the shadow colour
02876             mShadowCasterPlainBlackPass->setAmbient(ColourValue::White);
02877             mShadowCasterPlainBlackPass->setDiffuse(ColourValue::Black);
02878             mShadowCasterPlainBlackPass->setSelfIllumination(ColourValue::Black);
02879             mShadowCasterPlainBlackPass->setSpecular(ColourValue::Black);
02880             // no textures or anything else, we will bind vertex programs
02881             // every so often though
02882         }
02883 
02884         Material* matShadRec = static_cast<Material*>(
02885             MaterialManager::getSingleton().getByName("Ogre/TextureShadowReceiver"));
02886         if (!matShadRec)
02887         {
02888             matShadRec = static_cast<Material*>(
02889                 MaterialManager::getSingleton().create("Ogre/TextureShadowReceiver"));
02890             mShadowReceiverPass = matShadRec->getTechnique(0)->getPass(0);
02891             mShadowReceiverPass->setSceneBlending(SBF_DEST_COLOUR, SBF_ZERO);
02892             // No lighting, one texture unit 
02893             // everything else will be bound as needed during the receiver pass
02894             mShadowReceiverPass->setLightingEnabled(false);
02895             TextureUnitState* t = mShadowReceiverPass->createTextureUnitState();
02896             t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
02897         }
02898 
02899         // Set up spot shadow fade texture (loaded from code data block)
02900         Texture* spotShadowFadeTex = (Texture*) 
02901             TextureManager::getSingleton().getByName("spot_shadow_fade.png");
02902         if (!spotShadowFadeTex)
02903         {
02904             // Load the manual buffer into an image
02905             DataChunk chunk(SPOT_SHADOW_FADE_PNG, SPOT_SHADOW_FADE_PNG_SIZE);
02906             Image img;
02907             img.load(chunk, "png");
02908             spotShadowFadeTex = 
02909                 TextureManager::getSingleton().loadImage("spot_shadow_fade.png", img, TEX_TYPE_2D);
02910         }
02911 
02912 
02913 
02914 
02915     }
02916     //---------------------------------------------------------------------
02917     Pass* SceneManager::deriveShadowCasterPass(Pass* pass)
02918     {
02919         switch (mShadowTechnique)
02920         {
02921         case SHADOWTYPE_TEXTURE_MODULATIVE:
02922             if (pass->hasVertexProgram())
02923             {
02924                 // Have to merge the shadow caster vertex program in
02925                 // This may in fact be blank, in which case it falls back on 
02926                 // fixed function
02927                 mShadowCasterPlainBlackPass->setVertexProgram(
02928                     pass->getShadowCasterVertexProgramName());
02929                 // Did this result in a new vertex program?
02930                 if (mShadowCasterPlainBlackPass->hasVertexProgram())
02931                 {
02932                     GpuProgram* prg = mShadowCasterPlainBlackPass->getVertexProgram();
02933                     // Load this program if not done already
02934                     if (!prg->isLoaded())
02935                         prg->load();
02936                     // Copy params
02937                     mShadowCasterPlainBlackPass->setVertexProgramParameters(
02938                         pass->getShadowCasterVertexProgramParameters());
02939                 }
02940                 // Also have to hack the light autoparams, that is done later
02941             }
02942             else if (mShadowCasterPlainBlackPass->hasVertexProgram())
02943             {
02944                 // reset
02945                 mShadowCasterPlainBlackPass->setVertexProgram("");
02946             }
02947             return mShadowCasterPlainBlackPass;
02948         /*
02949         case SHADOWTYPE_TEXTURE_SHADOWMAP:
02950             // todo
02951             return pass;
02952         */
02953         default:
02954             return pass;
02955         };
02956 
02957     }
02958     //---------------------------------------------------------------------
02959     Pass* SceneManager::deriveShadowReceiverPass(Pass* pass)
02960     {
02961 
02962         switch (mShadowTechnique)
02963         {
02964         case SHADOWTYPE_TEXTURE_MODULATIVE:
02965             if (pass->hasVertexProgram())
02966             {
02967                 // Have to merge the receiver vertex program in
02968                 // This may return "" which means fixed function will be used
02969                 mShadowReceiverPass->setVertexProgram(
02970                     pass->getShadowReceiverVertexProgramName());
02971                 // Did this result in a new vertex program?
02972                 if (mShadowReceiverPass->hasVertexProgram())
02973                 {
02974                     GpuProgram* prg = mShadowReceiverPass->getVertexProgram();
02975                     // Load this program if required
02976                     if (!prg->isLoaded())
02977                         prg->load();
02978                     // Copy params
02979                     mShadowReceiverPass->setVertexProgramParameters(
02980                         pass->getShadowReceiverVertexProgramParameters());
02981                 }
02982                 // Also have to hack the light autoparams, that is done later
02983             }
02984             else if (mShadowReceiverPass->hasVertexProgram())
02985             {
02986                 // reset
02987                 mShadowReceiverPass->setVertexProgram("");
02988 
02989             }
02990 
02991             return mShadowReceiverPass;
02992         /*
02993         case SHADOWTYPE_TEXTURE_SHADOWMAP:
02994             // todo
02995             return pass;
02996         */
02997         default:
02998             return pass;
02999         };
03000 
03001     }
03002     //---------------------------------------------------------------------
03003     void SceneManager::renderShadowVolumesToStencil(const Light* light, const Camera* camera)
03004     {
03005 
03006         // Set up scissor test (point & spot lights only)
03007         bool scissored = false;
03008         if (light->getType() != Light::LT_DIRECTIONAL && 
03009             mDestRenderSystem->getCapabilities()->hasCapability(RSC_SCISSOR_TEST))
03010         {
03011             // Project the sphere onto the camera
03012             Real left, right, top, bottom;
03013             Sphere sphere(light->getDerivedPosition(), light->getAttenuationRange());
03014             if (camera->projectSphere(sphere, &left, &top, &right, &bottom))
03015             {
03016                 scissored = true;
03017                 // Turn normalised device coordinates into pixels
03018                 int iLeft, iTop, iWidth, iHeight;
03019                 mCurrentViewport->getActualDimensions(iLeft, iTop, iWidth, iHeight);
03020                 size_t szLeft, szRight, szTop, szBottom;
03021 
03022                 szLeft = iLeft + ((left + 1) * 0.5 * iWidth);
03023                 szRight = iLeft + ((right + 1) * 0.5 * iWidth);
03024                 szTop = iTop + ((-top + 1) * 0.5 * iHeight);
03025                 szBottom = iTop + ((-bottom + 1) * 0.5 * iHeight);
03026 
03027                 mDestRenderSystem->setScissorTest(true, szLeft, szTop, szRight, szBottom);
03028 
03029             }
03030 
03031         }
03032 
03033 
03034 
03035         mDestRenderSystem->unbindGpuProgram(GPT_FRAGMENT_PROGRAM);
03036 
03037         // Can we do a 2-sided stencil?
03038         bool stencil2sided = false;
03039         if (mDestRenderSystem->getCapabilities()->hasCapability(RSC_TWO_SIDED_STENCIL) && 
03040             mDestRenderSystem->getCapabilities()->hasCapability(RSC_STENCIL_WRAP))
03041         {
03042             // enable
03043             stencil2sided = true;
03044         }
03045 
03046         // Do we have access to vertex programs?
03047         bool extrudeInSoftware = true;
03048         bool finiteExtrude = !mShadowUseInfiniteFarPlane || 
03049             !mDestRenderSystem->getCapabilities()->hasCapability(RSC_INFINITE_FAR_PLANE);
03050         if (mDestRenderSystem->getCapabilities()->hasCapability(RSC_VERTEX_PROGRAM))
03051         {
03052             extrudeInSoftware = false;
03053             // attach the appropriate extrusion vertex program
03054             // Note we never unset it because support for vertex programs is constant
03055             mShadowStencilPass->setVertexProgram(
03056                 ShadowVolumeExtrudeProgram::getProgramName(light->getType(), finiteExtrude, false)
03057                 , false);
03058             // Set params
03059             if (finiteExtrude)
03060             {
03061                 mShadowStencilPass->setVertexProgramParameters(mFiniteExtrusionParams);
03062             }
03063             else
03064             {
03065                 mShadowStencilPass->setVertexProgramParameters(mInfiniteExtrusionParams);
03066             }
03067             if (mDebugShadows)
03068             {
03069                 mShadowDebugPass->setVertexProgram(
03070                     ShadowVolumeExtrudeProgram::getProgramName(light->getType(), finiteExtrude, true)
03071                     , false);
03072                 // Set params
03073                 if (finiteExtrude)
03074                 {
03075                     mShadowDebugPass->setVertexProgramParameters(mFiniteExtrusionParams);
03076                 }
03077                 else
03078                 {
03079                     mShadowDebugPass->setVertexProgramParameters(mInfiniteExtrusionParams);
03080                 }
03081             }
03082 
03083             mDestRenderSystem->bindGpuProgram(mShadowStencilPass->getVertexProgram()->_getBindingDelegate());
03084 
03085         }
03086         else
03087         {
03088             mDestRenderSystem->unbindGpuProgram(GPT_VERTEX_PROGRAM);
03089         }
03090 
03091         // Add light to internal list for use in render call
03092         LightList lightList;
03093         // const_cast is forgiveable here since we pass this const
03094         lightList.push_back(const_cast<Light*>(light));
03095 
03096         // Turn off colour writing and depth writing
03097         mDestRenderSystem->_setColourBufferWriteEnabled(false, false, false, false);
03098         mDestRenderSystem->_setDepthBufferWriteEnabled(false);
03099         mDestRenderSystem->setStencilCheckEnabled(true);
03100         mDestRenderSystem->_setDepthBufferFunction(CMPF_LESS);
03101 
03102         // Calculate extrusion distance
03103         Real extrudeDist;
03104         if (light->getType() == Light::LT_DIRECTIONAL)
03105         {
03106             extrudeDist = mShadowDirLightExtrudeDist;
03107         }
03108 
03109         // Figure out the near clip volume
03110         const PlaneBoundedVolume& nearClipVol = 
03111             light->_getNearClipVolume(camera);
03112 
03113         // Get the shadow caster list
03114         const ShadowCasterList& casters = findShadowCastersForLight(light, camera);
03115         ShadowCasterList::const_iterator si, siend;
03116         siend = casters.end();
03117 
03118         // Determine whether zfail is required
03119         // We need to use zfail for ALL objects if we find a single object which
03120         // requires it
03121         bool zfailAlgo = false;
03122         unsigned long flags = 0;
03123 
03124         for (si = casters.begin(); si != siend; ++si)
03125         {
03126             ShadowCaster* caster = *si;
03127 
03128             if (nearClipVol.intersects(caster->getWorldBoundingBox()))
03129             {
03130                 // We have a zfail case, we must use zfail for all objects
03131                 zfailAlgo = true;
03132                 break;
03133             }
03134         }
03135 
03136         // Now iterate over the casters and render
03137         for (si = casters.begin(); si != siend; ++si)
03138         {
03139             ShadowCaster* caster = *si;
03140             flags = 0;
03141 
03142             if (light->getType() != Light::LT_DIRECTIONAL)
03143             {
03144                 extrudeDist = caster->getPointExtrusionDistance(light); 
03145             }
03146 
03147             if (!extrudeInSoftware && !finiteExtrude)
03148             {
03149                 // hardware extrusion, to infinity (and beyond!)
03150                 flags |= SRF_EXTRUDE_TO_INFINITY;
03151             }
03152 
03153             if (zfailAlgo)
03154             {
03155                 // We need to include the light and / or dark cap
03156                 // But only if they will be visible
03157                 if(camera->isVisible(caster->getLightCapBounds()))
03158                 {
03159                     flags |= SRF_INCLUDE_LIGHT_CAP;
03160                 }
03161             }
03162             // Dark cap (no dark cap for directional lights using 
03163             // hardware extrusion to infinity)
03164             if(!((flags & SRF_EXTRUDE_TO_INFINITY) && 
03165                 light->getType() == Light::LT_DIRECTIONAL) &&
03166                 camera->isVisible(caster->getDarkCapBounds(*light, extrudeDist)))
03167             {
03168                 flags |= SRF_INCLUDE_DARK_CAP;
03169             }
03170 
03171             // Get shadow renderables
03172             ShadowCaster::ShadowRenderableListIterator iShadowRenderables =
03173                 caster->getShadowVolumeRenderableIterator(mShadowTechnique,
03174                 light, &mShadowIndexBuffer, extrudeInSoftware, 
03175                 extrudeDist, flags);
03176 
03177             while (iShadowRenderables.hasMoreElements())
03178             {
03179                 ShadowRenderable* sr = iShadowRenderables.getNext();
03180                 // omit hidden renderables
03181                 if (sr->isVisible())
03182                 {
03183                     // render volume, including dark and (maybe) light caps
03184                     renderSingleShadowVolumeToStencil(sr, zfailAlgo, stencil2sided, &lightList);
03185 
03186                     // optionally render separate light cap
03187                     if (sr->isLightCapSeparate() &&
03188                         (flags & SRF_INCLUDE_LIGHT_CAP))
03189                     {
03190                         // must always fail depth check
03191                         mDestRenderSystem->_setDepthBufferFunction(CMPF_ALWAYS_FAIL);
03192                         assert(sr->getLightCapRenderable() && "Shadow renderable is "
03193                             "missing a separate light cap renderable!");
03194                         renderSingleShadowVolumeToStencil(sr->getLightCapRenderable(),
03195                             zfailAlgo, stencil2sided, &lightList);
03196                         // reset depth function
03197                         mDestRenderSystem->_setDepthBufferFunction(CMPF_LESS);
03198                     }
03199                 }
03200             }
03201         }
03202         // revert colour write state
03203         mDestRenderSystem->_setColourBufferWriteEnabled(true, true, true, true);
03204         // revert depth state
03205         mDestRenderSystem->_setDepthBufferParams();
03206 
03207         mDestRenderSystem->setStencilCheckEnabled(false);
03208 
03209         mDestRenderSystem->unbindGpuProgram(GPT_VERTEX_PROGRAM);
03210 
03211         if (scissored)
03212         {
03213             // disable scissor test
03214             mDestRenderSystem->setScissorTest(false);
03215         }
03216 
03217     }
03218     //---------------------------------------------------------------------
03219     void SceneManager::renderSingleShadowVolumeToStencil(ShadowRenderable* sr,
03220         bool zfailAlgo, bool stencil2sided, const LightList *manualLightList)
03221     {
03222         // Render a shadow volume here
03223         //  - if we have 2-sided stencil, one render with no culling
03224         //  - otherwise, 2 renders, one with each culling method and invert the ops
03225         setShadowVolumeStencilState(false, zfailAlgo, stencil2sided);
03226         renderSingleObject(sr, mShadowStencilPass, false, manualLightList);
03227 
03228         if (!stencil2sided)
03229         {
03230             // Second pass
03231             setShadowVolumeStencilState(true, zfailAlgo, false);
03232             renderSingleObject(sr, mShadowStencilPass, false);
03233         }
03234 
03235         // Do we need to render a debug shadow marker?
03236         if (mDebugShadows)
03237         {
03238             // reset stencil & colour ops
03239             mDestRenderSystem->setStencilBufferParams();
03240             setPass(mShadowDebugPass);
03241             renderSingleObject(sr, mShadowDebugPass, false, manualLightList);
03242             mDestRenderSystem->_setColourBufferWriteEnabled(false, false, false, false);
03243         }
03244     }
03245     //---------------------------------------------------------------------
03246     void SceneManager::setShadowVolumeStencilState(bool secondpass, bool zfail, bool twosided)
03247     {
03248         // First pass, do front faces if zpass
03249         // Second pass, do back faces if zpass
03250         // Invert if zfail
03251         // this is to ensure we always increment before decrement
03252         if ( (secondpass || zfail) &&
03253             !(secondpass && zfail) )
03254         {
03255             mDestRenderSystem->_setCullingMode(
03256                 twosided? CULL_NONE : CULL_ANTICLOCKWISE);
03257             mDestRenderSystem->setStencilBufferParams(
03258                 CMPF_ALWAYS_PASS, // always pass stencil check
03259                 0, // no ref value (no compare)
03260                 0xFFFFFFFF, // no mask
03261                 SOP_KEEP, // stencil test will never fail
03262                 zfail? (twosided? SOP_INCREMENT_WRAP : SOP_INCREMENT) : SOP_KEEP, // back face depth fail
03263                 zfail? SOP_KEEP : (twosided? SOP_DECREMENT_WRAP : SOP_DECREMENT), // back face pass
03264                 twosided
03265                 );
03266         }
03267         else
03268         {
03269             mDestRenderSystem->_setCullingMode(
03270                 twosided? CULL_NONE : CULL_CLOCKWISE);
03271             mDestRenderSystem->setStencilBufferParams(
03272                 CMPF_ALWAYS_PASS, // always pass stencil check
03273                 0, // no ref value (no compare)
03274                 0xFFFFFFFF, // no mask
03275                 SOP_KEEP, // stencil test will never fail
03276                 zfail? (twosided? SOP_DECREMENT_WRAP : SOP_DECREMENT) : SOP_KEEP, // front face depth fail
03277                 zfail? SOP_KEEP : (twosided? SOP_INCREMENT_WRAP : SOP_INCREMENT), // front face pass
03278                 twosided
03279                 );
03280         }
03281     }
03282     //---------------------------------------------------------------------
03283     void SceneManager::setShadowColour(const ColourValue& colour)
03284     {
03285         mShadowColour = colour;
03286 
03287         if (!mShadowModulativePass && !mShadowCasterPlainBlackPass)
03288             initShadowVolumeMaterials();
03289 
03290         mShadowModulativePass->getTextureUnitState(0)->setColourOperationEx(
03291             LBX_MODULATE, LBS_MANUAL, LBS_CURRENT, colour);
03292     }
03293     //---------------------------------------------------------------------
03294     const ColourValue& SceneManager::getShadowColour(void) const
03295     {
03296         return mShadowColour;
03297     }
03298     //---------------------------------------------------------------------
03299     void SceneManager::setShadowFarDistance(Real distance)
03300     {
03301         mShadowFarDist = distance;
03302         mShadowFarDistSquared = distance * distance;
03303     }
03304     //---------------------------------------------------------------------
03305     void SceneManager::setShadowDirectionalLightExtrusionDistance(Real dist)
03306     {
03307         mShadowDirLightExtrudeDist = dist;
03308     }
03309     //---------------------------------------------------------------------
03310     Real SceneManager::getShadowDirectionalLightExtrusionDistance(void) const
03311     {
03312         return mShadowDirLightExtrudeDist;
03313     }
03314     //---------------------------------------------------------------------
03315     void SceneManager::setShadowIndexBufferSize(size_t size)
03316     {
03317         if (!mShadowIndexBuffer.isNull() && size != mShadowIndexBufferSize)
03318         {
03319             // re-create shadow buffer with new size
03320             mShadowIndexBuffer = HardwareBufferManager::getSingleton().
03321                 createIndexBuffer(HardwareIndexBuffer::IT_16BIT, 
03322                     mShadowIndexBufferSize, 
03323                     HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, 
03324                     false);
03325         }
03326         mShadowIndexBufferSize = size;
03327     }
03328     //---------------------------------------------------------------------
03329     void SceneManager::setShadowTextureSize(unsigned short size)
03330     {
03331         // possibly recreate
03332         createShadowTextures(size, mShadowTextureCount);
03333         mShadowTextureSize = size;
03334     }
03335     //---------------------------------------------------------------------
03336     void SceneManager::setShadowTextureCount(unsigned short count)
03337     {
03338         // possibly recreate
03339         createShadowTextures(mShadowTextureSize, count);
03340         mShadowTextureCount = count;
03341     }
03342     //---------------------------------------------------------------------
03343     void SceneManager::setShadowTextureSettings(unsigned short size, unsigned short count)
03344     {
03345         if (!mShadowTextures.empty() && 
03346             (count != mShadowTextureCount ||
03347              size != mShadowTextureSize))
03348         {
03349             // recreate
03350             createShadowTextures(size, count);
03351         }
03352         mShadowTextureCount = count;
03353         mShadowTextureSize = size;
03354     }
03355     //---------------------------------------------------------------------
03356     void SceneManager::createShadowTextures(unsigned short size, unsigned short count)
03357     {
03358         static const String baseName = "Ogre/ShadowTexture";
03359 
03360         if ((mShadowTechnique != SHADOWTYPE_TEXTURE_MODULATIVE 
03361             /*&& mShadowTechnique != SHADOWTYPE_TEXTURE_SHADOWMAP */) ||
03362             !mShadowTextures.empty() && 
03363             count == mShadowTextureCount &&
03364             size == mShadowTextureSize)
03365         {
03366             // no change
03367             return;
03368         }
03369 
03370 
03371         // destroy existing
03372         ShadowTextureList::iterator i, iend;
03373         iend = mShadowTextures.end();
03374         for (i = mShadowTextures.begin(); i != iend; ++i)
03375         {
03376             RenderTexture* r = *i;
03377             // remove camera and destroy texture
03378             removeCamera(r->getViewport(0)->getCamera());
03379             mDestRenderSystem->destroyRenderTexture(r->getName());
03380         }
03381         mShadowTextures.clear();
03382 
03383         // Recreate shadow textures
03384         for (unsigned short t = 0; t < mShadowTextureCount; ++t)
03385         {
03386             String targName = baseName + StringConverter::toString(t);
03387             String matName = baseName + "Mat" + StringConverter::toString(t);
03388             String camName = baseName + "Cam" + StringConverter::toString(t);
03389 
03390             RenderTexture* shadowTex;
03391             if (mShadowTechnique == SHADOWTYPE_TEXTURE_MODULATIVE)
03392             {
03393                 shadowTex = mDestRenderSystem->createRenderTexture( 
03394                     targName, size, size );
03395             }
03396             /*
03397             else if (mShadowTechnique == SHADOWTYPE_TEXTURE_SHADOWMAP)
03398             {
03399                 // todo
03400             }
03401             */
03402 
03403             // Create a camera to go with this texture
03404             Camera* cam = createCamera(camName);
03405             cam->setAspectRatio(1.0f);
03406             // Create a viewport
03407             Viewport *v = shadowTex->addViewport(cam);
03408             v->setClearEveryFrame(true);
03409             // remove overlays
03410             v->setOverlaysEnabled(false);
03411             // Don't update automatically - we'll do it when required
03412             shadowTex->setAutoUpdated(false);
03413             mShadowTextures.push_back(shadowTex);
03414 
03415             // Also create corresponding Material used for rendering this shadow
03416             Material* mat = (Material*)MaterialManager::getSingleton().getByName(matName);
03417             if (!mat)
03418             {
03419                 mat = (Material*)MaterialManager::getSingleton().create(matName);
03420             }
03421             else
03422             {
03423                 mat->getTechnique(0)->getPass(0)->removeAllTextureUnitStates();
03424             }
03425             // create texture unit referring to render target texture
03426             TextureUnitState* texUnit = 
03427                 mat->getTechnique(0)->getPass(0)->createTextureUnitState(targName);
03428             // set projective based on camera
03429             texUnit->setProjectiveTexturing(true, cam);
03430             texUnit->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
03431             mat->touch();
03432 
03433         }
03434     }
03435     //---------------------------------------------------------------------
03436     void SceneManager::prepareShadowTextures(Camera* cam, Viewport* vp)
03437     {
03438         // Set the illumination stage, prevents recursive calls
03439         IlluminationRenderStage savedStage = mIlluminationStage;
03440         mIlluminationStage = IRS_RENDER_TO_TEXTURE;
03441 
03442         // Determine far shadow distance
03443         Real shadowDist = mShadowFarDist;
03444         if (!shadowDist)
03445         {
03446             // need a shadow distance, make one up
03447             shadowDist = cam->getNearClipDistance() * 300;
03448         }
03449         // set fogging to hide the shadow edge
03450         Real shadowOffset = shadowDist * mShadowTextureOffset;
03451         Real shadowEnd = shadowDist + shadowOffset;
03452         mShadowReceiverPass->setFog(true, FOG_LINEAR, ColourValue::White, 
03453             0, shadowEnd * mShadowTextureFadeStart, shadowEnd * mShadowTextureFadeEnd);
03454 
03455         // Iterate over the lights we've found, max out at the limit of light textures
03456 
03457         LightList::iterator i, iend;
03458         ShadowTextureList::iterator si, siend;
03459         iend = mLightsAffectingFrustum.end();
03460         siend = mShadowTextures.end();
03461         for (i = mLightsAffectingFrustum.begin(), si = mShadowTextures.begin();
03462              i != iend && si != siend; ++i)
03463         {
03464             Light* light = *i;
03465             RenderTexture* shadowTex = *si;
03466             // Skip non-shadowing lights
03467             if (!light->getCastShadows())
03468                 continue;
03469 
03470             // Directional lights 
03471             if (light->getType() == Light::LT_DIRECTIONAL)
03472             {
03473 
03474                 // set up the shadow texture
03475                 Camera* texCam = shadowTex->getViewport(0)->getCamera();
03476                 // Set ortho projection
03477                 texCam->setProjectionType(PT_ORTHOGRAPHIC);
03478                 // set easy FOV and near dist so that texture covers far dist
03479                 texCam->setFOVy(90);
03480                 texCam->setNearClipDistance(shadowDist);
03481 
03482                 // Set size of projection
03483 
03484                 // Calculate look at position
03485                 // We want to look at a spot shadowOffset away from near plane
03486                 // 0.5 is a litle too close for angles
03487                 Vector3 target = cam->getDerivedPosition() + 
03488                     (cam->getDerivedDirection() * shadowOffset);
03489 
03490                 // Calculate position
03491                 // We want to be in the -ve direction of the light direction
03492                 // far enough to project for the dir light extrusion distance
03493                 Vector3 pos = target + 
03494                     (light->getDerivedDirection() * -mShadowDirLightExtrudeDist);
03495 
03496                 // Calculate orientation
03497                 Vector3 dir = (pos - target); // backwards since point down -z
03498                 dir.normalise();
03499                 /*
03500                 // Next section (camera oriented shadow map) abandoned
03501                 // Always point in the same direction, if we don't do this then
03502                 // we get 'shadow swimming' as camera rotates
03503                 // As it is, we get swimming on moving but this is less noticeable
03504 
03505                 // calculate up vector, we want it aligned with cam direction
03506                 Vector3 up = cam->getDerivedDirection();
03507                 // Check it's not coincident with dir
03508                 if (up.dotProduct(dir) >= 1.0f)
03509                 {
03510                     // Use camera up
03511                     up = cam->getUp();
03512                 }
03513                 */
03514                 Vector3 up = Vector3::UNIT_Y;
03515                 // Check it's not coincident with dir
03516                 if (up.dotProduct(dir) >= 1.0f)
03517                 {
03518                     // Use camera up
03519                     up = Vector3::UNIT_Z;
03520                 }
03521                 // cross twice to rederive, only direction is unaltered
03522                 Vector3 left = dir.crossProduct(up);
03523                 left.normalise();
03524                 up = dir.crossProduct(left);
03525                 up.normalise();
03526                 // Derive quaternion from axes
03527                 Quaternion q;
03528                 q.FromAxes(left, up, dir);
03529                 texCam->setOrientation(q);
03530 
03531                 // Round local x/y position based on a world-space texel; this helps to reduce
03532                 // jittering caused by the projection moving with the camera
03533                 // Viewport is 2 * near clip distance across (90 degree fov)
03534                 Real worldTexelSize = (texCam->getNearClipDistance() * 20) / mShadowTextureSize;
03535                 pos.x -= fmod(pos.x, worldTexelSize);
03536                 pos.y -= fmod(pos.y, worldTexelSize);
03537                 pos.z -= fmod(pos.z, worldTexelSize);
03538                 // Finally set position
03539                 texCam->setPosition(pos);
03540 
03541                 if (mShadowTechnique == SHADOWTYPE_TEXTURE_MODULATIVE)
03542                     shadowTex->getViewport(0)->setBackgroundColour(ColourValue::White);
03543 
03544                 // Update target
03545                 shadowTex->update();
03546 
03547                 ++si;
03548             }
03549             // Spotlight
03550             else if (light->getType() == Light::LT_SPOTLIGHT)
03551             {
03552 
03553                 // set up the shadow texture
03554                 Camera* texCam = shadowTex->getViewport(0)->getCamera();
03555                 // Set perspective projection
03556                 texCam->setProjectionType(PT_PERSPECTIVE);
03557                 // set FOV slightly larger than the spotlight range to ensure coverage
03558                 texCam->setFOVy(light->getSpotlightOuterAngle()*1.2);
03559                 texCam->setPosition(light->getDerivedPosition());
03560                 texCam->setDirection(light->getDerivedDirection());
03561                 // set near clip the same as main camera, since they are likely
03562                 // to both reflect the nature of the scene
03563                 texCam->setNearClipDistance(cam->getNearClipDistance());
03564 
03565                 if (mShadowTechnique == SHADOWTYPE_TEXTURE_MODULATIVE)
03566                     shadowTex->getViewport(0)->setBackgroundColour(ColourValue::White);
03567 
03568                 // Update target
03569                 shadowTex->update();
03570 
03571                 ++si;
03572             }
03573         }
03574         // Set the illumination stage, prevents recursive calls
03575         mIlluminationStage = savedStage;
03576     }
03577     //---------------------------------------------------------------------
03578     AxisAlignedBoxSceneQuery* 
03579     SceneManager::createAABBQuery(const AxisAlignedBox& box, unsigned long mask)
03580     {
03581         DefaultAxisAlignedBoxSceneQuery* q = new DefaultAxisAlignedBoxSceneQuery(this);
03582         q->setBox(box);
03583         q->setQueryMask(mask);
03584         return q;
03585     }
03586     //---------------------------------------------------------------------
03587     SphereSceneQuery* 
03588     SceneManager::createSphereQuery(const Sphere& sphere, unsigned long mask)
03589     {
03590         DefaultSphereSceneQuery* q = new DefaultSphereSceneQuery(this);
03591         q->setSphere(sphere);
03592         q->setQueryMask(mask);
03593         return q;
03594     }
03595     //---------------------------------------------------------------------
03596     PlaneBoundedVolumeListSceneQuery* 
03597     SceneManager::createPlaneBoundedVolumeQuery(const PlaneBoundedVolumeList& volumes, 
03598         unsigned long mask)
03599     {
03600         DefaultPlaneBoundedVolumeListSceneQuery* q = new DefaultPlaneBoundedVolumeListSceneQuery(this);
03601         q->setVolumes(volumes);
03602         q->setQueryMask(mask);
03603         return q;
03604     }
03605 
03606     //---------------------------------------------------------------------
03607     RaySceneQuery* 
03608     SceneManager::createRayQuery(const Ray& ray, unsigned long mask)
03609     {
03610         DefaultRaySceneQuery* q = new DefaultRaySceneQuery(this);
03611         q->setRay(ray);
03612         q->setQueryMask(mask);
03613         return q;
03614     }
03615     //---------------------------------------------------------------------
03616     IntersectionSceneQuery* 
03617     SceneManager::createIntersectionQuery(unsigned long mask)
03618     {
03619         
03620         DefaultIntersectionSceneQuery* q = new DefaultIntersectionSceneQuery(this);
03621         q->setQueryMask(mask);
03622         return q;
03623     }
03624     //---------------------------------------------------------------------
03625     void SceneManager::destroyQuery(SceneQuery* query)
03626     {
03627         delete query;
03628     }
03629     //---------------------------------------------------------------------
03630     DefaultIntersectionSceneQuery::DefaultIntersectionSceneQuery(SceneManager* creator)
03631         : IntersectionSceneQuery(creator)
03632     {
03633         // No world geometry results supported
03634         mSupportedWorldFragments.insert(SceneQuery::WFT_NONE);
03635     }
03636     //---------------------------------------------------------------------
03637     DefaultIntersectionSceneQuery::~DefaultIntersectionSceneQuery()
03638     {
03639     }
03640     //---------------------------------------------------------------------
03641     void DefaultIntersectionSceneQuery::execute(IntersectionSceneQueryListener* listener)
03642     {
03643         // TODO: BillboardSets? Will need per-billboard collision most likely
03644         // Entities only for now
03645         SceneManager::EntityList::const_iterator a, b, theEnd;
03646         theEnd = mParentSceneMgr->mEntities.end();
03647         int numEntities;
03648         // Loop a from first to last-1
03649         a = mParentSceneMgr->mEntities.begin();
03650         numEntities = (uint)mParentSceneMgr->mEntities.size();
03651         for (int i = 0; i < (numEntities - 1); ++i, ++a)
03652         {
03653             // Skip if a does not pass the mask
03654             if (! (a->second->getQueryFlags() & mQueryMask))
03655                 continue;
03656 
03657             // Loop b from a+1 to last
03658             b = a;
03659             for (++b; b != theEnd; ++b)
03660             {
03661                 // Apply mask to b (both must pass)
03662                 if (b->second->getQueryFlags() & mQueryMask)
03663                 {
03664                     const AxisAlignedBox& box1 = a->second->getWorldBoundingBox();
03665                     const AxisAlignedBox& box2 = b->second->getWorldBoundingBox();
03666 
03667                     if (box1.intersects(box2))
03668                     {
03669                         listener->queryResult(a->second, b->second);
03670                     }
03671                 }
03672 
03673             }
03674         }
03675     }
03676     //---------------------------------------------------------------------
03677     DefaultAxisAlignedBoxSceneQuery::
03678     DefaultAxisAlignedBoxSceneQuery(SceneManager* creator)
03679     : AxisAlignedBoxSceneQuery(creator)
03680     {
03681         // No world geometry results supported
03682         mSupportedWorldFragments.insert(SceneQuery::WFT_NONE);
03683     }
03684     //---------------------------------------------------------------------
03685     DefaultAxisAlignedBoxSceneQuery::~DefaultAxisAlignedBoxSceneQuery()
03686     {
03687     }
03688     //---------------------------------------------------------------------
03689     void DefaultAxisAlignedBoxSceneQuery::execute(SceneQueryListener* listener)
03690     {
03691         // TODO: BillboardSets? Will need per-billboard collision most likely
03692         // Entities only for now
03693         SceneManager::EntityList::const_iterator i, iEnd;
03694         iEnd = mParentSceneMgr->mEntities.end();
03695         for (i = mParentSceneMgr->mEntities.begin(); i != iEnd; ++i)
03696         {
03697             if (mAABB.intersects(i->second->getWorldBoundingBox()))
03698             {
03699                 listener->queryResult(i->second);
03700             }
03701         }
03702     }
03703     //---------------------------------------------------------------------
03704     DefaultRaySceneQuery::
03705     DefaultRaySceneQuery(SceneManager* creator) : RaySceneQuery(creator)
03706     {
03707         // No world geometry results supported
03708         mSupportedWorldFragments.insert(SceneQuery::WFT_NONE);
03709     }
03710     //---------------------------------------------------------------------
03711     DefaultRaySceneQuery::~DefaultRaySceneQuery()
03712     {
03713     }
03714     //---------------------------------------------------------------------
03715     void DefaultRaySceneQuery::execute(RaySceneQueryListener* listener)
03716     {
03717         // Note that becuase we have no scene partitioning, we actually
03718         // perform a complete scene search even if restricted results are
03719         // requested; smarter scene manager queries can utilise the paritioning 
03720         // of the scene in order to reduce the number of intersection tests 
03721         // required to fulfil the query
03722 
03723         // TODO: BillboardSets? Will need per-billboard collision most likely
03724         // Entities only for now
03725         SceneManager::EntityList::const_iterator i, iEnd;
03726         iEnd = mParentSceneMgr->mEntities.end();
03727         for (i = mParentSceneMgr->mEntities.begin(); i != iEnd; ++i)
03728         {
03729             // Do ray / box test
03730             std::pair<bool, Real> result = 
03731                 mRay.intersects(i->second->getWorldBoundingBox());
03732 
03733             if (result.first)
03734             {
03735                 listener->queryResult(i->second, result.second);
03736             }
03737         }
03738 
03739     }
03740     //---------------------------------------------------------------------
03741     DefaultSphereSceneQuery::
03742     DefaultSphereSceneQuery(SceneManager* creator) : SphereSceneQuery(creator)
03743     {
03744         // No world geometry results supported
03745         mSupportedWorldFragments.insert(SceneQuery::WFT_NONE);
03746     }
03747     //---------------------------------------------------------------------
03748     DefaultSphereSceneQuery::~DefaultSphereSceneQuery()
03749     {
03750     }
03751     //---------------------------------------------------------------------
03752     void DefaultSphereSceneQuery::execute(SceneQueryListener* listener)
03753     {
03754         // TODO: BillboardSets? Will need per-billboard collision most likely
03755         // Entities only for now
03756         SceneManager::EntityList::const_iterator i, iEnd;
03757         iEnd = mParentSceneMgr->mEntities.end();
03758         Sphere testSphere;
03759         for (i = mParentSceneMgr->mEntities.begin(); i != iEnd; ++i)
03760         {
03761             // Skip unattached
03762             if (!i->second->getParentNode())
03763                 continue;
03764 
03765             // Do sphere / sphere test
03766             testSphere.setCenter(i->second->getParentNode()->_getDerivedPosition());
03767             testSphere.setRadius(i->second->getBoundingRadius());
03768             if (mSphere.intersects(testSphere))
03769             {
03770                 listener->queryResult(i->second);
03771             }
03772         }
03773     }
03774     //---------------------------------------------------------------------
03775     DefaultPlaneBoundedVolumeListSceneQuery::
03776         DefaultPlaneBoundedVolumeListSceneQuery(SceneManager* creator) 
03777         : PlaneBoundedVolumeListSceneQuery(creator)
03778     {
03779         // No world geometry results supported
03780         mSupportedWorldFragments.insert(SceneQuery::WFT_NONE);
03781     }
03782     //---------------------------------------------------------------------
03783     DefaultPlaneBoundedVolumeListSceneQuery::~DefaultPlaneBoundedVolumeListSceneQuery()
03784     {
03785     }
03786     //---------------------------------------------------------------------
03787     void DefaultPlaneBoundedVolumeListSceneQuery::execute(SceneQueryListener* listener)
03788     {
03789         // Entities only for now
03790         SceneManager::EntityList::const_iterator i, iEnd;
03791         iEnd = mParentSceneMgr->mEntities.end();
03792         Sphere testSphere;
03793         for (i = mParentSceneMgr->mEntities.begin(); i != iEnd; ++i)
03794         {
03795             PlaneBoundedVolumeList::iterator pi, piend;
03796             piend = mVolumes.end();
03797             for (pi = mVolumes.begin(); pi != piend; ++pi)
03798             {
03799                 PlaneBoundedVolume& vol = *pi;
03800                 // Do AABB / plane volume test
03801                 if (vol.intersects(i->second->getWorldBoundingBox()))
03802                 {
03803                     listener->queryResult(i->second);
03804                     break;
03805                 }
03806             }
03807         }
03808     }
03809 
03810 }

Copyright © 2002-2003 by The OGRE Team
Last modified Fri May 14 23:22:44 2004