source: OGRE/trunk/ogrenew/OgreMain/src/OgreSceneManager.cpp @ 657

Revision 657, 149.8 KB checked in by mattausch, 18 years ago (diff)

added ogre dependencies and patched ogre sources

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