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

Revision 183, 148.6 KB checked in by mattausch, 19 years ago (diff)

added iv-reader library, testing code, and resources

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