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

Revision 131, 148.4 KB checked in by mattausch, 19 years ago (diff)

updated ogre_changes directory (added terrainrenderable, , renderable, scenemanager::renderMovable

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