source: trunk/VUT/work/ogre_changes/OgreMain/src/OgreSceneManager.cpp @ 193

Revision 193, 147.9 KB checked in by mattausch, 19 years ago (diff)

changed to ogre 103
added readme

Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4(Object-oriented Graphics Rendering Engine)
5For the latest info, see http://ogre.sourceforge.net/
6
7Copyright (c) 2000-2005 The OGRE Team
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23-----------------------------------------------------------------------------
24*/
25#include "OgreStableHeaders.h"
26
27#include "OgreSceneManager.h"
28
29#include "OgreCamera.h"
30#include "OgreRenderSystem.h"
31#include "OgreMeshManager.h"
32#include "OgreMesh.h"
33#include "OgreSubMesh.h"
34#include "OgreEntity.h"
35#include "OgreSubEntity.h"
36#include "OgreLight.h"
37#include "OgreMath.h"
38#include "OgreControllerManager.h"
39#include "OgreMaterialManager.h"
40#include "OgreAnimation.h"
41#include "OgreAnimationTrack.h"
42#include "OgreRenderQueueSortingGrouping.h"
43#include "OgreOverlay.h"
44#include "OgreOverlayManager.h"
45#include "OgreStringConverter.h"
46#include "OgreRenderQueueListener.h"
47#include "OgreBillboardSet.h"
48#include "OgrePass.h"
49#include "OgreTechnique.h"
50#include "OgreTextureUnitState.h"
51#include "OgreException.h"
52#include "OgreLogManager.h"
53#include "OgreHardwareBufferManager.h"
54#include "OgreRoot.h"
55#include "OgreSpotShadowFadePng.h"
56#include "OgreGpuProgramManager.h"
57#include "OgreGpuProgram.h"
58#include "OgreShadowVolumeExtrudeProgram.h"
59#include "OgreDataStream.h"
60#include "OgreStaticGeometry.h"
61
62// This class implements the most basic scene manager
63
64#include <cstdio>
65
66namespace Ogre {
67
68//-----------------------------------------------------------------------
69unsigned long SceneManager::WORLD_GEOMETRY_QUERY_MASK = 0x80000000;
70//-----------------------------------------------------------------------
71SceneManager::SceneManager() :
72mRenderQueue(0),
73mSkyPlaneEntity(0),
74mSkyPlaneNode(0),
75mSkyDomeNode(0),
76mSkyBoxNode(0),
77mSkyPlaneEnabled(false),
78mSkyBoxEnabled(false),
79mSkyDomeEnabled(false),
80mFogMode(FOG_NONE),
81mSpecialCaseQueueMode(SCRQM_EXCLUDE),
82mWorldGeometryRenderQueue(RENDER_QUEUE_WORLD_GEOMETRY_1),
83mShadowCasterPlainBlackPass(0),
84mShadowReceiverPass(0),
85mDisplayNodes(false),
86mShowBoundingBoxes(false),
87mShadowTechnique(SHADOWTYPE_NONE),
88mDebugShadows(false),
89mShadowColour(ColourValue(0.25, 0.25, 0.25)),
90mShadowDebugPass(0),
91mShadowStencilPass(0),
92mShadowModulativePass(0),
93mShadowMaterialInitDone(false),
94mShadowIndexBufferSize(51200),
95mFullScreenQuad(0),
96mShadowDirLightExtrudeDist(10000),
97mIlluminationStage(IRS_NONE),
98mShadowTextureSize(512),
99mShadowTextureCount(1),
100mShadowTextureFormat(PF_X8R8G8B8),
101mShadowUseInfiniteFarPlane(true),
102mShadowCasterSphereQuery(0),
103mShadowCasterAABBQuery(0),
104mShadowFarDist(0),
105mShadowFarDistSquared(0),
106mShadowTextureOffset(0.6),
107mShadowTextureFadeStart(0.7),
108mShadowTextureFadeEnd(0.9),
109mShadowTextureSelfShadow(false),
110mShadowTextureCustomCasterPass(0),
111mShadowTextureCustomReceiverPass(0),
112mShadowTextureCasterVPDirty(false),
113mShadowTextureReceiverVPDirty(false)
114{
115    // Root scene node
116    mSceneRoot = new SceneNode(this, "root node");
117        mSceneRoot->_notifyRootNode();
118
119    // init sky
120    size_t i;
121    for (i = 0; i < 6; ++i)
122    {
123        mSkyBoxEntity[i] = 0;
124    }
125    for (i = 0; i < 5; ++i)
126    {
127        mSkyDomeEntity[i] = 0;
128    }
129
130        mShadowCasterQueryListener = new ShadowCasterSceneQueryListener(this);
131
132    Root *root = Root::getSingletonPtr();
133    if (root)
134        _setDestinationRenderSystem(root->getRenderSystem());
135}
136//-----------------------------------------------------------------------
137SceneManager::~SceneManager()
138{
139    clearScene();
140    removeAllCameras();
141        delete mShadowCasterQueryListener;
142    delete mSceneRoot;
143    delete mFullScreenQuad;
144    delete mShadowCasterSphereQuery;
145    delete mShadowCasterAABBQuery;
146    delete mRenderQueue;
147}
148//-----------------------------------------------------------------------
149RenderQueue* SceneManager::getRenderQueue(void)
150{
151    if (!mRenderQueue)
152    {
153        initRenderQueue();
154    }
155    return mRenderQueue;
156}
157//-----------------------------------------------------------------------
158void SceneManager::initRenderQueue(void)
159{
160    mRenderQueue = new RenderQueue();
161    // init render queues that do not need shadows
162    mRenderQueue->getQueueGroup(RENDER_QUEUE_BACKGROUND)->setShadowsEnabled(false);
163    mRenderQueue->getQueueGroup(RENDER_QUEUE_OVERLAY)->setShadowsEnabled(false);
164    mRenderQueue->getQueueGroup(RENDER_QUEUE_SKIES_EARLY)->setShadowsEnabled(false);
165    mRenderQueue->getQueueGroup(RENDER_QUEUE_SKIES_LATE)->setShadowsEnabled(false);
166}
167//-----------------------------------------------------------------------
168void SceneManager::addSpecialCaseRenderQueue(RenderQueueGroupID qid)
169{
170        mSpecialCaseQueueList.insert(qid);
171}
172//-----------------------------------------------------------------------
173void SceneManager::removeSpecialCaseRenderQueue(RenderQueueGroupID qid)
174{
175        mSpecialCaseQueueList.erase(qid);
176}
177//-----------------------------------------------------------------------
178void SceneManager::clearSpecialCaseRenderQueues(void)
179{
180        mSpecialCaseQueueList.clear();
181}
182//-----------------------------------------------------------------------
183void SceneManager::setSpecialCaseRenderQueueMode(SceneManager::SpecialCaseRenderQueueMode mode)
184{
185        mSpecialCaseQueueMode = mode;
186}
187//-----------------------------------------------------------------------
188SceneManager::SpecialCaseRenderQueueMode SceneManager::getSpecialCaseRenderQueueMode(void)
189{
190        return mSpecialCaseQueueMode;
191}
192//-----------------------------------------------------------------------
193bool SceneManager::isRenderQueueToBeProcessed(RenderQueueGroupID qid)
194{
195        bool inList = mSpecialCaseQueueList.find(qid) != mSpecialCaseQueueList.end();
196        return (inList && mSpecialCaseQueueMode == SCRQM_INCLUDE)
197                || (!inList && mSpecialCaseQueueMode == SCRQM_EXCLUDE);
198}
199//-----------------------------------------------------------------------
200void SceneManager::setWorldGeometryRenderQueue(RenderQueueGroupID qid)
201{
202        mWorldGeometryRenderQueue = qid;
203}
204//-----------------------------------------------------------------------
205RenderQueueGroupID SceneManager::getWorldGeometryRenderQueue(void)
206{
207        return mWorldGeometryRenderQueue;
208}
209//-----------------------------------------------------------------------
210Camera* SceneManager::createCamera(const String& name)
211{
212    // Check name not used
213    if (mCameras.find(name) != mCameras.end())
214    {
215        OGRE_EXCEPT(
216            Exception::ERR_DUPLICATE_ITEM,
217            "A camera with the name " + name + " already exists",
218            "SceneManager::createCamera" );
219    }
220
221    Camera *c = new Camera(name, this);
222    mCameras.insert(CameraList::value_type(name, c));
223
224
225    return c;
226}
227
228//-----------------------------------------------------------------------
229Camera* SceneManager::getCamera(const String& name)
230{
231    CameraList::iterator i = mCameras.find(name);
232    if (i == mCameras.end())
233    {
234        OGRE_EXCEPT( Exception::ERR_ITEM_NOT_FOUND,
235            "Cannot find Camera with name " + name,
236            "SceneManager::getCamera");
237    }
238    else
239    {
240        return i->second;
241    }
242}
243
244//-----------------------------------------------------------------------
245void SceneManager::removeCamera(Camera *cam)
246{
247    // Find in list
248    CameraList::iterator i = mCameras.begin();
249    for (; i != mCameras.end(); ++i)
250    {
251        if (i->second == cam)
252        {
253            mCameras.erase(i);
254            // notify render targets
255            mDestRenderSystem->_notifyCameraRemoved(cam);
256            delete cam;
257            break;
258        }
259    }
260
261}
262
263//-----------------------------------------------------------------------
264void SceneManager::removeCamera(const String& name)
265{
266    // Find in list
267    CameraList::iterator i = mCameras.find(name);
268    if (i != mCameras.end())
269    {
270        // Notify render system
271        mDestRenderSystem->_notifyCameraRemoved(i->second);
272        delete i->second;
273        mCameras.erase(i);
274    }
275
276}
277
278//-----------------------------------------------------------------------
279void SceneManager::removeAllCameras(void)
280{
281
282    CameraList::iterator i = mCameras.begin();
283    for (; i != mCameras.end(); ++i)
284    {
285        // Notify render system
286        mDestRenderSystem->_notifyCameraRemoved(i->second);
287        delete i->second;
288    }
289    mCameras.clear();
290}
291
292//-----------------------------------------------------------------------
293Light* SceneManager::createLight(const String& name)
294{
295    // Check name not used
296    if (mLights.find(name) != mLights.end())
297    {
298        OGRE_EXCEPT(
299            Exception::ERR_DUPLICATE_ITEM,
300            "A light with the name " + name + " already exists",
301            "SceneManager::createLight" );
302    }
303
304    Light *l = new Light(name);
305    mLights.insert(SceneLightList::value_type(name, l));
306    return l;
307}
308
309//-----------------------------------------------------------------------
310Light* SceneManager::getLight(const String& name)
311{
312    SceneLightList::iterator i = mLights.find(name);
313    if (i == mLights.end())
314    {
315        OGRE_EXCEPT( Exception::ERR_ITEM_NOT_FOUND,
316            "Cannot find Light with name " + name,
317            "SceneManager::getLight");
318    }
319    else
320    {
321        return i->second;
322    }
323}
324
325//-----------------------------------------------------------------------
326void SceneManager::removeLight(Light *l)
327{
328    // Find in list
329    SceneLightList::iterator i = mLights.begin();
330    for (; i != mLights.end(); ++i)
331    {
332        if (i->second == l)
333        {
334            mLights.erase(i);
335            delete l;
336            break;
337        }
338    }
339
340}
341
342//-----------------------------------------------------------------------
343void SceneManager::removeLight(const String& name)
344{
345    // Find in list
346    SceneLightList::iterator i = mLights.find(name);
347    if (i != mLights.end())
348    {
349        delete i->second;
350        mLights.erase(i);
351    }
352
353}
354
355//-----------------------------------------------------------------------
356void SceneManager::removeAllLights(void)
357{
358
359    SceneLightList::iterator i = mLights.begin();
360    for (; i != mLights.end(); ++i)
361    {
362        delete i->second;
363    }
364    mLights.clear();
365}
366//-----------------------------------------------------------------------
367bool SceneManager::lightLess::operator()(const Light* a, const Light* b) const
368{
369    return a->tempSquareDist < b->tempSquareDist;
370}
371//-----------------------------------------------------------------------
372void SceneManager::_populateLightList(const Vector3& position, Real radius, LightList& destList)
373{
374    // Really basic trawl of the lights, then sort
375    // Subclasses could do something smarter
376    destList.clear();
377    Real squaredRadius = radius * radius;
378
379    SceneLightList::iterator i, iend;
380    iend = mLights.end();
381    for (i = mLights.begin(); i != iend; ++i)
382    {
383        Light* lt = i->second;
384        if (lt->isVisible())
385        {
386            if (lt->getType() == Light::LT_DIRECTIONAL)
387            {
388                // No distance
389                lt->tempSquareDist = 0.0f;
390                destList.push_back(lt);
391            }
392            else
393            {
394                // Calc squared distance
395                lt->tempSquareDist = (lt->getDerivedPosition() - position).squaredLength();
396                // only add in-range lights
397                Real range = lt->getAttenuationRange();
398                if ((lt->tempSquareDist - squaredRadius) <= (range * range))
399                {
400                    destList.push_back(lt);
401                }
402            }
403        }
404    }
405
406    // Sort (stable to guarantee ordering on directional lights)
407    std::stable_sort(destList.begin(), destList.end(), lightLess());
408
409
410}
411//-----------------------------------------------------------------------
412Entity* SceneManager::createEntity(const String& entityName, PrefabType ptype)
413{
414    switch (ptype)
415    {
416    case PT_PLANE:
417        return createEntity(entityName, "Prefab_Plane");
418
419        break;
420    }
421
422    OGRE_EXCEPT( Exception::ERR_ITEM_NOT_FOUND,
423        "Unknown prefab type for entity " + entityName,
424        "SceneManager::createEntity");
425}
426
427//-----------------------------------------------------------------------
428Entity* SceneManager::createEntity(
429                                   const String& entityName,
430                                   const String& meshName )
431{
432    // Check name not used
433    EntityList::iterator it = mEntities.find( entityName );
434    if( it != mEntities.end() )
435    {
436        OGRE_EXCEPT(
437            Exception::ERR_DUPLICATE_ITEM,
438            "An entity with the name " + entityName + " already exists",
439            "SceneManager::createEntity" );
440    }
441
442    // Get mesh (load if required)
443    MeshPtr pMesh = MeshManager::getSingleton().load(
444        meshName,
445        // note that you can change the group by pre-loading the mesh
446        ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME );
447
448    // Create entity
449    Entity* e = new Entity( entityName, pMesh, this );
450
451    // Add to internal list
452    mEntities[entityName] = e; //.insert(EntityList::value_type(entityName, e));
453
454    return e;
455}
456
457//-----------------------------------------------------------------------
458Entity* SceneManager::getEntity(const String& name)
459{
460    EntityList::iterator i = mEntities.find(name);
461    if (i == mEntities.end())
462    {
463        OGRE_EXCEPT( Exception::ERR_ITEM_NOT_FOUND,
464            "Cannot find Entity with name " + name,
465            "SceneManager::getEntity");
466    }
467    else
468    {
469        return i->second;
470    }
471}
472
473//-----------------------------------------------------------------------
474void SceneManager::removeEntity(Entity *cam)
475{
476    // Find in list
477    EntityList::iterator i = mEntities.begin();
478    for (; i != mEntities.end(); ++i)
479    {
480        if (i->second == cam)
481        {
482            mEntities.erase(i);
483            delete cam;
484            break;
485        }
486    }
487
488}
489
490//-----------------------------------------------------------------------
491void SceneManager::removeEntity(const String& name)
492{
493    // Find in list
494    EntityList::iterator i = mEntities.find(name);
495    if (i != mEntities.end())
496    {
497        delete i->second;
498        mEntities.erase(i);
499    }
500
501}
502
503//-----------------------------------------------------------------------
504void SceneManager::removeAllEntities(void)
505{
506
507    EntityList::iterator i = mEntities.begin();
508    for (; i != mEntities.end(); ++i)
509    {
510        delete i->second;
511    }
512    mEntities.clear();
513}
514
515//-----------------------------------------------------------------------
516void SceneManager::removeAllBillboardSets(void)
517{
518    // Delete all BillboardSets
519    for (BillboardSetList::iterator bi = mBillboardSets.begin();
520        bi != mBillboardSets.end(); ++bi)
521    {
522        delete bi->second;
523    }
524    mBillboardSets.clear();
525}
526//-----------------------------------------------------------------------
527void SceneManager::clearScene(void)
528{
529        removeAllStaticGeometry();
530    removeAllEntities();
531    removeAllBillboardSets();
532    removeAllLights();
533
534        // Clear root node of all children
535        mSceneRoot->removeAllChildren();
536        mSceneRoot->detachAllObjects();
537
538    // Delete all SceneNodes, except root that is
539    for (SceneNodeList::iterator i = mSceneNodes.begin();
540        i != mSceneNodes.end(); ++i)
541    {
542        delete i->second;
543    }
544    mSceneNodes.clear();
545    mAutoTrackingSceneNodes.clear();
546
547
548
549    // Clear animations
550    destroyAllAnimations();
551
552    // Remove sky nodes since they've been deleted
553    mSkyBoxNode = mSkyPlaneNode = mSkyDomeNode = 0;
554    mSkyBoxEnabled = mSkyPlaneEnabled = mSkyDomeEnabled = false;
555
556}
557//-----------------------------------------------------------------------
558SceneNode* SceneManager::createSceneNode(void)
559{
560    SceneNode* sn = new SceneNode(this);
561    assert(mSceneNodes.find(sn->getName()) == mSceneNodes.end());
562    mSceneNodes[sn->getName()] = sn;
563    return sn;
564}
565//-----------------------------------------------------------------------
566SceneNode* SceneManager::createSceneNode(const String& name)
567{
568    // Check name not used
569    if (mSceneNodes.find(name) != mSceneNodes.end())
570    {
571        OGRE_EXCEPT(
572            Exception::ERR_DUPLICATE_ITEM,
573            "A scene node with the name " + name + " already exists",
574            "SceneManager::createSceneNode" );
575    }
576
577    SceneNode* sn = new SceneNode(this, name);
578    mSceneNodes[sn->getName()] = sn;
579    return sn;
580}
581//-----------------------------------------------------------------------
582void SceneManager::destroySceneNode(const String& name)
583{
584    SceneNodeList::iterator i = mSceneNodes.find(name);
585
586    if (i == mSceneNodes.end())
587    {
588        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "SceneNode '" + name + "' not found.",
589            "SceneManager::destroySceneNode");
590    }
591
592    // Find any scene nodes which are tracking this node, and turn them off
593    AutoTrackingSceneNodes::iterator ai, aiend;
594    aiend = mAutoTrackingSceneNodes.end();
595    for (ai = mAutoTrackingSceneNodes.begin(); ai != aiend; ++ai)
596    {
597        SceneNode* n = *ai;
598        // Tracking this node
599        if (n->getAutoTrackTarget() == i->second)
600        {
601            // turn off, this will notify SceneManager to remove
602            n->setAutoTracking(false);
603            // no need to reset iterator since set erase does not invalidate
604        }
605        // node is itself a tracker
606        else if (n == i->second)
607        {
608            mAutoTrackingSceneNodes.erase(ai);
609        }
610    }
611
612        // detach from parent (don't do this in destructor since bulk destruction
613        // behaves differently)
614        Node* parentNode = i->second->getParent();
615        if (parentNode)
616        {
617                parentNode->removeChild(i->second);
618        }
619    delete i->second;
620    mSceneNodes.erase(i);
621}
622//-----------------------------------------------------------------------
623SceneNode* SceneManager::getRootSceneNode(void) const
624{
625    return mSceneRoot;
626}
627//-----------------------------------------------------------------------
628SceneNode* SceneManager::getSceneNode(const String& name) const
629{
630    SceneNodeList::const_iterator i = mSceneNodes.find(name);
631
632    if (i == mSceneNodes.end())
633    {
634        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "SceneNode '" + name + "' not found.",
635            "SceneManager::getSceneNode");
636    }
637
638    return i->second;
639
640}
641//-----------------------------------------------------------------------
642Pass* SceneManager::setPass(Pass* pass)
643{
644    static bool lastUsedVertexProgram = false;
645    static bool lastUsedFragmentProgram = false;
646
647    if (mIlluminationStage == IRS_RENDER_TO_TEXTURE)
648    {
649        // Derive a special shadow caster pass from this one
650        pass = deriveShadowCasterPass(pass);
651    }
652    else if (mIlluminationStage == IRS_RENDER_MODULATIVE_PASS)
653    {
654        pass = deriveShadowReceiverPass(pass);
655    }
656
657    // TEST
658    /*
659    LogManager::getSingleton().logMessage("BEGIN PASS " + StringConverter::toString(pass->getIndex()) +
660    " of " + pass->getParent()->getParent()->getName());
661    */
662    bool passSurfaceAndLightParams = true;
663
664    if (pass->hasVertexProgram())
665    {
666        mDestRenderSystem->bindGpuProgram(pass->getVertexProgram()->_getBindingDelegate());
667        // bind parameters later since they can be per-object
668        lastUsedVertexProgram = true;
669        // does the vertex program want surface and light params passed to rendersystem?
670        passSurfaceAndLightParams = pass->getVertexProgram()->getPassSurfaceAndLightStates();
671    }
672    else
673    {
674        // Unbind program?
675        if (lastUsedVertexProgram)
676        {
677            mDestRenderSystem->unbindGpuProgram(GPT_VERTEX_PROGRAM);
678            lastUsedVertexProgram = false;
679        }
680        // Set fixed-function vertex parameters
681    }
682
683    if (passSurfaceAndLightParams)
684    {
685        // Set surface reflectance properties, only valid if lighting is enabled
686        if (pass->getLightingEnabled())
687        {
688            mDestRenderSystem->_setSurfaceParams(
689                pass->getAmbient(),
690                pass->getDiffuse(),
691                pass->getSpecular(),
692                pass->getSelfIllumination(),
693                pass->getShininess(),
694                pass->getVertexColourTracking() );
695        }
696
697        // Dynamic lighting enabled?
698        mDestRenderSystem->setLightingEnabled(pass->getLightingEnabled());
699    }
700
701    // Using a fragment program?
702    if (pass->hasFragmentProgram())
703    {
704        mDestRenderSystem->bindGpuProgram(
705            pass->getFragmentProgram()->_getBindingDelegate());
706        // bind parameters later since they can be per-object
707        lastUsedFragmentProgram = true;
708    }
709    else
710    {
711        // Unbind program?
712        if (lastUsedFragmentProgram)
713        {
714            mDestRenderSystem->unbindGpuProgram(GPT_FRAGMENT_PROGRAM);
715            lastUsedFragmentProgram = false;
716        }
717
718        // Set fixed-function fragment settings
719
720        // Fog (assumes we want pixel fog which is the usual)
721        // New fog params can either be from scene or from material
722        FogMode newFogMode;
723        ColourValue newFogColour;
724        Real newFogStart, newFogEnd, newFogDensity;
725        if (pass->getFogOverride())
726        {
727            // New fog params from material
728            newFogMode = pass->getFogMode();
729            newFogColour = pass->getFogColour();
730            newFogStart = pass->getFogStart();
731            newFogEnd = pass->getFogEnd();
732            newFogDensity = pass->getFogDensity();
733        }
734        else
735        {
736            // New fog params from scene
737            newFogMode = mFogMode;
738            newFogColour = mFogColour;
739            newFogStart = mFogStart;
740            newFogEnd = mFogEnd;
741            newFogDensity = mFogDensity;
742        }
743        mDestRenderSystem->_setFog(
744            newFogMode, newFogColour, newFogDensity, newFogStart, newFogEnd);
745
746    }
747
748    // The rest of the settings are the same no matter whether we use programs or not
749
750    // Set scene blending
751    mDestRenderSystem->_setSceneBlending(
752        pass->getSourceBlendFactor(), pass->getDestBlendFactor());
753
754
755    // Texture unit settings
756
757    Pass::TextureUnitStateIterator texIter =  pass->getTextureUnitStateIterator();
758    size_t unit = 0;
759    while(texIter.hasMoreElements())
760    {
761        TextureUnitState* pTex = texIter.getNext();
762        mDestRenderSystem->_setTextureUnitSettings(unit, *pTex);
763        ++unit;
764    }
765    // Disable remaining texture units
766    mDestRenderSystem->_disableTextureUnitsFrom(pass->getNumTextureUnitStates());
767
768    // Set up non-texture related material settings
769    // Depth buffer settings
770    mDestRenderSystem->_setDepthBufferFunction(pass->getDepthFunction());
771    mDestRenderSystem->_setDepthBufferCheckEnabled(pass->getDepthCheckEnabled());
772    mDestRenderSystem->_setDepthBufferWriteEnabled(pass->getDepthWriteEnabled());
773    mDestRenderSystem->_setDepthBias(pass->getDepthBias());
774        // Alpha-reject settings
775        mDestRenderSystem->_setAlphaRejectSettings(
776                pass->getAlphaRejectFunction(), pass->getAlphaRejectValue());
777    // Set colour write mode
778    // Right now we only use on/off, not per-channel
779    bool colWrite = pass->getColourWriteEnabled();
780    mDestRenderSystem->_setColourBufferWriteEnabled(colWrite, colWrite, colWrite, colWrite);
781    // Culling mode
782    mDestRenderSystem->_setCullingMode(pass->getCullingMode());
783    // Shading
784    mDestRenderSystem->setShadingType(pass->getShadingMode());
785
786    return pass;
787}
788//-----------------------------------------------------------------------
789void SceneManager::_renderScene(Camera* camera, Viewport* vp, bool includeOverlays)
790{
791        Root::getSingleton()._setCurrentSceneManager(this);
792    // Prep Pass for use in debug shadows
793    initShadowVolumeMaterials();
794    // Perform a quick pre-check to see whether we should override far distance
795    // When using stencil volumes we have to use infinite far distance
796    // to prevent dark caps getting clipped
797    if ((mShadowTechnique == SHADOWTYPE_STENCIL_ADDITIVE ||
798        mShadowTechnique == SHADOWTYPE_STENCIL_MODULATIVE) &&
799        camera->getFarClipDistance() != 0 &&
800        mDestRenderSystem->getCapabilities()->hasCapability(RSC_INFINITE_FAR_PLANE) &&
801        mShadowUseInfiniteFarPlane)
802    {
803        // infinite far distance
804        camera->setFarClipDistance(0);
805    }
806
807    mCameraInProgress = camera;
808    mCamChanged = true;
809
810
811    // Update the scene, only do this once per frame
812    static unsigned long lastFrameNumber = 0;
813    unsigned long thisFrameNumber = Root::getSingleton().getCurrentFrameNumber();
814    if (thisFrameNumber != lastFrameNumber)
815    {
816        // Update animations
817        _applySceneAnimations();
818        // Update controllers
819        ControllerManager::getSingleton().updateAllControllers();
820        lastFrameNumber = thisFrameNumber;
821    }
822
823    // Update scene graph for this camera (can happen multiple times per frame)
824    _updateSceneGraph(camera);
825
826    // Auto-track nodes
827    AutoTrackingSceneNodes::iterator atsni, atsniend;
828    atsniend = mAutoTrackingSceneNodes.end();
829    for (atsni = mAutoTrackingSceneNodes.begin(); atsni != atsniend; ++atsni)
830    {
831        (*atsni)->_autoTrack();
832    }
833    // Auto-track camera if required
834    camera->_autoTrack();
835
836
837    // Are we using any shadows at all?
838    if (mShadowTechnique != SHADOWTYPE_NONE &&
839        mIlluminationStage != IRS_RENDER_TO_TEXTURE)
840    {
841        // Locate any lights which could be affecting the frustum
842        findLightsAffectingFrustum(camera);
843        if (mShadowTechnique == SHADOWTYPE_TEXTURE_MODULATIVE)
844        {
845            // *******
846            // WARNING
847            // *******
848            // This call will result in re-entrant calls to this method
849            // therefore anything which comes before this is NOT
850            // guaranteed persistent. Make sure that anything which
851            // MUST be specific to this camera / target is done
852            // AFTER THIS POINT
853            prepareShadowTextures(camera, vp);
854            // reset the cameras because of the re-entrant call
855            mCameraInProgress = camera;
856            mCamChanged = true;
857        }
858    }
859
860    // Invert vertex winding?
861    if (camera->isReflected())
862    {
863        mDestRenderSystem->setInvertVertexWinding(true);
864    }
865    else
866    {
867        mDestRenderSystem->setInvertVertexWinding(false);
868    }
869
870    // Set the viewport
871    setViewport(vp);
872
873    // Tell params about camera
874    mAutoParamDataSource.setCurrentCamera(camera);
875    // Set autoparams for finite dir light extrusion
876    mAutoParamDataSource.setShadowDirLightExtrusionDistance(mShadowDirLightExtrudeDist);
877
878    // Tell params about current ambient light
879    mAutoParamDataSource.setAmbientLightColour(mAmbientLight);
880        // Tell rendersystem
881        mDestRenderSystem->setAmbientLight(mAmbientLight.r, mAmbientLight.g, mAmbientLight.b);
882
883    // Tell params about render target
884    mAutoParamDataSource.setCurrentRenderTarget(vp->getTarget());
885
886
887    // Set camera window clipping planes (if any)
888    if (mDestRenderSystem->getCapabilities()->hasCapability(RSC_USER_CLIP_PLANES))
889    {
890        if (camera->isWindowSet()) 
891        {
892            const std::vector<Plane>& planeList =
893                camera->getWindowPlanes();
894            for (ushort i = 0; i < 4; ++i)
895            {
896                mDestRenderSystem->enableClipPlane(i, true);
897                mDestRenderSystem->setClipPlane(i, planeList[i]);
898            }
899        }
900        else
901        {
902            for (ushort i = 0; i < 4; ++i)
903            {
904                mDestRenderSystem->enableClipPlane(i, false);
905            }
906        }
907    }
908
909    // Clear the render queue
910    getRenderQueue()->clear();
911
912    // Parse the scene and tag visibles
913    _findVisibleObjects(camera,
914        mIlluminationStage == IRS_RENDER_TO_TEXTURE? true : false);
915    // Add overlays, if viewport deems it
916    if (vp->getOverlaysEnabled())
917    {
918        OverlayManager::getSingleton()._queueOverlaysForRendering(camera, getRenderQueue(), vp);
919    }
920    // Queue skies
921    _queueSkiesForRendering(camera);
922
923
924    // Don't do view / proj here anymore
925    // Checked per renderable now, although only changed when required
926    //mDestRenderSystem->_setViewMatrix(camera->getViewMatrix());
927    //mDestRenderSystem->_setProjectionMatrix(camera->getProjectionMatrix());
928
929    mDestRenderSystem->_beginGeometryCount();
930    // Begin the frame
931    mDestRenderSystem->_beginFrame();
932
933    // Set rasterisation mode
934    mDestRenderSystem->_setRasterisationMode(camera->getDetailLevel());
935
936    // Render scene content
937    _renderVisibleObjects();
938
939    // End frame
940    mDestRenderSystem->_endFrame();
941
942    // Notify camera or vis faces
943    camera->_notifyRenderedFaces(mDestRenderSystem->_getFaceCount());
944
945
946
947}
948
949
950//-----------------------------------------------------------------------
951void SceneManager::_setDestinationRenderSystem(RenderSystem* sys)
952{
953    mDestRenderSystem = sys;
954
955}
956
957
958//-----------------------------------------------------------------------
959void SceneManager::setWorldGeometry(const String& filename)
960{
961    // This default implementation cannot handle world geometry
962    OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
963        "World geometry is not supported by the generic SceneManager.",
964        "SceneManager::setWorldGeometry");
965}
966
967//-----------------------------------------------------------------------
968bool SceneManager::materialLess::operator() (const Material* x, const Material* y) const
969{
970    // If x transparent and y not, x > y (since x has to overlap y)
971    if (x->isTransparent() && !y->isTransparent())
972    {
973        return false;
974    }
975    // If y is transparent and x not, x < y
976    else if (!x->isTransparent() && y->isTransparent())
977    {
978        return true;
979    }
980    else
981    {
982        // Otherwise don't care (both transparent or both solid)
983        // Just arbitrarily use pointer
984        return x < y;
985    }
986
987}
988
989//-----------------------------------------------------------------------
990void SceneManager::setSkyPlane(
991                               bool enable,
992                               const Plane& plane,
993                               const String& materialName,
994                               Real gscale,
995                               Real tiling,
996                               bool drawFirst,
997                               Real bow,
998                               int xsegments, int ysegments,
999                               const String& groupName)
1000{
1001    if (enable)
1002    {
1003        String meshName = "SkyPlane";
1004        mSkyPlane = plane;
1005
1006        MaterialPtr m = MaterialManager::getSingleton().getByName(materialName);
1007        if (m.isNull())
1008        {
1009            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
1010                "Sky plane material '" + materialName + "' not found.",
1011                "SceneManager::setSkyPlane");
1012        }
1013        // Make sure the material doesn't update the depth buffer
1014        m->setDepthWriteEnabled(false);
1015        // Ensure loaded
1016        m->load();
1017
1018        mSkyPlaneDrawFirst = drawFirst;
1019
1020        // Set up the plane
1021        MeshPtr planeMesh = MeshManager::getSingleton().getByName(meshName);
1022        if (!planeMesh.isNull())
1023        {
1024            // Destroy the old one
1025            MeshManager::getSingleton().remove(planeMesh->getHandle());
1026        }
1027
1028        // Create up vector
1029        Vector3 up = plane.normal.crossProduct(Vector3::UNIT_X);
1030        if (up == Vector3::ZERO)
1031            up = plane.normal.crossProduct(-Vector3::UNIT_Z);
1032
1033        // Create skyplane
1034        if( bow > 0 )
1035        {
1036            // Build a curved skyplane
1037            planeMesh = MeshManager::getSingleton().createCurvedPlane(
1038                meshName, groupName, plane, gscale * 100, gscale * 100, gscale * bow * 100,
1039                xsegments, ysegments, false, 1, tiling, tiling, up);
1040        }
1041        else
1042        {
1043            planeMesh = MeshManager::getSingleton().createPlane(
1044                meshName, groupName, plane, gscale * 100, gscale * 100, xsegments, ysegments, false,
1045                1, tiling, tiling, up);
1046        }
1047
1048        // Create entity
1049        if (mSkyPlaneEntity)
1050        {
1051            // destroy old one, do it by name for speed
1052            removeEntity(meshName);
1053        }
1054        // Create, use the same name for mesh and entity
1055        mSkyPlaneEntity = createEntity(meshName, meshName);
1056        mSkyPlaneEntity->setMaterialName(materialName);
1057        mSkyPlaneEntity->setCastShadows(false);
1058
1059        // Create node and attach
1060        if (!mSkyPlaneNode)
1061        {
1062            mSkyPlaneNode = createSceneNode(meshName + "Node");
1063        }
1064        else
1065        {
1066            mSkyPlaneNode->detachAllObjects();
1067        }
1068        mSkyPlaneNode->attachObject(mSkyPlaneEntity);
1069
1070    }
1071        mSkyPlaneEnabled = enable;
1072}
1073//-----------------------------------------------------------------------
1074void SceneManager::setSkyBox(
1075                             bool enable,
1076                             const String& materialName,
1077                             Real distance,
1078                             bool drawFirst,
1079                             const Quaternion& orientation,
1080                             const String& groupName)
1081{
1082    if (enable)
1083    {
1084        MaterialPtr m = MaterialManager::getSingleton().getByName(materialName);
1085        if (m.isNull())
1086        {
1087            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
1088                "Sky box material '" + materialName + "' not found.",
1089                "SceneManager::setSkyBox");
1090        }
1091        // Make sure the material doesn't update the depth buffer
1092        m->setDepthWriteEnabled(false);
1093        // Ensure loaded
1094        m->load();
1095        // Also clamp texture, don't wrap (otherwise edges can get filtered)
1096        m->getBestTechnique()->getPass(0)->getTextureUnitState(0)->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
1097
1098
1099        mSkyBoxDrawFirst = drawFirst;
1100
1101        // Create node
1102        if (!mSkyBoxNode)
1103        {
1104            mSkyBoxNode = createSceneNode("SkyBoxNode");
1105        }
1106        else
1107        {
1108            mSkyBoxNode->detachAllObjects();
1109        }
1110
1111        MaterialManager& matMgr = MaterialManager::getSingleton();
1112        // Set up the box (6 planes)
1113        for (int i = 0; i < 6; ++i)
1114        {
1115            MeshPtr planeMesh = createSkyboxPlane((BoxPlane)i, distance, orientation, groupName);
1116            String entName = "SkyBoxPlane" + StringConverter::toString(i);
1117
1118            // Create entity
1119            if (mSkyBoxEntity[i])
1120            {
1121                // destroy old one, do it by name for speed
1122                removeEntity(entName);
1123            }
1124            mSkyBoxEntity[i] = createEntity(entName, planeMesh->getName());
1125            mSkyBoxEntity[i]->setCastShadows(false);
1126            // Have to create 6 materials, one for each frame
1127            // Used to use combined material but now we're using queue we can't split to change frame
1128            // This doesn't use much memory because textures aren't duplicated
1129            MaterialPtr boxMat = matMgr.getByName(entName);
1130            if (boxMat.isNull())
1131            {
1132                // Create new by clone
1133                boxMat = m->clone(entName);
1134                boxMat->load();
1135            }
1136            else
1137            {
1138                // Copy over existing
1139                m->copyDetailsTo(boxMat);
1140                boxMat->load();
1141            }
1142            // Set active frame
1143            boxMat->getBestTechnique()->getPass(0)->getTextureUnitState(0)
1144                ->setCurrentFrame(i);
1145
1146            mSkyBoxEntity[i]->setMaterialName(boxMat->getName());
1147
1148            // Attach to node
1149            mSkyBoxNode->attachObject(mSkyBoxEntity[i]);
1150        } // for each plane
1151
1152    }
1153        mSkyBoxEnabled = enable;
1154}
1155//-----------------------------------------------------------------------
1156void SceneManager::setSkyDome(
1157                              bool enable,
1158                              const String& materialName,
1159                              Real curvature,
1160                              Real tiling,
1161                              Real distance,
1162                              bool drawFirst,
1163                              const Quaternion& orientation,
1164                              int xsegments, int ysegments, int ySegmentsToKeep,
1165                              const String& groupName)
1166{
1167    if (enable)
1168    {
1169        MaterialPtr m = MaterialManager::getSingleton().getByName(materialName);
1170        if (m.isNull())
1171        {
1172            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
1173                "Sky dome material '" + materialName + "' not found.",
1174                "SceneManager::setSkyDome");
1175        }
1176        // Make sure the material doesn't update the depth buffer
1177        m->setDepthWriteEnabled(false);
1178        // Ensure loaded
1179        m->load();
1180
1181        mSkyDomeDrawFirst = drawFirst;
1182
1183        // Create node
1184        if (!mSkyDomeNode)
1185        {
1186            mSkyDomeNode = createSceneNode("SkyDomeNode");
1187        }
1188        else
1189        {
1190            mSkyDomeNode->detachAllObjects();
1191        }
1192
1193        // Set up the dome (5 planes)
1194        for (int i = 0; i < 5; ++i)
1195        {
1196            MeshPtr planeMesh = createSkydomePlane((BoxPlane)i, curvature,
1197                tiling, distance, orientation, xsegments, ysegments,
1198                i!=BP_UP ? ySegmentsToKeep : -1, groupName);
1199
1200            String entName = "SkyDomePlane" + StringConverter::toString(i);
1201
1202            // Create entity
1203            if (mSkyDomeEntity[i])
1204            {
1205                // destroy old one, do it by name for speed
1206                removeEntity(entName);
1207            }
1208            mSkyDomeEntity[i] = createEntity(entName, planeMesh->getName());
1209            mSkyDomeEntity[i]->setMaterialName(m->getName());
1210            mSkyDomeEntity[i]->setCastShadows(false);
1211
1212            // Attach to node
1213            mSkyDomeNode->attachObject(mSkyDomeEntity[i]);
1214        } // for each plane
1215
1216    }
1217        mSkyDomeEnabled = enable;
1218}
1219//-----------------------------------------------------------------------
1220MeshPtr SceneManager::createSkyboxPlane(
1221                                      BoxPlane bp,
1222                                      Real distance,
1223                                      const Quaternion& orientation,
1224                                      const String& groupName)
1225{
1226    Plane plane;
1227    String meshName;
1228    Vector3 up;
1229
1230    meshName = "SkyBoxPlane_";
1231    // Set up plane equation
1232    plane.d = distance;
1233    switch(bp)
1234    {
1235    case BP_FRONT:
1236        plane.normal = Vector3::UNIT_Z;
1237        up = Vector3::UNIT_Y;
1238        meshName += "Front";
1239        break;
1240    case BP_BACK:
1241        plane.normal = -Vector3::UNIT_Z;
1242        up = Vector3::UNIT_Y;
1243        meshName += "Back";
1244        break;
1245    case BP_LEFT:
1246        plane.normal = Vector3::UNIT_X;
1247        up = Vector3::UNIT_Y;
1248        meshName += "Left";
1249        break;
1250    case BP_RIGHT:
1251        plane.normal = -Vector3::UNIT_X;
1252        up = Vector3::UNIT_Y;
1253        meshName += "Right";
1254        break;
1255    case BP_UP:
1256        plane.normal = -Vector3::UNIT_Y;
1257        up = Vector3::UNIT_Z;
1258        meshName += "Up";
1259        break;
1260    case BP_DOWN:
1261        plane.normal = Vector3::UNIT_Y;
1262        up = -Vector3::UNIT_Z;
1263        meshName += "Down";
1264        break;
1265    }
1266    // Modify by orientation
1267    plane.normal = orientation * plane.normal;
1268    up = orientation * up;
1269
1270
1271    // Check to see if existing plane
1272    MeshManager& mm = MeshManager::getSingleton();
1273    MeshPtr planeMesh = mm.getByName(meshName);
1274    if(!planeMesh.isNull())
1275    {
1276        // destroy existing
1277        mm.remove(planeMesh->getHandle());
1278    }
1279    // Create new
1280    Real planeSize = distance * 2;
1281    const int BOX_SEGMENTS = 1;
1282    planeMesh = mm.createPlane(meshName, groupName, plane, planeSize, planeSize,
1283        BOX_SEGMENTS, BOX_SEGMENTS, false, 1, 1, 1, up);
1284
1285    //planeMesh->_dumpContents(meshName);
1286
1287    return planeMesh;
1288
1289}
1290//-----------------------------------------------------------------------
1291MeshPtr SceneManager::createSkydomePlane(
1292                                       BoxPlane bp,
1293                                       Real curvature,
1294                                       Real tiling,
1295                                       Real distance,
1296                                       const Quaternion& orientation,
1297                                       int xsegments, int ysegments, int ysegments_keep,
1298                                       const String& groupName)
1299{
1300
1301    Plane plane;
1302    String meshName;
1303    Vector3 up;
1304
1305    meshName = "SkyDomePlane_";
1306    // Set up plane equation
1307    plane.d = distance;
1308    switch(bp)
1309    {
1310    case BP_FRONT:
1311        plane.normal = Vector3::UNIT_Z;
1312        up = Vector3::UNIT_Y;
1313        meshName += "Front";
1314        break;
1315    case BP_BACK:
1316        plane.normal = -Vector3::UNIT_Z;
1317        up = Vector3::UNIT_Y;
1318        meshName += "Back";
1319        break;
1320    case BP_LEFT:
1321        plane.normal = Vector3::UNIT_X;
1322        up = Vector3::UNIT_Y;
1323        meshName += "Left";
1324        break;
1325    case BP_RIGHT:
1326        plane.normal = -Vector3::UNIT_X;
1327        up = Vector3::UNIT_Y;
1328        meshName += "Right";
1329        break;
1330    case BP_UP:
1331        plane.normal = -Vector3::UNIT_Y;
1332        up = Vector3::UNIT_Z;
1333        meshName += "Up";
1334        break;
1335    case BP_DOWN:
1336        // no down
1337        return MeshPtr();
1338    }
1339    // Modify by orientation
1340    plane.normal = orientation * plane.normal;
1341    up = orientation * up;
1342
1343    // Check to see if existing plane
1344    MeshManager& mm = MeshManager::getSingleton();
1345    MeshPtr planeMesh = mm.getByName(meshName);
1346    if(!planeMesh.isNull())
1347    {
1348        // destroy existing
1349        mm.remove(planeMesh->getHandle());
1350    }
1351    // Create new
1352    Real planeSize = distance * 2;
1353    planeMesh = mm.createCurvedIllusionPlane(meshName, groupName, plane,
1354        planeSize, planeSize, curvature,
1355        xsegments, ysegments, false, 1, tiling, tiling, up,
1356        orientation, HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, HardwareBuffer::HBU_STATIC_WRITE_ONLY,
1357        false, false, ysegments_keep);
1358
1359    //planeMesh->_dumpContents(meshName);
1360
1361    return planeMesh;
1362
1363}
1364
1365
1366//-----------------------------------------------------------------------
1367void SceneManager::_updateSceneGraph(Camera* cam)
1368{
1369    // Cascade down the graph updating transforms & world bounds
1370    // In this implementation, just update from the root
1371    // Smarter SceneManager subclasses may choose to update only
1372    //   certain scene graph branches
1373    mSceneRoot->_update(true, false);
1374
1375
1376}
1377//-----------------------------------------------------------------------
1378void SceneManager::_findVisibleObjects(Camera* cam, bool onlyShadowCasters)
1379{
1380    // Tell nodes to find, cascade down all nodes
1381    mSceneRoot->_findVisibleObjects(cam, getRenderQueue(), true,
1382        mDisplayNodes, onlyShadowCasters);
1383
1384}
1385//-----------------------------------------------------------------------
1386void SceneManager::_renderVisibleObjects(void)
1387{
1388    // Render each separate queue
1389    RenderQueue::QueueGroupIterator queueIt = getRenderQueue()->_getQueueGroupIterator();
1390
1391    // NB only queues which have been created are rendered, no time is wasted
1392    //   parsing through non-existent queues (even though there are 10 available)
1393
1394    while (queueIt.hasMoreElements())
1395    {
1396        // Get queue group id
1397        RenderQueueGroupID qId = queueIt.peekNextKey();
1398                RenderQueueGroup* pGroup = queueIt.getNext();
1399                // Skip this one if not to be processed
1400                if (!isRenderQueueToBeProcessed(qId))
1401                        continue;
1402
1403
1404        bool repeatQueue = false;
1405        do // for repeating queues
1406        {
1407            // Fire queue started event
1408            if (fireRenderQueueStarted(qId))
1409            {
1410                // Someone requested we skip this queue
1411                continue;
1412            }
1413
1414            renderQueueGroupObjects(pGroup);
1415
1416            // Fire queue ended event
1417            if (fireRenderQueueEnded(qId))
1418            {
1419                // Someone requested we repeat this queue
1420                repeatQueue = true;
1421            }
1422            else
1423            {
1424                repeatQueue = false;
1425            }
1426        } while (repeatQueue);
1427
1428    } // for each queue group
1429
1430}
1431//-----------------------------------------------------------------------
1432void SceneManager::renderAdditiveStencilShadowedQueueGroupObjects(RenderQueueGroup* pGroup)
1433{
1434    RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator();
1435    LightList lightList;
1436
1437    while (groupIt.hasMoreElements())
1438    {
1439        RenderPriorityGroup* pPriorityGrp = groupIt.getNext();
1440
1441        // Sort the queue first
1442        pPriorityGrp->sort(mCameraInProgress);
1443
1444        // Clear light list
1445        lightList.clear();
1446
1447        // Render all the ambient passes first, no light iteration, no lights
1448        mIlluminationStage = IRS_AMBIENT;
1449        renderObjects(pPriorityGrp->_getSolidPasses(), false, &lightList);
1450        // Also render any objects which have receive shadows disabled
1451        renderObjects(pPriorityGrp->_getSolidPassesNoShadow(), true);
1452
1453
1454        // Now iterate per light
1455        mIlluminationStage = IRS_PER_LIGHT;
1456
1457        // Iterate over lights, render all volumes to stencil
1458        LightList::const_iterator li, liend;
1459        liend = mLightsAffectingFrustum.end();
1460
1461        for (li = mLightsAffectingFrustum.begin(); li != liend; ++li)
1462        {
1463            Light* l = *li;
1464            // Set light state
1465
1466            if (l->getCastShadows())
1467            {
1468                // Clear stencil
1469                mDestRenderSystem->clearFrameBuffer(FBT_STENCIL);
1470                renderShadowVolumesToStencil(l, mCameraInProgress);
1471                // turn stencil check on
1472                mDestRenderSystem->setStencilCheckEnabled(true);
1473                // NB we render where the stencil is equal to zero to render lit areas
1474                mDestRenderSystem->setStencilBufferParams(CMPF_EQUAL, 0);
1475            }
1476
1477            // render lighting passes for this light
1478            if (lightList.empty())
1479                lightList.push_back(l);
1480            else
1481                lightList[0] = l;
1482            renderObjects(pPriorityGrp->_getSolidPassesDiffuseSpecular(), false, &lightList);
1483
1484            // Reset stencil params
1485            mDestRenderSystem->setStencilBufferParams();
1486            mDestRenderSystem->setStencilCheckEnabled(false);
1487            mDestRenderSystem->_setDepthBufferParams();
1488
1489        }// for each light
1490
1491
1492        // Now render decal passes, no need to set lights as lighting will be disabled
1493        mIlluminationStage = IRS_DECAL;
1494        renderObjects(pPriorityGrp->_getSolidPassesDecal(), false);
1495
1496
1497    }// for each priority
1498
1499    // reset lighting stage
1500    mIlluminationStage = IRS_NONE;
1501
1502    // Iterate again - variable name changed to appease gcc.
1503    RenderQueueGroup::PriorityMapIterator groupIt2 = pGroup->getIterator();
1504    while (groupIt2.hasMoreElements())
1505    {
1506        RenderPriorityGroup* pPriorityGrp = groupIt2.getNext();
1507
1508        // Do transparents
1509        renderObjects(pPriorityGrp->_getTransparentPasses(), true);
1510
1511    }// for each priority
1512
1513
1514}
1515//-----------------------------------------------------------------------
1516void SceneManager::renderModulativeStencilShadowedQueueGroupObjects(RenderQueueGroup* pGroup)
1517{
1518    /* For each light, we need to render all the solids from each group,
1519    then do the modulative shadows, then render the transparents from
1520    each group.
1521    Now, this means we are going to reorder things more, but that it required
1522    if the shadows are to look correct. The overall order is preserved anyway,
1523    it's just that all the transparents are at the end instead of them being
1524    interleaved as in the normal rendering loop.
1525    */
1526    // Iterate through priorities
1527    RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator();
1528
1529    while (groupIt.hasMoreElements())
1530    {
1531        RenderPriorityGroup* pPriorityGrp = groupIt.getNext();
1532
1533        // Sort the queue first
1534        pPriorityGrp->sort(mCameraInProgress);
1535
1536        // Do (shadowable) solids
1537        renderObjects(pPriorityGrp->_getSolidPasses(), true);
1538    }
1539
1540
1541    // Iterate over lights, render all volumes to stencil
1542    LightList::const_iterator li, liend;
1543    liend = mLightsAffectingFrustum.end();
1544
1545    for (li = mLightsAffectingFrustum.begin(); li != liend; ++li)
1546    {
1547        Light* l = *li;
1548        if (l->getCastShadows())
1549        {
1550            // Clear stencil
1551            mDestRenderSystem->clearFrameBuffer(FBT_STENCIL);
1552            renderShadowVolumesToStencil(l, mCameraInProgress);
1553            // render full-screen shadow modulator for all lights
1554            setPass(mShadowModulativePass);
1555            // turn stencil check on
1556            mDestRenderSystem->setStencilCheckEnabled(true);
1557            // NB we render where the stencil is not equal to zero to render shadows, not lit areas
1558            mDestRenderSystem->setStencilBufferParams(CMPF_NOT_EQUAL, 0);
1559            renderSingleObject(mFullScreenQuad, mShadowModulativePass, false);
1560            // Reset stencil params
1561            mDestRenderSystem->setStencilBufferParams();
1562            mDestRenderSystem->setStencilCheckEnabled(false);
1563            mDestRenderSystem->_setDepthBufferParams();
1564        }
1565
1566    }// for each light
1567
1568    // Iterate again - variable name changed to appease gcc.
1569    RenderQueueGroup::PriorityMapIterator groupIt2 = pGroup->getIterator();
1570    while (groupIt2.hasMoreElements())
1571    {
1572        RenderPriorityGroup* pPriorityGrp = groupIt2.getNext();
1573
1574        // Do non-shadowable solids
1575        renderObjects(pPriorityGrp->_getSolidPassesNoShadow(), true);
1576
1577    }// for each priority
1578
1579
1580    // Iterate again - variable name changed to appease gcc.
1581    RenderQueueGroup::PriorityMapIterator groupIt3 = pGroup->getIterator();
1582    while (groupIt3.hasMoreElements())
1583    {
1584        RenderPriorityGroup* pPriorityGrp = groupIt3.getNext();
1585
1586        // Do transparents
1587        renderObjects(pPriorityGrp->_getTransparentPasses(), true);
1588
1589    }// for each priority
1590
1591}
1592//-----------------------------------------------------------------------
1593void SceneManager::renderTextureShadowCasterQueueGroupObjects(RenderQueueGroup* pGroup)
1594{
1595    static LightList nullLightList;
1596    // This is like the basic group render, except we skip all transparents
1597    // and we also render any non-shadowed objects
1598    // Note that non-shadow casters will have already been eliminated during
1599    // _findVisibleObjects
1600
1601    // Iterate through priorities
1602    RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator();
1603
1604    // Override auto param ambient to force vertex programs and fixed function to
1605    // use shadow colour
1606    mAutoParamDataSource.setAmbientLightColour(mShadowColour);
1607    mDestRenderSystem->setAmbientLight(mShadowColour.r, mShadowColour.g, mShadowColour.b);
1608
1609    while (groupIt.hasMoreElements())
1610    {
1611        RenderPriorityGroup* pPriorityGrp = groupIt.getNext();
1612
1613        // Sort the queue first
1614        pPriorityGrp->sort(mCameraInProgress);
1615
1616        // Do solids, override light list incase any vertex programs use them
1617        renderObjects(pPriorityGrp->_getSolidPasses(), false, &nullLightList);
1618        renderObjects(pPriorityGrp->_getSolidPassesNoShadow(), false, &nullLightList);
1619                // Do transparents that cast shadows
1620                renderTransparentShadowCasterObjects(
1621                                pPriorityGrp->_getTransparentPasses(), false, &nullLightList);
1622
1623
1624    }// for each priority
1625
1626    // reset ambient light
1627    mAutoParamDataSource.setAmbientLightColour(mAmbientLight);
1628    mDestRenderSystem->setAmbientLight(mAmbientLight.r, mAmbientLight.g, mAmbientLight.b);
1629}
1630//-----------------------------------------------------------------------
1631void SceneManager::renderModulativeTextureShadowedQueueGroupObjects(RenderQueueGroup* pGroup)
1632{
1633    /* For each light, we need to render all the solids from each group,
1634    then do the modulative shadows, then render the transparents from
1635    each group.
1636    Now, this means we are going to reorder things more, but that it required
1637    if the shadows are to look correct. The overall order is preserved anyway,
1638    it's just that all the transparents are at the end instead of them being
1639    interleaved as in the normal rendering loop.
1640    */
1641    // Iterate through priorities
1642    RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator();
1643
1644    while (groupIt.hasMoreElements())
1645    {
1646        RenderPriorityGroup* pPriorityGrp = groupIt.getNext();
1647
1648        // Sort the queue first
1649        pPriorityGrp->sort(mCameraInProgress);
1650
1651        // Do solids
1652        renderObjects(pPriorityGrp->_getSolidPasses(), true);
1653        renderObjects(pPriorityGrp->_getSolidPassesNoShadow(), true);
1654    }
1655
1656
1657    // Iterate over lights, render received shadows
1658    // only perform this if we're in the 'normal' render stage, to avoid
1659    // doing it during the render to texture
1660    if (mIlluminationStage == IRS_NONE)
1661    {
1662        mIlluminationStage = IRS_RENDER_MODULATIVE_PASS;
1663
1664        LightList::iterator i, iend;
1665        ShadowTextureList::iterator si, siend;
1666        iend = mLightsAffectingFrustum.end();
1667        siend = mShadowTextures.end();
1668        for (i = mLightsAffectingFrustum.begin(), si = mShadowTextures.begin();
1669            i != iend && si != siend; ++i)
1670        {
1671            Light* l = *i;
1672
1673            if (!l->getCastShadows())
1674                continue;
1675
1676            mCurrentShadowTexture = *si;
1677            // Hook up receiver texture
1678            mShadowReceiverPass->getTextureUnitState(0)->setTextureName(
1679                mCurrentShadowTexture->getName());
1680            // Hook up projection frustum
1681            mShadowReceiverPass->getTextureUnitState(0)->setProjectiveTexturing(
1682                true, mCurrentShadowTexture->getViewport(0)->getCamera());
1683            mAutoParamDataSource.setTextureProjector(
1684                mCurrentShadowTexture->getViewport(0)->getCamera());
1685            // if this light is a spotlight, we need to add the spot fader layer
1686            if (l->getType() == Light::LT_SPOTLIGHT)
1687            {
1688                // Add spot fader if not present already
1689                if (mShadowReceiverPass->getNumTextureUnitStates() == 1)
1690                {
1691                    TextureUnitState* t =
1692                        mShadowReceiverPass->createTextureUnitState("spot_shadow_fade.png");
1693                    t->setProjectiveTexturing(
1694                        true, mCurrentShadowTexture->getViewport(0)->getCamera());
1695                    t->setColourOperation(LBO_ADD);
1696                    t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
1697                }
1698                else
1699                {
1700                    // Just set projector
1701                    TextureUnitState* t =
1702                        mShadowReceiverPass->getTextureUnitState(1);
1703                    t->setProjectiveTexturing(
1704                        true, mCurrentShadowTexture->getViewport(0)->getCamera());
1705                }
1706            }
1707            else if (mShadowReceiverPass->getNumTextureUnitStates() > 1)
1708            {
1709                // remove spot fader layer
1710                mShadowReceiverPass->removeTextureUnitState(1);
1711
1712            }
1713            mShadowReceiverPass->_load();
1714
1715            if (l->getCastShadows() && pGroup->getShadowsEnabled())
1716            {
1717                renderTextureShadowReceiverQueueGroupObjects(pGroup);
1718            }
1719
1720            ++si;
1721
1722        }// for each light
1723
1724        mIlluminationStage = IRS_NONE;
1725
1726    }
1727
1728    // Iterate again - variable name changed to appease gcc.
1729    RenderQueueGroup::PriorityMapIterator groupIt3 = pGroup->getIterator();
1730    while (groupIt3.hasMoreElements())
1731    {
1732        RenderPriorityGroup* pPriorityGrp = groupIt3.getNext();
1733
1734        // Do transparents
1735        renderObjects(pPriorityGrp->_getTransparentPasses(), true);
1736
1737    }// for each priority
1738
1739}
1740//-----------------------------------------------------------------------
1741void SceneManager::renderTextureShadowReceiverQueueGroupObjects(RenderQueueGroup* pGroup)
1742{
1743    static LightList nullLightList;
1744
1745    // Iterate through priorities
1746    RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator();
1747
1748    // Override auto param ambient to force vertex programs to go full-bright
1749    mAutoParamDataSource.setAmbientLightColour(ColourValue::White);
1750    mDestRenderSystem->setAmbientLight(1, 1, 1);
1751
1752    while (groupIt.hasMoreElements())
1753    {
1754        RenderPriorityGroup* pPriorityGrp = groupIt.getNext();
1755
1756        // Do solids, override light list incase any vertex programs use them
1757        renderObjects(pPriorityGrp->_getSolidPasses(), false, &nullLightList);
1758
1759        // Don't render transparents or passes which have shadow receipt disabled
1760
1761    }// for each priority
1762
1763    // reset ambient
1764    mAutoParamDataSource.setAmbientLightColour(mAmbientLight);
1765    mDestRenderSystem->setAmbientLight(mAmbientLight.r, mAmbientLight.g, mAmbientLight.b);
1766
1767}
1768//-----------------------------------------------------------------------
1769bool SceneManager::validatePassForRendering(Pass* pass)
1770{
1771    // Bypass if we're doing a texture shadow render and
1772    // this pass is after the first (only 1 pass needed for shadow texture)
1773    if ((mIlluminationStage == IRS_RENDER_TO_TEXTURE ||
1774        mIlluminationStage == IRS_RENDER_MODULATIVE_PASS) &&
1775        pass->getIndex() > 0)
1776    {
1777        return false;
1778    }
1779
1780    return true;
1781}
1782//-----------------------------------------------------------------------
1783bool SceneManager::validateRenderableForRendering(Pass* pass, Renderable* rend)
1784{
1785    // Skip this renderable if we're doing texture shadows, it casts shadows
1786    // and we're doing the render receivers pass and we're not self-shadowing
1787    if (mShadowTechnique == SHADOWTYPE_TEXTURE_MODULATIVE &&
1788        mIlluminationStage == IRS_RENDER_MODULATIVE_PASS &&
1789        rend->getCastsShadows() && !mShadowTextureSelfShadow)
1790    {
1791        return false;
1792    }
1793
1794    return true;
1795
1796}
1797//-----------------------------------------------------------------------
1798void SceneManager::renderObjects(
1799                                 const RenderPriorityGroup::SolidRenderablePassMap& objs, bool doLightIteration,
1800                                 const LightList* manualLightList)
1801{
1802    // ----- SOLIDS LOOP -----
1803    RenderPriorityGroup::SolidRenderablePassMap::const_iterator ipass, ipassend;
1804    ipassend = objs.end();
1805    for (ipass = objs.begin(); ipass != ipassend; ++ipass)
1806    {
1807        // Fast bypass if this group is now empty
1808        if (ipass->second->empty()) continue;
1809
1810        // Give SM a chance to eliminate this pass
1811        if (!validatePassForRendering(ipass->first))
1812            continue;
1813
1814        // For solids, we try to do each pass in turn
1815        Pass* usedPass = setPass(ipass->first);
1816        RenderPriorityGroup::RenderableList* rendList = ipass->second;
1817        RenderPriorityGroup::RenderableList::const_iterator irend, irendend;
1818        irendend = rendList->end();
1819        for (irend = rendList->begin(); irend != irendend; ++irend)
1820        {
1821            // Give SM a chance to eliminate
1822            if (!validateRenderableForRendering(ipass->first, *irend))
1823                continue;
1824            // Render a single object, this will set up auto params if required
1825            renderSingleObject(*irend, usedPass, doLightIteration, manualLightList);
1826        }
1827    }
1828}
1829//-----------------------------------------------------------------------
1830void SceneManager::renderObjects(
1831                                 const RenderPriorityGroup::TransparentRenderablePassList& objs, bool doLightIteration,
1832                                 const LightList* manualLightList)
1833{
1834    // ----- TRANSPARENT LOOP -----
1835    // This time we render by Z, not by pass
1836    // The mTransparentObjects set needs to be ordered first
1837    // Render each non-transparent entity in turn, grouped by material
1838    RenderPriorityGroup::TransparentRenderablePassList::const_iterator itrans, itransend;
1839
1840    itransend = objs.end();
1841    for (itrans = objs.begin();
1842        itrans != itransend; ++itrans)
1843    {
1844        // For transparents, we have to accept that we can't sort entirely by pass
1845        setPass(itrans->pass);
1846        renderSingleObject(itrans->renderable, itrans->pass, doLightIteration,
1847            manualLightList);
1848    }
1849
1850}
1851//-----------------------------------------------------------------------
1852void SceneManager::renderQueueGroupObjects(RenderQueueGroup* pGroup)
1853{
1854    if (pGroup->getShadowsEnabled() &&
1855        mShadowTechnique == SHADOWTYPE_STENCIL_ADDITIVE)
1856    {
1857        // Additive stencil shadows in use
1858        renderAdditiveStencilShadowedQueueGroupObjects(pGroup);
1859    }
1860    else if (pGroup->getShadowsEnabled() &&
1861        mShadowTechnique == SHADOWTYPE_STENCIL_MODULATIVE)
1862    {
1863        // Modulative stencil shadows in use
1864        renderModulativeStencilShadowedQueueGroupObjects(pGroup);
1865    }
1866    else if (mShadowTechnique == SHADOWTYPE_TEXTURE_MODULATIVE)
1867    {
1868        // Modulative texture shadows in use
1869        if (mIlluminationStage == IRS_RENDER_TO_TEXTURE)
1870        {
1871            // Shadow caster pass
1872            if (pGroup->getShadowsEnabled())
1873                renderTextureShadowCasterQueueGroupObjects(pGroup);
1874        }
1875        else
1876        {
1877            // Ordinary pass
1878            renderModulativeTextureShadowedQueueGroupObjects(pGroup);
1879        }
1880    }
1881    else
1882    {
1883        // No shadows, ordinary pass
1884        renderBasicQueueGroupObjects(pGroup);
1885    }
1886
1887
1888}
1889//-----------------------------------------------------------------------
1890void SceneManager::renderBasicQueueGroupObjects(RenderQueueGroup* pGroup)
1891{
1892    // Basic render loop
1893    // Iterate through priorities
1894    RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator();
1895
1896    while (groupIt.hasMoreElements())
1897    {
1898        RenderPriorityGroup* pPriorityGrp = groupIt.getNext();
1899
1900        // Sort the queue first
1901        pPriorityGrp->sort(mCameraInProgress);
1902
1903        // Do solids
1904        renderObjects(pPriorityGrp->_getSolidPasses(), true);
1905        // Do transparents
1906        renderObjects(pPriorityGrp->_getTransparentPasses(), true);
1907
1908
1909    }// for each priority
1910}
1911//-----------------------------------------------------------------------
1912void SceneManager::renderTransparentShadowCasterObjects(
1913        const RenderPriorityGroup::TransparentRenderablePassList& objs, bool doLightIteration,
1914        const LightList* manualLightList)
1915{
1916        // ----- TRANSPARENT LOOP as in renderObjects above, but changed a bit -----
1917        RenderPriorityGroup::TransparentRenderablePassList::const_iterator itrans, itransend;
1918
1919        itransend = objs.end();
1920        for (itrans = objs.begin();
1921                itrans != itransend; ++itrans)
1922        {
1923                Renderable *r = itrans->renderable;
1924                Pass *p = itrans->pass;
1925
1926                // only render this pass if it's being forced to cast shadows
1927                if (p->getParent()->getParent()->getTransparencyCastsShadows())
1928                {
1929                        setPass(p);
1930                        renderSingleObject(itrans->renderable, p, doLightIteration, manualLightList);
1931                }
1932        }
1933}
1934//-----------------------------------------------------------------------
1935void SceneManager::renderSingleObject(Renderable* rend, Pass* pass,
1936                                      bool doLightIteration, const LightList* manualLightList)
1937{
1938    static Matrix4 xform[256];
1939    unsigned short numMatrices;
1940    static bool normalisedNormals = false;
1941    SceneDetailLevel camDetailLevel = mCameraInProgress->getDetailLevel();
1942    static SceneDetailLevel lastDetailLevel = camDetailLevel;
1943    static RenderOperation ro;
1944    static LightList localLightList;
1945
1946    if (pass->isProgrammable())
1947    {
1948        // Tell auto params object about the renderable change
1949        mAutoParamDataSource.setCurrentRenderable(rend);
1950        pass->_updateAutoParamsNoLights(mAutoParamDataSource);
1951    }
1952
1953    // Set world transformation
1954    rend->getWorldTransforms(xform);
1955    numMatrices = rend->getNumWorldTransforms();
1956    if (numMatrices > 1)
1957    {
1958        mDestRenderSystem->_setWorldMatrices(xform, numMatrices);
1959    }
1960    else
1961    {
1962        mDestRenderSystem->_setWorldMatrix(*xform);
1963    }
1964
1965    // Issue view / projection changes if any
1966    useRenderableViewProjMode(rend);
1967
1968    // Reissue any texture gen settings which are dependent on view matrix
1969    Pass::TextureUnitStateIterator texIter =  pass->getTextureUnitStateIterator();
1970    size_t unit = 0;
1971    while(texIter.hasMoreElements())
1972    {
1973        TextureUnitState* pTex = texIter.getNext();
1974        if (pTex->hasViewRelativeTextureCoordinateGeneration())
1975        {
1976            mDestRenderSystem->_setTextureUnitSettings(unit, *pTex);
1977        }
1978        ++unit;
1979    }
1980
1981
1982    // Sort out normalisation
1983    bool thisNormalise = rend->getNormaliseNormals();
1984    if (thisNormalise != normalisedNormals)
1985    {
1986        mDestRenderSystem->setNormaliseNormals(thisNormalise);
1987        normalisedNormals = thisNormalise;
1988    }
1989
1990    // Set up the solid / wireframe override
1991    SceneDetailLevel reqDetail = rend->getRenderDetail();
1992    if (rend->getRenderDetailOverrideable())
1993    {
1994        // check camera detial only when render detail is overridable
1995        if (reqDetail > camDetailLevel)
1996        {
1997            // only downgrade detail; if cam says wireframe we don't go up to solid
1998            reqDetail = camDetailLevel;
1999        }
2000    }
2001    if (reqDetail != lastDetailLevel)
2002    {
2003        mDestRenderSystem->_setRasterisationMode(reqDetail);
2004        lastDetailLevel = reqDetail;
2005
2006    }
2007
2008    mDestRenderSystem->setClipPlanes(rend->getClipPlanes());
2009
2010    // Set up rendering operation
2011    rend->getRenderOperation(ro);
2012    ro.srcRenderable = rend;
2013
2014    if (doLightIteration)
2015    {
2016        // Here's where we issue the rendering operation to the render system
2017        // Note that we may do this once per light, therefore it's in a loop
2018        // and the light parameters are updated once per traversal through the
2019        // loop
2020        const LightList& rendLightList = rend->getLights();
2021        bool iteratePerLight = pass->getRunOncePerLight();
2022        size_t numIterations = iteratePerLight ? rendLightList.size() : 1;
2023        const LightList* pLightListToUse;
2024        for (size_t i = 0; i < numIterations; ++i)
2025        {
2026            // Determine light list to use
2027            if (iteratePerLight)
2028            {
2029                // Change the only element of local light list to be
2030                // the light at index i
2031                localLightList.clear();
2032                // Check whether we need to filter this one out
2033                if (pass->getRunOnlyForOneLightType() &&
2034                    pass->getOnlyLightType() != rendLightList[i]->getType())
2035                {
2036                    // Skip
2037                    continue;
2038                }
2039
2040                localLightList.push_back(rendLightList[i]);
2041                pLightListToUse = &localLightList;
2042            }
2043            else
2044            {
2045                // Use complete light list
2046                pLightListToUse = &rendLightList;
2047            }
2048
2049            // Do we need to update GPU program parameters?
2050            if (pass->isProgrammable())
2051            {
2052                // Update any automatic gpu params for lights
2053                // Other bits of information will have to be looked up
2054                mAutoParamDataSource.setCurrentLightList(pLightListToUse);
2055                pass->_updateAutoParamsLightsOnly(mAutoParamDataSource);
2056                // NOTE: We MUST bind parameters AFTER updating the autos
2057                // TEST
2058                if (pass->hasVertexProgram())
2059                {
2060                    mDestRenderSystem->bindGpuProgramParameters(GPT_VERTEX_PROGRAM,
2061                        pass->getVertexProgramParameters());
2062                }
2063                if (pass->hasFragmentProgram())
2064                {
2065                    mDestRenderSystem->bindGpuProgramParameters(GPT_FRAGMENT_PROGRAM,
2066                        pass->getFragmentProgramParameters());
2067                }
2068            }
2069            // Do we need to update light states?
2070            // Only do this if fixed-function vertex lighting applies
2071            if (pass->getLightingEnabled() &&
2072                (!pass->hasVertexProgram() || pass->getVertexProgram()->getPassSurfaceAndLightStates()))
2073            {
2074                mDestRenderSystem->_useLights(*pLightListToUse, pass->getMaxSimultaneousLights());
2075            }
2076            // issue the render op             
2077            mDestRenderSystem->_render(ro);
2078        } // possibly iterate per light
2079    }
2080    else // no automatic light processing
2081    {
2082        // Do we need to update GPU program parameters?
2083        if (pass->isProgrammable())
2084        {
2085            // Do we have a manual light list?
2086            if (manualLightList)
2087            {
2088                // Update any automatic gpu params for lights
2089                mAutoParamDataSource.setCurrentLightList(manualLightList);
2090                pass->_updateAutoParamsLightsOnly(mAutoParamDataSource);
2091            }
2092
2093            if (pass->hasVertexProgram())
2094            {
2095                mDestRenderSystem->bindGpuProgramParameters(GPT_VERTEX_PROGRAM,
2096                    pass->getVertexProgramParameters());
2097            }
2098            if (pass->hasFragmentProgram())
2099            {
2100                mDestRenderSystem->bindGpuProgramParameters(GPT_FRAGMENT_PROGRAM,
2101                    pass->getFragmentProgramParameters());
2102            }
2103        }
2104
2105        // Use manual lights if present, and fixed-function vertex lighting applies
2106        if (manualLightList &&
2107            pass->getLightingEnabled() &&
2108            (!pass->hasVertexProgram() || pass->getVertexProgram()->getPassSurfaceAndLightStates()))
2109        {
2110            mDestRenderSystem->_useLights(*manualLightList, pass->getMaxSimultaneousLights());
2111        }
2112        // issue the render op         
2113        mDestRenderSystem->_render(ro);
2114    }
2115}
2116//-----------------------------------------------------------------------
2117void SceneManager::setAmbientLight(const ColourValue& colour)
2118{
2119    mAmbientLight = colour;
2120    mDestRenderSystem->setAmbientLight(colour.r, colour.g, colour.b);
2121}
2122//-----------------------------------------------------------------------
2123const ColourValue& SceneManager::getAmbientLight(void) const
2124{
2125    return mAmbientLight;
2126}
2127//-----------------------------------------------------------------------
2128ViewPoint SceneManager::getSuggestedViewpoint(bool random)
2129{
2130    // By default return the origin
2131    ViewPoint vp;
2132    vp.position = Vector3::ZERO;
2133    vp.orientation = Quaternion::IDENTITY;
2134    return vp;
2135}
2136//-----------------------------------------------------------------------
2137void SceneManager::setFog(FogMode mode, const ColourValue& colour, Real density, Real start, Real end)
2138{
2139    mFogMode = mode;
2140    mFogColour = colour;
2141    mFogStart = start;
2142    mFogEnd = end;
2143    mFogDensity = density;
2144}
2145//-----------------------------------------------------------------------
2146FogMode SceneManager::getFogMode(void) const
2147{
2148    return mFogMode;
2149}
2150//-----------------------------------------------------------------------
2151const ColourValue& SceneManager::getFogColour(void) const
2152{
2153    return mFogColour;
2154}
2155//-----------------------------------------------------------------------
2156Real SceneManager::getFogStart(void) const
2157{
2158    return mFogStart;
2159}
2160//-----------------------------------------------------------------------
2161Real SceneManager::getFogEnd(void) const
2162{
2163    return mFogEnd;
2164}
2165//-----------------------------------------------------------------------
2166Real SceneManager::getFogDensity(void) const
2167{
2168    return mFogDensity;
2169}
2170//-----------------------------------------------------------------------
2171BillboardSet* SceneManager::createBillboardSet(const String& name, unsigned int poolSize)
2172{
2173    // Check name not used
2174    if (mBillboardSets.find(name) != mBillboardSets.end())
2175    {
2176        OGRE_EXCEPT(
2177            Exception::ERR_DUPLICATE_ITEM,
2178            "A billboard set with the name " + name + " already exists",
2179            "SceneManager::createBillboardSet" );
2180    }
2181
2182    BillboardSet* set = new BillboardSet( name, poolSize );
2183    mBillboardSets[name] = set;//.insert(BillboardSetList::value_type(name, set));
2184
2185    return set;
2186}
2187//-----------------------------------------------------------------------
2188BillboardSet* SceneManager::getBillboardSet(const String& name)
2189{
2190    BillboardSetList::iterator i = mBillboardSets.find(name);
2191    if (i == mBillboardSets.end())
2192    {
2193        OGRE_EXCEPT( Exception::ERR_ITEM_NOT_FOUND,
2194            "Cannot find BillboardSet with name " + name,
2195            "SceneManager::getBillboardSet");
2196    }
2197    else
2198    {
2199        return i->second;
2200    }
2201}
2202//-----------------------------------------------------------------------
2203void SceneManager::removeBillboardSet(BillboardSet* set)
2204{
2205    // Find in list
2206    BillboardSetList::iterator i = mBillboardSets.begin();
2207    for (; i != mBillboardSets.end(); ++i)
2208    {
2209        if (i->second == set)
2210        {
2211            mBillboardSets.erase(i);
2212            delete set;
2213            break;
2214        }
2215    }
2216
2217}
2218//-----------------------------------------------------------------------
2219void SceneManager::removeBillboardSet(const String& name)
2220{
2221    // Find in list
2222    BillboardSetList::iterator i = mBillboardSets.find(name);
2223    if (i != mBillboardSets.end())
2224    {
2225        delete i->second;
2226        mBillboardSets.erase(i);
2227    }
2228}
2229//-----------------------------------------------------------------------
2230void SceneManager::setDisplaySceneNodes(bool display)
2231{
2232    mDisplayNodes = display;
2233}
2234//-----------------------------------------------------------------------
2235Animation* SceneManager::createAnimation(const String& name, Real length)
2236{
2237    // Check name not used
2238    if (mAnimationsList.find(name) != mAnimationsList.end())
2239    {
2240        OGRE_EXCEPT(
2241            Exception::ERR_DUPLICATE_ITEM,
2242            "An animation with the name " + name + " already exists",
2243            "SceneManager::createAnimation" );
2244    }
2245
2246    Animation* pAnim = new Animation(name, length);
2247    mAnimationsList[name] = pAnim;
2248    return pAnim;
2249}
2250//-----------------------------------------------------------------------
2251Animation* SceneManager::getAnimation(const String& name) const
2252{
2253    AnimationList::const_iterator i = mAnimationsList.find(name);
2254    if (i == mAnimationsList.end())
2255    {
2256        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
2257            "Cannot find animation with name " + name,
2258            "SceneManager::getAnimation");
2259    }
2260    return i->second;
2261}
2262//-----------------------------------------------------------------------
2263void SceneManager::destroyAnimation(const String& name)
2264{
2265    // Also destroy any animation states referencing this animation
2266    AnimationStateSet::iterator si, siend;
2267    siend = mAnimationStates.end();
2268    for (si = mAnimationStates.begin(); si != siend; )
2269    {
2270        if (si->second.getAnimationName() == name)
2271        {
2272            // erase, post increment to avoid the invalidated iterator
2273            mAnimationStates.erase(si++);
2274        }
2275        else
2276        {
2277            ++si;
2278        }
2279    }
2280
2281    AnimationList::iterator i = mAnimationsList.find(name);
2282    if (i == mAnimationsList.end())
2283    {
2284        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
2285            "Cannot find animation with name " + name,
2286            "SceneManager::getAnimation");
2287    }
2288
2289    // Free memory
2290    delete i->second;
2291
2292    mAnimationsList.erase(i);
2293
2294
2295}
2296//-----------------------------------------------------------------------
2297void SceneManager::destroyAllAnimations(void)
2298{
2299    // Destroy all states too, since they cannot reference destroyed animations
2300    destroyAllAnimationStates();
2301
2302    AnimationList::iterator i;
2303    for (i = mAnimationsList.begin(); i != mAnimationsList.end(); ++i)
2304    {
2305        // destroy
2306        delete i->second;
2307    }
2308    mAnimationsList.clear();
2309}
2310//-----------------------------------------------------------------------
2311AnimationState* SceneManager::createAnimationState(const String& animName)
2312{
2313    if (mAnimationStates.find(animName) != mAnimationStates.end())
2314    {
2315        OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM,
2316            "Cannot create, AnimationState already exists: "+animName,
2317            "SceneManager::createAnimationState");
2318    }
2319
2320    // Get animation, this will throw an exception if not found
2321    Animation* anim = getAnimation(animName);
2322
2323    // Create new state
2324    AnimationState newState(animName, 0, anim->getLength());
2325
2326    // Record it
2327    std::pair<AnimationStateSet::iterator, bool> retPair =
2328        mAnimationStates.insert(AnimationStateSet::value_type(animName, newState));
2329
2330    // Check boolean return
2331    if (retPair.second)
2332    {
2333        // insert was OK
2334        // Get pointer from iterator in pair
2335        return &(retPair.first->second);
2336    }
2337    else
2338    {
2339        // Problem
2340        // Not because of duplicate item, that's checked for above
2341        OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Unexpected error creating new animation state.",
2342            "SceneManager::createAnimationState");
2343    }
2344
2345
2346}
2347//-----------------------------------------------------------------------
2348AnimationState* SceneManager::getAnimationState(const String& animName)
2349{
2350    AnimationStateSet::iterator i = mAnimationStates.find(animName);
2351
2352    if (i == mAnimationStates.end())
2353    {
2354        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
2355            "Cannot locate animation state for animation " + animName,
2356            "SceneManager::getAnimationState");
2357    }
2358
2359    return &(i->second);
2360
2361}
2362//-----------------------------------------------------------------------
2363void SceneManager::destroyAnimationState(const String& name)
2364{
2365    AnimationStateSet::iterator i = mAnimationStates.find(name);
2366
2367    if (i == mAnimationStates.end())
2368    {
2369        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
2370            "Cannot locate animation state for animation " + name,
2371            "SceneManager::destroyAnimationState");
2372    }
2373
2374    mAnimationStates.erase(i);
2375
2376
2377}
2378//-----------------------------------------------------------------------
2379void SceneManager::destroyAllAnimationStates(void)
2380{
2381    mAnimationStates.clear();
2382}
2383//-----------------------------------------------------------------------
2384void SceneManager::_applySceneAnimations(void)
2385{
2386    AnimationStateSet::const_iterator i, iend;
2387
2388    i = mAnimationStates.begin();
2389    iend = mAnimationStates.end();
2390
2391    for (;i != iend; ++i)
2392    {
2393        if (i->second.getEnabled())
2394        {
2395            Animation* anim = getAnimation(i->second.getAnimationName());
2396
2397            // Reset any nodes involved
2398            // NB this excludes blended animations
2399            const Animation::TrackList& trackList = anim->_getTrackList();
2400            Animation::TrackList::const_iterator ti, tend;
2401            ti = trackList.begin();
2402            tend = trackList.end();
2403            for (;ti != tend; ++ti)
2404            {
2405                Node* nd = ti->second->getAssociatedNode();
2406                nd->resetToInitialState();
2407            }
2408
2409
2410            // Apply the animation
2411            anim->apply(i->second.getTimePosition(), i->second.getWeight());
2412        }
2413    }
2414
2415
2416}
2417//---------------------------------------------------------------------
2418void SceneManager::manualRender(RenderOperation* rend,
2419                                Pass* pass, Viewport* vp, const Matrix4& worldMatrix,
2420                                const Matrix4& viewMatrix, const Matrix4& projMatrix,
2421                                bool doBeginEndFrame)
2422{
2423    mDestRenderSystem->_setViewport(vp);
2424    mDestRenderSystem->_setWorldMatrix(worldMatrix);
2425    mDestRenderSystem->_setViewMatrix(viewMatrix);
2426    mDestRenderSystem->_setProjectionMatrix(projMatrix);
2427
2428    if (doBeginEndFrame)
2429        mDestRenderSystem->_beginFrame();
2430
2431    setPass(pass);
2432    mDestRenderSystem->_render(*rend);
2433
2434    if (doBeginEndFrame)
2435        mDestRenderSystem->_endFrame();
2436
2437}
2438//---------------------------------------------------------------------
2439void SceneManager::useRenderableViewProjMode(Renderable* pRend)
2440{
2441    // Check view matrix
2442    static bool lastViewWasIdentity = false;
2443    bool useIdentityView = pRend->useIdentityView();
2444    if (useIdentityView && (mCamChanged || !lastViewWasIdentity))
2445    {
2446        // Using identity view now, change it
2447        mDestRenderSystem->_setViewMatrix(Matrix4::IDENTITY);
2448        lastViewWasIdentity = true;
2449    }
2450    else if (!useIdentityView && (mCamChanged || lastViewWasIdentity))
2451    {
2452        // Coming back to normal from identity view
2453        mDestRenderSystem->_setViewMatrix(mCameraInProgress->getViewMatrix());
2454        lastViewWasIdentity = false;
2455    }
2456
2457    static bool lastProjWasIdentity = false;
2458    bool useIdentityProj = pRend->useIdentityProjection();
2459
2460    if (useIdentityProj && (mCamChanged || !lastProjWasIdentity))
2461    {
2462        mDestRenderSystem->_setProjectionMatrix(Matrix4::IDENTITY);
2463
2464        lastProjWasIdentity = true;
2465    }
2466    else if (!useIdentityProj && (mCamChanged || lastProjWasIdentity))
2467    {
2468        // Coming back from flat projection
2469        mDestRenderSystem->_setProjectionMatrix(mCameraInProgress->getProjectionMatrix());
2470        lastProjWasIdentity = false;
2471    }
2472
2473    mCamChanged = false;
2474
2475}
2476
2477//---------------------------------------------------------------------
2478void SceneManager::_queueSkiesForRendering(Camera* cam)
2479{
2480    // Update nodes
2481    // Translate the box by the camera position (constant distance)
2482    if (mSkyPlaneNode)
2483    {
2484        // The plane position relative to the camera has already been set up
2485        mSkyPlaneNode->setPosition(cam->getDerivedPosition());
2486    }
2487
2488    if (mSkyBoxNode)
2489    {
2490        mSkyBoxNode->setPosition(cam->getDerivedPosition());
2491    }
2492
2493    if (mSkyDomeNode)
2494    {
2495        mSkyDomeNode->setPosition(cam->getDerivedPosition());
2496    }
2497
2498    RenderQueueGroupID qid;
2499    if (mSkyPlaneEnabled)
2500    {
2501        qid = mSkyPlaneDrawFirst?
2502RENDER_QUEUE_SKIES_EARLY : RENDER_QUEUE_SKIES_LATE;
2503        getRenderQueue()->addRenderable(mSkyPlaneEntity->getSubEntity(0), qid, OGRE_RENDERABLE_DEFAULT_PRIORITY);
2504    }
2505
2506    uint plane;
2507    if (mSkyBoxEnabled)
2508    {
2509        qid = mSkyBoxDrawFirst?
2510RENDER_QUEUE_SKIES_EARLY : RENDER_QUEUE_SKIES_LATE;
2511
2512        for (plane = 0; plane < 6; ++plane)
2513        {
2514            getRenderQueue()->addRenderable(
2515                mSkyBoxEntity[plane]->getSubEntity(0), qid, OGRE_RENDERABLE_DEFAULT_PRIORITY);
2516        }
2517    }
2518
2519    if (mSkyDomeEnabled)
2520    {
2521        qid = mSkyDomeDrawFirst?
2522RENDER_QUEUE_SKIES_EARLY : RENDER_QUEUE_SKIES_LATE;
2523
2524        for (plane = 0; plane < 5; ++plane)
2525        {
2526            getRenderQueue()->addRenderable(
2527                mSkyDomeEntity[plane]->getSubEntity(0), qid, OGRE_RENDERABLE_DEFAULT_PRIORITY);
2528        }
2529    }
2530}
2531//---------------------------------------------------------------------
2532void SceneManager::addRenderQueueListener(RenderQueueListener* newListener)
2533{
2534    mRenderQueueListeners.push_back(newListener);
2535}
2536//---------------------------------------------------------------------
2537void SceneManager::removeRenderQueueListener(RenderQueueListener* delListener)
2538{
2539    RenderQueueListenerList::iterator i, iend;
2540    iend = mRenderQueueListeners.end();
2541    for (i = mRenderQueueListeners.begin(); i != iend; ++i)
2542    {
2543        if (*i == delListener)
2544        {
2545            mRenderQueueListeners.erase(i);
2546            break;
2547        }
2548    }
2549
2550}
2551//---------------------------------------------------------------------
2552bool SceneManager::fireRenderQueueStarted(RenderQueueGroupID id)
2553{
2554    RenderQueueListenerList::iterator i, iend;
2555    bool skip = false;
2556
2557    iend = mRenderQueueListeners.end();
2558    for (i = mRenderQueueListeners.begin(); i != iend; ++i)
2559    {
2560        (*i)->renderQueueStarted(id, skip);
2561    }
2562    return skip;
2563}
2564//---------------------------------------------------------------------
2565bool SceneManager::fireRenderQueueEnded(RenderQueueGroupID id)
2566{
2567    RenderQueueListenerList::iterator i, iend;
2568    bool repeat = false;
2569
2570    iend = mRenderQueueListeners.end();
2571    for (i = mRenderQueueListeners.begin(); i != iend; ++i)
2572    {
2573        (*i)->renderQueueEnded(id, repeat);
2574    }
2575    return repeat;
2576}
2577//---------------------------------------------------------------------
2578void SceneManager::setViewport(Viewport* vp)
2579{
2580    mCurrentViewport = vp;
2581    // Set viewport in render system
2582    mDestRenderSystem->_setViewport(vp);
2583}
2584//---------------------------------------------------------------------
2585void SceneManager::showBoundingBoxes(bool bShow)
2586{
2587    mShowBoundingBoxes = bShow;
2588}
2589//---------------------------------------------------------------------
2590bool SceneManager::getShowBoundingBoxes() const
2591{
2592    return mShowBoundingBoxes;
2593}
2594//---------------------------------------------------------------------
2595void SceneManager::_notifyAutotrackingSceneNode(SceneNode* node, bool autoTrack)
2596{
2597    if (autoTrack)
2598    {
2599        mAutoTrackingSceneNodes.insert(node);
2600    }
2601    else
2602    {
2603        mAutoTrackingSceneNodes.erase(node);
2604    }
2605}
2606//---------------------------------------------------------------------
2607void SceneManager::setShadowTechnique(ShadowTechnique technique)
2608{
2609    mShadowTechnique = technique;
2610    if (technique == SHADOWTYPE_STENCIL_ADDITIVE ||
2611        technique == SHADOWTYPE_STENCIL_MODULATIVE)
2612    {
2613        // Firstly check that we  have a stencil
2614        // Otherwise forget it
2615        if (!mDestRenderSystem->getCapabilities()->hasCapability(RSC_HWSTENCIL))
2616        {
2617            LogManager::getSingleton().logMessage(
2618                "WARNING: Stencil shadows were requested, but this device does not "
2619                "have a hardware stencil. Shadows disabled.");
2620            mShadowTechnique = SHADOWTYPE_NONE;
2621        }
2622        else if (mShadowIndexBuffer.isNull())
2623        {
2624            // Create an estimated sized shadow index buffer
2625            mShadowIndexBuffer = HardwareBufferManager::getSingleton().
2626                createIndexBuffer(HardwareIndexBuffer::IT_16BIT,
2627                mShadowIndexBufferSize,
2628                HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE,
2629                false);
2630            // tell all meshes to prepare shadow volumes
2631            MeshManager::getSingleton().setPrepareAllMeshesForShadowVolumes(true);
2632        }
2633    }
2634
2635    if (mShadowTechnique == SHADOWTYPE_STENCIL_ADDITIVE)
2636    {
2637        // Additive stencil, we need to split everything by illumination stage
2638        getRenderQueue()->setSplitPassesByLightingType(true);
2639    }
2640    else
2641    {
2642        getRenderQueue()->setSplitPassesByLightingType(false);
2643    }
2644
2645    if (mShadowTechnique != SHADOWTYPE_NONE)
2646    {
2647        // Tell render queue to split off non-shadowable materials
2648        getRenderQueue()->setSplitNoShadowPasses(true);
2649    }
2650    else
2651    {
2652        getRenderQueue()->setSplitNoShadowPasses(false);
2653    }
2654
2655    if (mShadowTechnique == SHADOWTYPE_TEXTURE_MODULATIVE)
2656    {
2657        createShadowTextures(mShadowTextureSize, mShadowTextureCount, mShadowTextureFormat);
2658    }
2659
2660}
2661//---------------------------------------------------------------------
2662void SceneManager::findLightsAffectingFrustum(const Camera* camera)
2663{
2664    // Basic iteration for this SM
2665    mLightsAffectingFrustum.clear();
2666    SceneLightList::iterator i, iend;
2667    iend = mLights.end();
2668    Sphere sphere;
2669    for (i = mLights.begin(); i != iend; ++i)
2670    {
2671        Light* l = i->second;
2672                if (l->isVisible())
2673                {
2674                        if (l->getType() == Light::LT_DIRECTIONAL)
2675                        {
2676                                // Always visible
2677                                mLightsAffectingFrustum.push_back(l);
2678                        }
2679                        else
2680                        {
2681                                // NB treating spotlight as point for simplicity
2682                                // Just see if the lights attenuation range is within the frustum
2683                                sphere.setCenter(l->getDerivedPosition());
2684                                sphere.setRadius(l->getAttenuationRange());
2685                                if (camera->isVisible(sphere))
2686                                {
2687                                        mLightsAffectingFrustum.push_back(l);
2688                                }
2689
2690                        }
2691                }
2692    }
2693
2694}
2695//---------------------------------------------------------------------
2696bool SceneManager::ShadowCasterSceneQueryListener::queryResult(
2697    MovableObject* object)
2698{
2699    if (object->getCastShadows() && object->isVisible() &&
2700                mSceneMgr->isRenderQueueToBeProcessed(object->getRenderQueueGroup()))
2701    {
2702        if (mFarDistSquared)
2703        {
2704            // Check object is within the shadow far distance
2705            Vector3 toObj = object->getParentNode()->_getDerivedPosition()
2706                - mCamera->getDerivedPosition();
2707            Real radius = object->getWorldBoundingSphere().getRadius();
2708            Real dist =  toObj.squaredLength();               
2709            if (dist - (radius * radius) > mFarDistSquared)
2710            {
2711                // skip, beyond max range
2712                return true;
2713            }
2714        }
2715
2716        // If the object is in the frustum, we can always see the shadow
2717        if (mCamera->isVisible(object->getWorldBoundingBox()))
2718        {
2719            mCasterList->push_back(object);
2720            return true;
2721        }
2722
2723        // Otherwise, object can only be casting a shadow into our view if
2724        // the light is outside the frustum (or it's a directional light,
2725        // which are always outside), and the object is intersecting
2726        // on of the volumes formed between the edges of the frustum and the
2727        // light
2728        if (!mIsLightInFrustum || mLight->getType() == Light::LT_DIRECTIONAL)
2729        {
2730            // Iterate over volumes
2731            PlaneBoundedVolumeList::const_iterator i, iend;
2732            iend = mLightClipVolumeList->end();
2733            for (i = mLightClipVolumeList->begin(); i != iend; ++i)
2734            {
2735                if (i->intersects(object->getWorldBoundingBox()))
2736                {
2737                    mCasterList->push_back(object);
2738                    return true;
2739                }
2740
2741            }
2742
2743        }
2744    }
2745    return true;
2746}
2747//---------------------------------------------------------------------
2748bool SceneManager::ShadowCasterSceneQueryListener::queryResult(
2749    SceneQuery::WorldFragment* fragment)
2750{
2751    // don't deal with world geometry
2752    return true;
2753}
2754//---------------------------------------------------------------------
2755const SceneManager::ShadowCasterList& SceneManager::findShadowCastersForLight(
2756    const Light* light, const Camera* camera)
2757{
2758    mShadowCasterList.clear();
2759
2760    if (light->getType() == Light::LT_DIRECTIONAL)
2761    {
2762        // Basic AABB query encompassing the frustum and the extrusion of it
2763        AxisAlignedBox aabb;
2764        const Vector3* corners = camera->getWorldSpaceCorners();
2765        Vector3 min, max;
2766        Vector3 extrude = light->getDirection() * -mShadowDirLightExtrudeDist;
2767        // do first corner
2768        min = max = corners[0];
2769        min.makeFloor(corners[0] + extrude);
2770        max.makeCeil(corners[0] + extrude);
2771        for (size_t c = 1; c < 8; ++c)
2772        {
2773            min.makeFloor(corners[c]);
2774            max.makeCeil(corners[c]);
2775            min.makeFloor(corners[c] + extrude);
2776            max.makeCeil(corners[c] + extrude);
2777        }
2778        aabb.setExtents(min, max);
2779
2780        if (!mShadowCasterAABBQuery)
2781            mShadowCasterAABBQuery = createAABBQuery(aabb);
2782        else
2783            mShadowCasterAABBQuery->setBox(aabb);
2784        // Execute, use callback
2785        mShadowCasterQueryListener->prepare(false,
2786            &(light->_getFrustumClipVolumes(camera)),
2787            light, camera, &mShadowCasterList, mShadowFarDistSquared);
2788        mShadowCasterAABBQuery->execute(mShadowCasterQueryListener);
2789
2790
2791    }
2792    else
2793    {
2794        Sphere s(light->getPosition(), light->getAttenuationRange());
2795        // eliminate early if camera cannot see light sphere
2796        if (camera->isVisible(s))
2797        {
2798            if (!mShadowCasterSphereQuery)
2799                mShadowCasterSphereQuery = createSphereQuery(s);
2800            else
2801                mShadowCasterSphereQuery->setSphere(s);
2802
2803            // Determine if light is inside or outside the frustum
2804            bool lightInFrustum = camera->isVisible(light->getDerivedPosition());
2805            const PlaneBoundedVolumeList* volList = 0;
2806            if (!lightInFrustum)
2807            {
2808                // Only worth building an external volume list if
2809                // light is outside the frustum
2810                volList = &(light->_getFrustumClipVolumes(camera));
2811            }
2812
2813            // Execute, use callback
2814            mShadowCasterQueryListener->prepare(lightInFrustum,
2815                volList, light, camera, &mShadowCasterList, mShadowFarDistSquared);
2816            mShadowCasterSphereQuery->execute(mShadowCasterQueryListener);
2817
2818        }
2819
2820    }
2821
2822
2823    return mShadowCasterList;
2824}
2825//---------------------------------------------------------------------
2826void SceneManager::initShadowVolumeMaterials(void)
2827{
2828    /* This should have been set in the SceneManager constructor, but if you
2829       created the SceneManager BEFORE the Root object, you will need to call
2830       SceneManager::_setDestinationRenderSystem manually.
2831     */
2832    assert( mDestRenderSystem );
2833
2834    if (mShadowMaterialInitDone)
2835        return;
2836
2837    if (!mShadowDebugPass)
2838    {
2839        MaterialPtr matDebug =
2840            MaterialManager::getSingleton().getByName("Ogre/Debug/ShadowVolumes");
2841        if (matDebug.isNull())
2842        {
2843            // Create
2844            matDebug = MaterialManager::getSingleton().create(
2845                "Ogre/Debug/ShadowVolumes",
2846                ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
2847            mShadowDebugPass = matDebug->getTechnique(0)->getPass(0);
2848            mShadowDebugPass->setSceneBlending(SBT_ADD);
2849            mShadowDebugPass->setLightingEnabled(false);
2850            mShadowDebugPass->setDepthWriteEnabled(false);
2851            TextureUnitState* t = mShadowDebugPass->createTextureUnitState();
2852            t->setColourOperationEx(LBX_MODULATE, LBS_MANUAL, LBS_CURRENT,
2853                ColourValue(0.7, 0.0, 0.2));
2854            mShadowDebugPass->setCullingMode(CULL_NONE);
2855
2856            if (mDestRenderSystem->getCapabilities()->hasCapability(
2857                RSC_VERTEX_PROGRAM))
2858            {
2859                ShadowVolumeExtrudeProgram::initialise();
2860
2861                // Enable the (infinite) point light extruder for now, just to get some params
2862                mShadowDebugPass->setVertexProgram(
2863                    ShadowVolumeExtrudeProgram::programNames[ShadowVolumeExtrudeProgram::POINT_LIGHT]);
2864                mInfiniteExtrusionParams =
2865                    mShadowDebugPass->getVertexProgramParameters();
2866                mInfiniteExtrusionParams->setAutoConstant(0,
2867                    GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
2868                mInfiniteExtrusionParams->setAutoConstant(4,
2869                    GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE);
2870            }   
2871            matDebug->compile();
2872
2873        }
2874        else
2875        {
2876            mShadowDebugPass = matDebug->getTechnique(0)->getPass(0);
2877        }
2878    }
2879
2880    if (!mShadowStencilPass)
2881    {
2882
2883        MaterialPtr matStencil = MaterialManager::getSingleton().getByName(
2884            "Ogre/StencilShadowVolumes");
2885        if (matStencil.isNull())
2886        {
2887            // Init
2888            matStencil = MaterialManager::getSingleton().create(
2889                "Ogre/StencilShadowVolumes",
2890                ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
2891            mShadowStencilPass = matStencil->getTechnique(0)->getPass(0);
2892
2893            if (mDestRenderSystem->getCapabilities()->hasCapability(
2894                RSC_VERTEX_PROGRAM))
2895            {
2896
2897                // Enable the finite point light extruder for now, just to get some params
2898                mShadowStencilPass->setVertexProgram(
2899                    ShadowVolumeExtrudeProgram::programNames[ShadowVolumeExtrudeProgram::POINT_LIGHT_FINITE]);
2900                mFiniteExtrusionParams =
2901                    mShadowStencilPass->getVertexProgramParameters();
2902                mFiniteExtrusionParams->setAutoConstant(0,
2903                    GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
2904                mFiniteExtrusionParams->setAutoConstant(4,
2905                    GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE);
2906                // Note extra parameter
2907                mFiniteExtrusionParams->setAutoConstant(5,
2908                    GpuProgramParameters::ACT_SHADOW_EXTRUSION_DISTANCE);
2909            }
2910            matStencil->compile();
2911            // Nothing else, we don't use this like a 'real' pass anyway,
2912            // it's more of a placeholder
2913        }
2914        else
2915        {
2916            mShadowStencilPass = matStencil->getTechnique(0)->getPass(0);
2917        }
2918    }
2919
2920
2921
2922
2923    if (!mShadowModulativePass)
2924    {
2925
2926        MaterialPtr matModStencil = MaterialManager::getSingleton().getByName(
2927            "Ogre/StencilShadowModulationPass");
2928        if (matModStencil.isNull())
2929        {
2930            // Init
2931            matModStencil = MaterialManager::getSingleton().create(
2932                "Ogre/StencilShadowModulationPass",
2933                ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
2934            mShadowModulativePass = matModStencil->getTechnique(0)->getPass(0);
2935            mShadowModulativePass->setSceneBlending(SBF_DEST_COLOUR, SBF_ZERO);
2936            mShadowModulativePass->setLightingEnabled(false);
2937            mShadowModulativePass->setDepthWriteEnabled(false);
2938            mShadowModulativePass->setDepthCheckEnabled(false);
2939            TextureUnitState* t = mShadowModulativePass->createTextureUnitState();
2940            t->setColourOperationEx(LBX_MODULATE, LBS_MANUAL, LBS_CURRENT,
2941                mShadowColour);
2942            mShadowModulativePass->setCullingMode(CULL_NONE);
2943        }
2944        else
2945        {
2946            mShadowModulativePass = matModStencil->getTechnique(0)->getPass(0);
2947        }
2948    }
2949
2950    // Also init full screen quad while we're at it
2951    if (!mFullScreenQuad)
2952    {
2953        mFullScreenQuad = new Rectangle2D();
2954        mFullScreenQuad->setCorners(-1,1,1,-1);
2955    }
2956
2957    // Also init shadow caster material for texture shadows
2958    if (!mShadowCasterPlainBlackPass)
2959    {
2960        MaterialPtr matPlainBlack = MaterialManager::getSingleton().getByName(
2961            "Ogre/TextureShadowCaster");
2962        if (matPlainBlack.isNull())
2963        {
2964            matPlainBlack = MaterialManager::getSingleton().create(
2965                "Ogre/TextureShadowCaster",
2966                ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
2967            mShadowCasterPlainBlackPass = matPlainBlack->getTechnique(0)->getPass(0);
2968            // Lighting has to be on, because we need shadow coloured objects
2969            // Note that because we can't predict vertex programs, we'll have to
2970            // bind light values to those, and so we bind White to ambient
2971            // reflectance, and we'll set the ambient colour to the shadow colour
2972            mShadowCasterPlainBlackPass->setAmbient(ColourValue::White);
2973            mShadowCasterPlainBlackPass->setDiffuse(ColourValue::Black);
2974            mShadowCasterPlainBlackPass->setSelfIllumination(ColourValue::Black);
2975            mShadowCasterPlainBlackPass->setSpecular(ColourValue::Black);
2976                        // Override fog
2977                        mShadowCasterPlainBlackPass->setFog(true, FOG_NONE);
2978            // no textures or anything else, we will bind vertex programs
2979            // every so often though
2980        }
2981        else
2982        {
2983            mShadowCasterPlainBlackPass = matPlainBlack->getTechnique(0)->getPass(0);
2984        }
2985    }
2986
2987    if (!mShadowReceiverPass)
2988    {
2989        MaterialPtr matShadRec = MaterialManager::getSingleton().getByName(
2990            "Ogre/TextureShadowReceiver");
2991        if (matShadRec.isNull())                       
2992        {
2993            matShadRec = MaterialManager::getSingleton().create(
2994                "Ogre/TextureShadowReceiver",
2995                ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
2996            mShadowReceiverPass = matShadRec->getTechnique(0)->getPass(0);
2997            mShadowReceiverPass->setSceneBlending(SBF_DEST_COLOUR, SBF_ZERO);
2998            // No lighting, one texture unit
2999            // everything else will be bound as needed during the receiver pass
3000            mShadowReceiverPass->setLightingEnabled(false);
3001            TextureUnitState* t = mShadowReceiverPass->createTextureUnitState();
3002            t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
3003        }
3004        else
3005        {
3006            mShadowReceiverPass = matShadRec->getTechnique(0)->getPass(0);
3007        }
3008    }
3009
3010    // Set up spot shadow fade texture (loaded from code data block)
3011    TexturePtr spotShadowFadeTex =
3012        TextureManager::getSingleton().getByName("spot_shadow_fade.png");
3013    if (spotShadowFadeTex.isNull())
3014    {
3015        // Load the manual buffer into an image (don't destroy memory!
3016        DataStreamPtr stream(
3017                        new MemoryDataStream(SPOT_SHADOW_FADE_PNG, SPOT_SHADOW_FADE_PNG_SIZE, false));
3018        Image img;
3019        img.load(stream, "png");
3020        spotShadowFadeTex =
3021            TextureManager::getSingleton().loadImage(
3022                        "spot_shadow_fade.png", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
3023                        img, TEX_TYPE_2D);
3024    }
3025
3026    mShadowMaterialInitDone = true;
3027}
3028//---------------------------------------------------------------------
3029Pass* SceneManager::deriveShadowCasterPass(Pass* pass)
3030{
3031    switch (mShadowTechnique)
3032    {
3033    case SHADOWTYPE_TEXTURE_MODULATIVE:
3034                if (mShadowTextureCustomCasterPass)
3035                {
3036                        // Caster pass has been customised
3037
3038                        if (!pass->getShadowCasterVertexProgramName().empty())
3039                        {
3040                                // Have to merge the shadow caster vertex program in
3041                                mShadowTextureCustomCasterPass->setVertexProgram(
3042                                        pass->getShadowCasterVertexProgramName());
3043                                const GpuProgramPtr& prg = mShadowTextureCustomCasterPass->getVertexProgram();
3044                                // Load this program if not done already
3045                                if (!prg->isLoaded())
3046                                        prg->load();
3047                                // Copy params
3048                                mShadowTextureCustomCasterPass->setVertexProgramParameters(
3049                                        pass->getShadowCasterVertexProgramParameters());
3050                                // mark that we've overridden the standard
3051                                mShadowTextureCasterVPDirty = true;
3052                                // Also have to hack the light autoparams, that is done later
3053                        }
3054                        else if (mShadowTextureCasterVPDirty)
3055                        {
3056                                // reset
3057                                mShadowTextureCustomCasterPass->setVertexProgram(
3058                                        mShadowTextureCustomCasterVertexProgram);
3059                                if(mShadowTextureCustomCasterPass->hasVertexProgram())
3060                                {
3061                                        mShadowTextureCustomCasterPass->setVertexProgramParameters(
3062                                                mShadowTextureCustomCasterVPParams);
3063
3064                                }
3065                                mShadowTextureCasterVPDirty = false;
3066                        }
3067                        return mShadowTextureCustomCasterPass;
3068                }
3069                else
3070                {
3071                        // Standard pass
3072                        if (pass->hasVertexProgram())
3073                        {
3074                                // Have to merge the shadow caster vertex program in
3075                                // This may in fact be blank, in which case it falls back on
3076                                // fixed function
3077                                mShadowCasterPlainBlackPass->setVertexProgram(
3078                                        pass->getShadowCasterVertexProgramName());
3079                                // Did this result in a new vertex program?
3080                                if (mShadowCasterPlainBlackPass->hasVertexProgram())
3081                                {
3082                                        const GpuProgramPtr& prg = mShadowCasterPlainBlackPass->getVertexProgram();
3083                                        // Load this program if not done already
3084                                        if (!prg->isLoaded())
3085                                                prg->load();
3086                                        // Copy params
3087                                        mShadowCasterPlainBlackPass->setVertexProgramParameters(
3088                                                pass->getShadowCasterVertexProgramParameters());
3089                                }
3090                                // Also have to hack the light autoparams, that is done later
3091                        }
3092                        else if (mShadowCasterPlainBlackPass->hasVertexProgram())
3093                        {
3094                                // reset
3095                                mShadowCasterPlainBlackPass->setVertexProgram("");
3096                        }
3097                        return mShadowCasterPlainBlackPass;
3098                }
3099    default:
3100        return pass;
3101    };
3102
3103}
3104//---------------------------------------------------------------------
3105Pass* SceneManager::deriveShadowReceiverPass(Pass* pass)
3106{
3107
3108    switch (mShadowTechnique)
3109    {
3110    case SHADOWTYPE_TEXTURE_MODULATIVE:
3111                if (mShadowTextureCustomReceiverPass)
3112                {
3113                        // Receiver pass has been customised
3114
3115                        if (!pass->getShadowReceiverVertexProgramName().empty())
3116                        {
3117                                // Have to merge the shadow Receiver vertex program in
3118                                mShadowTextureCustomReceiverPass->setVertexProgram(
3119                                        pass->getShadowReceiverVertexProgramName());
3120                                const GpuProgramPtr& prg = mShadowTextureCustomReceiverPass->getVertexProgram();
3121                                // Load this program if not done already
3122                                if (!prg->isLoaded())
3123                                        prg->load();
3124                                // Copy params
3125                                mShadowTextureCustomReceiverPass->setVertexProgramParameters(
3126                                        pass->getShadowReceiverVertexProgramParameters());
3127                                // mark that we've overridden the standard
3128                                mShadowTextureReceiverVPDirty = true;
3129                                // Also have to hack the light autoparams, that is done later
3130                        }
3131                        else if (mShadowTextureReceiverVPDirty)
3132                        {
3133                                // reset
3134                                mShadowTextureCustomReceiverPass->setVertexProgram(
3135                                        mShadowTextureCustomReceiverVertexProgram);
3136                                if(mShadowTextureCustomReceiverPass->hasVertexProgram())
3137                                {
3138                                        mShadowTextureCustomReceiverPass->setVertexProgramParameters(
3139                                                mShadowTextureCustomReceiverVPParams);
3140
3141                                }
3142                                mShadowTextureReceiverVPDirty = false;
3143                        }
3144                        return mShadowTextureCustomReceiverPass;
3145                }
3146                else
3147                {
3148                        if (pass->hasVertexProgram())
3149                        {
3150                                // Have to merge the receiver vertex program in
3151                                // This may return "" which means fixed function will be used
3152                                mShadowReceiverPass->setVertexProgram(
3153                                        pass->getShadowReceiverVertexProgramName());
3154                                // Did this result in a new vertex program?
3155                                if (mShadowReceiverPass->hasVertexProgram())
3156                                {
3157                                        const GpuProgramPtr& prg = mShadowReceiverPass->getVertexProgram();
3158                                        // Load this program if required
3159                                        if (!prg->isLoaded())
3160                                                prg->load();
3161                                        // Copy params
3162                                        mShadowReceiverPass->setVertexProgramParameters(
3163                                                pass->getShadowReceiverVertexProgramParameters());
3164                                }
3165                                // Also have to hack the light autoparams, that is done later
3166                        }
3167                        else if (mShadowReceiverPass->hasVertexProgram())
3168                        {
3169                                // reset
3170                                mShadowReceiverPass->setVertexProgram("");
3171
3172                        }
3173                }
3174
3175        return mShadowReceiverPass;
3176    default:
3177        return pass;
3178    };
3179
3180}
3181//---------------------------------------------------------------------
3182void SceneManager::renderShadowVolumesToStencil(const Light* light, const Camera* camera)
3183{
3184    // Get the shadow caster list
3185    const ShadowCasterList& casters = findShadowCastersForLight(light, camera);
3186    // Check there are some shadow casters to render
3187    if (casters.empty())
3188    {
3189        // No casters, just do nothing
3190        return;
3191    }
3192
3193    // Set up scissor test (point & spot lights only)
3194    bool scissored = false;
3195    if (light->getType() != Light::LT_DIRECTIONAL &&
3196        mDestRenderSystem->getCapabilities()->hasCapability(RSC_SCISSOR_TEST))
3197    {
3198        // Project the sphere onto the camera
3199        Real left, right, top, bottom;
3200        Sphere sphere(light->getDerivedPosition(), light->getAttenuationRange());
3201        if (camera->projectSphere(sphere, &left, &top, &right, &bottom))
3202        {
3203            scissored = true;
3204            // Turn normalised device coordinates into pixels
3205            int iLeft, iTop, iWidth, iHeight;
3206            mCurrentViewport->getActualDimensions(iLeft, iTop, iWidth, iHeight);
3207            size_t szLeft, szRight, szTop, szBottom;
3208
3209            szLeft = (size_t)(iLeft + ((left + 1) * 0.5 * iWidth));
3210            szRight = (size_t)(iLeft + ((right + 1) * 0.5 * iWidth));
3211            szTop = (size_t)(iTop + ((-top + 1) * 0.5 * iHeight));
3212            szBottom = (size_t)(iTop + ((-bottom + 1) * 0.5 * iHeight));
3213
3214            mDestRenderSystem->setScissorTest(true, szLeft, szTop, szRight, szBottom);
3215        }
3216    }
3217
3218    mDestRenderSystem->unbindGpuProgram(GPT_FRAGMENT_PROGRAM);
3219
3220    // Can we do a 2-sided stencil?
3221    bool stencil2sided = false;
3222    if (mDestRenderSystem->getCapabilities()->hasCapability(RSC_TWO_SIDED_STENCIL) &&
3223        mDestRenderSystem->getCapabilities()->hasCapability(RSC_STENCIL_WRAP))
3224    {
3225        // enable
3226        stencil2sided = true;
3227    }
3228
3229    // Do we have access to vertex programs?
3230    bool extrudeInSoftware = true;
3231    bool finiteExtrude = !mShadowUseInfiniteFarPlane ||
3232        !mDestRenderSystem->getCapabilities()->hasCapability(RSC_INFINITE_FAR_PLANE);
3233    if (mDestRenderSystem->getCapabilities()->hasCapability(RSC_VERTEX_PROGRAM))
3234    {
3235        extrudeInSoftware = false;
3236        // attach the appropriate extrusion vertex program
3237        // Note we never unset it because support for vertex programs is constant
3238        mShadowStencilPass->setVertexProgram(
3239            ShadowVolumeExtrudeProgram::getProgramName(light->getType(), finiteExtrude, false)
3240            , false);
3241        // Set params
3242        if (finiteExtrude)
3243        {
3244            mShadowStencilPass->setVertexProgramParameters(mFiniteExtrusionParams);
3245        }
3246        else
3247        {
3248            mShadowStencilPass->setVertexProgramParameters(mInfiniteExtrusionParams);
3249        }
3250        if (mDebugShadows)
3251        {
3252            mShadowDebugPass->setVertexProgram(
3253                ShadowVolumeExtrudeProgram::getProgramName(light->getType(), finiteExtrude, true)
3254                , false);
3255            // Set params
3256            if (finiteExtrude)
3257            {
3258                mShadowDebugPass->setVertexProgramParameters(mFiniteExtrusionParams);
3259            }
3260            else
3261            {
3262                mShadowDebugPass->setVertexProgramParameters(mInfiniteExtrusionParams);
3263            }
3264        }
3265
3266        mDestRenderSystem->bindGpuProgram(mShadowStencilPass->getVertexProgram()->_getBindingDelegate());
3267
3268    }
3269    else
3270    {
3271        mDestRenderSystem->unbindGpuProgram(GPT_VERTEX_PROGRAM);
3272    }
3273
3274    // Add light to internal list for use in render call
3275    LightList lightList;
3276    // const_cast is forgiveable here since we pass this const
3277    lightList.push_back(const_cast<Light*>(light));
3278
3279    // Turn off colour writing and depth writing
3280    mDestRenderSystem->_setColourBufferWriteEnabled(false, false, false, false);
3281        mDestRenderSystem->_disableTextureUnitsFrom(0);
3282    mDestRenderSystem->_setDepthBufferParams(true, false, CMPF_LESS);
3283    mDestRenderSystem->setStencilCheckEnabled(true);
3284
3285    // Calculate extrusion distance
3286    // Use direction light extrusion distance now, just form optimize code
3287    // generate a little, point/spot light will up to date later
3288    Real extrudeDist = mShadowDirLightExtrudeDist;
3289
3290    // Figure out the near clip volume
3291    const PlaneBoundedVolume& nearClipVol =
3292        light->_getNearClipVolume(camera);
3293
3294    // Now iterate over the casters and render
3295    ShadowCasterList::const_iterator si, siend;
3296    siend = casters.end();
3297
3298
3299        // Now iterate over the casters and render
3300        for (si = casters.begin(); si != siend; ++si)
3301        {
3302        ShadowCaster* caster = *si;
3303                bool zfailAlgo = false;
3304                unsigned long flags = 0;
3305
3306        if (light->getType() != Light::LT_DIRECTIONAL)
3307        {
3308            extrudeDist = caster->getPointExtrusionDistance(light);
3309        }
3310
3311        if (!extrudeInSoftware && !finiteExtrude)
3312        {
3313            // hardware extrusion, to infinity (and beyond!)
3314            flags |= SRF_EXTRUDE_TO_INFINITY;
3315        }
3316
3317                // Determine whether zfail is required
3318        if (nearClipVol.intersects(caster->getWorldBoundingBox()))
3319        {
3320            // We use zfail for this object only because zfail
3321                // compatible with zpass algorithm
3322                        zfailAlgo = true;
3323            // We need to include the light and / or dark cap
3324            // But only if they will be visible
3325            if(camera->isVisible(caster->getLightCapBounds()))
3326            {
3327                flags |= SRF_INCLUDE_LIGHT_CAP;
3328            }
3329                        // zfail needs dark cap
3330                        // UNLESS directional lights using hardware extrusion to infinity
3331                        // since that extrudes to a single point
3332                        if(!((flags & SRF_EXTRUDE_TO_INFINITY) &&
3333                                light->getType() == Light::LT_DIRECTIONAL) &&
3334                                camera->isVisible(caster->getDarkCapBounds(*light, extrudeDist)))
3335                        {
3336                                flags |= SRF_INCLUDE_DARK_CAP;
3337                        }
3338        }
3339                else
3340                {
3341                        // In zpass we need a dark cap if
3342                        // 1: infinite extrusion on point/spotlight sources in modulative shadows
3343                        //    mode, since otherwise in areas where there is no depth (skybox)
3344                        //    the infinitely projected volume will leave a dark band
3345                        // 2: finite extrusion on any light source since glancing angles
3346                        //    can peek through the end and shadow objects behind incorrectly
3347                        if ((flags & SRF_EXTRUDE_TO_INFINITY) &&
3348                                light->getType() != Light::LT_DIRECTIONAL &&
3349                                mShadowTechnique == SHADOWTYPE_STENCIL_MODULATIVE &&
3350                                camera->isVisible(caster->getDarkCapBounds(*light, extrudeDist)))
3351                        {
3352                                flags |= SRF_INCLUDE_DARK_CAP;
3353                        }
3354                        else if (!(flags & SRF_EXTRUDE_TO_INFINITY) &&
3355                                camera->isVisible(caster->getDarkCapBounds(*light, extrudeDist)))
3356                        {
3357                                flags |= SRF_INCLUDE_DARK_CAP;
3358                        }
3359
3360                }
3361
3362        // Get shadow renderables                       
3363        ShadowCaster::ShadowRenderableListIterator iShadowRenderables =
3364            caster->getShadowVolumeRenderableIterator(mShadowTechnique,
3365            light, &mShadowIndexBuffer, extrudeInSoftware,
3366            extrudeDist, flags);
3367
3368        // Render a shadow volume here
3369        //  - if we have 2-sided stencil, one render with no culling
3370        //  - otherwise, 2 renders, one with each culling method and invert the ops
3371        setShadowVolumeStencilState(false, zfailAlgo, stencil2sided);
3372        renderShadowVolumeObjects(iShadowRenderables, mShadowStencilPass, &lightList, flags,
3373            false, zfailAlgo, stencil2sided);
3374        if (!stencil2sided)
3375        {
3376            // Second pass
3377            setShadowVolumeStencilState(true, zfailAlgo, false);
3378            renderShadowVolumeObjects(iShadowRenderables, mShadowStencilPass, &lightList, flags,
3379                true, zfailAlgo, false);
3380        }
3381
3382        // Do we need to render a debug shadow marker?
3383        if (mDebugShadows)
3384        {
3385            // reset stencil & colour ops
3386            mDestRenderSystem->setStencilBufferParams();
3387            mShadowDebugPass->getTextureUnitState(0)->
3388                setColourOperationEx(LBX_MODULATE, LBS_MANUAL, LBS_CURRENT,
3389                zfailAlgo ? ColourValue(0.7, 0.0, 0.2) : ColourValue(0.0, 0.7, 0.2));
3390            setPass(mShadowDebugPass);
3391            renderShadowVolumeObjects(iShadowRenderables, mShadowDebugPass, &lightList, flags,
3392                true, false, false);
3393            mDestRenderSystem->_setColourBufferWriteEnabled(false, false, false, false);
3394            mDestRenderSystem->_setDepthBufferFunction(CMPF_LESS);
3395        }
3396    }
3397
3398    // revert colour write state
3399    mDestRenderSystem->_setColourBufferWriteEnabled(true, true, true, true);
3400    // revert depth state
3401    mDestRenderSystem->_setDepthBufferParams();
3402
3403    mDestRenderSystem->setStencilCheckEnabled(false);
3404
3405    mDestRenderSystem->unbindGpuProgram(GPT_VERTEX_PROGRAM);
3406
3407    if (scissored)
3408    {
3409        // disable scissor test
3410        mDestRenderSystem->setScissorTest(false);
3411    }
3412
3413}
3414//---------------------------------------------------------------------
3415void SceneManager::renderShadowVolumeObjects(ShadowCaster::ShadowRenderableListIterator iShadowRenderables,
3416                                             Pass* pass,
3417                                             const LightList *manualLightList,
3418                                             unsigned long flags,
3419                                             bool secondpass, bool zfail, bool twosided)
3420{
3421    // ----- SHADOW VOLUME LOOP -----
3422    // Render all shadow renderables with same stencil operations
3423    while (iShadowRenderables.hasMoreElements())
3424    {
3425        ShadowRenderable* sr = iShadowRenderables.getNext();
3426
3427        // omit hidden renderables
3428        if (sr->isVisible())
3429        {
3430            // render volume, including dark and (maybe) light caps
3431            renderSingleObject(sr, pass, false, manualLightList);
3432
3433            // optionally render separate light cap
3434            if (sr->isLightCapSeparate() && (flags & SRF_INCLUDE_LIGHT_CAP))
3435            {
3436                ShadowRenderable* lightCap = sr->getLightCapRenderable();
3437                assert(lightCap && "Shadow renderable is missing a separate light cap renderable!");
3438
3439                // We must take care with light caps when we could 'see' the back facing
3440                // triangles directly:
3441                //   1. The front facing light caps must render as always fail depth
3442                //      check to avoid 'depth fighting'.
3443                //   2. The back facing light caps must use normal depth function to
3444                //      avoid break the standard depth check
3445                //
3446                // TODO:
3447                //   1. Separate light caps rendering doesn't need for the 'closed'
3448                //      mesh that never touch the near plane, because in this instance,
3449                //      we couldn't 'see' any back facing triangles directly. The
3450                //      'closed' mesh must determinate by edge list builder.
3451                //   2. There still exists 'depth fighting' bug with coplane triangles
3452                //      that has opposite facing. This usually occur when use two side
3453                //      material in the modeling tools and the model exporting tools
3454                //      exporting double triangles to represent this model. This bug
3455                //      can't fixed in GPU only, there must has extra work on edge list
3456                //      builder and shadow volume generater to fix it.
3457                //
3458                if (twosided)
3459                {
3460                    // select back facing light caps to render
3461                    mDestRenderSystem->_setCullingMode(CULL_ANTICLOCKWISE);
3462                    // use normal depth function for back facing light caps
3463                    renderSingleObject(lightCap, pass, false, manualLightList);
3464
3465                    // select front facing light caps to render
3466                    mDestRenderSystem->_setCullingMode(CULL_CLOCKWISE);
3467                    // must always fail depth check for front facing light caps
3468                    mDestRenderSystem->_setDepthBufferFunction(CMPF_ALWAYS_FAIL);
3469                    renderSingleObject(lightCap, pass, false, manualLightList);
3470
3471                    // reset depth function
3472                    mDestRenderSystem->_setDepthBufferFunction(CMPF_LESS);
3473                    // reset culling mode
3474                    mDestRenderSystem->_setCullingMode(CULL_NONE);
3475                }
3476                else if ((secondpass || zfail) && !(secondpass && zfail))
3477                {
3478                    // use normal depth function for back facing light caps
3479                    renderSingleObject(lightCap, pass, false, manualLightList);
3480                }
3481                else
3482                {
3483                    // must always fail depth check for front facing light caps
3484                    mDestRenderSystem->_setDepthBufferFunction(CMPF_ALWAYS_FAIL);
3485                    renderSingleObject(lightCap, pass, false, manualLightList);
3486
3487                    // reset depth function
3488                    mDestRenderSystem->_setDepthBufferFunction(CMPF_LESS);
3489                }
3490            }
3491        }
3492    }
3493}
3494//---------------------------------------------------------------------
3495void SceneManager::setShadowVolumeStencilState(bool secondpass, bool zfail, bool twosided)
3496{
3497    // Determinate the best stencil operation
3498    StencilOperation incrOp, decrOp;
3499    if (mDestRenderSystem->getCapabilities()->hasCapability(RSC_STENCIL_WRAP))
3500    {
3501        incrOp = SOP_INCREMENT_WRAP;
3502        decrOp = SOP_DECREMENT_WRAP;
3503    }
3504    else
3505    {
3506        incrOp = SOP_INCREMENT;
3507        decrOp = SOP_DECREMENT;
3508    }
3509
3510    // First pass, do front faces if zpass
3511    // Second pass, do back faces if zpass
3512    // Invert if zfail
3513    // this is to ensure we always increment before decrement
3514    // When two-sided stencil, always pass front face stencil
3515    // operation parameters and the inverse of them will happen
3516    // for back faces
3517    if ( !twosided && ((secondpass || zfail) && !(secondpass && zfail)) )
3518    {
3519        mDestRenderSystem->_setCullingMode(
3520            twosided? CULL_NONE : CULL_ANTICLOCKWISE);
3521        mDestRenderSystem->setStencilBufferParams(
3522            CMPF_ALWAYS_PASS, // always pass stencil check
3523            0, // no ref value (no compare)
3524            0xFFFFFFFF, // no mask
3525            SOP_KEEP, // stencil test will never fail
3526            zfail ? incrOp : SOP_KEEP, // back face depth fail
3527            zfail ? SOP_KEEP : decrOp, // back face pass
3528            twosided
3529            );
3530    }
3531    else
3532    {
3533        mDestRenderSystem->_setCullingMode(
3534            twosided? CULL_NONE : CULL_CLOCKWISE);
3535        mDestRenderSystem->setStencilBufferParams(
3536            CMPF_ALWAYS_PASS, // always pass stencil check
3537            0, // no ref value (no compare)
3538            0xFFFFFFFF, // no mask
3539            SOP_KEEP, // stencil test will never fail
3540            zfail ? decrOp : SOP_KEEP, // front face depth fail
3541            zfail ? SOP_KEEP : incrOp, // front face pass
3542            twosided
3543            );
3544    }
3545}
3546//---------------------------------------------------------------------
3547void SceneManager::setShadowColour(const ColourValue& colour)
3548{
3549    mShadowColour = colour;
3550
3551    // Prep materials first
3552    initShadowVolumeMaterials();
3553
3554    mShadowModulativePass->getTextureUnitState(0)->setColourOperationEx(
3555        LBX_MODULATE, LBS_MANUAL, LBS_CURRENT, colour);
3556}
3557//---------------------------------------------------------------------
3558const ColourValue& SceneManager::getShadowColour(void) const
3559{
3560    return mShadowColour;
3561}
3562//---------------------------------------------------------------------
3563void SceneManager::setShadowFarDistance(Real distance)
3564{
3565    mShadowFarDist = distance;
3566    mShadowFarDistSquared = distance * distance;
3567}
3568//---------------------------------------------------------------------
3569void SceneManager::setShadowDirectionalLightExtrusionDistance(Real dist)
3570{
3571    mShadowDirLightExtrudeDist = dist;
3572}
3573//---------------------------------------------------------------------
3574Real SceneManager::getShadowDirectionalLightExtrusionDistance(void) const
3575{
3576    return mShadowDirLightExtrudeDist;
3577}
3578//---------------------------------------------------------------------
3579void SceneManager::setShadowIndexBufferSize(size_t size)
3580{
3581    if (!mShadowIndexBuffer.isNull() && size != mShadowIndexBufferSize)
3582    {
3583        // re-create shadow buffer with new size
3584        mShadowIndexBuffer = HardwareBufferManager::getSingleton().
3585            createIndexBuffer(HardwareIndexBuffer::IT_16BIT,
3586            mShadowIndexBufferSize,
3587            HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE,
3588            false);
3589    }
3590    mShadowIndexBufferSize = size;
3591}
3592//---------------------------------------------------------------------
3593void SceneManager::setShadowTextureSize(unsigned short size)
3594{
3595    // possibly recreate
3596    createShadowTextures(size, mShadowTextureCount, mShadowTextureFormat);
3597    mShadowTextureSize = size;
3598}
3599//---------------------------------------------------------------------
3600void SceneManager::setShadowTextureCount(unsigned short count)
3601{
3602    // possibly recreate
3603    createShadowTextures(mShadowTextureSize, count, mShadowTextureFormat);
3604    mShadowTextureCount = count;
3605}
3606//---------------------------------------------------------------------
3607void SceneManager::setShadowTexturePixelFormat(PixelFormat fmt)
3608{
3609        // possibly recreate
3610        createShadowTextures(mShadowTextureSize, mShadowTextureCount, fmt);
3611        mShadowTextureFormat = fmt;
3612}
3613//---------------------------------------------------------------------
3614void SceneManager::setShadowTextureSettings(unsigned short size,
3615        unsigned short count, PixelFormat fmt)
3616{
3617    if (!mShadowTextures.empty() &&
3618        (count != mShadowTextureCount ||
3619        size != mShadowTextureSize ||
3620                fmt != mShadowTextureFormat))
3621    {
3622        // recreate
3623        createShadowTextures(size, count, fmt);
3624    }
3625    mShadowTextureCount = count;
3626    mShadowTextureSize = size;
3627        mShadowTextureFormat = fmt;
3628}
3629//---------------------------------------------------------------------
3630void SceneManager::setShadowTextureCasterMaterial(const String& name)
3631{
3632        if (name.empty())
3633        {
3634                mShadowTextureCustomCasterPass = 0;
3635        }
3636        else
3637        {
3638                MaterialPtr mat = MaterialManager::getSingleton().getByName(name);
3639                if (mat.isNull())
3640                {
3641                        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
3642                                "Cannot locate material called '" + name + "'",
3643                                "SceneManager::setShadowTextureCasterMaterial");
3644                }
3645                mat->load();
3646                mShadowTextureCustomCasterPass = mat->getBestTechnique()->getPass(0);
3647                if (mShadowTextureCustomCasterPass->hasVertexProgram())
3648                {
3649                        // Save vertex program and params in case we have to swap them out
3650                        mShadowTextureCustomCasterVertexProgram =
3651                                mShadowTextureCustomCasterPass->getVertexProgramName();
3652                        mShadowTextureCustomCasterVPParams =
3653                                mShadowTextureCustomCasterPass->getVertexProgramParameters();
3654                        mShadowTextureCasterVPDirty = false;
3655
3656                }
3657        }
3658}
3659//---------------------------------------------------------------------
3660void SceneManager::setShadowTextureReceiverMaterial(const String& name)
3661{
3662        if (name.empty())
3663        {
3664                mShadowTextureCustomReceiverPass = 0;
3665        }
3666        else
3667        {
3668                MaterialPtr mat = MaterialManager::getSingleton().getByName(name);
3669                if (mat.isNull())
3670                {
3671                        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
3672                                "Cannot locate material called '" + name + "'",
3673                                "SceneManager::setShadowTextureReceiverMaterial");
3674                }
3675                mat->load();
3676                mShadowTextureCustomReceiverPass = mat->getBestTechnique()->getPass(0);
3677                if (mShadowTextureCustomReceiverPass->hasVertexProgram())
3678                {
3679                        // Save vertex program and params in case we have to swap them out
3680                        mShadowTextureCustomReceiverVertexProgram =
3681                                mShadowTextureCustomReceiverPass->getVertexProgramName();
3682                        mShadowTextureCustomReceiverVPParams =
3683                                mShadowTextureCustomReceiverPass->getVertexProgramParameters();
3684                        mShadowTextureReceiverVPDirty = false;
3685
3686                }
3687        }
3688}
3689//---------------------------------------------------------------------
3690void SceneManager::createShadowTextures(unsigned short size,
3691        unsigned short count, PixelFormat fmt)
3692{
3693    static const String baseName = "Ogre/ShadowTexture";
3694
3695    if (mShadowTechnique != SHADOWTYPE_TEXTURE_MODULATIVE ||
3696        !mShadowTextures.empty() &&
3697        count == mShadowTextureCount &&
3698        size == mShadowTextureSize &&
3699                fmt == mShadowTextureFormat)
3700    {
3701        // no change
3702        return;
3703    }
3704
3705
3706    // destroy existing
3707    ShadowTextureList::iterator i, iend;
3708    iend = mShadowTextures.end();
3709    for (i = mShadowTextures.begin(); i != iend; ++i)
3710    {
3711        RenderTexture* r = *i;
3712        // remove camera and destroy texture
3713        removeCamera(r->getViewport(0)->getCamera());
3714        mDestRenderSystem->destroyRenderTexture(r->getName());
3715    }
3716    mShadowTextures.clear();
3717
3718    // Recreate shadow textures
3719    for (unsigned short t = 0; t < count; ++t)
3720    {
3721        String targName = baseName + StringConverter::toString(t);
3722        String matName = baseName + "Mat" + StringConverter::toString(t);
3723        String camName = baseName + "Cam" + StringConverter::toString(t);
3724
3725        RenderTexture* shadowTex;
3726        if (mShadowTechnique == SHADOWTYPE_TEXTURE_MODULATIVE)
3727        {
3728            shadowTex = mDestRenderSystem->createRenderTexture(
3729                targName, size, size, TEX_TYPE_2D, mShadowTextureFormat);
3730        }
3731
3732        // Create a camera to go with this texture
3733        Camera* cam = createCamera(camName);
3734        cam->setAspectRatio(1.0f);
3735        // Create a viewport
3736        Viewport *v = shadowTex->addViewport(cam);
3737        v->setClearEveryFrame(true);
3738        // remove overlays
3739        v->setOverlaysEnabled(false);
3740        // Don't update automatically - we'll do it when required
3741        shadowTex->setAutoUpdated(false);
3742        mShadowTextures.push_back(shadowTex);
3743
3744        // Also create corresponding Material used for rendering this shadow
3745        MaterialPtr mat = MaterialManager::getSingleton().getByName(matName);
3746        if (mat.isNull())
3747        {
3748            mat = MaterialManager::getSingleton().create(
3749                matName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
3750        }
3751        else
3752        {
3753            mat->getTechnique(0)->getPass(0)->removeAllTextureUnitStates();
3754        }
3755        // create texture unit referring to render target texture
3756        TextureUnitState* texUnit =
3757            mat->getTechnique(0)->getPass(0)->createTextureUnitState(targName);
3758        // set projective based on camera
3759        texUnit->setProjectiveTexturing(true, cam);
3760        texUnit->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
3761        mat->touch();
3762
3763    }
3764}
3765//---------------------------------------------------------------------
3766void SceneManager::prepareShadowTextures(Camera* cam, Viewport* vp)
3767{
3768    // Set the illumination stage, prevents recursive calls
3769    IlluminationRenderStage savedStage = mIlluminationStage;
3770    mIlluminationStage = IRS_RENDER_TO_TEXTURE;
3771
3772    // Determine far shadow distance
3773    Real shadowDist = mShadowFarDist;
3774    if (!shadowDist)
3775    {
3776        // need a shadow distance, make one up
3777        shadowDist = cam->getNearClipDistance() * 300;
3778    }
3779    // set fogging to hide the shadow edge
3780    Real shadowOffset = shadowDist * mShadowTextureOffset;
3781    Real shadowEnd = shadowDist + shadowOffset;
3782    mShadowReceiverPass->setFog(true, FOG_LINEAR, ColourValue::White,
3783        0, shadowEnd * mShadowTextureFadeStart, shadowEnd * mShadowTextureFadeEnd);
3784
3785    // Iterate over the lights we've found, max out at the limit of light textures
3786
3787    LightList::iterator i, iend;
3788    ShadowTextureList::iterator si, siend;
3789    iend = mLightsAffectingFrustum.end();
3790    siend = mShadowTextures.end();
3791    for (i = mLightsAffectingFrustum.begin(), si = mShadowTextures.begin();
3792        i != iend && si != siend; ++i)
3793    {
3794        Light* light = *i;
3795        RenderTexture* shadowTex = *si;
3796        // Skip non-shadowing lights
3797        if (!light->getCastShadows())
3798            continue;
3799
3800        // Directional lights
3801        if (light->getType() == Light::LT_DIRECTIONAL)
3802        {
3803
3804            // set up the shadow texture
3805            Camera* texCam = shadowTex->getViewport(0)->getCamera();
3806            // Set ortho projection
3807            texCam->setProjectionType(PT_ORTHOGRAPHIC);
3808            // set easy FOV and near dist so that texture covers far dist
3809            texCam->setFOVy(Degree(90));
3810            texCam->setNearClipDistance(shadowDist);
3811
3812            // Set size of projection
3813
3814            // Calculate look at position
3815            // We want to look at a spot shadowOffset away from near plane
3816            // 0.5 is a litle too close for angles
3817            Vector3 target = cam->getDerivedPosition() +
3818                (cam->getDerivedDirection() * shadowOffset);
3819
3820            // Calculate position
3821            // We want to be in the -ve direction of the light direction
3822            // far enough to project for the dir light extrusion distance
3823            Vector3 pos = target +
3824                (light->getDerivedDirection() * -mShadowDirLightExtrudeDist);
3825
3826            // Calculate orientation
3827            Vector3 dir = (pos - target); // backwards since point down -z
3828            dir.normalise();
3829            /*
3830            // Next section (camera oriented shadow map) abandoned
3831            // Always point in the same direction, if we don't do this then
3832            // we get 'shadow swimming' as camera rotates
3833            // As it is, we get swimming on moving but this is less noticeable
3834
3835            // calculate up vector, we want it aligned with cam direction
3836            Vector3 up = cam->getDerivedDirection();
3837            // Check it's not coincident with dir
3838            if (up.dotProduct(dir) >= 1.0f)
3839            {
3840            // Use camera up
3841            up = cam->getUp();
3842            }
3843            */
3844            Vector3 up = Vector3::UNIT_Y;
3845            // Check it's not coincident with dir
3846            if (up.dotProduct(dir) >= 1.0f)
3847            {
3848                // Use camera up
3849                up = Vector3::UNIT_Z;
3850            }
3851            // cross twice to rederive, only direction is unaltered
3852            Vector3 left = dir.crossProduct(up);
3853            left.normalise();
3854            up = dir.crossProduct(left);
3855            up.normalise();
3856            // Derive quaternion from axes
3857            Quaternion q;
3858            q.FromAxes(left, up, dir);
3859            texCam->setOrientation(q);
3860
3861            // Round local x/y position based on a world-space texel; this helps to reduce
3862            // jittering caused by the projection moving with the camera
3863            // Viewport is 2 * near clip distance across (90 degree fov)
3864            Real worldTexelSize = (texCam->getNearClipDistance() * 20) / mShadowTextureSize;
3865            pos.x -= fmod(pos.x, worldTexelSize);
3866            pos.y -= fmod(pos.y, worldTexelSize);
3867            pos.z -= fmod(pos.z, worldTexelSize);
3868            // Finally set position
3869            texCam->setPosition(pos);
3870
3871            if (mShadowTechnique == SHADOWTYPE_TEXTURE_MODULATIVE)
3872                shadowTex->getViewport(0)->setBackgroundColour(ColourValue::White);
3873
3874            // Update target
3875            shadowTex->update();
3876
3877            ++si;
3878        }
3879        // Spotlight
3880        else if (light->getType() == Light::LT_SPOTLIGHT)
3881        {
3882
3883            // set up the shadow texture
3884            Camera* texCam = shadowTex->getViewport(0)->getCamera();
3885            // Set perspective projection
3886            texCam->setProjectionType(PT_PERSPECTIVE);
3887            // set FOV slightly larger than the spotlight range to ensure coverage
3888            texCam->setFOVy(light->getSpotlightOuterAngle()*1.2);
3889            texCam->setPosition(light->getDerivedPosition());
3890            texCam->setDirection(light->getDerivedDirection());
3891            // set near clip the same as main camera, since they are likely
3892            // to both reflect the nature of the scene
3893            texCam->setNearClipDistance(cam->getNearClipDistance());
3894
3895            if (mShadowTechnique == SHADOWTYPE_TEXTURE_MODULATIVE)
3896                shadowTex->getViewport(0)->setBackgroundColour(ColourValue::White);
3897
3898            // Update target
3899            shadowTex->update();
3900
3901            ++si;
3902        }
3903    }
3904    // Set the illumination stage, prevents recursive calls
3905    mIlluminationStage = savedStage;
3906}
3907//---------------------------------------------------------------------
3908StaticGeometry* SceneManager::createStaticGeometry(const String& name)
3909{
3910        // Check not existing
3911        if (mStaticGeometryList.find(name) != mStaticGeometryList.end())
3912        {
3913                OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM,
3914                        "StaticGeometry with name '" + name + "' already exists!",
3915                        "SceneManager::createStaticGeometry");
3916        }
3917        StaticGeometry* ret = new StaticGeometry(this, name);
3918        mStaticGeometryList[name] = ret;
3919        return ret;
3920}
3921//---------------------------------------------------------------------
3922StaticGeometry* SceneManager::getStaticGeometry(const String& name) const
3923{
3924        StaticGeometryList::const_iterator i = mStaticGeometryList.find(name);
3925        if (i == mStaticGeometryList.end())
3926        {
3927                OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
3928                        "StaticGeometry with name '" + name + "' not found",
3929                        "SceneManager::createStaticGeometry");
3930        }
3931        return i->second;
3932}
3933//---------------------------------------------------------------------
3934void SceneManager::removeStaticGeometry(StaticGeometry* geom)
3935{
3936        removeStaticGeometry(geom->getName());
3937}
3938//---------------------------------------------------------------------
3939void SceneManager::removeStaticGeometry(const String& name)
3940{
3941        StaticGeometryList::iterator i = mStaticGeometryList.find(name);
3942        if (i != mStaticGeometryList.end())
3943        {
3944                delete i->second;
3945                mStaticGeometryList.erase(i);
3946        }
3947
3948}
3949//---------------------------------------------------------------------
3950void SceneManager::removeAllStaticGeometry(void)
3951{
3952        StaticGeometryList::iterator i, iend;
3953        iend = mStaticGeometryList.end();
3954        for (i = mStaticGeometryList.begin(); i != iend; ++i)
3955        {
3956                delete i->second;
3957        }
3958        mStaticGeometryList.clear();
3959}
3960//---------------------------------------------------------------------
3961AxisAlignedBoxSceneQuery*
3962SceneManager::createAABBQuery(const AxisAlignedBox& box, unsigned long mask)
3963{
3964    DefaultAxisAlignedBoxSceneQuery* q = new DefaultAxisAlignedBoxSceneQuery(this);
3965    q->setBox(box);
3966    q->setQueryMask(mask);
3967    return q;
3968}
3969//---------------------------------------------------------------------
3970SphereSceneQuery*
3971SceneManager::createSphereQuery(const Sphere& sphere, unsigned long mask)
3972{
3973    DefaultSphereSceneQuery* q = new DefaultSphereSceneQuery(this);
3974    q->setSphere(sphere);
3975    q->setQueryMask(mask);
3976    return q;
3977}
3978//---------------------------------------------------------------------
3979PlaneBoundedVolumeListSceneQuery*
3980SceneManager::createPlaneBoundedVolumeQuery(const PlaneBoundedVolumeList& volumes,
3981                                            unsigned long mask)
3982{
3983    DefaultPlaneBoundedVolumeListSceneQuery* q = new DefaultPlaneBoundedVolumeListSceneQuery(this);
3984    q->setVolumes(volumes);
3985    q->setQueryMask(mask);
3986    return q;
3987}
3988
3989//---------------------------------------------------------------------
3990RaySceneQuery*
3991SceneManager::createRayQuery(const Ray& ray, unsigned long mask)
3992{
3993    DefaultRaySceneQuery* q = new DefaultRaySceneQuery(this);
3994    q->setRay(ray);
3995    q->setQueryMask(mask);
3996    return q;
3997}
3998//---------------------------------------------------------------------
3999IntersectionSceneQuery*
4000SceneManager::createIntersectionQuery(unsigned long mask)
4001{
4002
4003    DefaultIntersectionSceneQuery* q = new DefaultIntersectionSceneQuery(this);
4004    q->setQueryMask(mask);
4005    return q;
4006}
4007//---------------------------------------------------------------------
4008void SceneManager::destroyQuery(SceneQuery* query)
4009{
4010    delete query;
4011}
4012//---------------------------------------------------------------------
4013DefaultIntersectionSceneQuery::DefaultIntersectionSceneQuery(SceneManager* creator)
4014: IntersectionSceneQuery(creator)
4015{
4016    // No world geometry results supported
4017    mSupportedWorldFragments.insert(SceneQuery::WFT_NONE);
4018}
4019//---------------------------------------------------------------------
4020DefaultIntersectionSceneQuery::~DefaultIntersectionSceneQuery()
4021{
4022}
4023//---------------------------------------------------------------------
4024void DefaultIntersectionSceneQuery::execute(IntersectionSceneQueryListener* listener)
4025{
4026    // Entities only for now
4027    SceneManager::EntityList::const_iterator a, b, theEnd;
4028    theEnd = mParentSceneMgr->mEntities.end();
4029    int numEntities;
4030    // Loop a from first to last-1
4031    a = mParentSceneMgr->mEntities.begin();
4032    numEntities = (uint)mParentSceneMgr->mEntities.size();
4033    for (int i = 0; i < (numEntities - 1); ++i, ++a)
4034    {
4035        // Skip if a does not pass the mask
4036        if (!(a->second->getQueryFlags() & mQueryMask) ||
4037                        !a->second->isInScene())
4038            continue;
4039
4040        // Loop b from a+1 to last
4041        b = a;
4042        for (++b; b != theEnd; ++b)
4043        {
4044            // Apply mask to b (both must pass)
4045            if ((b->second->getQueryFlags() & mQueryMask) && b->second->isInScene())
4046            {
4047                const AxisAlignedBox& box1 = a->second->getWorldBoundingBox();
4048                const AxisAlignedBox& box2 = b->second->getWorldBoundingBox();
4049
4050                if (box1.intersects(box2))
4051                {
4052                    if (!listener->queryResult(a->second, b->second)) return;
4053                }
4054            }
4055
4056        }
4057    }
4058}
4059//---------------------------------------------------------------------
4060DefaultAxisAlignedBoxSceneQuery::
4061DefaultAxisAlignedBoxSceneQuery(SceneManager* creator)
4062: AxisAlignedBoxSceneQuery(creator)
4063{
4064    // No world geometry results supported
4065    mSupportedWorldFragments.insert(SceneQuery::WFT_NONE);
4066}
4067//---------------------------------------------------------------------
4068DefaultAxisAlignedBoxSceneQuery::~DefaultAxisAlignedBoxSceneQuery()
4069{
4070}
4071//---------------------------------------------------------------------
4072void DefaultAxisAlignedBoxSceneQuery::execute(SceneQueryListener* listener)
4073{
4074    // Entities only for now
4075    SceneManager::EntityList::const_iterator i, iEnd;
4076    iEnd = mParentSceneMgr->mEntities.end();
4077    for (i = mParentSceneMgr->mEntities.begin(); i != iEnd; ++i)
4078    {
4079        if ((i->second->getQueryFlags() & mQueryMask) &&
4080                        i->second->isInScene() &&
4081                        mAABB.intersects(i->second->getWorldBoundingBox()))
4082        {
4083            if (!listener->queryResult(i->second)) return;
4084        }
4085    }
4086}
4087//---------------------------------------------------------------------
4088DefaultRaySceneQuery::
4089DefaultRaySceneQuery(SceneManager* creator) : RaySceneQuery(creator)
4090{
4091    // No world geometry results supported
4092    mSupportedWorldFragments.insert(SceneQuery::WFT_NONE);
4093}
4094//---------------------------------------------------------------------
4095DefaultRaySceneQuery::~DefaultRaySceneQuery()
4096{
4097}
4098//---------------------------------------------------------------------
4099void DefaultRaySceneQuery::execute(RaySceneQueryListener* listener)
4100{
4101    // Note that becuase we have no scene partitioning, we actually
4102    // perform a complete scene search even if restricted results are
4103    // requested; smarter scene manager queries can utilise the paritioning
4104    // of the scene in order to reduce the number of intersection tests
4105    // required to fulfil the query
4106
4107    // TODO: BillboardSets? Will need per-billboard collision most likely
4108    // Entities only for now
4109    SceneManager::EntityList::const_iterator i, iEnd;
4110    iEnd = mParentSceneMgr->mEntities.end();
4111    for (i = mParentSceneMgr->mEntities.begin(); i != iEnd; ++i)
4112    {
4113        if( (i->second->getQueryFlags() & mQueryMask) &&
4114                        i->second->isInScene())
4115        {
4116            // Do ray / box test
4117            std::pair<bool, Real> result =
4118                mRay.intersects(i->second->getWorldBoundingBox());
4119
4120            if (result.first)
4121            {
4122                if (!listener->queryResult(i->second, result.second)) return;
4123            }
4124        }
4125    }
4126
4127}
4128//---------------------------------------------------------------------
4129DefaultSphereSceneQuery::
4130DefaultSphereSceneQuery(SceneManager* creator) : SphereSceneQuery(creator)
4131{
4132    // No world geometry results supported
4133    mSupportedWorldFragments.insert(SceneQuery::WFT_NONE);
4134}
4135//---------------------------------------------------------------------
4136DefaultSphereSceneQuery::~DefaultSphereSceneQuery()
4137{
4138}
4139//---------------------------------------------------------------------
4140void DefaultSphereSceneQuery::execute(SceneQueryListener* listener)
4141{
4142    // TODO: BillboardSets? Will need per-billboard collision most likely
4143    // Entities only for now
4144    SceneManager::EntityList::const_iterator i, iEnd;
4145    iEnd = mParentSceneMgr->mEntities.end();
4146    Sphere testSphere;
4147    for (i = mParentSceneMgr->mEntities.begin(); i != iEnd; ++i)
4148    {
4149        // Skip unattached
4150        if (!i->second->isInScene() ||
4151                        !(i->second->getQueryFlags() & mQueryMask))
4152            continue;
4153
4154        // Do sphere / sphere test
4155        testSphere.setCenter(i->second->getParentNode()->_getDerivedPosition());
4156        testSphere.setRadius(i->second->getBoundingRadius());
4157        if (mSphere.intersects(testSphere))
4158        {
4159            if (!listener->queryResult(i->second)) return;
4160        }
4161    }
4162}
4163//---------------------------------------------------------------------
4164DefaultPlaneBoundedVolumeListSceneQuery::
4165DefaultPlaneBoundedVolumeListSceneQuery(SceneManager* creator)
4166: PlaneBoundedVolumeListSceneQuery(creator)
4167{
4168    // No world geometry results supported
4169    mSupportedWorldFragments.insert(SceneQuery::WFT_NONE);
4170}
4171//---------------------------------------------------------------------
4172DefaultPlaneBoundedVolumeListSceneQuery::~DefaultPlaneBoundedVolumeListSceneQuery()
4173{
4174}
4175//---------------------------------------------------------------------
4176void DefaultPlaneBoundedVolumeListSceneQuery::execute(SceneQueryListener* listener)
4177{
4178    // Entities only for now
4179    SceneManager::EntityList::const_iterator i, iEnd;
4180    iEnd = mParentSceneMgr->mEntities.end();
4181    Sphere testSphere;
4182    for (i = mParentSceneMgr->mEntities.begin(); i != iEnd; ++i)
4183    {
4184        PlaneBoundedVolumeList::iterator pi, piend;
4185        piend = mVolumes.end();
4186        for (pi = mVolumes.begin(); pi != piend; ++pi)
4187        {
4188            PlaneBoundedVolume& vol = *pi;
4189            // Do AABB / plane volume test
4190            if ((i->second->getQueryFlags() & mQueryMask) &&
4191                                i->second->isInScene() &&
4192                                vol.intersects(i->second->getWorldBoundingBox()))
4193            {
4194                if (!listener->queryResult(i->second)) return;
4195                break;
4196            }
4197        }
4198    }
4199}
4200#ifdef GTP_VISIBILITY_MODIFIED_OGRE
4201//-----------------------------------------------------------------------
4202void SceneManager::_renderSceneNode(Camera *cam, SceneNode *node, const int leavePassesInQueue)
4203{
4204        // delete previously rendered objects from renderqueue
4205        _deleteRenderedQueueGroups(leavePassesInQueue);
4206
4207        node->_findVisibleObjects(cam, getRenderQueue(), false, mDisplayNodes, false);
4208        SceneManager::_renderVisibleObjects();
4209}
4210//-----------------------------------------------------------------------
4211void SceneManager::_deleteRenderedQueueGroups(const int leavePassesInQueue)
4212{
4213        RenderQueue::QueueGroupIterator queueIt = getRenderQueue()->_getQueueGroupIterator();
4214
4215        // find currently processed queue groups and delelete them from render queue
4216        while (queueIt.hasMoreElements())
4217        {
4218                RenderQueueGroupID qId = queueIt.peekNextKey();
4219                RenderQueueGroup* pGroup = queueIt.getNext();
4220
4221                if (isRenderQueueToBeProcessed(qId))
4222                {
4223                        /*if (leaveTransparentsInQueue)
4224                        {       pGroup->clearSolids();  }       else
4225                        {       pGroup->clear(); }*/
4226                        pGroup->clear(leavePassesInQueue);
4227                }
4228        }
4229       
4230        // Now trigger the pending pass updates
4231        // Pass::processPendingPassUpdates();
4232}
4233//-----------------------------------------------------------------------
4234/*void SceneManager::renderEntity(Entity *ent)
4235{
4236        int n = (int)ent->getNumSubEntities();
4237
4238        for (int i = 0; i < n; ++i)
4239        {
4240                Pass *pass = setPass(ent->getSubEntity(i)->getTechnique()->getPass(0));
4241
4242                _renderSingleObject(ent->getSubEntity(i), pass, false);
4243        }
4244}*/
4245//-----------------------------------------------------------------------
4246void SceneManager::_renderMovableObject(MovableObject *mov, const int leavePassesInQueue)
4247{
4248        // delete previously rendered objects from renderqueue
4249        _deleteRenderedQueueGroups(leavePassesInQueue);
4250
4251        mov->_updateRenderQueue(getRenderQueue());
4252        SceneManager::_renderVisibleObjects();
4253}
4254//-----------------------------------------------------------------------
4255void SceneManager::_renderSingleRenderable(Renderable *rend)
4256{
4257        Pass *pass = rend->getTechnique()->getPass(0);
4258        setPass(pass);
4259        renderSingleObject(rend, pass, false);
4260}
4261#endif //GTP_VISIBILITY_MODIFIED_OGRE
4262}
Note: See TracBrowser for help on using the repository browser.