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