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

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