Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/OgreMain/src/OgreSceneManager.cpp @ 5

Last change on this file since 5 was 5, checked in by anonymous, 17 years ago

=hoffentlich gehts jetzt

File size: 184.3 KB
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4(Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org
6
7Copyright (c) 2000-2006 Torus Knot Software Ltd
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
24You may alternatively use this source under the terms of a specific version of
25the OGRE Unrestricted License provided you have obtained such a license from
26Torus Knot Software Ltd.
27-----------------------------------------------------------------------------
28*/
29#include "OgreStableHeaders.h"
30
31#include "OgreSceneManager.h"
32
33#include "OgreCamera.h"
34#include "OgreRenderSystem.h"
35#include "OgreMeshManager.h"
36#include "OgreMesh.h"
37#include "OgreSubMesh.h"
38#include "OgreEntity.h"
39#include "OgreSubEntity.h"
40#include "OgreLight.h"
41#include "OgreMath.h"
42#include "OgreControllerManager.h"
43#include "OgreMaterialManager.h"
44#include "OgreAnimation.h"
45#include "OgreAnimationTrack.h"
46#include "OgreRenderQueueSortingGrouping.h"
47#include "OgreOverlay.h"
48#include "OgreOverlayManager.h"
49#include "OgreStringConverter.h"
50#include "OgreRenderQueueListener.h"
51#include "OgreBillboardSet.h"
52#include "OgrePass.h"
53#include "OgreTechnique.h"
54#include "OgreTextureUnitState.h"
55#include "OgreException.h"
56#include "OgreLogManager.h"
57#include "OgreHardwareBufferManager.h"
58#include "OgreRoot.h"
59#include "OgreSpotShadowFadePng.h"
60#include "OgreGpuProgramManager.h"
61#include "OgreGpuProgram.h"
62#include "OgreShadowVolumeExtrudeProgram.h"
63#include "OgreDataStream.h"
64#include "OgreStaticGeometry.h"
65#include "OgreHardwarePixelBuffer.h"
66#include "OgreManualObject.h"
67#include "OgreRenderQueueInvocation.h"
68#include "OgreBillboardChain.h"
69#include "OgreRibbonTrail.h"
70#include "OgreParticleSystemManager.h"
71// This class implements the most basic scene manager
72
73#include <cstdio>
74
75namespace Ogre {
76
77//-----------------------------------------------------------------------
78uint32 SceneManager::WORLD_GEOMETRY_TYPE_MASK   = 0x80000000;
79uint32 SceneManager::ENTITY_TYPE_MASK                   = 0x40000000;
80uint32 SceneManager::FX_TYPE_MASK                               = 0x20000000;
81uint32 SceneManager::STATICGEOMETRY_TYPE_MASK   = 0x10000000;
82uint32 SceneManager::LIGHT_TYPE_MASK                    = 0x08000000;
83uint32 SceneManager::USER_TYPE_MASK_LIMIT         = SceneManager::LIGHT_TYPE_MASK;
84//-----------------------------------------------------------------------
85SceneManager::SceneManager(const String& name) :
86mName(name),
87mRenderQueue(0),
88mCurrentViewport(0),
89mSkyPlaneEntity(0),
90mSkyPlaneNode(0),
91mSkyDomeNode(0),
92mSkyBoxNode(0),
93mSkyPlaneEnabled(false),
94mSkyBoxEnabled(false),
95mSkyDomeEnabled(false),
96mFogMode(FOG_NONE),
97mFogColour(),
98mFogStart(0),
99mFogEnd(0),
100mFogDensity(0),
101mSpecialCaseQueueMode(SCRQM_EXCLUDE),
102mWorldGeometryRenderQueue(RENDER_QUEUE_WORLD_GEOMETRY_1),
103mLastFrameNumber(0),
104mResetIdentityView(false),
105mResetIdentityProj(false),
106mLightsDirtyCounter(0),
107mShadowCasterPlainBlackPass(0),
108mShadowReceiverPass(0),
109mDisplayNodes(false),
110mShowBoundingBoxes(false),
111mShadowTechnique(SHADOWTYPE_NONE),
112mDebugShadows(false),
113mShadowColour(ColourValue(0.25, 0.25, 0.25)),
114mShadowDebugPass(0),
115mShadowStencilPass(0),
116mShadowModulativePass(0),
117mShadowMaterialInitDone(false),
118mShadowIndexBufferSize(51200),
119mFullScreenQuad(0),
120mShadowDirLightExtrudeDist(10000),
121mIlluminationStage(IRS_NONE),
122mShadowTextureConfigDirty(true),
123mShadowUseInfiniteFarPlane(true),
124mShadowCasterRenderBackFaces(true),
125mShadowCasterSphereQuery(0),
126mShadowCasterAABBQuery(0),
127mShadowFarDist(0),
128mShadowFarDistSquared(0),
129mShadowTextureOffset(0.6), 
130mShadowTextureFadeStart(0.7), 
131mShadowTextureFadeEnd(0.9),
132mShadowTextureSelfShadow(false),
133mShadowTextureCustomCasterPass(0),
134mShadowTextureCustomReceiverPass(0),
135mVisibilityMask(0xFFFFFFFF),
136mFindVisibleObjects(true),
137mSuppressRenderStateChanges(false),
138mSuppressShadows(false)
139{
140    // Root scene node
141    mSceneRoot = new SceneNode(this, "root node");
142        mSceneRoot->_notifyRootNode();
143
144    // init sky
145    size_t i;
146    for (i = 0; i < 6; ++i)
147    {
148        mSkyBoxEntity[i] = 0;
149    }
150    for (i = 0; i < 5; ++i)
151    {
152        mSkyDomeEntity[i] = 0;
153    }
154
155        mShadowCasterQueryListener = new ShadowCasterSceneQueryListener(this);
156
157    Root *root = Root::getSingletonPtr();
158    if (root)
159        _setDestinationRenderSystem(root->getRenderSystem());
160
161        // Setup default queued renderable visitor
162        mActiveQueuedRenderableVisitor = &mDefaultQueuedRenderableVisitor;
163
164        // set up default shadow camera setup
165        mDefaultShadowCameraSetup.bind(new DefaultShadowCameraSetup);
166
167        // init shadow texture config
168        setShadowTextureCount(1);
169
170
171}
172//-----------------------------------------------------------------------
173SceneManager::~SceneManager()
174{
175    clearScene();
176    destroyAllCameras();
177
178        // clear down movable object collection map
179        {
180                OGRE_LOCK_MUTEX(mMovableObjectCollectionMapMutex)
181                for (MovableObjectCollectionMap::iterator i = mMovableObjectCollectionMap.begin();
182                        i != mMovableObjectCollectionMap.end(); ++i)
183                {
184                        delete i->second;
185                }
186                mMovableObjectCollectionMap.clear();
187        }
188
189        delete mShadowCasterQueryListener;
190    delete mSceneRoot;
191    delete mFullScreenQuad;
192    delete mShadowCasterSphereQuery;
193    delete mShadowCasterAABBQuery;
194    delete mRenderQueue;
195}
196//-----------------------------------------------------------------------
197RenderQueue* SceneManager::getRenderQueue(void)
198{
199    if (!mRenderQueue)
200    {
201        initRenderQueue();
202    }
203    return mRenderQueue;
204}
205//-----------------------------------------------------------------------
206void SceneManager::initRenderQueue(void)
207{
208    mRenderQueue = new RenderQueue();
209    // init render queues that do not need shadows
210    mRenderQueue->getQueueGroup(RENDER_QUEUE_BACKGROUND)->setShadowsEnabled(false);
211    mRenderQueue->getQueueGroup(RENDER_QUEUE_OVERLAY)->setShadowsEnabled(false);
212    mRenderQueue->getQueueGroup(RENDER_QUEUE_SKIES_EARLY)->setShadowsEnabled(false);
213    mRenderQueue->getQueueGroup(RENDER_QUEUE_SKIES_LATE)->setShadowsEnabled(false);
214}
215//-----------------------------------------------------------------------
216void SceneManager::addSpecialCaseRenderQueue(uint8 qid)
217{
218        mSpecialCaseQueueList.insert(qid);
219}
220//-----------------------------------------------------------------------
221void SceneManager::removeSpecialCaseRenderQueue(uint8 qid)
222{
223        mSpecialCaseQueueList.erase(qid);
224}
225//-----------------------------------------------------------------------
226void SceneManager::clearSpecialCaseRenderQueues(void)
227{
228        mSpecialCaseQueueList.clear();
229}
230//-----------------------------------------------------------------------
231void SceneManager::setSpecialCaseRenderQueueMode(SceneManager::SpecialCaseRenderQueueMode mode)
232{
233        mSpecialCaseQueueMode = mode;
234}
235//-----------------------------------------------------------------------
236SceneManager::SpecialCaseRenderQueueMode SceneManager::getSpecialCaseRenderQueueMode(void)
237{
238        return mSpecialCaseQueueMode;
239}
240//-----------------------------------------------------------------------
241bool SceneManager::isRenderQueueToBeProcessed(uint8 qid)
242{
243        bool inList = mSpecialCaseQueueList.find(qid) != mSpecialCaseQueueList.end();
244        return (inList && mSpecialCaseQueueMode == SCRQM_INCLUDE)
245                || (!inList && mSpecialCaseQueueMode == SCRQM_EXCLUDE);
246}
247//-----------------------------------------------------------------------
248void SceneManager::setWorldGeometryRenderQueue(uint8 qid)
249{
250        mWorldGeometryRenderQueue = qid;
251}
252//-----------------------------------------------------------------------
253uint8 SceneManager::getWorldGeometryRenderQueue(void)
254{
255        return mWorldGeometryRenderQueue;
256}
257//-----------------------------------------------------------------------
258Camera* SceneManager::createCamera(const String& name)
259{
260    // Check name not used
261    if (mCameras.find(name) != mCameras.end())
262    {
263        OGRE_EXCEPT(
264            Exception::ERR_DUPLICATE_ITEM,
265            "A camera with the name " + name + " already exists",
266            "SceneManager::createCamera" );
267    }
268
269    Camera *c = new Camera(name, this);
270    mCameras.insert(CameraList::value_type(name, c));
271
272        // create visible bounds aab map entry
273        mCamVisibleObjectsMap[c] = VisibleObjectsBoundsInfo();
274
275    return c;
276}
277
278//-----------------------------------------------------------------------
279Camera* SceneManager::getCamera(const String& name) const
280{
281    CameraList::const_iterator i = mCameras.find(name);
282    if (i == mCameras.end())
283    {
284        OGRE_EXCEPT( Exception::ERR_ITEM_NOT_FOUND, 
285            "Cannot find Camera with name " + name,
286            "SceneManager::getCamera");
287    }
288    else
289    {
290        return i->second;
291    }
292}
293//-----------------------------------------------------------------------
294bool SceneManager::hasCamera(const String& name) const
295{
296        return (mCameras.find(name) != mCameras.end());
297}
298
299//-----------------------------------------------------------------------
300void SceneManager::destroyCamera(Camera *cam)
301{
302        destroyCamera(cam->getName());
303
304}
305
306//-----------------------------------------------------------------------
307void SceneManager::destroyCamera(const String& name)
308{
309    // Find in list
310    CameraList::iterator i = mCameras.find(name);
311    if (i != mCameras.end())
312    {
313                // Remove visible boundary AAB entry
314                CamVisibleObjectsMap::iterator camVisObjIt = mCamVisibleObjectsMap.find( i->second );
315                if ( camVisObjIt != mCamVisibleObjectsMap.end() )
316                        mCamVisibleObjectsMap.erase( camVisObjIt );
317
318                // Remove light-shadow cam mapping entry
319                ShadowCamLightMapping::iterator camLightIt = mShadowCamLightMapping.find( i->second );
320                if ( camLightIt != mShadowCamLightMapping.end() )
321                        mShadowCamLightMapping.erase( camLightIt );
322
323                // Notify render system
324        mDestRenderSystem->_notifyCameraRemoved(i->second);
325        delete i->second;
326        mCameras.erase(i);
327    }
328
329}
330
331//-----------------------------------------------------------------------
332void SceneManager::destroyAllCameras(void)
333{
334
335    CameraList::iterator i = mCameras.begin();
336    for (; i != mCameras.end(); ++i)
337    {
338        // Notify render system
339        mDestRenderSystem->_notifyCameraRemoved(i->second);
340        delete i->second;
341    }
342    mCameras.clear();
343        mCamVisibleObjectsMap.clear();
344        mShadowCamLightMapping.clear();
345}
346//-----------------------------------------------------------------------
347Light* SceneManager::createLight(const String& name)
348{
349        return static_cast<Light*>(
350                createMovableObject(name, LightFactory::FACTORY_TYPE_NAME));
351}
352//-----------------------------------------------------------------------
353Light* SceneManager::getLight(const String& name) const
354{
355        return static_cast<Light*>(
356                getMovableObject(name, LightFactory::FACTORY_TYPE_NAME));
357}
358//-----------------------------------------------------------------------
359bool SceneManager::hasLight(const String& name) const
360{
361        return hasMovableObject(name, LightFactory::FACTORY_TYPE_NAME);
362}
363//-----------------------------------------------------------------------
364void SceneManager::destroyLight(Light *l)
365{
366        destroyMovableObject(l);
367}
368//-----------------------------------------------------------------------
369void SceneManager::destroyLight(const String& name)
370{
371        destroyMovableObject(name, LightFactory::FACTORY_TYPE_NAME);
372}
373//-----------------------------------------------------------------------
374void SceneManager::destroyAllLights(void)
375{
376        destroyAllMovableObjectsByType(LightFactory::FACTORY_TYPE_NAME);
377}
378//-----------------------------------------------------------------------
379const LightList& SceneManager::_getLightsAffectingFrustum(void) const
380{
381    return mLightsAffectingFrustum;
382}
383//-----------------------------------------------------------------------
384bool SceneManager::lightLess::operator()(const Light* a, const Light* b) const
385{
386    return a->tempSquareDist < b->tempSquareDist;
387}
388//-----------------------------------------------------------------------
389void SceneManager::_populateLightList(const Vector3& position, Real radius, 
390                                                                          LightList& destList)
391{
392    // Really basic trawl of the lights, then sort
393    // Subclasses could do something smarter
394
395    // Pick up the lights that affecting frustum only, which should has been
396    // cached, so better than take all lights in the scene into account.
397    const LightList& candidateLights = _getLightsAffectingFrustum();
398
399    // Pre-allocate memory
400    destList.clear();
401    destList.reserve(candidateLights.size());
402
403    LightList::const_iterator it;
404    for (it = candidateLights.begin(); it != candidateLights.end(); ++it)
405    {
406        Light* lt = *it;
407        if (lt->getType() == Light::LT_DIRECTIONAL)
408        {
409            // No distance
410            lt->tempSquareDist = 0.0f;
411            destList.push_back(lt);
412        }
413        else
414        {
415            // Calc squared distance
416            lt->tempSquareDist = (lt->getDerivedPosition() - position).squaredLength();
417            // only add in-range lights
418            Real range = lt->getAttenuationRange();
419            Real maxDist = range + radius;
420            if (lt->tempSquareDist <= Math::Sqr(maxDist))
421            {
422                destList.push_back(lt);
423            }
424        }
425    }
426
427    // Sort (stable to guarantee ordering on directional lights)
428        if (isShadowTechniqueTextureBased())
429        {
430                // Note that if we're using texture shadows, we actually want to use
431                // the first few lights unchanged from the frustum list, matching the
432                // texture shadows that were generated
433                // Thus we only allow object-relative sorting on the remainder of the list
434                if (destList.size() > getShadowTextureCount())
435                {
436                        LightList::iterator start = destList.begin();
437                        std::advance(start, getShadowTextureCount());
438                        std::stable_sort(start, destList.end(), lightLess());
439                }
440        }
441        else
442        {
443                std::stable_sort(destList.begin(), destList.end(), lightLess());
444        }
445
446
447}
448//-----------------------------------------------------------------------
449Entity* SceneManager::createEntity(const String& entityName, PrefabType ptype)
450{
451    switch (ptype)
452    {
453    case PT_PLANE:
454        return createEntity(entityName, "Prefab_Plane");
455        case PT_CUBE:
456                return createEntity(entityName, "Prefab_Cube");
457        case PT_SPHERE:
458                return createEntity(entityName, "Prefab_Sphere");
459
460        break;
461    }
462
463    OGRE_EXCEPT( Exception::ERR_ITEM_NOT_FOUND, 
464        "Unknown prefab type for entity " + entityName,
465        "SceneManager::createEntity");
466}
467
468//-----------------------------------------------------------------------
469Entity* SceneManager::createEntity(
470                                   const String& entityName,
471                                   const String& meshName )
472{
473        // delegate to factory implementation
474        NameValuePairList params;
475        params["mesh"] = meshName;
476        return static_cast<Entity*>(
477                createMovableObject(entityName, EntityFactory::FACTORY_TYPE_NAME, 
478                        &params));
479
480}
481
482//-----------------------------------------------------------------------
483Entity* SceneManager::getEntity(const String& name) const
484{
485        return static_cast<Entity*>(
486                getMovableObject(name, EntityFactory::FACTORY_TYPE_NAME));
487}
488//-----------------------------------------------------------------------
489bool SceneManager::hasEntity(const String& name) const
490{
491        return hasMovableObject(name, EntityFactory::FACTORY_TYPE_NAME);
492}
493
494//-----------------------------------------------------------------------
495void SceneManager::destroyEntity(Entity *e)
496{
497        destroyMovableObject(e);
498}
499
500//-----------------------------------------------------------------------
501void SceneManager::destroyEntity(const String& name)
502{
503        destroyMovableObject(name, EntityFactory::FACTORY_TYPE_NAME);
504
505}
506
507//-----------------------------------------------------------------------
508void SceneManager::destroyAllEntities(void)
509{
510
511        destroyAllMovableObjectsByType(EntityFactory::FACTORY_TYPE_NAME);
512}
513
514//-----------------------------------------------------------------------
515void SceneManager::destroyAllBillboardSets(void)
516{
517        destroyAllMovableObjectsByType(BillboardSetFactory::FACTORY_TYPE_NAME);
518}
519//-----------------------------------------------------------------------
520ManualObject* SceneManager::createManualObject(const String& name)
521{
522        return static_cast<ManualObject*>(
523                createMovableObject(name, ManualObjectFactory::FACTORY_TYPE_NAME));
524}
525//-----------------------------------------------------------------------
526ManualObject* SceneManager::getManualObject(const String& name) const
527{
528        return static_cast<ManualObject*>(
529                getMovableObject(name, ManualObjectFactory::FACTORY_TYPE_NAME));
530
531}
532//-----------------------------------------------------------------------
533bool SceneManager::hasManualObject(const String& name) const
534{
535        return hasMovableObject(name, ManualObjectFactory::FACTORY_TYPE_NAME);
536
537}
538//-----------------------------------------------------------------------
539void SceneManager::destroyManualObject(ManualObject* obj)
540{
541        destroyMovableObject(obj);
542}
543//-----------------------------------------------------------------------
544void SceneManager::destroyManualObject(const String& name)
545{
546        destroyMovableObject(name, ManualObjectFactory::FACTORY_TYPE_NAME);
547}
548//-----------------------------------------------------------------------
549void SceneManager::destroyAllManualObjects(void)
550{
551        destroyAllMovableObjectsByType(ManualObjectFactory::FACTORY_TYPE_NAME);
552}
553//-----------------------------------------------------------------------
554BillboardChain* SceneManager::createBillboardChain(const String& name)
555{
556        return static_cast<BillboardChain*>(
557                createMovableObject(name, BillboardChainFactory::FACTORY_TYPE_NAME));
558}
559//-----------------------------------------------------------------------
560BillboardChain* SceneManager::getBillboardChain(const String& name) const
561{
562        return static_cast<BillboardChain*>(
563                getMovableObject(name, BillboardChainFactory::FACTORY_TYPE_NAME));
564
565}
566//-----------------------------------------------------------------------
567bool SceneManager::hasBillboardChain(const String& name) const
568{
569        return hasMovableObject(name, BillboardChainFactory::FACTORY_TYPE_NAME);
570}
571
572//-----------------------------------------------------------------------
573void SceneManager::destroyBillboardChain(BillboardChain* obj)
574{
575        destroyMovableObject(obj);
576}
577//-----------------------------------------------------------------------
578void SceneManager::destroyBillboardChain(const String& name)
579{
580        destroyMovableObject(name, BillboardChainFactory::FACTORY_TYPE_NAME);
581}
582//-----------------------------------------------------------------------
583void SceneManager::destroyAllBillboardChains(void)
584{
585        destroyAllMovableObjectsByType(BillboardChainFactory::FACTORY_TYPE_NAME);
586}
587//-----------------------------------------------------------------------
588RibbonTrail* SceneManager::createRibbonTrail(const String& name)
589{
590        return static_cast<RibbonTrail*>(
591                createMovableObject(name, RibbonTrailFactory::FACTORY_TYPE_NAME));
592}
593//-----------------------------------------------------------------------
594RibbonTrail* SceneManager::getRibbonTrail(const String& name) const
595{
596        return static_cast<RibbonTrail*>(
597                getMovableObject(name, RibbonTrailFactory::FACTORY_TYPE_NAME));
598
599}
600//-----------------------------------------------------------------------
601bool SceneManager::hasRibbonTrail(const String& name) const
602{
603        return hasMovableObject(name, RibbonTrailFactory::FACTORY_TYPE_NAME);
604}
605
606//-----------------------------------------------------------------------
607void SceneManager::destroyRibbonTrail(RibbonTrail* obj)
608{
609        destroyMovableObject(obj);
610}
611//-----------------------------------------------------------------------
612void SceneManager::destroyRibbonTrail(const String& name)
613{
614        destroyMovableObject(name, RibbonTrailFactory::FACTORY_TYPE_NAME);
615}
616//-----------------------------------------------------------------------
617void SceneManager::destroyAllRibbonTrails(void)
618{
619        destroyAllMovableObjectsByType(RibbonTrailFactory::FACTORY_TYPE_NAME);
620}
621//-----------------------------------------------------------------------
622ParticleSystem* SceneManager::createParticleSystem(const String& name,
623        const String& templateName)
624{
625        NameValuePairList params;
626        params["templateName"] = templateName;
627       
628        return static_cast<ParticleSystem*>(
629                createMovableObject(name, ParticleSystemFactory::FACTORY_TYPE_NAME, 
630                        &params));
631}
632//-----------------------------------------------------------------------
633ParticleSystem* SceneManager::createParticleSystem(const String& name,
634        size_t quota, const String& group)
635{
636        NameValuePairList params;
637        params["quota"] = StringConverter::toString(quota);
638        params["resourceGroup"] = group;
639       
640        return static_cast<ParticleSystem*>(
641                createMovableObject(name, ParticleSystemFactory::FACTORY_TYPE_NAME, 
642                        &params));
643}
644//-----------------------------------------------------------------------
645ParticleSystem* SceneManager::getParticleSystem(const String& name) const
646{
647        return static_cast<ParticleSystem*>(
648                getMovableObject(name, ParticleSystemFactory::FACTORY_TYPE_NAME));
649
650}
651//-----------------------------------------------------------------------
652bool SceneManager::hasParticleSystem(const String& name) const
653{
654        return hasMovableObject(name, ParticleSystemFactory::FACTORY_TYPE_NAME);
655}
656
657//-----------------------------------------------------------------------
658void SceneManager::destroyParticleSystem(ParticleSystem* obj)
659{
660        destroyMovableObject(obj);
661}
662//-----------------------------------------------------------------------
663void SceneManager::destroyParticleSystem(const String& name)
664{
665        destroyMovableObject(name, ParticleSystemFactory::FACTORY_TYPE_NAME);
666}
667//-----------------------------------------------------------------------
668void SceneManager::destroyAllParticleSystems(void)
669{
670        destroyAllMovableObjectsByType(ParticleSystemFactory::FACTORY_TYPE_NAME);
671}
672//-----------------------------------------------------------------------
673void SceneManager::clearScene(void)
674{
675        destroyAllStaticGeometry();
676        destroyAllMovableObjects();
677
678        // Clear root node of all children
679        mSceneRoot->removeAllChildren();
680        mSceneRoot->detachAllObjects();
681
682        // Delete all SceneNodes, except root that is
683        for (SceneNodeList::iterator i = mSceneNodes.begin();
684                i != mSceneNodes.end(); ++i)
685        {
686                delete i->second;
687        }
688        mSceneNodes.clear();
689        mAutoTrackingSceneNodes.clear();
690
691
692       
693        // Clear animations
694    destroyAllAnimations();
695
696    // Remove sky nodes since they've been deleted
697    mSkyBoxNode = mSkyPlaneNode = mSkyDomeNode = 0;
698    mSkyBoxEnabled = mSkyPlaneEnabled = mSkyDomeEnabled = false; 
699
700        // Clear render queue, empty completely
701        if (mRenderQueue)
702                mRenderQueue->clear(true);
703
704}
705//-----------------------------------------------------------------------
706SceneNode* SceneManager::createSceneNode(void)
707{
708    SceneNode* sn = new SceneNode(this);
709    assert(mSceneNodes.find(sn->getName()) == mSceneNodes.end());
710    mSceneNodes[sn->getName()] = sn;
711    return sn;
712}
713//-----------------------------------------------------------------------
714SceneNode* SceneManager::createSceneNode(const String& name)
715{
716    // Check name not used
717    if (mSceneNodes.find(name) != mSceneNodes.end())
718    {
719        OGRE_EXCEPT(
720            Exception::ERR_DUPLICATE_ITEM,
721            "A scene node with the name " + name + " already exists",
722            "SceneManager::createSceneNode" );
723    }
724
725    SceneNode* sn = new SceneNode(this, name);
726    mSceneNodes[sn->getName()] = sn;
727    return sn;
728}
729//-----------------------------------------------------------------------
730void SceneManager::destroySceneNode(const String& name)
731{
732    SceneNodeList::iterator i = mSceneNodes.find(name);
733
734    if (i == mSceneNodes.end())
735    {
736        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "SceneNode '" + name + "' not found.",
737            "SceneManager::destroySceneNode");
738    }
739
740    // Find any scene nodes which are tracking this node, and turn them off
741    AutoTrackingSceneNodes::iterator ai, aiend;
742    aiend = mAutoTrackingSceneNodes.end();
743    for (ai = mAutoTrackingSceneNodes.begin(); ai != aiend; )
744    {
745                // Pre-increment incase we delete
746                AutoTrackingSceneNodes::iterator curri = ai++;
747        SceneNode* n = *curri;
748        // Tracking this node
749        if (n->getAutoTrackTarget() == i->second)
750        {
751            // turn off, this will notify SceneManager to remove
752            n->setAutoTracking(false);
753        }
754        // node is itself a tracker
755        else if (n == i->second)
756        {
757            mAutoTrackingSceneNodes.erase(curri);
758        }
759    }
760
761        // detach from parent (don't do this in destructor since bulk destruction
762        // behaves differently)
763        Node* parentNode = i->second->getParent();
764        if (parentNode)
765        {
766                parentNode->removeChild(i->second);
767        }
768    delete i->second;
769    mSceneNodes.erase(i);
770}
771//-----------------------------------------------------------------------
772SceneNode* SceneManager::getRootSceneNode(void) const
773{
774    return mSceneRoot;
775}
776//-----------------------------------------------------------------------
777SceneNode* SceneManager::getSceneNode(const String& name) const
778{
779    SceneNodeList::const_iterator i = mSceneNodes.find(name);
780
781    if (i == mSceneNodes.end())
782    {
783        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "SceneNode '" + name + "' not found.",
784            "SceneManager::getSceneNode");
785    }
786
787    return i->second;
788
789}
790//-----------------------------------------------------------------------
791bool SceneManager::hasSceneNode(const String& name) const
792{
793        return (mSceneNodes.find(name) != mSceneNodes.end());
794}
795
796//-----------------------------------------------------------------------
797const Pass* SceneManager::_setPass(const Pass* pass, bool evenIfSuppressed, 
798                                                                   bool shadowDerivation)
799{
800        if (!mSuppressRenderStateChanges || evenIfSuppressed)
801        {
802                if (mIlluminationStage == IRS_RENDER_TO_TEXTURE && shadowDerivation)
803                {
804                        // Derive a special shadow caster pass from this one
805                        pass = deriveShadowCasterPass(pass);
806                }
807                else if (mIlluminationStage == IRS_RENDER_RECEIVER_PASS && shadowDerivation)
808                {
809                        pass = deriveShadowReceiverPass(pass);
810                }
811
812        // Tell params about current pass
813        mAutoParamDataSource.setCurrentPass(pass);
814
815                // TEST
816                /*
817                LogManager::getSingleton().logMessage("BEGIN PASS " + StringConverter::toString(pass->getIndex()) +
818                " of " + pass->getParent()->getParent()->getName());
819                */
820                bool passSurfaceAndLightParams = true;
821
822                if (pass->hasVertexProgram())
823                {
824                        mDestRenderSystem->bindGpuProgram(pass->getVertexProgram()->_getBindingDelegate());
825                        // bind parameters later since they can be per-object
826                        // does the vertex program want surface and light params passed to rendersystem?
827                        passSurfaceAndLightParams = pass->getVertexProgram()->getPassSurfaceAndLightStates();
828                }
829                else
830                {
831                        // Unbind program?
832                        if (mDestRenderSystem->isGpuProgramBound(GPT_VERTEX_PROGRAM))
833                        {
834                                mDestRenderSystem->unbindGpuProgram(GPT_VERTEX_PROGRAM);
835                        }
836                        // Set fixed-function vertex parameters
837                }
838
839                if (passSurfaceAndLightParams)
840                {
841                        // Set surface reflectance properties, only valid if lighting is enabled
842                        if (pass->getLightingEnabled())
843                        {
844                                mDestRenderSystem->_setSurfaceParams( 
845                                        pass->getAmbient(), 
846                                        pass->getDiffuse(), 
847                                        pass->getSpecular(), 
848                                        pass->getSelfIllumination(), 
849                                        pass->getShininess(),
850                        pass->getVertexColourTracking() );
851                        }
852
853                        // Dynamic lighting enabled?
854                        mDestRenderSystem->setLightingEnabled(pass->getLightingEnabled());
855                }
856
857                // Using a fragment program?
858                if (pass->hasFragmentProgram())
859                {
860                        mDestRenderSystem->bindGpuProgram(
861                                pass->getFragmentProgram()->_getBindingDelegate());
862                        // bind parameters later since they can be per-object
863                }
864                else
865                {
866                        // Unbind program?
867                        if (mDestRenderSystem->isGpuProgramBound(GPT_FRAGMENT_PROGRAM))
868                        {
869                                mDestRenderSystem->unbindGpuProgram(GPT_FRAGMENT_PROGRAM);
870                        }
871
872                        // Set fixed-function fragment settings
873                }
874
875        /* We need sets fog properties always. In D3D, it applies to shaders prior
876        to version vs_3_0 and ps_3_0. And in OGL, it applies to "ARB_fog_XXX" in
877        fragment program, and in other ways, them maybe access by gpu program via
878        "state.fog.XXX".
879        */
880        // New fog params can either be from scene or from material
881        FogMode newFogMode;
882        ColourValue newFogColour;
883        Real newFogStart, newFogEnd, newFogDensity;
884        if (pass->getFogOverride())
885        {
886            // New fog params from material
887            newFogMode = pass->getFogMode();
888            newFogColour = pass->getFogColour();
889            newFogStart = pass->getFogStart();
890            newFogEnd = pass->getFogEnd();
891            newFogDensity = pass->getFogDensity();
892        }
893        else
894        {
895            // New fog params from scene
896            newFogMode = mFogMode;
897            newFogColour = mFogColour;
898            newFogStart = mFogStart;
899            newFogEnd = mFogEnd;
900            newFogDensity = mFogDensity;
901        }
902        mDestRenderSystem->_setFog(
903            newFogMode, newFogColour, newFogDensity, newFogStart, newFogEnd);
904        // Tell params about ORIGINAL fog
905                // Need to be able to override fixed function fog, but still have
906                // original fog parameters available to a shader than chooses to use
907        mAutoParamDataSource.setFog(
908            mFogMode, mFogColour, mFogDensity, mFogStart, mFogEnd);
909
910                // The rest of the settings are the same no matter whether we use programs or not
911
912                // Set scene blending
913                mDestRenderSystem->_setSceneBlending(
914                        pass->getSourceBlendFactor(), pass->getDestBlendFactor());
915
916                // Set point parameters
917                mDestRenderSystem->_setPointParameters(
918                        pass->getPointSize(),
919                        pass->isPointAttenuationEnabled(), 
920                        pass->getPointAttenuationConstant(), 
921                        pass->getPointAttenuationLinear(), 
922                        pass->getPointAttenuationQuadratic(), 
923                        pass->getPointMinSize(), 
924                        pass->getPointMaxSize());
925
926                mDestRenderSystem->_setPointSpritesEnabled(pass->getPointSpritesEnabled());
927
928                // Texture unit settings
929
930                Pass::ConstTextureUnitStateIterator texIter =  pass->getTextureUnitStateIterator();
931                size_t unit = 0;
932                // Reset the shadow texture index for each pass
933                size_t shadowTexIndex = pass->getStartLight(); // all shadow casters are at the start
934                while(texIter.hasMoreElements())
935                {
936                        TextureUnitState* pTex = texIter.getNext();
937                        if (!pass->getIteratePerLight() && 
938                                isShadowTechniqueTextureBased() && 
939                                pTex->getContentType() == TextureUnitState::CONTENT_SHADOW)
940                        {
941                                // Need to bind the correct shadow texture, based on the start light
942                                // Even though the light list can change per object, our restrictions
943                                // say that when texture shadows are enabled, the lights up to the
944                                // number of texture shadows will be fixed for all objects
945                                // to match the shadow textures that have been generated
946                                // see ShadowListener::sortLightsAffectingFrustum and
947                                // MovableObject::Listener::objectQueryLights
948                                // Note that light iteration throws the indexes out so we don't bind here
949                                // if that's the case, we have to bind when lights are iterated
950                                // in renderSingleObject
951
952                                TexturePtr shadowTex;
953                                if (shadowTexIndex < mShadowTextures.size())
954                                {
955                                        shadowTex = getShadowTexture(shadowTexIndex);
956                                        // Hook up projection frustum
957                                        Camera *cam = shadowTex->getBuffer()->getRenderTarget()->getViewport(0)->getCamera();
958                                        // Enable projective texturing if fixed-function, but also need to
959                                        // disable it explicitly for program pipeline.
960                                        pTex->setProjectiveTexturing(!pass->hasVertexProgram(), cam);
961                                        mAutoParamDataSource.setTextureProjector(cam, shadowTexIndex);
962                                }
963                                else
964                                {
965                                        // Use fallback 'null' shadow texture
966                                        // no projection since all uniform colour anyway
967                                        shadowTex = mNullShadowTexture;
968                                        pTex->setProjectiveTexturing(false);
969                                        mAutoParamDataSource.setTextureProjector(0, shadowTexIndex);
970
971                                }
972                                pTex->_setTexturePtr(shadowTex);
973
974                                ++shadowTexIndex;
975                        }
976                        else if (mIlluminationStage == IRS_NONE && pass->hasVertexProgram())
977                        {
978                                // Manually set texture projector for shaders if present
979                                // This won't get set any other way if using manual projection
980                                TextureUnitState::EffectMap::const_iterator effi = 
981                                        pTex->getEffects().find(TextureUnitState::ET_PROJECTIVE_TEXTURE);
982                                if (effi != pTex->getEffects().end())
983                                {
984                                        mAutoParamDataSource.setTextureProjector(effi->second.frustum, unit);
985                                }
986                        }
987                        mDestRenderSystem->_setTextureUnitSettings(unit, *pTex);
988                        ++unit;
989                }
990                // Disable remaining texture units
991                mDestRenderSystem->_disableTextureUnitsFrom(pass->getNumTextureUnitStates());
992
993                // Set up non-texture related material settings
994                // Depth buffer settings
995                mDestRenderSystem->_setDepthBufferFunction(pass->getDepthFunction());
996                mDestRenderSystem->_setDepthBufferCheckEnabled(pass->getDepthCheckEnabled());
997                mDestRenderSystem->_setDepthBufferWriteEnabled(pass->getDepthWriteEnabled());
998                mDestRenderSystem->_setDepthBias(pass->getDepthBiasConstant(), 
999                        pass->getDepthBiasSlopeScale());
1000                // Alpha-reject settings
1001                mDestRenderSystem->_setAlphaRejectSettings(
1002                        pass->getAlphaRejectFunction(), pass->getAlphaRejectValue());
1003                // Set colour write mode
1004                // Right now we only use on/off, not per-channel
1005                bool colWrite = pass->getColourWriteEnabled();
1006                mDestRenderSystem->_setColourBufferWriteEnabled(colWrite, colWrite, colWrite, colWrite);
1007                // Culling mode
1008                if (isShadowTechniqueTextureBased() 
1009                        && mIlluminationStage == IRS_RENDER_TO_TEXTURE
1010                        && mShadowCasterRenderBackFaces
1011                        && pass->getCullingMode() == CULL_CLOCKWISE)
1012                {
1013                        // render back faces into shadow caster, can help with depth comparison
1014                        mDestRenderSystem->_setCullingMode(CULL_ANTICLOCKWISE);
1015                }
1016                else
1017                {
1018                        mDestRenderSystem->_setCullingMode(pass->getCullingMode());
1019                }
1020               
1021                // Shading
1022                mDestRenderSystem->setShadingType(pass->getShadingMode());
1023                // Polygon mode
1024                mDestRenderSystem->_setPolygonMode(pass->getPolygonMode());
1025
1026                // set pass number
1027        mAutoParamDataSource.setPassNumber( pass->getIndex() );
1028        }
1029
1030    return pass;
1031}
1032//-----------------------------------------------------------------------
1033void SceneManager::prepareRenderQueue(void)
1034{
1035        RenderQueue* q = getRenderQueue();
1036        // Clear the render queue
1037        q->clear();
1038
1039        // Prep the ordering options
1040
1041        // If we're using a custom render squence, define based on that
1042        RenderQueueInvocationSequence* seq = 
1043                mCurrentViewport->_getRenderQueueInvocationSequence();
1044        if (seq)
1045        {
1046                // Iterate once to crate / reset all
1047                RenderQueueInvocationIterator invokeIt = seq->iterator();
1048                while (invokeIt.hasMoreElements())
1049                {
1050                        RenderQueueInvocation* invocation = invokeIt.getNext();
1051                        RenderQueueGroup* group = 
1052                                q->getQueueGroup(invocation->getRenderQueueGroupID());
1053                        group->resetOrganisationModes();
1054                }
1055                // Iterate again to build up options (may be more than one)
1056                invokeIt = seq->iterator();
1057                while (invokeIt.hasMoreElements())
1058                {
1059                        RenderQueueInvocation* invocation = invokeIt.getNext();
1060                        RenderQueueGroup* group = 
1061                                q->getQueueGroup(invocation->getRenderQueueGroupID());
1062                        group->addOrganisationMode(invocation->getSolidsOrganisation());
1063                        // also set splitting options
1064                        updateRenderQueueGroupSplitOptions(group, invocation->getSuppressShadows(), 
1065                                invocation->getSuppressRenderStateChanges());
1066                }
1067        }
1068        else
1069        {
1070                // Default all the queue groups that are there, new ones will be created
1071                // with defaults too
1072                RenderQueue::QueueGroupIterator groupIter = q->_getQueueGroupIterator();
1073                while (groupIter.hasMoreElements())
1074                {
1075                        RenderQueueGroup* g = groupIter.getNext();
1076                        g->defaultOrganisationMode();
1077                }
1078                // Global split options
1079                updateRenderQueueSplitOptions();
1080        }
1081
1082}
1083//-----------------------------------------------------------------------
1084void SceneManager::_renderScene(Camera* camera, Viewport* vp, bool includeOverlays)
1085{
1086    Root::getSingleton()._setCurrentSceneManager(this);
1087        mActiveQueuedRenderableVisitor->targetSceneMgr = this;
1088        mAutoParamDataSource.setCurrentSceneManager(this);
1089
1090        // Also set the internal viewport pointer at this point, for calls that need it
1091        // However don't call setViewport just yet (see below)
1092        mCurrentViewport = vp;
1093
1094    if (isShadowTechniqueInUse())
1095    {
1096        // Prepare shadow materials
1097        initShadowVolumeMaterials();
1098    }
1099
1100    // Perform a quick pre-check to see whether we should override far distance
1101    // When using stencil volumes we have to use infinite far distance
1102    // to prevent dark caps getting clipped
1103    if (isShadowTechniqueStencilBased() && 
1104        camera->getProjectionType() == PT_PERSPECTIVE &&
1105        camera->getFarClipDistance() != 0 && 
1106        mDestRenderSystem->getCapabilities()->hasCapability(RSC_INFINITE_FAR_PLANE) && 
1107        mShadowUseInfiniteFarPlane)
1108    {
1109        // infinite far distance
1110        camera->setFarClipDistance(0);
1111    }
1112
1113    mCameraInProgress = camera;
1114
1115
1116    // Update controllers
1117    ControllerManager::getSingleton().updateAllControllers();
1118
1119    // Update the scene, only do this once per frame
1120    unsigned long thisFrameNumber = Root::getSingleton().getCurrentFrameNumber();
1121    if (thisFrameNumber != mLastFrameNumber)
1122    {
1123        // Update animations
1124        _applySceneAnimations();
1125        mLastFrameNumber = thisFrameNumber;
1126    }
1127
1128        {
1129                // Lock scene graph mutex, no more changes until we're ready to render
1130                OGRE_LOCK_MUTEX(sceneGraphMutex)
1131
1132                // Update scene graph for this camera (can happen multiple times per frame)
1133                _updateSceneGraph(camera);
1134
1135                // Auto-track nodes
1136                AutoTrackingSceneNodes::iterator atsni, atsniend;
1137                atsniend = mAutoTrackingSceneNodes.end();
1138                for (atsni = mAutoTrackingSceneNodes.begin(); atsni != atsniend; ++atsni)
1139                {
1140                        (*atsni)->_autoTrack();
1141                }
1142                // Auto-track camera if required
1143                camera->_autoTrack();
1144
1145
1146                if (mIlluminationStage != IRS_RENDER_TO_TEXTURE && mFindVisibleObjects)
1147                {
1148                        // Locate any lights which could be affecting the frustum
1149                        findLightsAffectingFrustum(camera);
1150
1151                        // Are we using any shadows at all?
1152                        if (isShadowTechniqueInUse() && vp->getShadowsEnabled())
1153                        {
1154                                // Prepare shadow textures if texture shadow based shadowing
1155                                // technique in use
1156                                if (isShadowTechniqueTextureBased())
1157                                {
1158                                        // *******
1159                                        // WARNING
1160                                        // *******
1161                                        // This call will result in re-entrant calls to this method
1162                                        // therefore anything which comes before this is NOT
1163                                        // guaranteed persistent. Make sure that anything which
1164                                        // MUST be specific to this camera / target is done
1165                                        // AFTER THIS POINT
1166                                        prepareShadowTextures(camera, vp);
1167                                        // reset the cameras because of the re-entrant call
1168                                        mCameraInProgress = camera;
1169                                }
1170                        }
1171                }
1172
1173                // Invert vertex winding?
1174                if (camera->isReflected())
1175                {
1176                        mDestRenderSystem->setInvertVertexWinding(true);
1177                }
1178                else
1179                {
1180                        mDestRenderSystem->setInvertVertexWinding(false);
1181                }
1182
1183                // Tell params about viewport
1184                mAutoParamDataSource.setCurrentViewport(vp);
1185                // Set the viewport - this is deliberately after the shadow texture update
1186                setViewport(vp);
1187
1188                // Tell params about camera
1189                mAutoParamDataSource.setCurrentCamera(camera);
1190                // Set autoparams for finite dir light extrusion
1191                mAutoParamDataSource.setShadowDirLightExtrusionDistance(mShadowDirLightExtrudeDist);
1192
1193                // Tell params about current ambient light
1194                mAutoParamDataSource.setAmbientLightColour(mAmbientLight);
1195                // Tell rendersystem
1196                mDestRenderSystem->setAmbientLight(mAmbientLight.r, mAmbientLight.g, mAmbientLight.b);
1197
1198                // Tell params about render target
1199                mAutoParamDataSource.setCurrentRenderTarget(vp->getTarget());
1200
1201
1202                // Set camera window clipping planes (if any)
1203                if (mDestRenderSystem->getCapabilities()->hasCapability(RSC_USER_CLIP_PLANES))
1204                {
1205                        if (camera->isWindowSet()) 
1206                        {
1207                                const std::vector<Plane>& planeList = 
1208                                        camera->getWindowPlanes();
1209                                for (ushort i = 0; i < 4; ++i)
1210                                {
1211                                        mDestRenderSystem->enableClipPlane(i, true);
1212                                        mDestRenderSystem->setClipPlane(i, planeList[i]);
1213                                }
1214                        }
1215                        else
1216                        {
1217                                for (ushort i = 0; i < 4; ++i)
1218                                {
1219                                        mDestRenderSystem->enableClipPlane(i, false);
1220                                }
1221                        }
1222                }
1223
1224                // Prepare render queue for receiving new objects
1225                prepareRenderQueue();
1226
1227                if (mFindVisibleObjects)
1228                {
1229                        // Assemble an AAB on the fly which contains the scene elements visible
1230                        // by the camera.
1231                        CamVisibleObjectsMap::iterator camVisObjIt = mCamVisibleObjectsMap.find( camera );
1232
1233                        assert (camVisObjIt != mCamVisibleObjectsMap.end() &&
1234                                "Should never fail to find a visible object bound for a camera, "
1235                                "did you override SceneManager::createCamera or something?");
1236
1237                        // reset the bounds
1238                        camVisObjIt->second.reset();
1239
1240                        // Parse the scene and tag visibles
1241                        _findVisibleObjects(camera, &(camVisObjIt->second),
1242                                mIlluminationStage == IRS_RENDER_TO_TEXTURE? true : false);
1243
1244                        mAutoParamDataSource.setMainCamBoundsInfo(&(camVisObjIt->second));
1245                }
1246                // Add overlays, if viewport deems it
1247                if (vp->getOverlaysEnabled() && mIlluminationStage != IRS_RENDER_TO_TEXTURE)
1248                {
1249                        OverlayManager::getSingleton()._queueOverlaysForRendering(camera, getRenderQueue(), vp);
1250                }
1251                // Queue skies, if viewport seems it
1252                if (vp->getSkiesEnabled() && mFindVisibleObjects && mIlluminationStage != IRS_RENDER_TO_TEXTURE)
1253                {
1254                        _queueSkiesForRendering(camera);
1255                }
1256        } // end lock on scene graph mutex
1257
1258    mDestRenderSystem->_beginGeometryCount();
1259        // Clear the viewport if required
1260        if (mCurrentViewport->getClearEveryFrame())
1261        {
1262                mDestRenderSystem->clearFrameBuffer(
1263                        mCurrentViewport->getClearBuffers(), 
1264                        mCurrentViewport->getBackgroundColour());
1265        }       
1266    // Begin the frame
1267    mDestRenderSystem->_beginFrame();
1268
1269    // Set rasterisation mode
1270    mDestRenderSystem->_setPolygonMode(camera->getPolygonMode());
1271
1272        // Set initial camera state
1273        mDestRenderSystem->_setProjectionMatrix(mCameraInProgress->getProjectionMatrixRS());
1274        mDestRenderSystem->_setViewMatrix(mCameraInProgress->getViewMatrix(true));
1275
1276    // Render scene content
1277    _renderVisibleObjects();
1278
1279    // End frame
1280    mDestRenderSystem->_endFrame();
1281
1282    // Notify camera of vis faces
1283    camera->_notifyRenderedFaces(mDestRenderSystem->_getFaceCount());
1284
1285    // Notify camera of vis batches
1286    camera->_notifyRenderedBatches(mDestRenderSystem->_getBatchCount());
1287
1288
1289}
1290
1291
1292//-----------------------------------------------------------------------
1293void SceneManager::_setDestinationRenderSystem(RenderSystem* sys)
1294{
1295    mDestRenderSystem = sys;
1296
1297}
1298
1299
1300//-----------------------------------------------------------------------
1301void SceneManager::setWorldGeometry(const String& filename)
1302{
1303    // This default implementation cannot handle world geometry
1304    OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
1305        "World geometry is not supported by the generic SceneManager.",
1306        "SceneManager::setWorldGeometry");
1307}
1308//-----------------------------------------------------------------------
1309void SceneManager::setWorldGeometry(DataStreamPtr& stream, 
1310        const String& typeName)
1311{
1312    // This default implementation cannot handle world geometry
1313    OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
1314        "World geometry is not supported by the generic SceneManager.",
1315        "SceneManager::setWorldGeometry");
1316}
1317
1318//-----------------------------------------------------------------------
1319bool SceneManager::materialLess::operator() (const Material* x, const Material* y) const
1320{
1321    // If x transparent and y not, x > y (since x has to overlap y)
1322    if (x->isTransparent() && !y->isTransparent())
1323    {
1324        return false;
1325    }
1326    // If y is transparent and x not, x < y
1327    else if (!x->isTransparent() && y->isTransparent())
1328    {
1329        return true;
1330    }
1331    else
1332    {
1333        // Otherwise don't care (both transparent or both solid)
1334        // Just arbitrarily use pointer
1335        return x < y;
1336    }
1337
1338}
1339
1340//-----------------------------------------------------------------------
1341void SceneManager::setSkyPlane(
1342                               bool enable,
1343                               const Plane& plane,
1344                               const String& materialName,
1345                               Real gscale,
1346                               Real tiling,
1347                               bool drawFirst,
1348                               Real bow, 
1349                               int xsegments, int ysegments, 
1350                               const String& groupName)
1351{
1352    if (enable)
1353    {
1354        String meshName = mName + "SkyPlane";
1355        mSkyPlane = plane;
1356
1357        MaterialPtr m = MaterialManager::getSingleton().getByName(materialName);
1358        if (m.isNull())
1359        {
1360            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 
1361                "Sky plane material '" + materialName + "' not found.",
1362                "SceneManager::setSkyPlane");
1363        }
1364        // Make sure the material doesn't update the depth buffer
1365        m->setDepthWriteEnabled(false);
1366        // Ensure loaded
1367        m->load();
1368
1369        mSkyPlaneDrawFirst = drawFirst;
1370
1371        // Set up the plane
1372        MeshPtr planeMesh = MeshManager::getSingleton().getByName(meshName);
1373        if (!planeMesh.isNull())
1374        {
1375            // Destroy the old one
1376            MeshManager::getSingleton().remove(planeMesh->getHandle());
1377        }
1378
1379        // Create up vector
1380        Vector3 up = plane.normal.crossProduct(Vector3::UNIT_X);
1381        if (up == Vector3::ZERO)
1382            up = plane.normal.crossProduct(-Vector3::UNIT_Z);
1383
1384        // Create skyplane
1385        if( bow > 0 )
1386        {
1387            // Build a curved skyplane
1388            planeMesh = MeshManager::getSingleton().createCurvedPlane(
1389                meshName, groupName, plane, gscale * 100, gscale * 100, gscale * bow * 100, 
1390                xsegments, ysegments, false, 1, tiling, tiling, up);
1391        }
1392        else
1393        {
1394            planeMesh = MeshManager::getSingleton().createPlane(
1395                meshName, groupName, plane, gscale * 100, gscale * 100, xsegments, ysegments, false, 
1396                1, tiling, tiling, up);
1397        }
1398
1399        // Create entity
1400        if (mSkyPlaneEntity)
1401        {
1402            // destroy old one, do it by name for speed
1403            destroyEntity(meshName);
1404        }
1405        // Create, use the same name for mesh and entity
1406        mSkyPlaneEntity = createEntity(meshName, meshName);
1407        mSkyPlaneEntity->setMaterialName(materialName);
1408        mSkyPlaneEntity->setCastShadows(false);
1409
1410        // Create node and attach
1411        if (!mSkyPlaneNode)
1412        {
1413            mSkyPlaneNode = createSceneNode(meshName + "Node");
1414        }
1415        else
1416        {
1417            mSkyPlaneNode->detachAllObjects();
1418        }
1419        mSkyPlaneNode->attachObject(mSkyPlaneEntity);
1420
1421    }
1422        mSkyPlaneEnabled = enable;
1423        mSkyPlaneGenParameters.skyPlaneBow = bow;
1424        mSkyPlaneGenParameters.skyPlaneScale = gscale;
1425        mSkyPlaneGenParameters.skyPlaneTiling = tiling;
1426        mSkyPlaneGenParameters.skyPlaneXSegments = xsegments;
1427        mSkyPlaneGenParameters.skyPlaneYSegments = ysegments;
1428}
1429//-----------------------------------------------------------------------
1430void SceneManager::setSkyBox(
1431                             bool enable,
1432                             const String& materialName,
1433                             Real distance,
1434                             bool drawFirst,
1435                             const Quaternion& orientation,
1436                             const String& groupName)
1437{
1438    if (enable)
1439    {
1440        MaterialPtr m = MaterialManager::getSingleton().getByName(materialName);
1441        if (m.isNull())
1442        {
1443            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 
1444                "Sky box material '" + materialName + "' not found.",
1445                "SceneManager::setSkyBox");
1446        }
1447        // Make sure the material doesn't update the depth buffer
1448        m->setDepthWriteEnabled(false);
1449        // Ensure loaded
1450        m->load();
1451        // Also clamp texture, don't wrap (otherwise edges can get filtered)
1452        m->getBestTechnique()->getPass(0)->getTextureUnitState(0)->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
1453
1454
1455        mSkyBoxDrawFirst = drawFirst;
1456
1457        // Create node
1458        if (!mSkyBoxNode)
1459        {
1460            mSkyBoxNode = createSceneNode("SkyBoxNode");
1461        }
1462        else
1463        {
1464            mSkyBoxNode->detachAllObjects();
1465        }
1466
1467        MaterialManager& matMgr = MaterialManager::getSingleton();
1468        // Set up the box (6 planes)
1469        for (int i = 0; i < 6; ++i)
1470        {
1471            MeshPtr planeMesh = createSkyboxPlane((BoxPlane)i, distance, orientation, groupName);
1472            String entName = mName + "SkyBoxPlane" + StringConverter::toString(i);
1473
1474            // Create entity
1475            if (mSkyBoxEntity[i])
1476            {
1477                // destroy old one, do it by name for speed
1478                destroyEntity(entName);
1479            }
1480            mSkyBoxEntity[i] = createEntity(entName, planeMesh->getName());
1481            mSkyBoxEntity[i]->setCastShadows(false);
1482            // Have to create 6 materials, one for each frame
1483            // Used to use combined material but now we're using queue we can't split to change frame
1484            // This doesn't use much memory because textures aren't duplicated
1485            MaterialPtr boxMat = matMgr.getByName(entName);
1486            if (boxMat.isNull())
1487            {
1488                // Create new by clone
1489                boxMat = m->clone(entName);
1490                boxMat->load();
1491            }
1492            else
1493            {
1494                // Copy over existing
1495                m->copyDetailsTo(boxMat);
1496                boxMat->load();
1497            }
1498            // Set active frame
1499                        Material::TechniqueIterator ti = boxMat->getSupportedTechniqueIterator();
1500                        while (ti.hasMoreElements())
1501                        {
1502                                Technique* tech = ti.getNext();
1503                                tech->getPass(0)->getTextureUnitState(0)->setCurrentFrame(i);
1504                        }
1505
1506            mSkyBoxEntity[i]->setMaterialName(boxMat->getName());
1507
1508            // Attach to node
1509            mSkyBoxNode->attachObject(mSkyBoxEntity[i]);
1510        } // for each plane
1511
1512    }
1513        mSkyBoxEnabled = enable;
1514        mSkyBoxGenParameters.skyBoxDistance = distance;
1515}
1516//-----------------------------------------------------------------------
1517void SceneManager::setSkyDome(
1518                              bool enable,
1519                              const String& materialName,
1520                              Real curvature,
1521                              Real tiling,
1522                              Real distance,
1523                              bool drawFirst,
1524                              const Quaternion& orientation,
1525                              int xsegments, int ysegments, int ySegmentsToKeep,
1526                              const String& groupName)
1527{
1528    if (enable)
1529    {
1530        MaterialPtr m = MaterialManager::getSingleton().getByName(materialName);
1531        if (m.isNull())
1532        {
1533            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 
1534                "Sky dome material '" + materialName + "' not found.",
1535                "SceneManager::setSkyDome");
1536        }
1537        // Make sure the material doesn't update the depth buffer
1538        m->setDepthWriteEnabled(false);
1539        // Ensure loaded
1540        m->load();
1541
1542        mSkyDomeDrawFirst = drawFirst;
1543
1544        // Create node
1545        if (!mSkyDomeNode)
1546        {
1547            mSkyDomeNode = createSceneNode("SkyDomeNode");
1548        }
1549        else
1550        {
1551            mSkyDomeNode->detachAllObjects();
1552        }
1553
1554        // Set up the dome (5 planes)
1555        for (int i = 0; i < 5; ++i)
1556        {
1557            MeshPtr planeMesh = createSkydomePlane((BoxPlane)i, curvature, 
1558                tiling, distance, orientation, xsegments, ysegments, 
1559                i!=BP_UP ? ySegmentsToKeep : -1, groupName);
1560
1561            String entName = "SkyDomePlane" + StringConverter::toString(i);
1562
1563            // Create entity
1564            if (mSkyDomeEntity[i])
1565            {
1566                // destroy old one, do it by name for speed
1567                destroyEntity(entName);
1568            }
1569            mSkyDomeEntity[i] = createEntity(entName, planeMesh->getName());
1570            mSkyDomeEntity[i]->setMaterialName(m->getName());
1571            mSkyDomeEntity[i]->setCastShadows(false);
1572
1573            // Attach to node
1574            mSkyDomeNode->attachObject(mSkyDomeEntity[i]);
1575        } // for each plane
1576
1577    }
1578        mSkyDomeEnabled = enable;
1579        mSkyDomeGenParameters.skyDomeCurvature = curvature;
1580        mSkyDomeGenParameters.skyDomeDistance = distance;
1581        mSkyDomeGenParameters.skyDomeTiling = tiling;
1582        mSkyDomeGenParameters.skyDomeXSegments = xsegments;
1583        mSkyDomeGenParameters.skyDomeYSegments = ysegments;
1584        mSkyDomeGenParameters.skyDomeYSegments_keep = ySegmentsToKeep;
1585}
1586//-----------------------------------------------------------------------
1587MeshPtr SceneManager::createSkyboxPlane(
1588                                      BoxPlane bp,
1589                                      Real distance,
1590                                      const Quaternion& orientation,
1591                                      const String& groupName)
1592{
1593    Plane plane;
1594    String meshName;
1595    Vector3 up;
1596
1597    meshName = mName + "SkyBoxPlane_";
1598    // Set up plane equation
1599    plane.d = distance;
1600    switch(bp)
1601    {
1602    case BP_FRONT:
1603        plane.normal = Vector3::UNIT_Z;
1604        up = Vector3::UNIT_Y;
1605        meshName += "Front";
1606        break;
1607    case BP_BACK:
1608        plane.normal = -Vector3::UNIT_Z;
1609        up = Vector3::UNIT_Y;
1610        meshName += "Back";
1611        break;
1612    case BP_LEFT:
1613        plane.normal = Vector3::UNIT_X;
1614        up = Vector3::UNIT_Y;
1615        meshName += "Left";
1616        break;
1617    case BP_RIGHT:
1618        plane.normal = -Vector3::UNIT_X;
1619        up = Vector3::UNIT_Y;
1620        meshName += "Right";
1621        break;
1622    case BP_UP:
1623        plane.normal = -Vector3::UNIT_Y;
1624        up = Vector3::UNIT_Z;
1625        meshName += "Up";
1626        break;
1627    case BP_DOWN:
1628        plane.normal = Vector3::UNIT_Y;
1629        up = -Vector3::UNIT_Z;
1630        meshName += "Down";
1631        break;
1632    }
1633    // Modify by orientation
1634    plane.normal = orientation * plane.normal;
1635    up = orientation * up;
1636
1637
1638    // Check to see if existing plane
1639    MeshManager& mm = MeshManager::getSingleton();
1640    MeshPtr planeMesh = mm.getByName(meshName);
1641    if(!planeMesh.isNull())
1642    {
1643        // destroy existing
1644        mm.remove(planeMesh->getHandle());
1645    }
1646    // Create new
1647    Real planeSize = distance * 2;
1648    const int BOX_SEGMENTS = 1;
1649    planeMesh = mm.createPlane(meshName, groupName, plane, planeSize, planeSize, 
1650        BOX_SEGMENTS, BOX_SEGMENTS, false, 1, 1, 1, up);
1651
1652    //planeMesh->_dumpContents(meshName);
1653
1654    return planeMesh;
1655
1656}
1657//-----------------------------------------------------------------------
1658MeshPtr SceneManager::createSkydomePlane(
1659                                       BoxPlane bp,
1660                                       Real curvature,
1661                                       Real tiling,
1662                                       Real distance,
1663                                       const Quaternion& orientation,
1664                                       int xsegments, int ysegments, int ysegments_keep, 
1665                                       const String& groupName)
1666{
1667
1668    Plane plane;
1669    String meshName;
1670    Vector3 up;
1671
1672    meshName = mName + "SkyDomePlane_";
1673    // Set up plane equation
1674    plane.d = distance;
1675    switch(bp)
1676    {
1677    case BP_FRONT:
1678        plane.normal = Vector3::UNIT_Z;
1679        up = Vector3::UNIT_Y;
1680        meshName += "Front";
1681        break;
1682    case BP_BACK:
1683        plane.normal = -Vector3::UNIT_Z;
1684        up = Vector3::UNIT_Y;
1685        meshName += "Back";
1686        break;
1687    case BP_LEFT:
1688        plane.normal = Vector3::UNIT_X;
1689        up = Vector3::UNIT_Y;
1690        meshName += "Left";
1691        break;
1692    case BP_RIGHT:
1693        plane.normal = -Vector3::UNIT_X;
1694        up = Vector3::UNIT_Y;
1695        meshName += "Right";
1696        break;
1697    case BP_UP:
1698        plane.normal = -Vector3::UNIT_Y;
1699        up = Vector3::UNIT_Z;
1700        meshName += "Up";
1701        break;
1702    case BP_DOWN:
1703        // no down
1704        return MeshPtr();
1705    }
1706    // Modify by orientation
1707    plane.normal = orientation * plane.normal;
1708    up = orientation * up;
1709
1710    // Check to see if existing plane
1711    MeshManager& mm = MeshManager::getSingleton();
1712    MeshPtr planeMesh = mm.getByName(meshName);
1713    if(!planeMesh.isNull())
1714    {
1715        // destroy existing
1716        mm.remove(planeMesh->getHandle());
1717    }
1718    // Create new
1719    Real planeSize = distance * 2;
1720    planeMesh = mm.createCurvedIllusionPlane(meshName, groupName, plane, 
1721        planeSize, planeSize, curvature, 
1722        xsegments, ysegments, false, 1, tiling, tiling, up, 
1723        orientation, HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, HardwareBuffer::HBU_STATIC_WRITE_ONLY, 
1724        false, false, ysegments_keep);
1725
1726    //planeMesh->_dumpContents(meshName);
1727
1728    return planeMesh;
1729
1730}
1731
1732
1733//-----------------------------------------------------------------------
1734void SceneManager::_updateSceneGraph(Camera* cam)
1735{
1736        // Process queued needUpdate calls
1737        Node::processQueuedUpdates();
1738
1739    // Cascade down the graph updating transforms & world bounds
1740    // In this implementation, just update from the root
1741    // Smarter SceneManager subclasses may choose to update only
1742    //   certain scene graph branches
1743    mSceneRoot->_update(true, false);
1744
1745
1746}
1747//-----------------------------------------------------------------------
1748void SceneManager::_findVisibleObjects(
1749        Camera* cam, VisibleObjectsBoundsInfo* visibleBounds, bool onlyShadowCasters)
1750{
1751    // Tell nodes to find, cascade down all nodes
1752    mSceneRoot->_findVisibleObjects(cam, getRenderQueue(), visibleBounds, true, 
1753        mDisplayNodes, onlyShadowCasters);
1754
1755}
1756//-----------------------------------------------------------------------
1757void SceneManager::_renderVisibleObjects(void)
1758{
1759        RenderQueueInvocationSequence* invocationSequence = 
1760                mCurrentViewport->_getRenderQueueInvocationSequence();
1761        // Use custom sequence only if we're not doing the texture shadow render
1762        // since texture shadow render should not be interfered with by suppressing
1763        // render state changes for example
1764        if (invocationSequence && mIlluminationStage != IRS_RENDER_TO_TEXTURE)
1765        {
1766                renderVisibleObjectsCustomSequence(invocationSequence);
1767        }
1768        else
1769        {
1770                renderVisibleObjectsDefaultSequence();
1771        }
1772}
1773//-----------------------------------------------------------------------
1774void SceneManager::renderVisibleObjectsCustomSequence(RenderQueueInvocationSequence* seq)
1775{
1776        RenderQueueInvocationIterator invocationIt = seq->iterator();
1777        while (invocationIt.hasMoreElements())
1778        {
1779                RenderQueueInvocation* invocation = invocationIt.getNext();
1780                uint8 qId = invocation->getRenderQueueGroupID();
1781                // Skip this one if not to be processed
1782                if (!isRenderQueueToBeProcessed(qId))
1783                        continue;
1784
1785
1786                bool repeatQueue = false;
1787                const String& invocationName = invocation->getInvocationName();
1788                RenderQueueGroup* queueGroup = getRenderQueue()->getQueueGroup(qId);
1789                do // for repeating queues
1790                {
1791                        // Fire queue started event
1792                        if (fireRenderQueueStarted(qId, invocationName))
1793                        {
1794                                // Someone requested we skip this queue
1795                                break;
1796                        }
1797
1798                        // Invoke it
1799                        invocation->invoke(queueGroup, this);
1800
1801                        // Fire queue ended event
1802                        if (fireRenderQueueEnded(qId, invocationName))
1803                        {
1804                                // Someone requested we repeat this queue
1805                                repeatQueue = true;
1806                        }
1807                        else
1808                        {
1809                                repeatQueue = false;
1810                        }
1811                } while (repeatQueue);
1812
1813
1814        }
1815}
1816//-----------------------------------------------------------------------
1817void SceneManager::renderVisibleObjectsDefaultSequence(void)
1818{
1819    // Render each separate queue
1820    RenderQueue::QueueGroupIterator queueIt = getRenderQueue()->_getQueueGroupIterator();
1821
1822    // NB only queues which have been created are rendered, no time is wasted
1823    //   parsing through non-existent queues (even though there are 10 available)
1824
1825    while (queueIt.hasMoreElements())
1826    {
1827        // Get queue group id
1828        uint8 qId = queueIt.peekNextKey();
1829                RenderQueueGroup* pGroup = queueIt.getNext();
1830                // Skip this one if not to be processed
1831                if (!isRenderQueueToBeProcessed(qId))
1832                        continue;
1833
1834
1835        bool repeatQueue = false;
1836        do // for repeating queues
1837        {
1838            // Fire queue started event
1839                        if (fireRenderQueueStarted(qId, 
1840                                mIlluminationStage == IRS_RENDER_TO_TEXTURE ? 
1841                                        RenderQueueInvocation::RENDER_QUEUE_INVOCATION_SHADOWS : 
1842                                        StringUtil::BLANK))
1843            {
1844                // Someone requested we skip this queue
1845                break;
1846            }
1847
1848                        _renderQueueGroupObjects(pGroup, QueuedRenderableCollection::OM_PASS_GROUP);
1849
1850            // Fire queue ended event
1851                        if (fireRenderQueueEnded(qId, 
1852                                mIlluminationStage == IRS_RENDER_TO_TEXTURE ? 
1853                                        RenderQueueInvocation::RENDER_QUEUE_INVOCATION_SHADOWS : 
1854                                        StringUtil::BLANK))
1855            {
1856                // Someone requested we repeat this queue
1857                repeatQueue = true;
1858            }
1859            else
1860            {
1861                repeatQueue = false;
1862            }
1863        } while (repeatQueue);
1864
1865    } // for each queue group
1866
1867}
1868//-----------------------------------------------------------------------
1869void SceneManager::renderAdditiveStencilShadowedQueueGroupObjects(
1870        RenderQueueGroup* pGroup, 
1871        QueuedRenderableCollection::OrganisationMode om)
1872{
1873    RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator();
1874    LightList lightList;
1875
1876    while (groupIt.hasMoreElements())
1877    {
1878        RenderPriorityGroup* pPriorityGrp = groupIt.getNext();
1879
1880        // Sort the queue first
1881        pPriorityGrp->sort(mCameraInProgress);
1882
1883        // Clear light list
1884        lightList.clear();
1885
1886        // Render all the ambient passes first, no light iteration, no lights
1887        renderObjects(pPriorityGrp->getSolidsBasic(), om, false, &lightList);
1888        // Also render any objects which have receive shadows disabled
1889        renderObjects(pPriorityGrp->getSolidsNoShadowReceive(), om, true);
1890
1891
1892        // Now iterate per light
1893        // Iterate over lights, render all volumes to stencil
1894        LightList::const_iterator li, liend;
1895        liend = mLightsAffectingFrustum.end();
1896
1897        for (li = mLightsAffectingFrustum.begin(); li != liend; ++li)
1898        {
1899            Light* l = *li;
1900            // Set light state
1901
1902            if (l->getCastShadows())
1903            {
1904                // Clear stencil
1905                mDestRenderSystem->clearFrameBuffer(FBT_STENCIL);
1906                renderShadowVolumesToStencil(l, mCameraInProgress);
1907                // turn stencil check on
1908                mDestRenderSystem->setStencilCheckEnabled(true);
1909                // NB we render where the stencil is equal to zero to render lit areas
1910                mDestRenderSystem->setStencilBufferParams(CMPF_EQUAL, 0);
1911            }
1912
1913            // render lighting passes for this light
1914            if (lightList.empty())
1915                lightList.push_back(l);
1916            else
1917                lightList[0] = l;
1918            renderObjects(pPriorityGrp->getSolidsDiffuseSpecular(), om, false, &lightList);
1919
1920            // Reset stencil params
1921            mDestRenderSystem->setStencilBufferParams();
1922            mDestRenderSystem->setStencilCheckEnabled(false);
1923            mDestRenderSystem->_setDepthBufferParams();
1924
1925        }// for each light
1926
1927
1928        // Now render decal passes, no need to set lights as lighting will be disabled
1929        renderObjects(pPriorityGrp->getSolidsDecal(), om, false);
1930
1931
1932    }// for each priority
1933
1934    // Iterate again - variable name changed to appease gcc.
1935    RenderQueueGroup::PriorityMapIterator groupIt2 = pGroup->getIterator();
1936    while (groupIt2.hasMoreElements())
1937    {
1938        RenderPriorityGroup* pPriorityGrp = groupIt2.getNext();
1939
1940        // Do transparents (always descending sort)
1941        renderObjects(pPriorityGrp->getTransparents(), 
1942                        QueuedRenderableCollection::OM_SORT_DESCENDING, true);
1943
1944    }// for each priority
1945
1946
1947}
1948//-----------------------------------------------------------------------
1949void SceneManager::renderModulativeStencilShadowedQueueGroupObjects(
1950        RenderQueueGroup* pGroup, 
1951        QueuedRenderableCollection::OrganisationMode om)
1952{
1953    /* For each light, we need to render all the solids from each group,
1954    then do the modulative shadows, then render the transparents from
1955    each group.
1956    Now, this means we are going to reorder things more, but that it required
1957    if the shadows are to look correct. The overall order is preserved anyway,
1958    it's just that all the transparents are at the end instead of them being
1959    interleaved as in the normal rendering loop.
1960    */
1961    // Iterate through priorities
1962    RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator();
1963
1964    while (groupIt.hasMoreElements())
1965    {
1966        RenderPriorityGroup* pPriorityGrp = groupIt.getNext();
1967
1968        // Sort the queue first
1969        pPriorityGrp->sort(mCameraInProgress);
1970
1971        // Do (shadowable) solids
1972        renderObjects(pPriorityGrp->getSolidsBasic(), om, true);
1973    }
1974
1975
1976    // Iterate over lights, render all volumes to stencil
1977    LightList::const_iterator li, liend;
1978    liend = mLightsAffectingFrustum.end();
1979
1980    for (li = mLightsAffectingFrustum.begin(); li != liend; ++li)
1981    {
1982        Light* l = *li;
1983        if (l->getCastShadows())
1984        {
1985            // Clear stencil
1986            mDestRenderSystem->clearFrameBuffer(FBT_STENCIL);
1987            renderShadowVolumesToStencil(l, mCameraInProgress);
1988            // render full-screen shadow modulator for all lights
1989            _setPass(mShadowModulativePass);
1990            // turn stencil check on
1991            mDestRenderSystem->setStencilCheckEnabled(true);
1992            // NB we render where the stencil is not equal to zero to render shadows, not lit areas
1993            mDestRenderSystem->setStencilBufferParams(CMPF_NOT_EQUAL, 0);
1994            renderSingleObject(mFullScreenQuad, mShadowModulativePass, false);
1995            // Reset stencil params
1996            mDestRenderSystem->setStencilBufferParams();
1997            mDestRenderSystem->setStencilCheckEnabled(false);
1998            mDestRenderSystem->_setDepthBufferParams();
1999        }
2000
2001    }// for each light
2002
2003    // Iterate again - variable name changed to appease gcc.
2004    RenderQueueGroup::PriorityMapIterator groupIt2 = pGroup->getIterator();
2005    while (groupIt2.hasMoreElements())
2006    {
2007        RenderPriorityGroup* pPriorityGrp = groupIt2.getNext();
2008
2009        // Do non-shadowable solids
2010        renderObjects(pPriorityGrp->getSolidsNoShadowReceive(), om, true);
2011
2012    }// for each priority
2013
2014
2015    // Iterate again - variable name changed to appease gcc.
2016    RenderQueueGroup::PriorityMapIterator groupIt3 = pGroup->getIterator();
2017    while (groupIt3.hasMoreElements())
2018    {
2019        RenderPriorityGroup* pPriorityGrp = groupIt3.getNext();
2020
2021        // Do transparents (always descending sort)
2022        renderObjects(pPriorityGrp->getTransparents(), 
2023                        QueuedRenderableCollection::OM_SORT_DESCENDING, true);
2024
2025    }// for each priority
2026
2027}
2028//-----------------------------------------------------------------------
2029void SceneManager::renderTextureShadowCasterQueueGroupObjects(
2030        RenderQueueGroup* pGroup, 
2031        QueuedRenderableCollection::OrganisationMode om)
2032{
2033    static LightList nullLightList;
2034    // This is like the basic group render, except we skip all transparents
2035    // and we also render any non-shadowed objects
2036    // Note that non-shadow casters will have already been eliminated during
2037    // _findVisibleObjects
2038
2039    // Iterate through priorities
2040    RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator();
2041
2042    // Override auto param ambient to force vertex programs and fixed function to
2043        if (isShadowTechniqueAdditive())
2044        {
2045                // Use simple black / white mask if additive
2046                mAutoParamDataSource.setAmbientLightColour(ColourValue::Black);
2047                mDestRenderSystem->setAmbientLight(0, 0, 0);
2048        }
2049        else
2050        {
2051                // Use shadow colour as caster colour if modulative
2052                mAutoParamDataSource.setAmbientLightColour(mShadowColour);
2053                mDestRenderSystem->setAmbientLight(mShadowColour.r, mShadowColour.g, mShadowColour.b);
2054        }
2055
2056    while (groupIt.hasMoreElements())
2057    {
2058        RenderPriorityGroup* pPriorityGrp = groupIt.getNext();
2059
2060        // Sort the queue first
2061        pPriorityGrp->sort(mCameraInProgress);
2062
2063        // Do solids, override light list incase any vertex programs use them
2064        renderObjects(pPriorityGrp->getSolidsBasic(), om, false, &nullLightList);
2065        renderObjects(pPriorityGrp->getSolidsNoShadowReceive(), om, false, &nullLightList);
2066                // Do transparents that cast shadows
2067                renderTransparentShadowCasterObjects(
2068                                pPriorityGrp->getTransparents(), 
2069                                QueuedRenderableCollection::OM_SORT_DESCENDING, 
2070                                false, &nullLightList);
2071
2072
2073    }// for each priority
2074
2075    // reset ambient light
2076    mAutoParamDataSource.setAmbientLightColour(mAmbientLight);
2077    mDestRenderSystem->setAmbientLight(mAmbientLight.r, mAmbientLight.g, mAmbientLight.b);
2078}
2079//-----------------------------------------------------------------------
2080void SceneManager::renderModulativeTextureShadowedQueueGroupObjects(
2081        RenderQueueGroup* pGroup, 
2082        QueuedRenderableCollection::OrganisationMode om)
2083{
2084    /* For each light, we need to render all the solids from each group,
2085    then do the modulative shadows, then render the transparents from
2086    each group.
2087    Now, this means we are going to reorder things more, but that it required
2088    if the shadows are to look correct. The overall order is preserved anyway,
2089    it's just that all the transparents are at the end instead of them being
2090    interleaved as in the normal rendering loop.
2091    */
2092    // Iterate through priorities
2093    RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator();
2094
2095    while (groupIt.hasMoreElements())
2096    {
2097        RenderPriorityGroup* pPriorityGrp = groupIt.getNext();
2098
2099        // Sort the queue first
2100        pPriorityGrp->sort(mCameraInProgress);
2101
2102        // Do solids
2103        renderObjects(pPriorityGrp->getSolidsBasic(), om, true);
2104        renderObjects(pPriorityGrp->getSolidsNoShadowReceive(), om, true);
2105    }
2106
2107
2108    // Iterate over lights, render received shadows
2109    // only perform this if we're in the 'normal' render stage, to avoid
2110    // doing it during the render to texture
2111    if (mIlluminationStage == IRS_NONE)
2112    {
2113        mIlluminationStage = IRS_RENDER_RECEIVER_PASS;
2114
2115        LightList::iterator i, iend;
2116        ShadowTextureList::iterator si, siend;
2117        iend = mLightsAffectingFrustum.end();
2118        siend = mShadowTextures.end();
2119        for (i = mLightsAffectingFrustum.begin(), si = mShadowTextures.begin();
2120            i != iend && si != siend; ++i)
2121        {
2122            Light* l = *i;
2123
2124            if (!l->getCastShadows())
2125                continue;
2126
2127                        // Store current shadow texture
2128            mCurrentShadowTexture = si->getPointer();
2129                        // Get camera for current shadow texture
2130            Camera *cam = mCurrentShadowTexture->getBuffer()->getRenderTarget()->getViewport(0)->getCamera();
2131            // Hook up receiver texture
2132                        Pass* targetPass = mShadowTextureCustomReceiverPass ?
2133                                mShadowTextureCustomReceiverPass : mShadowReceiverPass;
2134                        targetPass->getTextureUnitState(0)->setTextureName(
2135                                mCurrentShadowTexture->getName());
2136                        // Hook up projection frustum if fixed-function, but also need to
2137                        // disable it explicitly for program pipeline.
2138                        TextureUnitState* texUnit = targetPass->getTextureUnitState(0);
2139                        texUnit->setProjectiveTexturing(!targetPass->hasVertexProgram(), cam);
2140                        // clamp to border colour in case this is a custom material
2141                        texUnit->setTextureAddressingMode(TextureUnitState::TAM_BORDER);
2142                        texUnit->setTextureBorderColour(ColourValue::White);
2143
2144            mAutoParamDataSource.setTextureProjector(cam, 0);
2145            // if this light is a spotlight, we need to add the spot fader layer
2146                        // BUT not if using a custom projection matrix, since then it will be
2147                        // inappropriately shaped most likely
2148            if (l->getType() == Light::LT_SPOTLIGHT && !cam->isCustomProjectionMatrixEnabled())
2149            {
2150                                // remove all TUs except 0 & 1
2151                                // (only an issue if additive shadows have been used)
2152                                while(targetPass->getNumTextureUnitStates() > 2)
2153                                        targetPass->removeTextureUnitState(2);
2154
2155                // Add spot fader if not present already
2156                if (targetPass->getNumTextureUnitStates() == 2 && 
2157                                        targetPass->getTextureUnitState(1)->getTextureName() == 
2158                                                "spot_shadow_fade.png")
2159                                {
2160                                        // Just set
2161                                        TextureUnitState* t = 
2162                                                targetPass->getTextureUnitState(1);
2163                                        t->setProjectiveTexturing(!targetPass->hasVertexProgram(), cam);
2164                                }
2165                else
2166                                {
2167                                        // Remove any non-conforming spot layers
2168                                        while(targetPass->getNumTextureUnitStates() > 1)
2169                                                targetPass->removeTextureUnitState(1);
2170
2171                    TextureUnitState* t = 
2172                        targetPass->createTextureUnitState("spot_shadow_fade.png");
2173                    t->setProjectiveTexturing(!targetPass->hasVertexProgram(), cam);
2174                    t->setColourOperation(LBO_ADD);
2175                    t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
2176                }
2177            }
2178            else 
2179            {
2180                                // remove all TUs except 0 including spot
2181                                while(targetPass->getNumTextureUnitStates() > 1)
2182                        targetPass->removeTextureUnitState(1);
2183
2184            }
2185                        // Set lighting / blending modes
2186                        targetPass->setSceneBlending(SBF_DEST_COLOUR, SBF_ZERO);
2187                        targetPass->setLightingEnabled(false);
2188
2189            targetPass->_load();
2190
2191                        // Fire pre-receiver event
2192                        fireShadowTexturesPreReceiver(l, cam);
2193
2194            renderTextureShadowReceiverQueueGroupObjects(pGroup, om);
2195
2196            ++si;
2197
2198        }// for each light
2199
2200        mIlluminationStage = IRS_NONE;
2201
2202    }
2203
2204    // Iterate again - variable name changed to appease gcc.
2205    RenderQueueGroup::PriorityMapIterator groupIt3 = pGroup->getIterator();
2206    while (groupIt3.hasMoreElements())
2207    {
2208        RenderPriorityGroup* pPriorityGrp = groupIt3.getNext();
2209
2210        // Do transparents (always descending)
2211        renderObjects(pPriorityGrp->getTransparents(), 
2212                        QueuedRenderableCollection::OM_SORT_DESCENDING, true);
2213
2214    }// for each priority
2215
2216}
2217//-----------------------------------------------------------------------
2218void SceneManager::renderAdditiveTextureShadowedQueueGroupObjects(
2219        RenderQueueGroup* pGroup, 
2220        QueuedRenderableCollection::OrganisationMode om)
2221{
2222        RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator();
2223        LightList lightList;
2224
2225        while (groupIt.hasMoreElements())
2226        {
2227                RenderPriorityGroup* pPriorityGrp = groupIt.getNext();
2228
2229                // Sort the queue first
2230                pPriorityGrp->sort(mCameraInProgress);
2231
2232                // Clear light list
2233                lightList.clear();
2234
2235                // Render all the ambient passes first, no light iteration, no lights
2236                renderObjects(pPriorityGrp->getSolidsBasic(), om, false, &lightList);
2237                // Also render any objects which have receive shadows disabled
2238                renderObjects(pPriorityGrp->getSolidsNoShadowReceive(), om, true);
2239
2240
2241                // only perform this next part if we're in the 'normal' render stage, to avoid
2242                // doing it during the render to texture
2243                if (mIlluminationStage == IRS_NONE)
2244                {
2245                        // Iterate over lights, render masked
2246                        LightList::const_iterator li, liend;
2247                        ShadowTextureList::iterator si, siend;
2248                        liend = mLightsAffectingFrustum.end();
2249                        siend = mShadowTextures.end();
2250            si = mShadowTextures.begin();
2251
2252                        for (li = mLightsAffectingFrustum.begin(); li != liend; ++li)
2253                        {
2254                                Light* l = *li;
2255
2256                                if (l->getCastShadows() && si != siend)
2257                                {
2258                                        // Store current shadow texture
2259                                        mCurrentShadowTexture = si->getPointer();
2260                                        // Get camera for current shadow texture
2261                                        Camera *cam = mCurrentShadowTexture->getBuffer()->getRenderTarget()->getViewport(0)->getCamera();
2262                                        // Hook up receiver texture
2263                                        Pass* targetPass = mShadowTextureCustomReceiverPass ?
2264                                                mShadowTextureCustomReceiverPass : mShadowReceiverPass;
2265                                        targetPass->getTextureUnitState(0)->setTextureName(
2266                                                mCurrentShadowTexture->getName());
2267                                        // Hook up projection frustum if fixed-function, but also need to
2268                                        // disable it explicitly for program pipeline.
2269                                        TextureUnitState* texUnit = targetPass->getTextureUnitState(0);
2270                                        texUnit->setProjectiveTexturing(!targetPass->hasVertexProgram(), cam);
2271                                        // clamp to border colour in case this is a custom material
2272                                        texUnit->setTextureAddressingMode(TextureUnitState::TAM_BORDER);
2273                                        texUnit->setTextureBorderColour(ColourValue::White);
2274                                        mAutoParamDataSource.setTextureProjector(cam, 0);
2275                                        // Remove any spot fader layer
2276                                        if (targetPass->getNumTextureUnitStates() > 1 && 
2277                                                targetPass->getTextureUnitState(1)->getTextureName() 
2278                                                        == "spot_shadow_fade.png")
2279                                        {
2280                                                // remove spot fader layer (should only be there if
2281                                                // we previously used modulative shadows)
2282                                                targetPass->removeTextureUnitState(1);
2283                                        }
2284                                        // Set lighting / blending modes
2285                                        targetPass->setSceneBlending(SBF_ONE, SBF_ONE);
2286                                        targetPass->setLightingEnabled(true);
2287                                        targetPass->_load();
2288
2289                                        // increment shadow texture since used
2290                                        ++si;
2291
2292                                        mIlluminationStage = IRS_RENDER_RECEIVER_PASS;
2293
2294                                }
2295                                else
2296                                {
2297                                        mIlluminationStage = IRS_NONE;
2298
2299                                }
2300
2301                // render lighting passes for this light
2302                if (lightList.empty())
2303                    lightList.push_back(l);
2304                else
2305                    lightList[0] = l;
2306                                renderObjects(pPriorityGrp->getSolidsDiffuseSpecular(), om, false, &lightList);
2307
2308                        }// for each light
2309
2310                        mIlluminationStage = IRS_NONE;
2311
2312                        // Now render decal passes, no need to set lights as lighting will be disabled
2313                        renderObjects(pPriorityGrp->getSolidsDecal(), om, false);
2314
2315                }
2316
2317
2318        }// for each priority
2319
2320        // Iterate again - variable name changed to appease gcc.
2321        RenderQueueGroup::PriorityMapIterator groupIt2 = pGroup->getIterator();
2322        while (groupIt2.hasMoreElements())
2323        {
2324                RenderPriorityGroup* pPriorityGrp = groupIt2.getNext();
2325
2326                // Do transparents (always descending sort)
2327                renderObjects(pPriorityGrp->getTransparents(), 
2328                        QueuedRenderableCollection::OM_SORT_DESCENDING, true);
2329
2330        }// for each priority
2331
2332}
2333//-----------------------------------------------------------------------
2334void SceneManager::renderTextureShadowReceiverQueueGroupObjects(
2335        RenderQueueGroup* pGroup, 
2336        QueuedRenderableCollection::OrganisationMode om)
2337{
2338    static LightList nullLightList;
2339
2340    // Iterate through priorities
2341    RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator();
2342
2343    // Override auto param ambient to force vertex programs to go full-bright
2344    mAutoParamDataSource.setAmbientLightColour(ColourValue::White);
2345    mDestRenderSystem->setAmbientLight(1, 1, 1);
2346
2347    while (groupIt.hasMoreElements())
2348    {
2349        RenderPriorityGroup* pPriorityGrp = groupIt.getNext();
2350
2351        // Do solids, override light list incase any vertex programs use them
2352        renderObjects(pPriorityGrp->getSolidsBasic(), om, false, &nullLightList);
2353
2354        // Don't render transparents or passes which have shadow receipt disabled
2355
2356    }// for each priority
2357
2358    // reset ambient
2359    mAutoParamDataSource.setAmbientLightColour(mAmbientLight);
2360    mDestRenderSystem->setAmbientLight(mAmbientLight.r, mAmbientLight.g, mAmbientLight.b);
2361
2362}
2363//-----------------------------------------------------------------------
2364void SceneManager::SceneMgrQueuedRenderableVisitor::visit(const Renderable* r)
2365{
2366        // Give SM a chance to eliminate
2367        if (targetSceneMgr->validateRenderableForRendering(mUsedPass, r))
2368        {
2369                // Render a single object, this will set up auto params if required
2370                targetSceneMgr->renderSingleObject(r, mUsedPass, autoLights, manualLightList);
2371        }
2372}
2373//-----------------------------------------------------------------------
2374bool SceneManager::SceneMgrQueuedRenderableVisitor::visit(const Pass* p)
2375{
2376        // Give SM a chance to eliminate this pass
2377        if (!targetSceneMgr->validatePassForRendering(p))
2378                return false;
2379
2380        // Set pass, store the actual one used
2381        mUsedPass = targetSceneMgr->_setPass(p);
2382
2383
2384        return true;
2385}
2386//-----------------------------------------------------------------------
2387void SceneManager::SceneMgrQueuedRenderableVisitor::visit(const RenderablePass* rp)
2388{
2389        // Skip this one if we're in transparency cast shadows mode & it doesn't
2390        // Don't need to implement this one in the other visit methods since
2391        // transparents are never grouped, always sorted
2392        if (transparentShadowCastersMode && 
2393                !rp->pass->getParent()->getParent()->getTransparencyCastsShadows())
2394                return;
2395
2396        // Give SM a chance to eliminate
2397        if (targetSceneMgr->validateRenderableForRendering(rp->pass, rp->renderable))
2398        {
2399                mUsedPass = targetSceneMgr->_setPass(rp->pass);
2400                targetSceneMgr->renderSingleObject(rp->renderable, mUsedPass, autoLights, 
2401                        manualLightList);
2402        }
2403}
2404//-----------------------------------------------------------------------
2405bool SceneManager::validatePassForRendering(const Pass* pass)
2406{
2407    // Bypass if we're doing a texture shadow render and
2408    // this pass is after the first (only 1 pass needed for shadow texture render, and
2409        // one pass for shadow texture receive for modulative technique)
2410        // Also bypass if passes above the first if render state changes are
2411        // suppressed since we're not actually using this pass data anyway
2412    if (!mSuppressShadows && mCurrentViewport->getShadowsEnabled() &&
2413                ((isShadowTechniqueModulative() && mIlluminationStage == IRS_RENDER_RECEIVER_PASS)
2414                 || mIlluminationStage == IRS_RENDER_TO_TEXTURE || mSuppressRenderStateChanges) && 
2415        pass->getIndex() > 0)
2416    {
2417        return false;
2418    }
2419
2420    return true;
2421}
2422//-----------------------------------------------------------------------
2423bool SceneManager::validateRenderableForRendering(const Pass* pass, const Renderable* rend)
2424{
2425    // Skip this renderable if we're doing modulative texture shadows, it casts shadows
2426    // and we're doing the render receivers pass and we're not self-shadowing
2427        // also if pass number > 0
2428    if (!mSuppressShadows && mCurrentViewport->getShadowsEnabled() &&
2429                isShadowTechniqueTextureBased())
2430        {
2431                if (mIlluminationStage == IRS_RENDER_RECEIVER_PASS && 
2432                        rend->getCastsShadows() && !mShadowTextureSelfShadow)
2433                {
2434                        return false;
2435                }
2436                // Some duplication here with validatePassForRendering, for transparents
2437                if (((isShadowTechniqueModulative() && mIlluminationStage == IRS_RENDER_RECEIVER_PASS)
2438                        || mIlluminationStage == IRS_RENDER_TO_TEXTURE || mSuppressRenderStateChanges) && 
2439                        pass->getIndex() > 0)
2440                {
2441                        return false;
2442                }
2443    }
2444
2445    return true;
2446
2447}
2448//-----------------------------------------------------------------------
2449void SceneManager::renderObjects(const QueuedRenderableCollection& objs, 
2450                                                                 QueuedRenderableCollection::OrganisationMode om, 
2451                                                                 bool doLightIteration, 
2452                                 const LightList* manualLightList)
2453{
2454        mActiveQueuedRenderableVisitor->autoLights = doLightIteration;
2455        mActiveQueuedRenderableVisitor->manualLightList = manualLightList;
2456        mActiveQueuedRenderableVisitor->transparentShadowCastersMode = false;
2457        // Use visitor
2458        objs.acceptVisitor(mActiveQueuedRenderableVisitor, om);
2459}
2460//-----------------------------------------------------------------------
2461void SceneManager::_renderQueueGroupObjects(RenderQueueGroup* pGroup, 
2462                                                                                   QueuedRenderableCollection::OrganisationMode om)
2463{
2464        bool doShadows = 
2465                pGroup->getShadowsEnabled() && 
2466                mCurrentViewport->getShadowsEnabled() && 
2467                !mSuppressShadows && !mSuppressRenderStateChanges;
2468       
2469    if (doShadows && mShadowTechnique == SHADOWTYPE_STENCIL_ADDITIVE)
2470    {
2471        // Additive stencil shadows in use
2472        renderAdditiveStencilShadowedQueueGroupObjects(pGroup, om);
2473    }
2474    else if (doShadows && mShadowTechnique == SHADOWTYPE_STENCIL_MODULATIVE)
2475    {
2476        // Modulative stencil shadows in use
2477        renderModulativeStencilShadowedQueueGroupObjects(pGroup, om);
2478    }
2479    else if (isShadowTechniqueTextureBased())
2480    {
2481        // Modulative texture shadows in use
2482        if (mIlluminationStage == IRS_RENDER_TO_TEXTURE)
2483        {
2484            // Shadow caster pass
2485            if (mCurrentViewport->getShadowsEnabled() &&
2486                !mSuppressShadows && !mSuppressRenderStateChanges)
2487            {
2488                renderTextureShadowCasterQueueGroupObjects(pGroup, om);
2489            }
2490        }
2491        else
2492        {
2493            // Ordinary + receiver pass
2494            if (doShadows && !isShadowTechniqueIntegrated())
2495                        {
2496                                // Receiver pass(es)
2497                                if (isShadowTechniqueAdditive())
2498                                {
2499                                        // Auto-additive
2500                                        renderAdditiveTextureShadowedQueueGroupObjects(pGroup, om);
2501                                }
2502                                else
2503                                {
2504                                        // Modulative
2505                        renderModulativeTextureShadowedQueueGroupObjects(pGroup, om);
2506                                }
2507                        }
2508                        else
2509                                renderBasicQueueGroupObjects(pGroup, om);
2510        }
2511    }
2512    else
2513    {
2514        // No shadows, ordinary pass
2515        renderBasicQueueGroupObjects(pGroup, om);
2516    }
2517
2518
2519}
2520//-----------------------------------------------------------------------
2521void SceneManager::renderBasicQueueGroupObjects(RenderQueueGroup* pGroup, 
2522                                                                                                QueuedRenderableCollection::OrganisationMode om)
2523{
2524    // Basic render loop
2525    // Iterate through priorities
2526    RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator();
2527
2528    while (groupIt.hasMoreElements())
2529    {
2530        RenderPriorityGroup* pPriorityGrp = groupIt.getNext();
2531
2532        // Sort the queue first
2533        pPriorityGrp->sort(mCameraInProgress);
2534
2535        // Do solids
2536        renderObjects(pPriorityGrp->getSolidsBasic(), om, true);
2537        // Do transparents (always descending)
2538        renderObjects(pPriorityGrp->getTransparents(), 
2539                        QueuedRenderableCollection::OM_SORT_DESCENDING, true);
2540
2541
2542    }// for each priority
2543}
2544//-----------------------------------------------------------------------
2545void SceneManager::renderTransparentShadowCasterObjects(
2546        const QueuedRenderableCollection& objs, 
2547        QueuedRenderableCollection::OrganisationMode om, bool doLightIteration,
2548        const LightList* manualLightList)
2549{
2550        mActiveQueuedRenderableVisitor->transparentShadowCastersMode = true;
2551        mActiveQueuedRenderableVisitor->autoLights = doLightIteration;
2552        mActiveQueuedRenderableVisitor->manualLightList = manualLightList;
2553       
2554        // Sort descending (transparency)
2555        objs.acceptVisitor(mActiveQueuedRenderableVisitor, 
2556                QueuedRenderableCollection::OM_SORT_DESCENDING);
2557
2558        mActiveQueuedRenderableVisitor->transparentShadowCastersMode = false;
2559}
2560//-----------------------------------------------------------------------
2561void SceneManager::renderSingleObject(const Renderable* rend, const Pass* pass, 
2562                                      bool doLightIteration, const LightList* manualLightList)
2563{
2564    unsigned short numMatrices;
2565    static RenderOperation ro;
2566
2567    // Set up rendering operation
2568    // I know, I know, const_cast is nasty but otherwise it requires all internal
2569    // state of the Renderable assigned to the rop to be mutable
2570    const_cast<Renderable*>(rend)->getRenderOperation(ro);
2571    ro.srcRenderable = rend;
2572
2573    // Set world transformation
2574    rend->getWorldTransforms(mTempXform);
2575    numMatrices = rend->getNumWorldTransforms();
2576    if (numMatrices > 1)
2577    {
2578        mDestRenderSystem->_setWorldMatrices(mTempXform, numMatrices);
2579    }
2580    else
2581    {
2582        mDestRenderSystem->_setWorldMatrix(*mTempXform);
2583    }
2584
2585    // Issue view / projection changes if any
2586    useRenderableViewProjMode(rend);
2587
2588    if (!mSuppressRenderStateChanges)
2589    {
2590        bool passSurfaceAndLightParams = true;
2591
2592        if (pass->isProgrammable())
2593        {
2594            // Tell auto params object about the renderable change
2595            mAutoParamDataSource.setCurrentRenderable(rend);
2596            // Tell auto params object about the world matrices, eliminated query from renderable again
2597            mAutoParamDataSource.setWorldMatrices(mTempXform, numMatrices);
2598            pass->_updateAutoParamsNoLights(mAutoParamDataSource);
2599            if (pass->hasVertexProgram())
2600            {
2601                passSurfaceAndLightParams = pass->getVertexProgram()->getPassSurfaceAndLightStates();
2602            }
2603        }
2604
2605        // Reissue any texture gen settings which are dependent on view matrix
2606        Pass::ConstTextureUnitStateIterator texIter =  pass->getTextureUnitStateIterator();
2607        size_t unit = 0;
2608        while(texIter.hasMoreElements())
2609        {
2610            TextureUnitState* pTex = texIter.getNext();
2611            if (pTex->hasViewRelativeTextureCoordinateGeneration())
2612            {
2613                mDestRenderSystem->_setTextureUnitSettings(unit, *pTex);
2614            }
2615            ++unit;
2616        }
2617
2618        // Sort out normalisation
2619        mDestRenderSystem->setNormaliseNormals(rend->getNormaliseNormals());
2620
2621        // Set up the solid / wireframe override
2622                // Precedence is Camera, Object, Material
2623                // Camera might not override object if not overrideable
2624                PolygonMode reqMode = pass->getPolygonMode();
2625                if (rend->getPolygonModeOverrideable())
2626                {
2627            PolygonMode camPolyMode = mCameraInProgress->getPolygonMode();
2628                        // check camera detial only when render detail is overridable
2629                        if (reqMode > camPolyMode)
2630                        {
2631                                // only downgrade detail; if cam says wireframe we don't go up to solid
2632                                reqMode = camPolyMode;
2633                        }
2634                }
2635                mDestRenderSystem->_setPolygonMode(reqMode);
2636
2637                mDestRenderSystem->setClipPlanes(rend->getClipPlanes());
2638
2639                if (doLightIteration)
2640                {
2641            // Create local light list for faster light iteration setup
2642            static LightList localLightList;
2643
2644
2645                        // Here's where we issue the rendering operation to the render system
2646                        // Note that we may do this once per light, therefore it's in a loop
2647                        // and the light parameters are updated once per traversal through the
2648                        // loop
2649                        const LightList& rendLightList = rend->getLights();
2650
2651                        bool iteratePerLight = pass->getIteratePerLight();
2652
2653                        // deliberately unsigned in case start light exceeds number of lights
2654                        // in which case this pass would be skipped
2655                        int lightsLeft = 1;
2656                        if (iteratePerLight)
2657                        {
2658                                lightsLeft = static_cast<int>(rendLightList.size()) - pass->getStartLight();
2659                                // Don't allow total light count for all iterations to exceed max per pass
2660                                if (lightsLeft > static_cast<int>(pass->getMaxSimultaneousLights()))
2661                                {
2662                                        lightsLeft = static_cast<int>(pass->getMaxSimultaneousLights());
2663                                }
2664
2665                        }
2666
2667                        const LightList* pLightListToUse;
2668                        // Start counting from the start light
2669                        size_t lightIndex = pass->getStartLight();
2670
2671                        while (lightsLeft > 0)
2672                        {
2673                                // Determine light list to use
2674                                if (iteratePerLight)
2675                                {
2676                                        localLightList.resize(pass->getLightCountPerIteration());
2677
2678                                        LightList::iterator destit = localLightList.begin();
2679                                        unsigned short numShadowTextureLights = 0;
2680                                        for (; destit != localLightList.end() 
2681                                                        && lightIndex < rendLightList.size(); 
2682                                                ++lightIndex, --lightsLeft)
2683                                        {
2684                                                // Check whether we need to filter this one out
2685                                                if (pass->getRunOnlyForOneLightType() && 
2686                                                        pass->getOnlyLightType() != rendLightList[lightIndex]->getType())
2687                                                {
2688                                                        // Skip
2689                                                        continue;
2690                                                }
2691
2692                                                *destit++ = rendLightList[lightIndex];
2693                                                // potentially need to update content_type shadow texunit
2694                                                // corresponding to this light
2695                                                if (isShadowTechniqueTextureBased() && lightIndex < mShadowTextures.size())
2696                                                {
2697                                                        // link the numShadowTextureLights'th shadow texture unit
2698                                                        unsigned short tuindex = 
2699                                                                pass->_getTextureUnitWithContentTypeIndex(
2700                                                                TextureUnitState::CONTENT_SHADOW, numShadowTextureLights);
2701                                                        if (tuindex < pass->getNumTextureUnitStates())
2702                                                        {
2703                                                                // I know, nasty const_cast
2704                                                                TextureUnitState* tu = 
2705                                                                        const_cast<TextureUnitState*>(
2706                                                                                pass->getTextureUnitState(tuindex));
2707                                                                const TexturePtr& shadowTex = mShadowTextures[lightIndex];
2708                                                                tu->_setTexturePtr(shadowTex);
2709                                                                Camera *cam = shadowTex->getBuffer()->getRenderTarget()->getViewport(0)->getCamera();
2710                                                                tu->setProjectiveTexturing(!pass->hasVertexProgram(), cam);
2711                                                                mAutoParamDataSource.setTextureProjector(cam, numShadowTextureLights);
2712                                                                ++numShadowTextureLights;
2713                                                                // Have to set TU on rendersystem right now, although
2714                                                                // autoparams will be set later
2715                                                                mDestRenderSystem->_setTextureUnitSettings(tuindex, *tu);
2716                                                        }
2717
2718                                                }
2719
2720
2721
2722                                        }
2723                                        // Did we run out of lights before slots? e.g. 5 lights, 2 per iteration
2724                                        if (destit != localLightList.end())
2725                                        {
2726                                                localLightList.erase(destit, localLightList.end());
2727                                                lightsLeft = 0;
2728                                        }
2729                                        pLightListToUse = &localLightList;
2730                                }
2731                                else
2732                                {
2733                                        // Use complete light list potentially adjusted by start light
2734                                        if (pass->getStartLight() || pass->getMaxSimultaneousLights() != OGRE_MAX_SIMULTANEOUS_LIGHTS)
2735                                        {
2736                                                // out of lights?
2737                                                if (pass->getStartLight() >= rendLightList.size())
2738                                                {
2739                                                        lightsLeft = 0;
2740                                                        break;
2741                                                }
2742                                                else
2743                                                {
2744                                                        localLightList.clear();
2745                                                        LightList::const_iterator copyStart = rendLightList.begin();
2746                                                        std::advance(copyStart, pass->getStartLight());
2747                                                        LightList::const_iterator copyEnd = copyStart;
2748                                                        // Clamp lights to copy to avoid overrunning the end of the list
2749                                                        size_t lightsToCopy = std::min(
2750                                                                static_cast<size_t>(pass->getMaxSimultaneousLights()), 
2751                                                                rendLightList.size() - pass->getStartLight());
2752                                                        std::advance(copyEnd, lightsToCopy);
2753                                                        localLightList.insert(localLightList.begin(), 
2754                                                                copyStart, copyEnd);
2755                                                        pLightListToUse = &localLightList;
2756                                                }
2757                                        }
2758                                        else
2759                                        {
2760                                                pLightListToUse = &rendLightList;
2761                                        }
2762                                        lightsLeft = 0;
2763                                }
2764
2765
2766                                // Do we need to update GPU program parameters?
2767                                if (pass->isProgrammable())
2768                                {
2769                                        // Update any automatic gpu params for lights
2770                                        // Other bits of information will have to be looked up
2771                                        mAutoParamDataSource.setCurrentLightList(pLightListToUse);
2772                                        pass->_updateAutoParamsLightsOnly(mAutoParamDataSource);
2773                                        // NOTE: We MUST bind parameters AFTER updating the autos
2774
2775                                        if (pass->hasVertexProgram())
2776                                        {
2777                                                mDestRenderSystem->bindGpuProgramParameters(GPT_VERTEX_PROGRAM, 
2778                                                        pass->getVertexProgramParameters());
2779                                        }
2780                                        if (pass->hasFragmentProgram())
2781                                        {
2782                                                mDestRenderSystem->bindGpuProgramParameters(GPT_FRAGMENT_PROGRAM, 
2783                                                        pass->getFragmentProgramParameters());
2784                                        }
2785                                }
2786                                // Do we need to update light states?
2787                                // Only do this if fixed-function vertex lighting applies
2788                                if (pass->getLightingEnabled() && passSurfaceAndLightParams)
2789                                {
2790                                        mDestRenderSystem->_useLights(*pLightListToUse, pass->getMaxSimultaneousLights());
2791                                }
2792                                // issue the render op         
2793                                // nfz: check for gpu_multipass
2794                                mDestRenderSystem->setCurrentPassIterationCount(pass->getPassIterationCount());
2795                                mDestRenderSystem->_render(ro);
2796                        } // possibly iterate per light
2797                }
2798                else // no automatic light processing
2799                {
2800                        // Even if manually driving lights, check light type passes
2801                        bool skipBecauseOfLightType = false;
2802                        if (pass->getRunOnlyForOneLightType())
2803                        {
2804                                if (!manualLightList ||
2805                                        (manualLightList->size() == 1 && 
2806                                        manualLightList->at(0)->getType() != pass->getOnlyLightType())) 
2807                                {
2808                                        skipBecauseOfLightType = true;
2809                                }
2810                        }
2811
2812                        if (!skipBecauseOfLightType)
2813                        {
2814                                // Do we need to update GPU program parameters?
2815                                if (pass->isProgrammable())
2816                                {
2817                                        // Do we have a manual light list?
2818                                        if (manualLightList)
2819                                        {
2820                                                // Update any automatic gpu params for lights
2821                                                mAutoParamDataSource.setCurrentLightList(manualLightList);
2822                                                pass->_updateAutoParamsLightsOnly(mAutoParamDataSource);
2823                                        }
2824
2825                                        if (pass->hasVertexProgram())
2826                                        {
2827                                                mDestRenderSystem->bindGpuProgramParameters(GPT_VERTEX_PROGRAM, 
2828                                                        pass->getVertexProgramParameters());
2829                                        }
2830                                        if (pass->hasFragmentProgram())
2831                                        {
2832                                                mDestRenderSystem->bindGpuProgramParameters(GPT_FRAGMENT_PROGRAM, 
2833                                                        pass->getFragmentProgramParameters());
2834                                        }
2835                                }
2836
2837                                // Use manual lights if present, and not using vertex programs that don't use fixed pipeline
2838                                if (manualLightList && 
2839                                        pass->getLightingEnabled() && passSurfaceAndLightParams)
2840                                {
2841                                        mDestRenderSystem->_useLights(*manualLightList, pass->getMaxSimultaneousLights());
2842                                }
2843                                // issue the render op         
2844                                // nfz: set up multipass rendering
2845                                mDestRenderSystem->setCurrentPassIterationCount(pass->getPassIterationCount());
2846                                mDestRenderSystem->_render(ro);
2847                        } // !skipBecauseOfLightType
2848                }
2849
2850        }
2851        else // mSuppressRenderStateChanges
2852        {
2853                // Just render
2854                mDestRenderSystem->setCurrentPassIterationCount(1);
2855                mDestRenderSystem->_render(ro);
2856        }
2857       
2858    // Reset view / projection changes if any
2859    resetViewProjMode();
2860
2861}
2862//-----------------------------------------------------------------------
2863void SceneManager::setAmbientLight(const ColourValue& colour)
2864{
2865    mAmbientLight = colour;
2866}
2867//-----------------------------------------------------------------------
2868const ColourValue& SceneManager::getAmbientLight(void) const
2869{
2870    return mAmbientLight;
2871}
2872//-----------------------------------------------------------------------
2873ViewPoint SceneManager::getSuggestedViewpoint(bool random)
2874{
2875    // By default return the origin
2876    ViewPoint vp;
2877    vp.position = Vector3::ZERO;
2878    vp.orientation = Quaternion::IDENTITY;
2879    return vp;
2880}
2881//-----------------------------------------------------------------------
2882void SceneManager::setFog(FogMode mode, const ColourValue& colour, Real density, Real start, Real end)
2883{
2884    mFogMode = mode;
2885    mFogColour = colour;
2886    mFogStart = start;
2887    mFogEnd = end;
2888    mFogDensity = density;
2889}
2890//-----------------------------------------------------------------------
2891FogMode SceneManager::getFogMode(void) const
2892{
2893    return mFogMode;
2894}
2895//-----------------------------------------------------------------------
2896const ColourValue& SceneManager::getFogColour(void) const
2897{
2898    return mFogColour;
2899}
2900//-----------------------------------------------------------------------
2901Real SceneManager::getFogStart(void) const
2902{
2903    return mFogStart;
2904}
2905//-----------------------------------------------------------------------
2906Real SceneManager::getFogEnd(void) const
2907{
2908    return mFogEnd;
2909}
2910//-----------------------------------------------------------------------
2911Real SceneManager::getFogDensity(void) const
2912{
2913    return mFogDensity;
2914}
2915//-----------------------------------------------------------------------
2916BillboardSet* SceneManager::createBillboardSet(const String& name, unsigned int poolSize)
2917{
2918        NameValuePairList params;
2919        params["poolSize"] = StringConverter::toString(poolSize);
2920        return static_cast<BillboardSet*>(
2921                createMovableObject(name, BillboardSetFactory::FACTORY_TYPE_NAME, &params));
2922}
2923//-----------------------------------------------------------------------
2924BillboardSet* SceneManager::getBillboardSet(const String& name) const
2925{
2926        return static_cast<BillboardSet*>(
2927                getMovableObject(name, BillboardSetFactory::FACTORY_TYPE_NAME));
2928}
2929//-----------------------------------------------------------------------
2930bool SceneManager::hasBillboardSet(const String& name) const
2931{
2932        return hasMovableObject(name, BillboardSetFactory::FACTORY_TYPE_NAME);
2933}
2934
2935//-----------------------------------------------------------------------
2936void SceneManager::destroyBillboardSet(BillboardSet* set)
2937{
2938        destroyMovableObject(set);
2939}
2940//-----------------------------------------------------------------------
2941void SceneManager::destroyBillboardSet(const String& name)
2942{
2943        destroyMovableObject(name, BillboardSetFactory::FACTORY_TYPE_NAME);
2944}
2945//-----------------------------------------------------------------------
2946void SceneManager::setDisplaySceneNodes(bool display)
2947{
2948    mDisplayNodes = display;
2949}
2950//-----------------------------------------------------------------------
2951Animation* SceneManager::createAnimation(const String& name, Real length)
2952{
2953        OGRE_LOCK_MUTEX(mAnimationsListMutex)
2954
2955    // Check name not used
2956    if (mAnimationsList.find(name) != mAnimationsList.end())
2957    {
2958        OGRE_EXCEPT(
2959            Exception::ERR_DUPLICATE_ITEM,
2960            "An animation with the name " + name + " already exists",
2961            "SceneManager::createAnimation" );
2962    }
2963
2964    Animation* pAnim = new Animation(name, length);
2965    mAnimationsList[name] = pAnim;
2966    return pAnim;
2967}
2968//-----------------------------------------------------------------------
2969Animation* SceneManager::getAnimation(const String& name) const
2970{
2971        OGRE_LOCK_MUTEX(mAnimationsListMutex)
2972
2973        AnimationList::const_iterator i = mAnimationsList.find(name);
2974    if (i == mAnimationsList.end())
2975    {
2976        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 
2977            "Cannot find animation with name " + name, 
2978            "SceneManager::getAnimation");
2979    }
2980    return i->second;
2981}
2982//-----------------------------------------------------------------------
2983bool SceneManager::hasAnimation(const String& name) const
2984{
2985        OGRE_LOCK_MUTEX(mAnimationsListMutex)
2986        return (mAnimationsList.find(name) != mAnimationsList.end());
2987}
2988//-----------------------------------------------------------------------
2989void SceneManager::destroyAnimation(const String& name)
2990{
2991        OGRE_LOCK_MUTEX(mAnimationsListMutex)
2992
2993        // Also destroy any animation states referencing this animation
2994        mAnimationStates.removeAnimationState(name);
2995
2996        AnimationList::iterator i = mAnimationsList.find(name);
2997        if (i == mAnimationsList.end())
2998        {
2999                OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 
3000                        "Cannot find animation with name " + name, 
3001                        "SceneManager::getAnimation");
3002        }
3003
3004        // Free memory
3005        delete i->second;
3006
3007        mAnimationsList.erase(i);
3008
3009}
3010//-----------------------------------------------------------------------
3011void SceneManager::destroyAllAnimations(void)
3012{
3013        OGRE_LOCK_MUTEX(mAnimationsListMutex)
3014    // Destroy all states too, since they cannot reference destroyed animations
3015    destroyAllAnimationStates();
3016
3017        AnimationList::iterator i;
3018        for (i = mAnimationsList.begin(); i != mAnimationsList.end(); ++i)
3019        {
3020                // destroy
3021                delete i->second;
3022        }
3023        mAnimationsList.clear();
3024}
3025//-----------------------------------------------------------------------
3026AnimationState* SceneManager::createAnimationState(const String& animName)
3027{
3028    // Get animation, this will throw an exception if not found
3029    Animation* anim = getAnimation(animName);
3030
3031    // Create new state
3032        return mAnimationStates.createAnimationState(animName, 0, anim->getLength());
3033
3034}
3035//-----------------------------------------------------------------------
3036AnimationState* SceneManager::getAnimationState(const String& animName) const
3037{
3038        return mAnimationStates.getAnimationState(animName);
3039
3040}
3041//-----------------------------------------------------------------------
3042bool SceneManager::hasAnimationState(const String& name) const
3043{
3044        return mAnimationStates.hasAnimationState(name);
3045}
3046//-----------------------------------------------------------------------
3047void SceneManager::destroyAnimationState(const String& name)
3048{
3049        mAnimationStates.removeAnimationState(name);
3050}
3051//-----------------------------------------------------------------------
3052void SceneManager::destroyAllAnimationStates(void)
3053{
3054    mAnimationStates.removeAllAnimationStates();
3055}
3056//-----------------------------------------------------------------------
3057void SceneManager::_applySceneAnimations(void)
3058{
3059        // manual lock over states (extended duration required)
3060        OGRE_LOCK_MUTEX(mAnimationStates.OGRE_AUTO_MUTEX_NAME)
3061
3062    ConstEnabledAnimationStateIterator stateIt = mAnimationStates.getEnabledAnimationStateIterator();
3063
3064    while (stateIt.hasMoreElements())
3065    {
3066        const AnimationState* state = stateIt.getNext();
3067        Animation* anim = getAnimation(state->getAnimationName());
3068
3069        // Reset any nodes involved
3070        // NB this excludes blended animations
3071        Animation::NodeTrackIterator nodeTrackIt = anim->getNodeTrackIterator();
3072        while(nodeTrackIt.hasMoreElements())
3073        {
3074            Node* nd = nodeTrackIt.getNext()->getAssociatedNode();
3075                        if (nd)
3076                                nd->resetToInitialState();
3077        }
3078
3079        Animation::NumericTrackIterator numTrackIt = anim->getNumericTrackIterator();
3080        while(numTrackIt.hasMoreElements())
3081        {
3082            const AnimableValuePtr& anim = numTrackIt.getNext()->getAssociatedAnimable();
3083                        if (!anim.isNull())
3084                                anim->resetToBaseValue();
3085        }
3086
3087        // Apply the animation
3088        anim->apply(state->getTimePosition(), state->getWeight());
3089    }
3090
3091
3092}
3093//---------------------------------------------------------------------
3094void SceneManager::manualRender(RenderOperation* rend, 
3095                                Pass* pass, Viewport* vp, const Matrix4& worldMatrix, 
3096                                const Matrix4& viewMatrix, const Matrix4& projMatrix, 
3097                                bool doBeginEndFrame) 
3098{
3099    mDestRenderSystem->_setViewport(vp);
3100    mDestRenderSystem->_setWorldMatrix(worldMatrix);
3101    mDestRenderSystem->_setViewMatrix(viewMatrix);
3102    mDestRenderSystem->_setProjectionMatrix(projMatrix);
3103
3104    if (doBeginEndFrame)
3105        mDestRenderSystem->_beginFrame();
3106
3107    _setPass(pass);
3108        // Do we need to update GPU program parameters?
3109        if (pass->isProgrammable())
3110        {
3111                mAutoParamDataSource.setCurrentViewport(vp);
3112                mAutoParamDataSource.setCurrentRenderTarget(vp->getTarget());
3113                mAutoParamDataSource.setCurrentSceneManager(this);
3114                mAutoParamDataSource.setWorldMatrices(&worldMatrix, 1);
3115                Camera dummyCam(StringUtil::BLANK, 0);
3116                dummyCam.setCustomViewMatrix(true, viewMatrix);
3117                dummyCam.setCustomProjectionMatrix(true, projMatrix);
3118                pass->_updateAutoParamsNoLights(mAutoParamDataSource);
3119                // NOTE: We MUST bind parameters AFTER updating the autos
3120                if (pass->hasVertexProgram())
3121                {
3122                        mDestRenderSystem->bindGpuProgramParameters(GPT_VERTEX_PROGRAM, 
3123                                pass->getVertexProgramParameters());
3124                }
3125                if (pass->hasFragmentProgram())
3126                {
3127                        mDestRenderSystem->bindGpuProgramParameters(GPT_FRAGMENT_PROGRAM, 
3128                                pass->getFragmentProgramParameters());
3129                }
3130        }
3131    mDestRenderSystem->_render(*rend);
3132
3133    if (doBeginEndFrame)
3134        mDestRenderSystem->_endFrame();
3135
3136}
3137//---------------------------------------------------------------------
3138void SceneManager::useRenderableViewProjMode(const Renderable* pRend)
3139{
3140    // Check view matrix
3141    bool useIdentityView = pRend->getUseIdentityView();
3142    if (useIdentityView)
3143    {
3144        // Using identity view now, change it
3145        mDestRenderSystem->_setViewMatrix(Matrix4::IDENTITY);
3146        mResetIdentityView = true;
3147    }
3148
3149    bool useIdentityProj = pRend->getUseIdentityProjection();
3150    if (useIdentityProj)
3151    {
3152        // Use identity projection matrix, still need to take RS depth into account.
3153        Matrix4 mat;
3154        mDestRenderSystem->_convertProjectionMatrix(Matrix4::IDENTITY, mat);
3155        mDestRenderSystem->_setProjectionMatrix(mat);
3156
3157        mResetIdentityProj = true;
3158    }
3159
3160   
3161}
3162//---------------------------------------------------------------------
3163void SceneManager::resetViewProjMode(void)
3164{
3165    if (mResetIdentityView)
3166    {
3167        // Coming back to normal from identity view
3168        mDestRenderSystem->_setViewMatrix(mCameraInProgress->getViewMatrix(true));
3169        mResetIdentityView = false;
3170    }
3171   
3172    if (mResetIdentityProj)
3173    {
3174        // Coming back from flat projection
3175        mDestRenderSystem->_setProjectionMatrix(mCameraInProgress->getProjectionMatrixRS());
3176        mResetIdentityProj = false;
3177    }
3178   
3179
3180}
3181//---------------------------------------------------------------------
3182void SceneManager::_queueSkiesForRendering(Camera* cam)
3183{
3184    // Update nodes
3185    // Translate the box by the camera position (constant distance)
3186    if (mSkyPlaneNode)
3187    {
3188        // The plane position relative to the camera has already been set up
3189        mSkyPlaneNode->setPosition(cam->getDerivedPosition());
3190    }
3191
3192    if (mSkyBoxNode)
3193    {
3194        mSkyBoxNode->setPosition(cam->getDerivedPosition());
3195    }
3196
3197    if (mSkyDomeNode)
3198    {
3199        mSkyDomeNode->setPosition(cam->getDerivedPosition());
3200    }
3201
3202    uint8 qid;
3203    if (mSkyPlaneEnabled)
3204    {
3205        qid = mSkyPlaneDrawFirst? 
3206RENDER_QUEUE_SKIES_EARLY : RENDER_QUEUE_SKIES_LATE;
3207        getRenderQueue()->addRenderable(mSkyPlaneEntity->getSubEntity(0), qid, OGRE_RENDERABLE_DEFAULT_PRIORITY);
3208    }
3209
3210    uint plane;
3211    if (mSkyBoxEnabled)
3212    {
3213        qid = mSkyBoxDrawFirst? 
3214RENDER_QUEUE_SKIES_EARLY : RENDER_QUEUE_SKIES_LATE;
3215
3216        for (plane = 0; plane < 6; ++plane)
3217        {
3218            getRenderQueue()->addRenderable(
3219                mSkyBoxEntity[plane]->getSubEntity(0), qid, OGRE_RENDERABLE_DEFAULT_PRIORITY);
3220        }
3221    }
3222
3223    if (mSkyDomeEnabled)
3224    {
3225        qid = mSkyDomeDrawFirst? 
3226RENDER_QUEUE_SKIES_EARLY : RENDER_QUEUE_SKIES_LATE;
3227
3228        for (plane = 0; plane < 5; ++plane)
3229        {
3230            getRenderQueue()->addRenderable(
3231                mSkyDomeEntity[plane]->getSubEntity(0), qid, OGRE_RENDERABLE_DEFAULT_PRIORITY);
3232        }
3233    }
3234}
3235//---------------------------------------------------------------------
3236void SceneManager::addRenderQueueListener(RenderQueueListener* newListener)
3237{
3238    mRenderQueueListeners.push_back(newListener);
3239}
3240//---------------------------------------------------------------------
3241void SceneManager::removeRenderQueueListener(RenderQueueListener* delListener)
3242{
3243    RenderQueueListenerList::iterator i, iend;
3244    iend = mRenderQueueListeners.end();
3245    for (i = mRenderQueueListeners.begin(); i != iend; ++i)
3246    {
3247        if (*i == delListener)
3248        {
3249            mRenderQueueListeners.erase(i);
3250            break;
3251        }
3252    }
3253
3254}
3255//---------------------------------------------------------------------
3256void SceneManager::addShadowListener(ShadowListener* newListener)
3257{
3258    mShadowListeners.push_back(newListener);
3259}
3260//---------------------------------------------------------------------
3261void SceneManager::removeShadowListener(ShadowListener* delListener)
3262{
3263    ShadowListenerList::iterator i, iend;
3264    iend = mShadowListeners.end();
3265    for (i = mShadowListeners.begin(); i != iend; ++i)
3266    {
3267        if (*i == delListener)
3268        {
3269            mShadowListeners.erase(i);
3270            break;
3271        }
3272    }
3273
3274}
3275//---------------------------------------------------------------------
3276bool SceneManager::fireRenderQueueStarted(uint8 id, const String& invocation)
3277{
3278    RenderQueueListenerList::iterator i, iend;
3279    bool skip = false;
3280
3281    iend = mRenderQueueListeners.end();
3282    for (i = mRenderQueueListeners.begin(); i != iend; ++i)
3283    {
3284        (*i)->renderQueueStarted(id, invocation, skip);
3285    }
3286    return skip;
3287}
3288//---------------------------------------------------------------------
3289bool SceneManager::fireRenderQueueEnded(uint8 id, const String& invocation)
3290{
3291    RenderQueueListenerList::iterator i, iend;
3292    bool repeat = false;
3293
3294    iend = mRenderQueueListeners.end();
3295    for (i = mRenderQueueListeners.begin(); i != iend; ++i)
3296    {
3297        (*i)->renderQueueEnded(id, invocation, repeat);
3298    }
3299    return repeat;
3300}
3301//---------------------------------------------------------------------
3302void SceneManager::fireShadowTexturesUpdated(size_t numberOfShadowTextures)
3303{
3304    ShadowListenerList::iterator i, iend;
3305
3306    iend = mShadowListeners.end();
3307    for (i = mShadowListeners.begin(); i != iend; ++i)
3308    {
3309        (*i)->shadowTexturesUpdated(numberOfShadowTextures);
3310    }
3311}
3312//---------------------------------------------------------------------
3313void SceneManager::fireShadowTexturesPreCaster(Light* light, Camera* camera)
3314{
3315    ShadowListenerList::iterator i, iend;
3316
3317    iend = mShadowListeners.end();
3318    for (i = mShadowListeners.begin(); i != iend; ++i)
3319    {
3320        (*i)->shadowTextureCasterPreViewProj(light, camera);
3321    }
3322}
3323//---------------------------------------------------------------------
3324void SceneManager::fireShadowTexturesPreReceiver(Light* light, Frustum* f)
3325{
3326    ShadowListenerList::iterator i, iend;
3327
3328    iend = mShadowListeners.end();
3329    for (i = mShadowListeners.begin(); i != iend; ++i)
3330    {
3331        (*i)->shadowTextureReceiverPreViewProj(light, f);
3332    }
3333}
3334//---------------------------------------------------------------------
3335void SceneManager::setViewport(Viewport* vp)
3336{
3337    mCurrentViewport = vp;
3338    // Set viewport in render system
3339    mDestRenderSystem->_setViewport(vp);
3340        // Set the active material scheme for this viewport
3341        MaterialManager::getSingleton().setActiveScheme(vp->getMaterialScheme());
3342}
3343//---------------------------------------------------------------------
3344void SceneManager::showBoundingBoxes(bool bShow) 
3345{
3346    mShowBoundingBoxes = bShow;
3347}
3348//---------------------------------------------------------------------
3349bool SceneManager::getShowBoundingBoxes() const
3350{
3351    return mShowBoundingBoxes;
3352}
3353//---------------------------------------------------------------------
3354void SceneManager::_notifyAutotrackingSceneNode(SceneNode* node, bool autoTrack)
3355{
3356    if (autoTrack)
3357    {
3358        mAutoTrackingSceneNodes.insert(node);
3359    }
3360    else
3361    {
3362        mAutoTrackingSceneNodes.erase(node);
3363    }
3364}
3365//---------------------------------------------------------------------
3366void SceneManager::setShadowTechnique(ShadowTechnique technique)
3367{
3368    mShadowTechnique = technique;
3369    if (isShadowTechniqueStencilBased())
3370    {
3371        // Firstly check that we  have a stencil
3372        // Otherwise forget it
3373        if (!mDestRenderSystem->getCapabilities()->hasCapability(RSC_HWSTENCIL))
3374        {
3375            LogManager::getSingleton().logMessage(
3376                "WARNING: Stencil shadows were requested, but this device does not "
3377                "have a hardware stencil. Shadows disabled.");
3378            mShadowTechnique = SHADOWTYPE_NONE;
3379        }
3380        else if (mShadowIndexBuffer.isNull())
3381        {
3382            // Create an estimated sized shadow index buffer
3383            mShadowIndexBuffer = HardwareBufferManager::getSingleton().
3384                createIndexBuffer(HardwareIndexBuffer::IT_16BIT, 
3385                mShadowIndexBufferSize, 
3386                HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE, 
3387                false);
3388            // tell all meshes to prepare shadow volumes
3389            MeshManager::getSingleton().setPrepareAllMeshesForShadowVolumes(true);
3390        }
3391        }
3392
3393    if (!isShadowTechniqueTextureBased())
3394    {
3395        // Destroy shadow textures to optimise resource usage
3396        destroyShadowTextures();
3397    }
3398        else
3399        {
3400                // assure no custom shadow matrix is used accidentally in case we switch
3401                // from a custom shadow mapping type to a non-custom (uniform shadow mapping)
3402                for ( size_t i = 0; i < mShadowTextureCameras.size(); ++i )
3403                {
3404                        Camera* texCam = mShadowTextureCameras[i];
3405
3406                        texCam->setCustomViewMatrix(false);
3407                        texCam->setCustomProjectionMatrix(false);
3408                }
3409        }
3410
3411}
3412//---------------------------------------------------------------------
3413void SceneManager::_suppressShadows(bool suppress)
3414{
3415        mSuppressShadows = suppress;
3416}
3417//---------------------------------------------------------------------
3418void SceneManager::_suppressRenderStateChanges(bool suppress)
3419{
3420        mSuppressRenderStateChanges = suppress;
3421}
3422//---------------------------------------------------------------------
3423void SceneManager::updateRenderQueueSplitOptions(void)
3424{
3425        if (isShadowTechniqueStencilBased())
3426        {
3427                // Casters can always be receivers
3428                getRenderQueue()->setShadowCastersCannotBeReceivers(false);
3429        }
3430        else // texture based
3431        {
3432                getRenderQueue()->setShadowCastersCannotBeReceivers(!mShadowTextureSelfShadow);
3433        }
3434
3435        if (isShadowTechniqueAdditive() && !isShadowTechniqueIntegrated()
3436                && mCurrentViewport->getShadowsEnabled())
3437        {
3438                // Additive lighting, we need to split everything by illumination stage
3439                getRenderQueue()->setSplitPassesByLightingType(true);
3440        }
3441        else
3442        {
3443                getRenderQueue()->setSplitPassesByLightingType(false);
3444        }
3445
3446        if (isShadowTechniqueInUse() && mCurrentViewport->getShadowsEnabled()
3447                && !isShadowTechniqueIntegrated())
3448        {
3449                // Tell render queue to split off non-shadowable materials
3450                getRenderQueue()->setSplitNoShadowPasses(true);
3451        }
3452        else
3453        {
3454                getRenderQueue()->setSplitNoShadowPasses(false);
3455        }
3456
3457
3458}
3459//---------------------------------------------------------------------
3460void SceneManager::updateRenderQueueGroupSplitOptions(RenderQueueGroup* group, 
3461        bool suppressShadows, bool suppressRenderState)
3462{
3463        if (isShadowTechniqueStencilBased())
3464        {
3465                // Casters can always be receivers
3466                group->setShadowCastersCannotBeReceivers(false);
3467        }
3468        else if (isShadowTechniqueTextureBased()) 
3469        {
3470                group->setShadowCastersCannotBeReceivers(!mShadowTextureSelfShadow);
3471        }
3472
3473        if (!suppressShadows && mCurrentViewport->getShadowsEnabled() &&
3474                isShadowTechniqueAdditive() && !isShadowTechniqueIntegrated())
3475        {
3476                // Additive lighting, we need to split everything by illumination stage
3477                group->setSplitPassesByLightingType(true);
3478        }
3479        else
3480        {
3481                group->setSplitPassesByLightingType(false);
3482        }
3483
3484        if (!suppressShadows && mCurrentViewport->getShadowsEnabled() 
3485                && isShadowTechniqueInUse())
3486        {
3487                // Tell render queue to split off non-shadowable materials
3488                group->setSplitNoShadowPasses(true);
3489        }
3490        else
3491        {
3492                group->setSplitNoShadowPasses(false);
3493        }
3494
3495
3496}
3497//-----------------------------------------------------------------------
3498void SceneManager::_notifyLightsDirty(void)
3499{
3500    ++mLightsDirtyCounter;
3501}
3502//---------------------------------------------------------------------
3503bool SceneManager::lightsForShadowTextureLess::operator ()(
3504        const Ogre::Light *l1, const Ogre::Light *l2) const
3505{
3506        if (l1 == l2)
3507                return false;
3508
3509        // sort shadow casting lights ahead of non-shadow casting
3510        if (l1->getCastShadows() != l2->getCastShadows())
3511        {
3512                return l1->getCastShadows();
3513        }
3514
3515        // otherwise sort by distance (directional lights will have 0 here)
3516        return l1->tempSquareDist < l2->tempSquareDist;
3517
3518}
3519//---------------------------------------------------------------------
3520void SceneManager::findLightsAffectingFrustum(const Camera* camera)
3521{
3522    // Basic iteration for this SM
3523
3524    MovableObjectCollection* lights =
3525        getMovableObjectCollection(LightFactory::FACTORY_TYPE_NAME);
3526
3527
3528        {
3529                OGRE_LOCK_MUTEX(lights->mutex)
3530
3531                // Pre-allocate memory
3532                mTestLightInfos.clear();
3533                mTestLightInfos.reserve(lights->map.size());
3534
3535                MovableObjectIterator it(lights->map.begin(), lights->map.end());
3536
3537                while(it.hasMoreElements())
3538                {
3539                        Light* l = static_cast<Light*>(it.getNext());
3540                        if (l->isVisible())
3541                        {
3542                                LightInfo lightInfo;
3543                                lightInfo.light = l;
3544                                lightInfo.type = l->getType();
3545                                if (lightInfo.type == Light::LT_DIRECTIONAL)
3546                                {
3547                                        // Always visible
3548                                        lightInfo.position = Vector3::ZERO;
3549                                        lightInfo.range = 0;
3550                                        mTestLightInfos.push_back(lightInfo);
3551                                }
3552                                else
3553                                {
3554                                        // NB treating spotlight as point for simplicity
3555                                        // Just see if the lights attenuation range is within the frustum
3556                                        lightInfo.range = l->getAttenuationRange();
3557                                        lightInfo.position = l->getDerivedPosition();
3558                                        Sphere sphere(lightInfo.position, lightInfo.range);
3559                                        if (camera->isVisible(sphere))
3560                                        {
3561                                                mTestLightInfos.push_back(lightInfo);
3562                                        }
3563                                }
3564                        }
3565                }
3566        } // release lock on lights collection
3567
3568    // Update lights affecting frustum if changed
3569    if (mCachedLightInfos != mTestLightInfos)
3570    {
3571        mLightsAffectingFrustum.resize(mTestLightInfos.size());
3572        LightInfoList::const_iterator i;
3573        LightList::iterator j = mLightsAffectingFrustum.begin();
3574        for (i = mTestLightInfos.begin(); i != mTestLightInfos.end(); ++i, ++j)
3575        {
3576            *j = i->light;
3577                        // add cam distance for sorting if texture shadows
3578                        if (isShadowTechniqueTextureBased())
3579                        {
3580                                (*j)->tempSquareDist = 
3581                                        (camera->getDerivedPosition() - (*j)->getDerivedPosition()).squaredLength();
3582                        }
3583        }
3584
3585                // Sort the lights if using texture shadows, since the first 'n' will be
3586                // used to generate shadow textures and we should pick the most appropriate
3587                if (isShadowTechniqueTextureBased())
3588                {
3589                        // Allow a ShadowListener to override light sorting
3590                        // Reverse iterate so last takes precedence
3591                        bool overridden = false;
3592                        for (ShadowListenerList::reverse_iterator ri = mShadowListeners.rbegin();
3593                                ri != mShadowListeners.rend(); ++ri)
3594                        {
3595                                overridden = (*ri)->sortLightsAffectingFrustum(mLightsAffectingFrustum);
3596                                if (overridden)
3597                                        break;
3598                        }
3599                        if (!overridden)
3600                        {
3601                                // default sort (stable to preserve directional light ordering
3602                                std::stable_sort(
3603                                        mLightsAffectingFrustum.begin(), mLightsAffectingFrustum.end(), 
3604                                        lightsForShadowTextureLess());
3605                        }
3606                       
3607                }
3608
3609        // Use swap instead of copy operator for efficiently
3610        mCachedLightInfos.swap(mTestLightInfos);
3611
3612        // notify light dirty, so all movable objects will re-populate
3613        // their light list next time
3614        _notifyLightsDirty();
3615    }
3616
3617}
3618//---------------------------------------------------------------------
3619bool SceneManager::ShadowCasterSceneQueryListener::queryResult(
3620    MovableObject* object)
3621{
3622    if (object->getCastShadows() && object->isVisible() && 
3623                mSceneMgr->isRenderQueueToBeProcessed(object->getRenderQueueGroup()) &&
3624                // objects need an edge list to cast shadows (shadow volumes only)
3625                ((mSceneMgr->getShadowTechnique() & SHADOWDETAILTYPE_TEXTURE) ||
3626                 (mSceneMgr->getShadowTechnique() & SHADOWDETAILTYPE_STENCIL) && object->hasEdgeList()
3627                )
3628           )
3629    {
3630        if (mFarDistSquared)
3631        {
3632            // Check object is within the shadow far distance
3633            Vector3 toObj = object->getParentNode()->_getDerivedPosition() 
3634                - mCamera->getDerivedPosition();
3635            Real radius = object->getWorldBoundingSphere().getRadius();
3636            Real dist =  toObj.squaredLength();               
3637            if (dist - (radius * radius) > mFarDistSquared)
3638            {
3639                // skip, beyond max range
3640                return true;
3641            }
3642        }
3643
3644        // If the object is in the frustum, we can always see the shadow
3645        if (mCamera->isVisible(object->getWorldBoundingBox()))
3646        {
3647            mCasterList->push_back(object);
3648            return true;
3649        }
3650
3651        // Otherwise, object can only be casting a shadow into our view if
3652        // the light is outside the frustum (or it's a directional light,
3653        // which are always outside), and the object is intersecting
3654        // on of the volumes formed between the edges of the frustum and the
3655        // light
3656        if (!mIsLightInFrustum || mLight->getType() == Light::LT_DIRECTIONAL)
3657        {
3658            // Iterate over volumes
3659            PlaneBoundedVolumeList::const_iterator i, iend;
3660            iend = mLightClipVolumeList->end();
3661            for (i = mLightClipVolumeList->begin(); i != iend; ++i)
3662            {
3663                if (i->intersects(object->getWorldBoundingBox()))
3664                {
3665                    mCasterList->push_back(object);
3666                    return true;
3667                }
3668
3669            }
3670
3671        }
3672    }
3673    return true;
3674}
3675//---------------------------------------------------------------------
3676bool SceneManager::ShadowCasterSceneQueryListener::queryResult(
3677    SceneQuery::WorldFragment* fragment)
3678{
3679    // don't deal with world geometry
3680    return true;
3681}
3682//---------------------------------------------------------------------
3683const SceneManager::ShadowCasterList& SceneManager::findShadowCastersForLight(
3684    const Light* light, const Camera* camera)
3685{
3686    mShadowCasterList.clear();
3687
3688    if (light->getType() == Light::LT_DIRECTIONAL)
3689    {
3690        // Basic AABB query encompassing the frustum and the extrusion of it
3691        AxisAlignedBox aabb;
3692        const Vector3* corners = camera->getWorldSpaceCorners();
3693        Vector3 min, max;
3694        Vector3 extrude = light->getDerivedDirection() * -mShadowDirLightExtrudeDist;
3695        // do first corner
3696        min = max = corners[0];
3697        min.makeFloor(corners[0] + extrude);
3698        max.makeCeil(corners[0] + extrude);
3699        for (size_t c = 1; c < 8; ++c)
3700        {
3701            min.makeFloor(corners[c]);
3702            max.makeCeil(corners[c]);
3703            min.makeFloor(corners[c] + extrude);
3704            max.makeCeil(corners[c] + extrude);
3705        }
3706        aabb.setExtents(min, max);
3707
3708        if (!mShadowCasterAABBQuery)
3709            mShadowCasterAABBQuery = createAABBQuery(aabb);
3710        else
3711            mShadowCasterAABBQuery->setBox(aabb);
3712        // Execute, use callback
3713        mShadowCasterQueryListener->prepare(false, 
3714            &(light->_getFrustumClipVolumes(camera)), 
3715            light, camera, &mShadowCasterList, mShadowFarDistSquared);
3716        mShadowCasterAABBQuery->execute(mShadowCasterQueryListener);
3717
3718
3719    }
3720    else
3721    {
3722        Sphere s(light->getDerivedPosition(), light->getAttenuationRange());
3723        // eliminate early if camera cannot see light sphere
3724        if (camera->isVisible(s))
3725        {
3726            if (!mShadowCasterSphereQuery)
3727                mShadowCasterSphereQuery = createSphereQuery(s);
3728            else
3729                mShadowCasterSphereQuery->setSphere(s);
3730
3731            // Determine if light is inside or outside the frustum
3732            bool lightInFrustum = camera->isVisible(light->getDerivedPosition());
3733            const PlaneBoundedVolumeList* volList = 0;
3734            if (!lightInFrustum)
3735            {
3736                // Only worth building an external volume list if
3737                // light is outside the frustum
3738                volList = &(light->_getFrustumClipVolumes(camera));
3739            }
3740
3741            // Execute, use callback
3742            mShadowCasterQueryListener->prepare(lightInFrustum, 
3743                volList, light, camera, &mShadowCasterList, mShadowFarDistSquared);
3744            mShadowCasterSphereQuery->execute(mShadowCasterQueryListener);
3745
3746        }
3747
3748    }
3749
3750
3751    return mShadowCasterList;
3752}
3753//---------------------------------------------------------------------
3754void SceneManager::initShadowVolumeMaterials(void)
3755{
3756    /* This should have been set in the SceneManager constructor, but if you
3757       created the SceneManager BEFORE the Root object, you will need to call
3758       SceneManager::_setDestinationRenderSystem manually.
3759     */
3760    assert( mDestRenderSystem );
3761
3762    if (mShadowMaterialInitDone)
3763        return;
3764
3765    if (!mShadowDebugPass)
3766    {
3767        MaterialPtr matDebug = 
3768            MaterialManager::getSingleton().getByName("Ogre/Debug/ShadowVolumes");
3769        if (matDebug.isNull())
3770        {
3771            // Create
3772            matDebug = MaterialManager::getSingleton().create(
3773                "Ogre/Debug/ShadowVolumes", 
3774                ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME);
3775            mShadowDebugPass = matDebug->getTechnique(0)->getPass(0);
3776            mShadowDebugPass->setSceneBlending(SBT_ADD); 
3777            mShadowDebugPass->setLightingEnabled(false);
3778            mShadowDebugPass->setDepthWriteEnabled(false);
3779            TextureUnitState* t = mShadowDebugPass->createTextureUnitState();
3780            t->setColourOperationEx(LBX_MODULATE, LBS_MANUAL, LBS_CURRENT, 
3781                ColourValue(0.7, 0.0, 0.2));
3782            mShadowDebugPass->setCullingMode(CULL_NONE);
3783
3784            if (mDestRenderSystem->getCapabilities()->hasCapability(
3785                RSC_VERTEX_PROGRAM))
3786            {
3787                ShadowVolumeExtrudeProgram::initialise();
3788
3789                // Enable the (infinite) point light extruder for now, just to get some params
3790                mShadowDebugPass->setVertexProgram(
3791                    ShadowVolumeExtrudeProgram::programNames[ShadowVolumeExtrudeProgram::POINT_LIGHT]);
3792                mInfiniteExtrusionParams = 
3793                    mShadowDebugPass->getVertexProgramParameters();
3794                mInfiniteExtrusionParams->setAutoConstant(0, 
3795                    GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
3796                mInfiniteExtrusionParams->setAutoConstant(4, 
3797                    GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE);
3798            }   
3799            matDebug->compile();
3800
3801        }
3802        else
3803        {
3804            mShadowDebugPass = matDebug->getTechnique(0)->getPass(0);
3805
3806            if (mDestRenderSystem->getCapabilities()->hasCapability(RSC_VERTEX_PROGRAM))
3807            {
3808                mInfiniteExtrusionParams = mShadowDebugPass->getVertexProgramParameters();
3809            }
3810        }
3811    }
3812
3813    if (!mShadowStencilPass)
3814    {
3815
3816        MaterialPtr matStencil = MaterialManager::getSingleton().getByName(
3817            "Ogre/StencilShadowVolumes");
3818        if (matStencil.isNull())
3819        {
3820            // Init
3821            matStencil = MaterialManager::getSingleton().create(
3822                "Ogre/StencilShadowVolumes",
3823                ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME);
3824            mShadowStencilPass = matStencil->getTechnique(0)->getPass(0);
3825
3826            if (mDestRenderSystem->getCapabilities()->hasCapability(
3827                RSC_VERTEX_PROGRAM))
3828            {
3829
3830                // Enable the finite point light extruder for now, just to get some params
3831                mShadowStencilPass->setVertexProgram(
3832                    ShadowVolumeExtrudeProgram::programNames[ShadowVolumeExtrudeProgram::POINT_LIGHT_FINITE]);
3833                mFiniteExtrusionParams = 
3834                    mShadowStencilPass->getVertexProgramParameters();
3835                mFiniteExtrusionParams->setAutoConstant(0, 
3836                    GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
3837                mFiniteExtrusionParams->setAutoConstant(4, 
3838                    GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE);
3839                // Note extra parameter
3840                mFiniteExtrusionParams->setAutoConstant(5, 
3841                    GpuProgramParameters::ACT_SHADOW_EXTRUSION_DISTANCE);
3842            }
3843            matStencil->compile();
3844            // Nothing else, we don't use this like a 'real' pass anyway,
3845            // it's more of a placeholder
3846        }
3847        else
3848        {
3849            mShadowStencilPass = matStencil->getTechnique(0)->getPass(0);
3850
3851            if (mDestRenderSystem->getCapabilities()->hasCapability(RSC_VERTEX_PROGRAM))
3852            {
3853                mFiniteExtrusionParams = mShadowStencilPass->getVertexProgramParameters();
3854            }
3855        }
3856    }
3857
3858
3859
3860
3861    if (!mShadowModulativePass)
3862    {
3863
3864        MaterialPtr matModStencil = MaterialManager::getSingleton().getByName(
3865            "Ogre/StencilShadowModulationPass");
3866        if (matModStencil.isNull())
3867        {
3868            // Init
3869            matModStencil = MaterialManager::getSingleton().create(
3870                "Ogre/StencilShadowModulationPass",
3871                ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME);
3872            mShadowModulativePass = matModStencil->getTechnique(0)->getPass(0);
3873            mShadowModulativePass->setSceneBlending(SBF_DEST_COLOUR, SBF_ZERO); 
3874            mShadowModulativePass->setLightingEnabled(false);
3875            mShadowModulativePass->setDepthWriteEnabled(false);
3876            mShadowModulativePass->setDepthCheckEnabled(false);
3877            TextureUnitState* t = mShadowModulativePass->createTextureUnitState();
3878            t->setColourOperationEx(LBX_MODULATE, LBS_MANUAL, LBS_CURRENT, 
3879                mShadowColour);
3880            mShadowModulativePass->setCullingMode(CULL_NONE);
3881        }
3882        else
3883        {
3884            mShadowModulativePass = matModStencil->getTechnique(0)->getPass(0);
3885        }
3886    }
3887
3888    // Also init full screen quad while we're at it
3889    if (!mFullScreenQuad)
3890    {
3891        mFullScreenQuad = new Rectangle2D();
3892        mFullScreenQuad->setCorners(-1,1,1,-1);
3893    }
3894
3895    // Also init shadow caster material for texture shadows
3896    if (!mShadowCasterPlainBlackPass)
3897    {
3898        MaterialPtr matPlainBlack = MaterialManager::getSingleton().getByName(
3899            "Ogre/TextureShadowCaster");
3900        if (matPlainBlack.isNull())
3901        {
3902            matPlainBlack = MaterialManager::getSingleton().create(
3903                "Ogre/TextureShadowCaster",
3904                ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME);
3905            mShadowCasterPlainBlackPass = matPlainBlack->getTechnique(0)->getPass(0);
3906            // Lighting has to be on, because we need shadow coloured objects
3907            // Note that because we can't predict vertex programs, we'll have to
3908            // bind light values to those, and so we bind White to ambient
3909            // reflectance, and we'll set the ambient colour to the shadow colour
3910            mShadowCasterPlainBlackPass->setAmbient(ColourValue::White);
3911            mShadowCasterPlainBlackPass->setDiffuse(ColourValue::Black);
3912            mShadowCasterPlainBlackPass->setSelfIllumination(ColourValue::Black);
3913            mShadowCasterPlainBlackPass->setSpecular(ColourValue::Black);
3914                        // Override fog
3915                        mShadowCasterPlainBlackPass->setFog(true, FOG_NONE);
3916            // no textures or anything else, we will bind vertex programs
3917            // every so often though
3918        }
3919        else
3920        {
3921            mShadowCasterPlainBlackPass = matPlainBlack->getTechnique(0)->getPass(0);
3922        }
3923    }
3924
3925    if (!mShadowReceiverPass)
3926    {
3927        MaterialPtr matShadRec = MaterialManager::getSingleton().getByName(
3928            "Ogre/TextureShadowReceiver");
3929        if (matShadRec.isNull())                       
3930        {
3931            matShadRec = MaterialManager::getSingleton().create(
3932                "Ogre/TextureShadowReceiver",
3933                ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME);
3934            mShadowReceiverPass = matShadRec->getTechnique(0)->getPass(0);
3935                        // Don't set lighting and blending modes here, depends on additive / modulative
3936            TextureUnitState* t = mShadowReceiverPass->createTextureUnitState();
3937            t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
3938        }
3939        else
3940        {
3941            mShadowReceiverPass = matShadRec->getTechnique(0)->getPass(0);
3942        }
3943    }
3944
3945    // Set up spot shadow fade texture (loaded from code data block)
3946    TexturePtr spotShadowFadeTex = 
3947        TextureManager::getSingleton().getByName("spot_shadow_fade.png");
3948    if (spotShadowFadeTex.isNull())
3949    {
3950        // Load the manual buffer into an image (don't destroy memory!
3951        DataStreamPtr stream(
3952                        new MemoryDataStream(SPOT_SHADOW_FADE_PNG, SPOT_SHADOW_FADE_PNG_SIZE, false));
3953        Image img;
3954        img.load(stream, "png");
3955        spotShadowFadeTex = 
3956            TextureManager::getSingleton().loadImage(
3957                        "spot_shadow_fade.png", ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME, 
3958                        img, TEX_TYPE_2D);
3959    }
3960
3961    mShadowMaterialInitDone = true;
3962}
3963//---------------------------------------------------------------------
3964const Pass* SceneManager::deriveShadowCasterPass(const Pass* pass)
3965{
3966        if (isShadowTechniqueTextureBased())
3967    {
3968                Pass* retPass = mShadowTextureCustomCasterPass ? 
3969                        mShadowTextureCustomCasterPass : mShadowCasterPlainBlackPass;
3970
3971               
3972                // Special case alpha-blended passes
3973                if ((pass->getSourceBlendFactor() == SBF_SOURCE_ALPHA && 
3974                        pass->getDestBlendFactor() == SBF_ONE_MINUS_SOURCE_ALPHA) 
3975                        || pass->getAlphaRejectFunction() != CMPF_ALWAYS_PASS)
3976                {
3977                        // Alpha blended passes must retain their transparency
3978                        retPass->setAlphaRejectSettings(pass->getAlphaRejectFunction(), 
3979                                pass->getAlphaRejectValue());
3980                        retPass->setSceneBlending(pass->getSourceBlendFactor(), pass->getDestBlendFactor());
3981                        retPass->getParent()->getParent()->setTransparencyCastsShadows(true);
3982
3983                        // So we allow the texture units, but override the colour functions
3984                        // Copy texture state, shift up one since 0 is shadow texture
3985                        unsigned short origPassTUCount = pass->getNumTextureUnitStates();
3986                        for (unsigned short t = 0; t < origPassTUCount; ++t)
3987                        {
3988                                TextureUnitState* tex;
3989                                if (retPass->getNumTextureUnitStates() <= t)
3990                                {
3991                                        tex = retPass->createTextureUnitState();
3992                                }
3993                                else
3994                                {
3995                                        tex = retPass->getTextureUnitState(t);
3996                                }
3997                                // copy base state
3998                                (*tex) = *(pass->getTextureUnitState(t));
3999                                // override colour function
4000                                tex->setColourOperationEx(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT,
4001                                        isShadowTechniqueAdditive()? ColourValue::Black : mShadowColour);
4002
4003                        }
4004                        // Remove any extras
4005                        while (retPass->getNumTextureUnitStates() > origPassTUCount)
4006                        {
4007                                retPass->removeTextureUnitState(origPassTUCount);
4008                        }
4009
4010                }
4011                else
4012                {
4013                        // reset
4014                        retPass->setSceneBlending(SBT_REPLACE);
4015                        retPass->setAlphaRejectFunction(CMPF_ALWAYS_PASS);
4016                        while (retPass->getNumTextureUnitStates() > 0)
4017                        {
4018                                retPass->removeTextureUnitState(0);
4019                        }
4020                }
4021
4022                // Propagate culling modes
4023                retPass->setCullingMode(pass->getCullingMode());
4024                retPass->setManualCullingMode(pass->getManualCullingMode());
4025               
4026
4027                // Does incoming pass have a custom shadow caster program?
4028                if (!pass->getShadowCasterVertexProgramName().empty())
4029                {
4030                        // Have to merge the shadow caster vertex program in
4031                        retPass->setVertexProgram(
4032                                pass->getShadowCasterVertexProgramName(), false);
4033                        const GpuProgramPtr& prg = retPass->getVertexProgram();
4034                        // Load this program if not done already
4035                        if (!prg->isLoaded())
4036                                prg->load();
4037                        // Copy params
4038                        retPass->setVertexProgramParameters(
4039                                pass->getShadowCasterVertexProgramParameters());
4040                        // Also have to hack the light autoparams, that is done later
4041                }
4042                else 
4043                {
4044                        if (retPass == mShadowTextureCustomCasterPass)
4045                        {
4046                                // reset vp?
4047                                if (mShadowTextureCustomCasterPass->getVertexProgramName() !=
4048                                        mShadowTextureCustomCasterVertexProgram)
4049                                {
4050                                        mShadowTextureCustomCasterPass->setVertexProgram(
4051                                                mShadowTextureCustomCasterVertexProgram, false);
4052                                        if(mShadowTextureCustomCasterPass->hasVertexProgram())
4053                                        {
4054                                                mShadowTextureCustomCasterPass->setVertexProgramParameters(
4055                                                        mShadowTextureCustomCasterVPParams);
4056
4057                                        }
4058
4059                                }
4060
4061                        }
4062                        else
4063                        {
4064                                // Standard shadow caster pass, reset to no vp
4065                                retPass->setVertexProgram(StringUtil::BLANK);
4066                        }
4067                }
4068                return retPass;
4069        }
4070        else
4071        {
4072        return pass;
4073    }
4074
4075}
4076//---------------------------------------------------------------------
4077const Pass* SceneManager::deriveShadowReceiverPass(const Pass* pass)
4078{
4079
4080    if (isShadowTechniqueTextureBased())
4081    {
4082                Pass* retPass = mShadowTextureCustomReceiverPass ? 
4083                        mShadowTextureCustomReceiverPass : mShadowReceiverPass;
4084
4085                // Does incoming pass have a custom shadow receiver program?
4086                if (!pass->getShadowReceiverVertexProgramName().empty())
4087                {
4088                        // Have to merge the shadow receiver vertex program in
4089                        retPass->setVertexProgram(
4090                                pass->getShadowReceiverVertexProgramName(), false);
4091                        const GpuProgramPtr& prg = retPass->getVertexProgram();
4092                        // Load this program if not done already
4093                        if (!prg->isLoaded())
4094                                prg->load();
4095                        // Copy params
4096                        retPass->setVertexProgramParameters(
4097                                pass->getShadowReceiverVertexProgramParameters());
4098                        // Also have to hack the light autoparams, that is done later
4099                }
4100                else 
4101                {
4102                        if (retPass == mShadowTextureCustomReceiverPass)
4103                        {
4104                                // reset vp?
4105                                if (mShadowTextureCustomReceiverPass->getVertexProgramName() !=
4106                                        mShadowTextureCustomReceiverVertexProgram)
4107                                {
4108                                        mShadowTextureCustomReceiverPass->setVertexProgram(
4109                                                mShadowTextureCustomReceiverVertexProgram, false);
4110                                        if(mShadowTextureCustomReceiverPass->hasVertexProgram())
4111                                        {
4112                                                mShadowTextureCustomReceiverPass->setVertexProgramParameters(
4113                                                        mShadowTextureCustomReceiverVPParams);
4114
4115                                        }
4116
4117                                }
4118
4119                        }
4120                        else
4121                        {
4122                                // Standard shadow receiver pass, reset to no vp
4123                                retPass->setVertexProgram(StringUtil::BLANK);
4124                        }
4125                }
4126
4127        unsigned short keepTUCount;
4128                // If additive, need lighting parameters & standard programs
4129                if (isShadowTechniqueAdditive())
4130                {
4131                        retPass->setLightingEnabled(true);
4132                        retPass->setAmbient(pass->getAmbient());
4133                        retPass->setSelfIllumination(pass->getSelfIllumination());
4134                        retPass->setDiffuse(pass->getDiffuse());
4135                        retPass->setSpecular(pass->getSpecular());
4136                        retPass->setShininess(pass->getShininess());
4137                        retPass->setIteratePerLight(pass->getIteratePerLight(), 
4138                                pass->getRunOnlyForOneLightType(), pass->getOnlyLightType());
4139
4140            // We need to keep alpha rejection settings
4141            retPass->setAlphaRejectSettings(pass->getAlphaRejectFunction(),
4142                pass->getAlphaRejectValue());
4143            // Copy texture state, shift up one since 0 is shadow texture
4144            unsigned short origPassTUCount = pass->getNumTextureUnitStates();
4145            for (unsigned short t = 0; t < origPassTUCount; ++t)
4146            {
4147                unsigned short targetIndex = t+1;
4148                TextureUnitState* tex;
4149                if (retPass->getNumTextureUnitStates() <= targetIndex)
4150                {
4151                    tex = retPass->createTextureUnitState();
4152                }
4153                else
4154                {
4155                    tex = retPass->getTextureUnitState(targetIndex);
4156                }
4157                (*tex) = *(pass->getTextureUnitState(t));
4158                                // If programmable, have to adjust the texcoord sets too
4159                                // D3D insists that texcoordsets match tex unit in programmable mode
4160                                if (retPass->hasVertexProgram())
4161                                        tex->setTextureCoordSet(targetIndex);
4162            }
4163            keepTUCount = origPassTUCount + 1;
4164                }// additive lighting
4165                else
4166                {
4167                        // need to keep spotlight fade etc
4168                        keepTUCount = retPass->getNumTextureUnitStates();
4169                }
4170
4171
4172                // Will also need fragment programs since this is a complex light setup
4173                if (!pass->getShadowReceiverFragmentProgramName().empty())
4174                {
4175                        // Have to merge the shadow receiver vertex program in
4176                        retPass->setFragmentProgram(
4177                                pass->getShadowReceiverFragmentProgramName(), false);
4178                        const GpuProgramPtr& prg = retPass->getFragmentProgram();
4179                        // Load this program if not done already
4180                        if (!prg->isLoaded())
4181                                prg->load();
4182                        // Copy params
4183                        retPass->setFragmentProgramParameters(
4184                                pass->getShadowReceiverFragmentProgramParameters());
4185
4186                        // Did we bind a shadow vertex program?
4187                        if (pass->hasVertexProgram() && !retPass->hasVertexProgram())
4188                        {
4189                                // We didn't bind a receiver-specific program, so bind the original
4190                                retPass->setVertexProgram(pass->getVertexProgramName(), false);
4191                                const GpuProgramPtr& prg = retPass->getVertexProgram();
4192                                // Load this program if required
4193                                if (!prg->isLoaded())
4194                                        prg->load();
4195                                // Copy params
4196                                retPass->setVertexProgramParameters(
4197                                        pass->getVertexProgramParameters());
4198
4199                        }
4200                }
4201                else 
4202                {
4203                        // Reset any merged fragment programs from last time
4204                        if (retPass == mShadowTextureCustomReceiverPass)
4205                        {
4206                                // reset fp?
4207                                if (mShadowTextureCustomReceiverPass->getFragmentProgramName() !=
4208                                        mShadowTextureCustomReceiverFragmentProgram)
4209                                {
4210                                        mShadowTextureCustomReceiverPass->setFragmentProgram(
4211                                                mShadowTextureCustomReceiverFragmentProgram, false);
4212                                        if(mShadowTextureCustomReceiverPass->hasFragmentProgram())
4213                                        {
4214                                                mShadowTextureCustomReceiverPass->setFragmentProgramParameters(
4215                                                        mShadowTextureCustomReceiverFPParams);
4216
4217                                        }
4218
4219                                }
4220
4221                        }
4222                        else
4223                        {
4224                                // Standard shadow receiver pass, reset to no fp
4225                                retPass->setFragmentProgram(StringUtil::BLANK);
4226                        }
4227
4228                }
4229
4230        // Remove any extra texture units
4231        while (retPass->getNumTextureUnitStates() > keepTUCount)
4232        {
4233            retPass->removeTextureUnitState(keepTUCount);
4234        }
4235
4236                retPass->_load();
4237
4238                return retPass;
4239        }
4240        else
4241        {
4242        return pass;
4243    }
4244
4245}
4246//---------------------------------------------------------------------
4247void SceneManager::renderShadowVolumesToStencil(const Light* light, const Camera* camera)
4248{
4249    // Get the shadow caster list
4250    const ShadowCasterList& casters = findShadowCastersForLight(light, camera);
4251    // Check there are some shadow casters to render
4252    if (casters.empty())
4253    {
4254        // No casters, just do nothing
4255        return;
4256    }
4257
4258    // Set up scissor test (point & spot lights only)
4259    bool scissored = false;
4260    if (light->getType() != Light::LT_DIRECTIONAL && 
4261        mDestRenderSystem->getCapabilities()->hasCapability(RSC_SCISSOR_TEST))
4262    {
4263        // Project the sphere onto the camera
4264        Real left, right, top, bottom;
4265        Sphere sphere(light->getDerivedPosition(), light->getAttenuationRange());
4266        if (camera->projectSphere(sphere, &left, &top, &right, &bottom))
4267        {
4268            scissored = true;
4269            // Turn normalised device coordinates into pixels
4270            int iLeft, iTop, iWidth, iHeight;
4271            mCurrentViewport->getActualDimensions(iLeft, iTop, iWidth, iHeight);
4272            size_t szLeft, szRight, szTop, szBottom;
4273
4274            szLeft = (size_t)(iLeft + ((left + 1) * 0.5 * iWidth));
4275            szRight = (size_t)(iLeft + ((right + 1) * 0.5 * iWidth));
4276            szTop = (size_t)(iTop + ((-top + 1) * 0.5 * iHeight));
4277            szBottom = (size_t)(iTop + ((-bottom + 1) * 0.5 * iHeight));
4278
4279            mDestRenderSystem->setScissorTest(true, szLeft, szTop, szRight, szBottom);
4280        }
4281    }
4282
4283    mDestRenderSystem->unbindGpuProgram(GPT_FRAGMENT_PROGRAM);
4284
4285    // Can we do a 2-sided stencil?
4286    bool stencil2sided = false;
4287    if (mDestRenderSystem->getCapabilities()->hasCapability(RSC_TWO_SIDED_STENCIL) && 
4288        mDestRenderSystem->getCapabilities()->hasCapability(RSC_STENCIL_WRAP))
4289    {
4290        // enable
4291        stencil2sided = true;
4292    }
4293
4294    // Do we have access to vertex programs?
4295    bool extrudeInSoftware = true;
4296    bool finiteExtrude = !mShadowUseInfiniteFarPlane || 
4297        !mDestRenderSystem->getCapabilities()->hasCapability(RSC_INFINITE_FAR_PLANE);
4298    if (mDestRenderSystem->getCapabilities()->hasCapability(RSC_VERTEX_PROGRAM))
4299    {
4300        extrudeInSoftware = false;
4301        // attach the appropriate extrusion vertex program
4302        // Note we never unset it because support for vertex programs is constant
4303        mShadowStencilPass->setVertexProgram(
4304            ShadowVolumeExtrudeProgram::getProgramName(light->getType(), finiteExtrude, false)
4305            , false);
4306        // Set params
4307        if (finiteExtrude)
4308        {
4309            mShadowStencilPass->setVertexProgramParameters(mFiniteExtrusionParams);
4310        }
4311        else
4312        {
4313            mShadowStencilPass->setVertexProgramParameters(mInfiniteExtrusionParams);
4314        }
4315        if (mDebugShadows)
4316        {
4317            mShadowDebugPass->setVertexProgram(
4318                ShadowVolumeExtrudeProgram::getProgramName(light->getType(), finiteExtrude, true)
4319                , false);
4320            // Set params
4321            if (finiteExtrude)
4322            {
4323                mShadowDebugPass->setVertexProgramParameters(mFiniteExtrusionParams);
4324            }
4325            else
4326            {
4327                mShadowDebugPass->setVertexProgramParameters(mInfiniteExtrusionParams);
4328            }
4329        }
4330
4331        mDestRenderSystem->bindGpuProgram(mShadowStencilPass->getVertexProgram()->_getBindingDelegate());
4332
4333    }
4334    else
4335    {
4336        mDestRenderSystem->unbindGpuProgram(GPT_VERTEX_PROGRAM);
4337    }
4338
4339    // Add light to internal list for use in render call
4340    LightList lightList;
4341    // const_cast is forgiveable here since we pass this const
4342    lightList.push_back(const_cast<Light*>(light));
4343
4344    // Turn off colour writing and depth writing
4345    mDestRenderSystem->_setColourBufferWriteEnabled(false, false, false, false);
4346        mDestRenderSystem->_disableTextureUnitsFrom(0);
4347    mDestRenderSystem->_setDepthBufferParams(true, false, CMPF_LESS);
4348    mDestRenderSystem->setStencilCheckEnabled(true);
4349
4350    // Calculate extrusion distance
4351    // Use direction light extrusion distance now, just form optimize code
4352    // generate a little, point/spot light will up to date later
4353    Real extrudeDist = mShadowDirLightExtrudeDist;
4354
4355    // Figure out the near clip volume
4356    const PlaneBoundedVolume& nearClipVol = 
4357        light->_getNearClipVolume(camera);
4358
4359    // Now iterate over the casters and render
4360    ShadowCasterList::const_iterator si, siend;
4361    siend = casters.end();
4362
4363
4364        // Now iterate over the casters and render
4365        for (si = casters.begin(); si != siend; ++si)
4366        {
4367        ShadowCaster* caster = *si;
4368                bool zfailAlgo = camera->isCustomNearClipPlaneEnabled();
4369                unsigned long flags = 0;
4370
4371        if (light->getType() != Light::LT_DIRECTIONAL)
4372        {
4373            extrudeDist = caster->getPointExtrusionDistance(light); 
4374        }
4375
4376        if (!extrudeInSoftware && !finiteExtrude)
4377        {
4378            // hardware extrusion, to infinity (and beyond!)
4379            flags |= SRF_EXTRUDE_TO_INFINITY;
4380        }
4381
4382                // Determine whether zfail is required
4383        if (zfailAlgo || nearClipVol.intersects(caster->getWorldBoundingBox()))
4384        {
4385            // We use zfail for this object only because zfail
4386                // compatible with zpass algorithm
4387                        zfailAlgo = true;
4388            // We need to include the light and / or dark cap
4389            // But only if they will be visible
4390            if(camera->isVisible(caster->getLightCapBounds()))
4391            {
4392                flags |= SRF_INCLUDE_LIGHT_CAP;
4393            }
4394                        // zfail needs dark cap
4395                        // UNLESS directional lights using hardware extrusion to infinity
4396                        // since that extrudes to a single point
4397                        if(!((flags & SRF_EXTRUDE_TO_INFINITY) && 
4398                                light->getType() == Light::LT_DIRECTIONAL) &&
4399                                camera->isVisible(caster->getDarkCapBounds(*light, extrudeDist)))
4400                        {
4401                                flags |= SRF_INCLUDE_DARK_CAP;
4402                        }
4403        }
4404                else
4405                {
4406                        // In zpass we need a dark cap if
4407                        // 1: infinite extrusion on point/spotlight sources in modulative shadows
4408                        //    mode, since otherwise in areas where there is no depth (skybox)
4409                        //    the infinitely projected volume will leave a dark band
4410                        // 2: finite extrusion on any light source since glancing angles
4411                        //    can peek through the end and shadow objects behind incorrectly
4412                        if ((flags & SRF_EXTRUDE_TO_INFINITY) && 
4413                                light->getType() != Light::LT_DIRECTIONAL && 
4414                                isShadowTechniqueModulative() && 
4415                                camera->isVisible(caster->getDarkCapBounds(*light, extrudeDist)))
4416                        {
4417                                flags |= SRF_INCLUDE_DARK_CAP;
4418                        }
4419                        else if (!(flags & SRF_EXTRUDE_TO_INFINITY) && 
4420                                camera->isVisible(caster->getDarkCapBounds(*light, extrudeDist)))
4421                        {
4422                                flags |= SRF_INCLUDE_DARK_CAP;
4423                        }
4424
4425                }
4426
4427        // Get shadow renderables                       
4428        ShadowCaster::ShadowRenderableListIterator iShadowRenderables =
4429            caster->getShadowVolumeRenderableIterator(mShadowTechnique,
4430            light, &mShadowIndexBuffer, extrudeInSoftware, 
4431            extrudeDist, flags);
4432
4433        // Render a shadow volume here
4434        //  - if we have 2-sided stencil, one render with no culling
4435        //  - otherwise, 2 renders, one with each culling method and invert the ops
4436        setShadowVolumeStencilState(false, zfailAlgo, stencil2sided);
4437        renderShadowVolumeObjects(iShadowRenderables, mShadowStencilPass, &lightList, flags,
4438            false, zfailAlgo, stencil2sided);
4439        if (!stencil2sided)
4440        {
4441            // Second pass
4442            setShadowVolumeStencilState(true, zfailAlgo, false);
4443            renderShadowVolumeObjects(iShadowRenderables, mShadowStencilPass, &lightList, flags,
4444                true, zfailAlgo, false);
4445        }
4446
4447        // Do we need to render a debug shadow marker?
4448        if (mDebugShadows)
4449        {
4450            // reset stencil & colour ops
4451            mDestRenderSystem->setStencilBufferParams();
4452            mShadowDebugPass->getTextureUnitState(0)->
4453                setColourOperationEx(LBX_MODULATE, LBS_MANUAL, LBS_CURRENT,
4454                zfailAlgo ? ColourValue(0.7, 0.0, 0.2) : ColourValue(0.0, 0.7, 0.2));
4455            _setPass(mShadowDebugPass);
4456            renderShadowVolumeObjects(iShadowRenderables, mShadowDebugPass, &lightList, flags,
4457                true, false, false);
4458            mDestRenderSystem->_setColourBufferWriteEnabled(false, false, false, false);
4459            mDestRenderSystem->_setDepthBufferFunction(CMPF_LESS);
4460        }
4461    }
4462
4463    // revert colour write state
4464    mDestRenderSystem->_setColourBufferWriteEnabled(true, true, true, true);
4465    // revert depth state
4466    mDestRenderSystem->_setDepthBufferParams();
4467
4468    mDestRenderSystem->setStencilCheckEnabled(false);
4469
4470    mDestRenderSystem->unbindGpuProgram(GPT_VERTEX_PROGRAM);
4471
4472    if (scissored)
4473    {
4474        // disable scissor test
4475        mDestRenderSystem->setScissorTest(false);
4476    }
4477
4478}
4479//---------------------------------------------------------------------
4480void SceneManager::renderShadowVolumeObjects(ShadowCaster::ShadowRenderableListIterator iShadowRenderables,
4481                                             Pass* pass,
4482                                             const LightList *manualLightList,
4483                                             unsigned long flags,
4484                                             bool secondpass, bool zfail, bool twosided)
4485{
4486    // ----- SHADOW VOLUME LOOP -----
4487    // Render all shadow renderables with same stencil operations
4488    while (iShadowRenderables.hasMoreElements())
4489    {
4490        ShadowRenderable* sr = iShadowRenderables.getNext();
4491
4492        // omit hidden renderables
4493        if (sr->isVisible())
4494        {
4495            // render volume, including dark and (maybe) light caps
4496            renderSingleObject(sr, pass, false, manualLightList);
4497
4498            // optionally render separate light cap
4499            if (sr->isLightCapSeparate() && (flags & SRF_INCLUDE_LIGHT_CAP))
4500            {
4501                ShadowRenderable* lightCap = sr->getLightCapRenderable();
4502                assert(lightCap && "Shadow renderable is missing a separate light cap renderable!");
4503
4504                // We must take care with light caps when we could 'see' the back facing
4505                // triangles directly:
4506                //   1. The front facing light caps must render as always fail depth
4507                //      check to avoid 'depth fighting'.
4508                //   2. The back facing light caps must use normal depth function to
4509                //      avoid break the standard depth check
4510                //
4511                // TODO:
4512                //   1. Separate light caps rendering doesn't need for the 'closed'
4513                //      mesh that never touch the near plane, because in this instance,
4514                //      we couldn't 'see' any back facing triangles directly. The
4515                //      'closed' mesh must determinate by edge list builder.
4516                //   2. There still exists 'depth fighting' bug with coplane triangles
4517                //      that has opposite facing. This usually occur when use two side
4518                //      material in the modeling tools and the model exporting tools
4519                //      exporting double triangles to represent this model. This bug
4520                //      can't fixed in GPU only, there must has extra work on edge list
4521                //      builder and shadow volume generater to fix it.
4522                //
4523                if (twosided)
4524                {
4525                    // select back facing light caps to render
4526                    mDestRenderSystem->_setCullingMode(CULL_ANTICLOCKWISE);
4527                    // use normal depth function for back facing light caps
4528                    renderSingleObject(lightCap, pass, false, manualLightList);
4529
4530                    // select front facing light caps to render
4531                    mDestRenderSystem->_setCullingMode(CULL_CLOCKWISE);
4532                    // must always fail depth check for front facing light caps
4533                    mDestRenderSystem->_setDepthBufferFunction(CMPF_ALWAYS_FAIL);
4534                    renderSingleObject(lightCap, pass, false, manualLightList);
4535
4536                    // reset depth function
4537                    mDestRenderSystem->_setDepthBufferFunction(CMPF_LESS);
4538                    // reset culling mode
4539                    mDestRenderSystem->_setCullingMode(CULL_NONE);
4540                }
4541                else if ((secondpass || zfail) && !(secondpass && zfail))
4542                {
4543                    // use normal depth function for back facing light caps
4544                    renderSingleObject(lightCap, pass, false, manualLightList);
4545                }
4546                else
4547                {
4548                    // must always fail depth check for front facing light caps
4549                    mDestRenderSystem->_setDepthBufferFunction(CMPF_ALWAYS_FAIL);
4550                    renderSingleObject(lightCap, pass, false, manualLightList);
4551
4552                    // reset depth function
4553                    mDestRenderSystem->_setDepthBufferFunction(CMPF_LESS);
4554                }
4555            }
4556        }
4557    }
4558}
4559//---------------------------------------------------------------------
4560void SceneManager::setShadowVolumeStencilState(bool secondpass, bool zfail, bool twosided)
4561{
4562    // Determinate the best stencil operation
4563    StencilOperation incrOp, decrOp;
4564    if (mDestRenderSystem->getCapabilities()->hasCapability(RSC_STENCIL_WRAP))
4565    {
4566        incrOp = SOP_INCREMENT_WRAP;
4567        decrOp = SOP_DECREMENT_WRAP;
4568    }
4569    else
4570    {
4571        incrOp = SOP_INCREMENT;
4572        decrOp = SOP_DECREMENT;
4573    }
4574
4575    // First pass, do front faces if zpass
4576    // Second pass, do back faces if zpass
4577    // Invert if zfail
4578    // this is to ensure we always increment before decrement
4579    // When two-sided stencil, always pass front face stencil
4580    // operation parameters and the inverse of them will happen
4581    // for back faces
4582    if ( !twosided && ((secondpass || zfail) && !(secondpass && zfail)) )
4583    {
4584        mDestRenderSystem->_setCullingMode(
4585            twosided? CULL_NONE : CULL_ANTICLOCKWISE);
4586        mDestRenderSystem->setStencilBufferParams(
4587            CMPF_ALWAYS_PASS, // always pass stencil check
4588            0, // no ref value (no compare)
4589            0xFFFFFFFF, // no mask
4590            SOP_KEEP, // stencil test will never fail
4591            zfail ? incrOp : SOP_KEEP, // back face depth fail
4592            zfail ? SOP_KEEP : decrOp, // back face pass
4593            twosided
4594            );
4595    }
4596    else
4597    {
4598        mDestRenderSystem->_setCullingMode(
4599            twosided? CULL_NONE : CULL_CLOCKWISE);
4600        mDestRenderSystem->setStencilBufferParams(
4601            CMPF_ALWAYS_PASS, // always pass stencil check
4602            0, // no ref value (no compare)
4603            0xFFFFFFFF, // no mask
4604            SOP_KEEP, // stencil test will never fail
4605            zfail ? decrOp : SOP_KEEP, // front face depth fail
4606            zfail ? SOP_KEEP : incrOp, // front face pass
4607            twosided
4608            );
4609    }
4610}
4611//---------------------------------------------------------------------
4612void SceneManager::setShadowColour(const ColourValue& colour)
4613{
4614    mShadowColour = colour;
4615
4616    // Change shadow material setting only when it's prepared,
4617    // otherwise, it'll set up while preparing shadow materials.
4618    if (mShadowModulativePass)
4619    {
4620        mShadowModulativePass->getTextureUnitState(0)->setColourOperationEx(
4621            LBX_MODULATE, LBS_MANUAL, LBS_CURRENT, colour);
4622    }
4623}
4624//---------------------------------------------------------------------
4625const ColourValue& SceneManager::getShadowColour(void) const
4626{
4627    return mShadowColour;
4628}
4629//---------------------------------------------------------------------
4630void SceneManager::setShadowFarDistance(Real distance)
4631{
4632    mShadowFarDist = distance;
4633    mShadowFarDistSquared = distance * distance;
4634}
4635//---------------------------------------------------------------------
4636void SceneManager::setShadowDirectionalLightExtrusionDistance(Real dist)
4637{
4638    mShadowDirLightExtrudeDist = dist;
4639}
4640//---------------------------------------------------------------------
4641Real SceneManager::getShadowDirectionalLightExtrusionDistance(void) const
4642{
4643    return mShadowDirLightExtrudeDist;
4644}
4645//---------------------------------------------------------------------
4646void SceneManager::setShadowIndexBufferSize(size_t size)
4647{
4648    if (!mShadowIndexBuffer.isNull() && size != mShadowIndexBufferSize)
4649    {
4650        // re-create shadow buffer with new size
4651        mShadowIndexBuffer = HardwareBufferManager::getSingleton().
4652            createIndexBuffer(HardwareIndexBuffer::IT_16BIT, 
4653            size, 
4654            HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE, 
4655            false);
4656    }
4657    mShadowIndexBufferSize = size;
4658}
4659//---------------------------------------------------------------------
4660void SceneManager::setShadowTextureConfig(size_t shadowIndex, unsigned short width, 
4661        unsigned short height, PixelFormat format)
4662{
4663        ShadowTextureConfig conf;
4664        conf.width = width;
4665        conf.height = height;
4666        conf.format = format;
4667
4668        setShadowTextureConfig(shadowIndex, conf);
4669
4670
4671}
4672//---------------------------------------------------------------------
4673void SceneManager::setShadowTextureConfig(size_t shadowIndex, 
4674        const ShadowTextureConfig& config)
4675{
4676        if (shadowIndex >= mShadowTextureConfigList.size())
4677        {
4678                OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 
4679                        "shadowIndex out of bounds",
4680                        "SceneManager::setShadowTextureConfig");
4681        }
4682        mShadowTextureConfigList[shadowIndex] = config;
4683
4684        mShadowTextureConfigDirty = true;
4685}
4686//---------------------------------------------------------------------
4687ConstShadowTextureConfigIterator SceneManager::getShadowTextureConfigIterator() const
4688{
4689        return ConstShadowTextureConfigIterator(
4690                mShadowTextureConfigList.begin(), mShadowTextureConfigList.end());
4691
4692}
4693//---------------------------------------------------------------------
4694void SceneManager::setShadowTextureSize(unsigned short size)
4695{
4696        // default all current
4697        for (ShadowTextureConfigList::iterator i = mShadowTextureConfigList.begin();
4698                i != mShadowTextureConfigList.end(); ++i)
4699        {
4700                if (i->width != size || i->height != size)
4701                {
4702                        i->width = i->height = size;
4703                        mShadowTextureConfigDirty = true;
4704                }
4705        }
4706
4707}
4708//---------------------------------------------------------------------
4709void SceneManager::setShadowTextureCount(size_t count)
4710{
4711    // Change size, any new items will take default
4712        if (count != mShadowTextureConfigList.size())
4713        {
4714                mShadowTextureConfigList.resize(count);
4715                mShadowTextureConfigDirty = true;
4716        }
4717}
4718//---------------------------------------------------------------------
4719void SceneManager::setShadowTexturePixelFormat(PixelFormat fmt)
4720{
4721        for (ShadowTextureConfigList::iterator i = mShadowTextureConfigList.begin();
4722                i != mShadowTextureConfigList.end(); ++i)
4723        {
4724                if (i->format != fmt)
4725                {
4726                        i->format = fmt;
4727                        mShadowTextureConfigDirty = true;
4728                }
4729        }
4730}
4731//---------------------------------------------------------------------
4732void SceneManager::setShadowTextureSettings(unsigned short size, 
4733        unsigned short count, PixelFormat fmt)
4734{
4735        setShadowTextureCount(count);
4736        for (ShadowTextureConfigList::iterator i = mShadowTextureConfigList.begin();
4737                i != mShadowTextureConfigList.end(); ++i)
4738        {
4739                if (i->width != size || i->height != size || i->format != fmt)
4740                {
4741                        i->width = i->height = size;
4742                        i->format = fmt;
4743                        mShadowTextureConfigDirty = true;
4744                }
4745        }
4746}
4747//---------------------------------------------------------------------
4748const TexturePtr& SceneManager::getShadowTexture(size_t shadowIndex)
4749{
4750        if (shadowIndex >= mShadowTextureConfigList.size())
4751        {
4752                OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 
4753                        "shadowIndex out of bounds",
4754                        "SceneManager::getShadowTexture");
4755        }
4756        ensureShadowTexturesCreated();
4757
4758        return mShadowTextures[shadowIndex];
4759
4760
4761}
4762//---------------------------------------------------------------------
4763void SceneManager::setShadowTextureSelfShadow(bool selfShadow) 
4764{ 
4765        mShadowTextureSelfShadow = selfShadow;
4766        if (isShadowTechniqueTextureBased())
4767                getRenderQueue()->setShadowCastersCannotBeReceivers(!selfShadow);
4768}
4769//---------------------------------------------------------------------
4770void SceneManager::setShadowTextureCasterMaterial(const String& name)
4771{
4772        if (name.empty())
4773        {
4774                mShadowTextureCustomCasterPass = 0;
4775        }
4776        else
4777        {
4778                MaterialPtr mat = MaterialManager::getSingleton().getByName(name);
4779                if (mat.isNull())
4780                {
4781                        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
4782                                "Cannot locate material called '" + name + "'", 
4783                                "SceneManager::setShadowTextureCasterMaterial");
4784                }
4785                mat->load();
4786                mShadowTextureCustomCasterPass = mat->getBestTechnique()->getPass(0);
4787                if (mShadowTextureCustomCasterPass->hasVertexProgram())
4788                {
4789                        // Save vertex program and params in case we have to swap them out
4790                        mShadowTextureCustomCasterVertexProgram = 
4791                                mShadowTextureCustomCasterPass->getVertexProgramName();
4792                        mShadowTextureCustomCasterVPParams = 
4793                                mShadowTextureCustomCasterPass->getVertexProgramParameters();
4794
4795                }
4796        }
4797}
4798//---------------------------------------------------------------------
4799void SceneManager::setShadowTextureReceiverMaterial(const String& name)
4800{
4801        if (name.empty())
4802        {
4803                mShadowTextureCustomReceiverPass = 0;
4804        }
4805        else
4806        {
4807                MaterialPtr mat = MaterialManager::getSingleton().getByName(name);
4808                if (mat.isNull())
4809                {
4810                        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
4811                                "Cannot locate material called '" + name + "'", 
4812                                "SceneManager::setShadowTextureReceiverMaterial");
4813                }
4814                mat->load();
4815                mShadowTextureCustomReceiverPass = mat->getBestTechnique()->getPass(0);
4816                if (mShadowTextureCustomReceiverPass->hasVertexProgram())
4817                {
4818                        // Save vertex program and params in case we have to swap them out
4819                        mShadowTextureCustomReceiverVertexProgram = 
4820                                mShadowTextureCustomReceiverPass->getVertexProgramName();
4821                        mShadowTextureCustomReceiverVPParams = 
4822                                mShadowTextureCustomReceiverPass->getVertexProgramParameters();
4823
4824                }
4825                else
4826                {
4827                        mShadowTextureCustomReceiverVertexProgram = StringUtil::BLANK;
4828
4829                }
4830                if (mShadowTextureCustomReceiverPass->hasFragmentProgram())
4831                {
4832                        // Save fragment program and params in case we have to swap them out
4833                        mShadowTextureCustomReceiverFragmentProgram = 
4834                                mShadowTextureCustomReceiverPass->getFragmentProgramName();
4835                        mShadowTextureCustomReceiverFPParams = 
4836                                mShadowTextureCustomReceiverPass->getFragmentProgramParameters();
4837
4838                }
4839                else
4840                {
4841                        mShadowTextureCustomReceiverFragmentProgram = StringUtil::BLANK;
4842
4843                }
4844        }
4845}
4846//---------------------------------------------------------------------
4847void SceneManager::setShadowCameraSetup(const ShadowCameraSetupPtr& shadowSetup)
4848{
4849        mDefaultShadowCameraSetup = shadowSetup;
4850
4851}
4852//---------------------------------------------------------------------
4853const ShadowCameraSetupPtr& SceneManager::getShadowCameraSetup() const
4854{
4855        return mDefaultShadowCameraSetup;
4856}
4857//---------------------------------------------------------------------
4858void SceneManager::ensureShadowTexturesCreated()
4859{
4860        if (mShadowTextureConfigDirty)
4861        {
4862                destroyShadowTextures();
4863                ShadowTextureManager::getSingleton().getShadowTextures(
4864                        mShadowTextureConfigList, mShadowTextures);
4865
4866                // clear shadow cam - light mapping
4867                mShadowCamLightMapping.clear();
4868
4869
4870                // Recreate shadow textures
4871                for (ShadowTextureList::iterator i = mShadowTextures.begin(); 
4872                        i != mShadowTextures.end(); ++i) 
4873                {
4874                        const TexturePtr& shadowTex = *i;
4875
4876                        // Camera names are local to SM
4877                        String camName = shadowTex->getName() + "Cam";
4878                        // Material names are global to SM, make specific
4879                        String matName = shadowTex->getName() + "Mat" + getName();
4880
4881                        RenderTexture *shadowRTT = shadowTex->getBuffer()->getRenderTarget();
4882
4883                        // Create camera for this texture, but note that we have to rebind
4884                        // in prepareShadowTextures to coexist with multiple SMs
4885                        Camera* cam = createCamera(camName);
4886                        cam->setAspectRatio(shadowTex->getWidth() / shadowTex->getHeight());
4887                        // Don't use rendering distance for light cameras; we don't want shadows
4888                        // for visible objects disappearing, especially for directional lights
4889                        cam->setUseRenderingDistance(false);
4890                        mShadowTextureCameras.push_back(cam);
4891
4892                        // Create a viewport, if not there already
4893                        if (shadowRTT->getNumViewports() == 0)
4894                        {
4895                                // Note camera assignment is transient when multiple SMs
4896                                Viewport *v = shadowRTT->addViewport(cam);
4897                                v->setClearEveryFrame(true);
4898                                // remove overlays
4899                                v->setOverlaysEnabled(false);
4900                        }
4901
4902                        // Don't update automatically - we'll do it when required
4903                        shadowRTT->setAutoUpdated(false);
4904
4905                        // Also create corresponding Material used for rendering this shadow
4906                        MaterialPtr mat = MaterialManager::getSingleton().getByName(matName);
4907                        if (mat.isNull())
4908                        {
4909                                mat = MaterialManager::getSingleton().create(
4910                                        matName, ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME);
4911                        }
4912                        Pass* p = mat->getTechnique(0)->getPass(0);
4913                        if (p->getNumTextureUnitStates() != 1 ||
4914                                p->getTextureUnitState(0)->_getTexturePtr(0) != shadowTex)
4915                        {
4916                                mat->getTechnique(0)->getPass(0)->removeAllTextureUnitStates();
4917                                // create texture unit referring to render target texture
4918                                TextureUnitState* texUnit = 
4919                                        p->createTextureUnitState(shadowTex->getName());
4920                                // set projective based on camera
4921                                texUnit->setProjectiveTexturing(!p->hasVertexProgram(), cam);
4922                                // clamp to border colour
4923                                texUnit->setTextureAddressingMode(TextureUnitState::TAM_BORDER);
4924                                texUnit->setTextureBorderColour(ColourValue::White);
4925                                mat->touch();
4926
4927                        }
4928
4929                        // insert dummy camera-light combination
4930                        mShadowCamLightMapping[cam] = 0;
4931
4932                        // Get null shadow texture
4933                        if (mShadowTextureConfigList.empty())
4934                        {
4935                                mNullShadowTexture.setNull();
4936                        }
4937                        else
4938                        {
4939                                mNullShadowTexture = 
4940                                        ShadowTextureManager::getSingleton().getNullShadowTexture(
4941                                                mShadowTextureConfigList[0].format);
4942                        }
4943
4944
4945                }
4946                mShadowTextureConfigDirty = false;
4947        }
4948
4949}
4950//---------------------------------------------------------------------
4951void SceneManager::destroyShadowTextures(void)
4952{
4953       
4954    ShadowTextureList::iterator i, iend;
4955    ShadowTextureCameraList::iterator ci;
4956    iend = mShadowTextures.end();
4957    ci = mShadowTextureCameras.begin();
4958    for (i = mShadowTextures.begin(); i != iend; ++i, ++ci)
4959    {
4960        TexturePtr &shadowTex = *i;
4961
4962                // Cleanup material that references this texture
4963                String matName = shadowTex->getName() + "Mat" + getName();
4964                MaterialPtr mat = MaterialManager::getSingleton().getByName(matName);
4965                if (!mat.isNull())
4966                {
4967                        // manually clear TUS to ensure texture ref released
4968                        mat->getTechnique(0)->getPass(0)->removeAllTextureUnitStates();
4969                        MaterialManager::getSingleton().remove(mat->getHandle());
4970                }
4971
4972                // Always destroy camera since they are local to this SM
4973                destroyCamera(*ci);
4974    }
4975    mShadowTextures.clear();
4976        mShadowTextureCameras.clear();
4977
4978        // Will destroy if no other scene managers referencing
4979        ShadowTextureManager::getSingleton().clearUnused();
4980
4981        mShadowTextureConfigDirty = true;
4982       
4983}
4984//---------------------------------------------------------------------
4985void SceneManager::prepareShadowTextures(Camera* cam, Viewport* vp)
4986{
4987        // create shadow textures if needed
4988        ensureShadowTexturesCreated();
4989
4990    // Set the illumination stage, prevents recursive calls
4991    IlluminationRenderStage savedStage = mIlluminationStage;
4992    mIlluminationStage = IRS_RENDER_TO_TEXTURE;
4993
4994    // Determine far shadow distance
4995    Real shadowDist = mShadowFarDist;
4996    if (!shadowDist)
4997    {
4998        // need a shadow distance, make one up
4999        shadowDist = cam->getNearClipDistance() * 300;
5000    }
5001        Real shadowOffset = shadowDist * mShadowTextureOffset;
5002    // Precalculate fading info
5003        Real shadowEnd = shadowDist + shadowOffset;
5004        Real fadeStart = shadowEnd * mShadowTextureFadeStart;
5005        Real fadeEnd = shadowEnd * mShadowTextureFadeEnd;
5006        // Additive lighting should not use fogging, since it will overbrighten; use border clamp
5007        if (!isShadowTechniqueAdditive())
5008        {
5009                // set fogging to hide the shadow edge
5010                mShadowReceiverPass->setFog(true, FOG_LINEAR, ColourValue::White, 
5011                        0, fadeStart, fadeEnd);
5012        }
5013    else
5014    {
5015        // disable fogging explicitly
5016        mShadowReceiverPass->setFog(true, FOG_NONE);
5017    }
5018
5019    // Iterate over the lights we've found, max out at the limit of light textures
5020        // Note that the light sorting must now place shadow casting lights at the
5021        // start of the light list, therefore we do not need to deal with potential
5022        // mismatches in the light<->shadow texture list any more
5023
5024    LightList::iterator i, iend;
5025    ShadowTextureList::iterator si, siend;
5026        ShadowTextureCameraList::iterator ci;
5027    iend = mLightsAffectingFrustum.end();
5028    siend = mShadowTextures.end();
5029        ci = mShadowTextureCameras.begin();
5030    for (i = mLightsAffectingFrustum.begin(), si = mShadowTextures.begin();
5031        i != iend && si != siend; ++i)
5032    {
5033        Light* light = *i;
5034
5035                // skip light if shadows are disabled
5036                if (!light->getCastShadows())
5037                        continue;
5038
5039                TexturePtr &shadowTex = *si;
5040        RenderTarget *shadowRTT = shadowTex->getBuffer()->getRenderTarget();
5041        Viewport *shadowView = shadowRTT->getViewport(0);
5042        Camera *texCam = *ci;
5043                // rebind camera, incase another SM in use which has switched to its cam
5044                shadowView->setCamera(texCam);
5045       
5046                // update shadow cam - light mapping
5047                ShadowCamLightMapping::iterator camLightIt = mShadowCamLightMapping.find( texCam );
5048                assert(camLightIt != mShadowCamLightMapping.end());
5049                camLightIt->second = light;
5050
5051                if (light->getCustomShadowCameraSetup().isNull())
5052                        mDefaultShadowCameraSetup->getShadowCamera(this, cam, vp, light, texCam);
5053                else
5054                        light->getCustomShadowCameraSetup()->getShadowCamera(this, cam, vp, light, texCam);
5055
5056        // Setup background colour
5057        shadowView->setBackgroundColour(ColourValue::White);
5058
5059                // Fire shadow caster update, callee can alter camera settings
5060                fireShadowTexturesPreCaster(light, texCam);
5061
5062        // Update target
5063        shadowRTT->update();
5064
5065        ++si; // next shadow texture
5066                ++ci; // next camera
5067    }
5068    // Set the illumination stage, prevents recursive calls
5069    mIlluminationStage = savedStage;
5070
5071        fireShadowTexturesUpdated(
5072                std::min(mLightsAffectingFrustum.size(), mShadowTextures.size()));
5073
5074        ShadowTextureManager::getSingleton().clearUnused();
5075
5076}
5077//---------------------------------------------------------------------
5078StaticGeometry* SceneManager::createStaticGeometry(const String& name)
5079{
5080        // Check not existing
5081        if (mStaticGeometryList.find(name) != mStaticGeometryList.end())
5082        {
5083                OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM, 
5084                        "StaticGeometry with name '" + name + "' already exists!", 
5085                        "SceneManager::createStaticGeometry");
5086        }
5087        StaticGeometry* ret = new StaticGeometry(this, name);
5088        mStaticGeometryList[name] = ret;
5089        return ret;
5090}
5091//---------------------------------------------------------------------
5092StaticGeometry* SceneManager::getStaticGeometry(const String& name) const
5093{
5094        StaticGeometryList::const_iterator i = mStaticGeometryList.find(name);
5095        if (i == mStaticGeometryList.end())
5096        {
5097                OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 
5098                        "StaticGeometry with name '" + name + "' not found", 
5099                        "SceneManager::createStaticGeometry");
5100        }
5101        return i->second;
5102}
5103//-----------------------------------------------------------------------
5104bool SceneManager::hasStaticGeometry(const String& name) const
5105{
5106        return (mStaticGeometryList.find(name) != mStaticGeometryList.end());
5107}
5108
5109//---------------------------------------------------------------------
5110void SceneManager::destroyStaticGeometry(StaticGeometry* geom)
5111{
5112        destroyStaticGeometry(geom->getName());
5113}
5114//---------------------------------------------------------------------
5115void SceneManager::destroyStaticGeometry(const String& name)
5116{
5117        StaticGeometryList::iterator i = mStaticGeometryList.find(name);
5118        if (i != mStaticGeometryList.end())
5119        {
5120                delete i->second;
5121                mStaticGeometryList.erase(i);
5122        }
5123
5124}
5125//---------------------------------------------------------------------
5126void SceneManager::destroyAllStaticGeometry(void)
5127{
5128        StaticGeometryList::iterator i, iend;
5129        iend = mStaticGeometryList.end();
5130        for (i = mStaticGeometryList.begin(); i != iend; ++i)
5131        {
5132                delete i->second;
5133        }
5134        mStaticGeometryList.clear();
5135}
5136//---------------------------------------------------------------------
5137InstancedGeometry* SceneManager::createInstancedGeometry(const String& name)
5138{
5139        // Check not existing
5140        if (mInstancedGeometryList.find(name) != mInstancedGeometryList.end())
5141        {
5142                OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM, 
5143                        "InstancedGeometry with name '" + name + "' already exists!", 
5144                        "SceneManager::createInstancedGeometry");
5145        }
5146        InstancedGeometry* ret = new InstancedGeometry(this, name);
5147        mInstancedGeometryList[name] = ret;
5148        return ret;
5149}
5150//---------------------------------------------------------------------
5151InstancedGeometry* SceneManager::getInstancedGeometry(const String& name) const
5152{
5153        InstancedGeometryList::const_iterator i = mInstancedGeometryList.find(name);
5154        if (i == mInstancedGeometryList.end())
5155        {
5156                OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 
5157                        "InstancedGeometry with name '" + name + "' not found", 
5158                        "SceneManager::createInstancedGeometry");
5159        }
5160        return i->second;
5161}
5162//---------------------------------------------------------------------
5163void SceneManager::destroyInstancedGeometry(InstancedGeometry* geom)
5164{
5165        destroyInstancedGeometry(geom->getName());
5166}
5167//---------------------------------------------------------------------
5168void SceneManager::destroyInstancedGeometry(const String& name)
5169{
5170        InstancedGeometryList::iterator i = mInstancedGeometryList.find(name);
5171        if (i != mInstancedGeometryList.end())
5172        {
5173                delete i->second;
5174                mInstancedGeometryList.erase(i);
5175        }
5176
5177}
5178//---------------------------------------------------------------------
5179void SceneManager::destroyAllInstancedGeometry(void)
5180{
5181        InstancedGeometryList::iterator i, iend;
5182        iend = mInstancedGeometryList.end();
5183        for (i = mInstancedGeometryList.begin(); i != iend; ++i)
5184        {
5185                delete i->second;
5186        }
5187        mInstancedGeometryList.clear();
5188}
5189//---------------------------------------------------------------------
5190AxisAlignedBoxSceneQuery* 
5191SceneManager::createAABBQuery(const AxisAlignedBox& box, unsigned long mask)
5192{
5193    DefaultAxisAlignedBoxSceneQuery* q = new DefaultAxisAlignedBoxSceneQuery(this);
5194    q->setBox(box);
5195    q->setQueryMask(mask);
5196    return q;
5197}
5198//---------------------------------------------------------------------
5199SphereSceneQuery* 
5200SceneManager::createSphereQuery(const Sphere& sphere, unsigned long mask)
5201{
5202    DefaultSphereSceneQuery* q = new DefaultSphereSceneQuery(this);
5203    q->setSphere(sphere);
5204    q->setQueryMask(mask);
5205    return q;
5206}
5207//---------------------------------------------------------------------
5208PlaneBoundedVolumeListSceneQuery* 
5209SceneManager::createPlaneBoundedVolumeQuery(const PlaneBoundedVolumeList& volumes, 
5210                                            unsigned long mask)
5211{
5212    DefaultPlaneBoundedVolumeListSceneQuery* q = new DefaultPlaneBoundedVolumeListSceneQuery(this);
5213    q->setVolumes(volumes);
5214    q->setQueryMask(mask);
5215    return q;
5216}
5217
5218//---------------------------------------------------------------------
5219RaySceneQuery* 
5220SceneManager::createRayQuery(const Ray& ray, unsigned long mask)
5221{
5222    DefaultRaySceneQuery* q = new DefaultRaySceneQuery(this);
5223    q->setRay(ray);
5224    q->setQueryMask(mask);
5225    return q;
5226}
5227//---------------------------------------------------------------------
5228IntersectionSceneQuery* 
5229SceneManager::createIntersectionQuery(unsigned long mask)
5230{
5231
5232    DefaultIntersectionSceneQuery* q = new DefaultIntersectionSceneQuery(this);
5233    q->setQueryMask(mask);
5234    return q;
5235}
5236//---------------------------------------------------------------------
5237void SceneManager::destroyQuery(SceneQuery* query)
5238{
5239    delete query;
5240}
5241//---------------------------------------------------------------------
5242SceneManager::MovableObjectCollection* 
5243SceneManager::getMovableObjectCollection(const String& typeName)
5244{
5245        // lock collection mutex
5246        OGRE_LOCK_MUTEX(mMovableObjectCollectionMapMutex)
5247
5248        MovableObjectCollectionMap::iterator i = 
5249                mMovableObjectCollectionMap.find(typeName);
5250        if (i == mMovableObjectCollectionMap.end())
5251        {
5252                // create
5253                MovableObjectCollection* newCollection = new MovableObjectCollection();
5254                mMovableObjectCollectionMap[typeName] = newCollection;
5255                return newCollection;
5256        }
5257        else
5258        {
5259                return i->second;
5260        }
5261}
5262//---------------------------------------------------------------------
5263const SceneManager::MovableObjectCollection* 
5264SceneManager::getMovableObjectCollection(const String& typeName) const
5265{
5266        // lock collection mutex
5267        OGRE_LOCK_MUTEX(mMovableObjectCollectionMapMutex)
5268
5269        MovableObjectCollectionMap::const_iterator i = 
5270                mMovableObjectCollectionMap.find(typeName);
5271        if (i == mMovableObjectCollectionMap.end())
5272        {
5273                OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 
5274                        "Object collection named '" + typeName + "' does not exist.", 
5275                        "SceneManager::getMovableObjectCollection");
5276        }
5277        else
5278        {
5279                return i->second;
5280        }
5281}
5282//---------------------------------------------------------------------
5283MovableObject* SceneManager::createMovableObject(const String& name, 
5284        const String& typeName, const NameValuePairList* params)
5285{
5286        MovableObjectFactory* factory = 
5287                Root::getSingleton().getMovableObjectFactory(typeName);
5288        // Check for duplicate names
5289        MovableObjectCollection* objectMap = getMovableObjectCollection(typeName);
5290
5291        {
5292                OGRE_LOCK_MUTEX(objectMap->mutex)
5293
5294                if (objectMap->map.find(name) != objectMap->map.end())
5295                {
5296                        OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM, 
5297                                "An object of type '" + typeName + "' with name '" + name
5298                                + "' already exists.", 
5299                                "SceneManager::createMovableObject");
5300                }
5301
5302                MovableObject* newObj = factory->createInstance(name, this, params);
5303                objectMap->map[name] = newObj;
5304                return newObj;
5305        }
5306
5307}
5308//---------------------------------------------------------------------
5309void SceneManager::destroyMovableObject(const String& name, const String& typeName)
5310{
5311        MovableObjectCollection* objectMap = getMovableObjectCollection(typeName);
5312        MovableObjectFactory* factory = 
5313                Root::getSingleton().getMovableObjectFactory(typeName);
5314
5315        {
5316                OGRE_LOCK_MUTEX(objectMap->mutex)
5317
5318                MovableObjectMap::iterator mi = objectMap->map.find(name);
5319                if (mi != objectMap->map.end())
5320                {
5321                        factory->destroyInstance(mi->second);
5322                        objectMap->map.erase(mi);
5323                }
5324        }
5325}
5326//---------------------------------------------------------------------
5327void SceneManager::destroyAllMovableObjectsByType(const String& typeName)
5328{
5329        MovableObjectCollection* objectMap = getMovableObjectCollection(typeName);
5330        MovableObjectFactory* factory = 
5331                Root::getSingleton().getMovableObjectFactory(typeName);
5332       
5333        {
5334                OGRE_LOCK_MUTEX(objectMap->mutex)
5335                MovableObjectMap::iterator i = objectMap->map.begin();
5336                for (; i != objectMap->map.end(); ++i)
5337                {
5338                        // Only destroy our own
5339                        if (i->second->_getManager() == this)
5340                        {
5341                                factory->destroyInstance(i->second);
5342                        }
5343                }
5344                objectMap->map.clear();
5345        }
5346}
5347//---------------------------------------------------------------------
5348void SceneManager::destroyAllMovableObjects(void)
5349{
5350        // Lock collection mutex
5351        OGRE_LOCK_MUTEX(mMovableObjectCollectionMapMutex)
5352
5353        MovableObjectCollectionMap::iterator ci = mMovableObjectCollectionMap.begin();
5354
5355        for(;ci != mMovableObjectCollectionMap.end(); ++ci)
5356        {
5357                MovableObjectCollection* coll = ci->second;
5358
5359                // lock map mutex
5360                OGRE_LOCK_MUTEX(coll->mutex)
5361
5362                if (Root::getSingleton().hasMovableObjectFactory(ci->first))
5363                {
5364                        // Only destroy if we have a factory instance; otherwise must be injected
5365                        MovableObjectFactory* factory = 
5366                                Root::getSingleton().getMovableObjectFactory(ci->first);
5367                        MovableObjectMap::iterator i = coll->map.begin();
5368                        for (; i != coll->map.end(); ++i)
5369                        {
5370                                if (i->second->_getManager() == this)
5371                                {
5372                                        factory->destroyInstance(i->second);
5373                                }
5374                        }
5375                }
5376                coll->map.clear();
5377        }
5378
5379}
5380//---------------------------------------------------------------------
5381MovableObject* SceneManager::getMovableObject(const String& name, const String& typeName) const
5382{
5383        const MovableObjectCollection* objectMap = getMovableObjectCollection(typeName);
5384       
5385        {
5386                OGRE_LOCK_MUTEX(objectMap->mutex)
5387                MovableObjectMap::const_iterator mi = objectMap->map.find(name);
5388                if (mi == objectMap->map.end())
5389                {
5390                        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 
5391                                "Object named '" + name + "' does not exist.", 
5392                                "SceneManager::getMovableObject");
5393                }
5394                return mi->second;
5395        }
5396       
5397}
5398//-----------------------------------------------------------------------
5399bool SceneManager::hasMovableObject(const String& name, const String& typeName) const
5400{
5401        OGRE_LOCK_MUTEX(mMovableObjectCollectionMapMutex)
5402
5403        MovableObjectCollectionMap::const_iterator i = 
5404                mMovableObjectCollectionMap.find(typeName);
5405        if (i == mMovableObjectCollectionMap.end())
5406                return false;
5407       
5408        {
5409                OGRE_LOCK_MUTEX(i->second->mutex)
5410                return (i->second->map.find(name) != i->second->map.end());
5411        }
5412}
5413
5414//---------------------------------------------------------------------
5415SceneManager::MovableObjectIterator
5416SceneManager::getMovableObjectIterator(const String& typeName)
5417{
5418        MovableObjectCollection* objectMap = getMovableObjectCollection(typeName);
5419        // Iterator not thread safe! Warned in header.
5420        return MovableObjectIterator(objectMap->map.begin(), objectMap->map.end());
5421}
5422//---------------------------------------------------------------------
5423void SceneManager::destroyMovableObject(MovableObject* m)
5424{
5425        destroyMovableObject(m->getName(), m->getMovableType());
5426}
5427//---------------------------------------------------------------------
5428void SceneManager::injectMovableObject(MovableObject* m)
5429{
5430        MovableObjectCollection* objectMap = getMovableObjectCollection(m->getMovableType());
5431        {
5432                OGRE_LOCK_MUTEX(objectMap->mutex)
5433
5434                objectMap->map[m->getName()] = m;
5435        }
5436}
5437//---------------------------------------------------------------------
5438void SceneManager::extractMovableObject(const String& name, const String& typeName)
5439{
5440        MovableObjectCollection* objectMap = getMovableObjectCollection(typeName);
5441        {
5442                OGRE_LOCK_MUTEX(objectMap->mutex)
5443                MovableObjectMap::iterator mi = objectMap->map.find(name);
5444                if (mi != objectMap->map.end())
5445                {
5446                        // no delete
5447                        objectMap->map.erase(mi);
5448                }
5449        }
5450
5451}
5452//---------------------------------------------------------------------
5453void SceneManager::extractMovableObject(MovableObject* m)
5454{
5455        extractMovableObject(m->getName(), m->getMovableType());
5456}
5457//---------------------------------------------------------------------
5458void SceneManager::extractAllMovableObjectsByType(const String& typeName)
5459{
5460        MovableObjectCollection* objectMap = getMovableObjectCollection(typeName);
5461        {
5462                OGRE_LOCK_MUTEX(objectMap->mutex)
5463                // no deletion
5464                objectMap->map.clear();
5465        }
5466}
5467//---------------------------------------------------------------------
5468void SceneManager::_injectRenderWithPass(Pass *pass, Renderable *rend, bool shadowDerivation )
5469{
5470        // render something as if it came from the current queue
5471    const Pass *usedPass = _setPass(pass, false, shadowDerivation);
5472    renderSingleObject(rend, usedPass, false);
5473}
5474//---------------------------------------------------------------------
5475RenderSystem *SceneManager::getDestinationRenderSystem()
5476{
5477        return mDestRenderSystem;
5478}
5479//---------------------------------------------------------------------
5480uint32 SceneManager::_getCombinedVisibilityMask(void) const
5481{
5482        return mCurrentViewport ?
5483                mCurrentViewport->getVisibilityMask() & mVisibilityMask : mVisibilityMask;
5484
5485}
5486//---------------------------------------------------------------------
5487const VisibleObjectsBoundsInfo& 
5488SceneManager::getVisibleObjectsBoundsInfo(const Camera* cam) const
5489{
5490        static VisibleObjectsBoundsInfo nullBox;
5491
5492        CamVisibleObjectsMap::const_iterator camVisObjIt = mCamVisibleObjectsMap.find( cam );
5493
5494        if ( camVisObjIt == mCamVisibleObjectsMap.end() )
5495                return nullBox;
5496        else
5497                return camVisObjIt->second;
5498}
5499//---------------------------------------------------------------------
5500const VisibleObjectsBoundsInfo& 
5501SceneManager::getShadowCasterBoundsInfo( const Light* light ) const
5502{
5503        static VisibleObjectsBoundsInfo nullBox;
5504
5505        // find light
5506        ShadowCamLightMapping::const_iterator it; 
5507        for ( it = mShadowCamLightMapping.begin() ; it != mShadowCamLightMapping.end(); ++it )
5508        {
5509                if ( it->second == light )
5510                {
5511                        // search the camera-aab list for the texture cam
5512                        CamVisibleObjectsMap::const_iterator camIt = mCamVisibleObjectsMap.find( it->first );
5513
5514                        if ( camIt == mCamVisibleObjectsMap.end() )
5515                        {
5516                                return nullBox;
5517                        }
5518                        else
5519                        {
5520                return camIt->second;
5521                        }
5522                }
5523        }
5524
5525        // AAB not available
5526        return nullBox;
5527}
5528//---------------------------------------------------------------------
5529void SceneManager::setQueuedRenderableVisitor(SceneManager::SceneMgrQueuedRenderableVisitor* visitor)
5530{
5531        if (visitor)
5532                mActiveQueuedRenderableVisitor = visitor;
5533        else
5534                mActiveQueuedRenderableVisitor = &mDefaultQueuedRenderableVisitor;
5535}
5536//---------------------------------------------------------------------
5537SceneManager::SceneMgrQueuedRenderableVisitor* SceneManager::getQueuedRenderableVisitor(void) const
5538{
5539        return mActiveQueuedRenderableVisitor;
5540}
5541
5542
5543
5544}
Note: See TracBrowser for help on using the repository browser.