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

Copyright © 2002-2003 by The OGRE Team
Last modified Sun Nov 28 19:48:44 2004