Index: OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/OgreTextureUnitState.h
===================================================================
--- OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/OgreTextureUnitState.h	(revision 768)
+++ OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/OgreTextureUnitState.h	(revision 768)
@@ -0,0 +1,1063 @@
+/*
+-----------------------------------------------------------------------------
+This source file is part of OGRE
+(Object-oriented Graphics Rendering Engine)
+For the latest info, see http://ogre.sourceforge.net/
+
+Copyright (c) 2000-2005 The OGRE Team
+Also see acknowledgements in Readme.html
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+#ifndef __TextureUnitState_H__
+#define __TextureUnitState_H__
+
+#include "OgrePrerequisites.h"
+#include "OgreCommon.h"
+#include "OgreBlendMode.h"
+#include "OgreMatrix4.h"
+#include "OgreIteratorWrappers.h"
+#include "OgreString.h"
+#include "OgreTexture.h"
+
+namespace Ogre {
+    /** Class representing the state of a single texture unit during a Pass of a
+        Technique, of a Material.
+    @remarks
+        Texture units are pipelines for retrieving texture data for rendering onto
+        your objects in the world. Using them is common to both the fixed-function and 
+        the programmable (vertex and fragment program) pipeline, but some of the 
+        settings will only have an effect in the fixed-function pipeline (for example, 
+        setting a texture rotation will have no effect if you use the programmable
+        pipeline, because this is overridden by the fragment program). The effect
+        of each setting as regards the 2 pipelines is commented in each setting.
+    @par
+        When I use the term 'fixed-function pipeline' I mean traditional rendering
+        where you do not use vertex or fragment programs (shaders). Programmable 
+        pipeline means that for this pass you are using vertex or fragment programs.
+    */
+    class _OgreExport TextureUnitState
+    {
+        friend class RenderSystem;
+    public:
+        /** Definition of the broad types of texture effect you can apply to a texture unit.
+        @note
+            Note that these have no effect when using the programmable pipeline, since their
+            effect is overridden by the vertex / fragment programs.
+        */
+        enum TextureEffectType
+        {
+            /// Generate all texture coords based on angle between camera and vertex
+            ET_ENVIRONMENT_MAP,
+            /// Generate texture coords based on a frustum
+            ET_PROJECTIVE_TEXTURE,
+            /// Constant u/v scrolling effect
+            ET_UVSCROLL,
+			/// Constant u scrolling effect
+            ET_USCROLL,
+			/// Constant u/v scrolling effect
+            ET_VSCROLL,
+            /// Constant rotation
+            ET_ROTATE,
+            /// More complex transform
+            ET_TRANSFORM
+
+        };
+
+        /** Enumeration to specify type of envmap.
+        @note
+            Note that these have no effect when using the programmable pipeline, since their
+            effect is overridden by the vertex / fragment programs.
+        */
+        enum EnvMapType
+        {
+            /// Envmap based on vector from camera to vertex position, good for planar geometry
+            ENV_PLANAR,
+            /// Envmap based on dot of vector from camera to vertex and vertex normal, good for curves
+            ENV_CURVED,
+            /// Envmap entended to supply reflection vectors for cube mapping
+            ENV_REFLECTION,
+            /// Envmap entended to supply normal vectors for cube mapping
+            ENV_NORMAL
+        };
+
+        /** Useful enumeration when dealing with procedural transforms.
+        @note
+            Note that these have no effect when using the programmable pipeline, since their
+            effect is overridden by the vertex / fragment programs.
+        */
+        enum TextureTransformType
+        {
+            TT_TRANSLATE_U,
+            TT_TRANSLATE_V,
+            TT_SCALE_U,
+            TT_SCALE_V,
+            TT_ROTATE
+        };
+
+        /** Texture addressing modes - default is TAM_WRAP.
+        @note
+            These settings are relevant in both the fixed-function and the
+            programmable pipeline.
+        */
+        enum TextureAddressingMode
+        {
+            /// Texture wraps at values over 1.0
+            TAM_WRAP,
+            /// Texture mirrors (flips) at joins over 1.0
+            TAM_MIRROR,
+            /// Texture clamps at 1.0
+            TAM_CLAMP,
+            /// Texture coordinates outside the range [0.0, 1.0] are set to the border colour
+            TAM_BORDER
+        };
+
+		/** Texture addressing mode for each texture coordinate. */
+		struct UVWAddressingMode
+		{
+			TextureAddressingMode u, v, w;
+		};
+
+        /** Enum identifying the frame indexes for faces of a cube map (not the composite 3D type.
+        */
+        enum TextureCubeFace
+        {
+            CUBE_FRONT = 0,
+            CUBE_BACK = 1,
+            CUBE_LEFT = 2,
+            CUBE_RIGHT = 3,
+            CUBE_UP = 4,
+            CUBE_DOWN = 5
+        };
+
+        /** Internal structure defining a texture effect.
+        */
+        struct TextureEffect {
+            TextureEffectType type;
+            int subtype;
+            Real arg1, arg2;
+            WaveformType waveType;
+            Real base;
+            Real frequency;
+            Real phase;
+            Real amplitude;
+            Controller<Real>* controller;
+            const Frustum* frustum;
+        };
+
+        /** Texture effects in a multimap paired array
+        */
+        typedef std::multimap<TextureEffectType, TextureEffect> EffectMap;
+
+        /** Default constructor.
+        */
+        TextureUnitState(Pass* parent);
+
+        TextureUnitState(Pass* parent, const TextureUnitState& oth );
+
+        TextureUnitState & operator = ( const TextureUnitState& oth );
+
+        /** Default destructor.
+        */
+        ~TextureUnitState();
+
+        /** Name-based constructor.
+        @param
+        name The basic name of the texture e.g. brickwall.jpg, stonefloor.png
+        @param
+        texCoordSet The index of the texture coordinate set to use.
+        */
+		TextureUnitState( Pass* parent, const String& texName, unsigned int texCoordSet = 0);
+
+        /** Get the name of current texture image for this layer.
+        @remarks
+        This will either always be a single name for this layer,
+        or will be the name of the current frame for an animated
+        or otherwise multi-frame texture.
+        @note
+        Applies to both fixed-function and programmable pipeline.
+        */
+        const String& getTextureName(void) const;
+
+        /** Sets this texture layer to use a single texture, given the
+        name of the texture to use on this layer.
+        @note
+        Applies to both fixed-function and programmable pipeline.
+        */
+        void setTextureName( const String& name, TextureType ttype = TEX_TYPE_2D, int mipmaps = -1, bool isAlpha = false);
+
+        /** Sets this texture layer to use a combination of 6 texture maps, each one relating to a face of a cube.
+        @remarks
+        Cubic textures are made up of 6 separate texture images. Each one of these is an orthoganal view of the
+        world with a FOV of 90 degrees and an aspect ratio of 1:1. You can generate these from 3D Studio by
+        rendering a scene to a reflection map of a transparent cube and saving the output files.
+        @par
+        Cubic maps can be used either for skyboxes (complete wrap-around skies, like space) or as environment
+        maps to simulate reflections. The system deals with these 2 scenarios in different ways:
+        <ol>
+        <li>
+        <p>
+        for cubic environment maps, the 6 textures are combined into a single 'cubic' texture map which
+        is then addressed using 3D texture coordinates. This is required because you don't know what
+        face of the box you're going to need to address when you render an object, and typically you
+        need to reflect more than one face on the one object, so all 6 textures are needed to be
+        'active' at once. Cubic environment maps are enabled by calling this method with the forUVW
+        parameter set to true, and then calling setEnvironmentMap(true).
+        </p>
+        <p>
+        Note that not all cards support cubic environment mapping.
+        </p>
+        </li>
+        <li>
+        <p>
+        for skyboxes, the 6 textures are kept separate and used independently for each face of the skybox.
+        This is done because not all cards support 3D cubic maps and skyboxes do not need to use 3D
+        texture coordinates so it is simpler to render each face of the box with 2D coordinates, changing
+        texture between faces.
+        </p>
+        <p>
+        Skyboxes are created by calling SceneManager::setSkyBox.
+        </p>
+        </li>
+        </ul>
+        @note
+        Applies to both fixed-function and programmable pipeline.
+        @param
+        name The basic name of the texture e.g. brickwall.jpg, stonefloor.png. There must be 6 versions
+        of this texture with the suffixes _fr, _bk, _up, _dn, _lf, and _rt (before the extension) which
+        make up the 6 sides of the box. The textures must all be the same size and be powers of 2 in width & height.
+        If you can't make your texture names conform to this, use the alternative method of the same name which takes
+        an array of texture names instead.
+        @param
+        forUVW Set to true if you want a single 3D texture addressable with 3D texture coordinates rather than
+        6 separate textures. Useful for cubic environment mapping.
+        */
+        void setCubicTextureName( const String& name, bool forUVW = false );
+
+        /** Sets this texture layer to use a combination of 6 texture maps, each one relating to a face of a cube.
+        @remarks
+        Cubic textures are made up of 6 separate texture images. Each one of these is an orthoganal view of the
+        world with a FOV of 90 degrees and an aspect ratio of 1:1. You can generate these from 3D Studio by
+        rendering a scene to a reflection map of a transparent cube and saving the output files.
+        @par
+        Cubic maps can be used either for skyboxes (complete wrap-around skies, like space) or as environment
+        maps to simulate reflections. The system deals with these 2 scenarios in different ways:
+        <ol>
+        <li>
+        <p>
+        for cubic environment maps, the 6 textures are combined into a single 'cubic' texture map which
+        is then addressed using 3D texture coordinates. This is required because you don't know what
+        face of the box you're going to need to address when you render an object, and typically you
+        need to reflect more than one face on the one object, so all 6 textures are needed to be
+        'active' at once. Cubic environment maps are enabled by calling this method with the forUVW
+        parameter set to true, and then calling setEnvironmentMap(true).
+        </p>
+        <p>
+        Note that not all cards support cubic environment mapping.
+        </p>
+        </li>
+        <li>
+        <p>
+        for skyboxes, the 6 textures are kept separate and used independently for each face of the skybox.
+        This is done because not all cards support 3D cubic maps and skyboxes do not need to use 3D
+        texture coordinates so it is simpler to render each face of the box with 2D coordinates, changing
+        texture between faces.
+        </p>
+        <p>
+        Skyboxes are created by calling SceneManager::setSkyBox.
+        </p>
+        </li>
+        </ul>
+        @note
+        Applies to both fixed-function and programmable pipeline.
+        @param
+        name The basic name of the texture e.g. brickwall.jpg, stonefloor.png. There must be 6 versions
+        of this texture with the suffixes _fr, _bk, _up, _dn, _lf, and _rt (before the extension) which
+        make up the 6 sides of the box. The textures must all be the same size and be powers of 2 in width & height.
+        If you can't make your texture names conform to this, use the alternative method of the same name which takes
+        an array of texture names instead.
+        @param
+        forUVW Set to true if you want a single 3D texture addressable with 3D texture coordinates rather than
+        6 separate textures. Useful for cubic environment mapping.
+        */
+        void setCubicTextureName( const String* const names, bool forUVW = false );
+
+        /** Sets the names of the texture images for an animated texture.
+        @remarks
+        Animated textures are just a series of images making up the frames of the animation. All the images
+        must be the same size, and their names must have a frame number appended before the extension, e.g.
+        if you specify a name of "wall.jpg" with 3 frames, the image names must be "wall_0.jpg", "wall_1.jpg"
+        and "wall_2.jpg".
+        @par
+        You can change the active frame on a texture layer by calling the setCurrentFrame method.
+        @note
+        If you can't make your texture images conform to the naming standard layed out here, you
+        can call the alternative setAnimatedTextureName method which takes an array of names instead.
+        @note
+        Applies to both fixed-function and programmable pipeline.
+        @param
+        name The base name of the textures to use e.g. wall.jpg for frames wall_0.jpg, wall_1.jpg etc.
+        @param
+        numFrames The number of frames in the sequence.
+        @param
+        duration The length of time it takes to display the whole animation sequence, in seconds.
+        If 0, no automatic transition occurs.
+        */
+        void setAnimatedTextureName( const String& name, unsigned int numFrames, Real duration = 0 );
+
+        /** Sets the names of the texture images for an animated texture.
+        @remarks
+        This an alternative method to the one where you specify a single name and let the system derive
+        the names of each frame, incase your images can't conform to this naming standard.
+        @par
+        Animated textures are just a series of images making up the frames of the animation. All the images
+        must be the same size, and you must provide their names as an array in the first parameter.
+        You can change the active frame on a texture layer by calling the setCurrentFrame method.
+        @note
+        If you can make your texture images conform to a naming standard of basicName_frame.ext, you
+        can call the alternative setAnimatedTextureName method which just takes a base name instead.
+        @note
+        Applies to both fixed-function and programmable pipeline.
+        @param
+        names Pointer to array of names of the textures to use, in frame order.
+        @param
+        numFrames The number of frames in the sequence.
+        @param
+        duration The length of time it takes to display the whole animation sequence, in seconds.
+        If 0, no automatic transition occurs.
+        */
+        void setAnimatedTextureName( const String* const names, unsigned int numFrames, Real duration = 0 );
+
+        /** Returns the width and height of the texture in the given frame.
+        */
+        std::pair< uint, uint > getTextureDimensions( unsigned int frame = 0 ) const;
+
+        /** Changes the active frame in an animated or multi-image texture.
+        @remarks
+        An animated texture (or a cubic texture where the images are not combined for 3D use) is made up of
+        a number of frames. This method sets the active frame.
+        @note
+        Applies to both fixed-function and programmable pipeline.
+        */
+        void setCurrentFrame( unsigned int frameNumber );
+
+        /** Gets the active frame in an animated or multi-image texture layer.
+        @note
+        Applies to both fixed-function and programmable pipeline.
+        */
+        unsigned int getCurrentFrame(void) const;
+
+        /** Gets the name of the texture associated with a frame number.
+            Throws an exception if frameNumber exceeds the number of stored frames.
+        @note
+        Applies to both fixed-function and programmable pipeline.
+        */
+        const String& getFrameTextureName(unsigned int frameNumber) const;
+
+        /** Sets the name of the texture associated with a frame.
+        @param name The name of the texture
+        @param frameNumber The frame the texture name is to be placed in
+        @note
+        Throws an exception if frameNumber exceeds the number of stored frames.
+        Applies to both fixed-function and programmable pipeline.
+        */
+        void setFrameTextureName(const String& name, unsigned int frameNumber);
+
+        /** Add a Texture name to the end of the frame container.
+        @param name The name of the texture
+        @note
+        Applies to both fixed-function and programmable pipeline.
+        */
+        void addFrameTextureName(const String& name);
+        /** deletes a specific texture frame.  The texture used is not deleted but the
+            texture will no longer be used by the Texture Unit.  An exception is raised
+            if the frame number exceeds the number of actual frames.
+        @param frameNumber The frame number of the texture to be deleted.
+        @note
+        Applies to both fixed-function and programmable pipeline.
+        */
+        void deleteFrameTextureName(const size_t frameNumber);
+        /** Gets the number of frames for a texture.
+        @note
+        Applies to both fixed-function and programmable pipeline.
+        */
+        unsigned int getNumFrames(void) const;
+
+        /** Returns true if this texture unit is either a series of 6 2D textures, each
+            in it's own frame, or is a full 3D cube map. You can tell which by checking
+            getTextureType.
+        @note
+        Applies to both fixed-function and programmable pipeline.
+        */
+        bool isCubic(void) const;
+
+        /** Returns true if this texture layer uses a composite 3D cubic texture.
+        @note
+        Applies to both fixed-function and programmable pipeline.
+        */
+        bool is3D(void) const;
+
+        /** Returns the type of this texture.
+        @note
+        Applies to both fixed-function and programmable pipeline.
+        */
+        TextureType getTextureType(void) const;
+
+        /** Gets the index of the set of texture co-ords this layer uses.
+        @note
+        Applies to both fixed-function and programmable pipeline.
+        */
+        unsigned int getTextureCoordSet(void) const;
+
+        /** Sets the index of the set of texture co-ords this layer uses.
+        @note
+        Default is 0 for all layers. Only change this if you have provided multiple texture co-ords per
+        vertex.
+        @note
+        Applies to both fixed-function and programmable pipeline.
+        */
+        void setTextureCoordSet(unsigned int set);
+
+        /** Sets a matrix used to transform any texture coordinates on this layer.
+        @remarks
+        Texture coordinates can be modified on a texture layer to create effects like scrolling
+        textures. A texture transform can either be applied to a layer which takes the source coordinates
+        from a fixed set in the geometry, or to one which generates them dynamically (e.g. environment mapping).
+        @par
+        It's obviously a bit impractical to create scrolling effects by calling this method manually since you
+        would have to call it every framw with a slight alteration each time, which is tedious. Instead
+        you can use the ControllerManager class to create a Controller object which will manage the
+        effect over time for you. See the ControllerManager::createTextureScroller and it's sibling methods for details.<BR>
+        In addition, if you want to set the individual texture transformations rather than concatenating them
+        yourself, use setTextureScroll, setTextureScale and setTextureRotate.
+        @note
+        Has no effect in the programmable pipeline.
+        */
+        void setTextureTransform(const Matrix4& xform);
+
+        /** Gets the current texture transformation matrix.
+        @remarks
+        Causes a reclaculation of the matrix if any parameters have been changed via
+        setTextureScroll, setTextureScale and setTextureRotate.
+        @note
+        Has no effect in the programmable pipeline.
+        */
+        const Matrix4& getTextureTransform(void) const;
+
+        /** Sets the translation offset of the texture, ie scrolls the texture.
+        @remarks
+        This method sets the translation element of the texture transformation, and is easier to use than setTextureTransform if
+        you are combining translation, scaling and rotation in your texture transformation. Again if you want
+        to animate these values you need to use a Controller
+        @note
+        Has no effect in the programmable pipeline.
+        @param u The amount the texture should be moved horizontally (u direction).
+        @param v The amount the texture should be moved vertically (v direction).
+        @see
+        ControllerManager, Controller
+        */
+        void setTextureScroll(Real u, Real v);
+
+        /** As setTextureScroll, but sets only U value.
+        @note
+        Has no effect in the programmable pipeline.
+        */
+        void setTextureUScroll(Real value);
+        // get texture uscroll value
+        Real getTextureUScroll(void) const;
+
+        /** As setTextureScroll, but sets only V value.
+        @note
+        Has no effect in the programmable pipeline.
+        */
+        void setTextureVScroll(Real value);
+        // get texture vscroll value
+        Real getTextureVScroll(void) const;
+
+        /** As setTextureScale, but sets only U value.
+        @note
+        Has no effect in the programmable pipeline.
+        */
+        void setTextureUScale(Real value);
+        // get texture uscale value
+        Real getTextureUScale(void) const;
+
+        /** As setTextureScale, but sets only V value.
+        @note
+        Has no effect in the programmable pipeline.
+        */
+        void setTextureVScale(Real value);
+        // get texture vscale value
+        Real getTextureVScale(void) const;
+
+        /** Sets the scaling factor applied to texture coordinates.
+        @remarks
+        This method sets the scale element of the texture transformation, and is easier to use than
+        setTextureTransform if you are combining translation, scaling and rotation in your texture transformation. Again if you want
+        to animate these values you need to use a Controller (see ControllerManager and it's methods for
+        more information).
+        @note
+        Has no effect in the programmable pipeline.
+        @param
+        uScale The value by which the texture is to be scaled horizontally.
+        @param
+        vScale The value by which the texture is to be scaled vertically.
+        */
+        void setTextureScale(Real uScale, Real vScale);
+
+        /** Sets the anticlockwise rotation factor applied to texture coordinates.
+        @remarks
+        This sets a fixed rotation angle - if you wish to animate this, see the
+        ControllerManager::createTextureRotater method.
+        @note
+        Has no effect in the programmable pipeline.
+        @param
+        angle The angle of rotation (anticlockwise).
+        */
+        void setTextureRotate(const Radian& angle);
+#ifndef OGRE_FORCE_ANGLE_TYPES
+        inline void setTextureRotate(Real angle) {
+            setTextureRotate ( Degree(angle) );
+        }
+#endif//OGRE_FORCE_ANGLE_TYPES
+        // get texture rotation effects angle value
+        const Radian& getTextureRotate(void) const;
+
+        /** Gets the texture addressing mode for a given coordinate, 
+		 	i.e. what happens at uv values above 1.0.
+        @note
+        	The default is TAM_WRAP i.e. the texture repeats over values of 1.0.
+        */
+        const UVWAddressingMode& getTextureAddressingMode(void) const;
+
+        /** Sets the texture addressing mode, i.e. what happens at uv values above 1.0.
+        @note
+        The default is TAM_WRAP i.e. the texture repeats over values of 1.0.
+		@note This is a shortcut method which sets the addressing mode for all
+			coordinates at once; you can also call the more specific method
+			to set the addressing mode per coordinate.
+        @note
+        This applies for both the fixed-function and programmable pipelines.
+        */
+        void setTextureAddressingMode( TextureAddressingMode tam);
+
+        /** Sets the texture addressing mode, i.e. what happens at uv values above 1.0.
+        @note
+        The default is TAM_WRAP i.e. the texture repeats over values of 1.0.
+        @note
+        This applies for both the fixed-function and programmable pipelines.
+		*/
+        void setTextureAddressingMode( TextureAddressingMode u, 
+			TextureAddressingMode v, TextureAddressingMode w);
+
+        /** Sets the texture addressing mode, i.e. what happens at uv values above 1.0.
+        @note
+        The default is TAM_WRAP i.e. the texture repeats over values of 1.0.
+        @note
+        This applies for both the fixed-function and programmable pipelines.
+		*/
+        void setTextureAddressingMode( const UVWAddressingMode& uvw);
+
+        /** Sets the texture border colour.
+        @note
+            The default is ColourValue::Black, and this value only used when addressing mode
+            is TAM_BORDER.
+        @note
+            This applies for both the fixed-function and programmable pipelines.
+		*/
+        void setTextureBorderColour(const ColourValue& colour);
+
+        /** Sets the texture border colour.
+        @note
+            The default is ColourValue::Black, and this value only used when addressing mode
+            is TAM_BORDER.
+		*/
+        const ColourValue& getTextureBorderColour(void) const;
+
+		/** Setting advanced blending options.
+        @remarks
+        This is an extended version of the TextureUnitState::setColourOperation method which allows
+        extremely detailed control over the blending applied between this and earlier layers.
+        See the IMPORTANT note below about the issues between mulitpass and multitexturing that
+        using this method can create.
+        @par
+        Texture colour operations determine how the final colour of the surface appears when
+        rendered. Texture units are used to combine colour values from various sources (ie. the
+        diffuse colour of the surface from lighting calculations, combined with the colour of
+        the texture). This method allows you to specify the 'operation' to be used, ie. the
+        calculation such as adds or multiplies, and which values to use as arguments, such as
+        a fixed value or a value from a previous calculation.
+        @par
+        The defaults for each layer are:
+        <ul>
+        <li>op = LBX_MODULATE</li>
+        <li>source1 = LBS_TEXTURE</li>
+        <li>source2 = LBS_CURRENT</li>
+        </ul>
+        ie. each layer takes the colour results of the previous layer, and multiplies them
+        with the new texture being applied. Bear in mind that colours are RGB values from
+        0.0 - 1.0 so multiplying them together will result in values in the same range,
+        'tinted' by the multiply. Note however that a straight multiply normally has the
+        effect of darkening the textures - for this reason there are brightening operations
+        like LBO_MODULATE_X2. See the LayerBlendOperation and LayerBlendSource enumerated
+        types for full details.
+        @note
+        Because of the limitations on some underlying APIs (Direct3D included)
+        the LBS_TEXTURE argument can only be used as the first argument, not the second.
+        @par
+        The final 3 parameters are only required if you decide to pass values manually
+        into the operation, i.e. you want one or more of the inputs to the colour calculation
+        to come from a fixed value that you supply. Hence you only need to fill these in if
+        you supply LBS_MANUAL to the corresponding source, or use the LBX_BLEND_MANUAL
+        operation.
+        @warning
+        Ogre tries to use multitexturing hardware to blend texture layers
+        together. However, if it runs out of texturing units (e.g. 2 of a GeForce2, 4 on a
+        GeForce3) it has to fall back on multipass rendering, i.e. rendering the same object
+        multiple times with different textures. This is both less efficient and there is a smaller
+        range of blending operations which can be performed. For this reason, if you use this method
+        you MUST also call TextureUnitState::setColourOpMultipassFallback to specify which effect you
+        want to fall back on if sufficient hardware is not available.
+        @note
+        This has no effect in the programmable pipeline.
+        @param
+        If you wish to avoid having to do this, use the simpler TextureUnitState::setColourOperation method
+        which allows less flexible blending options but sets up the multipass fallback automatically,
+        since it only allows operations which have direct multipass equivalents.
+        @param
+        op The operation to be used, e.g. modulate (multiply), add, subtract
+        @param
+        source1 The source of the first colour to the operation e.g. texture colour
+        @param
+        source2 The source of the second colour to the operation e.g. current surface colour
+        @param
+        arg1 Manually supplied colour value (only required if source1 = LBS_MANUAL)
+        @param
+        arg2 Manually supplied colour value (only required if source2 = LBS_MANUAL)
+        @param
+        manualBlend Manually supplied 'blend' value - only required for operations
+        which require manual blend e.g. LBX_BLEND_MANUAL
+        */
+        void setColourOperationEx(
+            LayerBlendOperationEx op,
+            LayerBlendSource source1 = LBS_TEXTURE,
+            LayerBlendSource source2 = LBS_CURRENT,
+
+            const ColourValue& arg1 = ColourValue::White,
+            const ColourValue& arg2 = ColourValue::White,
+
+            Real manualBlend = 0.0);
+
+        /** Determines how this texture layer is combined with the one below it (or the diffuse colour of
+        the geometry if this is layer 0).
+        @remarks
+        This method is the simplest way to blend tetxure layers, because it requires only one parameter,
+        gives you the most common blending types, and automatically sets up 2 blending methods: one for
+        if single-pass multitexturing hardware is available, and another for if it is not and the blending must
+        be achieved through multiple rendering passes. It is, however, quite limited and does not expose
+        the more flexible multitexturing operations, simply because these can't be automatically supported in
+        multipass fallback mode. If want to use the fancier options, use TextureUnitState::setColourOperationEx,
+        but you'll either have to be sure that enough multitexturing units will be available, or you should
+        explicitly set a fallback using TextureUnitState::setColourOpMultipassFallback.
+        @note
+        The default method is LBO_MODULATE for all layers.
+        @note
+        This option has no effect in the programmable pipeline.
+        @param
+        op One of the LayerBlendOperation enumerated blending types.
+        */
+        void setColourOperation( const LayerBlendOperation op);
+
+        /** Sets the multipass fallback operation for this layer, if you used TextureUnitState::setColourOperationEx
+        and not enough multitexturing hardware is available.
+        @remarks
+        Because some effects exposed using TextureUnitState::setColourOperationEx are only supported under
+        multitexturing hardware, if the hardware is lacking the system must fallback on multipass rendering,
+        which unfortunately doesn't support as many effects. This method is for you to specify the fallback
+        operation which most suits you.
+        @par
+        You'll notice that the interface is the same as the Material::setSceneBlending method; this is
+        because multipass rendering IS effectively scene blending, since each layer is rendered on top
+        of the last using the same mechanism as making an object transparent, it's just being rendered
+        in the same place repeatedly to get the multitexture effect.
+        @par
+        If you use the simpler (and hence less flexible) TextureUnitState::setColourOperation method you
+        don't need to call this as the system sets up the fallback for you.
+        @note
+        This option has no effect in the programmable pipeline, because there is no multipass fallback
+        and multitexture blending is handled by the fragment shader.
+        */
+        void setColourOpMultipassFallback( const SceneBlendFactor sourceFactor, const SceneBlendFactor destFactor);
+
+        /** Get multitexturing colour blending mode.
+        */
+        const LayerBlendModeEx& getColourBlendMode(void) const;
+
+        /** Get multitexturing alpha blending mode.
+        */
+        const LayerBlendModeEx& getAlphaBlendMode(void) const;
+
+        /** Get the multipass fallback for colour blending operation source factor.
+        */
+        SceneBlendFactor getColourBlendFallbackSrc(void) const;
+
+        /** Get the multipass fallback for colour blending operation destination factor.
+        */
+        SceneBlendFactor getColourBlendFallbackDest(void) const;
+
+        /** Sets the alpha operation to be applied to this texture.
+        @remarks
+        This works in exactly the same way as setColourOperation, except
+        that the effect is applied to the level of alpha (i.e. transparency)
+        of the texture rather than its colour. When the alpha of a texel (a pixel
+        on a texture) is 1.0, it is opaque, wheras it is fully transparent if the
+        alpha is 0.0. Please refer to the setColourOperation method for more info.
+        @param
+        op The operation to be used, e.g. modulate (multiply), add, subtract
+        @param
+        source1 The source of the first alpha value to the operation e.g. texture alpha
+        @param
+        source2 The source of the second alpha value to the operation e.g. current surface alpha
+        @param
+        arg1 Manually supplied alpha value (only required if source1 = LBS_MANUAL)
+        @param
+        arg2 Manually supplied alpha value (only required if source2 = LBS_MANUAL)
+        @param
+        manualBlend Manually supplied 'blend' value - only required for operations
+        which require manual blend e.g. LBX_BLEND_MANUAL
+        @see
+        setColourOperation
+        @note
+        This option has no effect in the programmable pipeline.
+        */
+        void setAlphaOperation(LayerBlendOperationEx op,
+            LayerBlendSource source1 = LBS_TEXTURE,
+            LayerBlendSource source2 = LBS_CURRENT,
+            Real arg1 = 1.0,
+            Real arg2 = 1.0,
+            Real manualBlend = 0.0);
+
+        /** Generic method for setting up texture effects.
+        @remarks
+        Allows you to specify effects directly by using the TextureEffectType enumeration. The
+        arguments that go with it depend on the effect type. Only one effect of
+        each type can be applied to a texture layer.
+        @par
+        This method is used internally by Ogre but it is better generally for applications to use the
+        more intuitive specialised methods such as setEnvironmentMap and setScroll.
+        @note
+        This option has no effect in the programmable pipeline.
+        */
+        void addEffect(TextureEffect& effect);
+
+        /** Turns on/off texture coordinate effect that makes this layer an environment map.
+        @remarks
+        Environment maps make an object look reflective by using the object's vertex normals relative
+        to the camera view to generate texture coordinates.
+        @par
+        The vectors generated can either be used to address a single 2D texture which
+        is a 'fish-eye' lens view of a scene, or a 3D cubic environment map which requires 6 textures
+        for each side of the inside of a cube. The type depends on what texture you set up - if you use the
+        setTextureName method then a 2D fisheye lens texture is required, whereas if you used setCubicTextureName
+        then a cubic environemnt map will be used.
+        @par
+        This effect works best if the object has lots of gradually changing normals. The texture also
+        has to be designed for this effect - see the example spheremap.png included with the sample
+        application for a 2D environment map; a cubic map can be generated by rendering 6 views of a
+        scene to each of the cube faces with orthoganal views.
+        @note
+        Enabling this disables any other texture coordinate generation effects.
+        However it can be combined with texture coordinate modification functions, which then operate on the
+        generated coordinates rather than static model texture coordinates.
+        @param
+        enable True to enable, false to disable
+        @param
+        planar If set to true, instead of being based on normals the environment effect is based on
+        vertex positions. This is good for planar surfaces.
+        @note
+        This option has no effect in the programmable pipeline.
+        */
+        void setEnvironmentMap(bool enable, EnvMapType envMapType = ENV_CURVED);
+
+        /** Sets up an animated scroll for the texture layer.
+        @note
+        Useful for creating constant scrolling effects on a texture layer (for varying scrolls, see setTransformAnimation).
+        @param
+        uSpeed The number of horizontal loops per second (+ve=moving right, -ve = moving left)
+        @param
+        vSpeed The number of vertical loops per second (+ve=moving up, -ve= moving down)
+        @note
+        This option has no effect in the programmable pipeline.
+        */
+        void setScrollAnimation(Real uSpeed, Real vSpeed);
+
+        /** Sets up an animated texture rotation for this layer.
+        @note
+        Useful for constant rotations (for varying rotations, see setTransformAnimation).
+        @param
+        speed The number of complete anticlockwise revolutions per second (use -ve for clockwise)
+        @note
+        This option has no effect in the programmable pipeline.
+        */
+        void setRotateAnimation(Real speed);
+
+        /** Sets up a general time-relative texture modification effect.
+        @note
+        This can be called multiple times for different values of ttype, but only the latest effect
+        applies if called multiple time for the same ttype.
+        @param
+        ttype The type of transform, either translate (scroll), scale (stretch) or rotate (spin)
+        @param
+        waveType The shape of the wave, see WaveformType enum for details
+        @param
+        base The base value for the function (range of output = {base, base + amplitude})
+        @param
+        frequency The speed of the wave in cycles per second
+        @param
+        phase The offset of the start of the wave, e.g. 0.5 to start half-way through the wave
+        @param
+        amplitude Scales the output so that instead of lying within 0..1 it lies within 0..1*amplitude for exaggerated effects
+        @note
+        This option has no effect in the programmable pipeline.
+        */
+        void setTransformAnimation( const TextureTransformType ttype,
+            const WaveformType waveType, Real base = 0, Real frequency = 1, Real phase = 0, Real amplitude = 1 );
+
+
+        /** Enables or disables projective texturing on this texture unit.
+        @remarks
+            Projective texturing allows you to generate texture coordinates 
+            based on a Frustum, which gives the impression that a texture is
+            being projected onto the surface. Note that once you have called
+            this method, the texture unit continues to monitor the Frustum you 
+            passed in and the projection will change if you can alter it. It also
+            means that you must ensure that the Frustum object you pass a pointer
+            to remains in existence for as long as this TextureUnitState does.
+        @par
+            This effect cannot be combined with other texture generation effects, 
+            such as environment mapping. It also has no effect on passes which 
+            have a vertex program enabled - projective texturing has to be done
+            in the vertex program instead.
+        @param enabled Whether to enable / disable
+        @param projectionSettings The Frustum which will be used to derive the 
+            projection parameters.
+        */
+        void setProjectiveTexturing(bool enabled, const Frustum* projectionSettings = 0);
+
+        /** Removes all effects applied to this texture layer.
+        */
+        void removeAllEffects(void);
+
+        /** Removes a single effect applied to this texture layer.
+        @note
+        Because you can only have 1 effect of each type (e.g. 1 texture coordinate generation) applied
+        to a layer, only the effect type is required.
+        */
+        void removeEffect( const TextureEffectType type );
+
+        /** Determines if this texture layer is currently blank.
+        @note
+        This can happen if a texture fails to load or some other non-fatal error. Worth checking after
+        setting texture name.
+        */
+        bool isBlank(void) const;
+
+        /** Sets this texture layer to be blank.
+        */
+        void setBlank(void);
+
+        // get texture effects in a multimap paired array
+        const EffectMap& getEffects(void) const;
+        // get the animated-texture animation duration
+        Real getAnimationDuration(void) const;
+
+        /** Set the texture filtering for this unit, using the simplified interface.
+        @remarks
+            You also have the option of specifying the minification, magnification
+            and mip filter individually if you want more control over filtering
+            options. See the alternative setTextureFiltering methods for details.
+        @note
+        This option applies in both the fixed function and the programmable pipeline.
+        @param filterType The high-level filter type to use.
+        */
+        void setTextureFiltering(TextureFilterOptions filterType);
+        /** Set a single filtering option on this texture unit. 
+        @params ftype The filtering type to set
+        @params opts The filtering option to set
+        */
+        void setTextureFiltering(FilterType ftype, FilterOptions opts);
+        /** Set a the detailed filtering options on this texture unit. 
+        @params minFilter The filtering to use when reducing the size of the texture. 
+            Can be FO_POINT, FO_LINEAR or FO_ANISOTROPIC
+        @params magFilter The filtering to use when increasing the size of the texture
+            Can be FO_POINT, FO_LINEAR or FO_ANISOTROPIC
+        @params mipFilter The filtering to use between mip levels
+            Can be FO_NONE (turns off mipmapping), FO_POINT or FO_LINEAR (trilinear filtering)
+        */
+        void setTextureFiltering(FilterOptions minFilter, FilterOptions magFilter, FilterOptions mipFilter);
+        // get the texture filtering for the given type
+        FilterOptions getTextureFiltering(FilterType ftpye) const;
+
+        /** Sets the anisotropy level to be used for this texture level.
+        @par maxAniso The maximal anisotropy level, should be between 2 and the maximum supported by hardware (1 is the default, ie. no anisotrophy).
+        @note
+        This option applies in both the fixed function and the programmable pipeline.
+        */
+        void setTextureAnisotropy(unsigned int maxAniso);
+        // get this layer texture anisotropy level
+        unsigned int getTextureAnisotropy() const;
+
+        /// Gets the parent Pass object
+        Pass* getParent(void) const { return mParent; }
+
+		/** Internal method for loading this object as part of Material::load */
+		void _load(void);
+		/** Internal method for unloading this object as part of Material::unload */
+		void _unload(void);
+        /// Returns whether this unit has texture coordinate generation that depends on the camera
+        bool hasViewRelativeTextureCoordinateGeneration(void);
+
+        // Is this loaded?
+        bool isLoaded(void);
+        /** Tells the class that it needs recompilation. */
+        void _notifyNeedsRecompile(void);
+
+        /** Set the name of the Texture Unit State
+        @remarks
+            The name of the Texture Unit State is optional.  Its usefull in material scripts where a material could inherit
+            from another material and only want to modify a particalar Texture Unit State.
+        */
+        void setName(const String& name);
+        /// get the name of the Texture Unit State
+        const String& getName(void) const { return mName; }
+
+        /** Set the alias name used for texture frame names
+        @param name can be any sequence of characters and does not have to be unique           
+        */
+        void setTextureNameAlias(const String& name);
+        /** gets the Texture Name Alias of the Texture Unit.
+        */
+        const String& getTextureNameAlias(void) const { return mTextureNameAlias;}
+
+        /** Applies texture names to Texture Unit State with matching texture name aliases.
+            If no matching aliases are found then the TUS state does not change.
+        @remarks
+            Cubic, 1d, 2d, and 3d textures are determined from current state of the Texture Unit.
+            Assumes animated frames are sequentially numbered in the name.
+            If matching texture aliases are found then true is returned.
+
+        @param
+            aliasList is a map container of texture alias, texture name pairs
+        @param
+            apply set true to apply the texture aliases else just test to see if texture alias matches are found.
+        @return
+            True if matching texture aliases were found in the Texture Unit State.
+        */
+        bool applyTextureAliases(const AliasTextureNamePairList& aliasList, const bool apply = true);
+
+		/** Notify this object that its parent has changed */
+		void _notifyParent(Pass* parent);
+	
+protected:
+        // State
+        /// The current animation frame.
+        unsigned int mCurrentFrame;
+
+        /// Duration of animation in seconds
+        Real mAnimDuration;            
+        bool mCubic; // is this a series of 6 2D textures to make up a cube?
+		
+        TextureType mTextureType; 
+		int mTextureSrcMipmaps; // Request number of mipmaps
+
+        unsigned int mTextureCoordSetIndex;
+        UVWAddressingMode mAddressMode;
+        ColourValue mBorderColour;
+
+        LayerBlendModeEx colourBlendMode;
+        SceneBlendFactor colourBlendFallbackSrc;
+        SceneBlendFactor colourBlendFallbackDest;
+
+        LayerBlendModeEx alphaBlendMode;
+        bool mIsBlank;
+        bool mIsAlpha;
+
+        mutable bool mRecalcTexMatrix;
+        Real mUMod, mVMod;
+        Real mUScale, mVScale;
+        Radian mRotate;
+        mutable Matrix4 mTexModMatrix;
+
+        // Animation, will be set up as Controllers
+        Real mUScrollAnim, mVScrollAnim;
+        Real mRotateAnim;
+
+        /// Texture filtering - minification
+        FilterOptions mMinFilter;
+        /// Texture filtering - magnification
+        FilterOptions mMagFilter;
+        /// Texture filtering - mipmapping
+        FilterOptions mMipFilter;
+        ///Texture anisotropy
+        unsigned int mMaxAniso;
+
+        bool mIsDefaultAniso;
+        bool mIsDefaultFiltering;
+
+
+        //-----------------------------------------------------------------------------
+        // Complex members (those that can't be copied using memcpy) are at the end to 
+        // allow for fast copying of the basic members.
+        //
+        std::vector<String> mFrames;
+        String mName;               // optional name for the TUS
+        String mTextureNameAlias;       // optional alias for texture frames
+        EffectMap mEffects;
+        //-----------------------------------------------------------------------------
+
+        //-----------------------------------------------------------------------------
+        // Pointer members (those that can't be copied using memcpy), and MUST
+        // preserving even if assign from others
+        //
+        Pass* mParent;
+        Controller<Real>* mAnimController;
+        //-----------------------------------------------------------------------------
+
+
+        /** Internal method for calculating texture matrix.
+        */
+        void recalcTextureMatrix(void) const;
+
+        /** Internal method for creating animation controller.
+        */
+        void createAnimController(void);
+
+        /** Internal method for creating texture effect controller.
+        */
+        void createEffectController(TextureEffect& effect);
+
+#ifdef GAMETOOLS_ILLUMINATION_MODULE
+		bool isVT;
+	public:
+		void setVertexTexture(bool vertexTexture){isVT = vertexTexture;}
+		bool isVertexTexture(){return isVT;}
+#endif
+    };
+
+
+}
+
+#endif
Index: OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/OgreRenderable.h
===================================================================
--- OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/OgreRenderable.h	(revision 768)
+++ OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/OgreRenderable.h	(revision 768)
@@ -0,0 +1,283 @@
+/*
+-----------------------------------------------------------------------------
+This source file is part of OGRE
+    (Object-oriented Graphics Rendering Engine)
+For the latest info, see http://ogre.sourceforge.net/
+
+Copyright (c) 2000-2005 The OGRE Team
+Also see acknowledgements in Readme.html
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+#ifndef __Renderable_H__
+#define __Renderable_H__
+
+#include "OgrePrerequisites.h"
+#include "OgreCommon.h"
+
+#include "OgreRenderOperation.h"
+#include "OgreMatrix4.h"
+#include "OgreMaterial.h"
+#include "OgrePlane.h"
+#include "OgreGpuProgram.h"
+#include "OgreVector4.h"
+#include "OgreException.h"
+
+namespace Ogre {
+
+    /** Abstract class defining the interface all renderable objects must implement.
+        @remarks
+            This interface abstracts renderable discrete objects which will be queued in the render pipeline,
+            grouped by material. Classes implementing this interface must be based on a single material, a single
+            world matrix (or a collection of world matrices which are blended by weights), and must be 
+            renderable via a single render operation.
+        @par
+            Note that deciding whether to put these objects in the rendering pipeline is done from the more specific
+            classes e.g. entities. Only once it is decided that the specific class is to be rendered is the abstract version
+            created (could be more than one per visible object) and pushed onto the rendering queue.
+    */
+    class _OgreExport Renderable
+    {
+    public:
+		Renderable() : mPolygonModeOverrideable(true) 
+		{
+#ifdef GAMETOOLS_ILLUMINATION_MODULE
+			this->mRenderTechniqueGroup = 0;			
+#endif
+		}
+        /** Virtual destructor needed as class has virtual methods. */
+        virtual ~Renderable() { }
+        /** Retrieves a weak reference to the material this renderable object uses.
+        @remarks
+            Note that the Renderable also has the option to override the getTechnique method
+            to specify a particular Technique to use instead of the best one available.
+        */
+        virtual const MaterialPtr& getMaterial(void) const = 0;
+        /** Retrieves a pointer to the Material Technique this renderable object uses.
+        @remarks
+            This is to allow Renderables to use a chosen Technique if they wish, otherwise
+            they will use the best Technique available for the Material they are using.
+        */
+        virtual Technique* getTechnique(void) const { return getMaterial()->getBestTechnique(); }
+        /** Gets the render operation required to send this object to the frame buffer.
+        */
+        virtual void getRenderOperation(RenderOperation& op) = 0;
+        /** Gets the world transform matrix / matrices for this renderable object.
+            @remarks
+                If the object has any derived transforms, these are expected to be up to date as long as
+                all the SceneNode structures have been updated before this is called.
+            @par
+                This method will populate xform with 1 matrix if it does not use vertex blending. If it
+                does use vertex blending it will fill the passed in pointer with an array of matrices,
+                the length being the value returned from getNumWorldTransforms.
+        */
+        virtual void getWorldTransforms(Matrix4* xform) const = 0;
+        /** Gets the worldspace orientation of this renderable; this is used in order to
+            more efficiently update parameters to vertex & fragment programs, since inverting Quaterion
+            and Vector in order to derive object-space positions / directions for cameras and
+            lights is much more efficient than inverting a complete 4x4 matrix, and also 
+            eliminates problems introduced by scaling. */
+        virtual const Quaternion& getWorldOrientation(void) const = 0;
+        /** Gets the worldspace orientation of this renderable; this is used in order to
+            more efficiently update parameters to vertex & fragment programs, since inverting Quaterion
+            and Vector in order to derive object-space positions / directions for cameras and
+            lights is much more efficient than inverting a complete 4x4 matrix, and also 
+            eliminates problems introduced by scaling. */
+        virtual const Vector3& getWorldPosition(void) const = 0;
+
+        /** Returns the number of world transform matrices this renderable requires.
+        @remarks
+            When a renderable uses vertex blending, it uses multiple world matrices instead of a single
+            one. Each vertex sent to the pipeline can reference one or more matrices in this list
+            with given weights.
+            If a renderable does not use vertex blending this method returns 1, which is the default for 
+            simplicity.
+        */
+        virtual unsigned short getNumWorldTransforms(void) const { return 1; }
+
+        /** Returns whether or not to use an 'identity' projection.
+        @remarks
+            Usually Renderable objects will use a projection matrix as determined
+            by the active camera. However, if they want they can cancel this out
+            and use an identity projection, which effectively projects in 2D using
+            a {-1, 1} view space. Useful for overlay rendering. Normal renderables need
+            not override this.
+        */
+        virtual bool useIdentityProjection(void) const { return false; }
+
+        /** Returns whether or not to use an 'identity' projection.
+        @remarks
+            Usually Renderable objects will use a view matrix as determined
+            by the active camera. However, if they want they can cancel this out
+            and use an identity matrix, which means all geometry is assumed
+            to be relative to camera space already. Useful for overlay rendering. 
+            Normal renderables need not override this.
+        */
+        virtual bool useIdentityView(void) const { return false; }
+
+		/** Returns the camera-relative squared depth of this renderable.
+		@remarks
+			Used to sort transparent objects. Squared depth is used rather than
+			actual depth to avoid having to perform a square root on the result.
+		*/
+		virtual Real getSquaredViewDepth(const Camera* cam) const = 0;
+
+        /** Returns whether or not this Renderable wishes the hardware to normalise normals. */
+        virtual bool getNormaliseNormals(void) const { return false; }
+
+        /** Gets a list of lights, ordered relative to how close they are to this renderable.
+        @remarks
+            Directional lights, which have no position, will always be first on this list.
+        */
+        virtual const LightList& getLights(void) const = 0;
+
+        virtual const PlaneList& getClipPlanes() const { return msDummyPlaneList; };
+
+        /** Method which reports whether this renderable would normally cast a
+            shadow. 
+        @remarks
+            Subclasses should override this if they could have been used to 
+            generate a shadow.
+        */
+        virtual bool getCastsShadows(void) const { return false; }
+
+        /** Sets a custom parameter for this Renderable, which may be used to 
+            drive calculations for this specific Renderable, like GPU program parameters.
+        @remarks
+            Calling this method simply associates a numeric index with a 4-dimensional
+            value for this specific Renderable. This is most useful if the material
+            which this Renderable uses a vertex or fragment program, and has an 
+            ACT_CUSTOM parameter entry. This parameter entry can refer to the
+            index you specify as part of this call, thereby mapping a custom
+            parameter for this renderable to a program parameter.
+        @param index The index with which to associate the value. Note that this
+            does not have to start at 0, and can include gaps. It also has no direct
+            correlation with a GPU program parameter index - the mapping between the
+            two is performed by the ACT_CUSTOM entry, if that is used.
+        @param value The value to associate.
+        */
+        void setCustomParameter(size_t index, const Vector4& value) 
+        {
+            mCustomParameters[index] = value;
+        }
+
+        /** Gets the custom value associated with this Renderable at the given index.
+        @param
+            @see setCustomParaemter for full details.
+        */
+        const Vector4& getCustomParameter(size_t index) const
+        {
+            CustomParameterMap::const_iterator i = mCustomParameters.find(index);
+            if (i != mCustomParameters.end())
+            {
+                return i->second;
+            }
+            else
+            {
+                OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 
+                    "Parameter at the given index was not found.",
+                    "Renderable::getCustomParameter");
+            }
+        }
+
+        /** Update a custom GpuProgramParameters constant which is derived from 
+            information only this Renderable knows.
+        @remarks
+            This method allows a Renderable to map in a custom GPU program parameter
+            based on it's own data. This is represented by a GPU auto parameter
+            of ACT_CUSTOM, and to allow there to be more than one of these per
+            Renderable, the 'data' field on the auto parameter will identify
+            which parameter is being updated. The implementation of this method
+            must identify the parameter being updated, and call a 'setConstant' 
+            method on the passed in GpuProgramParameters object, using the details
+            provided in the incoming auto constant setting to identify the index
+            at which to set the parameter.
+        @par
+            You do not need to override this method if you're using the standard
+            sets of data associated with the Renderable as provided by setCustomParameter
+            and getCustomParameter. By default, the implementation will map from the
+            value indexed by the 'constantEntry.data' parameter to a value previously
+            set by setCustomParameter. But custom Renderables are free to override
+            this if they want, in any case.
+        @param constantEntry The auto constant entry referring to the parameter
+            being updated
+        @param params The parameters object which this method should call to 
+            set the updated parameters.
+        */
+        virtual void _updateCustomGpuParameter(
+            const GpuProgramParameters::AutoConstantEntry& constantEntry,
+            GpuProgramParameters* params) const
+        {
+            CustomParameterMap::const_iterator i = mCustomParameters.find(constantEntry.data);
+            if (i != mCustomParameters.end())
+            {
+                params->setConstant(constantEntry.index, i->second);
+            }
+        }
+
+		/** Sets whether this renderable's chosen detail level can be
+			overridden (downgraded) by the camera setting. 
+		@param override true means that a lower camera detail will override this
+			renderables detail level, false means it won't.
+		*/
+		virtual void setPolygonModeOverrideable(bool override)
+		{
+			mPolygonModeOverrideable = override;
+		}
+
+		/** Gets whether this renderable's chosen detail level can be
+			overridden (downgraded) by the camera setting. 
+		*/
+		virtual bool getPolygonModeOverrideable(void) const
+		{
+			return mPolygonModeOverrideable;
+		}
+
+
+
+    protected:
+        static const PlaneList msDummyPlaneList;
+        typedef std::map<size_t, Vector4> CustomParameterMap;
+        CustomParameterMap mCustomParameters;
+		bool mPolygonModeOverrideable;
+
+#ifdef GAMETOOLS_ILLUMINATION_MODULE
+	public:
+
+		virtual void setRenderTechniqueGroup(UserDefinedObject* renderTechniqueGroup)
+		{
+			this->mRenderTechniqueGroup = renderTechniqueGroup;
+		}
+
+		virtual UserDefinedObject* getRenderTechniqueGroup(void) const
+		{
+			return this->mRenderTechniqueGroup;
+		}		
+
+		virtual void setMaterialName(const String &name){}
+
+		protected:
+
+			UserDefinedObject* mRenderTechniqueGroup;
+#endif
+
+    };
+
+
+
+}
+
+#endif //__Renderable_H__
Index: OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/OgrePrerequisites.h
===================================================================
--- OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/OgrePrerequisites.h	(revision 768)
+++ OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/OgrePrerequisites.h	(revision 768)
@@ -0,0 +1,391 @@
+/*-------------------------------------------------------------------------
+This source file is a part of OGRE
+(Object-oriented Graphics Rendering Engine)
+
+For the latest info, see http://www.ogre3d.org/
+
+Copyright (c) 2000-2005 The OGRE Team
+Also see acknowledgements in Readme.html
+
+This library is free software; you can redistribute it and/or modify it
+under the terms of the GNU Lesser General Public License (LGPL) as
+published by the Free Software Foundation; either version 2.1 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this library; if not, write to the Free Software Foundation,
+Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA or go to
+http://www.gnu.org/copyleft/lesser.txt
+-------------------------------------------------------------------------*/
+#ifndef __Prerequisites_H__
+#define __Prerequisites_H__
+
+#define GAMETOOLS_ILLUMINATION_MODULE
+
+// undefine this to not require new angular units where applicable
+#define OGRE_FORCE_ANGLE_TYPES
+
+// Platform-specific stuff
+#include "OgrePlatform.h"
+
+#if OGRE_COMPILER == OGRE_COMPILER_MSVC
+// Turn off warnings generated by long std templates
+// This warns about truncation to 255 characters in debug/browse info
+#   pragma warning (disable : 4786)
+
+// Turn off warnings generated by long std templates
+// This warns about truncation to 255 characters in debug/browse info
+#   pragma warning (disable : 4503)
+
+// disable: "conversion from 'double' to 'float', possible loss of data
+#   pragma warning (disable : 4244)
+
+// disable: "truncation from 'double' to 'float'
+#   pragma warning (disable : 4305)
+
+// disable: "<type> needs to have dll-interface to be used by clients'
+// Happens on STL member variables which are not public therefore is ok
+#   pragma warning (disable : 4251)
+
+// disable: "non dll-interface class used as base for dll-interface class"
+// Happens when deriving from Singleton because bug in compiler ignores
+// template export
+#   pragma warning (disable : 4275)
+
+// disable: "C++ Exception Specification ignored"
+// This is because MSVC 6 did not implement all the C++ exception
+// specifications in the ANSI C++ draft.
+#   pragma warning( disable : 4290 )
+
+// disable: "no suitable definition provided for explicit template
+// instantiation request" Occurs in VC7 for no justifiable reason on all
+// #includes of Singleton
+#   pragma warning( disable: 4661)
+
+// disable: deprecation warnings when using CRT calls in VC8
+// These show up on all C runtime lib code in VC8, disable since they clutter
+// the warnings with things we may not be able to do anything about (e.g.
+// generated code from nvparse etc). I doubt very much that these calls
+// will ever be actually removed from VC anyway, it would break too much code.
+#	pragma warning( disable: 4996)
+#endif
+
+#if OGRE_COMPILER == OGRE_COMPILER_MSVC
+#   undef _DEFINE_DEPRECATED_HASH_CLASSES
+#   if OGRE_COMP_VER > 1300
+#       define _DEFINE_DEPRECATED_HASH_CLASSES 0
+#   else
+#      define _DEFINE_DEPRECATED_HASH_CLASSES 1
+#   endif
+#endif
+
+/* Include all the standard header *after* all the configuration
+   settings have been made.
+*/
+#include "OgreStdHeaders.h"
+
+
+#include "OgreMemoryManager.h"
+
+namespace Ogre {
+    // Define ogre version
+    #define OGRE_VERSION_MAJOR 1
+    #define OGRE_VERSION_MINOR 2
+    #define OGRE_VERSION_PATCH 0
+    #define OGRE_VERSION_NAME "Dagon"
+
+    #define OGRE_VERSION    ((OGRE_VERSION_MAJOR << 16) | (OGRE_VERSION_MINOR << 8) | OGRE_VERSION_PATCH)
+
+    // define the real number values to be used
+    // default to use 'float' unless precompiler option set
+    #if OGRE_DOUBLE_PRECISION == 1
+		/** Software floating point type.
+		@note Not valid as a pointer to GPU buffers / parameters
+		*/
+        typedef double Real;
+    #else
+		/** Software floating point type.
+		@note Not valid as a pointer to GPU buffers / parameters
+		*/
+        typedef float Real;
+    #endif
+
+    // define the Char type as either char or wchar_t
+    #if OGRE_WCHAR_T_STRINGS == 1
+    #   define OgreChar wchar_t
+    #	define _TO_CHAR( x ) L##x
+    #else
+    #   define OgreChar char
+    #	define _TO_CHAR( x ) x
+    #endif
+
+    #if OGRE_COMPILER == OGRE_COMPILER_GNUC && OGRE_COMP_VER >= 310 && !defined(STLPORT)
+    #   define HashMap ::__gnu_cxx::hash_map
+    #else
+    #   if OGRE_COMPILER == OGRE_COMPILER_MSVC
+    #       if OGRE_COMP_VER > 1300 && !defined(_STLP_MSVC)
+    #           define HashMap ::stdext::hash_map
+    #       else
+    #           define HashMap ::std::hash_map
+    #       endif
+    #   else
+    #       define HashMap ::std::hash_map
+    #   endif
+    #endif
+
+    /** In order to avoid finger-aches :)
+    */
+    typedef unsigned char uchar;
+    typedef unsigned short ushort;
+    typedef unsigned int uint;
+	typedef unsigned long ulong;
+
+    /// Useful macros
+    #define OGRE_DELETE(p)       { if(p) { delete (p);     (p)=NULL; } }
+    #define OGRE_DELETE_ARRAY(p) { if(p) { delete[] (p);   (p)=NULL; } }
+
+	#if OGRE_WCHAR_T_STRINGS
+		typedef std::wstring _StringBase;
+	#else
+		typedef std::string _StringBase;
+	#endif
+
+	typedef _StringBase String;
+
+	// Useful threading defines
+	#define OGRE_AUTO_MUTEX_NAME mutex
+	#if OGRE_THREAD_SUPPORT
+		#define OGRE_AUTO_MUTEX mutable boost::recursive_mutex OGRE_AUTO_MUTEX_NAME;
+		#define OGRE_LOCK_AUTO_MUTEX boost::recursive_mutex::scoped_lock ogreAutoMutexLock(OGRE_AUTO_MUTEX_NAME);
+		#define OGRE_MUTEX(name) mutable boost::recursive_mutex name;
+		#define OGRE_LOCK_MUTEX(name) boost::recursive_mutex::scoped_lock ogrenameLock(name);
+		// like OGRE_AUTO_MUTEX but mutex held by pointer
+		#define OGRE_AUTO_SHARED_MUTEX mutable boost::recursive_mutex *OGRE_AUTO_MUTEX_NAME;
+		#define OGRE_LOCK_AUTO_SHARED_MUTEX boost::recursive_mutex::scoped_lock ogreAutoMutexLock(*OGRE_AUTO_MUTEX_NAME);
+		#define OGRE_NEW_AUTO_SHARED_MUTEX OGRE_AUTO_MUTEX_NAME = new boost::recursive_mutex();
+		#define OGRE_DELETE_AUTO_SHARED_MUTEX delete OGRE_AUTO_MUTEX_NAME;
+		#define OGRE_COPY_AUTO_SHARED_MUTEX(from) OGRE_AUTO_MUTEX_NAME = from;
+	#else
+		#define OGRE_AUTO_MUTEX
+		#define OGRE_LOCK_AUTO_MUTEX
+		#define OGRE_MUTEX(name)
+		#define OGRE_LOCK_MUTEX(name)
+		#define OGRE_AUTO_SHARED_MUTEX
+		#define OGRE_LOCK_AUTO_SHARED_MUTEX
+		#define OGRE_NEW_AUTO_SHARED_MUTEX
+		#define OGRE_DELETE_AUTO_SHARED_MUTEX
+		#define OGRE_COPY_AUTO_SHARED_MUTEX(from)
+	#endif
+
+
+// Pre-declare classes
+// Allows use of pointers in header files without including individual .h
+// so decreases dependencies between files
+    class Angle;
+    class Animation;
+    class AnimationState;
+    class AnimationStateSet;
+    class AnimationTrack;
+    class Archive;
+    class ArchiveFactory;
+    class ArchiveManager;
+    class AutoParamDataSource;
+    class AxisAlignedBox;
+    class AxisAlignedBoxSceneQuery;
+    class Billboard;
+    class BillboardChain;
+    class BillboardSet;
+    class Bone;
+    class Camera;
+    class Codec;
+    class ColourValue;
+    class ConfigDialog;
+    template <typename T> class Controller;
+	template <typename T> class ControllerFunction;
+    class ControllerManager;
+    template <typename T> class ControllerValue;
+	class Cursor;
+	class Degree;
+    class DynLib;
+    class DynLibManager;
+    class EdgeData;
+    class EdgeListBuilder;
+    class Entity;
+    class ErrorDialog;
+	class EventDispatcher;
+	class EventProcessor;
+	class EventQueue;
+	class EventTarget;
+    class ExternalTextureSourceManager;
+    class Factory;
+    class Font;
+    class FontPtr;
+    class FontManager;
+    struct FrameEvent;
+    class FrameListener;
+    class Frustum;
+    class GpuProgram;
+    class GpuProgramPtr;
+    class GpuProgramManager;
+	class GpuProgramUsage;
+    class HardwareIndexBuffer;
+    class HardwareOcclusionQuery;
+    class HardwareVertexBuffer;
+	class HardwarePixelBuffer;
+    class HardwarePixelBufferSharedPtr;
+	class HighLevelGpuProgram;
+    class HighLevelGpuProgramPtr;
+	class HighLevelGpuProgramManager;
+	class HighLevelGpuProgramFactory;
+    class IndexData;
+	class InputEvent;
+    class InputReader;
+    class IntersectionSceneQuery;
+    class IntersectionSceneQueryListener;
+    class Image;
+	class KeyEvent;
+    class KeyFrame;
+	class KeyListener;
+	class KeyTarget;
+    class Light;
+    class Log;
+    class LogManager;
+	class ManualResourceLoader;
+	class ManualObject;
+    class Material;
+    class MaterialPtr;
+    class MaterialManager;
+    class Math;
+    class Matrix3;
+    class Matrix4;
+    class MemoryManager;
+    class Mesh;
+    class MeshPtr;
+    class MeshSerializer;
+    class MeshSerializerImpl;
+    class MeshManager;
+    class MovableObject;
+    class MovablePlane;
+	class MouseEvent;
+	class MouseListener;
+	class MouseMotionListener;
+	class MouseTarget;
+    class Node;
+	class NodeAnimationTrack;
+	class NodeKeyFrame;
+	class NumericAnimationTrack;
+	class NumericKeyFrame;
+    class Overlay;
+    class OverlayContainer;
+    class OverlayElement;
+    class OverlayElementFactory;
+    class OverlayManager;
+    class Particle;
+    class ParticleAffector;
+    class ParticleAffectorFactory;
+    class ParticleEmitter;
+    class ParticleEmitterFactory;
+    class ParticleSystem;
+    class ParticleSystemManager;
+    class ParticleSystemRenderer;
+    class ParticleSystemRendererFactory;
+    class ParticleVisualData;
+    class Pass;
+    class PatchMesh;
+    class PixelBox;
+    class PlatformManager;
+    class Plane;
+    class PlaneBoundedVolume;
+	class Pose;
+	class PositionTarget;
+    class ProgressiveMesh;
+    class Profile;
+	class Profiler;
+    class Quaternion;
+	class Radian;
+    class Ray;
+    class RaySceneQuery;
+    class RaySceneQueryListener;
+    class Renderable;
+    class RenderPriorityGroup;
+    class RenderQueue;
+    class RenderQueueGroup;
+	class RenderQueueInvocation;
+	class RenderQueueInvocationSequence;
+    class RenderQueueListener;
+    class RenderSystem;
+    class RenderSystemCapabilities;
+    class RenderTarget;
+    class RenderTargetListener;
+    class RenderTexture;
+	class MultiRenderTarget;
+    class RenderWindow;
+    class RenderOperation;
+    class Resource;
+	class ResourceBackgroundQueue;
+	class ResourceGroupManager;
+    class ResourceManager;
+    class RibbonTrail;
+	class Root;
+    class SceneManager;
+    class SceneManagerEnumerator;
+    class SceneNode;
+    class SceneQuery;
+    class SceneQueryListener;
+	class ScriptLoader;
+    class Serializer;
+    class ShadowCaster;
+    class ShadowRenderable;
+    class SimpleRenderable;
+    class SimpleSpline;
+    class Skeleton;
+    class SkeletonPtr;
+    class SkeletonInstance;
+    class SkeletonManager;
+    class Sphere;
+    class SphereSceneQuery;
+	class StaticGeometry;
+    class StringConverter;
+    class StringInterface;
+    class SubEntity;
+    class SubMesh;
+	class TagPoint;
+	class TargetManager;
+    class Technique;
+	class TempBlendedBufferInfo;
+	class ExternalTextureSource;
+    class TextureUnitState;
+    class Texture;
+    class TexturePtr;
+	class TextureFont;
+    class TextureManager;
+    class TransformKeyFrame;
+	class Timer;
+    class UserDefinedObject;
+    class Vector2;
+    class Vector3;
+    class Vector4;
+    class Viewport;
+	class VertexAnimationTrack;
+    class VertexBufferBinding;
+    class VertexData;
+    class VertexDeclaration;
+	class VertexMorphKeyFrame;
+    class WireBoundingBox;
+    class Compositor;
+    class CompositorManager;
+    class CompositorChain;
+    class CompositorInstance;
+    class CompositionTechnique;
+    class CompositionPass;
+    class CompositionTargetPass;
+}
+
+#endif // __OgrePrerequisites_H__
+
+
Index: OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/SpriteParticleRenderer.h
===================================================================
--- OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/SpriteParticleRenderer.h	(revision 768)
+++ OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/SpriteParticleRenderer.h	(revision 768)
@@ -0,0 +1,81 @@
+#pragma once
+
+#ifdef GAMETOOLS_ILLUMINATION_MODULE
+
+#include "OgreBillboardParticleRenderer.h"
+#include "SpriteSet.h"
+
+namespace Ogre {
+
+    /** Specialisation of ParticleSystemRenderer to render particles using 
+        a BillboardSet. 
+    @remarks
+        This renderer has a few more options than the standard particle system,
+        which will be passed to it automatically when the particle system itself
+        does not understand them.
+    */
+    class _OgreExport SpriteParticleRenderer : public ParticleSystemRenderer
+    {
+    protected:
+        /// The billboard set that's doing the rendering
+        SpriteSet* mSpriteSet;
+		int particleSorting;
+
+    public:
+        SpriteParticleRenderer();
+        ~SpriteParticleRenderer();
+
+		void setParticleSorting(int sorting, Camera* cam);
+
+        
+        /// @copydoc ParticleSystemRenderer::getType
+        const String& getType(void) const;
+        /// @copydoc ParticleSystemRenderer::_updateRenderQueue
+        void _updateRenderQueue(RenderQueue* queue, 
+            std::list<Particle*>& currentParticles, bool cullIndividually);
+        /// @copydoc ParticleSystemRenderer::_setMaterial
+        void _setMaterial(MaterialPtr& mat);
+        /// @copydoc ParticleSystemRenderer::_notifyCurrentCamera
+        void _notifyCurrentCamera(Camera* cam);
+        /// @copydoc ParticleSystemRenderer::_notifyParticleRotated
+		void _notifyParticleRotated(void){}
+        /// @copydoc ParticleSystemRenderer::_notifyParticleResized
+        void _notifyParticleResized(void);
+        /// @copydoc ParticleSystemRenderer::_notifyParticleQuota
+        void _notifyParticleQuota(size_t quota);
+        /// @copydoc ParticleSystemRenderer::_notifyAttached
+        void _notifyAttached(Node* parent, bool isTagPoint = false);
+        /// @copydoc ParticleSystemRenderer::_notifyDefaultDimensions
+        void _notifyDefaultDimensions(Real width, Real height);
+		/// @copydoc ParticleSystemRenderer::setRenderQueueGroup
+		void setRenderQueueGroup(uint8 queueID);
+		virtual void setKeepParticlesInLocalSpace(bool keepLocal)
+		{
+			mSpriteSet->setBillboardsInWorldSpace(!keepLocal);
+		}
+		virtual SortMode _getSortMode(void) const
+		{
+			 return mSpriteSet->_getSortMode();
+		}
+
+		/// Access SpriteSet in use
+		SpriteSet* getSpriteSet(void) const { return mSpriteSet; }
+
+    };
+
+    /** Factory class for BillboardParticleRenderer */
+    class _OgreExport SpriteParticleRendererFactory : public ParticleSystemRendererFactory
+    {
+    public:
+        /// @copydoc FactoryObj::getType
+        const String& getType() const;
+        /// @copydoc FactoryObj::createInstance
+        ParticleSystemRenderer* createInstance( const String& name );    
+        /// @copydoc FactoryObj::destroyInstance
+        void destroyInstance( ParticleSystemRenderer* inst);    
+    };
+
+}
+
+
+#endif
Index: OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/SpriteSet.h
===================================================================
--- OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/SpriteSet.h	(revision 768)
+++ OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/SpriteSet.h	(revision 768)
@@ -0,0 +1,68 @@
+
+#pragma once
+
+#ifdef GAMETOOLS_ILLUMINATION_MODULE
+
+#include "Ogre.h"
+
+namespace Ogre {
+
+
+	class _OgreExport SpriteSet : public BillboardSet
+	{
+
+	public:
+
+		SpriteSet( const String& name, unsigned int poolSize = 20, 
+			bool externalDataSource = false): BillboardSet(name, poolSize, externalDataSource) 
+		{}
+
+		virtual ~SpriteSet(){}
+
+		/** Begin injection of billboard data; applicable when 
+				constructing the BillboardSet for external data use.       
+		*/
+		void beginBillboards(void);
+		/// Define a billboard.
+		void injectBillboard(const Billboard& bb);
+
+		const String& getMovableType(void) const;
+
+		/** Overridden from MovableObject
+            @see
+                MovableObject
+        */
+        virtual void getRenderOperation(RenderOperation& op);
+	   
+	protected:
+		/** Private constructor (instances cannot be created directly).
+			*/
+		SpriteSet(){}
+
+		void genVertices(  const Billboard& bb);
+
+		
+		void _createBuffers(void);
+
+	    
+	};
+
+/** Factory object for creating BillboardSet instances */
+	class _OgreExport SpriteSetFactory : public MovableObjectFactory
+	{
+	protected:
+		MovableObject* createInstanceImpl( const String& name, const NameValuePairList* params);
+	public:
+		SpriteSetFactory() {}
+		~SpriteSetFactory() {}
+
+		static String FACTORY_TYPE_NAME;
+
+		const String& getType(void) const;
+		void destroyInstance( MovableObject* obj);  
+
+	};
+
+
+}
+#endif
Index: OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/OgreBillboardSet.h
===================================================================
--- OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/OgreBillboardSet.h	(revision 768)
+++ OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/OgreBillboardSet.h	(revision 768)
@@ -0,0 +1,838 @@
+/*
+-----------------------------------------------------------------------------
+This source file is part of OGRE
+    (Object-oriented Graphics Rendering Engine)
+For the latest info, see http://www.ogre3d.org/
+
+Copyright (c) 2000-2005 The OGRE Team
+Also see acknowledgements in Readme.html
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+#ifndef __BillboardSet_H__
+#define __BillboardSet_H__
+
+#include "OgrePrerequisites.h"
+
+#include "OgreMovableObject.h"
+#include "OgreRenderable.h"
+#include "OgreRadixSort.h"
+#include "OgreCommon.h"
+
+namespace Ogre {
+
+    /** Enum covering what exactly a billboard's position means (center,
+        top-left etc).
+        @see
+            BillboardSet::setBillboardOrigin
+    */
+    enum BillboardOrigin
+    {
+        BBO_TOP_LEFT,
+        BBO_TOP_CENTER,
+        BBO_TOP_RIGHT,
+        BBO_CENTER_LEFT,
+        BBO_CENTER,
+        BBO_CENTER_RIGHT,
+        BBO_BOTTOM_LEFT,
+        BBO_BOTTOM_CENTER,
+        BBO_BOTTOM_RIGHT
+    };
+    /** The rotation type of billboard. */
+    enum BillboardRotationType
+    {
+        /// Rotate the billboard's vertices around their facing direction
+        BBR_VERTEX,
+        /// Rotate the billboard's texture coordinates
+        BBR_TEXCOORD
+    };
+    /** The type of billboard to use. */
+    enum BillboardType
+    {
+        /// Standard point billboard (default), always faces the camera completely and is always upright
+        BBT_POINT,
+        /// Billboards are oriented around a shared direction vector (used as Y axis) and only rotate around this to face the camera
+        BBT_ORIENTED_COMMON,
+        /// Billboards are oriented around their own direction vector (their own Y axis) and only rotate around this to face the camera
+        BBT_ORIENTED_SELF,
+        /// Billboards are perpendicular to a shared direction vector (used as Z axis, the facing direction) and X, Y axis are determined by a shared up-vertor
+        BBT_PERPENDICULAR_COMMON,
+        /// Billboards are perpendicular to their own direction vector (their own Z axis, the facing direction) and X, Y axis are determined by a shared up-vertor
+        BBT_PERPENDICULAR_SELF
+    };
+
+    /** A collection of billboards (faces which are always facing the given direction) with the same (default) dimensions, material
+        and which are fairly close proximity to each other.
+        @remarks
+            Billboards are rectangles made up of 2 tris which are always facing the given direction. They are typically used
+            for special effects like particles. This class collects together a set of billboards with the same (default) dimensions,
+            material and relative locality in order to process them more efficiently. The entire set of billboards will be
+            culled as a whole (by default, although this can be changed if you want a large set of billboards
+            which are spread out and you want them culled individually), individual Billboards have locations which are relative to the set (which itself derives it's
+            position from the SceneNode it is attached to since it is a MoveableObject), they will be rendered as a single rendering operation,
+            and some calculations will be sped up by the fact that they use the same dimensions so some workings can be reused.
+        @par
+            A BillboardSet can be created using the SceneManager::createBillboardSet method. They can also be used internally
+            by other classes to create effects.
+		@note
+			Billboard bounds are only automatically calculated when you create them.
+			If you modify the position of a billboard you may need to call 
+			_updateBounds if the billboard moves outside the original bounds. 
+			Similarly, the bounds do no shrink when you remove a billboard, 
+			if you want them to call _updateBounds, but note this requires a
+			potentially expensive examination of every billboard in the set.
+    */
+    class _OgreExport BillboardSet : public MovableObject, public Renderable
+    {
+    protected:
+        /** Private constructor (instances cannot be created directly).
+        */
+        BillboardSet();
+
+        /// Bounds of all billboards in this set
+        AxisAlignedBox mAABB;
+		/// Bounding radius
+		Real mBoundingRadius;
+
+        /// Origin of each billboard
+        BillboardOrigin mOriginType;
+        /// Rotation type of each billboard
+        BillboardRotationType mRotationType;
+
+        /// Default width of each billboard
+        Real mDefaultWidth;
+        /// Default height of each billboard
+        Real mDefaultHeight;
+
+        /// Name of the material to use
+        String mMaterialName;
+        /// Pointer to the material to use
+        MaterialPtr mpMaterial;
+
+        /// True if no billboards in this set have been resized - greater efficiency.
+        bool mAllDefaultSize;
+
+        /// Flag indicating whether to autoextend pool
+        bool mAutoExtendPool;
+
+		/// Flag indicating whether the billboards has to be sorted
+		bool mSortingEnabled;
+
+        // Use 'true' billboard to cam position facing, rather than camera direcion
+        bool mAccurateFacing;
+
+        bool mAllDefaultRotation;
+        bool mWorldSpace;
+
+        typedef std::list<Billboard*> ActiveBillboardList;
+        typedef std::list<Billboard*> FreeBillboardList;
+        typedef std::vector<Billboard*> BillboardPool;
+
+        /** Active billboard list.
+            @remarks
+                This is a linked list of pointers to billboards in the billboard pool.
+            @par
+                This allows very fast instertions and deletions from anywhere in the list to activate / deactivate billboards
+                (required for particle systems etc)    as well as resuse of Billboard instances in the pool
+                without construction & destruction which avoids memory thrashing.
+        */
+        ActiveBillboardList mActiveBillboards;
+
+        /** Free billboard queue.
+            @remarks
+                This contains a list of the billboards free for use as new instances
+                as required by the set. Billboard instances are preconstructed up to the estimated size in the
+                mBillboardPool vector and are referenced on this deque at startup. As they get used this deque
+                reduces, as they get released back to to the set they get added back to the deque.
+        */
+        FreeBillboardList mFreeBillboards;
+
+        /** Pool of billboard instances for use and reuse in the active billboard list.
+            @remarks
+                This vector will be preallocated with the estimated size of the set,and will extend as required.
+        */
+        BillboardPool mBillboardPool;
+
+        /// The vertex position data for all billboards in this set.
+        VertexData* mVertexData;
+        /// Shortcut to main buffer (positions, colours, texture coords)
+        HardwareVertexBufferSharedPtr mMainBuf;
+        /// Locked pointer to buffer
+        float* mLockPtr;
+        /// Boundary offsets based on origin and camera orientation
+        /// Vector3 vLeftOff, vRightOff, vTopOff, vBottomOff;
+        /// Final vertex offsets, used where sizes all default to save calcs
+        Vector3 mVOffset[4];
+        /// Current camera
+        Camera* mCurrentCamera;
+        // Parametric offsets of origin
+        Real mLeftOff, mRightOff, mTopOff, mBottomOff;
+        // Camera axes in billboard space
+        Vector3 mCamX, mCamY;
+        // Camera direction in billboard space
+        Vector3 mCamDir;
+        // Camera orientation in billboard space
+        Quaternion mCamQ;
+        // Camera position in billboard space
+        Vector3 mCamPos;
+
+        /// The vertex index data for all billboards in this set (1 set only)
+        //unsigned short* mpIndexes;
+        IndexData* mIndexData;
+
+        /// Flag indicating whether each billboard should be culled separately (default: false)
+        bool mCullIndividual;
+
+        typedef std::vector< Ogre::FloatRect > TextureCoordSets;
+        TextureCoordSets mTextureCoords;
+
+        /// The type of billboard to render
+        BillboardType mBillboardType;
+
+        /// Common direction for billboards of type BBT_ORIENTED_COMMON and BBT_PERPENDICULAR_COMMON
+        Vector3 mCommonDirection;
+        /// Common up-vector for billboards of type BBT_PERPENDICULAR_SELF and BBT_PERPENDICULAR_COMMON
+        Vector3 mCommonUpVector;
+
+        /// Internal method for culling individual billboards
+        inline bool billboardVisible(Camera* cam, const Billboard& bill);
+
+        // Number of visible billboards (will be == getNumBillboards if mCullIndividual == false)
+        unsigned short mNumVisibleBillboards;
+
+        /// Internal method for increasing pool size
+        virtual void increasePool(unsigned int size);
+
+
+        //-----------------------------------------------------------------------
+        // The internal methods which follow are here to allow maximum flexibility as to 
+        //  when various components of the calculation are done. Depending on whether the
+        //  billboards are of fixed size and whether they are point or oriented type will
+        //  determine how much calculation has to be done per-billboard. NOT a one-size fits all approach.
+        //-----------------------------------------------------------------------
+        /** Internal method for generating billboard corners. 
+        @remarks
+            Optional parameter pBill is only present for type BBT_ORIENTED_SELF and BBT_PERPENDICULAR_SELF
+        */
+        void genBillboardAxes(Vector3* pX, Vector3 *pY, const Billboard* pBill = 0);
+
+        /** Internal method, generates parametric offsets based on origin.
+        */
+        void getParametricOffsets(Real& left, Real& right, Real& top, Real& bottom);
+
+        /** Internal method for generating vertex data. 
+        @param offsets Array of 4 Vector3 offsets
+        @param bb Referenceto billboard
+        */
+        void genVertices(const Vector3* const offsets, const Billboard& pBillboard);
+
+        /** Internal method generates vertex offsets.
+        @remarks
+            Takes in parametric offsets as generated from getParametericOffsets, width and height values
+            and billboard x and y axes as generated from genBillboardAxes. 
+            Fills output array of 4 vectors with vector offsets
+            from origin for left-top, right-top, left-bottom, right-bottom corners.
+        */
+        void genVertOffsets(Real inleft, Real inright, Real intop, Real inbottom,
+            Real width, Real height,
+            const Vector3& x, const Vector3& y, Vector3* pDestVec);
+
+
+        /** Sort by direction functor */
+        struct SortByDirectionFunctor
+        {
+            /// Direction to sort in
+            Vector3 sortDir;
+
+            SortByDirectionFunctor(const Vector3& dir);
+            float operator()(Billboard* bill) const;
+        };
+
+        /** Sort by distance functor */
+        struct SortByDistanceFunctor
+        {
+            /// Position to sort in
+            Vector3 sortPos;
+
+            SortByDistanceFunctor(const Vector3& pos);
+            float operator()(Billboard* bill) const;
+        };
+
+		static RadixSort<ActiveBillboardList, Billboard*, float> mRadixSorter;
+
+		/// Use point rendering?
+		bool mPointRendering;
+
+
+#ifdef GAMETOOLS_ILLUMINATION_MODULE
+	protected:
+#else
+    private:
+#endif
+        /// Flag indicating whether the HW buffers have been created.
+        bool mBuffersCreated;
+        /// The number of billboard in the pool.
+        unsigned int mPoolSize;
+        /// Is external billboard data in use?
+        bool mExternalData;
+
+        /** Internal method creates vertex and index buffers.
+        */
+        void _createBuffers(void);
+        /** Internal method destroys vertex and index buffers.
+        */
+        void _destroyBuffers(void);
+
+    public:
+
+        /** Usual constructor - this is called by the SceneManager.
+            @param
+                name The name to give the billboard set (must be unique)
+            @param
+                poolSize The initial size of the billboard pool. Estimate of the number of billboards
+                which will be required, and pass it using this parameter. The set will
+                preallocate this number to avoid memory fragmentation. The default behaviour
+                once this pool has run out is to double it.
+            @param
+                externalDataSource If true, the source of data for drawing the 
+                billboards will not be the internal billboard list, but external 
+                data. When driving thebillboard from external data, you must call
+                _notifyCurrentCamera to reorient the billboards, setPoolSize to set
+                the maximum billboards you want to use, beginBillboards to 
+                start the update, and injectBillboard per billboard, 
+                followed by endBillboards.
+            @see
+                BillboardSet::setAutoextend
+        */
+        BillboardSet( const String& name, unsigned int poolSize = 20, 
+            bool externalDataSource = false);
+
+        virtual ~BillboardSet();
+
+        /** Creates a new billboard and adds it to this set.
+            @remarks
+                Behaviour once the billboard pool has been exhausted depends on the
+                BillboardSet::setAutoextendPool option.
+            @param
+                position The position of the new billboard realtive to the certer of the set
+            @param
+                colour Optional base colour of the billboard.
+            @returns
+                On success, a pointer to a newly created Billboard is
+                returned.
+            @par
+                On failiure (i.e. no more space and can't autoextend),
+                <b>NULL</b> is returned.
+            @see
+                BillboardSet::setAutoextend
+        */
+        Billboard* createBillboard(
+            const Vector3& position,
+            const ColourValue& colour = ColourValue::White );
+
+        /** Creates a new billboard and adds it to this set.
+            @remarks
+                Behaviour once the billboard pool has been exhausted depends on the
+                BillboardSet::setAutoextendPool option.
+            @param
+                x
+            @param
+                y
+            @param
+                z The position of the new billboard realtive to the certer of the set
+            @param
+                colour Optional base colour of the billboard.
+            @returns
+                On success, a pointer to a newly created Billboard is
+                returned.
+            @par
+                On failiure (i.e. no more space and can't autoextend),
+                <b>NULL</b> is returned.
+            @see
+                BillboardSet::setAutoextend
+        */
+        Billboard* createBillboard(
+            Real x, Real y, Real z,
+            const ColourValue& colour = ColourValue::White );
+
+        /** Returns the number of active billboards which currently make up this set.
+        */
+        virtual int getNumBillboards(void) const;
+
+        /** Tells the set whether to allow automatic extension of the pool of billboards.
+            @remarks
+                A BillboardSet stores a pool of pre-constructed billboards which are used as needed when
+                a new billboard is requested. This allows applications to create / remove billboards efficiently
+                without incurring construction / destruction costs (a must for sets with lots of billboards like
+                particle effects). This method allows you to configure the behaviour when a new billboard is requested
+                but the billboard pool has been exhausted.
+            @par
+                The default behaviour is to allow the pool to extend (typically this allocates double the current
+                pool of billboards when the pool is expended), equivalent to calling this method with
+                autoExtend = true. If you set the parameter to false however, any attempt to create a new billboard
+                when the pool has expired will simply fail silently, returning a null pointer.
+            @param autoextend true to double the pool every time it runs out, false to fail silently.
+        */
+        virtual void setAutoextend(bool autoextend);
+
+        /** Returns true if the billboard pool automatically extends.
+            @see
+                BillboardSet::setAutoextend
+        */
+        virtual bool getAutoextend(void) const;
+
+		/** Enables sorting for this BillboardSet. (default: off)
+			@param sortenable true to sort the billboards according to their distance to the camera
+		*/
+		virtual void setSortingEnabled(bool sortenable);
+
+		/** Returns true if sorting of billboards is enabled based on their distance from the camera
+		    @see
+				BillboardSet::setSortingEnabled
+		*/
+		virtual bool getSortingEnabled(void) const;
+
+        /** Adjusts the size of the pool of billboards available in this set.
+            @remarks
+                See the BillboardSet::setAutoextend method for full details of the billboard pool. This method adjusts
+                the preallocated size of the pool. If you try to reduce the size of the pool, the set has the option
+                of ignoring you if too many billboards are already in use. Bear in mind that calling this method will
+                incur significant construction / destruction calls so should be avoided in time-critical code. The same
+                goes for auto-extension, try to avoid it by estimating the pool size correctly up-front.
+            @param
+                size The new size for the pool.
+        */
+        virtual void setPoolSize(unsigned int size);
+
+        /** Returns the current size of the billboard pool.
+            @returns
+                The current size of the billboard pool.
+            @see
+                BillboardSet::setAutoextend
+        */
+        virtual unsigned int getPoolSize(void) const;
+
+
+        /** Empties this set of all billboards.
+        */
+        virtual void clear();
+
+        /** Returns a pointer to the billboard at the supplied index.
+            @note
+                This method requires linear time since the billboard list is a linked list.
+            @param
+                index The index of the billboard that is requested.
+            @returns
+                On success, a valid pointer to the requested billboard is
+                returned.
+            @par
+                On failiure, <b>NULL</b> is returned.
+        */
+        virtual Billboard* getBillboard(unsigned int index) const;
+
+        /** Removes the billboard at the supplied index.
+            @note
+                This method requires linear time since the billboard list is a linked list.
+        */
+        virtual void removeBillboard(unsigned int index);
+
+        /** Removes a billboard from the set.
+            @note
+                This version is more efficient than removing by index.
+        */
+        virtual void removeBillboard(Billboard* pBill);
+
+        /** Sets the point which acts as the origin point for all billboards in this set.
+            @remarks
+                This setting controls the fine tuning of where a billboard appears in relation to it's
+                position. It could be that a billboard's position represents it's center (e.g. for fireballs),
+                it could mean the center of the bottom edge (e.g. a tree which is positioned on the ground),
+                the top-left corner (e.g. a cursor).
+            @par
+                The default setting is BBO_CENTER.
+            @param
+                origin A member of the BillboardOrigin enum specifying the origin for all the billboards in this set.
+        */
+        virtual void setBillboardOrigin(BillboardOrigin origin);
+
+        /** Gets the point which acts as the origin point for all billboards in this set.
+            @returns
+                A member of the BillboardOrigin enum specifying the origin for all the billboards in this set.
+        */
+        virtual BillboardOrigin getBillboardOrigin(void) const;
+
+        /** Sets billboard rotation type.
+            @remarks
+                This setting controls the billboard rotation type, you can deciding rotate the billboard's vertices
+                around their facing direction or rotate the billboard's texture coordinates.
+            @par
+                The default settings is BBR_TEXCOORD.
+            @param
+                rotationType A member of the BillboardRotationType enum specifying the rotation type for all the billboards in this set.
+        */
+        virtual void setBillboardRotationType(BillboardRotationType rotationType);
+
+        /** Sets billboard rotation type.
+            @returns
+                A member of the BillboardRotationType enum specifying the rotation type for all the billboards in this set.
+        */
+        virtual BillboardRotationType getBillboardRotationType(void) const;
+
+        /** Sets the default dimensions of the billboards in this set.
+            @remarks
+                All billboards in a set are created with these default dimensions. The set will render most efficiently if
+                all the billboards in the set are the default size. It is possible to alter the size of individual
+                billboards at the expense of extra calculation. See the Billboard class for more info.
+            @param width
+                The new default width for the billboards in this set.
+            @param height
+                The new default height for the billboards in this set.
+        */
+        virtual void setDefaultDimensions(Real width, Real height);
+
+        /** See setDefaultDimensions - this sets 1 component individually. */
+        virtual void setDefaultWidth(Real width);
+        /** See setDefaultDimensions - this gets 1 component individually. */
+        virtual Real getDefaultWidth(void) const;
+        /** See setDefaultDimensions - this sets 1 component individually. */
+        virtual void setDefaultHeight(Real height);
+        /** See setDefaultDimensions - this gets 1 component individually. */
+        virtual Real getDefaultHeight(void) const;
+
+        /** Sets the name of the material to be used for this billboard set.
+            @param
+                name The new name of the material to use for this set.
+        */
+        virtual void setMaterialName(const String& name);
+
+        /** Sets the name of the material to be used for this billboard set.
+            @returns The name of the material that is used for this set.
+        */
+        virtual const String& getMaterialName(void) const;
+
+        /** Overridden from MovableObject
+            @see
+                MovableObject
+        */
+        virtual void _notifyCurrentCamera(Camera* cam);
+
+        /** Begin injection of billboard data; applicable when 
+            constructing the BillboardSet for external data use.
+        */
+        void beginBillboards(void);
+        /** Define a billboard. */
+        void injectBillboard(const Billboard& bb);
+        /** Finish defining billboards. */
+        void endBillboards(void);
+		/** Set the bounds of the BillboardSet.
+		@remarks
+			You may need to call this if you're injecting billboards manually, 
+			and you're relying on the BillboardSet to determine culling.
+		*/
+		void setBounds(const AxisAlignedBox& box, Real radius);
+
+
+        /** Overridden from MovableObject
+            @see
+                MovableObject
+        */
+        virtual const AxisAlignedBox& getBoundingBox(void) const;
+
+        /** Overridden from MovableObject
+            @see
+                MovableObject
+        */
+        virtual Real getBoundingRadius(void) const;
+        /** Overridden from MovableObject
+            @see
+                MovableObject
+        */
+        virtual void _updateRenderQueue(RenderQueue* queue);
+
+        /** Overridden from MovableObject
+            @see
+                MovableObject
+        */
+        virtual const MaterialPtr& getMaterial(void) const;
+
+        /** Overridden from MovableObject
+            @see
+                MovableObject
+        */
+        virtual void getRenderOperation(RenderOperation& op);
+
+        /** Overridden from MovableObject
+            @see
+                MovableObject
+        */
+        virtual void getWorldTransforms(Matrix4* xform) const;
+
+        /** @copydoc Renderable::getWorldOrientation */
+        const Quaternion& getWorldOrientation(void) const;
+        /** @copydoc Renderable::getWorldPosition */
+        const Vector3& getWorldPosition(void) const;
+        /** Internal callback used by Billboards to notify their parent that they have been resized.
+        */
+        virtual void _notifyBillboardResized(void);
+
+        /** Internal callback used by Billboards to notify their parent that they have been rotated..
+        */
+        virtual void _notifyBillboardRotated(void);
+
+        /** Returns whether or not billbards in this are tested individually for culling. */
+        virtual bool getCullIndividually(void) const;
+        /** Sets whether culling tests billboards in this individually as well as in a group.
+        @remarks
+            Billboard sets are always culled as a whole group, based on a bounding box which 
+            encloses all billboards in the set. For fairly localised sets, this is enough. However, you
+            can optionally tell the set to also cull individual billboards in the set, i.e. to test
+            each individual billboard before rendering. The default is not to do this.
+        @par
+            This is useful when you have a large, fairly distributed set of billboards, like maybe 
+            trees on a landscape. You probably still want to group them into more than one
+            set (maybe one set per section of landscape), which will be culled coarsely, but you also
+            want to cull the billboards individually because they are spread out. Whilst you could have
+            lots of single-tree sets which are culled separately, this would be inefficient to render
+            because each tree would be issued as it's own rendering operation.
+        @par
+            By calling this method with a parameter of true, you can have large billboard sets which 
+            are spaced out and so get the benefit of batch rendering and coarse culling, but also have
+            fine-grained culling so unnecessary rendering is avoided.
+        @param cullIndividual If true, each billboard is tested before being sent to the pipeline as well 
+            as the whole set having to pass the coarse group bounding test.
+        */
+        virtual void setCullIndividually(bool cullIndividual);
+
+        /** Sets the type of billboard to render.
+        @remarks
+            The default sort of billboard (BBT_POINT), always has both x and y axes parallel to 
+            the camera's local axes. This is fine for 'point' style billboards (e.g. flares,
+            smoke, anything which is symmetrical about a central point) but does not look good for
+            billboards which have an orientation (e.g. an elongated raindrop). In this case, the
+            oriented billboards are more suitable (BBT_ORIENTED_COMMON or BBT_ORIENTED_SELF) since
+            they retain an independant Y axis and only the X axis is generated, perpendicular to both
+            the local Y and the camera Z.
+        @par
+            In some case you might want the billboard has fixed Z axis and doesn't need to face to
+            camera (e.g. an aureola around the player and parallel to the ground). You can use
+            BBT_PERPENDICULAR_SELF which the billboard plane perpendicular to the billboard own
+            direction. Or BBT_PERPENDICULAR_COMMON which the billboard plane perpendicular to the
+            common direction.
+        @note
+            BBT_PERPENDICULAR_SELF and BBT_PERPENDICULAR_COMMON can't guarantee counterclockwise, you might
+            use double-side material (<b>cull_hardware node</b>) to ensure no billboard are culled.
+        @param bbt The type of billboard to render
+        */
+        virtual void setBillboardType(BillboardType bbt);
+
+        /** Returns the billboard type in use. */
+        virtual BillboardType getBillboardType(void) const;
+
+        /** Use this to specify the common direction given to billboards of type BBT_ORIENTED_COMMON or BBT_PERPENDICULAR_COMMON.
+        @remarks
+            Use BBT_ORIENTED_COMMON when you want oriented billboards but you know they are always going to 
+            be oriented the same way (e.g. rain in calm weather). It is faster for the system to calculate
+            the billboard vertices if they have a common direction.
+        @par
+            The common direction also use in BBT_PERPENDICULAR_COMMON, in this case the common direction
+            treat as Z axis, and an additional common up-vector was use to determine billboard X and Y
+            axis.
+            @see setCommonUpVector
+        @param vec The direction for all billboards.
+        @note
+            The direction are use as is, never normalised in internal, user are supposed to normalise it himself.
+        */
+        virtual void setCommonDirection(const Vector3& vec);
+
+        /** Gets the common direction for all billboards (BBT_ORIENTED_COMMON) */
+        virtual const Vector3& getCommonDirection(void) const;
+
+        /** Use this to specify the common up-vector given to billboards of type BBT_PERPENDICULAR_SELF or BBT_PERPENDICULAR_COMMON.
+        @remarks
+            Use BBT_PERPENDICULAR_SELF or BBT_PERPENDICULAR_COMMON when you want oriented billboards
+            perpendicular to specify direction vector (or, Z axis), and doesn't face to camera.
+            In this case, we need an additional up-vector to determine the billboard X and Y axis.
+            The generated billboard plane and X-axis guarantee perpendicular to specify direction.
+            @see setCommonDirection
+        @par
+            The specify direction is billboard own direction when billboard type is BBT_PERPENDICULAR_SELF,
+            and it's shared common direction when billboard type is BBT_PERPENDICULAR_COMMON.
+        @param vec The up-vector for all billboards.
+        @note
+            The up-vector are use as is, never normalised in internal, user are supposed to normalise it himself.
+        */
+        virtual void setCommonUpVector(const Vector3& vec);
+
+        /** Gets the common up-vector for all billboards (BBT_PERPENDICULAR_SELF and BBT_PERPENDICULAR_COMMON) */
+        virtual const Vector3& getCommonUpVector(void) const;
+        
+        /** Sets whether or not billboards should use an 'accurate' facing model
+            based on the vector from each billboard to the camera, rather than 
+            an optimised version using just the camera direction.
+        @remarks
+            By default, the axes for all billboards are calulated using the 
+            camera's view direction, not the vector from the camera position to
+            the billboard. The former is faster, and most of the time the difference
+            is not noticeable. However for some purposes (e.g. very large, static
+            billboards) the changing billboard orientation when rotating the camera
+            can be off putting, therefore you can enable this option to use a
+            more expensive, but more accurate version.
+        @param acc True to use the slower but more accurate model. Default is false.
+        */
+        virtual void setUseAccurateFacing(bool acc) { mAccurateFacing = acc; }
+        /** Gets whether or not billboards use an 'accurate' facing model
+            based on the vector from each billboard to the camera, rather than 
+            an optimised version using just the camera direction.
+        */
+        virtual bool getUseAccurateFacing(void) const { return mAccurateFacing; }
+
+        /** Overridden from MovableObject */
+        virtual const String& getMovableType(void) const;
+
+        /** Overridden, see Renderable */
+        Real getSquaredViewDepth(const Camera* cam) const;
+
+        /** Update the bounds of the billboardset */
+        virtual void _updateBounds(void);
+        /** @copydoc Renderable::getLights */
+        const LightList& getLights(void) const;
+
+        /** Sort the billboard set. Only called when enabled via setSortingEnabled */
+		virtual void _sortBillboards( Camera* cam);
+
+        /** Gets the sort mode of this billboard set */
+        virtual SortMode _getSortMode(void) const;
+
+        /** Sets whether billboards should be treated as being in world space. 
+        @remarks
+            This is most useful when you are driving the billboard set from 
+            an external data source.
+        */
+        virtual void setBillboardsInWorldSpace(bool ws) { mWorldSpace = ws; }
+
+        /** BillboardSet can use custom texture coordinates for various billboards. 
+            This is useful for selecting one of many particle images out of a tiled 
+            texture sheet, or doing flipbook animation within a single texture.
+          @par
+            The generic functionality is setTextureCoords(), which will copy the 
+            texture coordinate rects you supply into internal storage for the 
+            billboard set. If your texture sheet is a square grid, you can also 
+            use setTextureStacksAndSlices() for more convenience, which will construct 
+            the set of texture coordinates for you.
+          @par
+            When a Billboard is created, it can be assigned a texture coordinate 
+            set from within the sets you specify (that set can also be re-specified 
+            later). When drawn, the billboard will use those texture coordinates, 
+            rather than the full 0-1 range.
+          @par
+          @param coords is a vector of texture coordinates (in UV space) to choose 
+            from for each billboard created in the set.
+          @param numCoords is how many such coordinate rectangles there are to 
+            choose from.
+          @remarks
+            Set 'coords' to 0 and/or 'numCoords' to 0 to reset the texture coord 
+            rects to the initial set of a single rectangle spanning 0 through 1 in 
+            both U and V (i e, the entire texture).
+          @see
+            BillboardSet::setTextureStacksAndSlices()
+            Billboard::setTexcoordIndex()
+          */
+        virtual void setTextureCoords( Ogre::FloatRect const * coords, uint16 numCoords );
+
+        /** setTextureStacksAndSlices() will generate texture coordinate rects as if the 
+            texture for the billboard set contained 'stacks' rows of 'slices' 
+            images each, all equal size. Thus, if the texture size is 512x512 
+            and 'stacks' is 4 and 'slices' is 8, each sub-rectangle of the texture 
+            would be 128 texels tall and 64 texels wide.
+          @remarks
+            This function is short-hand for creating a regular set and calling 
+            setTextureCoords() yourself. The numbering used for Billboard::setTexcoordIndex() 
+            counts first across, then down, so top-left is 0, the one to the right 
+            of that is 1, and the lower-right is stacks*slices-1.
+          @see
+            BillboardSet::setTextureCoords()
+          */
+        virtual void setTextureStacksAndSlices( uchar stacks, uchar slices );
+
+        /** getTextureCoords() returns the current texture coordinate rects in 
+            effect. By default, there is only one texture coordinate rect in the 
+            set, spanning the entire texture from 0 through 1 in each direction.
+          @see
+            BillboardSet::setTextureCoords()
+          */
+        virtual Ogre::FloatRect const * getTextureCoords( uint16 * oNumCoords );
+
+		/** Set whether or not the BillboardSet will use point rendering
+			rather than manually generated quads.
+		@remarks
+			By default a billboardset is rendered by generating geometry for a
+			textured quad in memory, taking into account the size and 
+			orientation settings, and uploading it to the video card. 
+			The alternative is to use hardware point rendering, which means that
+			only one position needs to be sent per billboard rather than 4 and
+			the hardware sorts out how this is rendered based on the render
+			state.
+		@par
+			Using point rendering is faster than generating quads manually, but
+			is more restrictive. The following restrictions apply:
+			\li Only the BBT_POINT type is supported
+			\li Size and appearance of each billboard is controlled by the 
+				material (Pass::setPointSize, Pass::setPointSizeAttenuation, 
+				Pass::setPointSpritesEnabled)
+			\li Per-billboard size is not supported (stems from the above)
+			\li Per-billboard rotation is not supported, this can only be 
+				controlled through texture unit rotation
+			\li Only BBO_CENTER origin is supported
+			\li Per-billboard texture coordinates are not supported
+
+		@par
+			You will almost certainly want to enable in your material pass
+			both point attenuation and point sprites if you use this option. 
+		@param enabled True to enable point rendering, false otherwise
+		*/
+		virtual void setPointRenderingEnabled(bool enabled);
+
+		/** Returns whether point rendering is enabled. */
+		virtual bool isPointRenderingEnabled(void) const
+		{ return mPointRendering; }
+		
+		/// Override to return specific type flag
+		uint32 getTypeFlags(void) const;
+
+    };
+
+	/** Factory object for creating BillboardSet instances */
+	class _OgreExport BillboardSetFactory : public MovableObjectFactory
+	{
+	protected:
+		MovableObject* createInstanceImpl( const String& name, const NameValuePairList* params);
+	public:
+		BillboardSetFactory() {}
+		~BillboardSetFactory() {}
+
+		static String FACTORY_TYPE_NAME;
+
+		const String& getType(void) const;
+		void destroyInstance( MovableObject* obj);  
+
+	};
+
+
+}
+
+
+#endif
Index: OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/OgrePass.h
===================================================================
--- OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/OgrePass.h	(revision 768)
+++ OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/OgrePass.h	(revision 768)
@@ -0,0 +1,1196 @@
+/*
+-----------------------------------------------------------------------------
+This source file is part of OGRE
+(Object-oriented Graphics Rendering Engine)
+For the latest info, see http://ogre.sourceforge.net/
+
+Copyright (c) 2000-2005 The OGRE Team
+Also see acknowledgements in Readme.html
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+#ifndef __Pass_H__
+#define __Pass_H__
+
+#include "OgrePrerequisites.h"
+#include "OgreGpuProgram.h"
+#include "OgreColourValue.h"
+#include "OgreBlendMode.h"
+#include "OgreCommon.h"
+#include "OgreLight.h"
+
+namespace Ogre {
+    /** Class defining a single pass of a Technique (of a Material), ie
+        a single rendering call. 
+    @remarks
+        Rendering can be repeated with many passes for more complex effects.
+        Each pass is either a fixed-function pass (meaning it does not use
+        a vertex or fragment program) or a programmable pass (meaning it does
+        use either a vertex and fragment program, or both). 
+    @par
+        Programmable passes are complex to define, because they require custom
+        programs and you have to set all constant inputs to the programs (like
+        the position of lights, any base material colours you wish to use etc), but
+        they do give you much total flexibility over the algorithms used to render your
+        pass, and you can create some effects which are impossible with a fixed-function pass.
+        On the other hand, you can define a fixed-function pass in very little time, and
+        you can use a range of fixed-function effects like environment mapping very
+        easily, plus your pass will be more likely to be compatible with older hardware.
+        There are pros and cons to both, just remember that if you use a programmable
+        pass to create some great effects, allow more time for definition and testing.
+    */
+    class _OgreExport Pass
+    {
+    protected:
+        Technique* mParent;
+        unsigned short mIndex; // pass index
+        String mName; // optional name for the pass
+        uint32 mHash; // pass hash
+        //-------------------------------------------------------------------------
+        // Colour properties, only applicable in fixed-function passes
+        ColourValue mAmbient;
+        ColourValue mDiffuse;
+        ColourValue mSpecular;    
+        ColourValue mEmissive;
+        Real mShininess;
+        TrackVertexColourType mTracking;
+        //-------------------------------------------------------------------------
+
+        //-------------------------------------------------------------------------
+        // Blending factors
+        SceneBlendFactor mSourceBlendFactor;    
+        SceneBlendFactor mDestBlendFactor;
+        //-------------------------------------------------------------------------
+
+        //-------------------------------------------------------------------------    
+        // Depth buffer settings
+        bool mDepthCheck;
+        bool mDepthWrite;
+        CompareFunction mDepthFunc;
+        ushort mDepthBias;
+
+        // Colour buffer settings
+        bool mColourWrite;
+		
+		// Alpha reject settings
+		CompareFunction mAlphaRejectFunc;
+		unsigned char mAlphaRejectVal;
+        //-------------------------------------------------------------------------    
+
+        //-------------------------------------------------------------------------
+        // Culling mode
+        CullingMode mCullMode;
+        ManualCullingMode mManualCullMode;
+        //-------------------------------------------------------------------------
+
+        /// Lighting enabled?
+        bool mLightingEnabled;
+        /// Max simultaneous lights
+        unsigned short mMaxSimultaneousLights;
+		/// Run this pass once per light?
+		bool mIteratePerLight;
+        // Should it only be run for a certain light type?
+        bool mRunOnlyForOneLightType;
+        Light::LightTypes mOnlyLightType;
+
+        /// Shading options
+        ShadeOptions mShadeOptions;
+		/// Polygon mode
+		PolygonMode mPolygonMode;
+
+        //-------------------------------------------------------------------------    
+        // Fog
+        bool mFogOverride;
+        FogMode mFogMode;
+        ColourValue mFogColour;
+        Real mFogStart;
+        Real mFogEnd;
+        Real mFogDensity;
+        //-------------------------------------------------------------------------    
+
+        /// Storage of texture unit states 
+        typedef std::vector<TextureUnitState*> TextureUnitStates;
+        TextureUnitStates mTextureUnitStates;    
+
+		// Vertex program details
+		GpuProgramUsage *mVertexProgramUsage;
+        // Vertex program details
+        GpuProgramUsage *mShadowCasterVertexProgramUsage;
+        // Vertex program details
+        GpuProgramUsage *mShadowReceiverVertexProgramUsage;
+		// Fragment program details
+		GpuProgramUsage *mFragmentProgramUsage;
+		// Fragment program details
+		GpuProgramUsage *mShadowReceiverFragmentProgramUsage;
+        // Is this pass queued for deletion?
+        bool mQueuedForDeletion;
+        // number of pass iterations to perform
+        size_t mPassIterationCount;
+		// point size, applies when not using per-vertex point size
+		Real mPointSize;
+		Real mPointMinSize;
+		Real mPointMaxSize;
+		bool mPointSpritesEnabled;
+		bool mPointAttenuationEnabled;
+		// constant, linear, quadratic coeffs
+		Real mPointAttenuationCoeffs[3];
+	public:
+		typedef std::set<Pass*> PassSet;
+    protected:
+		/// List of Passes whose hashes need recalculating
+		static PassSet msDirtyHashList;
+        /// The place where passes go to die
+        static PassSet msPassGraveyard;
+    public:
+        /// Default constructor
+		Pass(Technique* parent, unsigned short index);
+        /// Copy constructor
+        Pass(Technique* parent, unsigned short index, const Pass& oth );
+        /// Operator = overload
+        Pass& operator=(const Pass& oth);
+        ~Pass();
+
+        /// Returns true if this pass is programmable ie includes either a vertex or fragment program.
+        bool isProgrammable(void) const { return mVertexProgramUsage || mFragmentProgramUsage; }
+        /// Returns true if this pass uses a programmable vertex pipeline
+        bool hasVertexProgram(void) const { return mVertexProgramUsage != NULL; }
+        /// Returns true if this pass uses a programmable fragment pipeline
+        bool hasFragmentProgram(void) const { return mFragmentProgramUsage != NULL; }
+        /// Returns true if this pass uses a shadow caster vertex program
+        bool hasShadowCasterVertexProgram(void) const { return mShadowCasterVertexProgramUsage != NULL; }
+        /// Returns true if this pass uses a shadow receiver vertex program
+        bool hasShadowReceiverVertexProgram(void) const { return mShadowReceiverVertexProgramUsage != NULL; }
+        /// Returns true if this pass uses a shadow receiver fragment program
+        bool hasShadowReceiverFragmentProgram(void) const { return mShadowReceiverFragmentProgramUsage != NULL; }
+
+
+        /// Gets the index of this Pass in the parent Technique
+        unsigned short getIndex(void) const { return mIndex; }
+        /* Set the name of the pass
+        @remarks
+        The name of the pass is optional.  Its usefull in material scripts where a material could inherit
+        from another material and only want to modify a particalar pass.
+        */
+        void setName(const String& name);
+        /// get the name of the pass
+        const String& getName(void) const { return mName; }
+
+        /** Sets the ambient colour reflectance properties of this pass.
+        @remarks
+        The base colour of a pass is determined by how much red, green and blue light is reflects
+        (provided texture layer #0 has a blend mode other than LBO_REPLACE). This property determines how
+        much ambient light (directionless global light) is reflected. The default is full white, meaning
+        objects are completely globally illuminated. Reduce this if you want to see diffuse or specular light
+        effects, or change the blend of colours to make the object have a base colour other than white.
+        @note
+        This setting has no effect if dynamic lighting is disabled (see Pass::setLightingEnabled),
+        or if this is a programmable pass.
+        */
+        void setAmbient(Real red, Real green, Real blue);
+
+        /** Sets the ambient colour reflectance properties of this pass.
+        @remarks
+        The base colour of a pass is determined by how much red, green and blue light is reflects
+        (provided texture layer #0 has a blend mode other than LBO_REPLACE). This property determines how
+        much ambient light (directionless global light) is reflected. The default is full white, meaning
+        objects are completely globally illuminated. Reduce this if you want to see diffuse or specular light
+        effects, or change the blend of colours to make the object have a base colour other than white.
+        @note
+        This setting has no effect if dynamic lighting is disabled (see Pass::setLightingEnabled),
+        or if this is a programmable pass.
+        */
+
+        void setAmbient(const ColourValue& ambient);
+
+        /** Sets the diffuse colour reflectance properties of this pass.
+        @remarks
+        The base colour of a pass is determined by how much red, green and blue light is reflects
+        (provided texture layer #0 has a blend mode other than LBO_REPLACE). This property determines how
+        much diffuse light (light from instances of the Light class in the scene) is reflected. The default
+        is full white, meaning objects reflect the maximum white light they can from Light objects.
+        @note
+        This setting has no effect if dynamic lighting is disabled (see Pass::setLightingEnabled),
+        or if this is a programmable pass.
+        */
+        void setDiffuse(Real red, Real green, Real blue, Real alpha);
+
+        /** Sets the diffuse colour reflectance properties of this pass.
+        @remarks
+        The base colour of a pass is determined by how much red, green and blue light is reflects
+        (provided texture layer #0 has a blend mode other than LBO_REPLACE). This property determines how
+        much diffuse light (light from instances of the Light class in the scene) is reflected. The default
+        is full white, meaning objects reflect the maximum white light they can from Light objects.
+        @note
+        This setting has no effect if dynamic lighting is disabled (see Pass::setLightingEnabled),
+        or if this is a programmable pass.
+        */
+        void setDiffuse(const ColourValue& diffuse);
+
+        /** Sets the specular colour reflectance properties of this pass.
+        @remarks
+        The base colour of a pass is determined by how much red, green and blue light is reflects
+        (provided texture layer #0 has a blend mode other than LBO_REPLACE). This property determines how
+        much specular light (highlights from instances of the Light class in the scene) is reflected.
+        The default is to reflect no specular light.
+        @note
+        The size of the specular highlights is determined by the separate 'shininess' property.
+        @note
+        This setting has no effect if dynamic lighting is disabled (see Pass::setLightingEnabled),
+        or if this is a programmable pass.
+        */
+        void setSpecular(Real red, Real green, Real blue, Real alpha);
+
+        /** Sets the specular colour reflectance properties of this pass.
+        @remarks
+        The base colour of a pass is determined by how much red, green and blue light is reflects
+        (provided texture layer #0 has a blend mode other than LBO_REPLACE). This property determines how
+        much specular light (highlights from instances of the Light class in the scene) is reflected.
+        The default is to reflect no specular light.
+        @note
+        The size of the specular highlights is determined by the separate 'shininess' property.
+        @note
+        This setting has no effect if dynamic lighting is disabled (see Pass::setLightingEnabled),
+        or if this is a programmable pass.
+        */
+        void setSpecular(const ColourValue& specular);
+
+        /** Sets the shininess of the pass, affecting the size of specular highlights.
+        @note
+        This setting has no effect if dynamic lighting is disabled (see Pass::setLightingEnabled),
+        or if this is a programmable pass.
+        */
+        void setShininess(Real val);
+
+        /** Sets the amount of self-illumination an object has.
+        @remarks
+        If an object is self-illuminating, it does not need external sources to light it, ambient or
+        otherwise. It's like the object has it's own personal ambient light. This property is rarely useful since
+        you can already specify per-pass ambient light, but is here for completeness.
+        @note
+        This setting has no effect if dynamic lighting is disabled (see Pass::setLightingEnabled),
+        or if this is a programmable pass.
+        */
+        void setSelfIllumination(Real red, Real green, Real blue);
+
+        /** Sets the amount of self-illumination an object has.
+        @remarks
+        If an object is self-illuminating, it does not need external sources to light it, ambient or
+        otherwise. It's like the object has it's own personal ambient light. This property is rarely useful since
+        you can already specify per-pass ambient light, but is here for completeness.
+        @note
+        This setting has no effect if dynamic lighting is disabled (see Pass::setLightingEnabled),
+        or if this is a programmable pass.
+        */
+        void setSelfIllumination(const ColourValue& selfIllum);
+
+        /** Sets which material properties follow the vertex colour
+         */
+        void setVertexColourTracking(TrackVertexColourType tracking);
+
+        /** Gets the point size of the pass.
+		@remarks
+			This property determines what point size is used to render a point 
+			list.
+        */
+        Real getPointSize(void) const;
+
+		/** Sets the point size of this pass.
+		@remarks
+			This setting allows you to change the size of points when rendering 
+			a point list, or a list of point sprites. The interpretation of this 
+			command depends on the Pass::setPointSizeAttenuation option - if it 
+			is off (the default), the point size is in screen pixels, if it is on, 
+			it expressed as normalised screen coordinates (1.0 is the height of 
+			the screen) when the point is at the origin.
+		@note 
+			Some drivers have an upper limit on the size of points they support 
+			- this can even vary between APIs on the same card! Don't rely on 
+			point sizes that cause the point sprites to get very large on screen, 
+			since they may get clamped on some cards. Upper sizes can range from 
+			64 to 256 pixels.
+		*/
+		void setPointSize(Real ps);
+		
+		/** Sets whether or not rendering points using OT_POINT_LIST will 
+			render point sprites (textured quads) or plain points (dots).
+		@param enabled True enables point sprites, false returns to normal
+			point rendering.
+		*/	
+		void setPointSpritesEnabled(bool enabled);
+
+		/** Returns whether point sprites are enabled when rendering a 
+			point list.
+		*/
+		bool getPointSpritesEnabled(void) const;
+
+		/** Sets how points are attenuated with distance.
+		@remarks
+			When performing point rendering or point sprite rendering,
+			point size can be attenuated with distance. The equation for
+			doing this is attenuation = 1 / (constant + linear * dist + quadratic * d^2).
+		@par
+			For example, to disable distance attenuation (constant screensize) 
+			you would set constant to 1, and linear and quadratic to 0. A
+			standard perspective attenuation would be 0, 1, 0 respectively.
+		@note 
+			The resulting size is clamped to the minimum and maximum point
+			size.
+		@param enabled Whether point attenuation is enabled
+		@param constant, linear, quadratic Parameters to the attentuation 
+			function defined above
+		*/
+		void setPointAttenuation(bool enabled, 
+			Real constant = 0.0f, Real linear = 1.0f, Real quadratic = 0.0f);
+
+		/** Returns whether points are attenuated with distance. */
+		bool isPointAttenuationEnabled(void) const;
+
+		/** Returns the constant coefficient of point attenuation. */
+		Real getPointAttenuationConstant(void) const;
+		/** Returns the linear coefficient of point attenuation. */
+		Real getPointAttenuationLinear(void) const;
+		/** Returns the quadratic coefficient of point attenuation. */
+		Real getPointAttenuationQuadratic(void) const;
+
+		/** Set the minimum point size, when point attenuation is in use. */
+		void setPointMinSize(Real min);
+		/** Get the minimum point size, when point attenuation is in use. */
+		Real getPointMinSize(void) const;
+		/** Set the maximum point size, when point attenuation is in use. 
+		@remarks Setting this to 0 indicates the max size supported by the card.
+		*/
+		void setPointMaxSize(Real max);
+		/** Get the maximum point size, when point attenuation is in use. 
+		@remarks 0 indicates the max size supported by the card.
+		*/
+		Real getPointMaxSize(void) const;
+
+		/** Gets the ambient colour reflectance of the pass.
+        */
+        const ColourValue& getAmbient(void) const;
+
+        /** Gets the diffuse colour reflectance of the pass.
+        */
+        const ColourValue& getDiffuse(void) const;
+
+        /** Gets the specular colour reflectance of the pass.
+        */
+        const ColourValue& getSpecular(void) const;
+
+        /** Gets the self illumination colour of the pass.
+        */
+        const ColourValue& getSelfIllumination(void) const;
+
+        /** Gets the 'shininess' property of the pass (affects specular highlights).
+        */
+        Real getShininess(void) const;
+        
+        /** Gets which material properties follow the vertex colour
+         */
+        TrackVertexColourType getVertexColourTracking(void) const;
+
+        /** Inserts a new TextureUnitState object into the Pass.
+        @remarks
+        This unit is is added on top of all previous units. 
+        */
+        TextureUnitState* createTextureUnitState(void);
+        /** Inserts a new TextureUnitState object into the Pass.
+        @remarks
+        This unit is is added on top of all previous units. 
+        @param
+        name The basic name of the texture e.g. brickwall.jpg, stonefloor.png
+        @param
+        texCoordSet The index of the texture coordinate set to use.
+        @note 
+        Applies to both fixed-function and programmable passes.
+        */
+        TextureUnitState* createTextureUnitState( const String& textureName, unsigned short texCoordSet = 0);
+		/** Adds the passed in TextureUnitState, to the existing Pass. 
+        @param
+        state The Texture Unit State to be attached to this pass.  It must not be attached to another pass.
+        @note
+            Throws an exception if the TextureUnitState is attached to another Pass.*/
+		void addTextureUnitState(TextureUnitState* state);
+        /** Retrieves a pointer to a texture unit state so it may be modified.
+        */
+        TextureUnitState* getTextureUnitState(unsigned short index);
+        /** Retrieves the Texture Unit State matching name.
+            Returns 0 if name match is not found.
+        */
+        TextureUnitState* getTextureUnitState(const String& name);
+		/** Retrieves a const pointer to a texture unit state.
+		*/
+		const TextureUnitState* getTextureUnitState(unsigned short index) const;
+		/** Retrieves the Texture Unit State matching name.
+		Returns 0 if name match is not found.
+		*/
+		const TextureUnitState* getTextureUnitState(const String& name) const;
+
+        /**  Retrieve the index of the Texture Unit State in the pass.
+        @param
+        state The Texture Unit State this is attached to this pass.
+        @note
+            Throws an exception if the state is not attached to the pass.
+        */
+        unsigned short getTextureUnitStateIndex(const TextureUnitState* state);
+
+        typedef VectorIterator<TextureUnitStates> TextureUnitStateIterator;
+        /** Get an iterator over the TextureUnitStates contained in this Pass. */
+        TextureUnitStateIterator getTextureUnitStateIterator(void);
+
+		typedef ConstVectorIterator<TextureUnitStates> ConstTextureUnitStateIterator;
+		/** Get an iterator over the TextureUnitStates contained in this Pass. */
+		ConstTextureUnitStateIterator getTextureUnitStateIterator(void) const;
+
+		/** Removes the indexed texture unit state from this pass.
+        @remarks
+            Note that removing a texture which is not the topmost will have a larger performance impact.
+        */
+        void removeTextureUnitState(unsigned short index);
+
+        /** Removes all texture unit settings.
+        */
+        void removeAllTextureUnitStates(void);
+
+        /** Returns the number of texture unit settings.
+        */
+        size_t getNumTextureUnitStates(void) const
+        {
+            return mTextureUnitStates.size();
+        }
+
+        /** Sets the kind of blending this pass has with the existing contents of the scene.
+        @remarks
+        Wheras the texture blending operations seen in the TextureUnitState class are concerned with
+        blending between texture layers, this blending is about combining the output of the Pass
+        as a whole with the existing contents of the rendering target. This blending therefore allows
+        object transparency and other special effects. If all passes in a technique have a scene
+        blend, then the whole technique is considered to be transparent.
+        @par
+        This method allows you to select one of a number of predefined blending types. If you require more
+        control than this, use the alternative version of this method which allows you to specify source and
+        destination blend factors.
+        @note
+        This method is applicable for both the fixed-function and programmable pipelines.
+        @param
+        sbt One of the predefined SceneBlendType blending types
+        */
+        void setSceneBlending( const SceneBlendType sbt );
+
+        /** Allows very fine control of blending this Pass with the existing contents of the scene.
+        @remarks
+        Wheras the texture blending operations seen in the TextureUnitState class are concerned with
+        blending between texture layers, this blending is about combining the output of the material
+        as a whole with the existing contents of the rendering target. This blending therefore allows
+        object transparency and other special effects.
+        @par
+        This version of the method allows complete control over the blending operation, by specifying the
+        source and destination blending factors. The result of the blending operation is:
+        <span align="center">
+        final = (texture * sourceFactor) + (pixel * destFactor)
+        </span>
+        @par
+        Each of the factors is specified as one of a number of options, as specified in the SceneBlendFactor
+        enumerated type.
+        @param
+        sourceFactor The source factor in the above calculation, i.e. multiplied by the texture colour components.
+        @param
+        destFactor The destination factor in the above calculation, i.e. multiplied by the pixel colour components.
+        @note
+        This method is applicable for both the fixed-function and programmable pipelines.
+        */
+        void setSceneBlending( const SceneBlendFactor sourceFactor, const SceneBlendFactor destFactor);
+
+        /** Retrieves the source blending factor for the material (as set using Materiall::setSceneBlending).
+        */
+        SceneBlendFactor getSourceBlendFactor() const;
+
+        /** Retrieves the destination blending factor for the material (as set using Materiall::setSceneBlending).
+        */
+        SceneBlendFactor getDestBlendFactor() const;
+
+		/** Returns true if this pass has some element of transparency. */
+		bool isTransparent(void) const;
+
+		/** Sets whether or not this pass renders with depth-buffer checking on or not.
+        @remarks
+        If depth-buffer checking is on, whenever a pixel is about to be written to the frame buffer
+        the depth buffer is checked to see if the pixel is in front of all other pixels written at that
+        point. If not, the pixel is not written.
+        @par
+        If depth checking is off, pixels are written no matter what has been rendered before.
+        Also see setDepthFunction for more advanced depth check configuration.
+        @see
+        setDepthFunction
+        */
+        void setDepthCheckEnabled(bool enabled);
+
+        /** Returns whether or not this pass renders with depth-buffer checking on or not.
+        @see
+        setDepthCheckEnabled
+        */
+        bool getDepthCheckEnabled(void) const;
+
+        /** Sets whether or not this pass renders with depth-buffer writing on or not.
+        @remarks
+        If depth-buffer writing is on, whenever a pixel is written to the frame buffer
+        the depth buffer is updated with the depth value of that new pixel, thus affecting future
+        rendering operations if future pixels are behind this one.
+        @par
+        If depth writing is off, pixels are written without updating the depth buffer Depth writing should
+        normally be on but can be turned off when rendering static backgrounds or when rendering a collection
+        of transparent objects at the end of a scene so that they overlap each other correctly.
+        */
+        void setDepthWriteEnabled(bool enabled);
+
+        /** Returns whether or not this pass renders with depth-buffer writing on or not.
+        @see
+        setDepthWriteEnabled
+        */
+        bool getDepthWriteEnabled(void) const;
+
+        /** Sets the function used to compare depth values when depth checking is on.
+        @remarks
+        If depth checking is enabled (see setDepthCheckEnabled) a comparison occurs between the depth
+        value of the pixel to be written and the current contents of the buffer. This comparison is
+        normally CMPF_LESS_EQUAL, i.e. the pixel is written if it is closer (or at the same distance)
+        than the current contents. If you wish you can change this comparison using this method.
+        */
+        void setDepthFunction( CompareFunction func );
+        /** Returns the function used to compare depth values when depth checking is on.
+        @see
+        setDepthFunction
+        */
+        CompareFunction getDepthFunction(void) const;
+
+		/** Sets whether or not colour buffer writing is enabled for this Pass.
+		@remarks
+			For some effects, you might wish to turn off the colour write operation
+			when rendering geometry; this means that only the depth buffer will be
+			updated (provided you have depth buffer writing enabled, which you 
+			probably will do, although you may wish to only update the stencil
+			buffer for example - stencil buffer state is managed at the RenderSystem
+			level only, not the Material since you are likely to want to manage it 
+			at a higher level).
+		*/
+		void setColourWriteEnabled(bool enabled);
+		/** Determines if colour buffer writing is enabled for this pass. */
+		bool getColourWriteEnabled(void) const;
+
+        /** Sets the culling mode for this pass  based on the 'vertex winding'.
+        @remarks
+        A typical way for the rendering engine to cull triangles is based on the 'vertex winding' of
+        triangles. Vertex winding refers to the direction in which the vertices are passed or indexed
+        to in the rendering operation as viewed from the camera, and will wither be clockwise or
+        anticlockwise (that's 'counterclockwise' for you Americans out there ;) The default is
+        CULL_CLOCKWISE i.e. that only triangles whose vertices are passed/indexed in anticlockwise order
+        are rendered - this is a common approach and is used in 3D studio models for example. You can
+        alter this culling mode if you wish but it is not advised unless you know what you are doing.
+        @par
+        You may wish to use the CULL_NONE option for mesh data that you cull yourself where the vertex
+        winding is uncertain.
+        */
+        void setCullingMode( CullingMode mode );
+
+        /** Returns the culling mode for geometry rendered with this pass. See setCullingMode for more information.
+        */
+        CullingMode getCullingMode(void) const;
+
+        /** Sets the manual culling mode, performed by CPU rather than hardware.
+        @pemarks
+        In some situations you want to use manual culling of triangles rather than sending the
+        triangles to the hardware and letting it cull them. This setting only takes effect on SceneManager's
+        that use it (since it is best used on large groups of planar world geometry rather than on movable
+        geometry since this would be expensive), but if used can cull geometry before it is sent to the
+        hardware.
+        @note
+        The default for this setting is MANUAL_CULL_BACK.
+        @param
+        mode The mode to use - see enum ManualCullingMode for details
+
+        */
+        void setManualCullingMode( ManualCullingMode mode );
+
+        /** Retrieves the manual culling mode for this pass
+        @see
+        setManualCullingMode
+        */
+        ManualCullingMode getManualCullingMode(void) const;
+
+        /** Sets whether or not dynamic lighting is enabled.
+        @param
+        enabled
+        If true, dynamic lighting is performed on geometry with normals supplied, geometry without
+        normals will not be displayed.
+        @par
+        If false, no lighting is applied and all geometry will be full brightness.
+        */
+        void setLightingEnabled(bool enabled);
+
+        /** Returns whether or not dynamic lighting is enabled.
+        */
+        bool getLightingEnabled(void) const;
+
+        /** Sets the maximum number of lights to be used by this pass. 
+        @remarks
+            During rendering, if lighting is enabled (or if the pass uses an automatic
+            program parameter based on a light) the engine will request the nearest lights 
+            to the object being rendered in order to work out which ones to use. This
+            parameter sets the limit on the number of lights which should apply to objects 
+            rendered with this pass. 
+        */
+        void setMaxSimultaneousLights(unsigned short maxLights);
+        /** Gets the maximum number of lights to be used by this pass. */
+        unsigned short getMaxSimultaneousLights(void) const;
+
+        /** Sets the type of light shading required
+        @note
+        The default shading method is Gouraud shading.
+        */
+        void setShadingMode( ShadeOptions mode );
+
+        /** Returns the type of light shading to be used.
+        */
+        ShadeOptions getShadingMode(void) const;
+
+		/** Sets the type of polygon rendering required
+		@note
+		The default shading method is Solid 
+		*/
+		void setPolygonMode( PolygonMode mode );
+
+		/** Returns the type of light shading to be used.
+		*/
+		PolygonMode getPolygonMode(void) const;
+
+        /** Sets the fogging mode applied to this pass.
+        @remarks
+        Fogging is an effect that is applied as polys are rendered. Sometimes, you want
+        fog to be applied to an entire scene. Other times, you want it to be applied to a few
+        polygons only. This pass-level specification of fog parameters lets you easily manage
+        both.
+        @par
+        The SceneManager class also has a setFog method which applies scene-level fog. This method
+        lets you change the fog behaviour for this pass compared to the standard scene-level fog.
+        @param
+        overrideScene If true, you authorise this pass to override the scene's fog params with it's own settings.
+        If you specify false, so other parameters are necessary, and this is the default behaviour for passs.
+        @param
+        mode Only applicable if overrideScene is true. You can disable fog which is turned on for the
+        rest of the scene by specifying FOG_NONE. Otherwise, set a pass-specific fog mode as
+        defined in the enum FogMode.
+        @param
+        colour The colour of the fog. Either set this to the same as your viewport background colour,
+        or to blend in with a skydome or skybox.
+        @param
+        expDensity The density of the fog in FOG_EXP or FOG_EXP2 mode, as a value between 0 and 1. 
+        The default is 0.001.
+        @param
+        linearStart Distance in world units at which linear fog starts to encroach. 
+        Only applicable if mode is FOG_LINEAR.
+        @param
+        linearEnd Distance in world units at which linear fog becomes completely opaque.
+        Only applicable if mode is FOG_LINEAR.
+        */
+        void setFog(
+            bool overrideScene,
+            FogMode mode = FOG_NONE,
+            const ColourValue& colour = ColourValue::White,
+            Real expDensity = 0.001, Real linearStart = 0.0, Real linearEnd = 1.0 );
+
+        /** Returns true if this pass is to override the scene fog settings.
+        */
+        bool getFogOverride(void) const;
+
+        /** Returns the fog mode for this pass.
+        @note
+        Only valid if getFogOverride is true.
+        */
+        FogMode getFogMode(void) const;
+
+        /** Returns the fog colour for the scene.
+        */
+        const ColourValue& getFogColour(void) const;
+
+        /** Returns the fog start distance for this pass.
+        @note
+        Only valid if getFogOverride is true.
+        */
+        Real getFogStart(void) const;
+
+        /** Returns the fog end distance for this pass.
+        @note
+        Only valid if getFogOverride is true.
+        */
+        Real getFogEnd(void) const;
+
+        /** Returns the fog density for this pass.
+        @note
+        Only valid if getFogOverride is true.
+        */
+        Real getFogDensity(void) const;
+
+        /** Sets the depth bias to be used for this material.
+        @remarks
+        When polygons are coplanar, you can get problems with 'depth fighting' where
+        the pixels from the two polys compete for the same screen pixel. This is particularly
+        a problem for decals (polys attached to another surface to represent details such as
+        bulletholes etc.).
+        @par
+        A way to combat this problem is to use a depth bias to adjust the depth buffer value
+        used for the decal such that it is slightly higher than the true value, ensuring that
+        the decal appears on top.
+        @param bias The bias value, should be between 0 and 16.
+        */
+        void setDepthBias(ushort bias);
+
+        /** Retrieves the depth bias value as set by setDepthValue. */
+        ushort getDepthBias(void) const;
+
+        /** Sets the way the pass will have use alpha to totally reject pixels from the pipeline.
+        @remarks
+			The default is CMPF_ALWAYS_PASS i.e. alpha is not used to reject pixels.
+        @param func The comparison which must pass for the pixel to be written.
+        @param value 1 byte value against which alpha values will be tested(0-255)
+        @note
+			This option applies in both the fixed function and the programmable pipeline.
+        */
+        void setAlphaRejectSettings(CompareFunction func, unsigned char value);
+
+		/** Sets the alpha reject function. See setAlphaRejectSettings for more information.
+		*/
+		void setAlphaRejectFunction(CompareFunction func);
+
+		/** Gets the alpha reject value. See setAlphaRejectSettings for more information.
+		*/
+		void setAlphaRejectValue(unsigned char val);
+
+		/** Gets the alpha reject function. See setAlphaRejectSettings for more information.
+        */
+		CompareFunction getAlphaRejectFunction(void) const { return mAlphaRejectFunc; }
+
+        /** Gets the alpha reject value. See setAlphaRejectSettings for more information.
+        */
+		unsigned char getAlphaRejectValue(void) const { return mAlphaRejectVal; }
+        /** Sets whether or not this pass should iterate per light which
+		    can affect the object being rendered.
+		@remarks
+			The default behaviour for a pass (when this option is 'false'), is 
+			for a pass to be rendered only once (or the number of times set in 
+			setPassIterationCount), with all the lights which could
+			affect this object set at the same time (up to the maximum lights
+			allowed in the render system, which is typically 8). 
+		@par
+			Setting this option to 'true' changes this behaviour, such that 
+			instead of trying to issue render this pass once per object, it
+			is run <b>per light</b> which can affect this object, the number of
+			times set in setPassIterationCount (default is once). In
+			this case, only light index 0 is ever used, and is a different light
+			every time the pass is issued, up to the total number of lights
+			which is affecting this object. This has 2 advantages:
+			<ul><li>There is no limit on the number of lights which can be 
+			supported</li>
+			<li>It's easier to write vertex / fragment programs for this because
+			a single program can be used for any number of lights</li>
+			</ul>
+			However, this technique is a lot more expensive, and typically you
+			will want an additional ambient pass, because if no lights are 
+			affecting the object it will not be rendered at all, which will look
+			odd even if ambient light is zero (imagine if there are lit objects
+			behind it - the objects silhouette would not show up). Therefore,
+			use this option with care, and you would be well advised to provide
+			a less expensive fallback technique for use in the distance.
+		@note
+			The number of times this pass runs is still limited by the maximum
+			number of lights allowed as set in setMaxSimultaneousLights, so
+			you will never get more passes than this.
+        @param enabled Whether this feature is enabled
+        @param onlyForOneLightType If true, the pass will only be run for a single type
+            of light, other light types will be ignored.
+        @param lightType The single light type which will be considered for this pass
+		*/
+        void setIteratePerLight(bool enabled, 
+            bool onlyForOneLightType = true, Light::LightTypes lightType = Light::LT_POINT);
+
+        /** Does this pass run once for every light in range? */
+		bool getIteratePerLight(void) const { return mIteratePerLight; }
+        /** Does this pass run only for a single light type (if getIteratePerLight is true). */
+        bool getRunOnlyForOneLightType(void) const { return mRunOnlyForOneLightType; }
+        /** Gets the single light type this pass runs for if  getIteratePerLight and 
+            getRunOnlyForOneLightType are both true. */
+        Light::LightTypes getOnlyLightType() const { return mOnlyLightType; }
+		
+		/// Gets the parent Technique
+        Technique* getParent(void) { return mParent; }
+
+		/// Gets the resource group of the ultimate parent Material
+		const String& getResourceGroup(void) const;
+
+		/** Sets the details of the vertex program to use.
+		@remarks
+			Only applicable to programmable passes, this sets the details of
+			the vertex program to use in this pass. The program will not be
+			loaded until the parent Material is loaded.
+		@param name The name of the program - this must have been 
+			created using GpuProgramManager by the time that this Pass 
+			is loaded. If this parameter is blank, any vertex program in this pass is disabled.
+        @param resetParams
+            If true, this will create a fresh set of parameters from the
+            new program being linked, so if you had previously set parameters
+            you will have to set them again. If you set this to false, you must
+            be absolutely sure that the parameters match perfectly, and in the
+            case of named parameters refers to the indexes underlying them, 
+            not just the names.
+		*/
+		void setVertexProgram(const String& name, bool resetParams = true);
+		/** Sets the vertex program parameters.
+		@remarks
+			Only applicable to programmable passes, and this particular call is
+			designed for low-level programs; use the named parameter methods
+			for setting high-level program parameters.
+		*/
+		void setVertexProgramParameters(GpuProgramParametersSharedPtr params);
+		/** Gets the name of the vertex program used by this pass. */
+		const String& getVertexProgramName(void) const;
+        /** Gets the vertex program parameters used by this pass. */
+        GpuProgramParametersSharedPtr getVertexProgramParameters(void) const;
+		/** Gets the vertex program used by this pass, only available after _load(). */
+		const GpuProgramPtr& getVertexProgram(void) const;
+
+
+        /** Sets the details of the vertex program to use when rendering as a 
+        shadow caster.
+        @remarks
+        Texture-based shadows require that the caster is rendered to a texture 
+        in a solid colour (the shadow colour in the case of modulative texture
+        shadows). Whilst Ogre can arrange this for the fixed function 
+        pipeline, passes which use vertex programs might need the vertex
+        programs still to run in order to preserve any deformation etc
+        that it does. However, lighting calculations must be a lot simpler, 
+        with only the ambient colour being used (which the engine will ensure
+        is bound to the shadow colour). 
+        @par
+        Therefore, it is up to implemetors of vertex programs to provide an
+        alternative vertex program which can be used to render the object
+        to a shadow texture. Do all the same vertex transforms, but set the
+        colour of the vertex to the ambient colour, as bound using the 
+        standard auto parameter binding mechanism. 
+        @note
+        Some vertex programs will work without doing this, because Ogre ensures
+        that all lights except for ambient are set black. However, the chances
+        are that your vertex program is doing a lot of unnecessary work in this
+        case, since the other lights are having no effect, and it is good practice
+        to supply an alternative.
+        @note
+        This is only applicable to programmable passes.
+        @par
+        The default behaviour is for Ogre to switch to fixed-function 
+        rendering if an explict vertex program alternative is not set.
+        */
+        void setShadowCasterVertexProgram(const String& name);
+        /** Sets the vertex program parameters for rendering as a shadow caster.
+        @remarks
+        Only applicable to programmable passes, and this particular call is
+        designed for low-level programs; use the named parameter methods
+        for setting high-level program parameters.
+        */
+        void setShadowCasterVertexProgramParameters(GpuProgramParametersSharedPtr params);
+        /** Gets the name of the vertex program used by this pass when rendering shadow casters. */
+        const String& getShadowCasterVertexProgramName(void) const;
+        /** Gets the vertex program parameters used by this pass when rendering shadow casters. */
+        GpuProgramParametersSharedPtr getShadowCasterVertexProgramParameters(void) const;
+        /** Gets the vertex program used by this pass when rendering shadow casters, 
+            only available after _load(). */
+        const GpuProgramPtr& getShadowCasterVertexProgram(void) const;
+
+        /** Sets the details of the vertex program to use when rendering as a 
+            shadow receiver.
+        @remarks
+            Texture-based shadows require that the shadow receiver is rendered using
+            a projective texture. Whilst Ogre can arrange this for the fixed function 
+            pipeline, passes which use vertex programs might need the vertex
+            programs still to run in order to preserve any deformation etc
+            that it does. So in this case, we need a vertex program which does the 
+            appropriate vertex transformation, but generates projective texture
+            coordinates. 
+        @par
+            Therefore, it is up to implemetors of vertex programs to provide an
+            alternative vertex program which can be used to render the object
+            as a shadow receiver. Do all the same vertex transforms, but generate
+            <strong>2 sets</strong> of texture coordinates using the auto parameter
+            ACT_TEXTURE_VIEWPROJ_MATRIX, which Ogre will bind to the parameter name / 
+            index you supply as the second parameter to this method. 2 texture 
+            sets are needed because Ogre needs to use 2 texture units for some 
+            shadow effects.
+        @note
+            This is only applicable to programmable passes.
+        @par
+            The default behaviour is for Ogre to switch to fixed-function 
+            rendering if an explict vertex program alternative is not set.         
+        */
+        void setShadowReceiverVertexProgram(const String& name);
+        /** Sets the vertex program parameters for rendering as a shadow receiver.
+        @remarks
+        Only applicable to programmable passes, and this particular call is
+        designed for low-level programs; use the named parameter methods
+        for setting high-level program parameters.
+        */
+        void setShadowReceiverVertexProgramParameters(GpuProgramParametersSharedPtr params);
+
+		/** This method allows you to specify a fragment program for use when
+			rendering a texture shadow receiver. 
+		@remarks
+			Texture shadows are applied by rendering the receiver. Modulative texture
+			shadows are performed as a post-render darkening pass, and as such 
+			fragment programs are generally not required per-object. Additive
+			texture shadows, however, are applied by accumulating light masked
+			out using a texture shadow (black & white by default, unless you
+			customise this using SceneManager::setCustomShadowCasterMaterial).
+			OGRE can do this for you for most materials, but if you use a custom
+			lighting program (e.g. per pixel lighting) then you'll need to provide
+			a custom version for receiving shadows. You don't need to provide
+			this for shadow casters if you don't use self-shadowing since they
+			will never be shadow receivers too.
+		@par
+			The shadow texture is always bound to texture unit 0 when rendering
+			texture shadow passes. Therefore your custom shadow receiver program
+			may well just need to shift it's texture unit usage up by one unit,
+			and take the shadow texture into account in its calculations.
+		*/
+		void setShadowReceiverFragmentProgram(const String& name);
+        /** Sets the fragment program parameters for rendering as a shadow receiver.
+        @remarks
+        Only applicable to programmable passes, and this particular call is
+        designed for low-level programs; use the named parameter methods
+        for setting high-level program parameters.
+        */
+        void setShadowReceiverFragmentProgramParameters(GpuProgramParametersSharedPtr params);
+
+        /** Gets the name of the vertex program used by this pass when rendering shadow receivers. */
+        const String& getShadowReceiverVertexProgramName(void) const;
+        /** Gets the vertex program parameters used by this pass when rendering shadow receivers. */
+        GpuProgramParametersSharedPtr getShadowReceiverVertexProgramParameters(void) const;
+        /** Gets the vertex program used by this pass when rendering shadow receivers, 
+        only available after _load(). */
+        const GpuProgramPtr& getShadowReceiverVertexProgram(void) const;
+
+		/** Gets the name of the fragment program used by this pass when rendering shadow receivers. */
+		const String& getShadowReceiverFragmentProgramName(void) const;
+		/** Gets the fragment program parameters used by this pass when rendering shadow receivers. */
+		GpuProgramParametersSharedPtr getShadowReceiverFragmentProgramParameters(void) const;
+		/** Gets the fragment program used by this pass when rendering shadow receivers, 
+		only available after _load(). */
+		const GpuProgramPtr& getShadowReceiverFragmentProgram(void) const;
+
+		/** Sets the details of the fragment program to use.
+		@remarks
+			Only applicable to programmable passes, this sets the details of
+			the fragment program to use in this pass. The program will not be
+			loaded until the parent Material is loaded.
+		@param name The name of the program - this must have been 
+			created using GpuProgramManager by the time that this Pass 
+			is loaded. If this parameter is blank, any fragment program in this pass is disabled.
+        @param resetParams
+            If true, this will create a fresh set of parameters from the
+            new program being linked, so if you had previously set parameters
+            you will have to set them again. If you set this to false, you must
+            be absolutely sure that the parameters match perfectly, and in the
+            case of named parameters refers to the indexes underlying them, 
+            not just the names.
+		*/
+		void setFragmentProgram(const String& name, bool resetParams = true);
+		/** Sets the vertex program parameters.
+		@remarks
+			Only applicable to programmable passes.
+		*/
+		void setFragmentProgramParameters(GpuProgramParametersSharedPtr params);
+		/** Gets the name of the fragment program used by this pass. */
+		const String& getFragmentProgramName(void) const;
+		/** Gets the vertex program parameters used by this pass. */
+		GpuProgramParametersSharedPtr getFragmentProgramParameters(void) const;
+		/** Gets the vertex program used by this pass, only available after _load(). */
+		const GpuProgramPtr& getFragmentProgram(void) const;
+
+		/** Splits this Pass to one which can be handled in the number of
+			texture units specified.
+		@remarks
+			Only works on non-programmable passes, programmable passes cannot be
+			split, it's up to the author to ensure that there is a fallback Technique
+			for less capable cards.
+		@param numUnits The target number of texture units
+		@returns A new Pass which contains the remaining units, and a scene_blend
+				setting appropriate to approximate the multitexture. This Pass will be 
+				attached to the parent Technique of this Pass.
+		*/
+		Pass* _split(unsigned short numUnits);
+
+		/** Internal method to adjust pass index. */
+		void _notifyIndex(unsigned short index);
+
+		/** Internal method for loading this pass. */
+		void _load(void);
+		/** Internal method for unloading this pass. */
+		void _unload(void);
+        // Is this loaded?
+        bool isLoaded(void) const;
+
+        /** Gets the 'hash' of this pass, ie a precomputed number to use for sorting
+        @remarks
+            This hash is used to sort passes, and for this reason the pass is hashed
+            using firstly its index (so that all passes are rendered in order), then
+            by the textures which it's TextureUnitState instances are using.
+        */
+        uint32 getHash(void) const;
+		/// Mark the hash as dirty
+		void _dirtyHash(void);
+        /** Internal method for recalculating the hash.
+		@remarks
+			Do not call this unless you are sure the old hash is not still being
+			used by anything. If in doubt, call _dirtyHash if you want to force
+			recalculation of the has next time.
+		*/
+        void _recalculateHash(void);
+        /** Tells the pass that it needs recompilation. */
+        void _notifyNeedsRecompile(void);
+
+        /** Update any automatic parameters (except lights) on this pass */
+        void _updateAutoParamsNoLights(const AutoParamDataSource& source) const;
+        /** Update any automatic light parameters on this pass */
+        void _updateAutoParamsLightsOnly(const AutoParamDataSource& source) const;
+
+        /** Set texture filtering for every texture unit 
+        @note
+            This property actually exists on the TextureUnitState class
+            For simplicity, this method allows you to set these properties for 
+            every current TeextureUnitState, If you need more precision, retrieve the  
+            TextureUnitState instance and set the property there.
+        @see TextureUnitState::setTextureFiltering
+        */
+        void setTextureFiltering(TextureFilterOptions filterType);
+        /** Sets the anisotropy level to be used for all textures.
+        @note
+            This property has been moved to the TextureUnitState class, which is accessible via the 
+            Technique and Pass. For simplicity, this method allows you to set these properties for 
+            every current TeextureUnitState, If you need more precision, retrieve the Technique, 
+            Pass and TextureUnitState instances and set the property there.
+        @see TextureUnitState::setTextureAnisotropy
+        */
+        void setTextureAnisotropy(unsigned int maxAniso);
+		/** Static method to retrieve all the Passes which need their
+		    hash values recalculated. 
+		*/
+		static const PassSet& getDirtyHashList(void) 
+		{ return msDirtyHashList; }
+        /** Static method to retrieve all the Passes which are pending deletion.
+        */
+        static const PassSet& getPassGraveyard(void) 
+        { return msPassGraveyard; }
+		/** Static method to reset the list of passes which need their hash 
+		    values recalculated. 
+		@remarks
+			For performance, the dirty list is not updated progressively as 
+			the hashes are recalculated, instead we expect the processor of the
+			dirty hash list to clear the list when they are done.
+		*/
+		static void clearDirtyHashList(void) { msDirtyHashList.clear(); }
+
+        /** Process all dirty and pending deletion passes. */
+        static void processPendingPassUpdates(void);
+
+        /** Queue this pass for deletion when appropriate. */
+        void queueForDeletion(void);
+
+        /** Returns whether this pass is ambient only.
+        */
+        bool isAmbientOnly(void) const;
+
+        /** set the number of iterations that this pass
+        should perform when doing fast multi pass operation.
+        @remarks
+            Only applicable for programmable passes.
+        @param count number of iterations to perform fast multi pass operations.
+            A value greater than 0 will cause the pass to be executed count number of
+            times without changing the render state.  This is very usefull for passes
+            that use programmable shaders that have to iterate more than once but don't
+            need a render state change.  Using multi pass can dramatically speed up rendering
+            for materials that do things like fur, blur.
+            A value of 0 turns off multi pass operation and the pass does
+            the normal pass operation.
+        */
+        void setPassIterationCount(const size_t count) { mPassIterationCount = count; }
+
+        /** Gets the multi pass count value.
+        */
+        size_t getPassIterationCount(void) const { return mPassIterationCount; }
+
+        /** Applies texture names to Texture Unit State with matching texture name aliases.
+            All Texture Unit States within the pass are checked.
+            If matching texture aliases are found then true is returned.
+
+        @param
+            aliasList is a map container of texture alias, texture name pairs
+        @param
+            apply set true to apply the texture aliases else just test to see if texture alias matches are found.
+        @return
+            True if matching texture aliases were found in the pass.
+        */
+        bool applyTextureAliases(const AliasTextureNamePairList& aliasList, const bool apply = true) const;
+   
+		
+#ifdef GAMETOOLS_ILLUMINATION_MODULE
+		public:
+			void setActive(bool active){mActive = active;}
+			bool isActive() const {return mActive;}	
+		protected:
+			bool mActive;
+#endif
+    };
+
+    enum IlluminationStage
+    {
+        /// Part of the rendering which occurs without any kind of direct lighting
+        IS_AMBIENT,
+        /// Part of the rendering which occurs per light
+        IS_PER_LIGHT,
+        /// Post-lighting rendering
+        IS_DECAL
+    };
+    /** Struct recording a pass which can be used for a specific illumination stage.
+    @remarks
+        This structure is used to record categorised passes which fit into a 
+        number of distinct illumination phases - ambient, diffuse / specular 
+        (per-light) and decal (post-lighting texturing).
+        An original pass may fit into one of these categories already, or it
+        may require splitting into its component parts in order to be categorised 
+        properly.
+    */
+    struct IlluminationPass
+    {
+        IlluminationStage stage;
+        /// The pass to use in this stage
+        Pass* pass;
+        /// Whether this pass is one which should be deleted itself
+        bool destroyOnShutdown;
+        /// The original pass which spawned this one
+        Pass* originalPass;
+    };
+
+    typedef std::vector<IlluminationPass*> IlluminationPassList;
+
+
+}
+
+#endif
Index: OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/OgreRenderTarget.h
===================================================================
--- OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/OgreRenderTarget.h	(revision 768)
+++ OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/OgreRenderTarget.h	(revision 768)
@@ -0,0 +1,370 @@
+/*
+-----------------------------------------------------------------------------
+This source file is part of OGRE
+    (Object-oriented Graphics Rendering Engine)
+For the latest info, see http://www.ogre3d.org/
+
+Copyright (c) 2000-2005 The OGRE Team
+Also see acknowledgements in Readme.html
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+#ifndef __RenderTarget_H__
+#define __RenderTarget_H__
+
+#include "OgrePrerequisites.h"
+
+#include "OgreString.h"
+#include "OgreTextureManager.h"
+#include "OgreViewport.h"
+#include "OgreTimer.h"
+
+/* Define the number of priority groups for the render system's render targets. */
+#ifndef OGRE_NUM_RENDERTARGET_GROUPS
+	#define OGRE_NUM_RENDERTARGET_GROUPS 10
+	#define OGRE_DEFAULT_RT_GROUP 4
+	#define OGRE_REND_TO_TEX_RT_GROUP 2
+#endif
+
+namespace Ogre {
+
+    /** A 'canvas' which can receive the results of a rendering
+        operation.
+        @remarks
+            This abstract class defines a common root to all targets of rendering operations. A
+            render target could be a window on a screen, or another
+            offscreen surface like a texture or bump map etc.
+        @author
+            Steven Streeting
+        @version
+            1.0
+     */
+    class _OgreExport RenderTarget
+    {
+    public:
+        enum StatFlags
+        {
+            SF_NONE           = 0,
+            SF_FPS            = 1,
+            SF_AVG_FPS        = 2,
+            SF_BEST_FPS       = 4,
+            SF_WORST_FPS      = 8,
+            SF_TRIANGLE_COUNT = 16,
+            SF_ALL            = 0xFFFF
+        };
+
+        struct FrameStats
+        {
+            float lastFPS;
+            float avgFPS;
+            float bestFPS;
+            float worstFPS;
+            unsigned long bestFrameTime;
+            unsigned long worstFrameTime;
+            size_t triangleCount;
+        };
+
+        RenderTarget();
+        virtual ~RenderTarget();
+
+        /// Retrieve target's name.
+        virtual const String& getName(void) const;
+
+        /// Retrieve information about the render target.
+        virtual void getMetrics(unsigned int& width, unsigned int& height, unsigned int& colourDepth);
+
+        virtual unsigned int getWidth(void) const;
+        virtual unsigned int getHeight(void) const;
+        virtual unsigned int getColourDepth(void) const;
+
+        /** Tells the target to update it's contents.
+            @remarks
+                If OGRE is not running in an automatic rendering loop
+                (started using Root::startRendering),
+                the user of the library is responsible for asking each render
+                target to refresh. This is the method used to do this. It automatically
+                re-renders the contents of the target using whatever cameras have been
+                pointed at it (using Camera::setRenderTarget).
+            @par
+                This allows OGRE to be used in multi-windowed utilities
+                and for contents to be refreshed only when required, rather than
+                constantly as with the automatic rendering loop.
+        */
+        virtual void update(void);
+
+        /** Adds a viewport to the rendering target.
+            @remarks
+                A viewport is the rectangle into which redering output is sent. This method adds
+                a viewport to the render target, rendering from the supplied camera. The
+                rest of the parameters are only required if you wish to add more than one viewport
+                to a single rendering target. Note that size information passed to this method is
+                passed as a parametric, i.e. it is relative rather than absolute. This is to allow
+                viewports to automatically resize along with the target.
+            @param
+                cam The camera from which the viewport contents will be rendered (mandatory)
+            @param
+                ZOrder The relative order of the viewport with others on the target (allows overlapping
+                viewports i.e. picture-in-picture). Higher ZOrders are on top of lower ones. The actual number
+                is irrelevant, only the relative ZOrder matters (you can leave gaps in the numbering)
+            @param
+                left The relative position of the left of the viewport on the target, as a value between 0 and 1.
+            @param
+                top The relative position of the top of the viewport on the target, as a value between 0 and 1.
+            @param
+                width The relative width of the viewport on the target, as a value between 0 and 1.
+            @param
+                height The relative height of the viewport on the target, as a value between 0 and 1.
+        */
+        virtual Viewport* addViewport(Camera* cam, int ZOrder = 0, float left = 0.0f, float top = 0.0f ,
+            float width = 1.0f, float height = 1.0f);
+
+        /** Returns the number of viewports attached to this target.*/
+        virtual unsigned short getNumViewports(void) const;
+
+        /** Retrieves a pointer to the viewport with the given index. */
+        virtual Viewport* getViewport(unsigned short index);
+
+        /** Removes a viewport at a given ZOrder.
+        */
+        virtual void removeViewport(int ZOrder);
+
+        /** Removes all viewports on this target.
+        */
+        virtual void removeAllViewports(void);
+
+        /** Retieves details of current rendering performance.
+            @remarks
+                If the user application wishes to do it's own performance
+                display, or use performance for some other means, this
+                method allows it to retrieve the statistics.
+                @param
+                    lastFPS Pointer to a float to receive the number of frames per second (FPS)
+                    based on the last frame rendered.
+                @param
+                    avgFPS Pointer to a float to receive the FPS rating based on an average of all
+                    the frames rendered since rendering began (the call to
+                    Root::startRendering).
+                @param
+                    bestFPS Pointer to a float to receive the best FPS rating that has been achieved
+                    since rendering began.
+                @param
+                    worstFPS Pointer to a float to receive the worst FPS rating seen so far.
+        */
+        virtual void getStatistics(float& lastFPS, float& avgFPS,
+            float& bestFPS, float& worstFPS) const;  // Access to stats
+
+        virtual const FrameStats& getStatistics(void) const;
+
+        /** Individual stats access - gets the number of frames per second (FPS) based on the last frame rendered.
+        */
+        virtual float getLastFPS() const;
+
+        /** Individual stats access - gets the average frames per second (FPS) since call to Root::startRendering.
+        */
+        virtual float getAverageFPS() const;
+
+        /** Individual stats access - gets the best frames per second (FPS) since call to Root::startRendering.
+        */
+        virtual float getBestFPS() const;
+
+        /** Individual stats access - gets the worst frames per second (FPS) since call to Root::startRendering.
+        */
+        virtual float getWorstFPS() const;
+
+        /** Individual stats access - gets the best frame time
+        */
+        virtual float getBestFrameTime() const;
+
+        /** Individual stats access - gets the worst frame time
+        */
+        virtual float getWorstFrameTime() const;
+
+        /** Resets saved frame-rate statistices.
+        */
+        virtual void resetStatistics(void);
+
+        /** Gets a custom (maybe platform-specific) attribute.
+            @remarks
+                This is a nasty way of satisfying any API's need to see platform-specific details.
+                It horrid, but D3D needs this kind of info. At least it's abstracted.
+            @param
+                name The name of the attribute.
+            @param
+                pData Pointer to memory of the right kind of structure to receive the info.
+        */
+        virtual void getCustomAttribute(const String& name, void* pData);
+
+        /** Adds debug text to this window. */
+        virtual void setDebugText(const String& text);
+
+		/** Returns the debug text. */
+		const String& getDebugText() const;
+
+        /** Add a listener to this RenderTarget which will be called back before & after rendering.
+        @remarks
+            If you want notifications before and after a target is updated by the system, use
+            this method to register your own custom RenderTargetListener class. This is useful
+            for potentially adding your own manual rendering commands before and after the
+            'normal' system rendering.
+        @par NB this should not be used for frame-based scene updates, use Root::addFrameListener for that.
+        */
+        virtual void addListener(RenderTargetListener* listener);
+        /** Removes a RenderTargetListener previously registered using addListener. */
+        virtual void removeListener(RenderTargetListener* listener);
+        /** Removes all listeners from this instance. */
+        virtual void removeAllListeners(void);
+
+		/** Sets the priority of this render target in relation to the others. 
+        @remarks
+            This can be used in order to schedule render target updates. Lower
+            priorities will be rendered first. Note that the priority must be set
+            at the time the render target is attached to the render system, changes
+            afterwards will not affect the ordering.
+        */
+        virtual void setPriority( uchar priority ) { mPriority = priority; }
+        /** Gets the priority of a render target. */
+		virtual uchar getPriority() const { return mPriority; }
+
+        /** Used to retrieve or set the active state of the render target.
+        */
+        virtual bool isActive() const;
+
+        /** Used to set the active state of the render target.
+        */
+        virtual void setActive( bool state );
+
+        /** Sets whether this target should be automatically updated if Ogre's rendering
+            loop or Root::_updateAllRenderTargets is being used.
+        @remarks
+            By default, if you use Ogre's own rendering loop (Root::startRendering)
+            or call Root::_updateAllRenderTargets, all render targets are updated 
+            automatically. This method allows you to control that behaviour, if 
+            for example you have a render target which you only want to update periodically.
+        @param autoupdate If true, the render target is updated during the automatic render
+            loop or when Root::_updateAllRenderTargets is called. If false, the 
+            target is only updated when its update() method is called explicitly.
+        */
+        virtual void setAutoUpdated(bool autoupdate);
+        /** Gets whether this target is automatically updated if Ogre's rendering
+            loop or Root::_updateAllRenderTargets is being used.
+        */
+        virtual bool isAutoUpdated(void) const;
+
+        /** Writes the current contents of the render target to the named file. */
+        virtual void writeContentsToFile(const String& filename) = 0;
+
+	/** Writes the current contents of the render target to the (PREFIX)(time-stamp)(SUFFIX) file.
+		@returns the name of the file used.*/
+	virtual String writeContentsToTimestampedFile(const String& filenamePrefix, const String& filenameSuffix);
+
+		virtual bool requiresTextureFlipping() const = 0;
+
+		/** Gets the number of triangles rendered in the last update() call. */
+		virtual size_t getTriangleCount(void) const;
+        /** Utility method to notify a render target that a camera has been removed, 
+        incase it was referring to it as a viewer. 
+        */
+        virtual void _notifyCameraRemoved(const Camera* cam);
+
+        /** Indicates whether this target is the primary window. The
+            primary window is special in that it is destroyed when 
+            ogre is shut down, and cannot be destroyed directly.
+            This is the case because it holds the context for vertex,
+            index buffers and textures.
+        */
+        virtual bool isPrimary(void) const;
+
+
+        /** RenderSystem specific interface for a RenderTarget;
+            this should be subclassed by RenderSystems.
+        */
+        class Impl
+        {
+        protected:
+            /** Declared protected as interface is never used for destruction.
+                gcc will issue a warning here: `class Impl' has virtual functions 
+                but non-virtual destructor. This is no problem because this interface 
+                is never used to delete an object.
+            */
+            ~Impl() { };
+        };
+        /** Get rendersystem specific interface for this RenderTarget.
+            This is used by the RenderSystem to (un)bind this target, 
+            and to get specific information like surfaces
+            and framebuffer objects.
+        */
+        virtual Impl *_getImpl();
+
+
+		
+    protected:
+        /// The name of this target.
+        String mName;
+		/// The priority of the render target.
+		uchar mPriority;
+
+        unsigned int mWidth;
+        unsigned int mHeight;
+        unsigned int mColourDepth;
+        bool mIsDepthBuffered;
+
+        // Stats
+		FrameStats mStats;
+        
+        Timer* mTimer ;
+        String mDebugText;
+        unsigned long mLastSecond;
+        unsigned long mLastTime;
+        size_t mFrameCount;
+
+        bool mActive;
+        bool mAutoUpdate;
+
+        void updateStats(void);
+
+        typedef std::map<int, Viewport*, std::less<int> > ViewportList;
+        /// List of viewports, map on Z-order
+        ViewportList mViewportList;
+
+        typedef std::vector<RenderTargetListener*> RenderTargetListenerList;
+        RenderTargetListenerList mListeners;
+	
+
+        /// internal method for firing events
+        virtual void firePreUpdate(void);
+        /// internal method for firing events
+        virtual void firePostUpdate(void);
+        /// internal method for firing events
+        virtual void fireViewportPreUpdate(Viewport* vp);
+        /// internal method for firing events
+        virtual void fireViewportPostUpdate(Viewport* vp);
+		/// internal method for firing events
+		virtual void fireViewportAdded(Viewport* vp);
+		/// internal method for firing events
+		virtual void fireViewportRemoved(Viewport* vp);
+
+		#ifdef GAMETOOLS_ILLUMINATION_MODULE 
+		public:
+			unsigned long getLastFrameNumber(){return lastFrame;}
+		protected:
+			unsigned long lastFrame;
+		#endif
+
+    };
+
+} // Namespace
+
+#endif
Index: OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/OgreSceneManager.h
===================================================================
--- OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/OgreSceneManager.h	(revision 768)
+++ OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/OgreSceneManager.h	(revision 768)
@@ -0,0 +1,2457 @@
+/*-------------------------------------------------------------------------
+This source file is a part of OGRE
+(Object-oriented Graphics Rendering Engine)
+
+For the latest info, see http://www.ogre3d.org/
+
+Copyright (c) 2000-2005 The OGRE Team
+Also see acknowledgements in Readme.html
+
+This library is free software; you can redistribute it and/or modify it
+under the terms of the GNU Lesser General Public License (LGPL) as 
+published by the Free Software Foundation; either version 2.1 of the 
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful, but 
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License 
+along with this library; if not, write to the Free Software Foundation, 
+Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA or go to
+http://www.gnu.org/copyleft/lesser.txt
+-------------------------------------------------------------------------*/
+#ifndef __SceneManager_H__
+#define __SceneManager_H__
+
+// Precompiler options
+#include "OgrePrerequisites.h"
+
+#include "OgreString.h"
+#include "OgreSceneNode.h"
+#include "OgrePlane.h"
+#include "OgreQuaternion.h"
+#include "OgreColourValue.h"
+#include "OgreCommon.h"
+#include "OgreSceneQuery.h"
+#include "OgreAutoParamDataSource.h"
+#include "OgreAnimationState.h"
+#include "OgreRenderQueue.h"
+#include "OgreRenderQueueSortingGrouping.h"
+#include "OgreRectangle2D.h"
+#include "OgrePixelFormat.h"
+#include "OgreResourceGroupManager.h"
+#include "OgreTexture.h"
+
+namespace Ogre {
+
+    /** Structure for holding a position & orientation pair. */
+    struct ViewPoint
+    {
+        Vector3 position;
+        Quaternion orientation;
+    };
+
+	// Forward declarations
+	class DefaultIntersectionSceneQuery;
+	class DefaultRaySceneQuery;
+	class DefaultSphereSceneQuery;
+	class DefaultAxisAlignedBoxSceneQuery;
+
+	/** Interface definition for classes which can listen in on the process
+		of rendering shadows, in order to implement custom behaviour.
+	*/
+	class _OgreExport ShadowListener
+	{
+	public:
+		ShadowListener() {}
+		virtual ~ShadowListener() {}
+
+		/** Event raised after all shadow textures have been rendered into for 
+			all queues / targets but before any other geometry has been rendered
+		    (including main scene geometry and any additional shadow receiver 
+			passes). 
+		@remarks
+			This callback is useful for those that wish to perform some 
+			additional processing on shadow textures before they are used to 
+			render shadows. For example you could perform some filtering by 
+			rendering the existing shadow textures into another alternative 
+			shadow texture with a shader.]
+		@note
+			This event will only be fired when texture shadows are in use.
+		@param numberOfShadowTextures The number of shadow textures in use
+		*/
+		virtual void shadowTexturesUpdated(size_t numberOfShadowTextures) = 0;
+
+		/** This event occurs just before the view & projection matrices are
+		 	set for rendering into a shadow texture.
+		@remarks
+			You can use this event hook to perform some custom processing,
+			such as altering the camera being used for rendering the light's
+			view, including setting custom view & projection matrices if you
+			want to perform an advanced shadow technique.
+		@note
+			This event will only be fired when texture shadows are in use.
+		@param light Pointer to the light for which shadows are being rendered
+		@param camera Pointer to the camera being used to render
+		*/
+		virtual void shadowTextureCasterPreViewProj(Light* light, 
+			Camera* camera) = 0;
+		/** This event occurs just before the view & projection matrices are
+		 	set for re-rendering a shadow receiver.
+		@remarks
+			You can use this event hook to perform some custom processing,
+			such as altering the projection frustum being used for rendering 
+			the shadow onto the receiver to perform an advanced shadow 
+			technique.
+		@note
+			This event will only be fired when texture shadows are in use.
+		@param light Pointer to the light for which shadows are being rendered
+		@param frustum Pointer to the projection frustum being used to project
+			the shadow texture
+		*/
+		virtual void shadowTextureReceiverPreViewProj(Light* light, 
+			Frustum* frustum) = 0;
+		
+	};
+
+    /** Manages the organisation and rendering of a 'scene' i.e. a collection 
+		of objects and potentially world geometry.
+    @remarks
+		This class defines the interface and the basic behaviour of a 
+		'Scene Manager'. A SceneManager organises the culling and rendering of
+		the scene, in conjunction with the RenderQueue. This class is designed 
+		to be extended through subclassing in order to provide more specialised
+		scene organisation structures for particular needs. The default 
+		SceneManager culls based on a hierarchy of node bounding boxes, other
+		implementations can use an octree (@see OctreeSceneManager), a BSP
+		tree (@see BspSceneManager), and many other options. New SceneManager
+		implementations can be added at runtime by plugins, see 
+		SceneManagerEnumerator for the interfaces for adding new SceneManager
+		types.
+	@par
+		There is a distinction between 'objects' (which subclass MovableObject, 
+		and are movable, discrete objects in the world), and 'world geometry',
+		which is large, generally static geometry. World geometry tends to 
+		influence the SceneManager organisational structure (e.g. lots of indoor
+		static geometry might result in a spatial tree structure) and as such
+		world geometry is generally tied to a given SceneManager implementation,
+		whilst MovableObject instances can be used with any SceneManager.
+		Subclasses are free to define world geometry however they please.
+	@par
+		Multiple SceneManager instances can exist at one time, each one with 
+		a distinct scene. Which SceneManager is used to render a scene is
+		dependent on the Camera, which will always call back the SceneManager
+		which created it to render the scene. 
+     */
+    class _OgreExport SceneManager
+    {
+    public:
+        /// Query type mask which will be used for world geometry @see SceneQuery
+        static uint32 WORLD_GEOMETRY_TYPE_MASK;
+		/// Query type mask which will be used for entities @see SceneQuery
+		static uint32 ENTITY_TYPE_MASK;
+		/// Query type mask which will be used for effects like billboardsets / particle systems @see SceneQuery
+		static uint32 FX_TYPE_MASK;
+		/// Query type mask which will be used for StaticGeometry  @see SceneQuery
+		static uint32 STATICGEOMETRY_TYPE_MASK;
+		/// Query type mask which will be used for lights  @see SceneQuery
+		static uint32 LIGHT_TYPE_MASK;
+		/// User type mask limit
+		static uint32 USER_TYPE_MASK_LIMIT;
+        /** Comparator for material map, for sorting materials into render order (e.g. transparent last).
+        */
+        struct materialLess
+        {
+            _OgreExport bool operator()(const Material* x, const Material* y) const;
+        };
+        /// Comparator for sorting lights relative to a point
+        struct lightLess
+        {
+            _OgreExport bool operator()(const Light* a, const Light* b) const;
+        };
+
+        /// Describes the stage of rendering when performing complex illumination
+        enum IlluminationRenderStage
+        {
+            /// No special illumination stage
+            IRS_NONE,
+            /// Render to texture stage, used for texture based shadows
+            IRS_RENDER_TO_TEXTURE,
+            /// Render from shadow texture to receivers stage
+            IRS_RENDER_RECEIVER_PASS
+        };
+
+		/** Enumeration of the possible modes allowed for processing the special case
+		render queue list.
+		@see SceneManager::setSpecialCaseRenderQueueMode
+		*/
+		enum SpecialCaseRenderQueueMode
+		{
+			/// Render only the queues in the special case list
+			SCRQM_INCLUDE,
+			/// Render all except the queues in the special case list
+			SCRQM_EXCLUDE
+		};
+
+		typedef struct SkyDomeGenParameters
+		{
+			Real skyDomeCurvature;
+			Real skyDomeTiling;
+			Real skyDomeDistance;
+			int skyDomeXSegments; 
+			int skyDomeYSegments;
+			int skyDomeYSegments_keep;
+		};
+		
+		struct SkyPlaneGenParameters
+		{
+			Real skyPlaneScale;
+			Real skyPlaneTiling; 
+			Real skyPlaneBow; 
+			int skyPlaneXSegments; 
+			int skyPlaneYSegments; 
+		};
+		
+		struct SkyBoxGenParameters
+		{
+			Real skyBoxDistance;
+		};
+    protected:
+		/// Instance name
+		String mName;
+
+        /// Queue of objects for rendering
+        RenderQueue* mRenderQueue;
+
+        /// Current ambient light, cached for RenderSystem
+        ColourValue mAmbientLight;
+
+        /// The rendering system to send the scene to
+        RenderSystem *mDestRenderSystem;
+
+        typedef std::map<String, Camera* > CameraList;
+
+        /** Central list of cameras - for easy memory management and lookup.
+        */
+        CameraList mCameras;
+
+		typedef std::map<String, StaticGeometry* > StaticGeometryList;
+		StaticGeometryList mStaticGeometryList;
+
+        typedef std::map<String, SceneNode*> SceneNodeList;
+
+        /** Central list of SceneNodes - for easy memory management.
+            @note
+                Note that this list is used only for memory management; the structure of the scene
+                is held using the hierarchy of SceneNodes starting with the root node. However you
+                can look up nodes this way.
+        */
+        SceneNodeList mSceneNodes;
+
+        /// Camera in progress
+        Camera* mCameraInProgress;
+        /// Current Viewport
+        Viewport* mCurrentViewport;
+
+        /// Root scene node
+        SceneNode* mSceneRoot;
+
+        /// Autotracking scene nodes
+        typedef std::set<SceneNode*> AutoTrackingSceneNodes;
+        AutoTrackingSceneNodes mAutoTrackingSceneNodes;
+
+        // Sky params
+        // Sky plane
+        Entity* mSkyPlaneEntity;
+        Entity* mSkyDomeEntity[5];
+        Entity* mSkyBoxEntity[6];
+
+        SceneNode* mSkyPlaneNode;
+        SceneNode* mSkyDomeNode;
+        SceneNode* mSkyBoxNode;
+
+        bool mSkyPlaneEnabled;
+        bool mSkyPlaneDrawFirst;
+        Plane mSkyPlane;
+	SceneManager::SkyPlaneGenParameters	mSkyPlaneGenParameters;
+	   // Sky box
+        bool mSkyBoxEnabled;
+        bool mSkyBoxDrawFirst;
+        Quaternion mSkyBoxOrientation;
+		SceneManager::SkyBoxGenParameters	mSkyBoxGenParameters;
+	    // Sky dome
+        bool mSkyDomeEnabled;
+        bool mSkyDomeDrawFirst;
+        Quaternion mSkyDomeOrientation;
+		SceneManager::SkyDomeGenParameters mSkyDomeGenParameters;
+	
+		// Fog
+        FogMode mFogMode;
+        ColourValue mFogColour;
+        Real mFogStart;
+        Real mFogEnd;
+        Real mFogDensity;
+
+		typedef std::set<uint8> SpecialCaseRenderQueueList;
+		SpecialCaseRenderQueueList mSpecialCaseQueueList;
+		SpecialCaseRenderQueueMode mSpecialCaseQueueMode;
+		uint8 mWorldGeometryRenderQueue;
+		
+		unsigned long mLastFrameNumber;
+		Matrix4 mTempXform[256];
+		bool mResetIdentityView;
+		bool mResetIdentityProj;
+
+		typedef std::map<String, MovableObject*> MovableObjectMap;
+		typedef std::map<String, MovableObjectMap*> MovableObjectCollectionMap;
+		MovableObjectCollectionMap mMovableObjectCollectionMap;
+		MovableObjectMap* getMovableObjectMap(const String& typeName);
+
+        /** Internal method for initialising the render queue.
+        @remarks
+            Subclasses can use this to install their own RenderQueue implementation.
+        */
+        virtual void initRenderQueue(void);
+        /// A pass designed to let us render shadow colour on white for texture shadows
+        Pass* mShadowCasterPlainBlackPass;
+        /// A pass designed to let us render shadow receivers for texture shadows
+        Pass* mShadowReceiverPass;
+        /** Internal method for turning a regular pass into a shadow caster pass.
+        @remarks
+            This is only used for texture shadows, basically we're trying to
+            ensure that objects are rendered solid black.
+            This method will usually return the standard solid black pass for
+            all fixed function passes, but will merge in a vertex program
+            and fudge the AutpoParamDataSource to set black lighting for
+            passes with vertex programs. 
+        */
+        const Pass* deriveShadowCasterPass(const Pass* pass);
+        /** Internal method for turning a regular pass into a shadow receiver pass.
+        @remarks
+        This is only used for texture shadows, basically we're trying to
+        ensure that objects are rendered with a projective texture.
+        This method will usually return a standard single-texture pass for
+        all fixed function passes, but will merge in a vertex program
+        for passes with vertex programs. 
+        */
+        const Pass* deriveShadowReceiverPass(const Pass* pass);
+    
+        /** Internal method to validate whether a Pass should be allowed to render.
+        @remarks
+            Called just before a pass is about to be used for rendering a group to
+            allow the SceneManager to omit it if required. A return value of false
+            skips this pass. 
+        */
+        bool validatePassForRendering(const Pass* pass);
+
+        /** Internal method to validate whether a Renderable should be allowed to render.
+        @remarks
+        Called just before a pass is about to be used for rendering a Renderable to
+        allow the SceneManager to omit it if required. A return value of false
+        skips it. 
+        */
+        bool validateRenderableForRendering(const Pass* pass, const Renderable* rend);
+
+        enum BoxPlane
+        {
+            BP_FRONT = 0,
+            BP_BACK = 1,
+            BP_LEFT = 2,
+            BP_RIGHT = 3,
+            BP_UP = 4,
+            BP_DOWN = 5
+        };
+
+        /* Internal utility method for creating the planes of a skybox.
+        */
+        MeshPtr createSkyboxPlane(
+            BoxPlane bp,
+            Real distance,
+            const Quaternion& orientation,
+            const String& groupName);
+
+        /* Internal utility method for creating the planes of a skydome.
+        */
+        MeshPtr createSkydomePlane(
+            BoxPlane bp,
+            Real curvature, Real tiling, Real distance,
+            const Quaternion& orientation,
+            int xsegments, int ysegments, int ySegmentsToKeep, 
+            const String& groupName);
+
+        // Flag indicating whether SceneNodes will be rendered as a set of 3 axes
+        bool mDisplayNodes;
+
+        /// Storage of animations, lookup by name
+        typedef std::map<String, Animation*> AnimationList;
+        AnimationList mAnimationsList;
+        AnimationStateSet mAnimationStates;
+
+        /** Internal method used by _renderSingleObject to deal with renderables
+            which override the camera's own view / projection materices. */
+        void useRenderableViewProjMode(const Renderable* pRend);
+        
+        /** Internal method used by _renderSingleObject to deal with renderables
+            which override the camera's own view / projection matrices. */
+        void resetViewProjMode(void);
+
+        typedef std::vector<RenderQueueListener*> RenderQueueListenerList;
+        RenderQueueListenerList mRenderQueueListeners;
+
+        typedef std::vector<ShadowListener*> ShadowListenerList;
+        ShadowListenerList mShadowListeners;
+        /// Internal method for firing the queue start event, returns true if queue is to be skipped
+        bool fireRenderQueueStarted(uint8 id, const String& invocation);
+        /// Internal method for firing the queue end event, returns true if queue is to be repeated
+        bool fireRenderQueueEnded(uint8 id, const String& invocation);
+
+		/// Internal method for firing the texture shadows updated event
+        void fireShadowTexturesUpdated(size_t numberOfShadowTextures);
+		/// Internal method for firing the pre caster texture shadows event
+        void fireShadowTexturesPreCaster(Light* light, Camera* camera);
+		/// Internal method for firing the pre receiver texture shadows event
+        void fireShadowTexturesPreReceiver(Light* light, Frustum* f);
+        /** Internal method for setting the destination viewport for the next render. */
+        virtual void setViewport(Viewport *vp);
+
+		/** Flag that indicates if all of the scene node's bounding boxes should be shown as a wireframe. */
+		bool mShowBoundingBoxes;      
+
+		/** Internal method for rendering all objects using the default queue sequence. */
+		virtual void renderVisibleObjectsDefaultSequence(void);
+		/** Internal method for rendering all objects using a custom queue sequence. */
+		virtual void renderVisibleObjectsCustomSequence(RenderQueueInvocationSequence* s);
+		/** Internal method for preparing the render queue for use with each render. */
+		virtual void prepareRenderQueue(void);
+
+
+        /** Internal utility method for rendering a single object. 
+        @remarks
+            Assumes that the pass has already been set up.
+        @param rend The renderable to issue to the pipeline
+        @param pass The pass which is being used
+        @param doLightIteration If true, this method will issue the renderable to
+            the pipeline possibly multiple times, if the pass indicates it should be
+            done once per light
+        @param manualLightList Only applicable if doLightIteration is false, this
+            method allows you to pass in a previously determined set of lights
+            which will be used for a single render of this object.
+        */
+        virtual void renderSingleObject(const Renderable* rend, const Pass* pass, 
+			bool doLightIteration, const LightList* manualLightList = 0);
+
+        /// Utility class for calculating automatic parameters for gpu programs
+        AutoParamDataSource mAutoParamDataSource;
+
+        ShadowTechnique mShadowTechnique;
+        bool mDebugShadows;
+        ColourValue mShadowColour;
+        Pass* mShadowDebugPass;
+        Pass* mShadowStencilPass;
+        Pass* mShadowModulativePass;
+		bool mShadowMaterialInitDone;
+        LightList mLightsAffectingFrustum;
+        HardwareIndexBufferSharedPtr mShadowIndexBuffer;
+		size_t mShadowIndexBufferSize;
+        Rectangle2D* mFullScreenQuad;
+        Real mShadowDirLightExtrudeDist;
+        IlluminationRenderStage mIlluminationStage;
+        unsigned short mShadowTextureSize;
+        unsigned short mShadowTextureCount;
+		PixelFormat mShadowTextureFormat;
+        typedef std::vector<TexturePtr> ShadowTextureList;
+        ShadowTextureList mShadowTextures;
+		typedef std::vector<Camera*> ShadowTextureCameraList;
+		ShadowTextureCameraList mShadowTextureCameras;
+        Texture* mCurrentShadowTexture;
+		bool mShadowUseInfiniteFarPlane;
+
+        /** Internal method for locating a list of lights which could be affecting the frustum. 
+        @remarks
+            Custom scene managers are encouraged to override this method to make use of their
+            scene partitioning scheme to more efficiently locate lights, and to eliminate lights
+            which may be occluded by word geometry.
+        */
+        virtual void findLightsAffectingFrustum(const Camera* camera);
+        /// Internal method for setting up materials for shadows
+        virtual void initShadowVolumeMaterials(void);
+        /// Internal method for creating shadow textures (texture-based shadows)
+        virtual void createShadowTextures(unsigned short size, unsigned short count, 
+			PixelFormat fmt);
+        /// Internal method for destroying shadow textures (texture-based shadows)
+        virtual void destroyShadowTextures(void);
+        /// Internal method for preparing shadow textures ready for use in a regular render
+        virtual void prepareShadowTextures(Camera* cam, Viewport* vp);
+
+        /** Internal method for rendering all the objects for a given light into the 
+            stencil buffer.
+        @param light The light source
+        @param cam The camera being viewed from
+        */
+        virtual void renderShadowVolumesToStencil(const Light* light, const Camera* cam);
+        /** Internal utility method for setting stencil state for rendering shadow volumes. 
+        @param secondpass Is this the second pass?
+        @param zfail Should we be using the zfail method?
+        @param twosided Should we use a 2-sided stencil?
+        */
+        virtual void setShadowVolumeStencilState(bool secondpass, bool zfail, bool twosided);
+        /** Render a set of shadow renderables. */
+        void renderShadowVolumeObjects(ShadowCaster::ShadowRenderableListIterator iShadowRenderables,
+            Pass* pass, const LightList *manualLightList, unsigned long flags,
+            bool secondpass, bool zfail, bool twosided);
+        typedef std::vector<ShadowCaster*> ShadowCasterList;
+        ShadowCasterList mShadowCasterList;
+        SphereSceneQuery* mShadowCasterSphereQuery;
+        AxisAlignedBoxSceneQuery* mShadowCasterAABBQuery;
+        Real mShadowFarDist;
+        Real mShadowFarDistSquared;
+        Real mShadowTextureOffset; // proportion of texture offset in view direction e.g. 0.4
+        Real mShadowTextureFadeStart; // as a proportion e.g. 0.6
+        Real mShadowTextureFadeEnd; // as a proportion e.g. 0.9
+		bool mShadowTextureSelfShadow;
+		Pass* mShadowTextureCustomCasterPass;
+		Pass* mShadowTextureCustomReceiverPass;
+		String mShadowTextureCustomCasterVertexProgram;
+		String mShadowTextureCustomReceiverVertexProgram;
+		GpuProgramParametersSharedPtr mShadowTextureCustomCasterVPParams;
+		GpuProgramParametersSharedPtr mShadowTextureCustomReceiverVPParams;
+		bool mShadowTextureCasterVPDirty;
+		bool mShadowTextureReceiverVPDirty;
+
+		/// Visibility mask used to show / hide objects
+		uint32 mVisibilityMask;
+		bool mFindVisibleObjects;
+
+		/// Suppress render state changes?
+		bool mSuppressRenderStateChanges;
+		/// Suppress shadows?
+		bool mSuppressShadows;
+
+
+        GpuProgramParametersSharedPtr mInfiniteExtrusionParams;
+        GpuProgramParametersSharedPtr mFiniteExtrusionParams;
+
+        /// Inner class to use as callback for shadow caster scene query
+        class _OgreExport ShadowCasterSceneQueryListener : public SceneQueryListener
+        {
+        protected:
+			SceneManager* mSceneMgr;
+            ShadowCasterList* mCasterList;
+            bool mIsLightInFrustum;
+            const PlaneBoundedVolumeList* mLightClipVolumeList;
+            const Camera* mCamera;
+            const Light* mLight;
+            Real mFarDistSquared;
+        public:
+            ShadowCasterSceneQueryListener(SceneManager* sm) : mSceneMgr(sm),
+				mCasterList(0), mIsLightInFrustum(false), mLightClipVolumeList(0), 
+                mCamera(0) {}
+            // Prepare the listener for use with a set of parameters  
+            void prepare(bool lightInFrustum, 
+                const PlaneBoundedVolumeList* lightClipVolumes, 
+                const Light* light, const Camera* cam, ShadowCasterList* casterList, 
+                Real farDistSquared) 
+            {
+                mCasterList = casterList;
+                mIsLightInFrustum = lightInFrustum;
+                mLightClipVolumeList = lightClipVolumes;
+                mCamera = cam;
+                mLight = light;
+                mFarDistSquared = farDistSquared;
+            }
+            bool queryResult(MovableObject* object);
+            bool queryResult(SceneQuery::WorldFragment* fragment);
+        };
+
+        ShadowCasterSceneQueryListener* mShadowCasterQueryListener;
+
+        /** Internal method for locating a list of shadow casters which 
+            could be affecting the frustum for a given light. 
+        @remarks
+            Custom scene managers are encouraged to override this method to add optimisations, 
+            and to add their own custom shadow casters (perhaps for world geometry)
+        */
+        virtual const ShadowCasterList& findShadowCastersForLight(const Light* light, 
+            const Camera* camera);
+        /** Render a group in the ordinary way */
+		virtual void renderBasicQueueGroupObjects(RenderQueueGroup* pGroup, 
+			QueuedRenderableCollection::OrganisationMode om);
+		/** Render a group with the added complexity of additive stencil shadows. */
+		virtual void renderAdditiveStencilShadowedQueueGroupObjects(RenderQueueGroup* group, 
+			QueuedRenderableCollection::OrganisationMode om);
+		/** Render a group with the added complexity of modulative stencil shadows. */
+		virtual void renderModulativeStencilShadowedQueueGroupObjects(RenderQueueGroup* group, 
+			QueuedRenderableCollection::OrganisationMode om);
+        /** Render a group rendering only shadow casters. */
+		virtual void renderTextureShadowCasterQueueGroupObjects(RenderQueueGroup* group, 
+			QueuedRenderableCollection::OrganisationMode om);
+        /** Render a group rendering only shadow receivers. */
+		virtual void renderTextureShadowReceiverQueueGroupObjects(RenderQueueGroup* group, 
+			QueuedRenderableCollection::OrganisationMode om);
+        /** Render a group with the added complexity of modulative texture shadows. */
+		virtual void renderModulativeTextureShadowedQueueGroupObjects(RenderQueueGroup* group, 
+			QueuedRenderableCollection::OrganisationMode om);
+
+		/** Render a group with additive texture shadows. */
+		virtual void renderAdditiveTextureShadowedQueueGroupObjects(RenderQueueGroup* group, 
+			QueuedRenderableCollection::OrganisationMode om);
+		/** Render a set of objects, see renderSingleObject for param definitions */
+		virtual void renderObjects(const QueuedRenderableCollection& objs, 
+			QueuedRenderableCollection::OrganisationMode om, 
+            bool doLightIteration, const LightList* manualLightList = 0);
+		/** Render those objects in the transparent pass list which have shadow casting forced on
+		@remarks
+			This function is intended to be used to render the shadows of transparent objects which have
+			transparency_casts_shadows set to 'on' in their material
+		*/
+		virtual void renderTransparentShadowCasterObjects(const QueuedRenderableCollection& objs, 
+			QueuedRenderableCollection::OrganisationMode om, 
+			bool doLightIteration, const LightList* manualLightList = 0);
+
+		/** Update the state of the global render queue splitting based on a shadow
+		option change. */
+		virtual void updateRenderQueueSplitOptions(void);
+		/** Update the state of the render queue group splitting based on a shadow
+		option change. */
+		virtual void updateRenderQueueGroupSplitOptions(RenderQueueGroup* group, 
+			bool suppressShadows, bool suppressRenderState);
+
+		/** Inner helper class to implement the visitor pattern for rendering objects
+			in a queue. 
+		*/
+		class _OgreExport SceneMgrQueuedRenderableVisitor : public QueuedRenderableVisitor
+		{
+		protected:
+			/// Pass that was actually used at the grouping level
+			const Pass* mUsedPass;
+		public:
+			SceneMgrQueuedRenderableVisitor() 
+				:transparentShadowCastersMode(false) {}
+			~SceneMgrQueuedRenderableVisitor() {}
+			void visit(const Renderable* r);
+			bool visit(const Pass* p);
+			void visit(const RenderablePass* rp);
+
+			/// Target SM to send renderables to
+			SceneManager* targetSceneMgr;
+			/// Are we in transparent shadow caster mode?
+			bool transparentShadowCastersMode;
+			/// Automatic light handling?
+			bool autoLights;
+			/// Manual light list
+			const LightList* manualLightList;
+
+		};
+		/// Allow visitor helper to access protected methods
+		friend class SceneMgrQueuedRenderableVisitor;
+		/// The active renderable visitor class - subclasses could override this
+		SceneMgrQueuedRenderableVisitor* mActiveQueuedRenderableVisitor;
+		/// Storage for default renderable visitor
+		SceneMgrQueuedRenderableVisitor mDefaultQueuedRenderableVisitor;
+
+    public:
+        /** Constructor.
+        */
+        SceneManager(const String& instanceName);
+
+        /** Default destructor.
+        */
+        virtual ~SceneManager();
+
+		/** Return the instance name of this SceneManager. */
+		const String& getName(void) const { return mName; }
+
+		/** Retrieve the type name of this scene manager.
+		@remarks
+			This method has to be implemented by subclasses. It should
+			return the type name of this SceneManager which agrees with 
+			the type name of the SceneManagerFactory which created it.
+		*/
+		virtual const String& getTypeName(void) const = 0;
+
+        /** Creates a camera to be managed by this scene manager.
+            @remarks
+                This camera must be added to the scene at a later time using
+                the attachObject method of the SceneNode class.
+            @param
+                name Name to give the new camera.
+        */
+        virtual Camera* createCamera(const String& name);
+
+        /** Retrieves a pointer to the named camera.
+        */
+        virtual Camera* getCamera(const String& name);
+
+        /** Removes a camera from the scene.
+            @remarks
+                This method removes a previously added camera from the scene.
+                The camera is deleted so the caller must ensure no references
+                to it's previous instance (e.g. in a SceneNode) are used.
+            @param
+                cam Pointer to the camera to remove
+        */
+        virtual void destroyCamera(Camera *cam);
+
+        /** Removes a camera from the scene.
+            @remarks
+                This method removes an camera from the scene based on the
+                camera's name rather than a pointer.
+        */
+        virtual void destroyCamera(const String& name);
+
+        /** Removes (and destroys) all cameras from the scene.
+            @remarks
+                Some cameras are internal created to dealing with texture shadow,
+                their aren't supposed to destroy outside. So, while you are using
+                texture shadow, don't call this method, or you can set the shadow
+                technique other than texture-based, which will destroy all internal
+                created shadow cameras and textures.
+        */
+        virtual void destroyAllCameras(void);
+
+        /** Creates a light for use in the scene.
+            @remarks
+                Lights can either be in a fixed position and independent of the
+                scene graph, or they can be attached to SceneNodes so they derive
+                their position from the parent node. Either way, they are created
+                using this method so that the SceneManager manages their
+                existence.
+            @param
+                name The name of the new light, to identify it later.
+        */
+        virtual Light* createLight(const String& name);
+
+        /** Returns a pointer to the named Light which has previously been added to the scene.
+        */
+        virtual Light* getLight(const String& name);
+
+        /** Removes the named light from the scene and destroys it.
+            @remarks
+                Any pointers held to this light after calling this method will be invalid.
+        */
+        virtual void destroyLight(const String& name);
+
+        /** Removes the light from the scene and destroys it based on a pointer.
+            @remarks
+                Any pointers held to this light after calling this method will be invalid.
+        */
+        virtual void destroyLight(Light* light);
+        /** Removes and destroys all lights in the scene.
+        */
+        virtual void destroyAllLights(void);
+
+        /** Populate a light list with an ordered set of the lights which are closest
+        to the position specified.
+        @remarks
+            Note that since directional lights have no position, they are always considered
+            closer than any point lights and as such will always take precedence. 
+        @par
+            Subclasses of the default SceneManager may wish to take into account other issues
+            such as possible visibility of the light if that information is included in their
+            data structures. This basic scenemanager simply orders by distance, eliminating 
+            those lights which are out of range.
+        @par
+            The number of items in the list max exceed the maximum number of lights supported
+            by the renderer, but the extraneous ones will never be used. In fact the limit will
+            be imposed by Pass::getMaxSimultaneousLights.
+        @param position The position at which to evaluate the list of lights
+        @param radius The bounding radius to test
+        @param destList List to be populated with ordered set of lights; will be cleared by 
+            this method before population.
+        */
+        virtual void _populateLightList(const Vector3& position, Real radius, LightList& destList);
+
+
+        /** Creates an instance of a SceneNode.
+            @remarks
+                Note that this does not add the SceneNode to the scene hierarchy.
+                This method is for convenience, since it allows an instance to
+                be created for which the SceneManager is responsible for
+                allocating and releasing memory, which is convenient in complex
+                scenes.
+            @par
+                To include the returned SceneNode in the scene, use the addChild
+                method of the SceneNode which is to be it's parent.
+            @par
+                Note that this method takes no parameters, and the node created is unnamed (it is
+                actually given a generated name, which you can retrieve if you want).
+                If you wish to create a node with a specific name, call the alternative method
+                which takes a name parameter.
+        */
+        virtual SceneNode* createSceneNode(void);
+
+        /** Creates an instance of a SceneNode with a given name.
+            @remarks
+                Note that this does not add the SceneNode to the scene hierarchy.
+                This method is for convenience, since it allows an instance to
+                be created for which the SceneManager is responsible for
+                allocating and releasing memory, which is convenient in complex
+                scenes.
+            @par
+                To include the returned SceneNode in the scene, use the addChild
+                method of the SceneNode which is to be it's parent.
+            @par
+                Note that this method takes a name parameter, which makes the node easier to
+                retrieve directly again later.
+        */
+        virtual SceneNode* createSceneNode(const String& name);
+
+        /** Destroys a SceneNode with a given name.
+        @remarks
+            This allows you to physically delete an individual SceneNode if you want to.
+            Note that this is not normally recommended, it's better to allow SceneManager
+            to delete the nodes when the scene is cleared.
+        */
+        virtual void destroySceneNode(const String& name);
+
+        /** Gets the SceneNode at the root of the scene hierarchy.
+            @remarks
+                The entire scene is held as a hierarchy of nodes, which
+                allows things like relative transforms, general changes in
+                rendering state etc (See the SceneNode class for more info).
+                In this basic SceneManager class, the application using
+                Ogre is free to structure this hierarchy however it likes,
+                since it has no real significance apart from making transforms
+                relative to each node (more specialised subclasses will
+                provide utility methods for building specific node structures
+                e.g. loading a BSP tree).
+            @par
+                However, in all cases there is only ever one root node of
+                the hierarchy, and this method returns a pointer to it.
+        */
+        virtual SceneNode* getRootSceneNode(void) const;
+
+        /** Retrieves a named SceneNode from the scene graph.
+        @remarks
+            If you chose to name a SceneNode as you created it, or if you
+            happened to make a note of the generated name, you can look it
+            up wherever it is in the scene graph using this method.
+        */
+        virtual SceneNode* getSceneNode(const String& name) const;
+
+        /** Create an Entity (instance of a discrete mesh).
+            @param
+                entityName The name to be given to the entity (must be unique).
+            @param
+                meshName The name of the Mesh it is to be based on (e.g. 'knot.oof'). The
+                mesh will be loaded if it is not already.
+        */
+        virtual Entity* createEntity(const String& entityName, const String& meshName);
+
+        /** Prefab shapes available without loading a model.
+            @note
+                Minimal implementation at present.
+            @todo
+                Add more prefabs (teapots, teapots!!!)
+        */
+        enum PrefabType {
+            PT_PLANE
+        };
+
+        /** Create an Entity (instance of a discrete mesh) from a range of prefab shapes.
+            @param
+                entityName The name to be given to the entity (must be unique).
+            @param
+                ptype The prefab type.
+        */
+        virtual Entity* createEntity(const String& entityName, PrefabType ptype);
+        /** Retrieves a pointer to the named Entity. */
+        virtual Entity* getEntity(const String& name);
+
+        /** Removes & destroys an Entity from the SceneManager.
+            @warning
+                Must only be done if the Entity is not attached
+                to a SceneNode. It may be safer to wait to clear the whole
+                scene if you are unsure use clearScene.
+            @see
+                SceneManager::clearScene
+        */
+        virtual void destroyEntity(Entity* ent);
+
+        /** Removes & destroys an Entity from the SceneManager by name.
+            @warning
+                Must only be done if the Entity is not attached
+                to a SceneNode. It may be safer to wait to clear the whole
+                scene if you are unsure use clearScene.
+            @see
+                SceneManager::clearScene
+        */
+        virtual void destroyEntity(const String& name);
+
+        /** Removes & destroys all Entities.
+            @warning
+                Again, use caution since no Entity must be referred to
+                elsewhere e.g. attached to a SceneNode otherwise a crash
+                is likely. Use clearScene if you are unsure (it clears SceneNode
+                entries too.)
+            @see
+                SceneManager::clearScene
+        */
+        virtual void destroyAllEntities(void);
+
+        /** Create a ManualObject, an object which you populate with geometry
+			manually through a GL immediate-mode style interface.
+        @param
+            name The name to be given to the object (must be unique).
+        */
+        virtual ManualObject* createManualObject(const String& name);
+        /** Retrieves a pointer to the named ManualObject. */
+        virtual ManualObject* getManualObject(const String& name);
+
+        /** Removes & destroys a ManualObject from the SceneManager.
+        */
+        virtual void destroyManualObject(ManualObject* obj);
+		/** Removes & destroys a ManualObject from the SceneManager.
+		*/
+		virtual void destroyManualObject(const String& name);
+		/** Removes & destroys all ManualObjects from the SceneManager.
+		*/
+		virtual void destroyAllManualObjects(void);
+        /** Create a BillboardChain, an object which you can use to render
+            a linked chain of billboards.
+        @param
+            name The name to be given to the object (must be unique).
+        */
+        virtual BillboardChain* createBillboardChain(const String& name);
+        /** Retrieves a pointer to the named BillboardChain. */
+        virtual BillboardChain* getBillboardChain(const String& name);
+
+        /** Removes & destroys a BillboardChain from the SceneManager.
+        */
+        virtual void destroyBillboardChain(BillboardChain* obj);
+		/** Removes & destroys a BillboardChain from the SceneManager.
+		*/
+		virtual void destroyBillboardChain(const String& name);
+		/** Removes & destroys all BillboardChains from the SceneManager.
+		*/
+		virtual void destroyAllBillboardChains(void);		
+        /** Create a RibbonTrail, an object which you can use to render
+            a linked chain of billboards which follows one or more nodes.
+        @param
+            name The name to be given to the object (must be unique).
+        */
+        virtual RibbonTrail* createRibbonTrail(const String& name);
+        /** Retrieves a pointer to the named RibbonTrail. */
+        virtual RibbonTrail* getRibbonTrail(const String& name);
+
+        /** Removes & destroys a RibbonTrail from the SceneManager.
+        */
+        virtual void destroyRibbonTrail(RibbonTrail* obj);
+		/** Removes & destroys a RibbonTrail from the SceneManager.
+		*/
+		virtual void destroyRibbonTrail(const String& name);
+		/** Removes & destroys all RibbonTrails from the SceneManager.
+		*/
+		virtual void destroyAllRibbonTrails(void);		
+
+        /** Creates a particle system based on a template.
+        @remarks
+            This method creates a new ParticleSystem instance based on the named template
+			(defined through ParticleSystemManager::createTemplate) and returns a 
+            pointer to the caller. The caller should not delete this object, it will be freed at system shutdown, 
+            or can be released earlier using the destroyParticleSystem method.
+        @par
+            Each system created from a template takes the template's settings at the time of creation, 
+            but is completely separate from the template from there on. 
+        @par
+            Creating a particle system does not make it a part of the scene. As with other MovableObject
+            subclasses, a ParticleSystem is not rendered until it is attached to a SceneNode. 
+        @par
+            This is probably the more useful particle system creation method since it does not require manual
+            setup of the system. Note that the initial quota is based on the template but may be changed later.
+        @param 
+            name The name to give the new particle system instance.
+        @param 
+            templateName The name of the template to base the new instance on.
+        */
+        virtual ParticleSystem* createParticleSystem(const String& name,
+			const String& templateName);
+        /** Create a blank particle system.
+        @remarks
+            This method creates a new, blank ParticleSystem instance and returns a pointer to it.
+            The caller should not delete this object, it will be freed at system shutdown, or can
+            be released earlier using the destroyParticleSystem method.
+        @par
+            The instance returned from this method won't actually do anything because on creation a
+            particle system has no emitters. The caller should manipulate the instance through it's 
+            ParticleSystem methods to actually create a real particle effect. 
+        @par
+            Creating a particle system does not make it a part of the scene. As with other MovableObject
+            subclasses, a ParticleSystem is not rendered until it is attached to a SceneNode. 
+        @param
+            name The name to give the ParticleSystem.
+        @param 
+            quota The maximum number of particles to allow in this system. 
+        @param
+            resourceGroup The resource group which will be used to load dependent resources
+        */
+        virtual ParticleSystem* createParticleSystem(const String& name,
+			size_t quota = 500, 
+            const String& resourceGroup = ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
+        /** Retrieves a pointer to the named ParticleSystem. */
+        virtual ParticleSystem* getParticleSystem(const String& name);
+
+        /** Removes & destroys a ParticleSystem from the SceneManager.
+        */
+        virtual void destroyParticleSystem(ParticleSystem* obj);
+		/** Removes & destroys a ParticleSystem from the SceneManager.
+		*/
+		virtual void destroyParticleSystem(const String& name);
+		/** Removes & destroys all ParticleSystems from the SceneManager.
+		*/
+		virtual void destroyAllParticleSystems(void);		
+
+		/** Empties the entire scene, inluding all SceneNodes, Entities, Lights, 
+            BillboardSets etc. Cameras are not deleted at this stage since
+            they are still referenced by viewports, which are not destroyed during
+            this process.
+        */
+        virtual void clearScene(void);
+
+        /** Sets the ambient light level to be used for the scene.
+            @remarks
+                This sets the colour and intensity of the ambient light in the scene, i.e. the
+                light which is 'sourceless' and illuminates all objects equally.
+                The colour of an object is affected by a combination of the light in the scene,
+                and the amount of light that object reflects (in this case based on the Material::ambient
+                property).
+            @remarks
+                By default the ambient light in the scene is ColourValue::Black, i.e. no ambient light. This
+                means that any objects rendered with a Material which has lighting enabled (see Material::setLightingEnabled)
+                will not be visible unless you have some dynamic lights in your scene.
+        */
+        void setAmbientLight(const ColourValue& colour);
+
+        /** Returns the ambient light level to be used for the scene.
+        */
+        const ColourValue& getAmbientLight(void) const;
+
+        /** Sets the source of the 'world' geometry, i.e. the large, mainly static geometry
+            making up the world e.g. rooms, landscape etc.
+            @remarks
+                Depending on the type of SceneManager (subclasses will be specialised
+                for particular world geometry types) you have requested via the Root or
+                SceneManagerEnumerator classes, you can pass a filename to this method and it
+                will attempt to load the world-level geometry for use. If you try to load
+                an inappropriate type of world data an exception will be thrown. The default
+                SceneManager cannot handle any sort of world geometry and so will always
+                throw an exception. However subclasses like BspSceneManager can load
+                particular types of world geometry e.g. "q3dm1.bsp".
+        */
+        virtual void setWorldGeometry(const String& filename);
+
+        /** Sets the source of the 'world' geometry, i.e. the large, mainly 
+			static geometry making up the world e.g. rooms, landscape etc.
+            @remarks
+                Depending on the type of SceneManager (subclasses will be 
+				specialised for particular world geometry types) you have 
+				requested via the Root or SceneManagerEnumerator classes, you 
+				can pass a stream to this method and it will attempt to load 
+				the world-level geometry for use. If the manager can only 
+				handle one input format the typeName parameter is not required.
+				The stream passed will be read (and it's state updated). 
+			@param stream Data stream containing data to load
+			@param typeName String identifying the type of world geometry
+				contained in the stream - not required if this manager only 
+				supports one type of world geometry.
+        */
+		virtual void setWorldGeometry(DataStreamPtr& stream, 
+			const String& typeName = StringUtil::BLANK);
+
+        /** Estimate the number of loading stages required to load the named
+            world geometry. 
+        @remarks
+            This method should be overridden by SceneManagers that provide
+            custom world geometry that can take some time to load. They should
+            return from this method a count of the number of stages of progress
+            they can report on whilst loading. During real loading (setWorldGeomtry),
+            they should call ResourceGroupManager::_notifyWorldGeometryProgress exactly
+            that number of times when loading the geometry for real.
+        @note 
+            The default is to return 0, ie to not report progress. 
+        */
+        virtual size_t estimateWorldGeometry(const String& filename) { return 0; }
+
+        /** Estimate the number of loading stages required to load the named
+            world geometry. 
+        @remarks
+			Operates just like the version of this method which takes a
+			filename, but operates on a stream instead. Note that since the
+			stream is updated, you'll need to reset the stream or reopen it
+			when it comes to loading it for real.
+		@param stream Data stream containing data to load
+		@param typeName String identifying the type of world geometry
+			contained in the stream - not required if this manager only 
+			supports one type of world geometry.
+		*/		
+        virtual size_t estimateWorldGeometry(DataStreamPtr& stream, 
+			const String& typeName = StringUtil::BLANK) { return 0; }
+        /** Asks the SceneManager to provide a suggested viewpoint from which the scene should be viewed.
+            @remarks
+                Typically this method returns the origin unless a) world geometry has been loaded using
+                SceneManager::setWorldGeometry and b) that world geometry has suggested 'start' points.
+                If there is more than one viewpoint which the scene manager can suggest, it will always suggest
+                the first one unless the random parameter is true.
+            @param
+                random If true, and there is more than one possible suggestion, a random one will be used. If false
+                the same one will always be suggested.
+            @return
+                On success, true is returned.
+            @par
+                On failiure, false is returned.
+        */
+        virtual ViewPoint getSuggestedViewpoint(bool random = false);
+
+        /** Method for setting a specific option of the Scene Manager. These options are usually
+            specific for a certain implemntation of the Scene Manager class, and may (and probably
+            will) not exist across different implementations.
+            @param
+                strKey The name of the option to set
+            @param
+                pValue A pointer to the value - the size should be calculated by the scene manager
+                based on the key
+            @return
+                On success, true is returned.
+            @par
+                On failiure, false is returned.
+        */
+        virtual bool setOption( const String& strKey, const void* pValue ) { return false; }
+
+        /** Method for getting the value of an implementation-specific Scene Manager option.
+            @param
+                strKey The name of the option
+            @param
+                pDestValue A pointer to a memory location where the value will
+                be copied. Currently, the memory will be allocated by the
+                scene manager, but this may change
+            @return
+                On success, true is returned and pDestValue points to the value of the given
+                option.
+            @par
+                On failiure, false is returned and pDestValue is set to NULL.
+        */
+        virtual bool getOption( const String& strKey, void* pDestValue ) { return false; }
+
+        /** Method for verifying wether the scene manager has an implementation-specific
+            option.
+            @param
+                strKey The name of the option to check for.
+            @return
+                If the scene manager contains the given option, true is returned.
+            @remarks
+                If it does not, false is returned.
+        */
+        virtual bool hasOption( const String& strKey ) const { return false; }
+        /** Method for getting all possible values for a specific option. When this list is too large
+            (i.e. the option expects, for example, a float), the return value will be true, but the
+            list will contain just one element whose size will be set to 0.
+            Otherwise, the list will be filled with all the possible values the option can
+            accept.
+            @param
+                strKey The name of the option to get the values for.
+            @param
+                refValueList A reference to a list that will be filled with the available values.
+            @return
+                On success (the option exists), true is returned.
+            @par
+                On failure, false is returned.
+        */
+        virtual bool getOptionValues( const String& strKey, StringVector& refValueList ) { return false; }
+
+        /** Method for getting all the implementation-specific options of the scene manager.
+            @param
+                refKeys A reference to a list that will be filled with all the available options.
+            @return
+                On success, true is returned. On failiure, false is returned.
+        */
+        virtual bool getOptionKeys( StringVector& refKeys ) { return false; }
+
+        /** Internal method for updating the scene graph ie the tree of SceneNode instances managed by this class.
+            @remarks
+                This must be done before issuing objects to the rendering pipeline, since derived transformations from
+                parent nodes are not updated until required. This SceneManager is a basic implementation which simply
+                updates all nodes from the root. This ensures the scene is up to date but requires all the nodes
+                to be updated even if they are not visible. Subclasses could trim this such that only potentially visible
+                nodes are updated.
+        */
+        virtual void _updateSceneGraph(Camera* cam);
+
+        /** Internal method which parses the scene to find visible objects to render.
+            @remarks
+                If you're implementing a custom scene manager, this is the most important method to
+                override since it's here you can apply your custom world partitioning scheme. Once you
+                have added the appropriate objects to the render queue, you can let the default
+                SceneManager objects _renderVisibleObjects handle the actual rendering of the objects
+                you pick.
+            @par
+                Any visible objects will be added to a rendering queue, which is indexed by material in order
+                to ensure objects with the same material are rendered together to minimise render state changes.
+        */
+        virtual void _findVisibleObjects(Camera* cam, bool onlyShadowCasters);
+
+        /** Internal method for applying animations to scene nodes.
+        @remarks
+            Uses the internally stored AnimationState objects to apply animation to SceneNodes.
+        */
+        virtual void _applySceneAnimations(void);
+
+        /** Sends visible objects found in _findVisibleObjects to the rendering engine.
+        */
+        virtual void _renderVisibleObjects(void);
+
+        /** Prompts the class to send its contents to the renderer.
+            @remarks
+                This method prompts the scene manager to send the
+                contents of the scene it manages to the rendering
+                pipeline, possibly preceded by some sorting, culling
+                or other scene management tasks. Note that this method is not normally called
+                directly by the user application; it is called automatically
+                by the Ogre rendering loop.
+            @param camera Pointer to a camera from whose viewpoint the scene is to
+                be rendered.
+            @param vp The target viewport
+            @param includeOverlays Whether or not overlay objects should be rendered
+        */
+        virtual void _renderScene(Camera* camera, Viewport* vp, bool includeOverlays);
+
+        /** Internal method for queueing the sky objects with the params as 
+            previously set through setSkyBox, setSkyPlane and setSkyDome.
+        */
+        virtual void _queueSkiesForRendering(Camera* cam);
+
+
+
+        /** Notifies the scene manager of its destination render system
+            @remarks
+                Called automatically by RenderSystem::addSceneManager
+                this method simply notifies the manager of the render
+                system to which its output must be directed.
+            @param
+                sys Pointer to the RenderSystem subclass to be used as a render target.
+        */
+        virtual void _setDestinationRenderSystem(RenderSystem* sys);
+
+        /** Enables / disables a 'sky plane' i.e. a plane at constant
+            distance from the camera representing the sky.
+            @remarks
+                You can create sky planes yourself using the standard mesh and
+                entity methods, but this creates a plane which the camera can
+                never get closer or further away from - it moves with the camera.
+                (NB you could create this effect by creating a world plane which
+                was attached to the same SceneNode as the Camera too, but this
+                would only apply to a single camera whereas this plane applies to
+                any camera using this scene manager).
+            @note
+                To apply scaling, scrolls etc to the sky texture(s) you
+                should use the TextureUnitState class methods.
+            @param
+                enable True to enable the plane, false to disable it
+            @param
+                plane Details of the plane, i.e. it's normal and it's
+                distance from the camera.
+            @param
+                materialName The name of the material the plane will use
+            @param
+                scale The scaling applied to the sky plane - higher values
+                mean a bigger sky plane - you may want to tweak this
+                depending on the size of plane.d and the other
+                characteristics of your scene
+            @param
+                tiling How many times to tile the texture across the sky.
+                Applies to all texture layers. If you need finer control use
+                the TextureUnitState texture coordinate transformation methods.
+            @param
+                drawFirst If true, the plane is drawn before all other
+                geometry in the scene, without updating the depth buffer.
+                This is the safest rendering method since all other objects
+                will always appear in front of the sky. However this is not
+                the most efficient way if most of the sky is often occluded
+                by other objects. If this is the case, you can set this
+                parameter to false meaning it draws <em>after</em> all other
+                geometry which can be an optimisation - however you must
+                ensure that the plane.d value is large enough that no objects
+                will 'poke through' the sky plane when it is rendered.
+			@param
+				bow If zero, the plane will be completely flat (like previous
+				versions.  If above zero, the plane will be curved, allowing
+				the sky to appear below camera level.  Curved sky planes are 
+				simular to skydomes, but are more compatable with fog.
+            @param xsegments, ysegments
+                Determines the number of segments the plane will have to it. This
+                is most important when you are bowing the plane, but may also be useful
+                if you need tesselation on the plane to perform per-vertex effects.
+            @param groupName
+                The name of the resource group to which to assign the plane mesh.
+        */
+        virtual void setSkyPlane(
+            bool enable,
+            const Plane& plane, const String& materialName, Real scale = 1000,
+            Real tiling = 10, bool drawFirst = true, Real bow = 0, 
+            int xsegments = 1, int ysegments = 1, 
+            const String& groupName = ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
+
+		/** Return whether a key plane is enabled */
+		virtual bool isSkyPlaneEnabled(void) const { return mSkyPlaneEnabled; }
+
+		/** Get the sky plane node, if enabled. */
+		virtual SceneNode* getSkyPlaneNode(void) { return mSkyPlaneNode; }		
+		/** Get the parameters used to construct the SkyPlane, if any **/
+		virtual SceneManager::SkyPlaneGenParameters getSkyPlaneGenParameters(void) const { return mSkyPlaneGenParameters; }
+
+        /** Enables / disables a 'sky box' i.e. a 6-sided box at constant
+            distance from the camera representing the sky.
+            @remarks
+                You could create a sky box yourself using the standard mesh and
+                entity methods, but this creates a plane which the camera can
+                never get closer or further away from - it moves with the camera.
+                (NB you could create this effect by creating a world box which
+                was attached to the same SceneNode as the Camera too, but this
+                would only apply to a single camera whereas this skybox applies
+                to any camera using this scene manager).
+            @par
+                The material you use for the skybox can either contain layers
+                which are single textures, or they can be cubic textures, i.e.
+                made up of 6 images, one for each plane of the cube. See the
+                TextureUnitState class for more information.
+            @param
+                enable True to enable the skybox, false to disable it
+            @param
+                materialName The name of the material the box will use
+            @param
+                distance Distance in world coorinates from the camera to
+                each plane of the box. The default is normally OK.
+            @param
+                drawFirst If true, the box is drawn before all other
+                geometry in the scene, without updating the depth buffer.
+                This is the safest rendering method since all other objects
+                will always appear in front of the sky. However this is not
+                the most efficient way if most of the sky is often occluded
+                by other objects. If this is the case, you can set this
+                parameter to false meaning it draws <em>after</em> all other
+                geometry which can be an optimisation - however you must
+                ensure that the distance value is large enough that no
+                objects will 'poke through' the sky box when it is rendered.
+            @param
+                orientation Optional parameter to specify the orientation
+                of the box. By default the 'top' of the box is deemed to be
+                in the +y direction, and the 'front' at the -z direction.
+                You can use this parameter to rotate the sky if you want.
+            @param groupName
+                The name of the resource group to which to assign the plane mesh.
+        */
+        virtual void setSkyBox(
+            bool enable, const String& materialName, Real distance = 5000,
+            bool drawFirst = true, const Quaternion& orientation = Quaternion::IDENTITY,
+            const String& groupName = ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
+
+		/** Return whether a skybox is enabled */
+		virtual bool isSkyBoxEnabled(void) const { return mSkyBoxEnabled; }
+
+		/** Get the skybox node, if enabled. */
+		virtual SceneNode* getSkyBoxNode(void) const { return mSkyBoxNode; }
+		
+		/** Get the parameters used to generate the current SKyBox, if any */
+		virtual SceneManager::SkyBoxGenParameters	getSkyBoxGenParameters(void) const { return mSkyBoxGenParameters; }
+        
+		/** Enables / disables a 'sky dome' i.e. an illusion of a curved sky.
+            @remarks
+                A sky dome is actually formed by 5 sides of a cube, but with
+                texture coordinates generated such that the surface appears
+                curved like a dome. Sky domes are appropriate where you need a
+                realistic looking sky where the scene is not going to be
+                'fogged', and there is always a 'floor' of some sort to prevent
+                the viewer looking below the horizon (the distortion effect below
+                the horizon can be pretty horrible, and there is never anyhting
+                directly below the viewer). If you need a complete wrap-around
+                background, use the setSkyBox method instead. You can actually
+                combine a sky box and a sky dome if you want, to give a positional
+                backdrop with an overlayed curved cloud layer.
+            @par
+                Sky domes work well with 2D repeating textures like clouds. You
+                can change the apparant 'curvature' of the sky depending on how
+                your scene is viewed - lower curvatures are better for 'open'
+                scenes like landscapes, whilst higher curvatures are better for
+                say FPS levels where you don't see a lot of the sky at once and
+                the exaggerated curve looks good.
+            @param
+                enable True to enable the skydome, false to disable it
+            @param
+                materialName The name of the material the dome will use
+            @param
+                curvature The curvature of the dome. Good values are
+                between 2 and 65. Higher values are more curved leading to
+                a smoother effect, lower values are less curved meaning
+                more distortion at the horizons but a better distance effect.
+            @param
+                tiling How many times to tile the texture(s) across the
+                dome.
+            @param
+                distance Distance in world coorinates from the camera to
+                each plane of the box the dome is rendered on. The default
+                is normally OK.
+            @param
+                drawFirst If true, the dome is drawn before all other
+                geometry in the scene, without updating the depth buffer.
+                This is the safest rendering method since all other objects
+                will always appear in front of the sky. However this is not
+                the most efficient way if most of the sky is often occluded
+                by other objects. If this is the case, you can set this
+                parameter to false meaning it draws <em>after</em> all other
+                geometry which can be an optimisation - however you must
+                ensure that the distance value is large enough that no
+                objects will 'poke through' the sky when it is rendered.
+            @param
+                orientation Optional parameter to specify the orientation
+                of the dome. By default the 'top' of the dome is deemed to
+                be in the +y direction, and the 'front' at the -z direction.
+                You can use this parameter to rotate the sky if you want.
+            @param groupName
+                The name of the resource group to which to assign the plane mesh.
+        */
+        virtual void setSkyDome(
+            bool enable, const String& materialName, Real curvature = 10,
+            Real tiling = 8, Real distance = 4000, bool drawFirst = true,
+            const Quaternion& orientation = Quaternion::IDENTITY,
+            int xsegments = 16, int ysegments = 16, int ysegments_keep = -1,
+            const String& groupName = ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
+
+		/** Return whether a skydome is enabled */
+		virtual bool isSkyDomeEnabled(void) const { return mSkyDomeEnabled; }
+
+		/** Get the sky dome node, if enabled. */
+		virtual SceneNode* getSkyDomeNode(void) { return mSkyDomeNode; }	
+		
+		/** Get the parameters used to generate the current SkyDome, if any */
+		virtual SceneManager::SkyDomeGenParameters	getSkyDomeGenParameters(void) const { return mSkyDomeGenParameters; }
+		/** Sets the fogging mode applied to the scene.
+            @remarks
+                This method sets up the scene-wide fogging effect. These settings
+                apply to all geometry rendered, UNLESS the material with which it
+                is rendered has it's own fog settings (see Material::setFog).
+            @param
+                mode Set up the mode of fog as described in the FogMode
+                enum, or set to FOG_NONE to turn off.
+            @param
+                colour The colour of the fog. Either set this to the same
+                as your viewport background colour, or to blend in with a
+                skydome or skybox.
+            @param
+                expDensity The density of the fog in FOG_EXP or FOG_EXP2
+                mode, as a value between 0 and 1. The default is 0.001. 
+            @param
+                linearStart Distance in world units at which linear fog starts to
+                encroach. Only applicable if mode is
+                FOG_LINEAR.
+            @param
+                linearEnd Distance in world units at which linear fog becomes completely
+                opaque. Only applicable if mode is
+                FOG_LINEAR.
+        */
+        void setFog(
+            FogMode mode = FOG_NONE, const ColourValue& colour = ColourValue::White,
+            Real expDensity = 0.001, Real linearStart = 0.0, Real linearEnd = 1.0);
+
+        /** Returns the fog mode for the scene.
+        */
+        virtual FogMode getFogMode(void) const;
+
+        /** Returns the fog colour for the scene.
+        */
+        virtual const ColourValue& getFogColour(void) const;
+
+        /** Returns the fog start distance for the scene.
+        */
+        virtual Real getFogStart(void) const;
+
+        /** Returns the fog end distance for the scene.
+        */
+        virtual Real getFogEnd(void) const;
+
+        /** Returns the fog density for the scene.
+        */
+        virtual Real getFogDensity(void) const;
+
+
+        /** Creates a new BillboardSet for use with this scene manager.
+            @remarks
+                This method creates a new BillboardSet which is registered with
+                the SceneManager. The SceneManager will destroy this object when
+                it shuts down or when the SceneManager::clearScene method is
+                called, so the caller does not have to worry about destroying
+                this object (in fact, it definitely should not do this).
+            @par
+                See the BillboardSet documentations for full details of the
+                returned class.
+            @param
+                name The name to give to this billboard set. Must be unique.
+            @param
+                poolSize The initial size of the pool of billboards (see BillboardSet for more information)
+            @see
+                BillboardSet
+        */
+        virtual BillboardSet* createBillboardSet(const String& name, unsigned int poolSize = 20);
+
+        /** Retrieves a pointer to the named BillboardSet.
+        */
+        virtual BillboardSet* getBillboardSet(const String& name);
+
+        /** Removes & destroys an BillboardSet from the SceneManager.
+            @warning
+                Must only be done if the BillboardSet is not attached
+                to a SceneNode. It may be safer to wait to clear the whole
+                scene. If you are unsure, use clearScene.
+        */
+        virtual void destroyBillboardSet(BillboardSet* set);
+
+        /** Removes & destroys an BillboardSet from the SceneManager by name.
+            @warning
+                Must only be done if the BillboardSet is not attached
+                to a SceneNode. It may be safer to wait to clear the whole
+                scene. If you are unsure, use clearScene.
+        */
+        virtual void destroyBillboardSet(const String& name);
+
+        /** Removes & destroys all BillboardSets.
+        @warning
+        Again, use caution since no BillboardSet must be referred to
+        elsewhere e.g. attached to a SceneNode otherwise a crash
+        is likely. Use clearScene if you are unsure (it clears SceneNode
+        entries too.)
+        @see
+        SceneManager::clearScene
+        */
+        virtual void destroyAllBillboardSets(void);
+
+        /** Tells the SceneManager whether it should render the SceneNodes which 
+            make up the scene as well as the objects in the scene.
+        @remarks
+            This method is mainly for debugging purposes. If you set this to 'true',
+            each node will be rendered as a set of 3 axes to allow you to easily see
+            the orientation of the nodes.
+        */
+        virtual void setDisplaySceneNodes(bool display);
+        /** Returns true if all scene nodes axis are to be displayed */
+        virtual bool getDisplaySceneNodes(void) const {return mDisplayNodes;}
+
+        /** Creates an animation which can be used to animate scene nodes.
+        @remarks
+            An animation is a collection of 'tracks' which over time change the position / orientation
+            of Node objects. In this case, the animation will likely have tracks to modify the position
+            / orientation of SceneNode objects, e.g. to make objects move along a path.
+        @par
+            You don't need to use an Animation object to move objects around - you can do it yourself
+            using the methods of the Node in your FrameListener class. However, when you need relatively
+            complex scripted animation, this is the class to use since it will interpolate between
+            keyframes for you and generally make the whole process easier to manage.
+        @par
+            A single animation can affect multiple Node objects (each AnimationTrack affects a single Node).
+            In addition, through animation blending a single Node can be affected by multiple animations,
+            athough this is more useful when performing skeletal animation (see Skeleton::createAnimation).
+        @par
+            Note that whilst it uses the same classes, the animations created here are kept separate from the
+            skeletal animations of meshes (each Skeleton owns those animations).
+        @param name The name of the animation, must be unique within this SceneManager.
+        @param length The total length of the animation.
+        */
+        virtual Animation* createAnimation(const String& name, Real length);
+
+        /** Looks up an Animation object previously created with createAnimation. */
+        virtual Animation* getAnimation(const String& name) const;
+
+        /** Destroys an Animation. 
+        @remarks
+            You should ensure that none of your code is referencing this animation objects since the 
+            memory will be freed.
+        */
+        virtual void destroyAnimation(const String& name);
+
+        /** Removes all animations created using this SceneManager. */
+        virtual void destroyAllAnimations(void);
+
+        /** Create an AnimationState object for managing application of animations.
+        @remarks
+            You can create Animation objects for animating SceneNode obejcts using the
+            createAnimation method. However, in order to actually apply those animations
+            you have to call methods on Node and Animation in a particular order (namely
+            Node::resetToInitialState and Animation::apply). To make this easier and to
+            help track the current time position of animations, the AnimationState object
+            is provided. </p>
+            So if you don't want to control animation application manually, call this method,
+            update the returned object as you like every frame and let SceneManager apply 
+            the animation state for you.
+        @par
+            Remember, AnimationState objects are disabled by default at creation time. 
+            Turn them on when you want them using their setEnabled method.
+        @par
+            Note that any SceneNode affected by this automatic animation will have it's state
+            reset to it's initial position before application of the animation. Unless specifically
+            modified using Node::setInitialState the Node assumes it's initial state is at the
+            origin. If you want the base state of the SceneNode to be elsewhere, make your changes
+            to the node using the standard transform methods, then call setInitialState to 
+            'bake' this reference position into the node.
+        @param animName The name of an animation created already with createAnimation.
+        */
+        virtual AnimationState* createAnimationState(const String& animName);
+
+        /** Retrieves animation state as previously created using createAnimationState */
+        virtual AnimationState* getAnimationState(const String& animName);
+
+        /** Destroys an AnimationState. 
+        @remarks
+            You should ensure that none of your code is referencing this animation 
+            state object since the memory will be freed.
+        */
+        virtual void destroyAnimationState(const String& name);
+
+        /** Removes all animation states created using this SceneManager. */
+        virtual void destroyAllAnimationStates(void);
+
+        /** Manual rendering method, for advanced users only.
+        @remarks
+            This method allows you to send rendering commands through the pipeline on
+            demand, bypassing OGRE's normal world processing. You should only use this if you
+            really know what you're doing; OGRE does lots of things for you that you really should
+            let it do. However, there are times where it may be useful to have this manual interface,
+            for example overlaying something on top of the scene rendered by OGRE.
+        @par
+            Because this is an instant rendering method, timing is important. The best 
+            time to call it is from a RenderTargetListener event handler.
+        @par
+            Don't call this method a lot, it's designed for rare (1 or 2 times per frame) use. 
+            Calling it regularly per frame will cause frame rate drops!
+        @param rend A RenderOperation object describing the rendering op
+        @param pass The Pass to use for this render
+        @param vp Pointer to the viewport to render to
+        @param worldMatrix The transform to apply from object to world space
+        @param viewMatrix The transform to apply from world to view space
+        @param projMatrix The transform to apply from view to screen space
+        @param doBeginEndFrame If true, beginFrame() and endFrame() are called, 
+            otherwise not. You should leave this as false if you are calling
+            this within the main render loop.
+        */
+        virtual void manualRender(RenderOperation* rend, Pass* pass, Viewport* vp, 
+            const Matrix4& worldMatrix, const Matrix4& viewMatrix, const Matrix4& projMatrix, 
+            bool doBeginEndFrame = false) ;
+
+        /** Retrieves the internal render queue, for advanced users only.
+        @remarks
+            The render queue is mainly used internally to manage the scene object 
+			rendering queue, it also exports some methods to allow advanced users 
+			to configure the behavior of rendering process.
+            Most methods provided by RenderQueue are supposed to be used 
+			internally only, you should reference to the RenderQueue API for 
+			more information. Do not access this directly unless you know what 
+			you are doing.
+        */
+        virtual RenderQueue* getRenderQueue(void);
+
+        /** Registers a new RenderQueueListener which will be notified when render queues
+            are processed.
+        */
+        virtual void addRenderQueueListener(RenderQueueListener* newListener);
+
+        /** Removes a listener previously added with addRenderQueueListener. */
+        virtual void removeRenderQueueListener(RenderQueueListener* delListener);
+
+		/** Adds an item to the 'special case' render queue list.
+		@remarks
+			Normally all render queues are rendered, in their usual sequence, 
+			only varying if a RenderQueueListener nominates for the queue to be 
+			repeated or skipped. This method allows you to add a render queue to 
+			a 'special case' list, which varies the behaviour. The effect of this
+			list depends on the 'mode' in which this list is in, which might be
+			to exclude these render queues, or to include them alone (excluding
+			all other queues). This allows you to perform broad selective
+			rendering without requiring a RenderQueueListener.
+		@param qid The identifier of the queue which should be added to the
+			special case list. Nothing happens if the queue is already in the list.
+		*/
+		virtual void addSpecialCaseRenderQueue(uint8 qid);
+		/** Removes an item to the 'special case' render queue list.
+		@see SceneManager::addSpecialCaseRenderQueue
+		@param qid The identifier of the queue which should be removed from the
+			special case list. Nothing happens if the queue is not in the list.
+		*/
+		virtual void removeSpecialCaseRenderQueue(uint8 qid);
+		/** Clears the 'special case' render queue list.
+		@see SceneManager::addSpecialCaseRenderQueue
+		*/
+		virtual void clearSpecialCaseRenderQueues(void);
+		/** Sets the way the special case render queue list is processed.
+		@see SceneManager::addSpecialCaseRenderQueue
+		@param mode The mode of processing
+		*/
+		virtual void setSpecialCaseRenderQueueMode(SpecialCaseRenderQueueMode mode);
+		/** Gets the way the special case render queue list is processed. */
+		virtual SpecialCaseRenderQueueMode getSpecialCaseRenderQueueMode(void);
+		/** Returns whether or not the named queue will be rendered based on the
+			current 'special case' render queue list and mode.
+		@see SceneManager::addSpecialCaseRenderQueue
+		@param qid The identifier of the queue which should be tested
+		@returns true if the queue will be rendered, false otherwise
+		*/
+		virtual bool isRenderQueueToBeProcessed(uint8 qid);
+
+		/** Sets the render queue that the world geometry (if any) this SceneManager
+			renders will be associated with.
+		@remarks
+			SceneManagers which provide 'world geometry' should place it in a 
+			specialised render queue in order to make it possible to enable / 
+			disable it easily using the addSpecialCaseRenderQueue method. Even 
+			if the SceneManager does not use the render queues to render the 
+			world geometry, it should still pick a queue to represent it's manual
+			rendering, and check isRenderQueueToBeProcessed before rendering.
+		@note
+			Setting this may not affect the actual ordering of rendering the
+			world geometry, if the world geometry is being rendered manually
+			by the SceneManager. If the SceneManager feeds world geometry into
+			the queues, however, the ordering will be affected. 
+		*/
+		virtual void setWorldGeometryRenderQueue(uint8 qid);
+		/** Gets the render queue that the world geometry (if any) this SceneManager
+			renders will be associated with.
+		@remarks
+			SceneManagers which provide 'world geometry' should place it in a 
+			specialised render queue in order to make it possible to enable / 
+			disable it easily using the addSpecialCaseRenderQueue method. Even 
+			if the SceneManager does not use the render queues to render the 
+			world geometry, it should still pick a queue to represent it's manual
+			rendering, and check isRenderQueueToBeProcessed before rendering.
+		*/
+		virtual uint8 getWorldGeometryRenderQueue(void);
+
+		/** Allows all bounding boxes of scene nodes to be displayed. */
+		virtual void showBoundingBoxes(bool bShow);
+
+		/** Returns if all bounding boxes of scene nodes are to be displayed */
+		virtual bool getShowBoundingBoxes() const;
+
+        /** Internal method for notifying the manager that a SceneNode is autotracking. */
+        virtual void _notifyAutotrackingSceneNode(SceneNode* node, bool autoTrack);
+
+        
+        /** Creates an AxisAlignedBoxSceneQuery for this scene manager. 
+        @remarks
+            This method creates a new instance of a query object for this scene manager, 
+            for an axis aligned box region. See SceneQuery and AxisAlignedBoxSceneQuery 
+            for full details.
+        @par
+            The instance returned from this method must be destroyed by calling
+            SceneManager::destroyQuery when it is no longer required.
+        @param box Details of the box which describes the region for this query.
+        @param mask The query mask to apply to this query; can be used to filter out
+            certain objects; see SceneQuery for details.
+        */
+        virtual AxisAlignedBoxSceneQuery* 
+            createAABBQuery(const AxisAlignedBox& box, unsigned long mask = 0xFFFFFFFF);
+        /** Creates a SphereSceneQuery for this scene manager. 
+        @remarks
+            This method creates a new instance of a query object for this scene manager, 
+            for a spherical region. See SceneQuery and SphereSceneQuery 
+            for full details.
+        @par
+            The instance returned from this method must be destroyed by calling
+            SceneManager::destroyQuery when it is no longer required.
+        @param sphere Details of the sphere which describes the region for this query.
+        @param mask The query mask to apply to this query; can be used to filter out
+            certain objects; see SceneQuery for details.
+        */
+        virtual SphereSceneQuery* 
+            createSphereQuery(const Sphere& sphere, unsigned long mask = 0xFFFFFFFF);
+        /** Creates a PlaneBoundedVolumeListSceneQuery for this scene manager. 
+        @remarks
+        This method creates a new instance of a query object for this scene manager, 
+        for a region enclosed by a set of planes (normals pointing inwards). 
+        See SceneQuery and PlaneBoundedVolumeListSceneQuery for full details.
+        @par
+        The instance returned from this method must be destroyed by calling
+        SceneManager::destroyQuery when it is no longer required.
+        @param volumes Details of the volumes which describe the region for this query.
+        @param mask The query mask to apply to this query; can be used to filter out
+        certain objects; see SceneQuery for details.
+        */
+        virtual PlaneBoundedVolumeListSceneQuery* 
+            createPlaneBoundedVolumeQuery(const PlaneBoundedVolumeList& volumes, unsigned long mask = 0xFFFFFFFF);
+
+
+        /** Creates a RaySceneQuery for this scene manager. 
+        @remarks
+            This method creates a new instance of a query object for this scene manager, 
+            looking for objects which fall along a ray. See SceneQuery and RaySceneQuery 
+            for full details.
+        @par
+            The instance returned from this method must be destroyed by calling
+            SceneManager::destroyQuery when it is no longer required.
+        @param ray Details of the ray which describes the region for this query.
+        @param mask The query mask to apply to this query; can be used to filter out
+            certain objects; see SceneQuery for details.
+        */
+        virtual RaySceneQuery* 
+            createRayQuery(const Ray& ray, unsigned long mask = 0xFFFFFFFF);
+        //PyramidSceneQuery* createPyramidQuery(const Pyramid& p, unsigned long mask = 0xFFFFFFFF);
+        /** Creates an IntersectionSceneQuery for this scene manager. 
+        @remarks
+            This method creates a new instance of a query object for locating
+            intersecting objects. See SceneQuery and IntersectionSceneQuery
+            for full details.
+        @par
+            The instance returned from this method must be destroyed by calling
+            SceneManager::destroyQuery when it is no longer required.
+        @param mask The query mask to apply to this query; can be used to filter out
+            certain objects; see SceneQuery for details.
+        */
+        virtual IntersectionSceneQuery* 
+            createIntersectionQuery(unsigned long mask = 0xFFFFFFFF);
+
+        /** Destroys a scene query of any type. */
+        virtual void destroyQuery(SceneQuery* query);
+
+        typedef MapIterator<CameraList> CameraIterator;
+        typedef MapIterator<AnimationList> AnimationIterator;
+
+        /** Returns a specialised MapIterator over all cameras in the scene. */
+        CameraIterator getCameraIterator(void) {
+            return CameraIterator(mCameras.begin(), mCameras.end());
+        }
+        /** Returns a specialised MapIterator over all animations in the scene. */
+        AnimationIterator getAnimationIterator(void) {
+            return AnimationIterator(mAnimationsList.begin(), mAnimationsList.end());
+        }
+        /** Returns a specialised MapIterator over all animation states in the scene. */
+        AnimationStateIterator getAnimationStateIterator(void) {
+            return mAnimationStates.getAnimationStateIterator();
+        }
+
+        /** Sets the general shadow technique to be used in this scene.
+        @remarks   
+            There are multiple ways to generate shadows in a scene, and each has 
+            strengths and weaknesses. 
+            <ul><li>Stencil-based approaches can be used to 
+            draw very long, extreme shadows without loss of precision and the 'additive'
+            version can correctly show the shadowing of complex effects like bump mapping
+            because they physically exclude the light from those areas. However, the edges
+            are very sharp and stencils cannot handle transparency, and they involve a 
+            fair amount of CPU work in order to calculate the shadow volumes, especially
+            when animated objects are involved.</li>
+            <li>Texture-based approaches are good for handling transparency (they can, for
+            example, correctly shadow a mesh which uses alpha to represent holes), and they
+            require little CPU overhead, and can happily shadow geometry which is deformed
+            by a vertex program, unlike stencil shadows. However, they have a fixed precision 
+            which can introduce 'jaggies' at long range and have fillrate issues of their own.</li>
+            </ul>
+        @par
+            We support 2 kinds of stencil shadows, and 2 kinds of texture-based shadows, and one
+            simple decal approach. The 2 stencil approaches differ in the amount of multipass work 
+            that is required - the modulative approach simply 'darkens' areas in shadow after the 
+            main render, which is the least expensive, whilst the additive approach has to perform 
+            a render per light and adds the cumulative effect, whcih is more expensive but more 
+            accurate. The texture based shadows both work in roughly the same way, the only difference is
+            that the shadowmap approach is slightly more accurate, but requires a more recent
+            graphics card.
+        @par
+            Note that because mixing many shadow techniques can cause problems, only one technique
+            is supported at once. Also, you should call this method at the start of the 
+            scene setup. 
+        @param technique The shadowing technique to use for the scene.
+        */
+        virtual void setShadowTechnique(ShadowTechnique technique);
+        
+        /** Gets the current shadow technique. */
+        virtual ShadowTechnique getShadowTechnique(void) const { return mShadowTechnique; }
+
+        /** Enables / disables the rendering of debug information for shadows. */
+        virtual void setShowDebugShadows(bool debug) { mDebugShadows = debug; }
+        /** Are debug shadows shown? */
+        virtual bool getShowDebugShadows(void ) const { return mDebugShadows; }
+
+        /** Set the colour used to modulate areas in shadow. 
+        @remarks This is only applicable for shadow techniques which involve 
+            darkening the area in shadow, as opposed to masking out the light. 
+            This colour provided is used as a modulative value to darken the
+            areas.
+        */
+        virtual void setShadowColour(const ColourValue& colour);
+        /** Get the colour used to modulate areas in shadow. 
+        @remarks This is only applicable for shadow techniques which involve 
+        darkening the area in shadow, as opposed to masking out the light. 
+        This colour provided is used as a modulative value to darken the
+        areas.
+        */
+        virtual const ColourValue& getShadowColour(void) const;
+        /** Sets the distance a shadow volume is extruded for a directional light.
+        @remarks
+            Although directional lights are essentially infinite, there are many
+            reasons to limit the shadow extrusion distance to a finite number, 
+            not least of which is compatibility with older cards (which do not
+            support infinite positions), and shadow caster elimination.
+        @par
+            The default value is 10,000 world units. This does not apply to
+            point lights or spotlights, since they extrude up to their 
+            attenuation range.
+        */
+        virtual void setShadowDirectionalLightExtrusionDistance(Real dist); 
+        /** Gets the distance a shadow volume is extruded for a directional light.
+        */
+        virtual Real getShadowDirectionalLightExtrusionDistance(void) const;
+        /** Sets the maximum distance away from the camera that shadows
+        will be visible.
+        @remarks
+        Shadow techniques can be expensive, therefore it is a good idea
+        to limit them to being rendered close to the camera if possible,
+        and to skip the expense of rendering shadows for distance objects.
+        This method allows you to set the distance at which shadows will no
+        longer be rendered.
+        @note
+        Each shadow technique can interpret this subtely differently.
+        For example, one technique may use this to eliminate casters,
+        another might use it to attenuate the shadows themselves.
+        You should tweak this value to suit your chosen shadow technique
+        and scene setup.
+        */
+        virtual void setShadowFarDistance(Real distance);
+        /** Gets the maximum distance away from the camera that shadows
+        will be visible.
+        */
+        virtual Real getShadowFarDistance(void) const
+        { return mShadowFarDist; }
+
+		/** Sets the maximum size of the index buffer used to render shadow
+		 	primitives.
+		@remarks
+			This method allows you to tweak the size of the index buffer used
+			to render shadow primitives (including stencil shadow volumes). The
+			default size is 51,200 entries, which is 100k of GPU memory, or
+			enough to render approximately 17,000 triangles. You can reduce this
+			as long as you do not have any models / world geometry chunks which 
+			could require more than the amount you set.
+		@par
+			The maximum number of triangles required to render a single shadow 
+			volume (including light and dark caps when needed) will be 3x the 
+			number of edges on the light silhouette, plus the number of 
+			light-facing triangles.	On average, half the 
+			triangles will be facing toward the light, but the number of 
+			triangles in the silhouette entirely depends on the mesh - 
+			angular meshes will have a higher silhouette tris/mesh tris
+			ratio than a smooth mesh. You can estimate the requirements for
+			your particular mesh by rendering it alone in a scene with shadows
+			enabled and a single light - rotate it or the light and make a note
+			of how high the triangle count goes (remembering to subtract the 
+			mesh triangle count)
+		@param size The number of indexes; divide this by 3 to determine the
+			number of triangles.
+		*/
+		virtual void setShadowIndexBufferSize(size_t size);
+        /// Get the size of the shadow index buffer
+		virtual size_t getShadowIndexBufferSize(void) const
+		{ return mShadowIndexBufferSize; }
+        /** Set the size of the texture used for texture-based shadows.
+        @remarks
+            The larger the shadow texture, the better the detail on 
+            texture based shadows, but obviously this takes more memory.
+            The default size is 512. Sizes must be a power of 2.
+        */
+        virtual void setShadowTextureSize(unsigned short size);
+        /// Get the size of the texture used for texture based shadows
+        unsigned short getShadowTextureSize(void) const {return mShadowTextureSize; }
+        /** Set the pixel format of the textures used for texture-based shadows.
+        @remarks
+			By default, a colour texture is used (PF_X8R8G8B8) for texture shadows,
+			but if you want to use more advanced texture shadow types you can 
+			alter this. If you do, you will have to also call
+			setShadowTextureCasterMaterial and setShadowTextureReceiverMaterial
+			to provide shader-based materials to use these customised shadow
+			texture formats.
+        */
+        virtual void setShadowTexturePixelFormat(PixelFormat fmt);
+        /// Get the format of the textures used for texture based shadows
+        PixelFormat getShadowTexturePixelFormat(void) const {return mShadowTextureFormat; }
+        /** Set the number of textures allocated for texture-based shadows.
+        @remarks
+            The default number of textures assigned to deal with texture based
+            shadows is 1; however this means you can only have one light casting
+            shadows at the same time. You can increase this number in order to 
+            make this more flexible, but be aware of the texture memory it will use.
+        */
+        virtual void setShadowTextureCount(unsigned short count);
+        /// Get the number of the textures allocated for texture based shadows
+        unsigned short getShadowTextureCount(void) const {return mShadowTextureCount; }
+        /** Sets the size and count of textures used in texture-based shadows. 
+        @remarks
+            @see setShadowTextureSize and setShadowTextureCount for details, this
+            method just allows you to change both at once, which can save on 
+            reallocation if the textures have already been created.
+        */
+        virtual void setShadowTextureSettings(unsigned short size, unsigned short count, 
+			PixelFormat fmt = PF_X8R8G8B8);
+        /** Sets the proportional distance which a texture shadow which is generated from a
+            directional light will be offset into the camera view to make best use of texture space.
+        @remarks
+            When generating a shadow texture from a directional light, an approximation is used
+            since it is not possible to render the entire scene to one texture. 
+            The texture is projected onto an area centred on the camera, and is
+            the shadow far distance * 2 in length (it is square). This wastes
+            a lot of texture space outside the frustum though, so this offset allows
+            you to move the texture in front of the camera more. However, be aware
+            that this can cause a little shadow 'jittering' during rotation, and
+            that if you move it too far then you'll start to get artefacts close 
+            to the camera. The value is represented as a proportion of the shadow
+            far distance, and the default is 0.6.
+        */
+        virtual void setShadowDirLightTextureOffset(Real offset) { mShadowTextureOffset = offset;}
+        /** Sets the proportional distance at which texture shadows begin to fade out.
+        @remarks
+            To hide the edges where texture shadows end (in directional lights)
+            Ogre will fade out the shadow in the distance. This value is a proportional
+            distance of the entire shadow visibility distance at which the shadow
+            begins to fade out. The default is 0.7
+        */
+        virtual void setShadowTextureFadeStart(Real fadeStart) 
+        { mShadowTextureFadeStart = fadeStart; }
+        /** Sets the proportional distance at which texture shadows finish to fading out.
+        @remarks
+        To hide the edges where texture shadows end (in directional lights)
+        Ogre will fade out the shadow in the distance. This value is a proportional
+        distance of the entire shadow visibility distance at which the shadow
+        is completely invisible. The default is 0.9.
+        */
+        virtual void setShadowTextureFadeEnd(Real fadeEnd) 
+        { mShadowTextureFadeEnd = fadeEnd; }
+
+		/** Sets whether or not texture shadows should attempt to self-shadow.
+		@remarks
+			The default implementation of texture shadows uses a fixed-function 
+			colour texture projection approach for maximum compatibility, and 
+			as such cannot support self-shadowing. However, if you decide to 
+			implement a more complex shadowing technique using the 
+			setShadowTextureCasterMaterial and setShadowTextureReceiverMaterial 
+			there is a possibility you may be able to support 
+			self-shadowing (e.g by implementing a shader-based shadow map). In 
+			this case you might want to enable this option.
+		@param selfShadow Whether to attempt self-shadowing with texture shadows
+		*/
+		virtual void setShadowTextureSelfShadow(bool selfShadow); 
+
+		/// Gets whether or not texture shadows attempt to self-shadow.
+		virtual bool getShadowTextureSelfShadow(void) const 
+		{ return mShadowTextureSelfShadow; }
+		/** Sets the default material to use for rendering shadow casters.
+		@remarks
+			By default shadow casters are rendered into the shadow texture using
+			an automatically generated fixed-function pass. This allows basic
+			projective texture shadows, but it's possible to use more advanced
+			shadow techniques by overriding the caster and receiver materials, for
+			example providing vertex and fragment programs to implement shadow
+			maps.
+		@par
+			You can rely on the ambient light in the scene being set to the 
+			requested texture shadow colour, if that's useful. 
+		@note
+			Individual objects may also override the vertex program in
+			your default material if their materials include 
+			shadow_caster_vertex_program_ref shadow_receiver_vertex_program_ref
+			entries, so if you use both make sure they are compatible.
+		@note
+			Only a single pass is allowed in your material, although multiple
+			techniques may be used for hardware fallback.
+		*/
+		virtual void setShadowTextureCasterMaterial(const String& name);
+		/** Sets the default material to use for rendering shadow receivers.
+		@remarks
+			By default shadow receivers are rendered as a post-pass using basic
+			modulation. This allows basic projective texture shadows, but it's 
+			possible to use more advanced shadow techniques by overriding the 
+			caster and receiver materials, for example providing vertex and 
+			fragment programs to implement shadow maps.
+		@par
+			You can rely on texture unit 0 containing the shadow texture, and 
+			for the unit to be set to use projective texturing from the light 
+			(only useful if you're using fixed-function, which is unlikely; 
+			otherwise you should rely on the texture_viewproj_matrix auto binding)
+		@note
+			Individual objects may also override the vertex program in
+			your default material if their materials include 
+			shadow_caster_vertex_program_ref shadow_receiver_vertex_program_ref
+			entries, so if you use both make sure they are compatible.
+		@note
+			Only a single pass is allowed in your material, although multiple
+			techniques may be used for hardware fallback.
+		*/
+		virtual void setShadowTextureReceiverMaterial(const String& name);
+
+		/** Sets whether we should use an inifinite camera far plane
+			when rendering stencil shadows.
+		@remarks
+			Stencil shadow coherency is very reliant on the shadow volume
+			not being clipped by the far plane. If this clipping happens, you
+			get a kind of 'negative' shadow effect. The best way to achieve
+			coherency is to move the far plane of the camera out to infinity,
+			thus preventing the far plane from clipping the shadow volumes.
+			When combined with vertex program extrusion of the volume to 
+			infinity, which	Ogre does when available, this results in very
+			robust shadow volumes. For this reason, when you enable stencil 
+			shadows, Ogre automatically changes your camera settings to 
+			project to infinity if the card supports it. You can disable this
+			behaviour if you like by calling this method; although you can 
+			never enable infinite projection if the card does not support it.
+		@par	
+			If you disable infinite projection, or it is not available, 
+			you need to be far more careful with your light attenuation /
+			directional light extrusion distances to avoid clipping artefacts
+			at the far plane.
+		@note
+			Recent cards will generally support infinite far plane projection.
+			However, we have found some cases where they do not, especially
+			on Direct3D. There is no standard capability we can check to 
+			validate this, so we use some heuristics based on experience:
+			<UL>
+			<LI>OpenGL always seems to support it no matter what the card</LI>
+			<LI>Direct3D on non-vertex program capable systems (including 
+			vertex program capable cards on Direct3D7) does not
+			support it</LI>
+			<LI>Direct3D on GeForce3 and GeForce4 Ti does not seem to support
+			infinite projection<LI>
+			</UL>
+			Therefore in the RenderSystem implementation, we may veto the use
+			of an infinite far plane based on these heuristics. 
+		*/
+        virtual void setShadowUseInfiniteFarPlane(bool enable) {
+            mShadowUseInfiniteFarPlane = enable; }
+
+		/** Is there a stencil shadow based shadowing technique in use? */
+		virtual bool isShadowTechniqueStencilBased(void) const 
+		{ return (mShadowTechnique & SHADOWDETAILTYPE_STENCIL) != 0; }
+		/** Is there a texture shadow based shadowing technique in use? */
+		virtual bool isShadowTechniqueTextureBased(void) const 
+		{ return (mShadowTechnique & SHADOWDETAILTYPE_TEXTURE) != 0; }
+		/** Is there a modulative shadowing technique in use? */
+		virtual bool isShadowTechniqueModulative(void) const 
+		{ return (mShadowTechnique & SHADOWDETAILTYPE_MODULATIVE) != 0; }
+		/** Is there an additive shadowing technique in use? */
+		virtual bool isShadowTechniqueAdditive(void) const 
+		{ return (mShadowTechnique & SHADOWDETAILTYPE_ADDITIVE) != 0; }
+		/** Is there any shadowing technique in use? */
+		virtual bool isShadowTechniqueInUse(void) const 
+		{ return mShadowTechnique != SHADOWTYPE_NONE; }
+
+		/** Add a shadow listener which will get called back on shadow
+			events.
+		*/
+		virtual void addShadowListener(ShadowListener* s);
+		/** Remove a shadow listener
+		*/
+		virtual void removeShadowListener(ShadowListener* s);
+
+		/** Creates a StaticGeometry instance suitable for use with this
+			SceneManager.
+		@remarks
+			StaticGeometry is a way of batching up geometry into a more 
+			efficient form at the expense of being able to move it. Please 
+			read the StaticGeometry class documentation for full information.
+		@param name The name to give the new object
+		@returns The new StaticGeometry instance
+		*/
+		virtual StaticGeometry* createStaticGeometry(const String& name);
+		/** Retrieve a previously created StaticGeometry instance. */
+		virtual StaticGeometry* getStaticGeometry(const String& name) const;
+		/** Remove & destroy a StaticGeometry instance. */
+		virtual void destroyStaticGeometry(StaticGeometry* geom);
+		/** Remove & destroy a StaticGeometry instance. */
+		virtual void destroyStaticGeometry(const String& name);
+		/** Remove & destroy all StaticGeometry instances. */
+		virtual void destroyAllStaticGeometry(void);
+
+
+		/** Create a movable object of the type specified.
+		@remarks
+			This is the generalised form of MovableObject creation where you can
+			create a MovableObject of any specialised type generically, including
+			any new types registered using plugins.
+		@param name The name to give the object. Must be unique within type.
+		@param typeName The type of object to create
+		@param params Optional name/value pair list to give extra parameters to
+			the created object.
+		*/
+		virtual MovableObject* createMovableObject(const String& name, 
+			const String& typeName, const NameValuePairList* params = 0);
+		/** Destroys a MovableObject with the name specified, of the type specified.
+		@remarks
+			The MovableObject will automatically detach itself from any nodes
+			on destruction.
+		*/
+		virtual void destroyMovableObject(const String& name, const String& typeName);
+		/** Destroys a MovableObject.
+		@remarks
+			The MovableObject will automatically detach itself from any nodes
+			on destruction.
+		*/
+		virtual void destroyMovableObject(MovableObject* m);
+		/** Destroy all MovableObjects of a given type. */
+		virtual void destroyAllMovableObjectsByType(const String& typeName);
+		/** Destroy all MovableObjects. */
+		virtual void destroyAllMovableObjects(void);
+		/** Get a reference to a previously created MovableObject. */
+		virtual MovableObject* getMovableObject(const String& name, const String& typeName);
+		typedef MapIterator<MovableObjectMap> MovableObjectIterator;
+		/** Get an iterator over all MovableObect instances of a given type. */
+		virtual MovableObjectIterator getMovableObjectIterator(const String& typeName);
+		/** Inject a MovableObject instance created externally.
+		@remarks
+			This method 'injects' a MovableObject instance created externally into
+			the MovableObject instance registry held in the SceneManager. You
+			might want to use this if you have a MovableObject which you don't
+			want to register a factory for; for example a MovableObject which 
+			cannot be generally constructed by clients. 
+		@note
+			It is important that the MovableObject has a unique name for the type,
+			and that its getMovableType() method returns a proper type name.
+		*/
+		virtual void injectMovableObject(MovableObject* m);
+		/** Extract a previously injected MovableObject.
+		@remarks
+			Essentially this does the same as destroyMovableObject, but only
+			removes the instance from the internal lists, it does not attempt
+			to destroy it.
+		*/
+		virtual void extractMovableObject(const String& name, const String& typeName);
+		/** Extract a previously injected MovableObject.
+		@remarks
+			Essentially this does the same as destroyMovableObject, but only
+			removes the instance from the internal lists, it does not attempt
+			to destroy it.
+		*/
+		virtual void extractMovableObject(MovableObject* m);
+		/** Extract all injected MovableObjects of a given type.
+		@remarks
+			Essentially this does the same as destroyAllMovableObjectsByType, 
+			but only removes the instances from the internal lists, it does not 
+			attempt to destroy them.
+		*/
+		virtual void extractAllMovableObjectsByType(const String& typeName);
+
+		/** Sets a mask which is bitwise 'and'ed with objects own visibility masks
+			to determine if the object is visible.
+		*/
+		virtual void setVisibilityMask(uint32 vmask) { mVisibilityMask = vmask; }
+
+		/** Gets a mask which is bitwise 'and'ed with objects own visibility masks
+			to determine if the object is visible.
+		*/
+		virtual uint32 getVisibilityMask(void) { return mVisibilityMask; }
+
+		/** Sets whether the SceneManager should search for visible objects, or
+            whether they are being manually handled.
+        @remarks
+            This is an advanced function, you should not use this unless you know
+            what you are doing.
+		*/
+		virtual void setFindVisibleObjects(bool find) { mFindVisibleObjects = find; }
+
+		/** Gets whether the SceneManager should search for visible objects, or
+            whether they are being manually handled.
+ 		*/
+		virtual bool getFindVisibleObjects(void) { return mFindVisibleObjects; }
+
+		/** Render something as if it came from the current queue.
+			@param pass		Material pass to use for setting up this quad.
+			@param rend		Renderable to render
+		 */
+		virtual void _injectRenderWithPass(Pass *pass, Renderable *rend);
+
+		/** Indicates to the SceneManager whether it should suppress changing
+			the RenderSystem states when rendering objects.
+		@remarks
+			This method allows you to tell the SceneManager not to change any
+			RenderSystem state until you tell it to. This method is only 
+			intended for advanced use, don't use it if you're unsure of the 
+			effect. The only RenderSystems calls made are to set the world 
+			matrix for each object (note - view an projection matrices are NOT
+			SET - they are under your control) and to render the object; it is up to 
+			the caller to do everything else, including enabling any vertex / 
+			fragment programs and updating their parameter state, and binding
+			parameters to the RenderSystem.
+		@note
+			Calling this implicitly disables shadow processing since no shadows
+			can be rendered without changing state.
+		@param suppress If true, no RenderSystem state changes will be issued
+			until this method is called again with a parameter of false.
+		*/
+		virtual void _suppressRenderStateChanges(bool suppress);
+		
+		/** Are render state changes suppressed? 
+		@see _suppressRenderStateChanges
+		*/
+		virtual bool _areRenderStateChangesSuppressed(void) const
+		{ return mSuppressRenderStateChanges; }
+
+        /** Internal method for setting up the renderstate for a rendering pass.
+            @param pass The Pass details to set.
+			@param evenIfSuppressed Sets the pass details even if render state
+				changes are suppressed; if you are using this to manually set state
+				when render state changes are suppressed, you should set this to 
+				true.
+            @returns
+                A Pass object that was used instead of the one passed in, can
+                happen when rendering shadow passes
+        */
+        virtual const Pass* _setPass(const Pass* pass, bool evenIfSuppressed = false);
+
+
+		/** Indicates to the SceneManager whether it should suppress the 
+			active shadow rendering technique until told otherwise.
+		@remarks
+			This is a temporary alternative to setShadowTechnique to suppress
+			the rendering of shadows and forcing all processing down the 
+			standard rendering path. This is intended for internal use only.
+		@param suppress If true, no shadow rendering will occur until this
+			method is called again with a parameter of false.
+		*/
+		virtual void _suppressShadows(bool suppress); 
+
+		/** Are shadows suppressed? 
+		@see _suppressShadows
+		*/
+		virtual bool _areShadowsSuppressed(void) const
+		{ return mSuppressShadows; }
+
+		/** Render the objects in a given queue group 
+		@remarks You should only call this from a RenderQueueInvocation implementation
+		*/
+		virtual void _renderQueueGroupObjects(RenderQueueGroup* group, 
+			QueuedRenderableCollection::OrganisationMode om);
+
+		/** Get the rendersystem subclass to which the output of this Scene Manager
+			gets sent
+		*/
+		RenderSystem *getDestinationRenderSystem();
+
+#ifdef GAMETOOLS_ILLUMINATION_MODULE 
+		public:
+			void prepareRenderQueue_Wrap(){this->prepareRenderQueue();}
+#endif
+
+    };
+
+    /** Default implementation of IntersectionSceneQuery. */
+    class _OgreExport DefaultIntersectionSceneQuery : 
+        public IntersectionSceneQuery
+    {
+    public:
+        DefaultIntersectionSceneQuery(SceneManager* creator);
+        ~DefaultIntersectionSceneQuery();
+
+        /** See IntersectionSceneQuery. */
+        void execute(IntersectionSceneQueryListener* listener);
+    };
+
+    /** Default implementation of RaySceneQuery. */
+	class _OgreExport DefaultRaySceneQuery : public RaySceneQuery
+    {
+    public:
+        DefaultRaySceneQuery(SceneManager* creator);
+        ~DefaultRaySceneQuery();
+
+        /** See RayScenQuery. */
+        void execute(RaySceneQueryListener* listener);
+    };
+    /** Default implementation of SphereSceneQuery. */
+	class _OgreExport DefaultSphereSceneQuery : public SphereSceneQuery
+    {
+    public:
+        DefaultSphereSceneQuery(SceneManager* creator);
+        ~DefaultSphereSceneQuery();
+
+        /** See SceneQuery. */
+        void execute(SceneQueryListener* listener);
+    };
+    /** Default implementation of PlaneBoundedVolumeListSceneQuery. */
+    class _OgreExport DefaultPlaneBoundedVolumeListSceneQuery : public PlaneBoundedVolumeListSceneQuery
+    {
+    public:
+        DefaultPlaneBoundedVolumeListSceneQuery(SceneManager* creator);
+        ~DefaultPlaneBoundedVolumeListSceneQuery();
+
+        /** See SceneQuery. */
+        void execute(SceneQueryListener* listener);
+    };
+    /** Default implementation of AxisAlignedBoxSceneQuery. */
+	class _OgreExport DefaultAxisAlignedBoxSceneQuery : public AxisAlignedBoxSceneQuery
+    {
+    public:
+        DefaultAxisAlignedBoxSceneQuery(SceneManager* creator);
+        ~DefaultAxisAlignedBoxSceneQuery();
+
+        /** See RayScenQuery. */
+        void execute(SceneQueryListener* listener);
+    };
+    
+
+	/// Bitmask containing scene types
+	typedef uint16 SceneTypeMask;
+
+	/** Classification of a scene to allow a decision of what type of
+	SceenManager to provide back to the application.
+	*/
+	enum SceneType
+	{
+		ST_GENERIC = 1,
+		ST_EXTERIOR_CLOSE = 2,
+		ST_EXTERIOR_FAR = 4,
+		ST_EXTERIOR_REAL_FAR = 8,
+		ST_INTERIOR = 16
+	};
+
+	/** Structure containing information about a scene manager. */
+	struct SceneManagerMetaData
+	{
+		/// A globally unique string identifying the scene manager type
+		String typeName;
+		/// A text description of the scene manager
+		String description;
+		/// A mask describing which sorts of scenes this manager can handle
+		SceneTypeMask sceneTypeMask;
+		/// Flag indicating whether world geometry is supported
+		bool worldGeometrySupported;
+	};
+
+
+
+	/** Class which will create instances of a given SceneManager. */
+	class _OgreExport SceneManagerFactory
+	{
+	protected:
+		mutable SceneManagerMetaData mMetaData;
+		mutable bool mMetaDataInit;
+		/// Internal method to initialise the metadata, must be implemented
+		virtual void initMetaData(void) const = 0;
+	public:
+		SceneManagerFactory() : mMetaDataInit(true) {}
+		virtual ~SceneManagerFactory() {}
+		/** Get information about the SceneManager type created by this factory. */
+		virtual const SceneManagerMetaData& getMetaData(void) const 
+		{
+			if (mMetaDataInit)
+			{
+				initMetaData();
+				mMetaDataInit = false;
+			}
+			return mMetaData; 
+		}
+		/** Create a new instance of a SceneManager.
+		@remarks
+		Don't call directly, use SceneManagerEnumerator::createSceneManager.
+		*/
+		virtual SceneManager* createInstance(const String& instanceName) = 0;
+		/** Destroy an instance of a SceneManager. */
+		virtual void destroyInstance(SceneManager* instance) = 0;
+
+	};
+
+
+
+} // Namespace
+
+
+
+#endif
Index: OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/OgreBillboard.h
===================================================================
--- OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/OgreBillboard.h	(revision 768)
+++ OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/OgreBillboard.h	(revision 768)
@@ -0,0 +1,219 @@
+/*
+-----------------------------------------------------------------------------
+This source file is part of OGRE
+    (Object-oriented Graphics Rendering Engine)
+For the latest info, see http://www.ogre3d.org/
+
+Copyright (c) 2000-2005 The OGRE Team
+Also see acknowledgements in Readme.html
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+#ifndef __Billboard_H__
+#define __Billboard_H__
+
+#include "OgrePrerequisites.h"
+
+#include "OgreVector3.h"
+#include "OgreColourValue.h"
+#include "OgreCommon.h"
+
+namespace Ogre {
+
+    /** A billboard is a primitive which always faces the camera in every frame.
+        @remarks
+            Billboards can be used for special effects or some other trickery which requires the
+            triangles to always facing the camera no matter where it is. Ogre groups billboards into
+            sets for efficiency, so you should never create a billboard on it's own (it's ok to have a
+            set of one if you need it).
+        @par
+            Billboards have their geometry generated every frame depending on where the camera is. It is most
+            beneficial for all billboards in a set to be identically sized since Ogre can take advantage of this and
+            save some calculations - useful when you have sets of hundreds of billboards as is possible with special
+            effects. You can deviate from this if you wish (example: a smoke effect would probably have smoke puffs
+            expanding as they rise, so each billboard will legitimately have it's own size) but be aware the extra
+            overhead this brings and try to avoid it if you can.
+        @par
+            Billboards are just the mechanism for rendering a range of effects such as particles. It is other classes
+            which use billboards to create their individual effects, so the methods here are quite generic.
+        @see
+            BillboardSet
+    */
+
+    class _OgreExport Billboard
+    {
+        friend class BillboardSet;
+        friend class BillboardParticleRenderer;
+
+#ifdef GAMETOOLS_ILLUMINATION_MODULE
+		friend class SpriteSet;
+        friend class SpriteParticleRenderer;
+#endif
+
+    protected:
+        bool mOwnDimensions;
+        bool mUseTexcoordRect;
+        uint16 mTexcoordIndex;      // index into the BillboardSet array of texture coordinates
+        FloatRect mTexcoordRect;    // individual texture coordinates
+        Real mWidth;
+        Real mHeight;
+    public:
+        // Note the intentional public access to main internal variables used at runtime
+        // Forcing access via get/set would be too costly for 000's of billboards
+        Vector3 mPosition;
+        // Normalised direction vector
+        Vector3 mDirection;
+        BillboardSet* mParentSet;
+        ColourValue mColour;
+        Radian mRotation;
+
+        /** Default constructor.
+        */
+        Billboard();
+
+        /** Default destructor.
+        */
+        ~Billboard();
+
+        /** Normal constructor as called by BillboardSet.
+        */
+        Billboard(const Vector3& position, BillboardSet* owner, const ColourValue& colour = ColourValue::White);
+
+        /** Get the rotation of the billboard.
+            @remarks
+                This rotation is relative to the center of the billboard.
+        */
+        const Radian& getRotation(void) const { return mRotation; }
+
+        /** Set the rotation of the billboard.
+            @remarks
+                This rotation is relative to the center of the billboard.
+        */
+        void setRotation(const Radian& rotation);
+
+        /** Set the position of the billboard.
+            @remarks
+                This position is relative to a point on the quad which is the billboard. Depending on the BillboardSet,
+                this may be the center of the quad, the top-left etc. See BillboardSet::setBillboardOrigin for more info.
+        */
+        void setPosition(const Vector3& position);
+
+        /** Set the position of the billboard.
+            @remarks
+                This position is relative to a point on the quad which is the billboard. Depending on the BillboardSet,
+                this may be the center of the quad, the top-left etc. See BillboardSet::setBillboardOrigin for more info.
+        */
+        void setPosition(Real x, Real y, Real z);
+
+        /** Get the position of the billboard.
+            @remarks
+                This position is relative to a point on the quad which is the billboard. Depending on the BillboardSet,
+                this may be the center of the quad, the top-left etc. See BillboardSet::setBillboardOrigin for more info.
+        */
+        const Vector3& getPosition(void) const;
+
+        /** Sets the width and height for this billboard.
+            @remarks
+                Note that it is most efficient for every billboard in a BillboardSet to have the same dimensions. If you
+                choose to alter the dimensions of an individual billboard the set will be less efficient. Do not call
+                this method unless you really need to have different billboard dimensions within the same set. Otherwise
+                just call the BillboardSet::setDefaultDimensions method instead.
+        */
+        void setDimensions(Real width, Real height);
+
+        /** Resets this Billboard to use the parent BillboardSet's dimensions instead of it's own. */
+        void resetDimensions(void) { mOwnDimensions = false; }
+        /** Sets the colour of this billboard.
+            @remarks
+                Billboards can be tinted based on a base colour. This allows variations in colour irresective of the
+                base colour of the material allowing more varied billboards. The default colour is white.
+                The tinting is effected using vertex colours.
+        */
+        void setColour(const ColourValue& colour);
+
+        /** Gets the colour of this billboard.
+        */
+        const ColourValue& getColour(void) const;
+
+        /** Returns true if this billboard deviates from the BillboardSet's default dimensions (i.e. if the
+            Billboard::setDimensions method has been called for this instance).
+            @see
+                Billboard::setDimensions
+        */
+        bool hasOwnDimensions(void) const;
+
+        /** Retrieves the billboard's personal width, if hasOwnDimensions is true. */
+        Real getOwnWidth(void) const;
+
+        /** Retrieves the billboard's personal width, if hasOwnDimensions is true. */
+        Real getOwnHeight(void) const;
+
+        /** Internal method for notifying the billboard of it's owner.
+        */
+        void _notifyOwner(BillboardSet* owner);
+
+        /** Returns true if this billboard use individual texture coordinate rect (i.e. if the 
+            Billboard::setTexcoordRect method has been called for this instance), or returns
+            false if use texture coordinates defined in the parent BillboardSet's texture
+            coordinates array (i.e. if the Billboard::setTexcoordIndex method has been called
+            for this instance).
+            @see
+                Billboard::setTexcoordIndex()
+                Billboard::setTexcoordRect()
+        */
+        bool isUseTexcoordRect(void) const { return mUseTexcoordRect; }
+
+        /** setTexcoordIndex() sets which texture coordinate rect this billboard will use 
+            when rendering. The parent billboard set may contain more than one, in which 
+            case a billboard can be textured with different pieces of a larger texture 
+            sheet very efficiently.
+          @see
+            BillboardSet::setTextureCoords()
+          */
+        void setTexcoordIndex(uint16 texcoordIndex);
+
+        /** getTexcoordIndex() returns the previous value set by setTexcoordIndex(). 
+            The default value is 0, which is always a valid texture coordinate set.
+            @remarks
+                This value is useful only when isUseTexcoordRect return false.
+          */
+        uint16 getTexcoordIndex(void) const { return mTexcoordIndex; }
+
+        /** setTexcoordRect() sets the individual texture coordinate rect of this billboard
+            will use when rendering. The parent billboard set may contain more than one, in
+            which case a billboard can be textured with different pieces of a larger texture
+            sheet very efficiently.
+        */
+        void setTexcoordRect(const FloatRect& texcoordRect);
+
+        /** setTexcoordRect() sets the individual texture coordinate rect of this billboard
+            will use when rendering. The parent billboard set may contain more than one, in
+            which case a billboard can be textured with different pieces of a larger texture
+            sheet very efficiently.
+        */
+        void setTexcoordRect(Real u0, Real v0, Real u1, Real v1);
+
+        /** getTexcoordRect() returns the previous value set by setTexcoordRect(). 
+            @remarks
+                This value is useful only when isUseTexcoordRect return true.
+        */
+        const FloatRect& getTexcoordRect(void) const { return mTexcoordRect; }
+    };
+
+}
+
+#endif
Index: OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/src/OgreTextureUnitState.cpp
===================================================================
--- OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/src/OgreTextureUnitState.cpp	(revision 768)
+++ OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/src/OgreTextureUnitState.cpp	(revision 768)
@@ -0,0 +1,1168 @@
+/*
+-----------------------------------------------------------------------------
+This source file is part of OGRE
+    (Object-oriented Graphics Rendering Engine)
+For the latest info, see http://ogre.sourceforge.net/
+
+Copyright (c) 2000-2005 The OGRE Team
+Also see acknowledgements in Readme.html
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+#include "OgreStableHeaders.h"
+
+#include "OgreTextureUnitState.h"
+#include "OgrePass.h"
+#include "OgreMaterialManager.h"
+#include "OgreControllerManager.h"
+#include "OgreLogManager.h"
+#include "OgreException.h"
+#include "OgreTextureManager.h"
+
+namespace Ogre {
+
+    //-----------------------------------------------------------------------
+    TextureUnitState::TextureUnitState(Pass* parent)
+        : mParent(parent)
+    {
+        mIsBlank = true;
+		mIsAlpha = false;
+        colourBlendMode.blendType = LBT_COLOUR;
+        setColourOperation(LBO_MODULATE);
+        setTextureAddressingMode(TAM_WRAP);
+        mBorderColour = ColourValue::Black;
+
+        alphaBlendMode.operation = LBX_MODULATE;
+        alphaBlendMode.blendType = LBT_ALPHA;
+        alphaBlendMode.source1 = LBS_TEXTURE;
+        alphaBlendMode.source2 = LBS_CURRENT;
+		
+		//default filtering
+		mMinFilter = FO_LINEAR;
+		mMagFilter = FO_LINEAR;
+		mMipFilter = FO_POINT;
+		mMaxAniso = MaterialManager::getSingleton().getDefaultAnisotropy();
+        mIsDefaultAniso = true;
+        mIsDefaultFiltering = true;
+
+		mUMod = mVMod = 0;
+        mUScale = mVScale = 1;
+        mRotate = 0;
+        mTexModMatrix = Matrix4::IDENTITY;
+        mRecalcTexMatrix = false;
+
+        mAnimDuration = 0;
+        mAnimController = 0;
+        mCubic = false;
+        mTextureType = TEX_TYPE_2D;
+		mTextureSrcMipmaps = -1;
+        mTextureCoordSetIndex = 0;
+
+        mCurrentFrame = 0;
+
+        mParent->_dirtyHash();
+
+		#ifdef GAMETOOLS_ILLUMINATION_MODULE
+			isVT = false;
+		#endif
+
+    }
+
+    //-----------------------------------------------------------------------
+    TextureUnitState::TextureUnitState(Pass* parent, const TextureUnitState& oth )
+    {
+        mParent = parent;
+        mAnimController = 0;
+        *this = oth;
+		#ifdef GAMETOOLS_ILLUMINATION_MODULE
+			isVT = false;
+		#endif
+    }
+
+    //-----------------------------------------------------------------------
+    TextureUnitState::TextureUnitState( Pass* parent, const String& texName, unsigned int texCoordSet)
+        :mParent(parent)
+    {
+        mIsBlank = true;
+		mIsAlpha = false;
+        colourBlendMode.blendType = LBT_COLOUR;
+        setColourOperation(LBO_MODULATE);
+        setTextureAddressingMode(TAM_WRAP);
+        mBorderColour = ColourValue::Black;
+
+        alphaBlendMode.operation = LBX_MODULATE;
+        alphaBlendMode.blendType = LBT_ALPHA;
+        alphaBlendMode.source1 = LBS_TEXTURE;
+        alphaBlendMode.source2 = LBS_CURRENT;
+
+		//default filtering && anisotropy
+		mMinFilter = FO_LINEAR;
+		mMagFilter = FO_LINEAR;
+		mMipFilter = FO_POINT;
+		mMaxAniso = MaterialManager::getSingleton().getDefaultAnisotropy();
+        mIsDefaultAniso = true;
+        mIsDefaultFiltering = true;
+
+		mUMod = mVMod = 0;
+        mUScale = mVScale = 1;
+        mRotate = 0;
+        mAnimDuration = 0;
+        mAnimController = 0;
+        mTexModMatrix = Matrix4::IDENTITY;
+        mRecalcTexMatrix = false;
+
+        mCubic = false;
+        mTextureType = TEX_TYPE_2D;
+        mTextureCoordSetIndex = 0;
+
+        setTextureName(texName);
+        setTextureCoordSet(texCoordSet);
+
+        mParent->_dirtyHash();
+
+		#ifdef GAMETOOLS_ILLUMINATION_MODULE
+			isVT = false;
+		#endif
+
+    }
+    //-----------------------------------------------------------------------
+    TextureUnitState::~TextureUnitState()
+    {
+        // Unload ensure all controllers destroyed
+        _unload();
+    }
+    //-----------------------------------------------------------------------
+    TextureUnitState & TextureUnitState::operator = ( 
+        const TextureUnitState &oth )
+    {
+        assert(mAnimController == 0);
+        assert(mEffects.empty());
+
+        // copy basic members (int's, real's)
+        memcpy( this, &oth, (uchar *)(&oth.mFrames) - (uchar *)(&oth) );
+        // copy complex members
+        mFrames  = oth.mFrames;
+        mName    = oth.mName;
+        mEffects = oth.mEffects;
+
+        mTextureNameAlias = oth.mTextureNameAlias;
+
+        // Can't sharing controllers with other TUS, reset to null to avoid potential bug.
+        for (EffectMap::iterator j = mEffects.begin(); j != mEffects.end(); ++j)
+        {
+            j->second.controller = 0;
+        }
+
+        // Load immediately if Material loaded
+        if (isLoaded())
+        {
+            _load();
+            // Tell parent to recalculate hash
+            mParent->_dirtyHash();
+        }
+
+        return *this;
+    }
+    //-----------------------------------------------------------------------
+    const String& TextureUnitState::getTextureName(void) const
+    {
+        // Return name of current frame
+        if (mCurrentFrame < mFrames.size())
+            return mFrames[mCurrentFrame];
+        else
+            return StringUtil::BLANK;
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setTextureName( const String& name, TextureType texType, int mipmaps, bool alpha)
+    {
+        if (texType == TEX_TYPE_CUBE_MAP)
+        {
+            // delegate to cubic texture implementation
+            setCubicTextureName(name, true);
+        }
+        else
+        {
+            mFrames.resize(1);
+            mFrames[0] = name;
+            mCurrentFrame = 0;
+            mCubic = false;
+            mTextureType = texType;
+			mTextureSrcMipmaps = mipmaps;
+            if (alpha)
+                mIsAlpha = alpha;
+            if (name == "")
+            {
+                mIsBlank = true;
+                return;
+            }
+            
+            // Load immediately ?
+            if (isLoaded())
+            {
+                _load(); // reload
+                // Tell parent to recalculate hash
+                mParent->_dirtyHash();
+            }
+        }
+
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setCubicTextureName( const String& name, bool forUVW)
+    {
+        if (forUVW)
+        {
+            setCubicTextureName(&name, forUVW);
+        }
+        else
+        {
+            String ext;
+            String suffixes[6] = {"_fr", "_bk", "_lf", "_rt", "_up", "_dn"};
+            String baseName;
+            String fullNames[6];
+
+
+            size_t pos = name.find_last_of(".");
+            baseName = name.substr(0, pos);
+            ext = name.substr(pos);
+
+            for (int i = 0; i < 6; ++i)
+            {
+                fullNames[i] = baseName + suffixes[i] + ext;
+            }
+
+            setCubicTextureName(fullNames, forUVW);
+        }
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setCubicTextureName(const String* const names, bool forUVW)
+    {
+        mFrames.resize(forUVW ? 1 : 6);
+        mCurrentFrame = 0;
+        mCubic = true;
+        mTextureType = forUVW ? TEX_TYPE_CUBE_MAP : TEX_TYPE_2D;
+
+        for (unsigned int i = 0; i < mFrames.size(); ++i)
+        {
+            mFrames[i] = names[i];
+        }
+        // Tell parent we need recompiling, will cause reload too
+        mParent->_notifyNeedsRecompile();
+    }
+    //-----------------------------------------------------------------------
+    bool TextureUnitState::isCubic(void) const
+    {
+        return mCubic;
+    }
+    //-----------------------------------------------------------------------
+    bool TextureUnitState::is3D(void) const
+    {
+        return mTextureType == TEX_TYPE_CUBE_MAP;
+    }
+    //-----------------------------------------------------------------------
+    TextureType TextureUnitState::getTextureType(void) const
+    {
+        return mTextureType;
+
+    }
+
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setFrameTextureName(const String& name, unsigned int frameNumber)
+    {
+        if (frameNumber < mFrames.size())
+        {
+            mFrames[frameNumber] = name;
+
+            if (isLoaded())
+            {
+                _load(); // reload
+                // Tell parent to recalculate hash
+                mParent->_dirtyHash();
+            }
+        }
+        else // raise exception for frameNumber out of bounds
+        {
+            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "frameNumber paramter value exceeds number of stored frames.",
+                "TextureUnitState::setFrameTextureName");
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    void TextureUnitState::addFrameTextureName(const String& name)
+    {
+        mFrames.push_back(name);
+
+        // Load immediately if Material loaded
+        if (isLoaded())
+        {
+            _load();
+            // Tell parent to recalculate hash
+            mParent->_dirtyHash();
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    void TextureUnitState::deleteFrameTextureName(const size_t frameNumber)
+    {
+        if (frameNumber < mFrames.size())
+        {
+            mFrames.erase(mFrames.begin() + frameNumber);
+
+            if (mFrames.empty())
+                mIsBlank = true;
+
+            if (isLoaded())
+            {
+                _load();
+                // Tell parent to recalculate hash
+                mParent->_dirtyHash();
+            }
+        }
+        else
+        {
+            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "frameNumber paramter value exceeds number of stored frames.",
+                "TextureUnitState::deleteFrameTextureName");
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setAnimatedTextureName( const String& name, unsigned int numFrames, Real duration)
+    {
+        String ext;
+        String baseName;
+
+        size_t pos = name.find_last_of(".");
+        baseName = name.substr(0, pos);
+        ext = name.substr(pos);
+
+        mFrames.resize(numFrames);
+        mAnimDuration = duration;
+        mCurrentFrame = 0;
+        mCubic = false;
+
+        for (unsigned int i = 0; i < mFrames.size(); ++i)
+        {
+			StringUtil::StrStreamType str;
+            str << baseName << "_" << i << ext;
+            mFrames[i] = str.str();
+        }
+
+        // Load immediately if Material loaded
+        if (isLoaded())
+        {
+            _load();
+            // Tell parent to recalculate hash
+            mParent->_dirtyHash();
+        }
+
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setAnimatedTextureName(const String* const names, unsigned int numFrames, Real duration)
+    {
+        mFrames.resize(numFrames);
+        mAnimDuration = duration;
+        mCurrentFrame = 0;
+        mCubic = false;
+
+        for (unsigned int i = 0; i < mFrames.size(); ++i)
+        {
+            mFrames[i] = names[i];
+        }
+
+        // Load immediately if Material loaded
+        if (isLoaded())
+        {
+            _load();
+            // Tell parent to recalculate hash
+            mParent->_dirtyHash();
+        }
+    }
+    //-----------------------------------------------------------------------
+    std::pair< uint, uint > TextureUnitState::getTextureDimensions( unsigned int frame ) const
+    {
+        if (frame < mFrames.size())
+        {
+            TexturePtr tex = TextureManager::getSingleton().getByName( mFrames[ frame ] );
+
+		    if (tex.isNull())
+			    OGRE_EXCEPT( Exception::ERR_ITEM_NOT_FOUND, "Could not find texture " + mFrames[ frame ],
+				    "TextureUnitState::getTextureDimensions" );
+            return std::pair< uint, uint >( tex->getWidth(), tex->getHeight() );
+        }
+        else // frame exceeds the number of frames stored
+        {
+		    OGRE_EXCEPT( Exception::ERR_ITEM_NOT_FOUND, "frame number exceeded number of stored frames" ,
+			    "TextureUnitState::getTextureDimensions" );
+        }
+
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setCurrentFrame(unsigned int frameNumber)
+    {
+        if (frameNumber < mFrames.size())
+        {
+            mCurrentFrame = frameNumber;
+            // this will affect the hash
+            mParent->_dirtyHash();
+        }
+        else
+        {
+            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "frameNumber paramter value exceeds number of stored frames.",
+                "TextureUnitState::setCurrentFrame");
+        }
+
+    }
+    //-----------------------------------------------------------------------
+    unsigned int TextureUnitState::getCurrentFrame(void) const
+    {
+        return mCurrentFrame;
+    }
+    //-----------------------------------------------------------------------
+    unsigned int TextureUnitState::getNumFrames(void) const
+    {
+        return (unsigned int)mFrames.size();
+    }
+    //-----------------------------------------------------------------------
+    const String& TextureUnitState::getFrameTextureName(unsigned int frameNumber) const
+    {
+        if (frameNumber >= mFrames.size())
+        {
+            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "frameNumber paramter value exceeds number of stored frames.",
+                "TextureUnitState::getFrameTextureName");
+        }
+
+        return mFrames[frameNumber];
+    }
+    //-----------------------------------------------------------------------
+    unsigned int TextureUnitState::getTextureCoordSet(void) const
+    {
+        return mTextureCoordSetIndex;
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setTextureCoordSet(unsigned int set)
+    {
+        mTextureCoordSetIndex = set;
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setColourOperationEx(LayerBlendOperationEx op,
+        LayerBlendSource source1,
+        LayerBlendSource source2,
+        const ColourValue& arg1,
+        const ColourValue& arg2,
+        Real manualBlend)
+    {
+        colourBlendMode.operation = op;
+        colourBlendMode.source1 = source1;
+        colourBlendMode.source2 = source2;
+        colourBlendMode.colourArg1 = arg1;
+        colourBlendMode.colourArg2 = arg2;
+        colourBlendMode.factor = manualBlend;
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setColourOperation(LayerBlendOperation op)
+    {
+        // Set up the multitexture and multipass blending operations
+        switch (op)
+        {
+        case LBO_REPLACE:
+            setColourOperationEx(LBX_SOURCE1, LBS_TEXTURE, LBS_CURRENT);
+            setColourOpMultipassFallback(SBF_ONE, SBF_ZERO);
+            break;
+        case LBO_ADD:
+            setColourOperationEx(LBX_ADD, LBS_TEXTURE, LBS_CURRENT);
+            setColourOpMultipassFallback(SBF_ONE, SBF_ONE);
+            break;
+        case LBO_MODULATE:
+            setColourOperationEx(LBX_MODULATE, LBS_TEXTURE, LBS_CURRENT);
+            setColourOpMultipassFallback(SBF_DEST_COLOUR, SBF_ZERO);
+            break;
+        case LBO_ALPHA_BLEND:
+            setColourOperationEx(LBX_BLEND_TEXTURE_ALPHA, LBS_TEXTURE, LBS_CURRENT);
+            setColourOpMultipassFallback(SBF_SOURCE_ALPHA, SBF_ONE_MINUS_SOURCE_ALPHA);
+            break;
+        }
+
+
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setColourOpMultipassFallback(SceneBlendFactor sourceFactor, SceneBlendFactor destFactor)
+    {
+        colourBlendFallbackSrc = sourceFactor;
+        colourBlendFallbackDest = destFactor;
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setAlphaOperation(LayerBlendOperationEx op,
+        LayerBlendSource source1,
+        LayerBlendSource source2,
+        Real arg1,
+        Real arg2,
+        Real manualBlend)
+    {
+        alphaBlendMode.operation = op;
+        alphaBlendMode.source1 = source1;
+        alphaBlendMode.source2 = source2;
+        alphaBlendMode.alphaArg1 = arg1;
+        alphaBlendMode.alphaArg2 = arg2;
+        alphaBlendMode.factor = manualBlend;
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::addEffect(TextureEffect& effect)
+    {
+        // Ensure controller pointer is null
+        effect.controller = 0;
+
+        if (effect.type == ET_ENVIRONMENT_MAP 
+			|| effect.type == ET_UVSCROLL
+			|| effect.type == ET_USCROLL
+			|| effect.type == ET_VSCROLL
+			|| effect.type == ET_ROTATE
+            || effect.type == ET_PROJECTIVE_TEXTURE)
+        {
+            // Replace - must be unique
+            // Search for existing effect of this type
+            EffectMap::iterator i = mEffects.find(effect.type);
+            if (i != mEffects.end())
+            {
+                // Destroy old effect controller if exist
+                if (i->second.controller)
+                {
+                    ControllerManager::getSingleton().destroyController(i->second.controller);
+                }
+
+                mEffects.erase(i);
+            }
+        }
+
+        if (isLoaded())
+        {
+            // Create controller
+            createEffectController(effect);
+        }
+
+        // Record new effect
+        mEffects.insert(EffectMap::value_type(effect.type, effect));
+
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::removeAllEffects(void)
+    {
+        // Iterate over effects to remove controllers
+        EffectMap::iterator i, iend;
+        iend = mEffects.end();
+        for (i = mEffects.begin(); i != iend; ++i)
+        {
+            if (i->second.controller)
+            {
+                ControllerManager::getSingleton().destroyController(i->second.controller);
+            }
+        }
+
+        mEffects.clear();
+    }
+
+    //-----------------------------------------------------------------------
+    bool TextureUnitState::isBlank(void) const
+    {
+        return mIsBlank;
+    }
+
+    //-----------------------------------------------------------------------
+    SceneBlendFactor TextureUnitState::getColourBlendFallbackSrc(void) const
+    {
+        return colourBlendFallbackSrc;
+    }
+    //-----------------------------------------------------------------------
+    SceneBlendFactor TextureUnitState::getColourBlendFallbackDest(void) const
+    {
+        return colourBlendFallbackDest;
+    }
+    //-----------------------------------------------------------------------
+    const LayerBlendModeEx& TextureUnitState::getColourBlendMode(void) const
+    {
+        return colourBlendMode;
+    }
+    //-----------------------------------------------------------------------
+    const LayerBlendModeEx& TextureUnitState::getAlphaBlendMode(void) const
+    {
+        return alphaBlendMode;
+    }
+    //-----------------------------------------------------------------------
+    const TextureUnitState::UVWAddressingMode& 
+	TextureUnitState::getTextureAddressingMode(void) const
+    {
+        return mAddressMode;
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setTextureAddressingMode(
+		TextureUnitState::TextureAddressingMode tam)
+    {
+        mAddressMode.u = tam;
+        mAddressMode.v = tam;
+        mAddressMode.w = tam;
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setTextureAddressingMode(
+		TextureUnitState::TextureAddressingMode u, 
+		TextureUnitState::TextureAddressingMode v,
+		TextureUnitState::TextureAddressingMode w)
+    {
+        mAddressMode.u = u;
+        mAddressMode.v = v;
+        mAddressMode.w = w;
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setTextureAddressingMode(
+		const TextureUnitState::UVWAddressingMode& uvw)
+    {
+        mAddressMode = uvw;
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setTextureBorderColour(const ColourValue& colour)
+    {
+        mBorderColour = colour;
+    }
+    //-----------------------------------------------------------------------
+    const ColourValue& TextureUnitState::getTextureBorderColour(void) const
+    {
+        return mBorderColour;
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setEnvironmentMap(bool enable, EnvMapType envMapType)
+    {
+        if (enable)
+        {
+            TextureEffect eff;
+            eff.type = ET_ENVIRONMENT_MAP;
+
+            eff.subtype = envMapType;
+            addEffect(eff);
+        }
+        else
+        {
+            removeEffect(ET_ENVIRONMENT_MAP);
+        }
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::removeEffect(TextureEffectType type)
+    {
+        // Get range of items matching this effect
+        std::pair< EffectMap::iterator, EffectMap::iterator > remPair = 
+            mEffects.equal_range( type );
+        // Remove controllers
+        for (EffectMap::iterator i = remPair.first; i != remPair.second; ++i)
+        {
+            if (i->second.controller)
+            {
+                ControllerManager::getSingleton().destroyController(i->second.controller);
+            }
+        }
+        // Erase         
+        mEffects.erase( remPair.first, remPair.second );
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setBlank(void)
+    {
+        mIsBlank = true;
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setTextureTransform(const Matrix4& xform)
+    {
+        mTexModMatrix = xform;
+        mRecalcTexMatrix = false;
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setTextureScroll(Real u, Real v)
+    {
+        mUMod = u;
+        mVMod = v;
+        mRecalcTexMatrix = true;
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setTextureScale(Real uScale, Real vScale)
+    {
+        mUScale = uScale;
+        mVScale = vScale;
+        mRecalcTexMatrix = true;
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setTextureRotate(const Radian& angle)
+    {
+        mRotate = angle;
+        mRecalcTexMatrix = true;
+    }
+    //-----------------------------------------------------------------------
+    const Matrix4& TextureUnitState::getTextureTransform() const
+    {
+        if (mRecalcTexMatrix)
+            recalcTextureMatrix();
+        return mTexModMatrix;
+
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::recalcTextureMatrix() const
+    {
+        // Assumption: 2D texture coords
+        Matrix4 xform;
+
+        xform = Matrix4::IDENTITY;
+        if (mUScale != 1 || mVScale != 1)
+        {
+            // Offset to center of texture
+            xform[0][0] = 1/mUScale;
+            xform[1][1] = 1/mVScale;
+            // Skip matrix concat since first matrix update
+            xform[0][3] = (-0.5 * xform[0][0]) + 0.5;
+            xform[1][3] = (-0.5 * xform[1][1]) + 0.5;
+        }
+
+        if (mUMod || mVMod)
+        {
+            Matrix4 xlate = Matrix4::IDENTITY;
+
+            xlate[0][3] = mUMod;
+            xlate[1][3] = mVMod;
+
+            xform = xlate * xform;
+        }
+
+        if (mRotate != Radian(0))
+        {
+            Matrix4 rot = Matrix4::IDENTITY;
+            Radian theta ( mRotate );
+            Real cosTheta = Math::Cos(theta);
+            Real sinTheta = Math::Sin(theta);
+
+            rot[0][0] = cosTheta;
+            rot[0][1] = -sinTheta;
+            rot[1][0] = sinTheta;
+            rot[1][1] = cosTheta;
+            // Offset center of rotation to center of texture
+            rot[0][3] = 0.5 + ( (-0.5 * cosTheta) - (-0.5 * sinTheta) );
+            rot[1][3] = 0.5 + ( (-0.5 * sinTheta) + (-0.5 * cosTheta) );
+
+            xform = rot * xform;
+        }
+
+        mTexModMatrix = xform;
+
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setTextureUScroll(Real value)
+    {
+        mUMod = value;
+        mRecalcTexMatrix = true;
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setTextureVScroll(Real value)
+    {
+        mVMod = value;
+        mRecalcTexMatrix = true;
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setTextureUScale(Real value)
+    {
+        mUScale = value;
+        mRecalcTexMatrix = true;
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setTextureVScale(Real value)
+    {
+        mVScale = value;
+        mRecalcTexMatrix = true;
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setScrollAnimation(Real uSpeed, Real vSpeed)
+    {
+        // Remove existing effects
+        removeEffect(ET_UVSCROLL);
+        removeEffect(ET_USCROLL);
+        removeEffect(ET_VSCROLL);
+        // Create new effect
+        TextureEffect eff;
+	if(uSpeed == vSpeed) 
+	{
+		eff.type = ET_UVSCROLL;
+		eff.arg1 = uSpeed;
+		addEffect(eff);
+	}
+	else
+	{
+		if(uSpeed)
+		{
+			eff.type = ET_USCROLL;
+        eff.arg1 = uSpeed;
+        addEffect(eff);
+    }
+		if(vSpeed)
+		{
+			eff.type = ET_VSCROLL;
+			eff.arg1 = vSpeed;
+			addEffect(eff);
+		}
+	}
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setRotateAnimation(Real speed)
+    {
+        // Remove existing effect
+        removeEffect(ET_ROTATE);
+        // Create new effect
+        TextureEffect eff;
+        eff.type = ET_ROTATE;
+        eff.arg1 = speed;
+        addEffect(eff);
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setTransformAnimation(TextureTransformType ttype,
+        WaveformType waveType, Real base, Real frequency, Real phase, Real amplitude)
+    {
+        // Remove existing effect
+        removeEffect(ET_TRANSFORM);
+        // Create new effect
+        TextureEffect eff;
+        eff.type = ET_TRANSFORM;
+        eff.subtype = ttype;
+        eff.waveType = waveType;
+        eff.base = base;
+        eff.frequency = frequency;
+        eff.phase = phase;
+        eff.amplitude = amplitude;
+        addEffect(eff);
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::_load(void)
+    {
+        // Unload first
+        _unload();
+
+        // Load textures
+        for (unsigned int i = 0; i < mFrames.size(); ++i)
+        {
+            if (mFrames[i] != "")
+            {
+                // Ensure texture is loaded, specified number of mipmaps and priority
+                try {
+
+                    TextureManager::getSingleton().load(mFrames[i], 
+						mParent->getResourceGroup(), mTextureType, mTextureSrcMipmaps, 1.0f, mIsAlpha);
+                    mIsBlank = false;
+                }
+                catch (Exception &e) {
+                    String msg;
+                    msg = msg + "Error loading texture " + mFrames[i]  + 
+					". Texture layer will be blank. Loading the texture failed with the following exception: "+e.getFullDescription();
+                    LogManager::getSingleton().logMessage(msg);
+                    mIsBlank = true;
+                }
+            }
+        }
+        // Animation controller
+        if (mAnimDuration != 0)
+        {
+            createAnimController();
+        }
+        // Effect controllers
+        for (EffectMap::iterator it = mEffects.begin(); it != mEffects.end(); ++it)
+        {
+            createEffectController(it->second);
+        }
+
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::createAnimController(void)
+    {
+        assert(mAnimController == 0);
+        mAnimController = ControllerManager::getSingleton().createTextureAnimator(this, mAnimDuration);
+
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::createEffectController(TextureEffect& effect)
+    {
+        assert(effect.controller == 0);
+        ControllerManager& cMgr = ControllerManager::getSingleton();
+        switch (effect.type)
+        {
+        case ET_UVSCROLL:
+            effect.controller = cMgr.createTextureUVScroller(this, effect.arg1);
+            break;
+        case ET_USCROLL:
+            effect.controller = cMgr.createTextureUScroller(this, effect.arg1);
+            break;
+        case ET_VSCROLL:
+            effect.controller = cMgr.createTextureVScroller(this, effect.arg1);
+            break;
+        case ET_ROTATE:
+            effect.controller = cMgr.createTextureRotater(this, effect.arg1);
+            break;
+        case ET_TRANSFORM:
+            effect.controller = cMgr.createTextureWaveTransformer(this, (TextureUnitState::TextureTransformType)effect.subtype, effect.waveType, effect.base,
+                effect.frequency, effect.phase, effect.amplitude);
+            break;
+        case ET_ENVIRONMENT_MAP:
+            break;
+        default:
+            break;
+        }
+    }
+    //-----------------------------------------------------------------------
+	Real TextureUnitState::getTextureUScroll(void) const
+    {
+		return mUMod;
+    }
+
+	//-----------------------------------------------------------------------
+	Real TextureUnitState::getTextureVScroll(void) const
+    {
+		return mVMod;
+    }
+
+	//-----------------------------------------------------------------------
+	Real TextureUnitState::getTextureUScale(void) const
+    {
+		return mUScale;
+    }
+
+	//-----------------------------------------------------------------------
+	Real TextureUnitState::getTextureVScale(void) const
+    {
+		return mVScale;
+    }
+
+	//-----------------------------------------------------------------------
+	const Radian& TextureUnitState::getTextureRotate(void) const
+    {
+		return mRotate;
+    }
+	
+	//-----------------------------------------------------------------------
+	Real TextureUnitState::getAnimationDuration(void) const
+	{
+		return mAnimDuration;
+	}
+
+	//-----------------------------------------------------------------------
+	const TextureUnitState::EffectMap& TextureUnitState::getEffects(void) const
+	{
+		return mEffects;
+	}
+
+	//-----------------------------------------------------------------------
+	void TextureUnitState::setTextureFiltering(TextureFilterOptions filterType)
+	{
+        switch (filterType)
+        {
+        case TFO_NONE:
+            setTextureFiltering(FO_POINT, FO_POINT, FO_NONE);
+            break;
+        case TFO_BILINEAR:
+            setTextureFiltering(FO_LINEAR, FO_LINEAR, FO_POINT);
+            break;
+        case TFO_TRILINEAR:
+            setTextureFiltering(FO_LINEAR, FO_LINEAR, FO_LINEAR);
+            break;
+        case TFO_ANISOTROPIC:
+            setTextureFiltering(FO_ANISOTROPIC, FO_ANISOTROPIC, FO_LINEAR);
+            break;
+        }
+        mIsDefaultFiltering = false;
+	}
+	//-----------------------------------------------------------------------
+    void TextureUnitState::setTextureFiltering(FilterType ft, FilterOptions fo)
+    {
+        switch (ft)
+        {
+        case FT_MIN:
+            mMinFilter = fo;
+            break;
+        case FT_MAG:
+            mMagFilter = fo;
+            break;
+        case FT_MIP:
+            mMipFilter = fo;
+            break;
+        }
+        mIsDefaultFiltering = false;
+    }
+	//-----------------------------------------------------------------------
+    void TextureUnitState::setTextureFiltering(FilterOptions minFilter, 
+        FilterOptions magFilter, FilterOptions mipFilter)
+    {
+        mMinFilter = minFilter;
+        mMagFilter = magFilter;
+        mMipFilter = mipFilter;
+        mIsDefaultFiltering = false;
+    }
+	//-----------------------------------------------------------------------
+	FilterOptions TextureUnitState::getTextureFiltering(FilterType ft) const
+	{
+
+        switch (ft)
+        {
+        case FT_MIN:
+            return mIsDefaultFiltering ? 
+                MaterialManager::getSingleton().getDefaultTextureFiltering(FT_MIN) : mMinFilter;
+        case FT_MAG:
+            return mIsDefaultFiltering ? 
+                MaterialManager::getSingleton().getDefaultTextureFiltering(FT_MAG) : mMagFilter;
+        case FT_MIP:
+            return mIsDefaultFiltering ? 
+                MaterialManager::getSingleton().getDefaultTextureFiltering(FT_MIP) : mMipFilter;
+        }
+		// to keep compiler happy
+		return mMinFilter;
+	}
+
+	//-----------------------------------------------------------------------
+	void TextureUnitState::setTextureAnisotropy(unsigned int maxAniso)
+	{
+		mMaxAniso = maxAniso;
+        mIsDefaultAniso = false;
+	}
+	//-----------------------------------------------------------------------
+	unsigned int TextureUnitState::getTextureAnisotropy() const
+	{
+        return mIsDefaultAniso? MaterialManager::getSingleton().getDefaultAnisotropy() : mMaxAniso;
+	}
+
+	//-----------------------------------------------------------------------
+    void TextureUnitState::_unload(void)
+    {
+        // Destroy animation controller
+        if (mAnimController)
+        {
+            ControllerManager::getSingleton().destroyController(mAnimController);
+            mAnimController = 0;
+        }
+
+        // Destroy effect controllers
+        for (EffectMap::iterator i = mEffects.begin(); i != mEffects.end(); ++i)
+        {
+            if (i->second.controller)
+            {
+                ControllerManager::getSingleton().destroyController(i->second.controller);
+                i->second.controller = 0;
+            }
+        }
+
+        // Don't unload textures. may be used elsewhere
+    }
+    //-----------------------------------------------------------------------------
+    bool TextureUnitState::isLoaded(void)
+    {
+        return mParent->isLoaded();
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::_notifyNeedsRecompile(void)
+    {
+        mParent->_notifyNeedsRecompile();
+    }
+    //-----------------------------------------------------------------------
+    bool TextureUnitState::hasViewRelativeTextureCoordinateGeneration(void)
+    {
+        // Right now this only returns true for reflection maps
+
+        EffectMap::const_iterator i, iend;
+        iend = mEffects.end();
+        
+        for(i = mEffects.find(ET_ENVIRONMENT_MAP); i != iend; ++i)
+        {
+            if (i->second.subtype == ENV_REFLECTION)
+                return true;
+        }
+        for(i = mEffects.find(ET_PROJECTIVE_TEXTURE); i != iend; ++i)
+        {
+            return true;
+        }
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setProjectiveTexturing(bool enable, 
+        const Frustum* projectionSettings)
+    {
+        if (enable)
+        {
+            TextureEffect eff;
+            eff.type = ET_PROJECTIVE_TEXTURE;
+            eff.frustum = projectionSettings;
+            addEffect(eff);
+        }
+        else
+        {
+            removeEffect(ET_PROJECTIVE_TEXTURE);
+        }
+
+    }
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setName(const String& name)
+    {
+        mName = name;
+		if (mTextureNameAlias.empty())
+			mTextureNameAlias = mName;
+    }
+
+    //-----------------------------------------------------------------------
+    void TextureUnitState::setTextureNameAlias(const String& name)
+    {
+        mTextureNameAlias = name;
+    }
+
+    //-----------------------------------------------------------------------
+    bool TextureUnitState::applyTextureAliases(const AliasTextureNamePairList& aliasList, const bool apply)
+    {
+        bool testResult = false;
+        // if TUS has an alias see if its in the alias container
+        if (!mTextureNameAlias.empty())
+        {
+            AliasTextureNamePairList::const_iterator aliasEntry =
+                aliasList.find(mTextureNameAlias);
+
+            if (aliasEntry != aliasList.end())
+            {
+                // match was found so change the texture name in mFrames
+                testResult = true;
+
+                if (apply)
+                {
+                    // currently assumes animated frames are sequentially numbered
+                    // cubic, 1d, 2d, and 3d textures are determined from current TUS state
+                    
+                    // if cubic or 3D
+                    if (mCubic)
+                    {
+                        setCubicTextureName(aliasEntry->second, mTextureType == TEX_TYPE_CUBE_MAP);
+                    }
+                    else
+                    {
+                        // if more than one frame then assume animated frames
+                        if (mFrames.size() > 1)
+                            setAnimatedTextureName(aliasEntry->second, mFrames.size(), mAnimDuration);
+                        else
+                            setTextureName(aliasEntry->second, mTextureType, mTextureSrcMipmaps);
+                    }
+                }
+                
+            }
+        }
+
+        return testResult;
+    }
+	//-----------------------------------------------------------------------------
+	void TextureUnitState::_notifyParent(Pass* parent)
+	{
+		mParent = parent;
+	}
+
+}
Index: OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/src/OgreParticleSystemManager.cpp
===================================================================
--- OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/src/OgreParticleSystemManager.cpp	(revision 768)
+++ OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/src/OgreParticleSystemManager.cpp	(revision 768)
@@ -0,0 +1,610 @@
+/*
+-----------------------------------------------------------------------------
+This source file is part of OGRE
+    (Object-oriented Graphics Rendering Engine)
+For the latest info, see http://www.ogre3d.org/
+
+Copyright (c) 2000-2005 The OGRE Team
+Also see acknowledgements in Readme.html
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+#include "OgreStableHeaders.h"
+
+#include "OgreParticleSystemManager.h"
+#include "OgreParticleEmitterFactory.h"
+#include "OgreParticleAffectorFactory.h"
+#include "OgreException.h"
+#include "OgreRoot.h"
+#include "OgreLogManager.h"
+#include "OgreString.h"
+#include "OgreParticleSystemRenderer.h"
+#include "OgreBillboardParticleRenderer.h"
+#include "OgreStringConverter.h"
+
+#ifdef GAMETOOLS_ILLUMINATION_MODULE
+	#include "SpriteParticleRenderer.h"
+#endif
+
+namespace Ogre {
+    //-----------------------------------------------------------------------
+    // Shortcut to set up billboard particle renderer
+    BillboardParticleRendererFactory* mBillboardRendererFactory = 0;
+    //-----------------------------------------------------------------------
+
+#ifdef GAMETOOLS_ILLUMINATION_MODULE
+	//-----------------------------------------------------------------------
+    // Shortcut to set up sprite particle renderer
+	SpriteParticleRendererFactory* mSpriteRendererFactory = 0;
+    //-----------------------------------------------------------------------
+#endif
+
+    template<> ParticleSystemManager* Singleton<ParticleSystemManager>::ms_Singleton = 0;
+    ParticleSystemManager* ParticleSystemManager::getSingletonPtr(void)
+    {
+        return ms_Singleton;
+    }
+    ParticleSystemManager& ParticleSystemManager::getSingleton(void)
+    {  
+        assert( ms_Singleton );  return ( *ms_Singleton );  
+    }
+    //-----------------------------------------------------------------------
+    ParticleSystemManager::ParticleSystemManager()
+    {
+        mScriptPatterns.push_back("*.particle");
+        ResourceGroupManager::getSingleton()._registerScriptLoader(this);
+		mFactory = new ParticleSystemFactory();
+		Root::getSingleton().addMovableObjectFactory(mFactory);
+    }
+    //-----------------------------------------------------------------------
+    ParticleSystemManager::~ParticleSystemManager()
+    {
+        // Destroy all templates
+        ParticleTemplateMap::iterator t;
+        for (t = mSystemTemplates.begin(); t != mSystemTemplates.end(); ++t)
+        {
+            delete t->second;
+        }
+        mSystemTemplates.clear();
+        ResourceGroupManager::getSingleton()._unregisterScriptLoader(this);
+        // delete billboard factory
+        if (mBillboardRendererFactory)
+		{
+            delete mBillboardRendererFactory;
+			mBillboardRendererFactory = 0;
+		}
+
+#ifdef GAMETOOLS_ILLUMINATION_MODULE
+		// delete billboard factory
+        if (mSpriteRendererFactory)
+		{
+            delete mSpriteRendererFactory;
+			mSpriteRendererFactory = 0;
+		}
+#endif
+
+		if (mFactory)
+		{
+			// delete particle system factory
+			Root::getSingleton().removeMovableObjectFactory(mFactory);
+			delete mFactory;
+			mFactory = 0;
+		}
+
+    }
+    //-----------------------------------------------------------------------
+    const StringVector& ParticleSystemManager::getScriptPatterns(void) const
+    {
+        return mScriptPatterns;
+    }
+    //-----------------------------------------------------------------------
+    Real ParticleSystemManager::getLoadingOrder(void) const
+    {
+        /// Load late
+        return 1000.0f;
+    }
+    //-----------------------------------------------------------------------
+    void ParticleSystemManager::parseScript(DataStreamPtr& stream, const String& groupName)
+    {
+        String line;
+        ParticleSystem* pSys;
+        std::vector<String> vecparams;
+
+        pSys = 0;
+
+        while(!stream->eof())
+        {
+            line = stream->getLine();
+            // Ignore comments & blanks
+            if (!(line.length() == 0 || line.substr(0,2) == "//"))
+            {
+                if (pSys == 0)
+                {
+                    // No current system
+                    // So first valid data should be a system name
+                    pSys = createTemplate(line, groupName);
+					pSys->_notifyOrigin(stream->getName());
+                    // Skip to and over next {
+                    skipToNextOpenBrace(stream);
+                }
+                else
+                {
+                    // Already in a system
+                    if (line == "}")
+                    {
+                        // Finished system
+                        pSys = 0;
+                    }
+                    else if (line.substr(0,7) == "emitter")
+                    {
+                        // new emitter
+                        // Get typename
+                        vecparams = StringUtil::split(line, "\t ");
+                        if (vecparams.size() < 2)
+                        {
+                            // Oops, bad emitter
+                            LogManager::getSingleton().logMessage("Bad particle system emitter line: '"
+                                + line + "' in " + pSys->getName());
+                            skipToNextCloseBrace(stream);
+
+                        }
+                        skipToNextOpenBrace(stream);
+                        parseNewEmitter(vecparams[1], stream, pSys);
+
+                    }
+                    else if (line.substr(0,8) == "affector")
+                    {
+                        // new affector
+                        // Get typename
+                        vecparams = StringUtil::split(line, "\t ");
+                        if (vecparams.size() < 2)
+                        {
+                            // Oops, bad emitter
+                            LogManager::getSingleton().logMessage("Bad particle system affector line: '"
+                                + line + "' in " + pSys->getName());
+                            skipToNextCloseBrace(stream);
+
+                        }
+                        skipToNextOpenBrace(stream);
+                        parseNewAffector(vecparams[1],stream, pSys);
+                    }
+                    else
+                    {
+                        // Attribute
+                        parseAttrib(line, pSys);
+                    }
+
+                }
+
+            }
+
+
+        }
+
+
+    }
+    //-----------------------------------------------------------------------
+    void ParticleSystemManager::addEmitterFactory(ParticleEmitterFactory* factory)
+    {
+        String name = factory->getName();
+        mEmitterFactories[name] = factory;
+        LogManager::getSingleton().logMessage("Particle Emitter Type '" + name + "' registered");
+    }
+    //-----------------------------------------------------------------------
+    void ParticleSystemManager::addAffectorFactory(ParticleAffectorFactory* factory)
+    {
+        String name = factory->getName();
+        mAffectorFactories[name] = factory;
+        LogManager::getSingleton().logMessage("Particle Affector Type '" + name + "' registered");
+    }
+	//-----------------------------------------------------------------------
+	void ParticleSystemManager::addRendererFactory(ParticleSystemRendererFactory* factory)
+	{
+        String name = factory->getType();
+        mRendererFactories[name] = factory;
+        LogManager::getSingleton().logMessage("Particle Renderer Type '" + name + "' registered");
+	}
+	//-----------------------------------------------------------------------
+    void ParticleSystemManager::addTemplate(const String& name, ParticleSystem* sysTemplate)
+    {
+		// check name
+		if (mSystemTemplates.find(name) != mSystemTemplates.end())
+		{
+			OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM, 
+				"ParticleSystem template with name '" + name + "' already exists.", 
+				"ParticleSystemManager::addTemplate");
+		}
+
+        mSystemTemplates[name] = sysTemplate;
+    }
+    //-----------------------------------------------------------------------
+    ParticleSystem* ParticleSystemManager::createTemplate(const String& name, 
+        const String& resourceGroup)
+    {
+		// check name
+		if (mSystemTemplates.find(name) != mSystemTemplates.end())
+		{
+			OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM, 
+				"ParticleSystem template with name '" + name + "' already exists.", 
+				"ParticleSystemManager::createTemplate");
+		}
+
+        ParticleSystem* tpl = new ParticleSystem(name, resourceGroup);
+        addTemplate(name, tpl);
+        return tpl;
+
+    }
+    //-----------------------------------------------------------------------
+    ParticleSystem* ParticleSystemManager::getTemplate(const String& name)
+    {
+        ParticleTemplateMap::iterator i = mSystemTemplates.find(name);
+        if (i != mSystemTemplates.end())
+        {
+            return i->second;
+        }
+        else
+        {
+            return 0;
+        }
+    }
+	//-----------------------------------------------------------------------
+    ParticleSystem* ParticleSystemManager::createSystemImpl(const String& name,
+		size_t quota, const String& resourceGroup)
+    {
+        ParticleSystem* sys = new ParticleSystem(name, resourceGroup);
+        sys->setParticleQuota(quota);
+        return sys;
+    }
+    //-----------------------------------------------------------------------
+    ParticleSystem* ParticleSystemManager::createSystemImpl(const String& name, 
+		const String& templateName)
+    {
+        // Look up template
+        ParticleSystem* pTemplate = getTemplate(templateName);
+        if (!pTemplate)
+        {
+            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Cannot find required template '" + templateName + "'", "ParticleSystemManager::createSystem");
+        }
+
+        ParticleSystem* sys = createSystemImpl(name, pTemplate->getParticleQuota(), 
+            pTemplate->getResourceGroupName());
+        // Copy template settings
+        *sys = *pTemplate;
+        return sys;
+        
+    }
+    //-----------------------------------------------------------------------
+    void ParticleSystemManager::destroySystemImpl(ParticleSystem* sys)
+	{
+		delete sys;
+	}
+    //-----------------------------------------------------------------------
+    ParticleEmitter* ParticleSystemManager::_createEmitter(
+        const String& emitterType, ParticleSystem* psys)
+    {
+        // Locate emitter type
+        ParticleEmitterFactoryMap::iterator pFact = mEmitterFactories.find(emitterType);
+
+        if (pFact == mEmitterFactories.end())
+        {
+            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Cannot find requested emitter type.", 
+                "ParticleSystemManager::_createEmitter");
+        }
+
+        return pFact->second->createEmitter(psys);
+    }
+    //-----------------------------------------------------------------------
+    void ParticleSystemManager::_destroyEmitter(ParticleEmitter* emitter)
+    {
+        // Destroy using the factory which created it
+        ParticleEmitterFactoryMap::iterator pFact = mEmitterFactories.find(emitter->getType());
+
+        if (pFact == mEmitterFactories.end())
+        {
+            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Cannot find emitter factory to destroy emitter.", 
+                "ParticleSystemManager::_destroyEmitter");
+        }
+
+        pFact->second->destroyEmitter(emitter);
+    }
+    //-----------------------------------------------------------------------
+    ParticleAffector* ParticleSystemManager::_createAffector(
+        const String& affectorType, ParticleSystem* psys)
+    {
+        // Locate affector type
+        ParticleAffectorFactoryMap::iterator pFact = mAffectorFactories.find(affectorType);
+
+        if (pFact == mAffectorFactories.end())
+        {
+            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Cannot find requested affector type.", 
+                "ParticleSystemManager::_createAffector");
+        }
+
+        return pFact->second->createAffector(psys);
+
+    }
+    //-----------------------------------------------------------------------
+    void ParticleSystemManager::_destroyAffector(ParticleAffector* affector)
+    {
+        // Destroy using the factory which created it
+        ParticleAffectorFactoryMap::iterator pFact = mAffectorFactories.find(affector->getType());
+
+        if (pFact == mAffectorFactories.end())
+        {
+            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Cannot find affector factory to destroy affector.", 
+                "ParticleSystemManager::_destroyAffector");
+        }
+
+        pFact->second->destroyAffector(affector);
+    }
+    //-----------------------------------------------------------------------
+    ParticleSystemRenderer* ParticleSystemManager::_createRenderer(const String& rendererType)
+	{
+        // Locate affector type
+        ParticleSystemRendererFactoryMap::iterator pFact = mRendererFactories.find(rendererType);
+
+        if (pFact == mRendererFactories.end())
+        {
+            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Cannot find requested renderer type.", 
+                "ParticleSystemManager::_createRenderer");
+        }
+
+        return pFact->second->createInstance(rendererType);
+	}
+	//-----------------------------------------------------------------------
+    void ParticleSystemManager::_destroyRenderer(ParticleSystemRenderer* renderer)
+	{
+        // Destroy using the factory which created it
+        ParticleSystemRendererFactoryMap::iterator pFact = mRendererFactories.find(renderer->getType());
+
+        if (pFact == mRendererFactories.end())
+        {
+            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Cannot find renderer factory to destroy renderer.", 
+                "ParticleSystemManager::_destroyRenderer");
+        }
+
+        pFact->second->destroyInstance(renderer);
+	}
+    //-----------------------------------------------------------------------
+    void ParticleSystemManager::_initialise(void)
+    {
+        // Create Billboard renderer factory
+        mBillboardRendererFactory = new BillboardParticleRendererFactory();
+        addRendererFactory(mBillboardRendererFactory);
+
+#ifdef GAMETOOLS_ILLUMINATION_MODULE
+		// Create Billboard renderer factory
+        mSpriteRendererFactory = new SpriteParticleRendererFactory();
+        addRendererFactory(mSpriteRendererFactory);
+#endif
+    }
+    //-----------------------------------------------------------------------
+    void ParticleSystemManager::parseNewEmitter(const String& type, DataStreamPtr& stream, ParticleSystem* sys)
+    {
+        // Create new emitter
+        ParticleEmitter* pEmit = sys->addEmitter(type);
+        // Parse emitter details
+        String line;
+
+        while(!stream->eof())
+        {
+            line = stream->getLine();
+            // Ignore comments & blanks
+            if (!(line.length() == 0 || line.substr(0,2) == "//"))
+            {
+                if (line == "}")
+                {
+                    // Finished emitter
+                    break;
+                }
+                else
+                {
+                    // Attribute
+					StringUtil::toLowerCase(line);
+                    parseEmitterAttrib(line, pEmit);
+                }
+            }
+        }
+
+
+        
+    }
+    //-----------------------------------------------------------------------
+    void ParticleSystemManager::parseNewAffector(const String& type, DataStreamPtr& stream, ParticleSystem* sys)
+    {
+        // Create new affector
+        ParticleAffector* pAff = sys->addAffector(type);
+        // Parse affector details
+        String line;
+
+        while(!stream->eof())
+        {
+            line = stream->getLine();
+            // Ignore comments & blanks
+            if (!(line.length() == 0 || line.substr(0,2) == "//"))
+            {
+                if (line == "}")
+                {
+                    // Finished affector
+                    break;
+                }
+                else
+                {
+                    // Attribute
+					StringUtil::toLowerCase(line);
+                    parseAffectorAttrib(line, pAff);
+                }
+            }
+        }
+    }
+    //-----------------------------------------------------------------------
+    void ParticleSystemManager::parseAttrib(const String& line, ParticleSystem* sys)
+    {
+        std::vector<String> vecparams;
+
+        // Split params on space
+        vecparams = StringUtil::split(line, "\t ", 1);
+
+        // Look up first param (command setting)
+        if (!sys->setParameter(vecparams[0], vecparams[1]))
+        {
+            // Attribute not supported by particle system, try the renderer
+            ParticleSystemRenderer* renderer = sys->getRenderer();
+            if (renderer)
+            {
+                if (!renderer->setParameter(vecparams[0], vecparams[1]))
+                {
+                    LogManager::getSingleton().logMessage("Bad particle system attribute line: '"
+                        + line + "' in " + sys->getName() + " (tried renderer)");
+                }
+            }
+            else
+            {
+                // BAD command. BAD!
+                LogManager::getSingleton().logMessage("Bad particle system attribute line: '"
+                    + line + "' in " + sys->getName() + " (no renderer)");
+            }
+        }
+    }
+    //-----------------------------------------------------------------------
+    void ParticleSystemManager::parseEmitterAttrib(const String& line, ParticleEmitter* emit)
+    {
+        std::vector<String> vecparams;
+
+        // Split params on first space
+        vecparams = StringUtil::split(line, "\t ", 1);
+
+        // Look up first param (command setting)
+        if (!emit->setParameter(vecparams[0], vecparams[1]))
+        {
+            // BAD command. BAD!
+            LogManager::getSingleton().logMessage("Bad particle emitter attribute line: '"
+                + line + "' for emitter " + emit->getType());
+        }
+    }
+    //-----------------------------------------------------------------------
+    void ParticleSystemManager::parseAffectorAttrib(const String& line, ParticleAffector* aff)
+    {
+        std::vector<String> vecparams;
+
+        // Split params on space
+        vecparams = StringUtil::split(line, "\t ", 1);
+
+        // Look up first param (command setting)
+        if (!aff->setParameter(vecparams[0], vecparams[1]))
+        {
+            // BAD command. BAD!
+            LogManager::getSingleton().logMessage("Bad particle affector attribute line: '"
+                + line + "' for affector " + aff->getType());
+        }
+    }
+    //-----------------------------------------------------------------------
+    void ParticleSystemManager::skipToNextCloseBrace(DataStreamPtr& stream)
+    {
+        String line = "";
+        while (!stream->eof() && line != "}")
+        {
+            line = stream->getLine();
+        }
+
+    }
+    //-----------------------------------------------------------------------
+    void ParticleSystemManager::skipToNextOpenBrace(DataStreamPtr& stream)
+    {
+        String line = "";
+        while (!stream->eof() && line != "{")
+        {
+            line = stream->getLine();
+        }
+
+    }
+	//-----------------------------------------------------------------------
+	ParticleSystemManager::ParticleAffectorFactoryIterator 
+	ParticleSystemManager::getAffectorFactoryIterator(void)
+	{
+		return ParticleAffectorFactoryIterator(
+			mAffectorFactories.begin(), mAffectorFactories.end());
+	}
+	//-----------------------------------------------------------------------
+	ParticleSystemManager::ParticleEmitterFactoryIterator 
+	ParticleSystemManager::getEmitterFactoryIterator(void)
+	{
+		return ParticleEmitterFactoryIterator(
+			mEmitterFactories.begin(), mEmitterFactories.end());
+	}
+	//-----------------------------------------------------------------------
+	ParticleSystemManager::ParticleRendererFactoryIterator 
+	ParticleSystemManager::getRendererFactoryIterator(void)
+	{
+		return ParticleRendererFactoryIterator(
+			mRendererFactories.begin(), mRendererFactories.end());
+	}
+	//-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+	String ParticleSystemFactory::FACTORY_TYPE_NAME = "ParticleSystem";
+    //-----------------------------------------------------------------------
+	MovableObject* ParticleSystemFactory::createInstanceImpl( const String& name, 
+			const NameValuePairList* params)
+	{
+		if (params != 0)
+		{
+			NameValuePairList::const_iterator ni = params->find("templateName");
+			if (ni != params->end())
+			{
+				String templateName = ni->second;
+				// create using manager
+				return ParticleSystemManager::getSingleton().createSystemImpl(
+						name, templateName);
+			}
+		}
+		// Not template based, look for quota & resource name
+		size_t quota = 500;
+		String resourceGroup = ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME;
+		if (params != 0)
+		{
+			NameValuePairList::const_iterator ni = params->find("quota");
+			if (ni != params->end())
+			{
+				quota = StringConverter::parseUnsignedInt(ni->second);
+			}
+			ni = params->find("resourceGroup");
+			if (ni != params->end())
+			{
+				resourceGroup = ni->second;
+			}
+		}
+		// create using manager
+		return ParticleSystemManager::getSingleton().createSystemImpl(
+				name, quota, resourceGroup);
+				
+
+	}
+    //-----------------------------------------------------------------------
+	const String& ParticleSystemFactory::getType(void) const
+	{
+		return FACTORY_TYPE_NAME;
+	}
+    //-----------------------------------------------------------------------
+	void ParticleSystemFactory::destroyInstance( MovableObject* obj) 
+	{
+		// use manager
+		ParticleSystemManager::getSingleton().destroySystemImpl(
+			static_cast<ParticleSystem*>(obj));
+
+	}
+    //-----------------------------------------------------------------------
+}
Index: OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/src/SpriteParticleRenderer.cpp
===================================================================
--- OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/src/SpriteParticleRenderer.cpp	(revision 768)
+++ OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/src/SpriteParticleRenderer.cpp	(revision 768)
@@ -0,0 +1,163 @@
+
+#include "OgreStableHeaders.h"
+
+#include "SpriteParticleRenderer.h"
+#include "OgreParticle.h"
+#include "OgreStringConverter.h"
+
+#ifdef GAMETOOLS_ILLUMINATION_MODULE
+
+namespace Ogre {
+
+	Vector3 cameraPosition;
+
+	class ParticleBackToFront
+	{
+		public:
+		bool operator() (const Particle* p1, const Particle* p2)
+		{
+			float dist1 = (cameraPosition - p1->position).length();
+			float dist2 = (cameraPosition - p2->position).length();
+            return dist1 < dist2;
+		}
+	};
+
+	class ParticleFrontToBack
+	{
+		public:
+		bool operator() (const Particle* p1, const Particle* p2)
+		{
+			float dist1 = (cameraPosition - p1->position).length();
+			float dist2 = (cameraPosition - p2->position).length();
+            return dist1 > dist2;
+		}
+	};
+ 
+	String SpriteName = "sprite";
+    //-----------------------------------------------------------------------
+    SpriteParticleRenderer::SpriteParticleRenderer()
+    {
+        if (createParamDictionary("SpriteParticleRenderer"))
+        {
+            ParamDictionary* dict = getParamDictionary();
+           
+        }
+		particleSorting = 0;
+        // Create billboard set
+		mSpriteSet = new SpriteSet("", 0, true);
+        // World-relative axes
+        mSpriteSet->setBillboardsInWorldSpace(true);
+    }
+    //-----------------------------------------------------------------------
+    SpriteParticleRenderer::~SpriteParticleRenderer()
+    {
+        delete mSpriteSet;
+    }
+    //-----------------------------------------------------------------------
+    const String& SpriteParticleRenderer::getType(void) const
+    {
+        return SpriteName;
+    }
+
+	void SpriteParticleRenderer::setParticleSorting(int sorting, Camera* cam)
+	{
+		this->particleSorting = sorting;
+		cameraPosition = cam->getWorldPosition();
+	}
+    //-----------------------------------------------------------------------
+    void SpriteParticleRenderer::_updateRenderQueue(RenderQueue* queue, 
+        std::list<Particle*>& currentParticles, bool cullIndividually)
+    {
+        mSpriteSet->setCullIndividually(cullIndividually);
+
+		////sort currentParticles
+		if(particleSorting > 0)
+			currentParticles.sort(ParticleBackToFront());
+		if(particleSorting < 0)
+			currentParticles.sort(ParticleFrontToBack());
+
+
+        // Update billboard set geometry
+        mSpriteSet->beginBillboards();
+        Billboard bb;
+        for (std::list<Particle*>::iterator i = currentParticles.begin();
+            i != currentParticles.end(); ++i)
+        {
+            Particle* p = *i;
+            bb.mPosition = p->position;
+            bb.mDirection = p->direction;
+            bb.mColour = p->colour;
+            bb.mRotation = p->rotation;
+            // Assign and compare at the same time
+            if (bb.mOwnDimensions = p->mOwnDimensions)
+            {
+                bb.mWidth = p->mWidth;
+                bb.mHeight = p->mHeight;
+            }
+            mSpriteSet->injectBillboard(bb);
+
+        }
+        
+        mSpriteSet->endBillboards();
+
+        // Update the queue
+        mSpriteSet->_updateRenderQueue(queue);
+    }
+    //-----------------------------------------------------------------------
+    void SpriteParticleRenderer::_setMaterial(MaterialPtr& mat)
+    {
+        mSpriteSet->setMaterialName(mat->getName());
+    }
+   
+	void SpriteParticleRenderer::_notifyCurrentCamera(Camera* cam)
+    {
+        mSpriteSet->_notifyCurrentCamera(cam);
+    }
+    //-----------------------------------------------------------------------
+    void SpriteParticleRenderer::_notifyDefaultDimensions(Real width, Real height)
+    {
+        mSpriteSet->setDefaultDimensions(width, height);
+    }
+    //-----------------------------------------------------------------------
+    void SpriteParticleRenderer::_notifyParticleResized(void)
+    {
+        mSpriteSet->_notifyBillboardResized();
+    }
+    //-----------------------------------------------------------------------
+    void SpriteParticleRenderer::_notifyParticleQuota(size_t quota)
+    {
+        mSpriteSet->setPoolSize(quota);
+    }
+    //-----------------------------------------------------------------------
+    void SpriteParticleRenderer::_notifyAttached(Node* parent, bool isTagPoint)
+    {
+        mSpriteSet->_notifyAttached(parent, isTagPoint);
+    }
+	//-----------------------------------------------------------------------
+	void SpriteParticleRenderer::setRenderQueueGroup(uint8 queueID)
+	{
+		mSpriteSet->setRenderQueueGroup(queueID);
+	}
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    const String& SpriteParticleRendererFactory::getType() const
+    {
+        return SpriteName;
+    }
+    //-----------------------------------------------------------------------
+    ParticleSystemRenderer* SpriteParticleRendererFactory::createInstance( 
+        const String& name )
+    {
+        return new SpriteParticleRenderer();
+    }
+    //-----------------------------------------------------------------------
+    void SpriteParticleRendererFactory::destroyInstance( 
+        ParticleSystemRenderer* inst)
+    {
+        delete inst;
+    }    
+
+}
+
+#endif
Index: OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/src/SpriteSet.cpp
===================================================================
--- OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/src/SpriteSet.cpp	(revision 768)
+++ OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/src/SpriteSet.cpp	(revision 768)
@@ -0,0 +1,247 @@
+#include "OgreStableHeaders.h"
+
+#include "SpriteSet.h"
+
+#include "OgreBillboard.h"
+#include "OgreMaterialManager.h"
+#include "OgreHardwareBufferManager.h"
+#include "OgreCamera.h"
+#include "OgreMath.h"
+#include "OgreSphere.h"
+#include "OgreRoot.h"
+#include "OgreException.h"
+#include <algorithm>
+
+#ifdef GAMETOOLS_ILLUMINATION_MODULE
+
+
+namespace Ogre 
+{
+	void SpriteSet::beginBillboards(void)
+    {      
+        // create vertex and index buffers if they haven't already been
+        if(!mBuffersCreated)
+            _createBuffers();		
+
+        // Init num visible
+        mNumVisibleBillboards = 0;
+
+        // Lock the buffer
+        mLockPtr = static_cast<float*>(
+            mMainBuf->lock(HardwareBuffer::HBL_DISCARD) );
+    }
+
+	void SpriteSet::_createBuffers(void)
+    {
+        mVertexData = new VertexData();
+       
+        mVertexData->vertexCount = mPoolSize * 6;
+        mVertexData->vertexStart = 0;
+
+        // Vertex declaration
+        VertexDeclaration* decl = mVertexData->vertexDeclaration;
+        VertexBufferBinding* binding = mVertexData->vertexBufferBinding;
+
+        size_t offset = 0;
+        decl->addElement(0, offset, VET_FLOAT3, VES_POSITION);
+        offset += VertexElement::getTypeSize(VET_FLOAT3);
+        decl->addElement(0, offset, VET_COLOUR, VES_DIFFUSE);
+        offset += VertexElement::getTypeSize(VET_COLOUR);
+        decl->addElement(0, offset, VET_FLOAT4, VES_TEXTURE_COORDINATES, 0);
+
+        mMainBuf = 
+            HardwareBufferManager::getSingleton().createVertexBuffer(
+                decl->getVertexSize(0),
+                mVertexData->vertexCount, 
+                HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE);
+        // bind position and diffuses
+        binding->setBinding(0, mMainBuf);
+     
+        mBuffersCreated = true;
+	}
+
+//-----------------------------------------------------------------------
+void SpriteSet::getRenderOperation(RenderOperation &op)
+{
+    op.operationType = RenderOperation::OT_TRIANGLE_LIST;
+    op.useIndexes = false;
+	op.indexData = 0;
+    op.vertexData = mVertexData;
+    op.vertexData->vertexCount = mNumVisibleBillboards * 6;
+    op.vertexData->vertexStart = 0;
+ }
+
+//-----------------------------------------------------------------------
+void SpriteSet::injectBillboard(const Billboard& bb)
+{
+      // Skip if not visible (NB always true if not bounds checking individual billboards)
+        if (!billboardVisible(mCurrentCamera, bb)) return;
+
+      
+        genVertices( bb);
+        
+        // Increment visibles
+        mNumVisibleBillboards++;
+ }
+
+ //-----------------------------------------------------------------------
+    void SpriteSet::genVertices(  const Billboard& bb)
+    {
+	RGBA colour;
+        Root::getSingleton().convertColourValue(bb.mColour, &colour);
+		RGBA* pCol;
+
+        // Texcoords
+        assert( bb.mUseTexcoordRect || bb.mTexcoordIndex < mTextureCoords.size() );
+        const Ogre::FloatRect & r =
+            bb.mUseTexcoordRect ? bb.mTexcoordRect : mTextureCoords[bb.mTexcoordIndex];
+
+		/*
+            // Left-top
+            // Positions
+            *mLockPtr++ = -50 + bb.mPosition.x;
+            *mLockPtr++ = 50 + bb.mPosition.y;
+            *mLockPtr++ = 0  + bb.mPosition.z;
+            // Colour
+            // Convert float* to RGBA*
+            pCol = static_cast<RGBA*>(static_cast<void*>(mLockPtr));
+            *pCol++ = colour;
+            // Update lock pointer
+            mLockPtr = static_cast<float*>(static_cast<void*>(pCol));
+            // Texture coords
+            *mLockPtr++ = r.left;
+            *mLockPtr++ = r.bottom;
+
+            // Right-top
+            // Positions
+            *mLockPtr++ = 50 + bb.mPosition.x;
+            *mLockPtr++ = 50 + bb.mPosition.y;
+            *mLockPtr++ = 0 + bb.mPosition.z;
+            // Colour
+            // Convert float* to RGBA*
+            pCol = static_cast<RGBA*>(static_cast<void*>(mLockPtr));
+            *pCol++ = colour;
+            // Update lock pointer
+            mLockPtr = static_cast<float*>(static_cast<void*>(pCol));
+            // Texture coords
+            *mLockPtr++ = r.right;
+            *mLockPtr++ = r.bottom;
+
+            // Left-bottom
+            // Positions
+            *mLockPtr++ = -50 + bb.mPosition.x;
+            *mLockPtr++ = -50 + bb.mPosition.y;
+            *mLockPtr++ = 0 + bb.mPosition.z;
+            // Colour
+            // Convert float* to RGBA*
+            pCol = static_cast<RGBA*>(static_cast<void*>(mLockPtr));
+            *pCol++ = colour;
+            // Update lock pointer
+            mLockPtr = static_cast<float*>(static_cast<void*>(pCol));
+            // Texture coords
+            *mLockPtr++ = r.left;
+            *mLockPtr++ = r.top;
+
+            // Right-bottom
+            // Positions
+            *mLockPtr++ = 50 + bb.mPosition.x;
+            *mLockPtr++ = -50 + bb.mPosition.y;
+            *mLockPtr++ = 0 + bb.mPosition.z;
+            // Colour
+            // Convert float* to RGBA*
+            pCol = static_cast<RGBA*>(static_cast<void*>(mLockPtr));
+            *pCol++ = colour;
+            // Update lock pointer
+            mLockPtr = static_cast<float*>(static_cast<void*>(pCol));
+            // Texture coords
+            *mLockPtr++ = r.right;
+            *mLockPtr++ = r.top;*/
+       
+		float width;
+		if(bb.hasOwnDimensions())
+			width = bb.getOwnWidth() / 2.0;
+		else
+			width = getDefaultWidth() / 2.0;
+
+		static float TexData[24] = 
+		{
+			r.left,		r.top,			-width,  width, 
+			r.left,		r.bottom,		-width, -width, 
+            r.right,	r.bottom,		 width,	-width, 
+			r.right,	r.top,			 width,	 width, 
+            r.left,		r.top,			-width,  width, 
+			r.right,	r.bottom,		 width,	-width 
+		};
+
+	   for(int i=0;i<6;i++)
+	   {
+		   *mLockPtr++ =  bb.mPosition.x;
+            *mLockPtr++ =  bb.mPosition.y;
+            *mLockPtr++ = bb.mPosition.z;
+
+			 pCol = static_cast<RGBA*>(static_cast<void*>(mLockPtr));
+            *pCol++ = colour;
+
+			 mLockPtr = static_cast<float*>(static_cast<void*>(pCol));
+            // Texture coords
+            *mLockPtr++ = TexData[i*4+0];
+            *mLockPtr++ = TexData[i*4+1];
+			*mLockPtr++ = TexData[i*4+2];
+			*mLockPtr++ = TexData[i*4+3];
+           
+	   }
+    }
+	//-----------------------------------------------------------------------
+    const String& SpriteSet::getMovableType(void) const
+    {
+		return SpriteSetFactory::FACTORY_TYPE_NAME;
+    }
+	//-----------------------------------------------------------------------
+	//-----------------------------------------------------------------------
+	String SpriteSetFactory::FACTORY_TYPE_NAME = "SpriteSet";
+	//-----------------------------------------------------------------------
+	const String& SpriteSetFactory::getType(void) const
+	{
+		return FACTORY_TYPE_NAME;
+	}
+	//-----------------------------------------------------------------------
+	MovableObject* SpriteSetFactory::createInstanceImpl( const String& name,
+		const NameValuePairList* params)
+	{
+		// may have parameters
+		bool externalData = false;
+		unsigned int poolSize = 0;
+
+		if (params != 0)
+		{
+			NameValuePairList::const_iterator ni = params->find("poolSize");
+			if (ni != params->end())
+			{
+				poolSize = StringConverter::parseUnsignedInt(ni->second);
+			}
+			ni = params->find("externalData");
+			if (ni != params->end())
+			{
+				externalData = StringConverter::parseBool(ni->second);
+			}
+
+		}
+
+		if (poolSize > 0)
+		{
+			return new SpriteSet(name, poolSize, externalData);
+		}
+		else
+		{
+			return new SpriteSet(name);
+		}
+
+	}
+	//-----------------------------------------------------------------------
+	void SpriteSetFactory::destroyInstance( MovableObject* obj)
+	{
+		delete obj;
+	}
+}
+
+#endif
Index: OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/src/OgrePass.cpp
===================================================================
--- OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/src/OgrePass.cpp	(revision 768)
+++ OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/src/OgrePass.cpp	(revision 768)
@@ -0,0 +1,1396 @@
+/*
+-----------------------------------------------------------------------------
+This source file is part of OGRE
+    (Object-oriented Graphics Rendering Engine)
+For the latest info, see http://ogre.sourceforge.net/
+
+Copyright (c) 2000-2005 The OGRE Team
+Also see acknowledgements in Readme.html
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+#include "OgreStableHeaders.h"
+
+#include "OgrePass.h"
+#include "OgreTechnique.h"
+#include "OgreException.h"
+#include "OgreGpuProgramUsage.h"
+#include "OgreTextureUnitState.h"
+#include "OgreStringConverter.h"
+
+namespace Ogre {
+	
+    //-----------------------------------------------------------------------------
+	Pass::PassSet Pass::msDirtyHashList;
+    Pass::PassSet Pass::msPassGraveyard;
+    //-----------------------------------------------------------------------------
+	Pass::Pass(Technique* parent, unsigned short index)
+        : mParent(parent), mIndex(index), mPassIterationCount(0)
+    {
+#ifdef GAMETOOLS_ILLUMINATION_MODULE
+		mActive = true;
+#endif
+        // Default to white ambient & diffuse, no specular / emissive
+	    mAmbient = mDiffuse = ColourValue::White;
+	    mSpecular = mEmissive = ColourValue::Black;
+	    mShininess = 0;
+        mPointSize = 1.0f;
+		mPointMinSize = 0.0f;
+		mPointMaxSize = 0.0f;
+		mPointSpritesEnabled = false;
+		mPointAttenuationEnabled = false;
+		mPointAttenuationCoeffs[0] = 1.0f;
+		mPointAttenuationCoeffs[1] = mPointAttenuationCoeffs[2] = 0.0f;
+        mTracking = TVC_NONE;
+        mHash = 0;
+
+        // By default, don't override the scene's fog settings
+        mFogOverride = false;
+        mFogMode = FOG_NONE;
+        mFogColour = ColourValue::White;
+        mFogStart = 0.0;
+        mFogEnd = 1.0;
+        mFogDensity = 0.001;
+
+	    // Default blending (overwrite)
+	    mSourceBlendFactor = SBF_ONE;
+	    mDestBlendFactor = SBF_ZERO;
+
+	    mDepthCheck = true;
+	    mDepthWrite = true;
+        mColourWrite = true;
+	    mDepthFunc = CMPF_LESS_EQUAL;
+        mDepthBias = 0;
+		mAlphaRejectFunc = CMPF_ALWAYS_PASS;
+		mAlphaRejectVal = 0;
+	    mCullMode = CULL_CLOCKWISE;
+	    mManualCullMode = MANUAL_CULL_BACK;
+	    mLightingEnabled = true;
+        mMaxSimultaneousLights = OGRE_MAX_SIMULTANEOUS_LIGHTS;
+		mIteratePerLight = false;
+        mRunOnlyForOneLightType = true;
+        mOnlyLightType = Light::LT_POINT;
+	    mShadeOptions = SO_GOURAUD;
+		mPolygonMode = PM_SOLID;
+
+		mVertexProgramUsage = NULL;
+        mShadowCasterVertexProgramUsage = NULL;
+        mShadowReceiverVertexProgramUsage = NULL;
+		mShadowReceiverFragmentProgramUsage = NULL;
+		mFragmentProgramUsage = NULL;
+
+        mQueuedForDeletion = false;
+
+        // default name to index
+        mName = StringConverter::toString(mIndex);
+
+        _dirtyHash();
+   }
+	
+    //-----------------------------------------------------------------------------
+	Pass::Pass(Technique *parent, unsigned short index, const Pass& oth)
+        :mParent(parent), mIndex(index), mQueuedForDeletion(false), mPassIterationCount(0)
+    {
+#ifdef GAMETOOLS_ILLUMINATION_MODULE
+		mActive = true;
+#endif
+        *this = oth;
+        mParent = parent;
+        mIndex = index;
+        mQueuedForDeletion = false;
+        _dirtyHash();
+    }
+    //-----------------------------------------------------------------------------
+    Pass::~Pass()
+    {
+
+    }
+    //-----------------------------------------------------------------------------
+    Pass& Pass::operator=(const Pass& oth)
+    {
+#ifdef GAMETOOLS_ILLUMINATION_MODULE
+		mActive = oth.mActive;
+#endif
+        mName = oth.mName;
+	    mAmbient = oth.mAmbient;
+        mDiffuse = oth.mDiffuse;
+	    mSpecular = oth.mSpecular;
+        mEmissive = oth.mEmissive;
+	    mShininess = oth.mShininess;
+        mTracking = oth.mTracking;
+
+        // Copy fog parameters
+        mFogOverride = oth.mFogOverride;
+        mFogMode = oth.mFogMode;
+        mFogColour = oth.mFogColour;
+        mFogStart = oth.mFogStart;
+        mFogEnd = oth.mFogEnd;
+        mFogDensity = oth.mFogDensity;
+
+	    // Default blending (overwrite)
+	    mSourceBlendFactor = oth.mSourceBlendFactor;
+	    mDestBlendFactor = oth.mDestBlendFactor;
+
+	    mDepthCheck = oth.mDepthCheck;
+	    mDepthWrite = oth.mDepthWrite;
+		mAlphaRejectFunc = oth.mAlphaRejectFunc;
+		mAlphaRejectVal = oth.mAlphaRejectVal;
+        mColourWrite = oth.mColourWrite;
+	    mDepthFunc = oth.mDepthFunc;
+        mDepthBias = oth.mDepthBias;
+	    mCullMode = oth.mCullMode;
+	    mManualCullMode = oth.mManualCullMode;
+	    mLightingEnabled = oth.mLightingEnabled;
+        mMaxSimultaneousLights = oth.mMaxSimultaneousLights;
+		mIteratePerLight = oth.mIteratePerLight;
+        mRunOnlyForOneLightType = oth.mRunOnlyForOneLightType;
+        mOnlyLightType = oth.mOnlyLightType;
+	    mShadeOptions = oth.mShadeOptions;
+		mPolygonMode = oth.mPolygonMode;
+        mPassIterationCount = oth.mPassIterationCount;
+		mPointSize = oth.mPointSize;
+		mPointMinSize = oth.mPointMinSize;
+		mPointMaxSize = oth.mPointMaxSize;
+		mPointSpritesEnabled = oth.mPointSpritesEnabled;
+		mPointAttenuationEnabled = oth.mPointAttenuationEnabled;
+		memcpy(mPointAttenuationCoeffs, oth.mPointAttenuationCoeffs, sizeof(Real)*3);
+
+
+		if (oth.mVertexProgramUsage)
+		{
+			mVertexProgramUsage = new GpuProgramUsage(*(oth.mVertexProgramUsage));
+		}
+		else
+		{
+		    mVertexProgramUsage = NULL;
+		}
+        if (oth.mShadowCasterVertexProgramUsage)
+        {
+            mShadowCasterVertexProgramUsage = new GpuProgramUsage(*(oth.mShadowCasterVertexProgramUsage));
+        }
+        else
+        {
+            mShadowCasterVertexProgramUsage = NULL;
+        }
+        if (oth.mShadowReceiverVertexProgramUsage)
+        {
+            mShadowReceiverVertexProgramUsage = new GpuProgramUsage(*(oth.mShadowReceiverVertexProgramUsage));
+        }
+        else
+        {
+            mShadowReceiverVertexProgramUsage = NULL;
+        }
+		if (oth.mFragmentProgramUsage)
+		{
+		    mFragmentProgramUsage = new GpuProgramUsage(*(oth.mFragmentProgramUsage));
+        }
+        else
+        {
+		    mFragmentProgramUsage = NULL;
+        }
+		if (oth.mShadowReceiverFragmentProgramUsage)
+		{
+			mShadowReceiverFragmentProgramUsage = new GpuProgramUsage(*(oth.mShadowReceiverFragmentProgramUsage));
+		}
+		else
+		{
+			mShadowReceiverFragmentProgramUsage = NULL;
+		}
+
+		TextureUnitStates::const_iterator i, iend;
+
+        // Clear texture units but doesn't notify need recompilation in the case
+        // we are cloning, The parent material will take care of this.
+        iend = mTextureUnitStates.end();
+        for (i = mTextureUnitStates.begin(); i != iend; ++i)
+        {
+            delete *i;
+        }
+
+        mTextureUnitStates.clear();
+
+		// Copy texture units
+		iend = oth.mTextureUnitStates.end();
+		for (i = oth.mTextureUnitStates.begin(); i != iend; ++i)
+		{
+			TextureUnitState* t = new TextureUnitState(this, *(*i));
+			mTextureUnitStates.push_back(t);
+		}
+
+        _dirtyHash();
+
+		return *this;
+    }
+    //-----------------------------------------------------------------------
+    void Pass::setName(const String& name)
+    {
+        mName = name;
+    }
+    //-----------------------------------------------------------------------
+    void Pass::setPointSize(Real ps)
+    {
+	    mPointSize = ps;
+    }
+    //-----------------------------------------------------------------------
+	void Pass::setPointSpritesEnabled(bool enabled)
+	{
+		mPointSpritesEnabled = enabled;
+	}
+    //-----------------------------------------------------------------------
+	bool Pass::getPointSpritesEnabled(void) const
+	{
+		return mPointSpritesEnabled;
+	}
+    //-----------------------------------------------------------------------
+	void Pass::setPointAttenuation(bool enabled, 
+		Real constant, Real linear, Real quadratic)
+	{
+		mPointAttenuationEnabled = enabled;
+		mPointAttenuationCoeffs[0] = constant;
+		mPointAttenuationCoeffs[1] = linear;
+		mPointAttenuationCoeffs[2] = quadratic;
+	}
+    //-----------------------------------------------------------------------
+	bool Pass::isPointAttenuationEnabled(void) const
+	{
+		return mPointAttenuationEnabled;
+	}
+    //-----------------------------------------------------------------------
+	Real Pass::getPointAttenuationConstant(void) const
+	{
+		return mPointAttenuationCoeffs[0];
+	}
+    //-----------------------------------------------------------------------
+	Real Pass::getPointAttenuationLinear(void) const
+	{
+		return mPointAttenuationCoeffs[1];
+	}
+    //-----------------------------------------------------------------------
+	Real Pass::getPointAttenuationQuadratic(void) const
+	{
+		return mPointAttenuationCoeffs[2];
+	}
+    //-----------------------------------------------------------------------
+	void Pass::setPointMinSize(Real min)
+	{
+		mPointMinSize = min;
+	}
+    //-----------------------------------------------------------------------
+	Real Pass::getPointMinSize(void) const
+	{
+		return mPointMinSize;
+	}
+    //-----------------------------------------------------------------------
+	void Pass::setPointMaxSize(Real max)
+	{
+		mPointMaxSize = max;
+	}
+    //-----------------------------------------------------------------------
+	Real Pass::getPointMaxSize(void) const
+	{
+		return mPointMaxSize;
+	}
+    //-----------------------------------------------------------------------
+    void Pass::setAmbient(Real red, Real green, Real blue)
+    {
+	    mAmbient.r = red;
+	    mAmbient.g = green;
+	    mAmbient.b = blue;
+
+    }
+    //-----------------------------------------------------------------------
+    void Pass::setAmbient(const ColourValue& ambient)
+    {
+	    mAmbient = ambient;
+    }
+    //-----------------------------------------------------------------------
+    void Pass::setDiffuse(Real red, Real green, Real blue, Real alpha)
+    {
+	    mDiffuse.r = red;
+	    mDiffuse.g = green;
+	    mDiffuse.b = blue;
+		mDiffuse.a = alpha;
+    }
+    //-----------------------------------------------------------------------
+    void Pass::setDiffuse(const ColourValue& diffuse)
+    {
+	    mDiffuse = diffuse;
+    }
+    //-----------------------------------------------------------------------
+    void Pass::setSpecular(Real red, Real green, Real blue, Real alpha)
+    {
+	    mSpecular.r = red;
+	    mSpecular.g = green;
+	    mSpecular.b = blue;
+		mSpecular.a = alpha;
+    }
+    //-----------------------------------------------------------------------
+    void Pass::setSpecular(const ColourValue& specular)
+    {
+	    mSpecular = specular;
+    }
+    //-----------------------------------------------------------------------
+    void Pass::setShininess(Real val)
+    {
+	    mShininess = val;
+    }
+    //-----------------------------------------------------------------------
+    void Pass::setSelfIllumination(Real red, Real green, Real blue)
+    {
+	    mEmissive.r = red;
+	    mEmissive.g = green;
+	    mEmissive.b = blue;
+
+    }
+    //-----------------------------------------------------------------------
+    void Pass::setSelfIllumination(const ColourValue& selfIllum)
+    {
+	    mEmissive = selfIllum;
+    }
+    //-----------------------------------------------------------------------
+    void Pass::setVertexColourTracking(TrackVertexColourType tracking)
+    {
+        mTracking = tracking;
+    }
+    //-----------------------------------------------------------------------
+    Real Pass::getPointSize(void) const
+    {
+	    return mPointSize;
+    }
+    //-----------------------------------------------------------------------
+    const ColourValue& Pass::getAmbient(void) const
+    {
+	    return mAmbient;
+    }
+    //-----------------------------------------------------------------------
+    const ColourValue& Pass::getDiffuse(void) const
+    {
+	    return mDiffuse;
+    }
+    //-----------------------------------------------------------------------
+    const ColourValue& Pass::getSpecular(void) const
+    {
+	    return mSpecular;
+    }
+    //-----------------------------------------------------------------------
+    const ColourValue& Pass::getSelfIllumination(void) const
+    {
+	    return mEmissive;
+    }
+    //-----------------------------------------------------------------------
+    Real Pass::getShininess(void) const
+    {
+	    return mShininess;
+    }
+    //-----------------------------------------------------------------------
+    TrackVertexColourType Pass::getVertexColourTracking(void) const
+    {
+        return mTracking;
+    }
+    //-----------------------------------------------------------------------
+    TextureUnitState* Pass::createTextureUnitState(void)
+    {
+        TextureUnitState *t = new TextureUnitState(this);
+        addTextureUnitState(t);
+	    return t;
+    }
+    //-----------------------------------------------------------------------
+    TextureUnitState* Pass::createTextureUnitState(
+        const String& textureName, unsigned short texCoordSet)
+    {
+        TextureUnitState *t = new TextureUnitState(this);
+	    t->setTextureName(textureName);
+	    t->setTextureCoordSet(texCoordSet);
+        addTextureUnitState(t);
+	    return t;
+    }
+    //-----------------------------------------------------------------------
+	void Pass::addTextureUnitState(TextureUnitState* state)
+	{
+        assert(state && "state is 0 in Pass::addTextureUnitState()");
+        if (state)
+        {
+            // only attach TUS to pass if TUS does not belong to another pass
+            if ((state->getParent() == 0) || (state->getParent() == this))
+            {
+		        mTextureUnitStates.push_back(state);
+				// Notify state
+				state->_notifyParent(this);
+                // if texture unit state name is empty then give it a default name based on its index
+                if (state->getName().empty())
+                {
+                    // its the last entry in the container so its index is size - 1
+                    size_t idx = mTextureUnitStates.size() - 1;
+                    state->setName( StringConverter::toString(idx) );
+                }
+                // Needs recompilation
+                mParent->_notifyNeedsRecompile();
+                _dirtyHash();
+            }
+            else
+            {
+			    OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "TextureUnitState already attached to another pass",
+				    "Pass:addTextureUnitState");
+
+            }
+        }
+	}
+    //-----------------------------------------------------------------------
+    TextureUnitState* Pass::getTextureUnitState(unsigned short index) 
+    {
+        assert (index < mTextureUnitStates.size() && "Index out of bounds");
+	    return mTextureUnitStates[index];
+    }
+    //-----------------------------------------------------------------------------
+    TextureUnitState* Pass::getTextureUnitState(const String& name)
+    {
+        TextureUnitStates::iterator i    = mTextureUnitStates.begin();
+        TextureUnitStates::iterator iend = mTextureUnitStates.end();
+        TextureUnitState* foundTUS = 0;
+
+        // iterate through TUS Container to find a match
+        while (i != iend)
+        {
+            if ( (*i)->getName() == name )
+            {
+                foundTUS = (*i);
+                break;
+            }
+
+            ++i;
+        }
+
+        return foundTUS;
+    }
+	//-----------------------------------------------------------------------
+	const TextureUnitState* Pass::getTextureUnitState(unsigned short index) const
+	{
+		assert (index < mTextureUnitStates.size() && "Index out of bounds");
+		return mTextureUnitStates[index];
+	}
+	//-----------------------------------------------------------------------------
+	const TextureUnitState* Pass::getTextureUnitState(const String& name) const
+	{
+		TextureUnitStates::const_iterator i    = mTextureUnitStates.begin();
+		TextureUnitStates::const_iterator iend = mTextureUnitStates.end();
+		const TextureUnitState* foundTUS = 0;
+
+		// iterate through TUS Container to find a match
+		while (i != iend)
+		{
+			if ( (*i)->getName() == name )
+			{
+				foundTUS = (*i);
+				break;
+			}
+
+			++i;
+		}
+
+		return foundTUS;
+	}
+
+    //-----------------------------------------------------------------------
+    unsigned short Pass::getTextureUnitStateIndex(const TextureUnitState* state)
+    {
+        assert(state && "state is 0 in Pass::addTextureUnitState()");
+        unsigned short idx = 0;
+
+        // only find index for state attached to this pass
+        if (state->getParent() == this)
+        {
+            // iterate through TUS container and find matching pointer to state
+            TextureUnitStates::iterator i    = mTextureUnitStates.begin();
+            TextureUnitStates::iterator iend = mTextureUnitStates.end();
+            while (i != iend)
+            {
+                if ( (*i) == state )
+                {
+                    // calculate index
+                    idx = static_cast<unsigned short>(i - mTextureUnitStates.begin());
+                    break;
+                }
+
+                ++i;
+            }
+        }
+        else
+        {
+			OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "TextureUnitState is not attached to this pass",
+				"Pass:getTextureUnitStateIndex");
+        }
+
+        return idx;
+    }
+
+    //-----------------------------------------------------------------------
+    Pass::TextureUnitStateIterator
+        Pass::getTextureUnitStateIterator(void)
+    {
+        return TextureUnitStateIterator(mTextureUnitStates.begin(), mTextureUnitStates.end());
+    }
+	//-----------------------------------------------------------------------
+	Pass::ConstTextureUnitStateIterator
+		Pass::getTextureUnitStateIterator(void) const
+	{
+		return ConstTextureUnitStateIterator(mTextureUnitStates.begin(), mTextureUnitStates.end());
+	}
+    //-----------------------------------------------------------------------
+    void Pass::removeTextureUnitState(unsigned short index)
+    {
+        assert (index < mTextureUnitStates.size() && "Index out of bounds");
+
+        TextureUnitStates::iterator i = mTextureUnitStates.begin() + index;
+        delete *i;
+	    mTextureUnitStates.erase(i);
+        if (!mQueuedForDeletion)
+        {
+            // Needs recompilation
+            mParent->_notifyNeedsRecompile();
+        }
+        _dirtyHash();
+    }
+    //-----------------------------------------------------------------------
+    void Pass::removeAllTextureUnitStates(void)
+    {
+        TextureUnitStates::iterator i, iend;
+        iend = mTextureUnitStates.end();
+        for (i = mTextureUnitStates.begin(); i != iend; ++i)
+        {
+            delete *i;
+        }
+        mTextureUnitStates.clear();
+        if (!mQueuedForDeletion)
+        {        
+            // Needs recompilation
+            mParent->_notifyNeedsRecompile();
+        }
+        _dirtyHash();
+    }
+    //-----------------------------------------------------------------------
+    void Pass::setSceneBlending(SceneBlendType sbt)
+    {
+	    // Turn predefined type into blending factors
+	    switch (sbt)
+	    {
+	    case SBT_TRANSPARENT_ALPHA:
+		    setSceneBlending(SBF_SOURCE_ALPHA, SBF_ONE_MINUS_SOURCE_ALPHA);
+		    break;
+	    case SBT_TRANSPARENT_COLOUR:
+		    setSceneBlending(SBF_SOURCE_COLOUR, SBF_ONE_MINUS_SOURCE_COLOUR);
+		    break;
+		case SBT_MODULATE:
+			setSceneBlending(SBF_DEST_COLOUR, SBF_ZERO);
+			break;
+	    case SBT_ADD:
+		    setSceneBlending(SBF_ONE, SBF_ONE);
+		    break;
+        case SBT_REPLACE:
+            setSceneBlending(SBF_ONE, SBF_ZERO);
+            break;
+	    // TODO: more
+	    }
+
+    }
+    //-----------------------------------------------------------------------
+    void Pass::setSceneBlending(SceneBlendFactor sourceFactor, SceneBlendFactor destFactor)
+    {
+	    mSourceBlendFactor = sourceFactor;
+	    mDestBlendFactor = destFactor;
+    }
+    //-----------------------------------------------------------------------
+    SceneBlendFactor Pass::getSourceBlendFactor(void) const
+    {
+	    return mSourceBlendFactor;
+    }
+    //-----------------------------------------------------------------------
+    SceneBlendFactor Pass::getDestBlendFactor(void) const
+    {
+	    return mDestBlendFactor;
+    }
+    //-----------------------------------------------------------------------
+    bool Pass::isTransparent(void) const
+    {
+		// Transparent if any of the destination colour is taken into account
+		if (mDestBlendFactor == SBF_ZERO && 
+			mSourceBlendFactor != SBF_DEST_COLOUR && 
+			mSourceBlendFactor != SBF_ONE_MINUS_DEST_COLOUR && 
+			mSourceBlendFactor != SBF_DEST_ALPHA && 
+			mSourceBlendFactor != SBF_ONE_MINUS_DEST_ALPHA)
+		{
+		    return false;
+		}
+	    else
+		{
+		    return true;
+		}
+    }
+    //-----------------------------------------------------------------------
+    void Pass::setDepthCheckEnabled(bool enabled)
+    {
+	    mDepthCheck = enabled;
+    }
+    //-----------------------------------------------------------------------
+    bool Pass::getDepthCheckEnabled(void) const
+    {
+	    return mDepthCheck;
+    }
+    //-----------------------------------------------------------------------
+    void Pass::setDepthWriteEnabled(bool enabled)
+    {
+	    mDepthWrite = enabled;
+    }
+    //-----------------------------------------------------------------------
+    bool Pass::getDepthWriteEnabled(void) const
+    {
+	    return mDepthWrite;
+    }
+    //-----------------------------------------------------------------------
+    void Pass::setDepthFunction( CompareFunction func)
+    {
+	    mDepthFunc = func;
+    }
+    //-----------------------------------------------------------------------
+    CompareFunction Pass::getDepthFunction(void) const
+    {
+	    return mDepthFunc;
+    }
+	//-----------------------------------------------------------------------
+	void Pass::setAlphaRejectSettings(CompareFunction func, unsigned char value)
+	{
+		mAlphaRejectFunc = func;
+		mAlphaRejectVal = value;
+	}
+	//-----------------------------------------------------------------------
+	void Pass::setAlphaRejectFunction(CompareFunction func)
+	{
+		mAlphaRejectFunc = func;
+	}
+	//-----------------------------------------------------------------------
+	void Pass::setAlphaRejectValue(unsigned char val)
+	{
+		mAlphaRejectVal = val;
+	}
+    //-----------------------------------------------------------------------
+	void Pass::setColourWriteEnabled(bool enabled)
+	{
+		mColourWrite = enabled;
+	}
+    //-----------------------------------------------------------------------
+	bool Pass::getColourWriteEnabled(void) const
+	{
+		return mColourWrite;
+	}
+    //-----------------------------------------------------------------------
+    void Pass::setCullingMode( CullingMode mode)
+    {
+	    mCullMode = mode;
+    }
+    //-----------------------------------------------------------------------
+    CullingMode Pass::getCullingMode(void) const
+    {
+	    return mCullMode;
+    }
+    //-----------------------------------------------------------------------
+    void Pass::setLightingEnabled(bool enabled)
+    {
+	    mLightingEnabled = enabled;
+    }
+    //-----------------------------------------------------------------------
+    bool Pass::getLightingEnabled(void) const
+    {
+	    return mLightingEnabled;
+    }
+    //-----------------------------------------------------------------------
+    void Pass::setMaxSimultaneousLights(unsigned short maxLights)
+    {
+        mMaxSimultaneousLights = maxLights;
+    }
+    //-----------------------------------------------------------------------
+    unsigned short Pass::getMaxSimultaneousLights(void) const
+    {
+        return mMaxSimultaneousLights;
+    }
+    //-----------------------------------------------------------------------
+    void Pass::setIteratePerLight(bool enabled, 
+            bool onlyForOneLightType, Light::LightTypes lightType)
+    {
+        mIteratePerLight = enabled;
+        mRunOnlyForOneLightType = onlyForOneLightType;
+        mOnlyLightType = lightType;
+    }
+    //-----------------------------------------------------------------------
+    void Pass::setShadingMode(ShadeOptions mode)
+    {
+	    mShadeOptions = mode;
+    }
+    //-----------------------------------------------------------------------
+    ShadeOptions Pass::getShadingMode(void) const
+    {
+	    return mShadeOptions;
+    }
+	//-----------------------------------------------------------------------
+	void Pass::setPolygonMode(PolygonMode mode)
+	{
+		mPolygonMode = mode;
+	}
+	//-----------------------------------------------------------------------
+	PolygonMode Pass::getPolygonMode(void) const
+	{
+		return mPolygonMode;
+	}
+    //-----------------------------------------------------------------------
+    void Pass::setManualCullingMode(ManualCullingMode mode)
+    {
+	    mManualCullMode = mode;
+    }
+    //-----------------------------------------------------------------------
+    ManualCullingMode Pass::getManualCullingMode(void) const
+    {
+	    return mManualCullMode;
+    }
+    //-----------------------------------------------------------------------
+    void Pass::setFog(bool overrideScene, FogMode mode, const ColourValue& colour, Real density, Real start, Real end)
+    {
+	    mFogOverride = overrideScene;
+	    if (overrideScene)
+	    {
+		    mFogMode = mode;
+		    mFogColour = colour;
+		    mFogStart = start;
+		    mFogEnd = end;
+		    mFogDensity = density;
+	    }
+    }
+    //-----------------------------------------------------------------------
+    bool Pass::getFogOverride(void) const
+    {
+	    return mFogOverride;
+    }
+    //-----------------------------------------------------------------------
+    FogMode Pass::getFogMode(void) const
+    {
+	    return mFogMode;
+    }
+    //-----------------------------------------------------------------------
+    const ColourValue& Pass::getFogColour(void) const
+    {
+	    return mFogColour;
+    }
+    //-----------------------------------------------------------------------
+    Real Pass::getFogStart(void) const
+    {
+	    return mFogStart;
+    }
+    //-----------------------------------------------------------------------
+    Real Pass::getFogEnd(void) const
+    {
+	    return mFogEnd;
+    }
+    //-----------------------------------------------------------------------
+    Real Pass::getFogDensity(void) const
+    {
+	    return mFogDensity;
+    }
+    //-----------------------------------------------------------------------
+    void Pass::setDepthBias(ushort bias)
+    {
+        assert(bias <= 16 && "Depth bias must be between 0 and 16");
+        mDepthBias = bias;
+    }
+    //-----------------------------------------------------------------------
+    ushort Pass::getDepthBias(void) const
+    {
+        return mDepthBias;
+    }
+    //-----------------------------------------------------------------------
+	Pass* Pass::_split(unsigned short numUnits)
+	{
+		if (mVertexProgramUsage || mFragmentProgramUsage)
+		{
+			OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Programmable passes cannot be "
+				"automatically split, define a fallback technique instead.",
+				"Pass:_split");
+		}
+
+		if (mTextureUnitStates.size() > numUnits)
+		{
+			size_t start = mTextureUnitStates.size() - numUnits;
+			
+			Pass* newPass = mParent->createPass();
+
+			TextureUnitStates::iterator istart, i, iend;
+			iend = mTextureUnitStates.end();
+			i = istart = mTextureUnitStates.begin() + start;
+			// Set the new pass to fallback using scene blend
+			newPass->setSceneBlending(
+				(*i)->getColourBlendFallbackSrc(), (*i)->getColourBlendFallbackDest());
+			// Fixup the texture unit 0   of new pass   blending method   to replace
+			// all colour and alpha   with texture without adjustment, because we
+			// assume it's detail texture.
+			(*i)->setColourOperationEx(LBX_SOURCE1,   LBS_TEXTURE, LBS_CURRENT);
+			(*i)->setAlphaOperation(LBX_SOURCE1, LBS_TEXTURE, LBS_CURRENT);
+
+			// Add all the other texture unit states
+			for (; i != iend; ++i)
+			{
+				// detach from parent first
+				(*i)->_notifyParent(0);
+				newPass->addTextureUnitState(*i);
+			}
+			// Now remove texture units from this Pass, we don't need to delete since they've
+			// been transferred
+			mTextureUnitStates.erase(istart, iend);
+			_dirtyHash();
+			return newPass;
+		}
+		return NULL;
+	}
+	//-----------------------------------------------------------------------------
+	void Pass::_notifyIndex(unsigned short index)
+	{
+		if (mIndex != index)
+		{
+			mIndex = index;
+			_dirtyHash();
+		}
+	}
+    //-----------------------------------------------------------------------
+	void Pass::_load(void)
+	{
+		// We assume the Technique only calls this when the material is being
+		// loaded
+
+		// Load each TextureUnitState
+		TextureUnitStates::iterator i, iend;
+		iend = mTextureUnitStates.end();
+		for (i = mTextureUnitStates.begin(); i != iend; ++i)
+		{
+			(*i)->_load();
+		}
+
+		// Load programs
+		if (mVertexProgramUsage)
+		{
+			// Load vertex program
+            mVertexProgramUsage->_load();
+        }
+        if (mShadowCasterVertexProgramUsage)
+        {
+            // Load vertex program
+            mShadowCasterVertexProgramUsage->_load();
+        }
+        if (mShadowReceiverVertexProgramUsage)
+        {
+            // Load vertex program
+            mShadowReceiverVertexProgramUsage->_load();
+        }
+
+        if (mFragmentProgramUsage)
+        {
+			// Load fragment program
+            mFragmentProgramUsage->_load();
+		}
+		if (mShadowReceiverFragmentProgramUsage)
+		{
+			// Load Fragment program
+			mShadowReceiverFragmentProgramUsage->_load();
+		}
+
+        // Recalculate hash
+        _dirtyHash();
+		
+	}
+    //-----------------------------------------------------------------------
+	void Pass::_unload(void)
+	{
+		// Unload each TextureUnitState
+		TextureUnitStates::iterator i, iend;
+		iend = mTextureUnitStates.end();
+		for (i = mTextureUnitStates.begin(); i != iend; ++i)
+		{
+			(*i)->_unload();
+		}
+
+		// Unload programs
+		if (mVertexProgramUsage)
+		{
+			// TODO
+		}
+        if (mFragmentProgramUsage)
+        {
+            // TODO
+        }
+	}
+    //-----------------------------------------------------------------------
+	void Pass::setVertexProgram(const String& name, bool resetParams)
+	{
+        // Turn off vertex program if name blank
+        if (name.empty())
+        {
+            if (mVertexProgramUsage) delete mVertexProgramUsage;
+            mVertexProgramUsage = NULL;
+        }
+        else
+        {
+            if (!mVertexProgramUsage)
+            {
+                mVertexProgramUsage = new GpuProgramUsage(GPT_VERTEX_PROGRAM);
+            }
+		    mVertexProgramUsage->setProgramName(name, resetParams);
+        }
+        // Needs recompilation
+        mParent->_notifyNeedsRecompile();
+	}
+    //-----------------------------------------------------------------------
+	void Pass::setVertexProgramParameters(GpuProgramParametersSharedPtr params)
+	{
+		if (!mVertexProgramUsage)
+        {
+            OGRE_EXCEPT (Exception::ERR_INVALIDPARAMS, 
+                "This pass does not have a vertex program assigned!", 
+                "Pass::setVertexProgramParameters");
+        }
+		mVertexProgramUsage->setParameters(params);
+	}
+    //-----------------------------------------------------------------------
+	void Pass::setFragmentProgram(const String& name, bool resetParams)
+	{
+        // Turn off fragment program if name blank
+        if (name.empty())
+        {
+            if (mFragmentProgramUsage) delete mFragmentProgramUsage;
+            mFragmentProgramUsage = NULL;
+        }
+        else
+        {
+            if (!mFragmentProgramUsage)
+            {
+                mFragmentProgramUsage = new GpuProgramUsage(GPT_FRAGMENT_PROGRAM);
+            }
+		    mFragmentProgramUsage->setProgramName(name, resetParams);
+        }
+        // Needs recompilation
+        mParent->_notifyNeedsRecompile();
+	}
+    //-----------------------------------------------------------------------
+	void Pass::setFragmentProgramParameters(GpuProgramParametersSharedPtr params)
+	{
+		if (!mFragmentProgramUsage)
+        {
+            OGRE_EXCEPT (Exception::ERR_INVALIDPARAMS, 
+                "This pass does not have a fragment program assigned!", 
+                "Pass::setFragmentProgramParameters");
+        }
+		mFragmentProgramUsage->setParameters(params);
+	}
+	//-----------------------------------------------------------------------
+	const String& Pass::getVertexProgramName(void) const
+	{
+        if (!mVertexProgramUsage)
+            return StringUtil::BLANK;
+        else
+		    return mVertexProgramUsage->getProgramName();
+	}
+	//-----------------------------------------------------------------------
+	GpuProgramParametersSharedPtr Pass::getVertexProgramParameters(void) const
+	{
+		if (!mVertexProgramUsage)
+        {
+            OGRE_EXCEPT (Exception::ERR_INVALIDPARAMS, 
+                "This pass does not have a vertex program assigned!", 
+                "Pass::getVertexProgramParameters");
+        }
+		return mVertexProgramUsage->getParameters();
+	}
+	//-----------------------------------------------------------------------
+	const GpuProgramPtr& Pass::getVertexProgram(void) const
+	{
+		return mVertexProgramUsage->getProgram();
+	}
+	//-----------------------------------------------------------------------
+	const String& Pass::getFragmentProgramName(void) const
+	{
+        if (!mFragmentProgramUsage)
+            return StringUtil::BLANK;
+        else
+    		return mFragmentProgramUsage->getProgramName();
+	}
+	//-----------------------------------------------------------------------
+	GpuProgramParametersSharedPtr Pass::getFragmentProgramParameters(void) const
+	{
+		return mFragmentProgramUsage->getParameters();
+	}
+	//-----------------------------------------------------------------------
+	const GpuProgramPtr& Pass::getFragmentProgram(void) const
+	{
+		return mFragmentProgramUsage->getProgram();
+	}
+	//-----------------------------------------------------------------------
+    bool Pass::isLoaded(void) const
+    {
+        return mParent->isLoaded();
+    }
+	//-----------------------------------------------------------------------
+    uint32 Pass::getHash(void) const
+    {
+        return mHash;
+    }
+	//-----------------------------------------------------------------------
+    void Pass::_recalculateHash(void)
+    {
+        /* Hash format is 32-bit, divided as follows (high to low bits)
+           bits   purpose
+            4     Pass index (i.e. max 16 passes!)
+           14     Hashed texture name from unit 0
+           14     Hashed texture name from unit 1
+
+           Note that at the moment we don't sort on the 3rd texture unit plus
+           on the assumption that these are less frequently used; sorting on 
+           the first 2 gives us the most benefit for now.
+       */
+        _StringHash H;
+        mHash = (mIndex << 28);
+        size_t c = getNumTextureUnitStates();
+
+        if (c && !mTextureUnitStates[0]->isBlank())
+            mHash += (H(mTextureUnitStates[0]->getTextureName()) % (1 << 14)) << 14;
+        if (c > 1 && !mTextureUnitStates[1]->isBlank())
+            mHash += (H(mTextureUnitStates[1]->getTextureName()) % (1 << 14));
+    }
+    //-----------------------------------------------------------------------
+	void Pass::_dirtyHash(void)
+	{
+		// Mark this hash as for follow up
+		msDirtyHashList.insert(this);
+	}
+    //-----------------------------------------------------------------------
+    void Pass::_notifyNeedsRecompile(void)
+    {
+        mParent->_notifyNeedsRecompile();
+    }
+    //-----------------------------------------------------------------------
+    void Pass::setTextureFiltering(TextureFilterOptions filterType)
+    {
+        TextureUnitStates::iterator i, iend;
+        iend = mTextureUnitStates.end();
+        for (i = mTextureUnitStates.begin(); i != iend; ++i)
+        {
+            (*i)->setTextureFiltering(filterType);
+        }
+    }
+    // --------------------------------------------------------------------
+    void Pass::setTextureAnisotropy(unsigned int maxAniso)
+    {
+        TextureUnitStates::iterator i, iend;
+        iend = mTextureUnitStates.end();
+        for (i = mTextureUnitStates.begin(); i != iend; ++i)
+        {
+            (*i)->setTextureAnisotropy(maxAniso);
+        }
+    }
+    //-----------------------------------------------------------------------
+    void Pass::_updateAutoParamsNoLights(const AutoParamDataSource& source) const
+    {
+        if (hasVertexProgram())
+        {
+            // Update vertex program auto params
+            mVertexProgramUsage->getParameters()->_updateAutoParamsNoLights(source);
+        }
+
+        if (hasFragmentProgram())
+        {
+            // Update fragment program auto params
+            mFragmentProgramUsage->getParameters()->_updateAutoParamsNoLights(source);
+        }
+    }
+    //-----------------------------------------------------------------------
+    void Pass::_updateAutoParamsLightsOnly(const AutoParamDataSource& source) const
+    {
+        if (hasVertexProgram())
+        {
+            // Update vertex program auto params
+            mVertexProgramUsage->getParameters()->_updateAutoParamsLightsOnly(source);
+        }
+
+        if (hasFragmentProgram())
+        {
+            // Update fragment program auto params
+            mFragmentProgramUsage->getParameters()->_updateAutoParamsLightsOnly(source);
+        }
+    }
+    //-----------------------------------------------------------------------
+    void Pass::processPendingPassUpdates(void)
+    {
+        // Delete items in the graveyard
+        PassSet::iterator i, iend;
+        iend = msPassGraveyard.end();
+        for (i = msPassGraveyard.begin(); i != iend; ++i)
+        {
+            delete *i;
+        }
+        msPassGraveyard.clear();
+
+        // The dirty ones will have been removed from the groups above using the old hash now
+        iend = msDirtyHashList.end();
+        for (i = msDirtyHashList.begin(); i != iend; ++i)
+        {
+            Pass* p = *i;
+            p->_recalculateHash();
+        }
+        // Clear the dirty list
+        msDirtyHashList.clear();
+    }
+    //-----------------------------------------------------------------------
+    void Pass::queueForDeletion(void)
+    {
+        mQueuedForDeletion = true;
+
+        removeAllTextureUnitStates();
+        if (mVertexProgramUsage)
+        {
+            delete mVertexProgramUsage;
+            mVertexProgramUsage = 0;
+        }
+        if (mShadowCasterVertexProgramUsage)
+        {
+            delete mShadowCasterVertexProgramUsage;
+            mShadowCasterVertexProgramUsage = 0;
+        }
+        if (mShadowReceiverVertexProgramUsage)
+        {
+            delete mShadowReceiverVertexProgramUsage;
+            mShadowReceiverVertexProgramUsage = 0;
+        }
+        if (mFragmentProgramUsage)
+        {
+            delete mFragmentProgramUsage;
+            mFragmentProgramUsage = 0;
+        }
+		if (mShadowReceiverFragmentProgramUsage)
+		{
+			delete mShadowReceiverFragmentProgramUsage;
+			mShadowReceiverFragmentProgramUsage = 0;
+		}
+        // remove from dirty list, if there
+        msDirtyHashList.erase(this);
+
+        msPassGraveyard.insert(this);
+    }
+    //-----------------------------------------------------------------------
+    bool Pass::isAmbientOnly(void) const
+    {
+        // treat as ambient if lighting is off, or colour write is off, 
+        // or all non-ambient (& emissive) colours are black
+        // NB a vertex program could override this, but passes using vertex
+        // programs are expected to indicate they are ambient only by 
+        // setting the state so it matches one of the conditions above, even 
+        // though this state is not used in rendering.
+        return (!mLightingEnabled || !mColourWrite ||
+            (mDiffuse == ColourValue::Black && 
+             mSpecular == ColourValue::Black));
+    }
+    //-----------------------------------------------------------------------
+    void Pass::setShadowCasterVertexProgram(const String& name)
+    {
+        // Turn off vertex program if name blank
+        if (name.empty())
+        {
+            if (mShadowCasterVertexProgramUsage) delete mShadowCasterVertexProgramUsage;
+            mShadowCasterVertexProgramUsage = NULL;
+        }
+        else
+        {
+            if (!mShadowCasterVertexProgramUsage)
+            {
+                mShadowCasterVertexProgramUsage = new GpuProgramUsage(GPT_VERTEX_PROGRAM);
+            }
+            mShadowCasterVertexProgramUsage->setProgramName(name);
+        }
+        // Needs recompilation
+        mParent->_notifyNeedsRecompile();
+    }
+    //-----------------------------------------------------------------------
+    void Pass::setShadowCasterVertexProgramParameters(GpuProgramParametersSharedPtr params)
+    {
+        if (!mShadowCasterVertexProgramUsage)
+        {
+            OGRE_EXCEPT (Exception::ERR_INVALIDPARAMS, 
+                "This pass does not have a shadow caster vertex program assigned!", 
+                "Pass::setShadowCasterVertexProgramParameters");
+        }
+        mShadowCasterVertexProgramUsage->setParameters(params);
+    }
+    //-----------------------------------------------------------------------
+    const String& Pass::getShadowCasterVertexProgramName(void) const
+    {
+        if (!mShadowCasterVertexProgramUsage)
+            return StringUtil::BLANK;
+        else
+            return mShadowCasterVertexProgramUsage->getProgramName();
+    }
+    //-----------------------------------------------------------------------
+    GpuProgramParametersSharedPtr Pass::getShadowCasterVertexProgramParameters(void) const
+    {
+        if (!mShadowCasterVertexProgramUsage)
+        {
+            OGRE_EXCEPT (Exception::ERR_INVALIDPARAMS, 
+                "This pass does not have a shadow caster vertex program assigned!", 
+                "Pass::getShadowCasterVertexProgramParameters");
+        }
+        return mShadowCasterVertexProgramUsage->getParameters();
+    }
+    //-----------------------------------------------------------------------
+    const GpuProgramPtr& Pass::getShadowCasterVertexProgram(void) const
+    {
+        return mShadowCasterVertexProgramUsage->getProgram();
+    }
+    //-----------------------------------------------------------------------
+    void Pass::setShadowReceiverVertexProgram(const String& name)
+    {
+        // Turn off vertex program if name blank
+        if (name.empty())
+        {
+            if (mShadowReceiverVertexProgramUsage) delete mShadowReceiverVertexProgramUsage;
+            mShadowReceiverVertexProgramUsage = NULL;
+        }
+        else
+        {
+            if (!mShadowReceiverVertexProgramUsage)
+            {
+                mShadowReceiverVertexProgramUsage = new GpuProgramUsage(GPT_VERTEX_PROGRAM);
+            }
+            mShadowReceiverVertexProgramUsage->setProgramName(name);
+        }
+        // Needs recompilation
+        mParent->_notifyNeedsRecompile();
+    }
+    //-----------------------------------------------------------------------
+    void Pass::setShadowReceiverVertexProgramParameters(GpuProgramParametersSharedPtr params)
+    {
+        if (!mShadowReceiverVertexProgramUsage)
+        {
+            OGRE_EXCEPT (Exception::ERR_INVALIDPARAMS, 
+                "This pass does not have a shadow receiver vertex program assigned!", 
+                "Pass::setShadowReceiverVertexProgramParameters");
+        }
+        mShadowReceiverVertexProgramUsage->setParameters(params);
+    }
+    //-----------------------------------------------------------------------
+    const String& Pass::getShadowReceiverVertexProgramName(void) const
+    {
+        if (!mShadowReceiverVertexProgramUsage)
+            return StringUtil::BLANK;
+        else
+            return mShadowReceiverVertexProgramUsage->getProgramName();
+    }
+    //-----------------------------------------------------------------------
+    GpuProgramParametersSharedPtr Pass::getShadowReceiverVertexProgramParameters(void) const
+    {
+        if (!mShadowReceiverVertexProgramUsage)
+        {
+            OGRE_EXCEPT (Exception::ERR_INVALIDPARAMS, 
+                "This pass does not have a shadow receiver vertex program assigned!", 
+                "Pass::getShadowReceiverVertexProgramParameters");
+        }
+        return mShadowReceiverVertexProgramUsage->getParameters();
+    }
+    //-----------------------------------------------------------------------
+    const GpuProgramPtr& Pass::getShadowReceiverVertexProgram(void) const
+    {
+        return mShadowReceiverVertexProgramUsage->getProgram();
+    }
+	//-----------------------------------------------------------------------
+	void Pass::setShadowReceiverFragmentProgram(const String& name)
+	{
+		// Turn off Fragment program if name blank
+		if (name.empty())
+		{
+			if (mShadowReceiverFragmentProgramUsage) delete mShadowReceiverFragmentProgramUsage;
+			mShadowReceiverFragmentProgramUsage = NULL;
+		}
+		else
+		{
+			if (!mShadowReceiverFragmentProgramUsage)
+			{
+				mShadowReceiverFragmentProgramUsage = new GpuProgramUsage(GPT_FRAGMENT_PROGRAM);
+			}
+			mShadowReceiverFragmentProgramUsage->setProgramName(name);
+		}
+		// Needs recompilation
+		mParent->_notifyNeedsRecompile();
+	}
+	//-----------------------------------------------------------------------
+	void Pass::setShadowReceiverFragmentProgramParameters(GpuProgramParametersSharedPtr params)
+	{
+		if (!mShadowReceiverFragmentProgramUsage)
+		{
+			OGRE_EXCEPT (Exception::ERR_INVALIDPARAMS, 
+				"This pass does not have a shadow receiver fragment program assigned!", 
+				"Pass::setShadowReceiverFragmentProgramParameters");
+		}
+		mShadowReceiverFragmentProgramUsage->setParameters(params);
+	}
+	//-----------------------------------------------------------------------
+	const String& Pass::getShadowReceiverFragmentProgramName(void) const
+	{
+		if (!mShadowReceiverFragmentProgramUsage)
+			return StringUtil::BLANK;
+		else
+			return mShadowReceiverFragmentProgramUsage->getProgramName();
+	}
+	//-----------------------------------------------------------------------
+	GpuProgramParametersSharedPtr Pass::getShadowReceiverFragmentProgramParameters(void) const
+	{
+		if (!mShadowReceiverFragmentProgramUsage)
+		{
+			OGRE_EXCEPT (Exception::ERR_INVALIDPARAMS, 
+				"This pass does not have a shadow receiver fragment program assigned!", 
+				"Pass::getShadowReceiverFragmentProgramParameters");
+		}
+		return mShadowReceiverFragmentProgramUsage->getParameters();
+	}
+	//-----------------------------------------------------------------------
+	const GpuProgramPtr& Pass::getShadowReceiverFragmentProgram(void) const
+	{
+		return mShadowReceiverFragmentProgramUsage->getProgram();
+	}
+    //-----------------------------------------------------------------------
+	const String& Pass::getResourceGroup(void) const
+	{
+		return mParent->getResourceGroup();
+	}
+
+    //-----------------------------------------------------------------------
+    bool Pass::applyTextureAliases(const AliasTextureNamePairList& aliasList, const bool apply) const
+    {
+        // iterate through each texture unit state and apply the texture alias if it applies
+        TextureUnitStates::const_iterator i, iend;
+        iend = mTextureUnitStates.end();
+        bool testResult = false;
+
+        for (i = mTextureUnitStates.begin(); i != iend; ++i)
+        {
+            if ((*i)->applyTextureAliases(aliasList, apply))
+                testResult = true;
+        }
+
+        return testResult;
+
+    }
+
+
+}
Index: OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/src/OgreRenderTarget.cpp
===================================================================
--- OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/src/OgreRenderTarget.cpp	(revision 768)
+++ OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/src/OgreRenderTarget.cpp	(revision 768)
@@ -0,0 +1,482 @@
+/*
+-----------------------------------------------------------------------------
+This source file is part of OGRE
+(Object-oriented Graphics Rendering Engine)
+For the latest info, see http://www.ogre3d.org/
+
+Copyright (c) 2000-2005 The OGRE Team
+Also see acknowledgements in Readme.html
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+#include "OgreStableHeaders.h"
+#include "OgreRenderTarget.h"
+#include "OgreStringConverter.h"
+
+#include "OgreViewport.h"
+#include "OgreException.h"
+#include "OgreLogManager.h"
+#include "OgreRenderTargetListener.h"
+#include "OgrePlatformManager.h"
+#include "OgreRoot.h"
+
+namespace Ogre {
+
+    RenderTarget::RenderTarget()
+		:mPriority(OGRE_DEFAULT_RT_GROUP),
+		mActive(true),
+		mAutoUpdate(true)
+		#ifdef GAMETOOLS_ILLUMINATION_MODULE 
+		, lastFrame(0)
+		#endif
+    {
+        mTimer = Root::getSingleton().getTimer();
+        resetStatistics();
+    }
+
+    RenderTarget::~RenderTarget()
+    {
+        // Delete viewports
+        for (ViewportList::iterator i = mViewportList.begin();
+            i != mViewportList.end(); ++i)
+        {
+            delete (*i).second;
+        }
+
+
+        // Write closing message
+		StringUtil::StrStreamType msg;
+		msg << "Render Target '" << mName << "' "
+			<< "Average FPS: " << mStats.avgFPS << " "
+			<< "Best FPS: " << mStats.bestFPS << " "
+			<< "Worst FPS: " << mStats.worstFPS; 
+        LogManager::getSingleton().logMessage(msg.str());
+
+    }
+
+    const String& RenderTarget::getName(void) const
+    {
+        return mName;
+    }
+
+
+    void RenderTarget::getMetrics(unsigned int& width, unsigned int& height, unsigned int& colourDepth)
+    {
+        width = mWidth;
+        height = mHeight;
+        colourDepth = mColourDepth;
+    }
+
+    unsigned int RenderTarget::getWidth(void) const
+    {
+        return mWidth;
+    }
+    unsigned int RenderTarget::getHeight(void) const
+    {
+        return mHeight;
+    }
+    unsigned int RenderTarget::getColourDepth(void) const
+    {
+        return mColourDepth;
+    }
+
+    void RenderTarget::update(void)
+    {
+
+        // notify listeners (pre)
+        firePreUpdate();
+
+        mStats.triangleCount = 0;
+        // Go through viewports in Z-order
+        // Tell each to refresh
+        ViewportList::iterator it = mViewportList.begin();
+        while (it != mViewportList.end())
+        {
+            fireViewportPreUpdate((*it).second);
+            (*it).second->update();
+            mStats.triangleCount += (*it).second->_getNumRenderedFaces();
+            fireViewportPostUpdate((*it).second);
+            ++it;
+        }
+
+        // notify listeners (post)
+        firePostUpdate();
+
+        // Update statistics (always on top)
+        updateStats();
+
+
+    }
+
+    Viewport* RenderTarget::addViewport(Camera* cam, int ZOrder, float left, float top ,
+        float width , float height)
+    {
+        // Check no existing viewport with this Z-order
+        ViewportList::iterator it = mViewportList.find(ZOrder);
+
+        if (it != mViewportList.end())
+        {
+			StringUtil::StrStreamType str;
+			str << "Can't create another viewport for "
+				<< mName << " with Z-Order " << ZOrder
+				<< " because a viewport exists with this Z-Order already.";
+            OGRE_EXCEPT(9999, str.str(), "RenderTarget::addViewport");
+        }
+        // Add viewport to list
+        // Order based on Z-Order
+        Viewport* vp = new Viewport(cam, this, left, top, width, height, ZOrder);
+
+        mViewportList.insert(ViewportList::value_type(ZOrder, vp));
+
+		fireViewportAdded(vp);
+
+        return vp;
+    }
+	//-----------------------------------------------------------------------
+    void RenderTarget::removeViewport(int ZOrder)
+    {
+        ViewportList::iterator it = mViewportList.find(ZOrder);
+
+        if (it != mViewportList.end())
+        {
+			fireViewportRemoved((*it).second);
+            delete (*it).second;
+            mViewportList.erase(ZOrder);
+        }
+    }
+
+    void RenderTarget::removeAllViewports(void)
+    {
+
+
+        for (ViewportList::iterator it = mViewportList.begin(); it != mViewportList.end(); ++it)
+        {
+            delete (*it).second;
+        }
+
+        mViewportList.clear();
+
+    }
+
+    void RenderTarget::getStatistics(float& lastFPS, float& avgFPS,
+        float& bestFPS, float& worstFPS) const
+    {
+
+        // Note - the will have been updated by the last render
+        lastFPS = mStats.lastFPS;
+        avgFPS = mStats.avgFPS;
+        bestFPS = mStats.bestFPS;
+        worstFPS = mStats.worstFPS;
+
+
+    }
+
+    const RenderTarget::FrameStats& RenderTarget::getStatistics(void) const
+    {
+        return mStats;
+    }
+
+    float RenderTarget::getLastFPS() const
+    {
+        return mStats.lastFPS;
+    }
+    float RenderTarget::getAverageFPS() const
+    {
+        return mStats.avgFPS;
+    }
+    float RenderTarget::getBestFPS() const
+    {
+        return mStats.bestFPS;
+    }
+    float RenderTarget::getWorstFPS() const
+    {
+        return mStats.worstFPS;
+    }
+
+    size_t RenderTarget::getTriangleCount(void) const
+    {
+        return mStats.triangleCount;
+    }
+
+    float RenderTarget::getBestFrameTime() const
+    {
+        return mStats.bestFrameTime;
+    }
+
+    float RenderTarget::getWorstFrameTime() const
+    {
+        return mStats.worstFrameTime;
+    }
+
+    void RenderTarget::resetStatistics(void)
+    {
+        mStats.avgFPS = 0.0;
+        mStats.bestFPS = 0.0;
+        mStats.lastFPS = 0.0;
+        mStats.worstFPS = 999.0;
+        mStats.triangleCount = 0;
+        mStats.bestFrameTime = 999999;
+        mStats.worstFrameTime = 0;
+
+        mLastTime = mTimer->getMilliseconds();
+        mLastSecond = mLastTime;
+        mFrameCount = 0;
+    }
+
+    void RenderTarget::updateStats(void)
+    {
+		#ifdef GAMETOOLS_ILLUMINATION_MODULE 
+		 lastFrame = Root::getSingleton().getCurrentFrameNumber();
+		#endif
+
+        ++mFrameCount;
+        unsigned long thisTime = mTimer->getMilliseconds();
+
+        // check frame time
+        unsigned long frameTime = thisTime - mLastTime ;
+        mLastTime = thisTime ;
+
+        mStats.bestFrameTime = std::min(mStats.bestFrameTime, frameTime);
+        mStats.worstFrameTime = std::max(mStats.worstFrameTime, frameTime);
+
+        // check if new second (update only once per second)
+        if (thisTime - mLastSecond > 1000) 
+        { 
+            // new second - not 100% precise
+            mStats.lastFPS = (float)mFrameCount / (float)(thisTime - mLastSecond) * 1000.0;
+
+            if (mStats.avgFPS == 0)
+                mStats.avgFPS = mStats.lastFPS;
+            else
+                mStats.avgFPS = (mStats.avgFPS + mStats.lastFPS) / 2; // not strictly correct, but good enough
+
+            mStats.bestFPS = std::max(mStats.bestFPS, mStats.lastFPS);
+            mStats.worstFPS = std::min(mStats.worstFPS, mStats.lastFPS);
+
+            mLastSecond = thisTime ;
+            mFrameCount  = 0;
+
+        }
+
+    }
+
+    void RenderTarget::getCustomAttribute(const String& name, void* pData)
+    {
+        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Attribute not found.", "RenderTarget::getCustomAttribute");
+    }
+    //-----------------------------------------------------------------------
+    void RenderTarget::setDebugText(const String& text)
+    {
+        mDebugText = text;
+    }
+    //-----------------------------------------------------------------------
+    const String & RenderTarget::getDebugText() const
+    { 
+        return mDebugText; 
+    }
+    //-----------------------------------------------------------------------
+    void RenderTarget::addListener(RenderTargetListener* listener)
+    {
+        mListeners.push_back(listener);
+    }
+    //-----------------------------------------------------------------------
+    void RenderTarget::removeListener(RenderTargetListener* listener)
+    {
+        RenderTargetListenerList::iterator i;
+        for (i = mListeners.begin(); i != mListeners.end(); ++i)
+        {
+            if (*i == listener)
+            {
+                mListeners.erase(i);
+                break;
+            }
+        }
+
+    }
+    //-----------------------------------------------------------------------
+    void RenderTarget::removeAllListeners(void)
+    {
+        mListeners.clear();
+    }
+    //-----------------------------------------------------------------------
+    void RenderTarget::firePreUpdate(void)
+    {
+        RenderTargetEvent evt;
+        evt.source = this;
+
+        RenderTargetListenerList::iterator i, iend;
+        i = mListeners.begin();
+        iend = mListeners.end();
+        for(; i != iend; ++i)
+        {
+            (*i)->preRenderTargetUpdate(evt);
+        }
+
+
+    }
+    //-----------------------------------------------------------------------
+    void RenderTarget::firePostUpdate(void)
+    {
+        RenderTargetEvent evt;
+        evt.source = this;
+
+        RenderTargetListenerList::iterator i, iend;
+        i = mListeners.begin();
+        iend = mListeners.end();
+        for(; i != iend; ++i)
+        {
+            (*i)->postRenderTargetUpdate(evt);
+        }
+    }
+    //-----------------------------------------------------------------------
+    unsigned short RenderTarget::getNumViewports(void) const
+    {
+        return (unsigned short)mViewportList.size();
+
+    }
+    //-----------------------------------------------------------------------
+    Viewport* RenderTarget::getViewport(unsigned short index)
+    {
+        assert (index < mViewportList.size() && "Index out of bounds");
+
+        ViewportList::iterator i = mViewportList.begin();
+        while (index--)
+            ++i;
+        return i->second;
+    }
+    //-----------------------------------------------------------------------
+    bool RenderTarget::isActive() const
+    {
+        return mActive;
+    }
+    //-----------------------------------------------------------------------
+    void RenderTarget::setActive( bool state )
+    {
+        mActive = state;
+    }
+    //-----------------------------------------------------------------------
+    void RenderTarget::fireViewportPreUpdate(Viewport* vp)
+    {
+        RenderTargetViewportEvent evt;
+        evt.source = vp;
+
+        RenderTargetListenerList::iterator i, iend;
+        i = mListeners.begin();
+        iend = mListeners.end();
+        for(; i != iend; ++i)
+        {
+            (*i)->preViewportUpdate(evt);
+        }
+    }
+    //-----------------------------------------------------------------------
+    void RenderTarget::fireViewportPostUpdate(Viewport* vp)
+    {
+        RenderTargetViewportEvent evt;
+        evt.source = vp;
+
+        RenderTargetListenerList::iterator i, iend;
+        i = mListeners.begin();
+        iend = mListeners.end();
+        for(; i != iend; ++i)
+        {
+            (*i)->postViewportUpdate(evt);
+        }
+    }
+	//-----------------------------------------------------------------------
+	void RenderTarget::fireViewportAdded(Viewport* vp)
+	{
+		RenderTargetViewportEvent evt;
+		evt.source = vp;
+
+		RenderTargetListenerList::iterator i, iend;
+		i = mListeners.begin();
+		iend = mListeners.end();
+		for(; i != iend; ++i)
+		{
+			(*i)->viewportAdded(evt);
+		}
+	}
+	//-----------------------------------------------------------------------
+	void RenderTarget::fireViewportRemoved(Viewport* vp)
+	{
+		RenderTargetViewportEvent evt;
+		evt.source = vp;
+
+		RenderTargetListenerList::iterator i, iend;
+		i = mListeners.begin();
+		iend = mListeners.end();
+		for(; i != iend; ++i)
+		{
+			(*i)->viewportRemoved(evt);
+		}
+	}
+    //-----------------------------------------------------------------------
+    String RenderTarget::writeContentsToTimestampedFile(const String& filenamePrefix, const String& filenameSuffix)
+    {
+        struct tm *pTime;
+        time_t ctTime; time(&ctTime);
+        pTime = localtime( &ctTime );
+        std::ostringstream oss;
+        oss	<< std::setw(2) << std::setfill('0') << (pTime->tm_mon + 1)
+            << std::setw(2) << std::setfill('0') << pTime->tm_mday
+            << std::setw(2) << std::setfill('0') << (pTime->tm_year + 1900)
+            << "_" << std::setw(2) << std::setfill('0') << pTime->tm_hour
+            << std::setw(2) << std::setfill('0') << pTime->tm_min
+            << std::setw(2) << std::setfill('0') << pTime->tm_sec
+            << std::setw(3) << std::setfill('0') << (mTimer->getMilliseconds() % 1000);
+        String filename = filenamePrefix + String(oss.str()) + filenameSuffix;
+        writeContentsToFile(filename);
+        return filename;
+
+    }
+    //-----------------------------------------------------------------------
+    void RenderTarget::_notifyCameraRemoved(const Camera* cam)
+    {
+        ViewportList::iterator i, iend;
+        iend = mViewportList.end();
+        for (i = mViewportList.begin(); i != iend; ++i)
+        {
+            Viewport* v = i->second;
+            if (v->getCamera() == cam)
+            {
+                // disable camera link
+                v->setCamera(0);
+            }
+        }
+    }
+    //-----------------------------------------------------------------------
+    void RenderTarget::setAutoUpdated(bool autoup)
+    {
+        mAutoUpdate = autoup;
+    }
+    //-----------------------------------------------------------------------
+    bool RenderTarget::isAutoUpdated(void) const
+    {
+        return mAutoUpdate;
+    }
+    //-----------------------------------------------------------------------
+    bool RenderTarget::isPrimary(void) const
+    {
+        // RenderWindow will override and return true for the primary window
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    RenderTarget::Impl *RenderTarget::_getImpl()
+    {
+        return 0;
+    }
+
+}        
Index: OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/src/OgreMaterialSerializer.cpp
===================================================================
--- OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/src/OgreMaterialSerializer.cpp	(revision 768)
+++ OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/src/OgreMaterialSerializer.cpp	(revision 768)
@@ -0,0 +1,4416 @@
+/*
+-----------------------------------------------------------------------------
+This source file is part of OGRE
+(Object-oriented Graphics Rendering Engine)
+For the latest info, see http://ogre.sourceforge.net/
+
+Copyright (c) 2000-2005 The OGRE Team
+Also see acknowledgements in Readme.html
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+#include "OgreStableHeaders.h"
+
+#include "OgreMaterialSerializer.h"
+#include "OgreStringConverter.h"
+#include "OgreLogManager.h"
+#include "OgreException.h"
+#include "OgreTechnique.h"
+#include "OgrePass.h"
+#include "OgreTextureUnitState.h"
+#include "OgreMaterialManager.h"
+#include "OgreGpuProgramManager.h"
+#include "OgreHighLevelGpuProgramManager.h"
+#include "OgreExternalTextureSourceManager.h"
+
+namespace Ogre 
+{
+
+    //-----------------------------------------------------------------------
+    // Internal parser methods
+    //-----------------------------------------------------------------------
+    void logParseError(const String& error, const MaterialScriptContext& context)
+    {
+        // log material name only if filename not specified
+        if (context.filename.empty() && !context.material.isNull())
+        {
+            LogManager::getSingleton().logMessage(
+                "Error in material " + context.material->getName() + 
+                " : " + error);
+        }
+        else
+        {
+            if (!context.material.isNull())
+            {
+                LogManager::getSingleton().logMessage(
+                    "Error in material " + context.material->getName() +
+                    " at line " + StringConverter::toString(context.lineNo) + 
+                    " of " + context.filename + ": " + error);
+            }
+            else
+            {
+                LogManager::getSingleton().logMessage(
+                    "Error at line " + StringConverter::toString(context.lineNo) + 
+                    " of " + context.filename + ": " + error);
+            }
+        }
+    }
+    //-----------------------------------------------------------------------
+    ColourValue _parseColourValue(StringVector& vecparams)
+    {
+        return ColourValue(
+            StringConverter::parseReal(vecparams[0]) ,
+            StringConverter::parseReal(vecparams[1]) ,
+            StringConverter::parseReal(vecparams[2]) ,
+            (vecparams.size()==4) ? StringConverter::parseReal(vecparams[3]) : 1.0f ) ;
+    }
+    //-----------------------------------------------------------------------
+    FilterOptions convertFiltering(const String& s)
+    {
+        if (s == "none")
+        {
+            return FO_NONE;
+        }
+        else if (s == "point")
+        {
+            return FO_POINT;
+        }
+        else if (s == "linear")
+        {
+            return FO_LINEAR;
+        }
+        else if (s == "anisotropic")
+        {
+            return FO_ANISOTROPIC;
+        }
+
+        return FO_POINT;
+    }
+    //-----------------------------------------------------------------------
+    bool parseAmbient(String& params, MaterialScriptContext& context)
+    {
+        StringVector vecparams = StringUtil::split(params, " \t");
+        // Must be 1, 3 or 4 parameters 
+        if (vecparams.size() == 1) {
+            if(vecparams[0] == "vertexcolour") {
+               context.pass->setVertexColourTracking(context.pass->getVertexColourTracking() | TVC_AMBIENT);
+            } else {
+                logParseError(
+                    "Bad ambient attribute, single parameter flag must be 'vertexcolour'", 
+                    context);
+            }
+        } 
+        else if (vecparams.size() == 3 || vecparams.size() == 4)
+        {
+            context.pass->setAmbient( _parseColourValue(vecparams) );
+            context.pass->setVertexColourTracking(context.pass->getVertexColourTracking() & ~TVC_AMBIENT);
+        }
+        else 
+        {
+            logParseError(
+                "Bad ambient attribute, wrong number of parameters (expected 1, 3 or 4)", 
+                context);
+        }
+        return false;
+    }
+   //-----------------------------------------------------------------------
+    bool parseDiffuse(String& params, MaterialScriptContext& context)
+    {
+        StringVector vecparams = StringUtil::split(params, " \t");
+        // Must be 1, 3 or 4 parameters 
+        if (vecparams.size() == 1) {
+            if(vecparams[0] == "vertexcolour") {
+               context.pass->setVertexColourTracking(context.pass->getVertexColourTracking() | TVC_DIFFUSE);
+            } else {
+                logParseError(
+                    "Bad diffuse attribute, single parameter flag must be 'vertexcolour'", 
+                    context);
+            }
+        }
+        else if (vecparams.size() == 3 || vecparams.size() == 4)
+        {
+            context.pass->setDiffuse( _parseColourValue(vecparams) );
+            context.pass->setVertexColourTracking(context.pass->getVertexColourTracking() & ~TVC_DIFFUSE);
+        }
+        else
+        {
+            logParseError(
+                "Bad diffuse attribute, wrong number of parameters (expected 1, 3 or 4)", 
+                context);
+        }        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseSpecular(String& params, MaterialScriptContext& context)
+    {
+        StringVector vecparams = StringUtil::split(params, " \t");
+        // Must be 2, 4 or 5 parameters 
+        if(vecparams.size() == 2) 
+        {   
+            if(vecparams[0] == "vertexcolour") {
+                context.pass->setVertexColourTracking(context.pass->getVertexColourTracking() | TVC_SPECULAR);
+                context.pass->setShininess(StringConverter::parseReal(vecparams[1]) );
+            }
+            else
+            {
+                logParseError(
+                    "Bad specular attribute, double parameter statement must be 'vertexcolour <shininess>'", 
+                    context);
+            }
+        } 
+        else if(vecparams.size() == 4 || vecparams.size() == 5) 
+        {
+            context.pass->setSpecular(
+                StringConverter::parseReal(vecparams[0]), 
+                StringConverter::parseReal(vecparams[1]), 
+                StringConverter::parseReal(vecparams[2]), 
+                vecparams.size() == 5? 
+                    StringConverter::parseReal(vecparams[3]) : 1.0f);
+            context.pass->setVertexColourTracking(context.pass->getVertexColourTracking() & ~TVC_SPECULAR);
+            context.pass->setShininess(
+                StringConverter::parseReal(vecparams[vecparams.size() - 1]) );
+        }
+        else 
+        {
+            logParseError(
+                "Bad specular attribute, wrong number of parameters (expected 2, 4 or 5)",
+                context);
+        }
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseEmissive(String& params, MaterialScriptContext& context)
+    {
+        StringVector vecparams = StringUtil::split(params, " \t");
+        // Must be 1, 3 or 4 parameters 
+        if (vecparams.size() == 1) {
+            if(vecparams[0] == "vertexcolour") {
+               context.pass->setVertexColourTracking(context.pass->getVertexColourTracking() | TVC_EMISSIVE);
+            } else {
+                logParseError(
+                    "Bad emissive attribute, single parameter flag must be 'vertexcolour'", 
+                    context);
+            }
+        }
+        else if (vecparams.size() == 3 || vecparams.size() == 4)
+        {
+            context.pass->setSelfIllumination( _parseColourValue(vecparams) );
+            context.pass->setVertexColourTracking(context.pass->getVertexColourTracking() & ~TVC_EMISSIVE);
+        }
+        else
+        {
+            logParseError(
+                "Bad emissive attribute, wrong number of parameters (expected 1, 3 or 4)", 
+                context);
+        }
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    SceneBlendFactor convertBlendFactor(const String& param)
+    {
+        if (param == "one")
+            return SBF_ONE;
+        else if (param == "zero")
+            return SBF_ZERO;
+        else if (param == "dest_colour")
+            return SBF_DEST_COLOUR;
+        else if (param == "src_colour")
+            return SBF_SOURCE_COLOUR;
+        else if (param == "one_minus_dest_colour")
+            return SBF_ONE_MINUS_DEST_COLOUR;
+        else if (param == "one_minus_src_colour")
+            return SBF_ONE_MINUS_SOURCE_COLOUR;
+        else if (param == "dest_alpha")
+            return SBF_DEST_ALPHA;
+        else if (param == "src_alpha")
+            return SBF_SOURCE_ALPHA;
+        else if (param == "one_minus_dest_alpha")
+            return SBF_ONE_MINUS_DEST_ALPHA;
+        else if (param == "one_minus_src_alpha")
+            return SBF_ONE_MINUS_SOURCE_ALPHA;
+        else
+        {
+            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid blend factor.", "convertBlendFactor");
+        }
+
+
+    }
+    //-----------------------------------------------------------------------
+    bool parseSceneBlend(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        StringVector vecparams = StringUtil::split(params, " \t");
+        // Should be 1 or 2 params 
+        if (vecparams.size() == 1)
+        {
+            //simple
+            SceneBlendType stype;
+            if (vecparams[0] == "add")
+                stype = SBT_ADD;
+            else if (vecparams[0] == "modulate")
+                stype = SBT_MODULATE;
+			else if (vecparams[0] == "colour_blend")
+				stype = SBT_TRANSPARENT_COLOUR;
+            else if (vecparams[0] == "alpha_blend")
+                stype = SBT_TRANSPARENT_ALPHA;
+            else
+            {
+                logParseError(
+                    "Bad scene_blend attribute, unrecognised parameter '" + vecparams[0] + "'",
+                    context);
+                return false;
+            }
+            context.pass->setSceneBlending(stype);
+
+        }
+        else if (vecparams.size() == 2)
+        {
+            //src/dest
+            SceneBlendFactor src, dest;
+
+            try {
+                src = convertBlendFactor(vecparams[0]);
+                dest = convertBlendFactor(vecparams[1]);
+                context.pass->setSceneBlending(src,dest);
+            }
+            catch (Exception& e)
+            {
+                logParseError("Bad scene_blend attribute, " + e.getFullDescription(), context);
+            }
+
+        }
+        else
+        {
+            logParseError(
+                "Bad scene_blend attribute, wrong number of parameters (expected 1 or 2)", 
+                context);
+        }
+
+        return false;
+
+    }
+    //-----------------------------------------------------------------------
+    CompareFunction convertCompareFunction(const String& param)
+    {
+        if (param == "always_fail")
+            return CMPF_ALWAYS_FAIL;
+        else if (param == "always_pass")
+            return CMPF_ALWAYS_PASS;
+        else if (param == "less")
+            return CMPF_LESS;
+        else if (param == "less_equal")
+            return CMPF_LESS_EQUAL;
+        else if (param == "equal")
+            return CMPF_EQUAL;
+        else if (param == "not_equal")
+            return CMPF_NOT_EQUAL;
+        else if (param == "greater_equal")
+            return CMPF_GREATER_EQUAL;
+        else if (param == "greater")
+            return CMPF_GREATER;
+        else
+            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid compare function", "convertCompareFunction");
+
+    }
+    //-----------------------------------------------------------------------
+    bool parseDepthCheck(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        if (params == "on")
+            context.pass->setDepthCheckEnabled(true);
+        else if (params == "off")
+            context.pass->setDepthCheckEnabled(false);
+        else
+            logParseError(
+            "Bad depth_check attribute, valid parameters are 'on' or 'off'.", 
+            context);
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseDepthWrite(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        if (params == "on")
+            context.pass->setDepthWriteEnabled(true);
+        else if (params == "off")
+            context.pass->setDepthWriteEnabled(false);
+        else
+            logParseError(
+                "Bad depth_write attribute, valid parameters are 'on' or 'off'.", 
+                context);
+        return false;
+    }
+
+    //-----------------------------------------------------------------------
+    bool parseDepthFunc(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        try {
+            CompareFunction func = convertCompareFunction(params);
+            context.pass->setDepthFunction(func);
+        }
+        catch (...)
+        {
+            logParseError("Bad depth_func attribute, invalid function parameter.", context);
+        }
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseColourWrite(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        if (params == "on")
+            context.pass->setColourWriteEnabled(true);
+        else if (params == "off")
+            context.pass->setColourWriteEnabled(false);
+        else
+            logParseError(
+                "Bad colour_write attribute, valid parameters are 'on' or 'off'.", 
+                context);
+        return false;
+    }
+
+    //-----------------------------------------------------------------------
+    bool parseCullHardware(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        if (params=="none")
+            context.pass->setCullingMode(CULL_NONE);
+        else if (params=="anticlockwise")
+            context.pass->setCullingMode(CULL_ANTICLOCKWISE);
+        else if (params=="clockwise")
+            context.pass->setCullingMode(CULL_CLOCKWISE);
+        else
+            logParseError(
+                "Bad cull_hardware attribute, valid parameters are "
+                "'none', 'clockwise' or 'anticlockwise'.", context);
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseCullSoftware(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        if (params=="none")
+            context.pass->setManualCullingMode(MANUAL_CULL_NONE);
+        else if (params=="back")
+            context.pass->setManualCullingMode(MANUAL_CULL_BACK);
+        else if (params=="front")
+            context.pass->setManualCullingMode(MANUAL_CULL_FRONT);
+        else
+            logParseError(
+                "Bad cull_software attribute, valid parameters are 'none', "
+                "'front' or 'back'.", context);
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseLighting(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        if (params=="on")
+            context.pass->setLightingEnabled(true);
+        else if (params=="off")
+            context.pass->setLightingEnabled(false);
+        else
+            logParseError(
+                "Bad lighting attribute, valid parameters are 'on' or 'off'.", context);
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseMaxLights(String& params, MaterialScriptContext& context)
+    {
+		context.pass->setMaxSimultaneousLights(StringConverter::parseInt(params));
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    void parseIterationLightTypes(String& params, MaterialScriptContext& context)
+    {
+        // Parse light type
+        if (params == "directional")
+        {
+            context.pass->setIteratePerLight(true, true, Light::LT_DIRECTIONAL);
+        }
+        else if (params == "point")
+        {
+            context.pass->setIteratePerLight(true, true, Light::LT_POINT);
+        }
+        else if (params == "spot")
+        {
+            context.pass->setIteratePerLight(true, true, Light::LT_SPOTLIGHT);
+        }
+        else
+        {
+            logParseError("Bad iteration attribute, valid values for light type parameter "
+                "are 'point' or 'directional' or 'spot'.", context);
+        }
+
+    }
+    //-----------------------------------------------------------------------
+    bool parseIteration(String& params, MaterialScriptContext& context)
+    {
+        // we could have more than one parameter
+        /** combinations could be:
+            iteration once
+            iteration once_per_light [light type]
+            iteration <number>
+            iteration <number> [per_light] [light type]
+        */
+        StringUtil::toLowerCase(params);
+        StringVector vecparams = StringUtil::split(params, " \t");
+        if (vecparams.size() < 1 || vecparams.size() > 3)
+        {
+            logParseError("Bad iteration attribute, expected 1 to 3 parameters.", context);
+            return false;
+        }
+
+        if (vecparams[0]=="once")
+            context.pass->setIteratePerLight(false);
+        else if (vecparams[0]=="once_per_light")
+        {
+            if (vecparams.size() == 2)
+            {
+                parseIterationLightTypes(vecparams[1], context);
+            }
+            else 
+            {
+                context.pass->setIteratePerLight(true, false);
+            }
+
+        }
+        else // could be using form: <number> [per_light] [light type]
+        {
+            int passIterationCount = StringConverter::parseInt(vecparams[0]);
+            if (passIterationCount > 0)
+            {
+                context.pass->setPassIterationCount(passIterationCount);
+                if (vecparams.size() > 1)
+                {
+                    if (vecparams[1] == "per_light")
+                    {
+                        if (vecparams.size() == 3)
+                        {
+                            parseIterationLightTypes(vecparams[2], context);
+                        }
+                        else 
+                        {
+                            context.pass->setIteratePerLight(true, false);
+                        }
+                    }
+                    else
+                        logParseError(
+                            "Bad iteration attribute, valid parameters are <number> [per_light] [light type].", context);
+                }
+            }
+            else
+                logParseError(
+                    "Bad iteration attribute, valid parameters are 'once' or 'once_per_light' or <number> [per_light] [light type].", context);
+        }
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parsePointSize(String& params, MaterialScriptContext& context)
+    {
+        context.pass->setPointSize(StringConverter::parseReal(params));
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parsePointSprites(String& params, MaterialScriptContext& context)
+    {
+        if (params=="on")
+	        context.pass->setPointSpritesEnabled(true);
+		else if (params=="off")
+	        context.pass->setPointSpritesEnabled(false);
+		else
+            logParseError(
+                "Bad point_sprites attribute, valid parameters are 'on' or 'off'.", context);
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+	bool parsePointAttenuation(String& params, MaterialScriptContext& context)
+	{
+        StringVector vecparams = StringUtil::split(params, " \t");
+        if (vecparams.size() != 1 && vecparams.size() != 4)
+		{
+			logParseError("Bad point_size_attenuation attribute, 1 or 4 parameters expected", context);
+			return false;
+		}
+		if (vecparams[0] == "off")
+		{
+			context.pass->setPointAttenuation(false);
+		}
+		else if (vecparams[0] == "on")
+		{
+			if (vecparams.size() == 4)
+			{
+				context.pass->setPointAttenuation(true, 
+					StringConverter::parseReal(vecparams[1]), 
+					StringConverter::parseReal(vecparams[2]),
+					StringConverter::parseReal(vecparams[3]));
+			}
+			else
+			{
+				context.pass->setPointAttenuation(true);
+			}
+		}
+		
+		return false;
+	}
+    //-----------------------------------------------------------------------
+	bool parsePointSizeMin(String& params, MaterialScriptContext& context)
+	{
+		context.pass->setPointMinSize(
+			StringConverter::parseReal(params));
+		return false;
+	}
+    //-----------------------------------------------------------------------
+	bool parsePointSizeMax(String& params, MaterialScriptContext& context)
+	{
+		context.pass->setPointMaxSize(
+			StringConverter::parseReal(params));
+		return false;
+	}
+    //-----------------------------------------------------------------------
+    bool parseFogging(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        StringVector vecparams = StringUtil::split(params, " \t");
+        if (vecparams[0]=="true")
+        {
+            // if true, we need to see if they supplied all arguments, or just the 1... if just the one,
+            // Assume they want to disable the default fog from effecting this material.
+            if( vecparams.size() == 8 )
+            {
+                FogMode mFogtype;
+                if( vecparams[1] == "none" )
+                    mFogtype = FOG_NONE;
+                else if( vecparams[1] == "linear" )
+                    mFogtype = FOG_LINEAR;
+                else if( vecparams[1] == "exp" )
+                    mFogtype = FOG_EXP;
+                else if( vecparams[1] == "exp2" )
+                    mFogtype = FOG_EXP2;
+                else
+                {
+                    logParseError(
+                        "Bad fogging attribute, valid parameters are "
+                        "'none', 'linear', 'exp', or 'exp2'.", context);
+                    return false;
+                }
+
+                context.pass->setFog(
+                    true,
+                    mFogtype,
+                    ColourValue(
+                    StringConverter::parseReal(vecparams[2]),
+                    StringConverter::parseReal(vecparams[3]),
+                    StringConverter::parseReal(vecparams[4])),
+                    StringConverter::parseReal(vecparams[5]),
+                    StringConverter::parseReal(vecparams[6]),
+                    StringConverter::parseReal(vecparams[7])
+                    );
+            }
+            else
+            {
+                context.pass->setFog(true);
+            }
+        }
+        else if (vecparams[0]=="false")
+            context.pass->setFog(false);
+        else
+            logParseError(
+                "Bad fog_override attribute, valid parameters are 'true' or 'false'.", 
+                context);
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseShading(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        if (params=="flat")
+            context.pass->setShadingMode(SO_FLAT);
+        else if (params=="gouraud")
+            context.pass->setShadingMode(SO_GOURAUD);
+        else if (params=="phong")
+            context.pass->setShadingMode(SO_PHONG);
+        else
+            logParseError("Bad shading attribute, valid parameters are 'flat', "
+                "'gouraud' or 'phong'.", context);
+
+        return false;
+    }
+	//-----------------------------------------------------------------------
+	bool parsePolygonMode(String& params, MaterialScriptContext& context)
+	{
+		StringUtil::toLowerCase(params);
+		if (params=="solid")
+			context.pass->setPolygonMode(PM_SOLID);
+		else if (params=="wireframe")
+			context.pass->setPolygonMode(PM_WIREFRAME);
+		else if (params=="points")
+			context.pass->setPolygonMode(PM_POINTS);
+		else
+			logParseError("Bad polygon_mode attribute, valid parameters are 'solid', "
+			"'wireframe' or 'points'.", context);
+
+		return false;
+	}
+    //-----------------------------------------------------------------------
+    bool parseFiltering(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        StringVector vecparams = StringUtil::split(params, " \t");
+        // Must be 1 or 3 parameters 
+        if (vecparams.size() == 1)
+        {
+            // Simple format
+            if (vecparams[0]=="none")
+                context.textureUnit->setTextureFiltering(TFO_NONE);
+            else if (vecparams[0]=="bilinear")
+                context.textureUnit->setTextureFiltering(TFO_BILINEAR);
+            else if (vecparams[0]=="trilinear")
+                context.textureUnit->setTextureFiltering(TFO_TRILINEAR);
+            else if (vecparams[0]=="anisotropic")
+                context.textureUnit->setTextureFiltering(TFO_ANISOTROPIC);
+            else
+            {
+                logParseError("Bad filtering attribute, valid parameters for simple format are "
+                    "'none', 'bilinear', 'trilinear' or 'anisotropic'.", context);
+                return false;
+            }
+        }
+        else if (vecparams.size() == 3)
+        {
+            // Complex format
+            context.textureUnit->setTextureFiltering(
+                convertFiltering(vecparams[0]), 
+                convertFiltering(vecparams[1]), 
+                convertFiltering(vecparams[2]));
+
+
+        }
+        else
+        {
+            logParseError(
+                "Bad filtering attribute, wrong number of parameters (expected 1 or 3)", 
+                context);
+        }
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    // Texture layer attributes
+    bool parseTexture(String& params, MaterialScriptContext& context)
+    {
+        StringVector vecparams = StringUtil::split(params, " \t");
+        const size_t numParams = vecparams.size();
+        if (numParams > 4)
+        {
+            logParseError("Invalid texture attribute - expected only 1, 2, 3 or 4 parameters.", 
+                context);
+        }
+        TextureType tt = TEX_TYPE_2D;
+		int mips = MIP_UNLIMITED; // When passed to TextureManager::load, this means default to default number of mipmaps
+        bool isAlpha = false;
+        if (numParams >= 2)
+        {
+            StringUtil::toLowerCase(vecparams[1]);
+            if (vecparams[1] == "1d")
+            {
+                tt = TEX_TYPE_1D;
+            }
+            else if (vecparams[1] == "2d")
+            {
+                tt = TEX_TYPE_2D;
+            }
+            else if (vecparams[1] == "3d")
+            {
+                tt = TEX_TYPE_3D;
+            }
+            else if (vecparams[1] == "cubic")
+            {
+                tt = TEX_TYPE_CUBE_MAP;
+            }  
+			else
+			{
+				logParseError("Invalid texture type - "+vecparams[1]+".", 
+                context);
+			}
+        }
+		if (numParams >= 3)
+		{
+			StringUtil::toLowerCase(vecparams[2]);
+			if (vecparams[2] == "unlimited")
+            {
+				mips = MIP_UNLIMITED;
+            }
+			else
+			{
+				mips = StringConverter::parseInt(vecparams[2]);
+			}
+        }
+        if (numParams >= 4)
+        {
+            StringUtil::toLowerCase(vecparams[3]);
+            if (vecparams[3] == "alpha")
+            {
+                isAlpha = true;
+            }
+        }
+        context.textureUnit->setTextureName(vecparams[0], tt, mips, isAlpha);
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseAnimTexture(String& params, MaterialScriptContext& context)
+    {
+        StringVector vecparams = StringUtil::split(params, " \t");
+        size_t numParams = vecparams.size();
+        // Determine which form it is
+        // Must have at least 3 params though
+        if (numParams < 3)
+        {
+            logParseError("Bad anim_texture attribute, wrong number of parameters "
+                "(expected at least 3)", context);
+            return false;
+        }
+        if (numParams == 3 && StringConverter::parseInt(vecparams[1]) != 0 )
+        {
+            // First form using base name & number of frames
+            context.textureUnit->setAnimatedTextureName(
+                vecparams[0], 
+                StringConverter::parseInt(vecparams[1]), 
+                StringConverter::parseReal(vecparams[2]));
+        }
+        else
+        {
+            // Second form using individual names
+            context.textureUnit->setAnimatedTextureName(
+                (String*)&vecparams[0], 
+                numParams-1, 
+                StringConverter::parseReal(vecparams[numParams-1]));
+        }
+        return false;
+
+    }
+    //-----------------------------------------------------------------------
+    bool parseCubicTexture(String& params, MaterialScriptContext& context)
+    {
+
+        StringVector vecparams = StringUtil::split(params, " \t");
+        size_t numParams = vecparams.size();
+
+        // Get final param
+        bool useUVW;
+        String& uvOpt = vecparams[numParams-1];
+		StringUtil::toLowerCase(uvOpt);
+        if (uvOpt == "combineduvw")
+            useUVW = true;
+        else if (uvOpt == "separateuv")
+            useUVW = false;
+        else
+        {
+            logParseError("Bad cubic_texture attribute, final parameter must be "
+                "'combinedUVW' or 'separateUV'.", context);
+            return false;
+        }
+        // Determine which form it is
+        if (numParams == 2)
+        {
+            // First form using base name
+            context.textureUnit->setCubicTextureName(vecparams[0], useUVW);
+        }
+        else if (numParams == 7)
+        {
+            // Second form using individual names
+            // Can use vecparams[0] as array start point
+            context.textureUnit->setCubicTextureName((String*)&vecparams[0], useUVW);
+        }
+        else
+        {
+            logParseError(
+                "Bad cubic_texture attribute, wrong number of parameters (expected 2 or 7)", 
+                context);
+            return false;
+        }
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseTexCoord(String& params, MaterialScriptContext& context)
+    {
+        context.textureUnit->setTextureCoordSet(
+            StringConverter::parseInt(params));
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+	TextureUnitState::TextureAddressingMode convTexAddressMode(const String& params, MaterialScriptContext& context)
+	{
+		if (params=="wrap")
+			return TextureUnitState::TAM_WRAP;
+		else if (params=="mirror")
+			return TextureUnitState::TAM_MIRROR;
+		else if (params=="clamp")
+			return TextureUnitState::TAM_CLAMP;
+		else if (params=="border")
+			return TextureUnitState::TAM_BORDER;
+		else
+			logParseError("Bad tex_address_mode attribute, valid parameters are "
+				"'wrap', 'mirror', 'clamp' or 'border'.", context);
+		// default
+		return TextureUnitState::TAM_WRAP;
+	}
+    //-----------------------------------------------------------------------
+    bool parseTexAddressMode(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+
+        StringVector vecparams = StringUtil::split(params, " \t");
+        size_t numParams = vecparams.size();
+		
+		if (numParams > 3 || numParams < 1)
+		{
+			logParseError("Invalid number of parameters to tex_address_mode"
+					" - must be between 1 and 3", context);
+		}
+		if (numParams == 1)
+		{
+			// Single-parameter option
+			context.textureUnit->setTextureAddressingMode(
+				convTexAddressMode(vecparams[0], context));
+		}
+		else 
+		{
+			// 2-3 parameter option
+			TextureUnitState::UVWAddressingMode uvw;
+			uvw.u = convTexAddressMode(vecparams[0], context);
+			uvw.v = convTexAddressMode(vecparams[1], context);
+			if (numParams == 3)
+			{
+				// w
+				uvw.w = convTexAddressMode(vecparams[2], context);
+			}
+			else
+			{
+				uvw.w = TextureUnitState::TAM_WRAP;
+			}
+			context.textureUnit->setTextureAddressingMode(uvw);
+		}
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseTexBorderColour(String& params, MaterialScriptContext& context)
+    {
+        StringVector vecparams = StringUtil::split(params, " \t");
+        // Must be 3 or 4 parameters 
+        if (vecparams.size() == 3 || vecparams.size() == 4)
+        {
+            context.textureUnit->setTextureBorderColour( _parseColourValue(vecparams) );
+        }
+        else 
+        {
+            logParseError(
+                "Bad tex_border_colour attribute, wrong number of parameters (expected 3 or 4)", 
+                context);
+        }
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseColourOp(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        if (params=="replace")
+            context.textureUnit->setColourOperation(LBO_REPLACE);
+        else if (params=="add")
+            context.textureUnit->setColourOperation(LBO_ADD);
+        else if (params=="modulate")
+            context.textureUnit->setColourOperation(LBO_MODULATE);
+        else if (params=="alpha_blend")
+            context.textureUnit->setColourOperation(LBO_ALPHA_BLEND);
+        else
+            logParseError("Bad colour_op attribute, valid parameters are "
+                "'replace', 'add', 'modulate' or 'alpha_blend'.", context);
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseAlphaRejection(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        StringVector vecparams = StringUtil::split(params, " \t");
+        if (vecparams.size() != 2)
+        {
+            logParseError(
+                "Bad alpha_rejection attribute, wrong number of parameters (expected 2)", 
+                context);
+            return false;
+        }
+
+        CompareFunction cmp;
+        try {
+            cmp = convertCompareFunction(vecparams[0]);
+        }
+        catch (...)
+        {
+            logParseError("Bad alpha_rejection attribute, invalid compare function.", context);
+            return false;
+        }
+
+        context.pass->setAlphaRejectSettings(cmp, StringConverter::parseInt(vecparams[1]));
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    LayerBlendOperationEx convertBlendOpEx(const String& param)
+    {
+        if (param == "source1")
+            return LBX_SOURCE1;
+        else if (param == "source2")
+            return LBX_SOURCE2;
+        else if (param == "modulate")
+            return LBX_MODULATE;
+        else if (param == "modulate_x2")
+            return LBX_MODULATE_X2;
+        else if (param == "modulate_x4")
+            return LBX_MODULATE_X4;
+        else if (param == "add")
+            return LBX_ADD;
+        else if (param == "add_signed")
+            return LBX_ADD_SIGNED;
+        else if (param == "add_smooth")
+            return LBX_ADD_SMOOTH;
+        else if (param == "subtract")
+            return LBX_SUBTRACT;
+        else if (param == "blend_diffuse_colour")
+            return LBX_BLEND_DIFFUSE_COLOUR;
+        else if (param == "blend_diffuse_alpha")
+            return LBX_BLEND_DIFFUSE_ALPHA;
+        else if (param == "blend_texture_alpha")
+            return LBX_BLEND_TEXTURE_ALPHA;
+        else if (param == "blend_current_alpha")
+            return LBX_BLEND_CURRENT_ALPHA;
+        else if (param == "blend_manual")
+            return LBX_BLEND_MANUAL;
+        else if (param == "dotproduct")
+            return LBX_DOTPRODUCT;
+        else
+            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid blend function", "convertBlendOpEx");
+    }
+    //-----------------------------------------------------------------------
+    LayerBlendSource convertBlendSource(const String& param)
+    {
+        if (param == "src_current")
+            return LBS_CURRENT;
+        else if (param == "src_texture")
+            return LBS_TEXTURE;
+        else if (param == "src_diffuse")
+            return LBS_DIFFUSE;
+        else if (param == "src_specular")
+            return LBS_SPECULAR;
+        else if (param == "src_manual")
+            return LBS_MANUAL;
+        else
+            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid blend source", "convertBlendSource");
+    }
+    //-----------------------------------------------------------------------
+    bool parseColourOpEx(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        StringVector vecparams = StringUtil::split(params, " \t");
+        size_t numParams = vecparams.size();
+
+        if (numParams < 3 || numParams > 10)
+        {
+            logParseError(
+                "Bad colour_op_ex attribute, wrong number of parameters (expected 3 to 10)", 
+                context);
+            return false;
+        }
+        LayerBlendOperationEx op;
+        LayerBlendSource src1, src2;
+        Real manual = 0.0;
+        ColourValue colSrc1 = ColourValue::White;
+        ColourValue colSrc2 = ColourValue::White;
+
+        try {
+            op = convertBlendOpEx(vecparams[0]);
+            src1 = convertBlendSource(vecparams[1]);
+            src2 = convertBlendSource(vecparams[2]);
+
+            if (op == LBX_BLEND_MANUAL)
+            {
+                if (numParams < 4)
+                {
+                    logParseError("Bad colour_op_ex attribute, wrong number of parameters "
+                        "(expected 4 for manual blend)", context);
+                    return false;
+                }
+                manual = StringConverter::parseReal(vecparams[3]);
+            }
+
+            if (src1 == LBS_MANUAL)
+            {
+                unsigned int parIndex = 3;
+                if (op == LBX_BLEND_MANUAL)
+                    parIndex++;
+
+                if (numParams < parIndex + 3)
+                {
+                    logParseError("Bad colour_op_ex attribute, wrong number of parameters "
+                        "(expected " + StringConverter::toString(parIndex + 3) + ")", context);
+                    return false;
+                }
+
+                colSrc1.r = StringConverter::parseReal(vecparams[parIndex++]);
+                colSrc1.g = StringConverter::parseReal(vecparams[parIndex++]);
+                colSrc1.b = StringConverter::parseReal(vecparams[parIndex++]);
+                if (numParams > parIndex)
+                {
+                    colSrc1.a = StringConverter::parseReal(vecparams[parIndex]);
+                }
+                else
+                {
+                    colSrc1.a = 1.0f;
+                }
+            }
+
+            if (src2 == LBS_MANUAL)
+            {
+                unsigned int parIndex = 3;
+                if (op == LBX_BLEND_MANUAL)
+                    parIndex++;
+                if (src1 == LBS_MANUAL)
+                    parIndex += 3;
+
+                if (numParams < parIndex + 3)
+                {
+                    logParseError("Bad colour_op_ex attribute, wrong number of parameters "
+                        "(expected " + StringConverter::toString(parIndex + 3) + ")", context);
+                    return false;
+                }
+
+                colSrc2.r = StringConverter::parseReal(vecparams[parIndex++]);
+                colSrc2.g = StringConverter::parseReal(vecparams[parIndex++]);
+                colSrc2.b = StringConverter::parseReal(vecparams[parIndex++]);
+                if (numParams > parIndex)
+                {
+                    colSrc2.a = StringConverter::parseReal(vecparams[parIndex]);
+                }
+                else
+                {
+                    colSrc2.a = 1.0f;
+                }
+            }
+        }
+        catch (Exception& e)
+        {
+            logParseError("Bad colour_op_ex attribute, " + e.getFullDescription(), context);
+            return false;
+        }
+
+        context.textureUnit->setColourOperationEx(op, src1, src2, colSrc1, colSrc2, manual);
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseColourOpFallback(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        StringVector vecparams = StringUtil::split(params, " \t");
+        if (vecparams.size() != 2)
+        {
+            logParseError("Bad colour_op_multipass_fallback attribute, wrong number "
+                "of parameters (expected 2)", context);
+            return false;
+        }
+
+        //src/dest
+        SceneBlendFactor src, dest;
+
+        try {
+            src = convertBlendFactor(vecparams[0]);
+            dest = convertBlendFactor(vecparams[1]);
+            context.textureUnit->setColourOpMultipassFallback(src,dest);
+        }
+        catch (Exception& e)
+        {
+            logParseError("Bad colour_op_multipass_fallback attribute, " 
+                + e.getFullDescription(), context);
+        }
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseAlphaOpEx(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        StringVector vecparams = StringUtil::split(params, " \t");
+        size_t numParams = vecparams.size();
+        if (numParams < 3 || numParams > 6)
+        {
+            logParseError("Bad alpha_op_ex attribute, wrong number of parameters "
+                "(expected 3 to 6)", context);
+            return false;
+        }
+        LayerBlendOperationEx op;
+        LayerBlendSource src1, src2;
+        Real manual = 0.0;
+        Real arg1 = 1.0, arg2 = 1.0;
+
+        try {
+            op = convertBlendOpEx(vecparams[0]);
+            src1 = convertBlendSource(vecparams[1]);
+            src2 = convertBlendSource(vecparams[2]);
+            if (op == LBX_BLEND_MANUAL)
+            {
+                if (numParams != 4)
+                {
+                    logParseError("Bad alpha_op_ex attribute, wrong number of parameters "
+                        "(expected 4 for manual blend)", context);
+                    return false;
+                }
+                manual = StringConverter::parseReal(vecparams[3]);
+            }
+            if (src1 == LBS_MANUAL)
+            {
+                unsigned int parIndex = 3;
+                if (op == LBX_BLEND_MANUAL)
+                    parIndex++;
+
+                if (numParams < parIndex)
+                {
+                    logParseError(
+                        "Bad alpha_op_ex attribute, wrong number of parameters (expected " + 
+                        StringConverter::toString(parIndex - 1) + ")", context);
+                    return false;
+                }
+
+                arg1 = StringConverter::parseReal(vecparams[parIndex]);
+            }
+
+            if (src2 == LBS_MANUAL)
+            {
+                unsigned int parIndex = 3;
+                if (op == LBX_BLEND_MANUAL)
+                    parIndex++;
+                if (src1 == LBS_MANUAL)
+                    parIndex++;
+
+                if (numParams < parIndex)
+                {
+                    logParseError(
+                        "Bad alpha_op_ex attribute, wrong number of parameters "
+                        "(expected " + StringConverter::toString(parIndex - 1) + ")", context);
+                    return false;
+                }
+
+                arg2 = StringConverter::parseReal(vecparams[parIndex]);
+            }
+        }
+        catch (Exception& e)
+        {
+            logParseError("Bad alpha_op_ex attribute, " + e.getFullDescription(), context);
+            return false;
+        }
+
+        context.textureUnit->setAlphaOperation(op, src1, src2, arg1, arg2, manual);
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseEnvMap(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        if (params=="off")
+            context.textureUnit->setEnvironmentMap(false);
+        else if (params=="spherical")
+            context.textureUnit->setEnvironmentMap(true, TextureUnitState::ENV_CURVED);
+        else if (params=="planar")
+            context.textureUnit->setEnvironmentMap(true, TextureUnitState::ENV_PLANAR);
+        else if (params=="cubic_reflection")
+            context.textureUnit->setEnvironmentMap(true, TextureUnitState::ENV_REFLECTION);
+        else if (params=="cubic_normal")
+            context.textureUnit->setEnvironmentMap(true, TextureUnitState::ENV_NORMAL);
+        else
+            logParseError("Bad env_map attribute, valid parameters are 'off', "
+                "'spherical', 'planar', 'cubic_reflection' and 'cubic_normal'.", context);
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseScroll(String& params, MaterialScriptContext& context)
+    {
+        StringVector vecparams = StringUtil::split(params, " \t");
+        if (vecparams.size() != 2)
+        {
+            logParseError("Bad scroll attribute, wrong number of parameters (expected 2)", context);
+            return false;
+        }
+        context.textureUnit->setTextureScroll(
+            StringConverter::parseReal(vecparams[0]), 
+            StringConverter::parseReal(vecparams[1]));
+
+    
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseScrollAnim(String& params, MaterialScriptContext& context)
+    {
+        StringVector vecparams = StringUtil::split(params, " \t");
+        if (vecparams.size() != 2)
+        {
+            logParseError("Bad scroll_anim attribute, wrong number of "
+                "parameters (expected 2)", context);
+            return false;
+        }
+        context.textureUnit->setScrollAnimation(
+            StringConverter::parseReal(vecparams[0]), 
+            StringConverter::parseReal(vecparams[1]));
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseRotate(String& params, MaterialScriptContext& context)
+    {
+        context.textureUnit->setTextureRotate(
+            StringConverter::parseAngle(params));
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseRotateAnim(String& params, MaterialScriptContext& context)
+    {
+        context.textureUnit->setRotateAnimation(
+            StringConverter::parseReal(params));
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseScale(String& params, MaterialScriptContext& context)
+    {
+        StringVector vecparams = StringUtil::split(params, " \t");
+        if (vecparams.size() != 2)
+        {
+            logParseError("Bad scale attribute, wrong number of parameters (expected 2)", context);
+            return false;
+        }
+        context.textureUnit->setTextureScale(
+            StringConverter::parseReal(vecparams[0]), 
+            StringConverter::parseReal(vecparams[1]));
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseWaveXform(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        StringVector vecparams = StringUtil::split(params, " \t");
+
+        if (vecparams.size() != 6)
+        {
+            logParseError("Bad wave_xform attribute, wrong number of parameters "
+                "(expected 6)", context);
+            return false;
+        }
+        TextureUnitState::TextureTransformType ttype;
+        WaveformType waveType;
+        // Check transform type
+        if (vecparams[0]=="scroll_x")
+            ttype = TextureUnitState::TT_TRANSLATE_U;
+        else if (vecparams[0]=="scroll_y")
+            ttype = TextureUnitState::TT_TRANSLATE_V;
+        else if (vecparams[0]=="rotate")
+            ttype = TextureUnitState::TT_ROTATE;
+        else if (vecparams[0]=="scale_x")
+            ttype = TextureUnitState::TT_SCALE_U;
+        else if (vecparams[0]=="scale_y")
+            ttype = TextureUnitState::TT_SCALE_V;
+        else
+        {
+            logParseError("Bad wave_xform attribute, parameter 1 must be 'scroll_x', "
+                "'scroll_y', 'rotate', 'scale_x' or 'scale_y'", context);
+            return false;
+        }
+        // Check wave type
+        if (vecparams[1]=="sine")
+            waveType = WFT_SINE;
+        else if (vecparams[1]=="triangle")
+            waveType = WFT_TRIANGLE;
+        else if (vecparams[1]=="square")
+            waveType = WFT_SQUARE;
+        else if (vecparams[1]=="sawtooth")
+            waveType = WFT_SAWTOOTH;
+        else if (vecparams[1]=="inverse_sawtooth")
+            waveType = WFT_INVERSE_SAWTOOTH;
+        else
+        {
+            logParseError("Bad wave_xform attribute, parameter 2 must be 'sine', "
+                "'triangle', 'square', 'sawtooth' or 'inverse_sawtooth'", context);
+            return false;
+        }
+
+        context.textureUnit->setTransformAnimation(
+            ttype, 
+            waveType, 
+            StringConverter::parseReal(vecparams[2]), 
+            StringConverter::parseReal(vecparams[3]),
+            StringConverter::parseReal(vecparams[4]), 
+            StringConverter::parseReal(vecparams[5]) );
+
+        return false;
+    }
+	//-----------------------------------------------------------------------
+	bool parseTransform(String& params, MaterialScriptContext& context)
+	{
+		StringVector vecparams = StringUtil::split(params, " \t");
+		if (vecparams.size() != 16)
+		{
+			logParseError("Bad transform attribute, wrong number of parameters (expected 16)", context);
+			return false;
+		}
+		Matrix4 xform(
+			StringConverter::parseReal(vecparams[0]), 
+			StringConverter::parseReal(vecparams[1]), 
+			StringConverter::parseReal(vecparams[2]), 
+			StringConverter::parseReal(vecparams[3]), 
+			StringConverter::parseReal(vecparams[4]), 
+			StringConverter::parseReal(vecparams[5]), 
+			StringConverter::parseReal(vecparams[6]), 
+			StringConverter::parseReal(vecparams[7]), 
+			StringConverter::parseReal(vecparams[8]), 
+			StringConverter::parseReal(vecparams[9]), 
+			StringConverter::parseReal(vecparams[10]), 
+			StringConverter::parseReal(vecparams[11]), 
+			StringConverter::parseReal(vecparams[12]), 
+			StringConverter::parseReal(vecparams[13]), 
+			StringConverter::parseReal(vecparams[14]), 
+			StringConverter::parseReal(vecparams[15]) );
+		context.textureUnit->setTextureTransform(xform);
+
+
+		return false;
+	}
+    //-----------------------------------------------------------------------
+    bool parseDepthBias(String& params, MaterialScriptContext& context)
+    {
+        context.pass->setDepthBias(
+            StringConverter::parseReal(params));
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseAnisotropy(String& params, MaterialScriptContext& context)
+    {
+        context.textureUnit->setTextureAnisotropy(
+            StringConverter::parseInt(params));
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseTextureAlias(String& params, MaterialScriptContext& context)
+    {
+        context.textureUnit->setTextureNameAlias(params);
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseLodDistances(String& params, MaterialScriptContext& context)
+    {
+        StringVector vecparams = StringUtil::split(params, " \t");
+
+        // iterate over the parameters and parse distances out of them
+        Material::LodDistanceList lodList;
+        StringVector::iterator i, iend;
+        iend = vecparams.end();
+        for (i = vecparams.begin(); i != iend; ++i)
+        {
+            lodList.push_back(StringConverter::parseReal(*i));
+        }
+
+        context.material->setLodLevels(lodList);
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseLodIndex(String& params, MaterialScriptContext& context)
+    {
+        context.technique->setLodIndex(StringConverter::parseInt(params));
+        return false;
+    }
+	//-----------------------------------------------------------------------
+	bool parseScheme(String& params, MaterialScriptContext& context)
+	{
+		context.technique->setSchemeName(params);
+		return false;
+	}
+    //-----------------------------------------------------------------------
+    bool parseSetTextureAlias(String& params, MaterialScriptContext& context)
+    {
+        StringVector vecparams = StringUtil::split(params, " \t");
+        if (vecparams.size() != 2)
+        {
+            logParseError("Wrong number of parameters for texture_alias, expected 2", context);
+            return false;
+        }
+        // first parameter is alias name and second paramater is texture name
+        context.textureAliases[vecparams[0]] = vecparams[1];
+
+        return false;
+    }
+
+    //-----------------------------------------------------------------------
+    void processManualProgramParam(size_t index, const String& commandname, 
+        StringVector& vecparams, MaterialScriptContext& context)
+    {
+        // NB we assume that the first element of vecparams is taken up with either 
+        // the index or the parameter name, which we ignore
+
+        // Determine type
+        size_t start, dims, roundedDims, i;
+        bool isReal;
+        bool isMatrix4x4 = false;
+
+        StringUtil::toLowerCase(vecparams[1]);
+
+        if (vecparams[1] == "matrix4x4")
+        {
+            dims = 16;
+            isReal = true;
+            isMatrix4x4 = true;
+        }
+        else if ((start = vecparams[1].find("float")) != String::npos)
+        {
+            // find the dimensionality
+            start = vecparams[1].find_first_not_of("float");
+            // Assume 1 if not specified
+            if (start == String::npos)
+            {
+                dims = 1;
+            }
+            else
+            {
+                dims = StringConverter::parseInt(vecparams[1].substr(start));
+            }
+            isReal = true;
+        }
+        else if ((start = vecparams[1].find("int")) != String::npos)
+        {
+            // find the dimensionality
+            start = vecparams[1].find_first_not_of("int");
+            // Assume 1 if not specified
+            if (start == String::npos)
+            {
+                dims = 1;
+            }
+            else
+            {
+                dims = StringConverter::parseInt(vecparams[1].substr(start));
+            }
+            isReal = false;
+        }
+        else
+        {
+            logParseError("Invalid " + commandname + " attribute - unrecognised "
+                "parameter type " + vecparams[1], context);
+            return;
+        }
+
+        if (vecparams.size() != 2 + dims)
+        {
+            logParseError("Invalid " + commandname + " attribute - you need " +
+                StringConverter::toString(2 + dims) + " parameters for a parameter of "
+                "type " + vecparams[1], context);
+        }
+
+        // Round dims to multiple of 4
+        if (dims %4 != 0)
+        {
+            roundedDims = dims + 4 - (dims % 4);
+        }
+        else
+        {
+            roundedDims = dims;
+        }
+
+        // set the name of the parameter if it exists
+        String paramName = (commandname == "param_named") ? vecparams[0] : "";
+
+        // Now parse all the values
+        if (isReal)
+        {
+            Real* realBuffer = new Real[roundedDims];
+            // Do specified values
+            for (i = 0; i < dims; ++i)
+            {
+                realBuffer[i] = StringConverter::parseReal(vecparams[i+2]);
+            }
+            // Fill up to multiple of 4 with zero
+            for (; i < roundedDims; ++i)
+            {
+                realBuffer[i] = 0.0f; 
+
+            }
+
+            if (isMatrix4x4)
+            {
+                // its a Matrix4x4 so pass as a Matrix4
+                // use specialized setConstant that takes a matrix so matrix is transposed if required
+                Matrix4 m4x4(
+                    realBuffer[0],  realBuffer[1],  realBuffer[2],  realBuffer[3],
+                    realBuffer[4],  realBuffer[5],  realBuffer[6],  realBuffer[7],
+                    realBuffer[8],  realBuffer[9],  realBuffer[10], realBuffer[11],
+                    realBuffer[12], realBuffer[13], realBuffer[14], realBuffer[15]
+                    );
+                context.programParams->setConstant(index, m4x4);
+            }
+            else 
+            {
+                // Set
+                context.programParams->setConstant(index, realBuffer, roundedDims * 0.25);
+
+            }
+
+            
+            delete [] realBuffer;
+            // log the parameter
+            context.programParams->addConstantDefinition(paramName, index, dims, GpuProgramParameters::ET_REAL);
+        }
+        else
+        {
+            int* intBuffer = new int[roundedDims];
+            // Do specified values
+            for (i = 0; i < dims; ++i)
+            {
+                intBuffer[i] = StringConverter::parseInt(vecparams[i+2]);
+            }
+            // Fill to multiple of 4 with 0
+            for (; i < roundedDims; ++i)
+            {
+                intBuffer[i] = 0;
+            }
+            // Set
+            context.programParams->setConstant(index, intBuffer, roundedDims * 0.25);
+            delete [] intBuffer;
+            // log the parameter
+            context.programParams->addConstantDefinition(paramName, index, dims, GpuProgramParameters::ET_INT);
+        }
+    }
+    //-----------------------------------------------------------------------
+    void processAutoProgramParam(size_t index, const String& commandname, 
+        StringVector& vecparams, MaterialScriptContext& context)
+    {
+        // NB we assume that the first element of vecparams is taken up with either 
+        // the index or the parameter name, which we ignore
+
+        // make sure param is in lower case
+        StringUtil::toLowerCase(vecparams[1]);
+
+        // lookup the param to see if its a valid auto constant
+        const GpuProgramParameters::AutoConstantDefinition* autoConstantDef =
+            context.programParams->getAutoConstantDefinition(vecparams[1]);
+
+        // exit with error msg if the auto constant definition wasn't found
+        if (!autoConstantDef)
+		{
+			logParseError("Invalid " + commandname + " attribute - "
+				+ vecparams[1], context);
+			return;
+		}
+
+        // add AutoConstant based on the type of data it uses
+        switch (autoConstantDef->dataType)
+        {
+        case GpuProgramParameters::ACDT_NONE:
+            context.programParams->setAutoConstant(index, autoConstantDef->acType, 0);
+            break;
+
+        case GpuProgramParameters::ACDT_INT:
+            {
+				// Special case animation_parametric, we need to keep track of number of times used
+				if (autoConstantDef->acType == GpuProgramParameters::ACT_ANIMATION_PARAMETRIC)
+				{
+					context.programParams->setAutoConstant(
+						index, autoConstantDef->acType, context.numAnimationParametrics++);
+				}
+				else
+				{
+
+					if (vecparams.size() != 3)
+					{
+						logParseError("Invalid " + commandname + " attribute - "
+							"expected 3 parameters.", context);
+						return;
+					}
+
+					size_t extraParam = StringConverter::parseInt(vecparams[2]);
+					context.programParams->setAutoConstant(
+						index, autoConstantDef->acType, extraParam);
+				}
+            }
+            break;
+
+        case GpuProgramParameters::ACDT_REAL:
+            {
+                // special handling for time
+                if (autoConstantDef->acType == GpuProgramParameters::ACT_TIME ||
+                    autoConstantDef->acType == GpuProgramParameters::ACT_FRAME_TIME)
+                {
+                    Real factor = 1.0f;
+                    if (vecparams.size() == 3)
+                    {
+                        factor = StringConverter::parseReal(vecparams[2]);
+                    }
+                    
+                    context.programParams->setAutoConstantReal(index, autoConstantDef->acType, factor);
+                }
+                else // normal processing for auto constants that take an extra real value
+                {
+                    if (vecparams.size() != 3)
+                    {
+                        logParseError("Invalid " + commandname + " attribute - "
+                            "expected 3 parameters.", context);
+                        return;
+                    }
+
+			        Real rData = StringConverter::parseReal(vecparams[2]);
+			        context.programParams->setAutoConstantReal(index, autoConstantDef->acType, rData);
+                }
+            }
+            break;
+
+        } // end switch
+
+        String paramName = (commandname == "param_named_auto") ? vecparams[0] : "";
+        // add constant definition based on AutoConstant
+        // make element count 0 so that proper allocation occurs when AutoState is set up
+        size_t constantIndex = context.programParams->addConstantDefinition(
+			paramName, index, 0, autoConstantDef->elementType);
+        // update constant definition auto settings
+        // since an autoconstant was just added, its the last one in the container
+        size_t autoIndex = context.programParams->getAutoConstantCount() - 1;
+        // setup autoState which will allocate the proper amount of storage required by constant entries
+        context.programParams->setConstantDefinitionAutoState(constantIndex, true, autoIndex);
+        
+    }
+
+    //-----------------------------------------------------------------------
+    bool parseParamIndexed(String& params, MaterialScriptContext& context)
+    {
+        // NB skip this if the program is not supported or could not be found
+        if (context.program.isNull() || !context.program->isSupported())
+        {
+            return false;
+        }
+
+        StringUtil::toLowerCase(params);
+        StringVector vecparams = StringUtil::split(params, " \t");
+        if (vecparams.size() < 3)
+        {
+            logParseError("Invalid param_indexed attribute - expected at least 3 parameters.", 
+                context);
+            return false;
+        }
+
+        // Get start index
+        size_t index = StringConverter::parseInt(vecparams[0]);
+
+        processManualProgramParam(index, "param_indexed", vecparams, context);
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseParamIndexedAuto(String& params, MaterialScriptContext& context)
+    {
+        // NB skip this if the program is not supported or could not be found
+        if (context.program.isNull() || !context.program->isSupported())
+        {
+            return false;
+        }
+
+        StringUtil::toLowerCase(params);
+        StringVector vecparams = StringUtil::split(params, " \t");
+        if (vecparams.size() != 2 && vecparams.size() != 3)
+        {
+            logParseError("Invalid param_indexed_auto attribute - expected 2 or 3 parameters.", 
+                context);
+            return false;
+        }
+
+        // Get start index
+        size_t index = StringConverter::parseInt(vecparams[0]);
+
+        processAutoProgramParam(index, "param_indexed_auto", vecparams, context);
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseParamNamed(String& params, MaterialScriptContext& context)
+    {
+        // NB skip this if the program is not supported or could not be found
+        if (context.program.isNull() || !context.program->isSupported())
+        {
+            return false;
+        }
+
+        StringVector vecparams = StringUtil::split(params, " \t");
+        if (vecparams.size() < 3)
+        {
+            logParseError("Invalid param_named attribute - expected at least 3 parameters.", 
+                context);
+            return false;
+        }
+
+        // Get start index from name
+        size_t index;
+        try {
+            index = context.programParams->getParamIndex(vecparams[0]);
+        }
+        catch (Exception& e)
+        {
+            logParseError("Invalid param_named attribute - " + e.getFullDescription(), context);
+            return false;
+        }
+
+        // TEST
+        /*
+        LogManager::getSingleton().logMessage("SETTING PARAMETER " + vecparams[0] + " as index " +
+            StringConverter::toString(index));
+        */
+        processManualProgramParam(index, "param_named", vecparams, context);
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseParamNamedAuto(String& params, MaterialScriptContext& context)
+    {
+        // NB skip this if the program is not supported or could not be found
+        if (context.program.isNull() || !context.program->isSupported())
+        {
+            return false;
+        }
+
+        StringVector vecparams = StringUtil::split(params, " \t");
+        if (vecparams.size() != 2 && vecparams.size() != 3)
+        {
+            logParseError("Invalid param_indexed_auto attribute - expected 2 or 3 parameters.", 
+                context);
+            return false;
+        }
+
+        // Get start index from name
+        size_t index;
+        try {
+            index = context.programParams->getParamIndex(vecparams[0]);
+        }
+        catch (Exception& e)
+        {
+            logParseError("Invalid param_named_auto attribute - " + e.getFullDescription(), context);
+            return false;
+        }
+
+        processAutoProgramParam(index, "param_named_auto", vecparams, context);
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseMaterial(String& params, MaterialScriptContext& context)
+    {
+        // nfz:
+        // check params for reference to parent material to copy from
+        // syntax: material name : parentMaterialName
+        // check params for a colon after the first name and extract the parent name
+        StringVector vecparams = StringUtil::split(params, ":", 1);
+        MaterialPtr basematerial;
+
+        // Create a brand new material
+        if (vecparams.size() >= 2)
+        {
+            // if a second parameter exists then assume its the name of the base material
+            // that this new material should clone from
+            StringUtil::trim(vecparams[1]);
+            // make sure base material exists
+            basematerial = MaterialManager::getSingleton().getByName(vecparams[1]);
+            // if it doesn't exist then report error in log and just create a new material
+            if (basematerial.isNull())
+            {
+                logParseError("parent material: " + vecparams[1] + " not found for new material:"
+                    + vecparams[0], context);
+            }
+        }
+
+        // get rid of leading and trailing white space from material name
+        StringUtil::trim(vecparams[0]);
+
+        context.material = 
+			MaterialManager::getSingleton().create(vecparams[0], context.groupName);
+
+        if (!basematerial.isNull())
+        {
+            // copy parent material details to new material
+            basematerial->copyDetailsTo(context.material);
+        }
+        else
+        {
+            // Remove pre-created technique from defaults
+            context.material->removeAllTechniques();
+        }
+
+		context.material->_notifyOrigin(context.filename);
+
+        // update section
+        context.section = MSS_MATERIAL;
+
+        // Return TRUE because this must be followed by a {
+        return true;
+    }
+    //-----------------------------------------------------------------------
+    bool parseTechnique(String& params, MaterialScriptContext& context)
+    {
+
+        // if params is not empty then see if the technique name already exists
+        if (!params.empty() && (context.material->getNumTechniques() > 0))
+        {
+            // find the technique with name = params
+            Technique * foundTechnique = context.material->getTechnique(params);
+            if (foundTechnique)
+            {
+                // figure out technique index by iterating through technique container
+                // would be nice if each technique remembered its index
+                int count = 0;
+                Material::TechniqueIterator i = context.material->getTechniqueIterator();
+                while(i.hasMoreElements())
+                {
+                    if (foundTechnique == i.peekNext())
+                        break;
+                    i.moveNext();
+                    ++count;
+                }
+
+                context.techLev = count;
+            }
+            else
+            {
+                // name was not found so a new technique is needed
+                // position technique level to the end index
+                // a new technique will be created later on
+                context.techLev = context.material->getNumTechniques();
+            }
+
+        }
+        else 
+        {
+            // no name was given in the script so a new technique will be created
+		    // Increase technique level depth
+		    ++context.techLev;
+        }
+
+        // Create a new technique if it doesn't already exist
+        if (context.material->getNumTechniques() > context.techLev)
+        {
+            context.technique = context.material->getTechnique(context.techLev);
+        }
+        else
+        {
+            context.technique = context.material->createTechnique();
+            if (!params.empty())
+                context.technique->setName(params);
+        }
+
+        // update section
+        context.section = MSS_TECHNIQUE;
+
+        // Return TRUE because this must be followed by a {
+        return true;
+    }
+    //-----------------------------------------------------------------------
+    bool parsePass(String& params, MaterialScriptContext& context)
+    {
+        // if params is not empty then see if the pass name already exists
+        if (!params.empty() && (context.technique->getNumPasses() > 0))
+        {
+            // find the pass with name = params
+            Pass * foundPass = context.technique->getPass(params);
+            if (foundPass)
+            {
+                context.passLev = foundPass->getIndex();
+            }
+            else
+            {
+                // name was not found so a new pass is needed
+                // position pass level to the end index
+                // a new pass will be created later on
+                context.passLev = context.technique->getNumPasses();
+            }
+
+        }
+        else
+        {
+		    //Increase pass level depth
+		    ++context.passLev;
+        }
+
+        if (context.technique->getNumPasses() > context.passLev)
+        {
+            context.pass = context.technique->getPass(context.passLev);
+        }
+        else
+        {
+            // Create a new pass
+            context.pass = context.technique->createPass();
+            if (!params.empty())
+                context.pass->setName(params);
+        }
+
+        // update section
+        context.section = MSS_PASS;
+
+        // Return TRUE because this must be followed by a {
+        return true;
+    }
+    //-----------------------------------------------------------------------
+    bool parseTextureUnit(String& params, MaterialScriptContext& context)
+    {
+        // if params is a name then see if that texture unit exists
+        // if not then log the warning and just move on to the next TU from current
+        if (!params.empty() && (context.pass->getNumTextureUnitStates() > 0))
+        {
+            // specifying a TUS name in the script for a TU means that a specific TU is being requested
+            // try to get the specific TU
+            // if the index requested is not valid, just creat a new TU
+            // find the TUS with name = params
+            TextureUnitState * foundTUS = context.pass->getTextureUnitState(params);
+            if (foundTUS)
+            {
+                context.stateLev = context.pass->getTextureUnitStateIndex(foundTUS);
+            }
+            else
+            {
+                // name was not found so a new TUS is needed
+                // position TUS level to the end index
+                // a new TUS will be created later on
+                context.stateLev = context.pass->getNumTextureUnitStates();
+            }
+        }
+        else
+        {
+		    //Increase Texture Unit State level depth
+		    ++context.stateLev;
+        }
+
+        if (context.pass->getNumTextureUnitStates() > static_cast<size_t>(context.stateLev))
+        {
+            context.textureUnit = context.pass->getTextureUnitState(context.stateLev);
+        }
+        else
+        {
+            // Create a new texture unit
+            context.textureUnit = context.pass->createTextureUnitState();
+            if (!params.empty())
+                context.textureUnit->setName(params);
+        }
+        // update section
+        context.section = MSS_TEXTUREUNIT;
+
+        // Return TRUE because this must be followed by a {
+        return true;
+    }
+
+    //-----------------------------------------------------------------------
+    bool parseVertexProgramRef(String& params, MaterialScriptContext& context)
+    {
+        // update section
+        context.section = MSS_PROGRAM_REF;
+
+        // check if pass has a vertex program already
+        if (context.pass->hasVertexProgram())
+        {
+            // if existing pass vertex program has same name as params
+            // or params is empty then use current vertex program
+            if (params.empty() || (context.pass->getVertexProgramName() == params))
+            {
+                context.program = context.pass->getVertexProgram();
+            }
+        }
+
+        // if context.program was not set then try to get the vertex program using the name 
+        // passed in params
+        if (context.program.isNull())
+        {
+            context.program = GpuProgramManager::getSingleton().getByName(params);
+            if (context.program.isNull())
+            {
+                // Unknown program
+                logParseError("Invalid vertex_program_ref entry - vertex program " 
+                    + params + " has not been defined.", context);
+                return true;
+            }
+
+            context.isProgramShadowCaster = false;
+            context.isVertexProgramShadowReceiver = false;
+			context.isFragmentProgramShadowReceiver = false;
+            
+            // Set the vertex program for this pass
+            context.pass->setVertexProgram(params);
+        }
+
+        // Create params? Skip this if program is not supported
+        if (context.program->isSupported())
+        {
+            context.programParams = context.pass->getVertexProgramParameters();
+			context.numAnimationParametrics = 0;
+        }
+
+        // Return TRUE because this must be followed by a {
+        return true;
+    }
+    //-----------------------------------------------------------------------
+    bool parseShadowCasterVertexProgramRef(String& params, MaterialScriptContext& context)
+    {
+        // update section
+        context.section = MSS_PROGRAM_REF;
+
+        context.program = GpuProgramManager::getSingleton().getByName(params);
+        if (context.program.isNull())
+        {
+            // Unknown program
+            logParseError("Invalid shadow_caster_vertex_program_ref entry - vertex program " 
+                + params + " has not been defined.", context);
+            return true;
+        }
+
+        context.isProgramShadowCaster = true;
+        context.isVertexProgramShadowReceiver = false;
+		context.isFragmentProgramShadowReceiver = false;
+
+        // Set the vertex program for this pass
+        context.pass->setShadowCasterVertexProgram(params);
+
+        // Create params? Skip this if program is not supported
+        if (context.program->isSupported())
+        {
+            context.programParams = context.pass->getShadowCasterVertexProgramParameters();
+			context.numAnimationParametrics = 0;
+        }
+
+        // Return TRUE because this must be followed by a {
+        return true;
+    }
+    //-----------------------------------------------------------------------
+    bool parseShadowReceiverVertexProgramRef(String& params, MaterialScriptContext& context)
+    {
+        // update section
+        context.section = MSS_PROGRAM_REF;
+
+        context.program = GpuProgramManager::getSingleton().getByName(params);
+        if (context.program.isNull())
+        {
+            // Unknown program
+            logParseError("Invalid shadow_receiver_vertex_program_ref entry - vertex program " 
+                + params + " has not been defined.", context);
+            return true;
+        }
+        
+
+        context.isProgramShadowCaster = false;
+        context.isVertexProgramShadowReceiver = true;
+		context.isFragmentProgramShadowReceiver = false;
+
+        // Set the vertex program for this pass
+        context.pass->setShadowReceiverVertexProgram(params);
+
+        // Create params? Skip this if program is not supported
+        if (context.program->isSupported())
+        {
+            context.programParams = context.pass->getShadowReceiverVertexProgramParameters();
+			context.numAnimationParametrics = 0;
+        }
+
+        // Return TRUE because this must be followed by a {
+        return true;
+    }
+	//-----------------------------------------------------------------------
+	bool parseShadowReceiverFragmentProgramRef(String& params, MaterialScriptContext& context)
+	{
+		// update section
+		context.section = MSS_PROGRAM_REF;
+
+		context.program = GpuProgramManager::getSingleton().getByName(params);
+		if (context.program.isNull())
+		{
+			// Unknown program
+			logParseError("Invalid shadow_receiver_fragment_program_ref entry - fragment program " 
+				+ params + " has not been defined.", context);
+			return true;
+		}
+
+
+		context.isProgramShadowCaster = false;
+		context.isVertexProgramShadowReceiver = false;
+		context.isFragmentProgramShadowReceiver = true;
+
+		// Set the vertex program for this pass
+		context.pass->setShadowReceiverFragmentProgram(params);
+
+		// Create params? Skip this if program is not supported
+		if (context.program->isSupported())
+		{
+			context.programParams = context.pass->getShadowReceiverFragmentProgramParameters();
+			context.numAnimationParametrics = 0;
+		}
+
+		// Return TRUE because this must be followed by a {
+		return true;
+	}
+    //-----------------------------------------------------------------------
+    bool parseFragmentProgramRef(String& params, MaterialScriptContext& context)
+    {
+        // update section
+        context.section = MSS_PROGRAM_REF;
+
+        // check if pass has a fragment program already
+        if (context.pass->hasFragmentProgram())
+        {
+            // if existing pass fragment program has same name as params
+            // or params is empty then use current fragment program
+            if (params.empty() || (context.pass->getFragmentProgramName() == params))
+            {
+                context.program = context.pass->getFragmentProgram();
+            }
+        }
+
+        // if context.program was not set then try to get the fragment program using the name 
+        // passed in params
+        if (context.program.isNull())
+        {
+            context.program = GpuProgramManager::getSingleton().getByName(params);
+            if (context.program.isNull())
+            {
+                // Unknown program
+                logParseError("Invalid fragment_program_ref entry - fragment program " 
+                    + params + " has not been defined.", context);
+                return true;
+            }
+            
+            // Set the vertex program for this pass
+            context.pass->setFragmentProgram(params);
+        }
+
+        // Create params? Skip this if program is not supported
+        if (context.program->isSupported())
+        {
+            context.programParams = context.pass->getFragmentProgramParameters();
+			context.numAnimationParametrics = 0;
+        }
+
+        // Return TRUE because this must be followed by a {
+        return true;
+    }
+    //-----------------------------------------------------------------------
+    bool parseVertexProgram(String& params, MaterialScriptContext& context)
+    {
+        // update section
+        context.section = MSS_PROGRAM;
+
+		// Create new program definition-in-progress
+		context.programDef = new MaterialScriptProgramDefinition();
+		context.programDef->progType = GPT_VERTEX_PROGRAM;
+        context.programDef->supportsSkeletalAnimation = false;
+		context.programDef->supportsMorphAnimation = false;
+		context.programDef->supportsPoseAnimation = 0;
+
+		// Get name and language code
+		StringVector vecparams = StringUtil::split(params, " \t");
+		if (vecparams.size() != 2)
+		{
+            logParseError("Invalid vertex_program entry - expected "
+				"2 parameters.", context);
+            return true;
+		}
+		// Name, preserve case
+		context.programDef->name = vecparams[0];
+		// language code, make lower case
+		context.programDef->language = vecparams[1];
+		StringUtil::toLowerCase(context.programDef->language);
+
+        // Return TRUE because this must be followed by a {
+        return true;
+	}
+    //-----------------------------------------------------------------------
+    bool parseFragmentProgram(String& params, MaterialScriptContext& context)
+    {
+        // update section
+        context.section = MSS_PROGRAM;
+
+		// Create new program definition-in-progress
+		context.programDef = new MaterialScriptProgramDefinition();
+		context.programDef->progType = GPT_FRAGMENT_PROGRAM;
+		context.programDef->supportsSkeletalAnimation = false;
+		context.programDef->supportsMorphAnimation = false;
+		context.programDef->supportsPoseAnimation = 0;
+
+		// Get name and language code
+		StringVector vecparams = StringUtil::split(params, " \t");
+		if (vecparams.size() != 2)
+		{
+            logParseError("Invalid fragment_program entry - expected "
+				"2 parameters.", context);
+            return true;
+		}
+		// Name, preserve case
+		context.programDef->name = vecparams[0];
+		// language code, make lower case
+		context.programDef->language = vecparams[1];
+		StringUtil::toLowerCase(context.programDef->language);
+
+		// Return TRUE because this must be followed by a {
+        return true;
+	
+	}
+    //-----------------------------------------------------------------------
+    bool parseProgramSource(String& params, MaterialScriptContext& context)
+    {
+		// Source filename, preserve case
+		context.programDef->source = params;
+
+		return false;
+	}
+    //-----------------------------------------------------------------------
+    bool parseProgramSkeletalAnimation(String& params, MaterialScriptContext& context)
+    {
+        // Source filename, preserve case
+        context.programDef->supportsSkeletalAnimation 
+            = StringConverter::parseBool(params);
+
+        return false;
+    }
+	//-----------------------------------------------------------------------
+	bool parseProgramMorphAnimation(String& params, MaterialScriptContext& context)
+	{
+		// Source filename, preserve case
+		context.programDef->supportsMorphAnimation 
+			= StringConverter::parseBool(params);
+
+		return false;
+	}
+	//-----------------------------------------------------------------------
+	bool parseProgramPoseAnimation(String& params, MaterialScriptContext& context)
+	{
+		// Source filename, preserve case
+		context.programDef->supportsPoseAnimation 
+			= StringConverter::parseInt(params);
+
+		return false;
+	}
+    //-----------------------------------------------------------------------
+    bool parseProgramSyntax(String& params, MaterialScriptContext& context)
+    {
+		// Syntax code, make lower case
+        StringUtil::toLowerCase(params);
+		context.programDef->syntax = params;
+
+		return false;
+	}
+    //-----------------------------------------------------------------------
+    bool parseProgramCustomParameter(String& params, MaterialScriptContext& context)
+    {
+		// This params object does not have the command stripped
+		// Lower case the command, but not the value incase it's relevant
+		// Split only up to first delimiter, program deals with the rest
+		StringVector vecparams = StringUtil::split(params, " \t", 1);
+		if (vecparams.size() != 2)
+		{
+            logParseError("Invalid custom program parameter entry; "
+				"there must be a parameter name and at least one value.", 
+				context);
+            return false;
+		}
+
+		context.programDef->customParameters[vecparams[0]] = vecparams[1];
+
+		return false;
+	}
+
+	//-----------------------------------------------------------------------
+    bool parseTextureSource(String& params, MaterialScriptContext& context)
+    {
+		StringUtil::toLowerCase(params);
+        StringVector vecparams = StringUtil::split(params, " \t");
+        if (vecparams.size() != 1)
+			logParseError("Invalid texture source attribute - expected 1 parameter.",                 context);
+        //The only param should identify which ExternalTextureSource is needed
+		ExternalTextureSourceManager::getSingleton().setCurrentPlugIn( vecparams[0] );
+
+		if(	ExternalTextureSourceManager::getSingleton().getCurrentPlugIn() != 0 )
+		{
+			String tps;
+			tps = StringConverter::toString( context.techLev ) + " "
+				+ StringConverter::toString( context.passLev ) + " "
+				+ StringConverter::toString( context.stateLev);
+
+			ExternalTextureSourceManager::getSingleton().getCurrentPlugIn()->setParameter( "set_T_P_S", tps );
+		}
+			
+        // update section
+        context.section = MSS_TEXTURESOURCE;
+        // Return TRUE because this must be followed by a {
+        return true;
+    }
+
+    //-----------------------------------------------------------------------
+    bool parseTextureCustomParameter(String& params, MaterialScriptContext& context)
+    {
+		// This params object does not have the command stripped
+		// Split only up to first delimiter, program deals with the rest
+		StringVector vecparams = StringUtil::split(params, " \t", 1);
+		if (vecparams.size() != 2)
+		{
+            logParseError("Invalid texture parameter entry; "
+				"there must be a parameter name and at least one value.", 
+				context);
+            return false;
+		}
+		
+		if(	ExternalTextureSourceManager::getSingleton().getCurrentPlugIn() != 0 )
+			////First is command, next could be a string with one or more values
+			ExternalTextureSourceManager::getSingleton().getCurrentPlugIn()->setParameter( vecparams[0], vecparams[1] );
+		
+		return false;
+	}
+    //-----------------------------------------------------------------------
+    bool parseReceiveShadows(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        if (params == "on")
+            context.material->setReceiveShadows(true);
+        else if (params == "off")
+            context.material->setReceiveShadows(false);
+        else
+            logParseError(
+            "Bad receive_shadows attribute, valid parameters are 'on' or 'off'.", 
+            context);
+
+        return false;
+
+    }
+    //-----------------------------------------------------------------------
+    bool parseDefaultParams(String& params, MaterialScriptContext& context)
+    {
+        context.section = MSS_DEFAULT_PARAMETERS;
+        // Should be a brace next
+        return true;
+    }
+
+	//-----------------------------------------------------------------------
+	bool parseTransparencyCastsShadows(String& params, MaterialScriptContext& context)
+	{
+        StringUtil::toLowerCase(params);
+		if (params == "on")
+			context.material->setTransparencyCastsShadows(true);
+		else if (params == "off")
+			context.material->setTransparencyCastsShadows(false);
+		else
+			logParseError(
+			"Bad transparency_casts_shadows attribute, valid parameters are 'on' or 'off'.", 
+			context);
+
+		return false;
+
+	}
+
+#ifdef GAMETOOLS_ILLUMINATION_MODULE
+	//-----------------------------------------------------------------------
+    bool parseVertexTexture(String& params, MaterialScriptContext& context)
+    {
+        context.textureUnit->setVertexTexture(
+			StringConverter::parseBool(params));
+
+        return false;
+    }
+#endif
+
+	//-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    MaterialSerializer::MaterialSerializer()
+    {
+        // Set up root attribute parsers
+        mRootAttribParsers.insert(AttribParserList::value_type("material", (ATTRIBUTE_PARSER)parseMaterial));
+        mRootAttribParsers.insert(AttribParserList::value_type("vertex_program", (ATTRIBUTE_PARSER)parseVertexProgram));
+        mRootAttribParsers.insert(AttribParserList::value_type("fragment_program", (ATTRIBUTE_PARSER)parseFragmentProgram));
+
+        // Set up material attribute parsers
+        mMaterialAttribParsers.insert(AttribParserList::value_type("lod_distances", (ATTRIBUTE_PARSER)parseLodDistances));
+        mMaterialAttribParsers.insert(AttribParserList::value_type("receive_shadows", (ATTRIBUTE_PARSER)parseReceiveShadows));
+		mMaterialAttribParsers.insert(AttribParserList::value_type("transparency_casts_shadows", (ATTRIBUTE_PARSER)parseTransparencyCastsShadows));
+        mMaterialAttribParsers.insert(AttribParserList::value_type("technique", (ATTRIBUTE_PARSER)parseTechnique));
+        mMaterialAttribParsers.insert(AttribParserList::value_type("set_texture_alias", (ATTRIBUTE_PARSER)parseSetTextureAlias));
+
+        // Set up technique attribute parsers
+        mTechniqueAttribParsers.insert(AttribParserList::value_type("lod_index", (ATTRIBUTE_PARSER)parseLodIndex));
+		mTechniqueAttribParsers.insert(AttribParserList::value_type("scheme", (ATTRIBUTE_PARSER)parseScheme));
+        mTechniqueAttribParsers.insert(AttribParserList::value_type("pass", (ATTRIBUTE_PARSER)parsePass));
+
+        // Set up pass attribute parsers
+        mPassAttribParsers.insert(AttribParserList::value_type("ambient", (ATTRIBUTE_PARSER)parseAmbient));
+        mPassAttribParsers.insert(AttribParserList::value_type("diffuse", (ATTRIBUTE_PARSER)parseDiffuse));
+        mPassAttribParsers.insert(AttribParserList::value_type("specular", (ATTRIBUTE_PARSER)parseSpecular));
+        mPassAttribParsers.insert(AttribParserList::value_type("emissive", (ATTRIBUTE_PARSER)parseEmissive));
+        mPassAttribParsers.insert(AttribParserList::value_type("scene_blend", (ATTRIBUTE_PARSER)parseSceneBlend));
+        mPassAttribParsers.insert(AttribParserList::value_type("depth_check", (ATTRIBUTE_PARSER)parseDepthCheck));
+        mPassAttribParsers.insert(AttribParserList::value_type("depth_write", (ATTRIBUTE_PARSER)parseDepthWrite));
+        mPassAttribParsers.insert(AttribParserList::value_type("depth_func", (ATTRIBUTE_PARSER)parseDepthFunc));
+		mPassAttribParsers.insert(AttribParserList::value_type("alpha_rejection", (ATTRIBUTE_PARSER)parseAlphaRejection));
+        mPassAttribParsers.insert(AttribParserList::value_type("colour_write", (ATTRIBUTE_PARSER)parseColourWrite));
+        mPassAttribParsers.insert(AttribParserList::value_type("cull_hardware", (ATTRIBUTE_PARSER)parseCullHardware));
+        mPassAttribParsers.insert(AttribParserList::value_type("cull_software", (ATTRIBUTE_PARSER)parseCullSoftware));
+        mPassAttribParsers.insert(AttribParserList::value_type("lighting", (ATTRIBUTE_PARSER)parseLighting));
+        mPassAttribParsers.insert(AttribParserList::value_type("fog_override", (ATTRIBUTE_PARSER)parseFogging));
+        mPassAttribParsers.insert(AttribParserList::value_type("shading", (ATTRIBUTE_PARSER)parseShading));
+		mPassAttribParsers.insert(AttribParserList::value_type("polygon_mode", (ATTRIBUTE_PARSER)parsePolygonMode));
+        mPassAttribParsers.insert(AttribParserList::value_type("depth_bias", (ATTRIBUTE_PARSER)parseDepthBias));
+        mPassAttribParsers.insert(AttribParserList::value_type("texture_unit", (ATTRIBUTE_PARSER)parseTextureUnit));
+        mPassAttribParsers.insert(AttribParserList::value_type("vertex_program_ref", (ATTRIBUTE_PARSER)parseVertexProgramRef));
+        mPassAttribParsers.insert(AttribParserList::value_type("shadow_caster_vertex_program_ref", (ATTRIBUTE_PARSER)parseShadowCasterVertexProgramRef));
+        mPassAttribParsers.insert(AttribParserList::value_type("shadow_receiver_vertex_program_ref", (ATTRIBUTE_PARSER)parseShadowReceiverVertexProgramRef));
+		mPassAttribParsers.insert(AttribParserList::value_type("shadow_receiver_fragment_program_ref", (ATTRIBUTE_PARSER)parseShadowReceiverFragmentProgramRef));
+        mPassAttribParsers.insert(AttribParserList::value_type("fragment_program_ref", (ATTRIBUTE_PARSER)parseFragmentProgramRef));
+        mPassAttribParsers.insert(AttribParserList::value_type("max_lights", (ATTRIBUTE_PARSER)parseMaxLights));
+        mPassAttribParsers.insert(AttribParserList::value_type("iteration", (ATTRIBUTE_PARSER)parseIteration));
+		mPassAttribParsers.insert(AttribParserList::value_type("point_size", (ATTRIBUTE_PARSER)parsePointSize));
+		mPassAttribParsers.insert(AttribParserList::value_type("point_sprites", (ATTRIBUTE_PARSER)parsePointSprites));
+		mPassAttribParsers.insert(AttribParserList::value_type("point_size_attenuation", (ATTRIBUTE_PARSER)parsePointAttenuation));
+		mPassAttribParsers.insert(AttribParserList::value_type("point_size_min", (ATTRIBUTE_PARSER)parsePointSizeMin));
+		mPassAttribParsers.insert(AttribParserList::value_type("point_size_max", (ATTRIBUTE_PARSER)parsePointSizeMax));
+
+        // Set up texture unit attribute parsers
+		mTextureUnitAttribParsers.insert(AttribParserList::value_type("texture_source", (ATTRIBUTE_PARSER)parseTextureSource));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("texture", (ATTRIBUTE_PARSER)parseTexture));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("anim_texture", (ATTRIBUTE_PARSER)parseAnimTexture));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("cubic_texture", (ATTRIBUTE_PARSER)parseCubicTexture));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("tex_coord_set", (ATTRIBUTE_PARSER)parseTexCoord));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("tex_address_mode", (ATTRIBUTE_PARSER)parseTexAddressMode));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("tex_border_colour", (ATTRIBUTE_PARSER)parseTexBorderColour));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("colour_op", (ATTRIBUTE_PARSER)parseColourOp));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("colour_op_ex", (ATTRIBUTE_PARSER)parseColourOpEx));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("colour_op_multipass_fallback", (ATTRIBUTE_PARSER)parseColourOpFallback));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("alpha_op_ex", (ATTRIBUTE_PARSER)parseAlphaOpEx));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("env_map", (ATTRIBUTE_PARSER)parseEnvMap));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("scroll", (ATTRIBUTE_PARSER)parseScroll));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("scroll_anim", (ATTRIBUTE_PARSER)parseScrollAnim));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("rotate", (ATTRIBUTE_PARSER)parseRotate));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("rotate_anim", (ATTRIBUTE_PARSER)parseRotateAnim));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("scale", (ATTRIBUTE_PARSER)parseScale));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("wave_xform", (ATTRIBUTE_PARSER)parseWaveXform));
+		mTextureUnitAttribParsers.insert(AttribParserList::value_type("transform", (ATTRIBUTE_PARSER)parseTransform));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("filtering", (ATTRIBUTE_PARSER)parseFiltering));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("max_anisotropy", (ATTRIBUTE_PARSER)parseAnisotropy));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("texture_alias", (ATTRIBUTE_PARSER)parseTextureAlias));
+#ifdef 	GAMETOOLS_ILLUMINATION_MODULE
+		mTextureUnitAttribParsers.insert(AttribParserList::value_type("vertex_texture", (ATTRIBUTE_PARSER)parseVertexTexture));
+#endif
+        // Set up program reference attribute parsers
+        mProgramRefAttribParsers.insert(AttribParserList::value_type("param_indexed", (ATTRIBUTE_PARSER)parseParamIndexed));
+        mProgramRefAttribParsers.insert(AttribParserList::value_type("param_indexed_auto", (ATTRIBUTE_PARSER)parseParamIndexedAuto));
+        mProgramRefAttribParsers.insert(AttribParserList::value_type("param_named", (ATTRIBUTE_PARSER)parseParamNamed));
+        mProgramRefAttribParsers.insert(AttribParserList::value_type("param_named_auto", (ATTRIBUTE_PARSER)parseParamNamedAuto));
+
+        // Set up program definition attribute parsers
+        mProgramAttribParsers.insert(AttribParserList::value_type("source", (ATTRIBUTE_PARSER)parseProgramSource));
+        mProgramAttribParsers.insert(AttribParserList::value_type("syntax", (ATTRIBUTE_PARSER)parseProgramSyntax));
+        mProgramAttribParsers.insert(AttribParserList::value_type("includes_skeletal_animation", (ATTRIBUTE_PARSER)parseProgramSkeletalAnimation));
+		mProgramAttribParsers.insert(AttribParserList::value_type("includes_morph_animation", (ATTRIBUTE_PARSER)parseProgramMorphAnimation));
+		mProgramAttribParsers.insert(AttribParserList::value_type("includes_pose_animation", (ATTRIBUTE_PARSER)parseProgramPoseAnimation));
+        mProgramAttribParsers.insert(AttribParserList::value_type("default_params", (ATTRIBUTE_PARSER)parseDefaultParams));
+		
+        // Set up program default param attribute parsers
+        mProgramDefaultParamAttribParsers.insert(AttribParserList::value_type("param_indexed", (ATTRIBUTE_PARSER)parseParamIndexed));
+        mProgramDefaultParamAttribParsers.insert(AttribParserList::value_type("param_indexed_auto", (ATTRIBUTE_PARSER)parseParamIndexedAuto));
+        mProgramDefaultParamAttribParsers.insert(AttribParserList::value_type("param_named", (ATTRIBUTE_PARSER)parseParamNamed));
+        mProgramDefaultParamAttribParsers.insert(AttribParserList::value_type("param_named_auto", (ATTRIBUTE_PARSER)parseParamNamedAuto));
+
+        mScriptContext.section = MSS_NONE;
+        mScriptContext.material.setNull();
+        mScriptContext.technique = 0;
+        mScriptContext.pass = 0;
+        mScriptContext.textureUnit = 0;
+        mScriptContext.program.setNull();
+        mScriptContext.lineNo = 0;
+        mScriptContext.filename = "";
+		mScriptContext.techLev = -1;
+		mScriptContext.passLev = -1;
+		mScriptContext.stateLev = -1;
+
+        mBuffer = "";
+    }
+
+    //-----------------------------------------------------------------------
+    void MaterialSerializer::parseScript(DataStreamPtr& stream, const String& groupName)
+    {
+        String line;
+        bool nextIsOpenBrace = false;
+
+        mScriptContext.section = MSS_NONE;
+        mScriptContext.material.setNull();
+        mScriptContext.technique = 0;
+        mScriptContext.pass = 0;
+        mScriptContext.textureUnit = 0;
+        mScriptContext.program.setNull();
+        mScriptContext.lineNo = 0;
+		mScriptContext.techLev = -1;
+		mScriptContext.passLev = -1;
+		mScriptContext.stateLev = -1;
+        mScriptContext.filename = stream->getName();
+		mScriptContext.groupName = groupName;
+        while(!stream->eof())
+        {
+            line = stream->getLine();
+            mScriptContext.lineNo++;
+            
+            // DEBUG LINE
+            // LogManager::getSingleton().logMessage("About to attempt line(#" + 
+            //    StringConverter::toString(mScriptContext.lineNo) + "): " + line);
+
+            // Ignore comments & blanks
+            if (!(line.length() == 0 || line.substr(0,2) == "//"))
+            {
+                if (nextIsOpenBrace)
+                {
+                    // NB, parser will have changed context already
+                    if (line != "{")
+                    {
+                        logParseError("Expecting '{' but got " +
+                            line + " instead.", mScriptContext);
+                    }
+                    nextIsOpenBrace = false;
+                }
+                else
+                {
+                    nextIsOpenBrace = parseScriptLine(line);
+                }
+
+            }
+        }
+
+        // Check all braces were closed
+        if (mScriptContext.section != MSS_NONE)
+        {
+            logParseError("Unexpected end of file.", mScriptContext);
+        }
+
+		// Make sure we invalidate our context shared pointer (don't wanna hold on)
+		mScriptContext.material.setNull();
+
+    }
+    //-----------------------------------------------------------------------
+    bool MaterialSerializer::parseScriptLine(String& line)
+    {
+        switch(mScriptContext.section)
+        {
+        case MSS_NONE:
+            if (line == "}")
+            {
+                logParseError("Unexpected terminating brace.", mScriptContext);
+                return false;
+            }
+            else
+            {
+                // find & invoke a parser
+                return invokeParser(line, mRootAttribParsers); 
+            }
+            break;
+        case MSS_MATERIAL:
+            if (line == "}")
+            {
+                // End of material
+                // if texture aliases were found, pass them to the material
+                // to update texture names used in Texture unit states
+                if (!mScriptContext.textureAliases.empty())
+                {
+                    // request material to update all texture names in TUS's
+                    // that use texture aliases in the list
+                    mScriptContext.material->applyTextureAliases(mScriptContext.textureAliases);
+                }
+
+                mScriptContext.section = MSS_NONE;
+                mScriptContext.material.setNull();
+				//Reset all levels for next material
+				mScriptContext.passLev = -1;
+				mScriptContext.stateLev= -1;
+				mScriptContext.techLev = -1;
+                mScriptContext.textureAliases.clear();
+            }
+            else
+            {
+                // find & invoke a parser
+                return invokeParser(line, mMaterialAttribParsers); 
+            }
+            break;
+        case MSS_TECHNIQUE:
+            if (line == "}")
+            {
+                // End of technique
+                mScriptContext.section = MSS_MATERIAL;
+                mScriptContext.technique = NULL;
+				mScriptContext.passLev = -1;	//Reset pass level (yes, the pass level)
+            }
+            else
+            {
+                // find & invoke a parser
+                return invokeParser(line, mTechniqueAttribParsers); 
+            }
+            break;
+        case MSS_PASS:
+            if (line == "}")
+            {
+                // End of pass
+                mScriptContext.section = MSS_TECHNIQUE;
+                mScriptContext.pass = NULL;
+				mScriptContext.stateLev = -1;	//Reset state level (yes, the state level)
+            }
+            else
+            {
+                // find & invoke a parser
+                return invokeParser(line, mPassAttribParsers); 
+            }
+            break;
+        case MSS_TEXTUREUNIT:
+            if (line == "}")
+            {
+                // End of texture unit
+                mScriptContext.section = MSS_PASS;
+                mScriptContext.textureUnit = NULL;
+            }
+            else
+            {
+                // find & invoke a parser
+                return invokeParser(line, mTextureUnitAttribParsers); 
+            }
+            break;
+		case MSS_TEXTURESOURCE:
+			if( line == "}" )
+			{
+				//End texture source section
+				//Finish creating texture here
+				String sMaterialName = mScriptContext.material->getName();
+				if(	ExternalTextureSourceManager::getSingleton().getCurrentPlugIn() != 0)
+					ExternalTextureSourceManager::getSingleton().getCurrentPlugIn()->
+					createDefinedTexture( sMaterialName, mScriptContext.groupName );
+				//Revert back to texture unit
+				mScriptContext.section = MSS_TEXTUREUNIT;
+			}
+			else
+			{
+				// custom texture parameter, use original line
+				parseTextureCustomParameter(line, mScriptContext);
+			}
+			break;
+        case MSS_PROGRAM_REF:
+            if (line == "}")
+            {
+                // End of program
+                mScriptContext.section = MSS_PASS;
+                mScriptContext.program.setNull();
+            }
+            else
+            {
+                // find & invoke a parser
+                return invokeParser(line, mProgramRefAttribParsers); 
+            }
+            break;
+        case MSS_PROGRAM:
+			// Program definitions are slightly different, they are deferred
+			// until all the information required is known
+            if (line == "}")
+            {
+                // End of program
+				finishProgramDefinition();
+                mScriptContext.section = MSS_NONE;
+                delete mScriptContext.programDef;
+                mScriptContext.defaultParamLines.clear();
+                mScriptContext.programDef = NULL;
+            }
+            else
+            {
+                // find & invoke a parser
+				// do this manually because we want to call a custom
+				// routine when the parser is not found
+				// First, split line on first divisor only
+				StringVector splitCmd = StringUtil::split(line, " \t", 1);
+				// Find attribute parser
+				AttribParserList::iterator iparser = mProgramAttribParsers.find(splitCmd[0]);
+				if (iparser == mProgramAttribParsers.end())
+				{
+					// custom parameter, use original line
+					parseProgramCustomParameter(line, mScriptContext);
+				}
+				else
+				{
+                    String cmd = splitCmd.size() >= 2? splitCmd[1]:StringUtil::BLANK;
+					// Use parser with remainder
+                    return iparser->second(cmd, mScriptContext );
+				}
+				
+            }
+            break;
+        case MSS_DEFAULT_PARAMETERS:
+            if (line == "}")
+            {
+                // End of default parameters
+                mScriptContext.section = MSS_PROGRAM;
+            }
+            else
+            {
+                // Save default parameter lines up until we finalise the program
+                mScriptContext.defaultParamLines.push_back(line);
+            }
+
+
+            break;
+        };
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+	void MaterialSerializer::finishProgramDefinition(void)
+	{
+		// Now it is time to create the program and propagate the parameters
+		MaterialScriptProgramDefinition* def = mScriptContext.programDef;
+        GpuProgramPtr gp;
+		if (def->language == "asm")
+		{
+			// Native assembler
+			// Validate
+			if (def->source.empty())
+			{
+				logParseError("Invalid program definition for " + def->name +
+					", you must specify a source file.", mScriptContext);
+			}
+			if (def->syntax.empty())
+			{
+				logParseError("Invalid program definition for " + def->name +
+					", you must specify a syntax code.", mScriptContext);
+			}
+			// Create
+			gp = GpuProgramManager::getSingleton().
+				createProgram(def->name, mScriptContext.groupName, def->source, 
+                    def->progType, def->syntax);
+
+		}
+		else
+		{
+			// High-level program
+			// Validate
+			if (def->source.empty())
+			{
+				logParseError("Invalid program definition for " + def->name +
+					", you must specify a source file.", mScriptContext);
+			}
+			// Create
+            try 
+            {
+			    HighLevelGpuProgramPtr hgp = HighLevelGpuProgramManager::getSingleton().
+				    createProgram(def->name, mScriptContext.groupName, 
+                        def->language, def->progType);
+                // Assign to generalised version
+                gp = hgp;
+                // Set source file
+                hgp->setSourceFile(def->source);
+
+			    // Set custom parameters
+			    std::map<String, String>::const_iterator i, iend;
+			    iend = def->customParameters.end();
+			    for (i = def->customParameters.begin(); i != iend; ++i)
+			    {
+				    if (!hgp->setParameter(i->first, i->second))
+				    {
+					    logParseError("Error in program " + def->name + 
+						    " parameter " + i->first + " is not valid.", mScriptContext);
+				    }
+			    }
+            }
+            catch (Exception& e)
+            {
+                logParseError("Could not create GPU program '"
+                    + def->name + "', error reported was: " + e.getFullDescription(), mScriptContext);
+				mScriptContext.program.setNull();
+            	mScriptContext.programParams.setNull();
+				return;
+            }
+        }
+        // Set skeletal animation option
+        gp->setSkeletalAnimationIncluded(def->supportsSkeletalAnimation);
+		// Set morph animation option
+		gp->setMorphAnimationIncluded(def->supportsMorphAnimation);
+		// Set pose animation option
+		gp->setPoseAnimationIncluded(def->supportsPoseAnimation);
+		// set origin
+		gp->_notifyOrigin(mScriptContext.filename);
+
+        // Set up to receive default parameters
+        if (gp->isSupported() 
+            && !mScriptContext.defaultParamLines.empty())
+        {
+            mScriptContext.programParams = gp->getDefaultParameters();
+			mScriptContext.numAnimationParametrics = 0;
+            mScriptContext.program = gp;
+            StringVector::iterator i, iend;
+            iend = mScriptContext.defaultParamLines.end();
+            for (i = mScriptContext.defaultParamLines.begin();
+                i != iend; ++i)
+            {
+                // find & invoke a parser
+                // do this manually because we want to call a custom
+                // routine when the parser is not found
+                // First, split line on first divisor only
+                StringVector splitCmd = StringUtil::split(*i, " \t", 1);
+                // Find attribute parser
+                AttribParserList::iterator iparser 
+                    = mProgramDefaultParamAttribParsers.find(splitCmd[0]);
+                if (iparser != mProgramDefaultParamAttribParsers.end())
+                {
+                    String cmd = splitCmd.size() >= 2? splitCmd[1]:StringUtil::BLANK;
+                    // Use parser with remainder
+                    iparser->second(cmd, mScriptContext );
+                }
+
+            }
+            // Reset
+            mScriptContext.program.setNull();
+            mScriptContext.programParams.setNull();
+        }
+
+	}
+    //-----------------------------------------------------------------------
+	bool MaterialSerializer::invokeParser(String& line, AttribParserList& parsers)
+    {
+        // First, split line on first divisor only
+        StringVector splitCmd(StringUtil::split(line, " \t", 1));
+
+        // Find attribute parser
+        AttribParserList::iterator iparser = parsers.find(splitCmd[0]);
+        if (iparser == parsers.end())
+        {
+            // BAD command. BAD!
+            logParseError("Unrecognised command: " + splitCmd[0], mScriptContext);
+            return false;
+        }
+        else
+        {
+            String cmd;
+            if(splitCmd.size() >= 2)
+                cmd = splitCmd[1];
+            // Use parser, make sure we have 2 params before using splitCmd[1]
+            return iparser->second( cmd, mScriptContext );
+        }
+    }
+    //-----------------------------------------------------------------------
+    void MaterialSerializer::exportMaterial(const MaterialPtr& pMat, const String &fileName, bool exportDefaults,
+        const bool includeProgDef, const String& programFilename)
+    {
+        clearQueue();
+        mDefaults = exportDefaults;
+        writeMaterial(pMat);
+        exportQueued(fileName, includeProgDef, programFilename);
+    }
+    //-----------------------------------------------------------------------
+    void MaterialSerializer::exportQueued(const String &fileName, const bool includeProgDef, const String& programFilename)
+    {
+        // write out gpu program definitions to the buffer
+        writeGpuPrograms();
+
+        if (mBuffer == "")
+            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Queue is empty !", "MaterialSerializer::exportQueued");
+
+        LogManager::getSingleton().logMessage("MaterialSerializer : writing material(s) to material script : " + fileName, LML_CRITICAL);
+        FILE *fp;
+        fp = fopen(fileName.c_str(), "w");
+        if (!fp)
+            OGRE_EXCEPT(Exception::ERR_CANNOT_WRITE_TO_FILE, "Cannot create material file.",
+            "MaterialSerializer::export");
+
+        // output gpu program definitions to material script file if includeProgDef is true
+        if (includeProgDef && !mGpuProgramBuffer.empty())
+        {
+            fputs(mGpuProgramBuffer.c_str(), fp);
+        }
+
+        // output main buffer holding material script
+        fputs(mBuffer.c_str(), fp);
+        fclose(fp);
+
+        // write program script if program filename and program definitions
+        // were not included in material script
+        if (!includeProgDef && !mGpuProgramBuffer.empty() && !programFilename.empty())
+        {
+            FILE *fp;
+            fp = fopen(programFilename.c_str(), "w");
+            if (!fp)
+                OGRE_EXCEPT(Exception::ERR_CANNOT_WRITE_TO_FILE, "Cannot create program material file.",
+                "MaterialSerializer::export");
+            fputs(mGpuProgramBuffer.c_str(), fp);
+            fclose(fp);
+        }
+
+        LogManager::getSingleton().logMessage("MaterialSerializer : done.", LML_CRITICAL);
+        clearQueue();
+    }
+    //-----------------------------------------------------------------------
+    void MaterialSerializer::queueForExport(const MaterialPtr& pMat, 
+		bool clearQueued, bool exportDefaults)
+    {
+        if (clearQueued)
+            clearQueue();
+
+        mDefaults = exportDefaults;
+        writeMaterial(pMat);
+    }
+    //-----------------------------------------------------------------------
+    void MaterialSerializer::clearQueue()
+    {
+        mBuffer = "";
+        mGpuProgramBuffer = "";
+        mGpuProgramDefinitionContainer.clear();
+    }
+    //-----------------------------------------------------------------------
+    const String &MaterialSerializer::getQueuedAsString() const
+    {
+        return mBuffer;
+    }
+    //-----------------------------------------------------------------------
+    void MaterialSerializer::writeMaterial(const MaterialPtr& pMat)
+    {
+        LogManager::getSingleton().logMessage("MaterialSerializer : writing material " + pMat->getName() + " to queue.", LML_CRITICAL);
+        // Material name
+        writeAttribute(0, "material " + pMat->getName());
+        beginSection(0);
+        {
+            // Write LOD information
+            Material::LodDistanceIterator distIt = pMat->getLodDistanceIterator();
+            // Skip zero value
+            if (distIt.hasMoreElements())
+                distIt.getNext();
+            String attributeVal;
+            while (distIt.hasMoreElements())
+            {
+                Real sqdist = distIt.getNext();
+                attributeVal.append(StringConverter::toString(Math::Sqrt(sqdist)));
+                if (distIt.hasMoreElements())
+                    attributeVal.append(" ");
+            }
+            if (!attributeVal.empty())
+            {
+                writeAttribute(1, "lod_distances");
+                writeValue(attributeVal);
+            }
+
+
+            // Shadow receive
+            if (mDefaults || 
+                pMat->getReceiveShadows() != true)
+            {
+                writeAttribute(1, "receive_shadows");
+                writeValue(pMat->getReceiveShadows() ? "on" : "off");
+            }
+
+			// When rendering shadows, treat transparent things as opaque?
+			if (mDefaults || 
+				pMat->getTransparencyCastsShadows() == true)
+			{
+				writeAttribute(1, "transparency_casts_shadows");
+				writeValue(pMat->getTransparencyCastsShadows() ? "on" : "off");
+			}
+
+            // Iterate over techniques
+            Material::TechniqueIterator it = pMat->getTechniqueIterator();
+            while (it.hasMoreElements())
+            {
+                writeTechnique(it.getNext());
+                mBuffer += "\n";
+            }
+        }
+        endSection(0);
+        mBuffer += "\n";
+    }
+    //-----------------------------------------------------------------------
+    void MaterialSerializer::writeTechnique(const Technique* pTech)
+    {
+        // Technique header
+        writeAttribute(1, "technique");
+        // only output technique name if it exists.
+        if (!pTech->getName().empty())
+            writeValue(pTech->getName());
+
+        beginSection(1);
+        {
+			// Lod index
+			if (mDefaults || 
+				pTech->getLodIndex() != 0)
+			{
+				writeAttribute(2, "lod_index");
+				writeValue(StringConverter::toString(pTech->getLodIndex()));
+			}
+
+			// Scheme name
+			if (mDefaults || 
+				pTech->getSchemeName() != MaterialManager::DEFAULT_SCHEME_NAME)
+			{
+				writeAttribute(2, "scheme");
+				writeValue(pTech->getSchemeName());
+			}
+
+            // Iterate over passes
+            Technique::PassIterator it = const_cast<Technique*>(pTech)->getPassIterator();
+            while (it.hasMoreElements())
+            {
+                writePass(it.getNext());
+                mBuffer += "\n";
+            }
+        }
+        endSection(1);
+
+    }
+    //-----------------------------------------------------------------------
+    void MaterialSerializer::writePass(const Pass* pPass)
+    {
+        writeAttribute(2, "pass");
+        // only output pass name if its not the default name
+        if (pPass->getName() != StringConverter::toString(pPass->getIndex()))
+            writeValue(pPass->getName());
+
+        beginSection(2);
+        {
+            //lighting
+            if (mDefaults || 
+                pPass->getLightingEnabled() != true)
+            {
+                writeAttribute(3, "lighting");
+                writeValue(pPass->getLightingEnabled() ? "on" : "off");
+            }
+			// max_lights
+            if (mDefaults || 
+                pPass->getMaxSimultaneousLights() != OGRE_MAX_SIMULTANEOUS_LIGHTS)
+            {
+                writeAttribute(3, "max_lights");
+                writeValue(StringConverter::toString(pPass->getMaxSimultaneousLights()));
+            }
+			// iteration
+            if (mDefaults || 
+                pPass->getIteratePerLight() || (pPass->getPassIterationCount() > 0))
+            {
+                writeAttribute(3, "iteration");
+                // pass iteration count
+                if (pPass->getPassIterationCount() > 0)
+                {
+                    writeValue(StringConverter::toString(pPass->getPassIterationCount()));
+                    if (pPass->getIteratePerLight())
+                        writeValue("per_light");
+                }
+                else
+                {
+                    writeValue(pPass->getIteratePerLight() ? "once_per_light" : "once");
+                }
+
+                if (pPass->getIteratePerLight() && pPass->getRunOnlyForOneLightType())
+                {
+                    switch (pPass->getOnlyLightType())
+                    {
+                    case Light::LT_DIRECTIONAL:
+                        writeValue("directional");
+                        break;
+                    case Light::LT_POINT:
+                        writeValue("point");
+                        break;
+                    case Light::LT_SPOTLIGHT:
+                        writeValue("spot");
+                        break;
+                    };
+                }
+            }
+			
+
+            if (pPass->getLightingEnabled())
+            {
+                // Ambient
+                if (mDefaults ||
+                    pPass->getAmbient().r != 1 ||
+                    pPass->getAmbient().g != 1 ||
+                    pPass->getAmbient().b != 1 ||
+                    pPass->getAmbient().a != 1 ||
+                    (pPass->getVertexColourTracking() & TVC_AMBIENT))
+                {
+                    writeAttribute(3, "ambient");
+                    if (pPass->getVertexColourTracking() & TVC_AMBIENT)
+                        writeValue("vertexcolour");
+                    else
+                        writeColourValue(pPass->getAmbient(), true);
+                }
+
+                // Diffuse
+                if (mDefaults ||
+                    pPass->getDiffuse().r != 1 ||
+                    pPass->getDiffuse().g != 1 ||
+                    pPass->getDiffuse().b != 1 ||
+                    pPass->getDiffuse().a != 1 ||
+                    (pPass->getVertexColourTracking() & TVC_DIFFUSE))
+                {
+                    writeAttribute(3, "diffuse");
+                    if (pPass->getVertexColourTracking() & TVC_DIFFUSE)
+                        writeValue("vertexcolour");
+                    else
+                        writeColourValue(pPass->getDiffuse(), true);
+                }
+
+                // Specular
+                if (mDefaults ||
+                    pPass->getSpecular().r != 0 ||
+                    pPass->getSpecular().g != 0 ||
+                    pPass->getSpecular().b != 0 ||
+                    pPass->getSpecular().a != 1 ||
+                    pPass->getShininess() != 0 ||
+                    (pPass->getVertexColourTracking() & TVC_SPECULAR))
+                {
+                    writeAttribute(3, "specular");
+                    if (pPass->getVertexColourTracking() & TVC_SPECULAR)
+                    {
+                        writeValue("vertexcolour");
+                    }
+                    else
+                    {
+                        writeColourValue(pPass->getSpecular(), true);
+                    }
+                    writeValue(StringConverter::toString(pPass->getShininess()));
+
+                }
+
+                // Emissive
+                if (mDefaults ||
+                    pPass->getSelfIllumination().r != 0 ||
+                    pPass->getSelfIllumination().g != 0 ||
+                    pPass->getSelfIllumination().b != 0 ||
+                    pPass->getSelfIllumination().a != 1 ||
+                    (pPass->getVertexColourTracking() & TVC_EMISSIVE))
+                {
+                    writeAttribute(3, "emissive");
+                    if (pPass->getVertexColourTracking() & TVC_EMISSIVE)
+                        writeValue("vertexcolour");
+                    else
+                        writeColourValue(pPass->getSelfIllumination(), true);
+                }
+            }
+
+            // Point size
+            if (mDefaults ||
+                pPass->getPointSize() != 1.0)
+            {
+                writeAttribute(3, "point_size");
+                writeValue(StringConverter::toString(pPass->getPointSize()));
+            }
+
+            // Point sprites
+            if (mDefaults ||
+                pPass->getPointSpritesEnabled())
+            {
+                writeAttribute(3, "point_sprites");
+                writeValue(pPass->getPointSpritesEnabled() ? "on" : "off");
+            }
+
+            // Point attenuation
+            if (mDefaults ||
+                pPass->isPointAttenuationEnabled())
+            {
+                writeAttribute(3, "point_size_attenuation");
+                writeValue(pPass->isPointAttenuationEnabled() ? "on" : "off");
+                if (pPass->isPointAttenuationEnabled() &&
+                    (pPass->getPointAttenuationConstant() != 0.0 ||
+                     pPass->getPointAttenuationLinear() != 1.0 ||
+                     pPass->getPointAttenuationQuadratic() != 0.0))
+                {
+                    writeValue(StringConverter::toString(pPass->getPointAttenuationConstant()));
+                    writeValue(StringConverter::toString(pPass->getPointAttenuationLinear()));
+                    writeValue(StringConverter::toString(pPass->getPointAttenuationQuadratic()));
+                }
+            }
+
+            // Point min size
+            if (mDefaults ||
+                pPass->getPointMinSize() != 0.0)
+            {
+                writeAttribute(3, "point_size_min");
+                writeValue(StringConverter::toString(pPass->getPointMinSize()));
+            }
+
+            // Point max size
+            if (mDefaults ||
+                pPass->getPointMaxSize() != 0.0)
+            {
+                writeAttribute(3, "point_size_max");
+                writeValue(StringConverter::toString(pPass->getPointMaxSize()));
+            }
+
+            // scene blend factor
+            if (mDefaults || 
+                pPass->getSourceBlendFactor() != SBF_ONE || 
+                pPass->getDestBlendFactor() != SBF_ZERO)
+            {
+                writeAttribute(3, "scene_blend");
+                writeSceneBlendFactor(pPass->getSourceBlendFactor(), pPass->getDestBlendFactor());
+            }
+
+
+            //depth check
+            if (mDefaults || 
+                pPass->getDepthCheckEnabled() != true)
+            {
+                writeAttribute(3, "depth_check");
+                writeValue(pPass->getDepthCheckEnabled() ? "on" : "off");
+            }
+			// alpha_rejection
+			if (mDefaults || 
+				pPass->getAlphaRejectFunction() != CMPF_ALWAYS_PASS ||
+				pPass->getAlphaRejectValue() != 0)
+			{
+				writeAttribute(3, "alpha_rejection");
+				writeCompareFunction(pPass->getAlphaRejectFunction());
+				writeValue(StringConverter::toString(pPass->getAlphaRejectValue()));
+			}
+
+
+            //depth write
+            if (mDefaults || 
+                pPass->getDepthWriteEnabled() != true)
+            {
+                writeAttribute(3, "depth_write");
+                writeValue(pPass->getDepthWriteEnabled() ? "on" : "off");
+            }
+
+            //depth function
+            if (mDefaults || 
+                pPass->getDepthFunction() != CMPF_LESS_EQUAL)
+            {
+                writeAttribute(3, "depth_func");
+                writeCompareFunction(pPass->getDepthFunction());
+            }
+
+            //depth bias
+            if (mDefaults || 
+                pPass->getDepthBias() != 0)
+            {
+                writeAttribute(3, "depth_bias");
+                writeValue(StringConverter::toString(pPass->getDepthBias()));
+            }
+
+            // hardware culling mode
+            if (mDefaults || 
+                pPass->getCullingMode() != CULL_CLOCKWISE)
+            {
+                CullingMode hcm = pPass->getCullingMode();
+                writeAttribute(3, "cull_hardware");
+                switch (hcm)
+                {
+                case CULL_NONE :
+                    writeValue("none");
+                    break;
+                case CULL_CLOCKWISE :
+                    writeValue("clockwise");
+                    break;
+                case CULL_ANTICLOCKWISE :
+                    writeValue("anticlockwise");
+                    break;
+                }
+            }
+
+            // software culling mode
+            if (mDefaults || 
+                pPass->getManualCullingMode() != MANUAL_CULL_BACK)
+            {
+                ManualCullingMode scm = pPass->getManualCullingMode();
+                writeAttribute(3, "cull_software");
+                switch (scm)
+                {
+                case MANUAL_CULL_NONE :
+                    writeValue("none");
+                    break;
+                case MANUAL_CULL_BACK :
+                    writeValue("back");
+                    break;
+                case MANUAL_CULL_FRONT :
+                    writeValue("front");
+                    break;
+                }
+            }
+
+            //shading
+            if (mDefaults || 
+                pPass->getShadingMode() != SO_GOURAUD)
+            {
+                writeAttribute(3, "shading");
+                switch (pPass->getShadingMode())
+                {
+                case SO_FLAT:
+                    writeValue("flat");
+                    break;
+                case SO_GOURAUD:
+                    writeValue("gouraud");
+                    break;
+                case SO_PHONG:
+                    writeValue("phong");
+                    break;
+                }
+            }
+
+
+			if (mDefaults || 
+				pPass->getPolygonMode() != PM_SOLID)
+			{
+				writeAttribute(3, "polygon_mode");
+				switch (pPass->getPolygonMode())
+				{
+				case PM_POINTS:
+					writeValue("points");
+					break;
+				case PM_WIREFRAME:
+					writeValue("wireframe");
+					break;
+				case PM_SOLID:
+					writeValue("solid");
+					break;
+				}
+			}
+
+            //fog override
+            if (mDefaults || 
+                pPass->getFogOverride() != false)
+            {
+                writeAttribute(3, "fog_override");
+                writeValue(pPass->getFogOverride() ? "true" : "false");
+                if (pPass->getFogOverride())
+                {
+                    switch (pPass->getFogMode())
+                    {
+                    case FOG_NONE:
+                        writeValue("none");
+                        break;
+                    case FOG_LINEAR:
+                        writeValue("linear");
+                        break;
+                    case FOG_EXP2:
+                        writeValue("exp2");
+                        break;
+                    case FOG_EXP:
+                        writeValue("exp");
+                        break;
+                    }
+
+                    if (pPass->getFogMode() != FOG_NONE)
+                    {
+                        writeColourValue(pPass->getFogColour());
+                        writeValue(StringConverter::toString(pPass->getFogDensity()));
+                        writeValue(StringConverter::toString(pPass->getFogStart()));
+                        writeValue(StringConverter::toString(pPass->getFogEnd()));
+                    }
+                }
+            }
+
+            // nfz
+
+            //  GPU Vertex and Fragment program references and parameters
+            if (pPass->hasVertexProgram())
+            {
+                writeVertexProgramRef(pPass);
+            }
+
+            if (pPass->hasFragmentProgram())
+            {
+                writeFragmentProgramRef(pPass);
+            }
+
+            if (pPass->hasShadowCasterVertexProgram())
+            {
+                writeShadowCasterVertexProgramRef(pPass);
+            }
+
+            if (pPass->hasShadowReceiverVertexProgram())
+            {
+                writeShadowReceiverVertexProgramRef(pPass);
+            }
+
+            if (pPass->hasShadowReceiverFragmentProgram())
+            {
+                writeShadowReceiverFragmentProgramRef(pPass);
+            }
+
+            // Nested texture layers
+            Pass::TextureUnitStateIterator it = const_cast<Pass*>(pPass)->getTextureUnitStateIterator();
+            while(it.hasMoreElements())
+            {
+                writeTextureUnit(it.getNext());
+            }
+        }
+        endSection(2);
+        LogManager::getSingleton().logMessage("MaterialSerializer : done.", LML_CRITICAL);
+    }
+    //-----------------------------------------------------------------------
+    String MaterialSerializer::convertFiltering(FilterOptions fo)
+    {
+        switch (fo)
+        {
+        case FO_NONE:
+            return "none";
+        case FO_POINT:
+            return "point";
+        case FO_LINEAR:
+            return "linear";
+        case FO_ANISOTROPIC:
+            return "anisotropic";
+        }
+
+        return "point";
+    }
+    //-----------------------------------------------------------------------
+    String convertTexAddressMode(TextureUnitState::TextureAddressingMode tam)
+	{
+        switch (tam)
+        {
+        case TextureUnitState::TAM_BORDER:
+            return "border";
+        case TextureUnitState::TAM_CLAMP:
+            return "clamp";
+        case TextureUnitState::TAM_MIRROR:
+            return "mirror";
+        case TextureUnitState::TAM_WRAP:
+            return "wrap";
+        }
+
+        return "wrap";
+	}
+    //-----------------------------------------------------------------------
+    void MaterialSerializer::writeTextureUnit(const TextureUnitState *pTex)
+    {
+        LogManager::getSingleton().logMessage("MaterialSerializer : parsing texture layer.", LML_CRITICAL);
+        mBuffer += "\n";
+        writeAttribute(3, "texture_unit");
+        // only write out name if its not equal to the default name
+        if (pTex->getName() != StringConverter::toString(pTex->getParent()->getTextureUnitStateIndex(pTex)))
+            writeValue(pTex->getName());
+
+        beginSection(3);
+        {
+            // texture_alias
+            if (!pTex->getTextureNameAlias().empty())
+            {
+                writeAttribute(4, "texture_alias");
+                writeValue(pTex->getTextureNameAlias());
+            }
+
+            //texture name
+            if (pTex->getNumFrames() == 1 && pTex->getTextureName() != "" && !pTex->isCubic())
+            {
+                writeAttribute(4, "texture");
+                writeValue(pTex->getTextureName());
+
+                switch (pTex->getTextureType())
+                {
+                case TEX_TYPE_1D:
+                    writeValue("1d");
+                    break;
+                case TEX_TYPE_2D:
+                    // nothing, this is the default
+                    break;
+                case TEX_TYPE_3D:
+                    writeValue("3d");
+                    break;
+                case TEX_TYPE_CUBE_MAP:
+                    // nothing, deal with this as cubic_texture since it copes with all variants
+                    break;
+                default:
+                    break;
+                };
+            }
+
+            //anim. texture
+            if (pTex->getNumFrames() > 1 && !pTex->isCubic())
+            {
+                writeAttribute(4, "anim_texture");
+                for (unsigned int n = 0; n < pTex->getNumFrames(); n++)
+                    writeValue(pTex->getFrameTextureName(n));
+                writeValue(StringConverter::toString(pTex->getAnimationDuration()));
+            }
+
+            //cubic texture
+            if (pTex->isCubic())
+            {
+                writeAttribute(4, "cubic_texture");
+                for (unsigned int n = 0; n < pTex->getNumFrames(); n++)
+                    writeValue(pTex->getFrameTextureName(n));
+
+                //combinedUVW/separateUW
+                if (pTex->getTextureType() == TEX_TYPE_CUBE_MAP)
+                    writeValue("combinedUVW");
+                else
+                    writeValue("separateUV");
+            }
+
+            //anisotropy level
+            if (mDefaults || 
+                pTex->getTextureAnisotropy() != 1)
+            {
+                writeAttribute(4, "max_anisotropy");
+                writeValue(StringConverter::toString(pTex->getTextureAnisotropy()));
+            }
+
+            //texture coordinate set
+            if (mDefaults || 
+                pTex->getTextureCoordSet() != 0)
+            {
+                writeAttribute(4, "tex_coord_set");
+                writeValue(StringConverter::toString(pTex->getTextureCoordSet()));
+            }
+
+            //addressing mode
+			const TextureUnitState::UVWAddressingMode& uvw = 
+				pTex->getTextureAddressingMode();
+            if (mDefaults || 
+                uvw.u != Ogre::TextureUnitState::TAM_WRAP ||
+				uvw.v != Ogre::TextureUnitState::TAM_WRAP ||
+				uvw.w != Ogre::TextureUnitState::TAM_WRAP )
+            {
+                writeAttribute(4, "tex_address_mode");
+                if (uvw.u == uvw.v && uvw.u == uvw.w)
+                {
+                    writeValue(convertTexAddressMode(uvw.u));
+                }
+                else
+                {
+                    writeValue(convertTexAddressMode(uvw.u));
+                    writeValue(convertTexAddressMode(uvw.v));
+                    if (uvw.w != TextureUnitState::TAM_WRAP)
+                    {
+                        writeValue(convertTexAddressMode(uvw.w));
+                    }
+                }
+            }
+
+            //border colour
+            const ColourValue& borderColour =
+                pTex->getTextureBorderColour();
+            if (mDefaults ||
+                borderColour != ColourValue::Black)
+            {
+                writeAttribute(4, "tex_border_colour");
+                writeColourValue(borderColour, true);
+            }
+
+            //filtering
+            if (mDefaults || 
+                pTex->getTextureFiltering(FT_MIN) != FO_LINEAR ||
+                pTex->getTextureFiltering(FT_MAG) != FO_LINEAR ||
+                pTex->getTextureFiltering(FT_MIP) != FO_POINT)
+            {
+                writeAttribute(4, "filtering");
+                writeValue(
+                    convertFiltering(pTex->getTextureFiltering(FT_MIN))
+                    + " "
+                    + convertFiltering(pTex->getTextureFiltering(FT_MAG))
+                    + " "
+                    + convertFiltering(pTex->getTextureFiltering(FT_MIP)));
+            }
+
+            // colour_op_ex
+            if (mDefaults || 
+                pTex->getColourBlendMode().operation != LBX_MODULATE ||
+                pTex->getColourBlendMode().source1 != LBS_TEXTURE ||
+                pTex->getColourBlendMode().source2 != LBS_CURRENT)
+            {
+                writeAttribute(4, "colour_op_ex");
+                writeLayerBlendOperationEx(pTex->getColourBlendMode().operation);
+                writeLayerBlendSource(pTex->getColourBlendMode().source1);
+                writeLayerBlendSource(pTex->getColourBlendMode().source2);
+                if (pTex->getColourBlendMode().operation == LBX_BLEND_MANUAL)
+                    writeValue(StringConverter::toString(pTex->getColourBlendMode().factor));
+                if (pTex->getColourBlendMode().source1 == LBS_MANUAL)
+                    writeColourValue(pTex->getColourBlendMode().colourArg1, false);
+                if (pTex->getColourBlendMode().source2 == LBS_MANUAL)
+                    writeColourValue(pTex->getColourBlendMode().colourArg2, false);
+
+                //colour_op_multipass_fallback
+                writeAttribute(4, "colour_op_multipass_fallback");
+                writeSceneBlendFactor(pTex->getColourBlendFallbackSrc());
+                writeSceneBlendFactor(pTex->getColourBlendFallbackDest());
+            }
+
+            // alpha_op_ex
+            if (mDefaults || 
+                pTex->getAlphaBlendMode().operation != LBX_MODULATE ||
+                pTex->getAlphaBlendMode().source1 != LBS_TEXTURE ||
+                pTex->getAlphaBlendMode().source2 != LBS_CURRENT)
+            {
+                writeAttribute(4, "alpha_op_ex");
+                writeLayerBlendOperationEx(pTex->getAlphaBlendMode().operation);
+                writeLayerBlendSource(pTex->getAlphaBlendMode().source1);
+                writeLayerBlendSource(pTex->getAlphaBlendMode().source2);
+                if (pTex->getAlphaBlendMode().operation == LBX_BLEND_MANUAL)
+                    writeValue(StringConverter::toString(pTex->getAlphaBlendMode().factor));
+                else if (pTex->getAlphaBlendMode().source1 == LBS_MANUAL)
+                    writeValue(StringConverter::toString(pTex->getAlphaBlendMode().alphaArg1));
+                else if (pTex->getAlphaBlendMode().source2 == LBS_MANUAL)
+                    writeValue(StringConverter::toString(pTex->getAlphaBlendMode().alphaArg2));
+            }
+
+			bool individualTransformElems = false;
+            // rotate
+            if (mDefaults ||
+                pTex->getTextureRotate() != Radian(0))
+            {
+                writeAttribute(4, "rotate");
+                writeValue(StringConverter::toString(pTex->getTextureRotate().valueDegrees()));
+				individualTransformElems = true;
+            }
+
+            // scroll
+            if (mDefaults ||
+                pTex->getTextureUScroll() != 0 || 
+                pTex->getTextureVScroll() != 0 )
+            {
+                writeAttribute(4, "scroll");
+                writeValue(StringConverter::toString(pTex->getTextureUScroll()));
+                writeValue(StringConverter::toString(pTex->getTextureVScroll()));
+				individualTransformElems = true;
+            }
+            // scale
+            if (mDefaults ||
+                pTex->getTextureUScale() != 1.0 || 
+                pTex->getTextureVScale() != 1.0 )
+            {
+                writeAttribute(4, "scale");
+                writeValue(StringConverter::toString(pTex->getTextureUScale()));
+                writeValue(StringConverter::toString(pTex->getTextureVScale()));
+				individualTransformElems = true;
+            }
+
+			// free transform
+			if (!individualTransformElems && 
+				(mDefaults ||
+				pTex->getTextureTransform() != Matrix4::IDENTITY))
+			{
+				writeAttribute(4, "transform");
+				const Matrix4& xform = pTex->getTextureTransform();
+				for (int row = 0; row < 4; ++row)
+				{
+					for (int col = 0; col < 4; ++col)
+					{
+						writeValue(StringConverter::toString(xform[row][col]));
+					}
+				}
+			}
+
+			// Used to store the u and v speeds of scroll animation effects
+			float scrollAnimU = 0;
+			float scrollAnimV = 0;
+
+            EffectMap m_ef = pTex->getEffects();
+            if (!m_ef.empty())
+            {
+                EffectMap::const_iterator it;
+                for (it = m_ef.begin(); it != m_ef.end(); ++it)
+                {
+                    const TextureUnitState::TextureEffect& ef = it->second;
+                    switch (ef.type)
+                    {
+                    case TextureUnitState::ET_ENVIRONMENT_MAP :
+                        writeEnvironmentMapEffect(ef, pTex);
+                        break;
+                    case TextureUnitState::ET_ROTATE :
+                        writeRotationEffect(ef, pTex);
+                        break;
+					case TextureUnitState::ET_UVSCROLL :
+						scrollAnimU = scrollAnimV = ef.arg1;
+						break;
+                    case TextureUnitState::ET_USCROLL :
+						scrollAnimU = ef.arg1;
+						break;
+					case TextureUnitState::ET_VSCROLL :
+						scrollAnimV = ef.arg1;                        
+                        break;
+                    case TextureUnitState::ET_TRANSFORM :
+                        writeTransformEffect(ef, pTex);
+                        break;
+                    default:
+                        break;
+                    }
+                }
+            }
+			
+			// u and v scroll animation speeds merged, if present serialize scroll_anim
+			if(scrollAnimU || scrollAnimV) {
+				TextureUnitState::TextureEffect texEffect;
+				texEffect.arg1 = scrollAnimU;
+				texEffect.arg2 = scrollAnimV;
+				writeScrollEffect(texEffect, pTex);
+			}
+        }
+        endSection(3);
+
+    }
+    //-----------------------------------------------------------------------
+    void MaterialSerializer::writeEnvironmentMapEffect(const TextureUnitState::TextureEffect& effect, const TextureUnitState *pTex)
+    {
+        writeAttribute(4, "env_map");
+        switch (effect.subtype)
+        {
+        case TextureUnitState::ENV_PLANAR:
+            writeValue("planar");
+            break;
+        case TextureUnitState::ENV_CURVED:
+            writeValue("spherical");
+            break;
+        case TextureUnitState::ENV_NORMAL:
+            writeValue("cubic_normal");
+            break;
+        case TextureUnitState::ENV_REFLECTION:
+            writeValue("cubic_reflection");
+            break;
+        }
+    }
+    //-----------------------------------------------------------------------
+    void MaterialSerializer::writeRotationEffect(const TextureUnitState::TextureEffect& effect, const TextureUnitState *pTex)
+    {
+        if (effect.arg1)
+        {
+            writeAttribute(4, "rotate_anim");
+            writeValue(StringConverter::toString(effect.arg1));
+        }
+    }
+    //-----------------------------------------------------------------------
+    void MaterialSerializer::writeTransformEffect(const TextureUnitState::TextureEffect& effect, const TextureUnitState *pTex)
+    {
+        writeAttribute(4, "wave_xform");
+
+        switch (effect.subtype)
+        {
+        case TextureUnitState::TT_ROTATE:
+            writeValue("rotate");
+            break;
+        case TextureUnitState::TT_SCALE_U:
+            writeValue("scale_x");
+            break;
+        case TextureUnitState::TT_SCALE_V:
+            writeValue("scale_y");
+            break;
+        case TextureUnitState::TT_TRANSLATE_U:
+            writeValue("scroll_x");
+            break;
+        case TextureUnitState::TT_TRANSLATE_V:
+            writeValue("scroll_y");
+            break;
+        }
+
+        switch (effect.waveType)
+        {
+        case WFT_INVERSE_SAWTOOTH:
+            writeValue("inverse_sawtooth");
+            break;
+        case WFT_SAWTOOTH:
+            writeValue("sawtooth");
+            break;
+        case WFT_SINE:
+            writeValue("sine");
+            break;
+        case WFT_SQUARE:
+            writeValue("square");
+            break;
+        case WFT_TRIANGLE:
+            writeValue("triangle");
+            break;
+        }
+
+        writeValue(StringConverter::toString(effect.base));
+        writeValue(StringConverter::toString(effect.frequency));
+        writeValue(StringConverter::toString(effect.phase));
+        writeValue(StringConverter::toString(effect.amplitude));
+    }
+    //-----------------------------------------------------------------------
+    void MaterialSerializer::writeScrollEffect(
+		const TextureUnitState::TextureEffect& effect, const TextureUnitState *pTex)
+    {
+        if (effect.arg1 || effect.arg2)
+        {
+            writeAttribute(4, "scroll_anim");
+            writeValue(StringConverter::toString(effect.arg1));
+            writeValue(StringConverter::toString(effect.arg2));
+        }
+    }
+    //-----------------------------------------------------------------------
+    void MaterialSerializer::writeSceneBlendFactor(const SceneBlendFactor sbf)
+    {
+        switch (sbf)
+        {
+        case SBF_DEST_ALPHA:
+            writeValue("dest_alpha");
+            break;
+        case SBF_DEST_COLOUR:
+            writeValue("dest_colour");
+            break;
+        case SBF_ONE:
+            writeValue("one");
+            break;
+        case SBF_ONE_MINUS_DEST_ALPHA:
+            writeValue("one_minus_dest_alpha");
+            break;
+        case SBF_ONE_MINUS_DEST_COLOUR:
+            writeValue("one_minus_dest_colour");
+            break;
+        case SBF_ONE_MINUS_SOURCE_ALPHA:
+            writeValue("one_minus_src_alpha");
+            break;
+        case SBF_ONE_MINUS_SOURCE_COLOUR:
+            writeValue("one_minus_src_colour");
+            break;
+        case SBF_SOURCE_ALPHA:
+            writeValue("src_alpha");
+            break;
+        case SBF_SOURCE_COLOUR:
+            writeValue("src_colour");
+            break;
+        case SBF_ZERO:
+            writeValue("zero");
+            break;
+        }
+    }
+    //-----------------------------------------------------------------------
+    void MaterialSerializer::writeSceneBlendFactor(const SceneBlendFactor sbf_src, const SceneBlendFactor sbf_dst)
+    {
+        if (sbf_src == SBF_ONE && sbf_dst == SBF_ONE )
+            writeValue("add");
+        else if (sbf_src == SBF_DEST_COLOUR && sbf_dst == SBF_ZERO)
+            writeValue("modulate");
+        else if (sbf_src == SBF_SOURCE_COLOUR && sbf_dst == SBF_ONE_MINUS_SOURCE_COLOUR)
+            writeValue("colour_blend");
+        else if (sbf_src == SBF_SOURCE_ALPHA && sbf_dst == SBF_ONE_MINUS_SOURCE_ALPHA)
+            writeValue("alpha_blend");
+        else
+        {
+            writeSceneBlendFactor(sbf_src);
+            writeSceneBlendFactor(sbf_dst);
+        }
+    }
+    //-----------------------------------------------------------------------
+    void MaterialSerializer::writeCompareFunction(const CompareFunction cf)
+    {
+        switch (cf)
+        {
+        case CMPF_ALWAYS_FAIL:
+            writeValue("always_fail");
+            break;
+        case CMPF_ALWAYS_PASS:
+            writeValue("always_pass");
+            break;
+        case CMPF_EQUAL:
+            writeValue("equal");
+            break;
+        case CMPF_GREATER:
+            writeValue("greater");
+            break;
+        case CMPF_GREATER_EQUAL:
+            writeValue("greater_equal");
+            break;
+        case CMPF_LESS:
+            writeValue("less");
+            break;
+        case CMPF_LESS_EQUAL:
+            writeValue("less_equal");
+            break;
+        case CMPF_NOT_EQUAL:
+            writeValue("not_equal");
+            break;
+        }
+    }
+    //-----------------------------------------------------------------------
+    void MaterialSerializer::writeColourValue(const ColourValue &colour, bool writeAlpha)
+    {
+        writeValue(StringConverter::toString(colour.r));
+        writeValue(StringConverter::toString(colour.g));
+        writeValue(StringConverter::toString(colour.b));
+        if (writeAlpha)
+            writeValue(StringConverter::toString(colour.a));
+    }
+    //-----------------------------------------------------------------------
+    void MaterialSerializer::writeLayerBlendOperationEx(const LayerBlendOperationEx op)
+    {
+        switch (op)
+        {
+        case LBX_ADD:
+            writeValue("add");
+            break;
+        case LBX_ADD_SIGNED:
+            writeValue("add_signed");
+            break;
+        case LBX_ADD_SMOOTH:
+            writeValue("add_smooth");
+            break;
+        case LBX_BLEND_CURRENT_ALPHA:
+            writeValue("blend_current_alpha");
+            break;
+        case LBX_BLEND_DIFFUSE_COLOUR:
+            writeValue("blend_diffuse_colour");
+            break;
+        case LBX_BLEND_DIFFUSE_ALPHA:
+            writeValue("blend_diffuse_alpha");
+            break;
+        case LBX_BLEND_MANUAL:
+            writeValue("blend_manual");
+            break;
+        case LBX_BLEND_TEXTURE_ALPHA:
+            writeValue("blend_texture_alpha");
+            break;
+        case LBX_MODULATE:
+            writeValue("modulate");
+            break;
+        case LBX_MODULATE_X2:
+            writeValue("modulate_x2");
+            break;
+        case LBX_MODULATE_X4:
+            writeValue("modulate_x4");
+            break;
+        case LBX_SOURCE1:
+            writeValue("source1");
+            break;
+        case LBX_SOURCE2:
+            writeValue("source2");
+            break;
+        case LBX_SUBTRACT:
+            writeValue("subtract");
+            break;
+        case LBX_DOTPRODUCT:
+            writeValue("dotproduct");
+            break;
+        }
+    }
+    //-----------------------------------------------------------------------
+    void MaterialSerializer::writeLayerBlendSource(const LayerBlendSource lbs)
+    {
+        switch (lbs)
+        {
+        case LBS_CURRENT:
+            writeValue("src_current");
+            break;
+        case LBS_DIFFUSE:
+            writeValue("src_diffuse");
+            break;
+        case LBS_MANUAL:
+            writeValue("src_manual");
+            break;
+        case LBS_SPECULAR:
+            writeValue("src_specular");
+            break;
+        case LBS_TEXTURE:
+            writeValue("src_texture");
+            break;
+        }
+    }
+
+    // nfz
+    //-----------------------------------------------------------------------
+    void MaterialSerializer::writeVertexProgramRef(const Pass* pPass)
+    {
+        writeGpuProgramRef("vertex_program_ref",
+            pPass->getVertexProgram(), pPass->getVertexProgramParameters());
+    }
+    //-----------------------------------------------------------------------
+    void MaterialSerializer::writeShadowCasterVertexProgramRef(const Pass* pPass)
+    {
+        writeGpuProgramRef("shadow_caster_vertex_program_ref",
+            pPass->getShadowCasterVertexProgram(), pPass->getShadowCasterVertexProgramParameters());
+    }
+    //-----------------------------------------------------------------------
+    void MaterialSerializer::writeShadowReceiverVertexProgramRef(const Pass* pPass)
+    {
+        writeGpuProgramRef("shadow_receiver_vertex_program_ref",
+            pPass->getShadowReceiverVertexProgram(), pPass->getShadowReceiverVertexProgramParameters());
+    }
+    //-----------------------------------------------------------------------
+    void MaterialSerializer::writeShadowReceiverFragmentProgramRef(const Pass* pPass)
+    {
+        writeGpuProgramRef("shadow_receiver_fragment_program_ref",
+            pPass->getShadowReceiverFragmentProgram(), pPass->getShadowReceiverFragmentProgramParameters());
+    }
+    //-----------------------------------------------------------------------
+    void MaterialSerializer::writeFragmentProgramRef(const Pass* pPass)
+    {
+        writeGpuProgramRef("fragment_program_ref",
+            pPass->getFragmentProgram(), pPass->getFragmentProgramParameters());
+    }
+    //-----------------------------------------------------------------------
+    void MaterialSerializer::writeGpuProgramRef(const String& attrib,
+        const GpuProgramPtr& program, const GpuProgramParametersSharedPtr& params)
+    {
+        mBuffer += "\n";
+        writeAttribute(3, attrib);
+        writeValue(program->getName());
+        beginSection(3);
+        {
+            // write out paramters
+            GpuProgramParameters* defaultParams= 0;
+            // does the GPU program have default parameters?
+            if (program->hasDefaultParameters())
+                defaultParams = program->getDefaultParameters().getPointer();
+
+            writeGPUProgramParameters(params, defaultParams);
+        }
+        endSection(3);
+
+        // add to GpuProgram contatiner
+        mGpuProgramDefinitionContainer.insert(program->getName());
+    }
+    //-----------------------------------------------------------------------
+    static bool isConstantRealValsEqual(const GpuProgramParameters::RealConstantEntry* constEntry,
+        const GpuProgramParameters::RealConstantEntry* defaultEntry, const size_t elementCount)
+    {
+        assert(constEntry && defaultEntry);
+        // assume values are equal
+        bool isEqual = false;
+
+        if (constEntry && defaultEntry)
+        {
+            // assume values are equal
+            isEqual = true;
+            size_t currentIndex = 0;
+            // iterate through real constants 
+            while ((currentIndex < elementCount) && isEqual)
+            {
+                // compare the values within the constant entry
+                size_t idx = 0;
+                while ((idx < 4) && (currentIndex < elementCount) && isEqual)
+                {
+                    if (constEntry->val[idx] != defaultEntry->val[idx])
+                        isEqual = false;
+                    ++idx;
+                    ++currentIndex;
+                }
+                ++constEntry;
+                ++defaultEntry;
+            }
+
+        }
+
+        return isEqual;
+    }
+
+    //-----------------------------------------------------------------------
+    static bool isConstantIntValsEqual(const GpuProgramParameters::IntConstantEntry* constEntry,
+        const GpuProgramParameters::IntConstantEntry* defaultEntry, const size_t elementCount)
+    {
+        assert(constEntry && defaultEntry);
+        // assume values are equal
+        bool isEqual = false;
+
+        if (constEntry && defaultEntry)
+        {
+            // assume values are equal
+            isEqual = true;
+            size_t currentIndex = 0;
+            // iterate through real constants 
+            while ((currentIndex < elementCount) && isEqual)
+            {
+                // compare the values within the constant entry
+                size_t idx = 0;
+                while ((idx < 4) && (currentIndex < elementCount) && isEqual)
+                {
+                    if (constEntry->val[idx] != defaultEntry->val[idx])
+                        isEqual = false;
+                    ++idx;
+                    ++currentIndex;
+                }
+                ++constEntry;
+                ++defaultEntry;
+            }
+
+        }
+
+        return isEqual;
+    }
+
+
+    //-----------------------------------------------------------------------
+    void MaterialSerializer::writeGPUProgramParameters(
+		const GpuProgramParametersSharedPtr& params, 
+		GpuProgramParameters* defaultParams, const int level, 
+		const bool useMainBuffer)
+    {
+        // iterate through the constant definitions
+        const size_t paramCount = params->getNumConstantDefinitions();
+        size_t paramIndex = 0;
+        while (paramIndex < paramCount)
+        {
+            // get the constant definition
+            const GpuProgramParameters::ConstantDefinition* constDef = 
+				params->getConstantDefinition(paramIndex);
+            // only output if the constant definition exists and its actually being used
+            // assume its being used if elementCount > 0
+            if (constDef && constDef->elementCount)
+            {
+                // don't duplicate constants that are defined as a default parameter
+                bool defaultExist = false;
+                if (defaultParams)
+                {
+                    // find matching default parameter
+                    const GpuProgramParameters::ConstantDefinition* defaultConstDef = 
+                        defaultParams->findMatchingConstantDefinition(
+							constDef->name, constDef->entryIndex, constDef->elementType);
+
+                    if (defaultConstDef)
+                    {
+                        // check all the elements for being equal
+                        // auto settings must be the same to be equal
+                        if ((defaultConstDef->isAuto && constDef->isAuto) && 
+							(defaultConstDef->autoIndex == constDef->autoIndex))
+                        {
+                            defaultExist = true;
+                        }
+                        else // check the values
+                        {
+                            if (constDef->elementType == GpuProgramParameters::ET_REAL)
+                            {
+                                const GpuProgramParameters::RealConstantEntry* constEntry =
+                                    params->getRealConstantEntry(constDef->entryIndex);
+
+                                if (!constEntry)
+                                    // no constant entry found so pretend default value exist and don't output anything
+                                    defaultExist = true;
+                                else
+                                {
+                                    const GpuProgramParameters::RealConstantEntry* defaultEntry =
+                                        defaultParams->getRealConstantEntry(defaultConstDef->entryIndex);
+                                    // compare current pass gpu parameter value with defualt entry parameter values
+                                    // only ouput if they are different
+                                    defaultExist = isConstantRealValsEqual(constEntry, defaultEntry, constDef->elementCount);
+                                }
+                            }
+                            else // dealing with int
+                            {
+                                const GpuProgramParameters::IntConstantEntry* constEntry =
+                                    params->getIntConstantEntry(constDef->entryIndex);
+
+                                if (!constEntry)
+                                    // no constant entry found so pretend default value exist and don't output anything
+                                    defaultExist = true;
+                                else
+                                {
+                                    const GpuProgramParameters::IntConstantEntry* defaultEntry =
+                                        defaultParams->getIntConstantEntry(defaultConstDef->entryIndex);
+
+                                    // compare current pass gpu parameter values with defualt entry parameter values
+                                    // only ouput if they are different
+                                    defaultExist = isConstantIntValsEqual(constEntry, defaultEntry, constDef->elementCount);
+                                }
+                            }
+
+                        }
+                    }
+
+                }
+
+                if (!defaultExist)
+                {
+                    String label;
+                    // is the param named
+                    if (!constDef->name.empty())
+                        label = "param_named";
+                    else
+                        label = "param_indexed";
+                    // is it auto
+                    if (constDef->isAuto)
+                        label += "_auto";
+
+                    writeAttribute(level, label, useMainBuffer);
+                    // output param name or index
+                    if (!constDef->name.empty())
+                        writeValue(constDef->name, useMainBuffer);
+                    else
+                        writeValue(StringConverter::toString(constDef->entryIndex), useMainBuffer);
+
+                    // if auto output auto type name and data if needed
+                    if (constDef->isAuto)
+                    {
+                        // get the auto constant entry associated with this constant definition
+                        const GpuProgramParameters::AutoConstantEntry* autoEntry =
+                            params->getAutoConstantEntry(constDef->autoIndex);
+
+                        if (autoEntry)
+                        {
+                            const GpuProgramParameters::AutoConstantDefinition* autoConstDef = 
+                                GpuProgramParameters::getAutoConstantDefinition(autoEntry->paramType);
+
+                            assert(autoConstDef && "Bad auto constant Definition Table");
+                            // output auto constant name
+                            writeValue(autoConstDef->name, useMainBuffer);
+                            // output data if it uses it
+                            switch(autoConstDef->dataType)
+                            {
+                            case GpuProgramParameters::ACDT_REAL:
+                                writeValue(StringConverter::toString(autoEntry->fData), useMainBuffer);
+                                break;
+
+                            case GpuProgramParameters::ACDT_INT:
+                                writeValue(StringConverter::toString(autoEntry->data), useMainBuffer);
+                                break;
+                            }
+                        }
+                    }
+                    else // not auto so output all the values used
+                    {
+                        String countLabel;
+                        const size_t elementCount = constDef->elementCount;
+                        // get starting index for constant
+                        size_t entryIndex = constDef->entryIndex;
+                        size_t currentIndex = 0;
+
+                        // only write a number if > 1
+                        if (elementCount > 1)
+                            countLabel = StringConverter::toString(elementCount);
+
+                        if (constDef->elementType == GpuProgramParameters::ET_REAL)
+                        {
+                            writeValue("float" + countLabel, useMainBuffer);
+                            // iterate through real constants 
+                            while (currentIndex < elementCount)
+                            {
+                                // get the constant entry
+                                const GpuProgramParameters::RealConstantEntry* constEntry =
+                                    params->getRealConstantEntry(entryIndex);
+
+                                // output the values within the constant entry
+                                size_t idx = 0;
+                                while ((idx < 4) && (currentIndex < elementCount))
+                                {
+                                    writeValue(StringConverter::toString(constEntry->val[idx]), useMainBuffer);
+                                    ++idx;
+                                    ++currentIndex;
+                                }
+                                ++entryIndex;
+                            }
+
+                        }
+                        else
+                        {
+                            writeValue("int" + countLabel, useMainBuffer);
+                            // iterate through int constants 
+                            while (currentIndex < elementCount)
+                            {
+                                // get the constant entry
+                                const GpuProgramParameters::IntConstantEntry* constEntry =
+                                    params->getIntConstantEntry(entryIndex + currentIndex);
+
+                                // output the values within the constant entry
+                                size_t idx = 0;
+                                while ((idx < 4) && (currentIndex < elementCount))
+                                {
+                                    writeValue(StringConverter::toString(constEntry->val[idx]), useMainBuffer);
+                                    ++idx;
+                                    ++currentIndex;
+                                }
+                                ++entryIndex;
+                            }
+
+                        }
+                    }
+                } // end if (!defaultExist)
+
+            } // end if
+
+            ++paramIndex;
+
+        } // end while
+
+    }
+
+    //-----------------------------------------------------------------------
+    void MaterialSerializer::writeGpuPrograms(void)
+    {
+        // iterate through gpu program names in container
+        GpuProgramDefIterator currentDef = mGpuProgramDefinitionContainer.begin();
+        GpuProgramDefIterator endDef = mGpuProgramDefinitionContainer.end();
+
+        while (currentDef != endDef)
+        {
+            // get gpu program from gpu program manager
+            GpuProgramPtr program = GpuProgramManager::getSingleton().getByName((*currentDef));
+            // write gpu program definition type to buffer
+            // check program type for vertex program
+            // write program type
+            mGpuProgramBuffer += "\n";
+            writeAttribute(0, program->getParameter("type"), false);
+
+            // write program name
+            writeValue( program->getName(), false);
+            // write program language
+            const String language = program->getLanguage();
+            writeValue( language, false );
+            // write opening braces
+            beginSection(0, false);
+            {
+                // write program source + filenmae
+                writeAttribute(1, "source", false);
+                writeValue(program->getSourceFile(), false);
+                // write special parameters based on language
+                const ParameterList& params = program->getParameters();
+                ParameterList::const_iterator currentParam = params.begin();
+                ParameterList::const_iterator endParam = params.end();
+
+                while (currentParam != endParam)
+                {
+                    if (currentParam->name != "type")
+                    {
+                        String paramstr = program->getParameter(currentParam->name);
+                        if ((currentParam->name == "includes_skeletal_animation")
+                            && (paramstr == "false"))
+                            paramstr = "";
+						if ((currentParam->name == "includes_morph_animation")
+							&& (paramstr == "false"))
+							paramstr = "";
+
+                        if ((language != "asm") && (currentParam->name == "syntax"))
+                            paramstr = "";
+
+                        if (!paramstr.empty())
+                        {
+                            writeAttribute(1, currentParam->name, false);
+                            writeValue(paramstr, false);
+                        }
+                    }
+                    ++currentParam;
+                }
+
+                // write default parameters
+                if (program->hasDefaultParameters())
+                {
+                    mGpuProgramBuffer += "\n";
+                    GpuProgramParametersSharedPtr gpuDefaultParams = program->getDefaultParameters();
+                    writeAttribute(1, "default_params", false);
+                    beginSection(1, false);
+                    writeGPUProgramParameters(gpuDefaultParams, 0, 2, false);
+                    endSection(1, false);
+                }
+            }
+            // write closing braces
+            endSection(0, false);
+
+            ++currentDef;
+
+        }
+
+        mGpuProgramBuffer += "\n";
+    }
+
+
+
+}
Index: OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/src/OgreSceneManager.cpp
===================================================================
--- OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/src/OgreSceneManager.cpp	(revision 768)
+++ OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/src/OgreSceneManager.cpp	(revision 768)
@@ -0,0 +1,4861 @@
+/*
+-----------------------------------------------------------------------------
+This source file is part of OGRE
+(Object-oriented Graphics Rendering Engine)
+For the latest info, see http://ogre.sourceforge.net/
+
+Copyright (c) 2000-2005 The OGRE Team
+Also see acknowledgements in Readme.html
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+#include "OgreStableHeaders.h"
+
+#include "OgreSceneManager.h"
+
+#include "OgreCamera.h"
+#include "OgreRenderSystem.h"
+#include "OgreMeshManager.h"
+#include "OgreMesh.h"
+#include "OgreSubMesh.h"
+#include "OgreEntity.h"
+#include "OgreSubEntity.h"
+#include "OgreLight.h"
+#include "OgreMath.h"
+#include "OgreControllerManager.h"
+#include "OgreMaterialManager.h"
+#include "OgreAnimation.h"
+#include "OgreAnimationTrack.h"
+#include "OgreRenderQueueSortingGrouping.h"
+#include "OgreOverlay.h"
+#include "OgreOverlayManager.h"
+#include "OgreStringConverter.h"
+#include "OgreRenderQueueListener.h"
+#include "OgreBillboardSet.h"
+#include "OgrePass.h"
+#include "OgreTechnique.h"
+#include "OgreTextureUnitState.h"
+#include "OgreException.h"
+#include "OgreLogManager.h"
+#include "OgreHardwareBufferManager.h"
+#include "OgreRoot.h"
+#include "OgreSpotShadowFadePng.h"
+#include "OgreGpuProgramManager.h"
+#include "OgreGpuProgram.h"
+#include "OgreShadowVolumeExtrudeProgram.h"
+#include "OgreDataStream.h"
+#include "OgreStaticGeometry.h"
+#include "OgreHardwarePixelBuffer.h"
+#include "OgreManualObject.h"
+#include "OgreRenderQueueInvocation.h"
+#include "OgreBillboardChain.h"
+#include "OgreRibbonTrail.h"
+#include "OgreParticleSystemManager.h"
+// This class implements the most basic scene manager
+
+#include <cstdio>
+
+namespace Ogre {
+
+//-----------------------------------------------------------------------
+uint32 SceneManager::WORLD_GEOMETRY_TYPE_MASK	= 0x80000000;
+uint32 SceneManager::ENTITY_TYPE_MASK			= 0x40000000;
+uint32 SceneManager::FX_TYPE_MASK				= 0x20000000;
+uint32 SceneManager::STATICGEOMETRY_TYPE_MASK   = 0x10000000;
+uint32 SceneManager::LIGHT_TYPE_MASK			= 0x08000000;
+uint32 SceneManager::USER_TYPE_MASK_LIMIT         = SceneManager::LIGHT_TYPE_MASK;
+//-----------------------------------------------------------------------
+SceneManager::SceneManager(const String& name) :
+mName(name),
+mRenderQueue(0),
+mSkyPlaneEntity(0),
+mSkyPlaneNode(0),
+mSkyDomeNode(0),
+mSkyBoxNode(0),
+mSkyPlaneEnabled(false),
+mSkyBoxEnabled(false),
+mSkyDomeEnabled(false),
+mFogMode(FOG_NONE),
+mSpecialCaseQueueMode(SCRQM_EXCLUDE),
+mWorldGeometryRenderQueue(RENDER_QUEUE_WORLD_GEOMETRY_1),
+mLastFrameNumber(0),
+mShadowCasterPlainBlackPass(0),
+mShadowReceiverPass(0),
+mDisplayNodes(false),
+mShowBoundingBoxes(false),
+mShadowTechnique(SHADOWTYPE_NONE),
+mDebugShadows(false),
+mShadowColour(ColourValue(0.25, 0.25, 0.25)),
+mShadowDebugPass(0),
+mShadowStencilPass(0),
+mShadowModulativePass(0),
+mShadowMaterialInitDone(false),
+mShadowIndexBufferSize(51200),
+mFullScreenQuad(0),
+mShadowDirLightExtrudeDist(10000),
+mIlluminationStage(IRS_NONE),
+mShadowTextureSize(512),
+mShadowTextureCount(1),
+mShadowTextureFormat(PF_X8R8G8B8),
+mShadowUseInfiniteFarPlane(true),
+mShadowCasterSphereQuery(0),
+mShadowCasterAABBQuery(0),
+mShadowFarDist(0),
+mShadowFarDistSquared(0),
+mShadowTextureOffset(0.6), 
+mShadowTextureFadeStart(0.7), 
+mShadowTextureFadeEnd(0.9),
+mShadowTextureSelfShadow(false),
+mShadowTextureCustomCasterPass(0),
+mShadowTextureCustomReceiverPass(0),
+mShadowTextureCasterVPDirty(false),
+mShadowTextureReceiverVPDirty(false),
+mVisibilityMask(0xFFFFFFFF),
+mFindVisibleObjects(true),
+mSuppressRenderStateChanges(false),
+mSuppressShadows(false)
+{
+    // Root scene node
+    mSceneRoot = new SceneNode(this, "root node");
+	mSceneRoot->_notifyRootNode();
+
+    // init sky
+    size_t i;
+    for (i = 0; i < 6; ++i)
+    {
+        mSkyBoxEntity[i] = 0;
+    }
+    for (i = 0; i < 5; ++i)
+    {
+        mSkyDomeEntity[i] = 0;
+    }
+
+	mShadowCasterQueryListener = new ShadowCasterSceneQueryListener(this);
+
+    Root *root = Root::getSingletonPtr();
+    if (root)
+        _setDestinationRenderSystem(root->getRenderSystem());
+
+	// Setup default queued renderable visitor
+	mActiveQueuedRenderableVisitor = &mDefaultQueuedRenderableVisitor;
+}
+//-----------------------------------------------------------------------
+SceneManager::~SceneManager()
+{
+    clearScene();
+    destroyAllCameras();
+
+	// clear down movable object collection map
+	for (MovableObjectCollectionMap::iterator i = mMovableObjectCollectionMap.begin();
+		i != mMovableObjectCollectionMap.end(); ++i)
+	{
+		delete i->second;
+	}
+	mMovableObjectCollectionMap.clear();
+
+	delete mShadowCasterQueryListener;
+    delete mSceneRoot;
+    delete mFullScreenQuad;
+    delete mShadowCasterSphereQuery;
+    delete mShadowCasterAABBQuery;
+    delete mRenderQueue;
+}
+//-----------------------------------------------------------------------
+RenderQueue* SceneManager::getRenderQueue(void)
+{
+    if (!mRenderQueue)
+    {
+        initRenderQueue();
+    }
+    return mRenderQueue;
+}
+//-----------------------------------------------------------------------
+void SceneManager::initRenderQueue(void)
+{
+    mRenderQueue = new RenderQueue();
+    // init render queues that do not need shadows
+    mRenderQueue->getQueueGroup(RENDER_QUEUE_BACKGROUND)->setShadowsEnabled(false);
+    mRenderQueue->getQueueGroup(RENDER_QUEUE_OVERLAY)->setShadowsEnabled(false);
+    mRenderQueue->getQueueGroup(RENDER_QUEUE_SKIES_EARLY)->setShadowsEnabled(false);
+    mRenderQueue->getQueueGroup(RENDER_QUEUE_SKIES_LATE)->setShadowsEnabled(false);
+}
+//-----------------------------------------------------------------------
+void SceneManager::addSpecialCaseRenderQueue(uint8 qid)
+{
+	mSpecialCaseQueueList.insert(qid);
+}
+//-----------------------------------------------------------------------
+void SceneManager::removeSpecialCaseRenderQueue(uint8 qid)
+{
+	mSpecialCaseQueueList.erase(qid);
+}
+//-----------------------------------------------------------------------
+void SceneManager::clearSpecialCaseRenderQueues(void)
+{
+	mSpecialCaseQueueList.clear();
+}
+//-----------------------------------------------------------------------
+void SceneManager::setSpecialCaseRenderQueueMode(SceneManager::SpecialCaseRenderQueueMode mode)
+{
+	mSpecialCaseQueueMode = mode;
+}
+//-----------------------------------------------------------------------
+SceneManager::SpecialCaseRenderQueueMode SceneManager::getSpecialCaseRenderQueueMode(void)
+{
+	return mSpecialCaseQueueMode;
+}
+//-----------------------------------------------------------------------
+bool SceneManager::isRenderQueueToBeProcessed(uint8 qid)
+{
+	bool inList = mSpecialCaseQueueList.find(qid) != mSpecialCaseQueueList.end();
+	return (inList && mSpecialCaseQueueMode == SCRQM_INCLUDE)
+		|| (!inList && mSpecialCaseQueueMode == SCRQM_EXCLUDE);
+}
+//-----------------------------------------------------------------------
+void SceneManager::setWorldGeometryRenderQueue(uint8 qid)
+{
+	mWorldGeometryRenderQueue = qid;
+}
+//-----------------------------------------------------------------------
+uint8 SceneManager::getWorldGeometryRenderQueue(void)
+{
+	return mWorldGeometryRenderQueue;
+}
+//-----------------------------------------------------------------------
+Camera* SceneManager::createCamera(const String& name)
+{
+    // Check name not used
+    if (mCameras.find(name) != mCameras.end())
+    {
+        OGRE_EXCEPT(
+            Exception::ERR_DUPLICATE_ITEM,
+            "A camera with the name " + name + " already exists",
+            "SceneManager::createCamera" );
+    }
+
+    Camera *c = new Camera(name, this);
+    mCameras.insert(CameraList::value_type(name, c));
+
+
+    return c;
+}
+
+//-----------------------------------------------------------------------
+Camera* SceneManager::getCamera(const String& name)
+{
+    CameraList::iterator i = mCameras.find(name);
+    if (i == mCameras.end())
+    {
+        OGRE_EXCEPT( Exception::ERR_ITEM_NOT_FOUND, 
+            "Cannot find Camera with name " + name,
+            "SceneManager::getCamera");
+    }
+    else
+    {
+        return i->second;
+    }
+}
+
+//-----------------------------------------------------------------------
+void SceneManager::destroyCamera(Camera *cam)
+{
+    // Find in list
+    CameraList::iterator i = mCameras.begin();
+    for (; i != mCameras.end(); ++i)
+    {
+        if (i->second == cam)
+        {
+            mCameras.erase(i);
+            // notify render targets
+            mDestRenderSystem->_notifyCameraRemoved(cam);
+            delete cam;
+            break;
+        }
+    }
+
+}
+
+//-----------------------------------------------------------------------
+void SceneManager::destroyCamera(const String& name)
+{
+    // Find in list
+    CameraList::iterator i = mCameras.find(name);
+    if (i != mCameras.end())
+    {
+        // Notify render system
+        mDestRenderSystem->_notifyCameraRemoved(i->second);
+        delete i->second;
+        mCameras.erase(i);
+    }
+
+}
+
+//-----------------------------------------------------------------------
+void SceneManager::destroyAllCameras(void)
+{
+
+    CameraList::iterator i = mCameras.begin();
+    for (; i != mCameras.end(); ++i)
+    {
+        // Notify render system
+        mDestRenderSystem->_notifyCameraRemoved(i->second);
+        delete i->second;
+    }
+    mCameras.clear();
+}
+//-----------------------------------------------------------------------
+Light* SceneManager::createLight(const String& name)
+{
+	return static_cast<Light*>(
+		createMovableObject(name, LightFactory::FACTORY_TYPE_NAME));
+}
+//-----------------------------------------------------------------------
+Light* SceneManager::getLight(const String& name)
+{
+	return static_cast<Light*>(
+		getMovableObject(name, LightFactory::FACTORY_TYPE_NAME));
+}
+//-----------------------------------------------------------------------
+void SceneManager::destroyLight(Light *l)
+{
+	destroyMovableObject(l);
+}
+//-----------------------------------------------------------------------
+void SceneManager::destroyLight(const String& name)
+{
+	destroyMovableObject(name, LightFactory::FACTORY_TYPE_NAME);
+}
+//-----------------------------------------------------------------------
+void SceneManager::destroyAllLights(void)
+{
+	destroyAllMovableObjectsByType(LightFactory::FACTORY_TYPE_NAME);
+}
+//-----------------------------------------------------------------------
+bool SceneManager::lightLess::operator()(const Light* a, const Light* b) const
+{
+    return a->tempSquareDist < b->tempSquareDist;
+}
+//-----------------------------------------------------------------------
+void SceneManager::_populateLightList(const Vector3& position, Real radius, 
+									  LightList& destList)
+{
+    // Really basic trawl of the lights, then sort
+    // Subclasses could do something smarter
+    destList.clear();
+
+	MovableObjectIterator it = 
+		getMovableObjectIterator(LightFactory::FACTORY_TYPE_NAME);
+
+    while(it.hasMoreElements())
+    {
+        Light* lt = static_cast<Light*>(it.getNext());
+        if (lt->isVisible())
+        {
+            if (lt->getType() == Light::LT_DIRECTIONAL)
+            {
+                // No distance
+                lt->tempSquareDist = 0.0f;
+                destList.push_back(lt);
+            }
+            else
+            {
+                // Calc squared distance
+                lt->tempSquareDist = (lt->getDerivedPosition() - position).squaredLength();
+                // only add in-range lights
+                Real range = lt->getAttenuationRange();
+                Real maxDist = range + radius;
+                if (lt->tempSquareDist <= Math::Sqr(maxDist))
+                {
+                    destList.push_back(lt);
+                }
+            }
+        }
+    }
+
+    // Sort (stable to guarantee ordering on directional lights)
+    std::stable_sort(destList.begin(), destList.end(), lightLess());
+
+
+}
+//-----------------------------------------------------------------------
+Entity* SceneManager::createEntity(const String& entityName, PrefabType ptype)
+{
+    switch (ptype)
+    {
+    case PT_PLANE:
+        return createEntity(entityName, "Prefab_Plane");
+
+        break;
+    }
+
+    OGRE_EXCEPT( Exception::ERR_ITEM_NOT_FOUND, 
+        "Unknown prefab type for entity " + entityName,
+        "SceneManager::createEntity");
+}
+
+//-----------------------------------------------------------------------
+Entity* SceneManager::createEntity(
+                                   const String& entityName,
+                                   const String& meshName )
+{
+	// delegate to factory implementation
+	NameValuePairList params;
+	params["mesh"] = meshName;
+	return static_cast<Entity*>(
+		createMovableObject(entityName, EntityFactory::FACTORY_TYPE_NAME, 
+			&params));
+
+}
+
+//-----------------------------------------------------------------------
+Entity* SceneManager::getEntity(const String& name)
+{
+	return static_cast<Entity*>(
+		getMovableObject(name, EntityFactory::FACTORY_TYPE_NAME));
+}
+
+//-----------------------------------------------------------------------
+void SceneManager::destroyEntity(Entity *e)
+{
+	destroyMovableObject(e);
+}
+
+//-----------------------------------------------------------------------
+void SceneManager::destroyEntity(const String& name)
+{
+	destroyMovableObject(name, EntityFactory::FACTORY_TYPE_NAME);
+
+}
+
+//-----------------------------------------------------------------------
+void SceneManager::destroyAllEntities(void)
+{
+
+	destroyAllMovableObjectsByType(EntityFactory::FACTORY_TYPE_NAME);
+}
+
+//-----------------------------------------------------------------------
+void SceneManager::destroyAllBillboardSets(void)
+{
+	destroyAllMovableObjectsByType(BillboardSetFactory::FACTORY_TYPE_NAME);
+}
+//-----------------------------------------------------------------------
+ManualObject* SceneManager::createManualObject(const String& name)
+{
+	return static_cast<ManualObject*>(
+		createMovableObject(name, ManualObjectFactory::FACTORY_TYPE_NAME));
+}
+//-----------------------------------------------------------------------
+ManualObject* SceneManager::getManualObject(const String& name)
+{
+	return static_cast<ManualObject*>(
+		getMovableObject(name, ManualObjectFactory::FACTORY_TYPE_NAME));
+
+}
+//-----------------------------------------------------------------------
+void SceneManager::destroyManualObject(ManualObject* obj)
+{
+	destroyMovableObject(obj);
+}
+//-----------------------------------------------------------------------
+void SceneManager::destroyManualObject(const String& name)
+{
+	destroyMovableObject(name, ManualObjectFactory::FACTORY_TYPE_NAME);
+}
+//-----------------------------------------------------------------------
+void SceneManager::destroyAllManualObjects(void)
+{
+	destroyAllMovableObjectsByType(ManualObjectFactory::FACTORY_TYPE_NAME);
+}
+//-----------------------------------------------------------------------
+BillboardChain* SceneManager::createBillboardChain(const String& name)
+{
+	return static_cast<BillboardChain*>(
+		createMovableObject(name, BillboardChainFactory::FACTORY_TYPE_NAME));
+}
+//-----------------------------------------------------------------------
+BillboardChain* SceneManager::getBillboardChain(const String& name)
+{
+	return static_cast<BillboardChain*>(
+		getMovableObject(name, BillboardChainFactory::FACTORY_TYPE_NAME));
+
+}
+//-----------------------------------------------------------------------
+void SceneManager::destroyBillboardChain(BillboardChain* obj)
+{
+	destroyMovableObject(obj);
+}
+//-----------------------------------------------------------------------
+void SceneManager::destroyBillboardChain(const String& name)
+{
+	destroyMovableObject(name, BillboardChainFactory::FACTORY_TYPE_NAME);
+}
+//-----------------------------------------------------------------------
+void SceneManager::destroyAllBillboardChains(void)
+{
+	destroyAllMovableObjectsByType(BillboardChainFactory::FACTORY_TYPE_NAME);
+}
+//-----------------------------------------------------------------------
+RibbonTrail* SceneManager::createRibbonTrail(const String& name)
+{
+	return static_cast<RibbonTrail*>(
+		createMovableObject(name, RibbonTrailFactory::FACTORY_TYPE_NAME));
+}
+//-----------------------------------------------------------------------
+RibbonTrail* SceneManager::getRibbonTrail(const String& name)
+{
+	return static_cast<RibbonTrail*>(
+		getMovableObject(name, RibbonTrailFactory::FACTORY_TYPE_NAME));
+
+}
+//-----------------------------------------------------------------------
+void SceneManager::destroyRibbonTrail(RibbonTrail* obj)
+{
+	destroyMovableObject(obj);
+}
+//-----------------------------------------------------------------------
+void SceneManager::destroyRibbonTrail(const String& name)
+{
+	destroyMovableObject(name, RibbonTrailFactory::FACTORY_TYPE_NAME);
+}
+//-----------------------------------------------------------------------
+void SceneManager::destroyAllRibbonTrails(void)
+{
+	destroyAllMovableObjectsByType(RibbonTrailFactory::FACTORY_TYPE_NAME);
+}
+//-----------------------------------------------------------------------
+ParticleSystem* SceneManager::createParticleSystem(const String& name,
+	const String& templateName)
+{
+	NameValuePairList params;
+	params["templateName"] = templateName;
+	
+	return static_cast<ParticleSystem*>(
+		createMovableObject(name, ParticleSystemFactory::FACTORY_TYPE_NAME, 
+			&params));
+}
+//-----------------------------------------------------------------------
+ParticleSystem* SceneManager::createParticleSystem(const String& name,
+	size_t quota, const String& group)
+{
+	NameValuePairList params;
+	params["quota"] = StringConverter::toString(quota);
+	params["resourceGroup"] = group;
+	
+	return static_cast<ParticleSystem*>(
+		createMovableObject(name, ParticleSystemFactory::FACTORY_TYPE_NAME, 
+			&params));
+}
+//-----------------------------------------------------------------------
+ParticleSystem* SceneManager::getParticleSystem(const String& name)
+{
+	return static_cast<ParticleSystem*>(
+		getMovableObject(name, ParticleSystemFactory::FACTORY_TYPE_NAME));
+
+}
+//-----------------------------------------------------------------------
+void SceneManager::destroyParticleSystem(ParticleSystem* obj)
+{
+	destroyMovableObject(obj);
+}
+//-----------------------------------------------------------------------
+void SceneManager::destroyParticleSystem(const String& name)
+{
+	destroyMovableObject(name, ParticleSystemFactory::FACTORY_TYPE_NAME);
+}
+//-----------------------------------------------------------------------
+void SceneManager::destroyAllParticleSystems(void)
+{
+	destroyAllMovableObjectsByType(ParticleSystemFactory::FACTORY_TYPE_NAME);
+}
+//-----------------------------------------------------------------------
+void SceneManager::clearScene(void)
+{
+	destroyAllStaticGeometry();
+	destroyAllMovableObjects();
+
+	// Clear root node of all children
+	mSceneRoot->removeAllChildren();
+	mSceneRoot->detachAllObjects();
+
+	// Delete all SceneNodes, except root that is
+	for (SceneNodeList::iterator i = mSceneNodes.begin();
+		i != mSceneNodes.end(); ++i)
+	{
+		delete i->second;
+	}
+	mSceneNodes.clear();
+	mAutoTrackingSceneNodes.clear();
+
+
+	
+	// Clear animations
+    destroyAllAnimations();
+
+    // Remove sky nodes since they've been deleted
+    mSkyBoxNode = mSkyPlaneNode = mSkyDomeNode = 0;
+    mSkyBoxEnabled = mSkyPlaneEnabled = mSkyDomeEnabled = false; 
+
+	// Clear render queue, empty completely
+	if (mRenderQueue)
+		mRenderQueue->clear(true);
+
+}
+//-----------------------------------------------------------------------
+SceneNode* SceneManager::createSceneNode(void)
+{
+    SceneNode* sn = new SceneNode(this);
+    assert(mSceneNodes.find(sn->getName()) == mSceneNodes.end());
+    mSceneNodes[sn->getName()] = sn;
+    return sn;
+}
+//-----------------------------------------------------------------------
+SceneNode* SceneManager::createSceneNode(const String& name)
+{
+    // Check name not used
+    if (mSceneNodes.find(name) != mSceneNodes.end())
+    {
+        OGRE_EXCEPT(
+            Exception::ERR_DUPLICATE_ITEM,
+            "A scene node with the name " + name + " already exists",
+            "SceneManager::createSceneNode" );
+    }
+
+    SceneNode* sn = new SceneNode(this, name);
+    mSceneNodes[sn->getName()] = sn;
+    return sn;
+}
+//-----------------------------------------------------------------------
+void SceneManager::destroySceneNode(const String& name)
+{
+    SceneNodeList::iterator i = mSceneNodes.find(name);
+
+    if (i == mSceneNodes.end())
+    {
+        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "SceneNode '" + name + "' not found.",
+            "SceneManager::destroySceneNode");
+    }
+
+    // Find any scene nodes which are tracking this node, and turn them off
+    AutoTrackingSceneNodes::iterator ai, aiend;
+    aiend = mAutoTrackingSceneNodes.end();
+    for (ai = mAutoTrackingSceneNodes.begin(); ai != aiend; )
+    {
+		// Pre-increment incase we delete
+		AutoTrackingSceneNodes::iterator curri = ai++;
+        SceneNode* n = *curri;
+        // Tracking this node
+        if (n->getAutoTrackTarget() == i->second)
+        {
+            // turn off, this will notify SceneManager to remove
+            n->setAutoTracking(false);
+        }
+        // node is itself a tracker
+        else if (n == i->second)
+        {
+            mAutoTrackingSceneNodes.erase(curri);
+        }
+    }
+
+	// detach from parent (don't do this in destructor since bulk destruction
+	// behaves differently)
+	Node* parentNode = i->second->getParent();
+	if (parentNode)
+	{
+		parentNode->removeChild(i->second);
+	}
+    delete i->second;
+    mSceneNodes.erase(i);
+}
+//-----------------------------------------------------------------------
+SceneNode* SceneManager::getRootSceneNode(void) const
+{
+    return mSceneRoot;
+}
+//-----------------------------------------------------------------------
+SceneNode* SceneManager::getSceneNode(const String& name) const
+{
+    SceneNodeList::const_iterator i = mSceneNodes.find(name);
+
+    if (i == mSceneNodes.end())
+    {
+        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "SceneNode '" + name + "' not found.",
+            "SceneManager::getSceneNode");
+    }
+
+    return i->second;
+
+}
+//-----------------------------------------------------------------------
+const Pass* SceneManager::_setPass(const Pass* pass, bool evenIfSuppressed)
+{
+	if (!mSuppressRenderStateChanges || evenIfSuppressed)
+	{
+		if (mIlluminationStage == IRS_RENDER_TO_TEXTURE)
+		{
+			// Derive a special shadow caster pass from this one
+			pass = deriveShadowCasterPass(pass);
+		}
+		else if (mIlluminationStage == IRS_RENDER_RECEIVER_PASS)
+		{
+			pass = deriveShadowReceiverPass(pass);
+		}
+
+		// TEST
+		/*
+		LogManager::getSingleton().logMessage("BEGIN PASS " + StringConverter::toString(pass->getIndex()) + 
+		" of " + pass->getParent()->getParent()->getName());
+		*/
+		bool passSurfaceAndLightParams = true;
+
+		if (pass->hasVertexProgram())
+		{
+			mDestRenderSystem->bindGpuProgram(pass->getVertexProgram()->_getBindingDelegate());
+			// bind parameters later since they can be per-object
+			// does the vertex program want surface and light params passed to rendersystem?
+			passSurfaceAndLightParams = pass->getVertexProgram()->getPassSurfaceAndLightStates();
+		}
+		else
+		{
+			// Unbind program?
+			if (mDestRenderSystem->isGpuProgramBound(GPT_VERTEX_PROGRAM))
+			{
+				mDestRenderSystem->unbindGpuProgram(GPT_VERTEX_PROGRAM);
+			}
+			// Set fixed-function vertex parameters
+		}
+
+		if (passSurfaceAndLightParams)
+		{
+			// Set surface reflectance properties, only valid if lighting is enabled
+			if (pass->getLightingEnabled())
+			{
+				mDestRenderSystem->_setSurfaceParams( 
+					pass->getAmbient(), 
+					pass->getDiffuse(), 
+					pass->getSpecular(), 
+					pass->getSelfIllumination(), 
+					pass->getShininess(),
+			pass->getVertexColourTracking() );
+			}
+
+			// Dynamic lighting enabled?
+			mDestRenderSystem->setLightingEnabled(pass->getLightingEnabled());
+		}
+
+		// Using a fragment program?
+		if (pass->hasFragmentProgram())
+		{
+			mDestRenderSystem->bindGpuProgram(
+				pass->getFragmentProgram()->_getBindingDelegate());
+			// bind parameters later since they can be per-object
+		}
+		else
+		{
+			// Unbind program?
+			if (mDestRenderSystem->isGpuProgramBound(GPT_FRAGMENT_PROGRAM))
+			{
+				mDestRenderSystem->unbindGpuProgram(GPT_FRAGMENT_PROGRAM);
+			}
+
+			// Set fixed-function fragment settings
+		}
+
+        /* We need sets fog properties always. In D3D, it applies to shaders prior
+        to version vs_3_0 and ps_3_0. And in OGL, it applies to "ARB_fog_XXX" in
+        fragment program, and in other ways, them maybe access by gpu program via
+        "state.fog.XXX".
+        */
+        // New fog params can either be from scene or from material
+        FogMode newFogMode;
+        ColourValue newFogColour;
+        Real newFogStart, newFogEnd, newFogDensity;
+        if (pass->getFogOverride())
+        {
+            // New fog params from material
+            newFogMode = pass->getFogMode();
+            newFogColour = pass->getFogColour();
+            newFogStart = pass->getFogStart();
+            newFogEnd = pass->getFogEnd();
+            newFogDensity = pass->getFogDensity();
+        }
+        else
+        {
+            // New fog params from scene
+            newFogMode = mFogMode;
+            newFogColour = mFogColour;
+            newFogStart = mFogStart;
+            newFogEnd = mFogEnd;
+            newFogDensity = mFogDensity;
+        }
+        // Tell params about current fog
+        mAutoParamDataSource.setFog(
+            newFogMode, newFogColour, newFogDensity, newFogStart, newFogEnd);
+        mDestRenderSystem->_setFog(
+            newFogMode, newFogColour, newFogDensity, newFogStart, newFogEnd);
+
+		// The rest of the settings are the same no matter whether we use programs or not
+
+		// Set scene blending
+		mDestRenderSystem->_setSceneBlending(
+			pass->getSourceBlendFactor(), pass->getDestBlendFactor());
+
+		// Set point parameters
+		mDestRenderSystem->_setPointParameters(
+			pass->getPointSize(),
+			pass->isPointAttenuationEnabled(), 
+			pass->getPointAttenuationConstant(), 
+			pass->getPointAttenuationLinear(), 
+			pass->getPointAttenuationQuadratic(), 
+			pass->getPointMinSize(), 
+			pass->getPointMaxSize());
+
+		mDestRenderSystem->_setPointSpritesEnabled(pass->getPointSpritesEnabled());
+
+		// Texture unit settings
+
+		Pass::ConstTextureUnitStateIterator texIter =  pass->getTextureUnitStateIterator();
+		size_t unit = 0;
+		while(texIter.hasMoreElements())
+		{
+			TextureUnitState* pTex = texIter.getNext();
+			mDestRenderSystem->_setTextureUnitSettings(unit, *pTex);
+			++unit;
+		}
+		// Disable remaining texture units
+		mDestRenderSystem->_disableTextureUnitsFrom(pass->getNumTextureUnitStates());
+
+		// Set up non-texture related material settings
+		// Depth buffer settings
+		mDestRenderSystem->_setDepthBufferFunction(pass->getDepthFunction());
+		mDestRenderSystem->_setDepthBufferCheckEnabled(pass->getDepthCheckEnabled());
+		mDestRenderSystem->_setDepthBufferWriteEnabled(pass->getDepthWriteEnabled());
+		mDestRenderSystem->_setDepthBias(pass->getDepthBias());
+		// Alpha-reject settings
+		mDestRenderSystem->_setAlphaRejectSettings(
+			pass->getAlphaRejectFunction(), pass->getAlphaRejectValue());
+		// Set colour write mode
+		// Right now we only use on/off, not per-channel
+		bool colWrite = pass->getColourWriteEnabled();
+		mDestRenderSystem->_setColourBufferWriteEnabled(colWrite, colWrite, colWrite, colWrite);
+		// Culling mode
+		mDestRenderSystem->_setCullingMode(pass->getCullingMode());
+		// Shading
+		mDestRenderSystem->setShadingType(pass->getShadingMode());
+		// Polygon mode
+		mDestRenderSystem->_setPolygonMode(pass->getPolygonMode());
+
+		// set pass number
+    	mAutoParamDataSource.setPassNumber( pass->getIndex() );
+	}
+
+    return pass;
+}
+//-----------------------------------------------------------------------
+void SceneManager::prepareRenderQueue(void)
+{
+	RenderQueue* q = getRenderQueue();
+	// Clear the render queue
+	q->clear();
+
+	// Prep the ordering options
+
+	// If we're using a custom render squence, define based on that
+	RenderQueueInvocationSequence* seq = 
+		mCurrentViewport->_getRenderQueueInvocationSequence();
+	if (seq)
+	{
+		// Iterate once to crate / reset all
+		RenderQueueInvocationIterator invokeIt = seq->iterator();
+		while (invokeIt.hasMoreElements())
+		{
+			RenderQueueInvocation* invocation = invokeIt.getNext();
+			RenderQueueGroup* group = 
+				q->getQueueGroup(invocation->getRenderQueueGroupID());
+			group->resetOrganisationModes();
+		}
+		// Iterate again to build up options (may be more than one)
+		invokeIt = seq->iterator();
+		while (invokeIt.hasMoreElements())
+		{
+			RenderQueueInvocation* invocation = invokeIt.getNext();
+			RenderQueueGroup* group = 
+				q->getQueueGroup(invocation->getRenderQueueGroupID());
+			group->addOrganisationMode(invocation->getSolidsOrganisation());
+			// also set splitting options
+			updateRenderQueueGroupSplitOptions(group, invocation->getSuppressShadows(), 
+				invocation->getSuppressRenderStateChanges());
+		}
+	}
+	else
+	{
+		// Default all the queue groups that are there, new ones will be created
+		// with defaults too
+		RenderQueue::QueueGroupIterator groupIter = q->_getQueueGroupIterator();
+		while (groupIter.hasMoreElements())
+		{
+			RenderQueueGroup* g = groupIter.getNext();
+			g->defaultOrganisationMode();
+		}
+		// Global split options
+		updateRenderQueueSplitOptions();
+	}
+
+}
+//-----------------------------------------------------------------------
+void SceneManager::_renderScene(Camera* camera, Viewport* vp, bool includeOverlays)
+{
+    Root::getSingleton()._setCurrentSceneManager(this);
+	mActiveQueuedRenderableVisitor->targetSceneMgr = this;
+
+    if (isShadowTechniqueInUse())
+    {
+        // Prepare shadow materials
+        initShadowVolumeMaterials();
+    }
+
+    // Perform a quick pre-check to see whether we should override far distance
+    // When using stencil volumes we have to use infinite far distance
+    // to prevent dark caps getting clipped
+    if (isShadowTechniqueStencilBased() && 
+        camera->getProjectionType() == PT_PERSPECTIVE &&
+        camera->getFarClipDistance() != 0 && 
+        mDestRenderSystem->getCapabilities()->hasCapability(RSC_INFINITE_FAR_PLANE) && 
+        mShadowUseInfiniteFarPlane)
+    {
+        // infinite far distance
+        camera->setFarClipDistance(0);
+    }
+
+    mCameraInProgress = camera;
+
+
+    // Update controllers 
+    ControllerManager::getSingleton().updateAllControllers();
+
+    // Update the scene, only do this once per frame
+    unsigned long thisFrameNumber = Root::getSingleton().getCurrentFrameNumber();
+    if (thisFrameNumber != mLastFrameNumber)
+    {
+        // Update animations
+        _applySceneAnimations();
+        mLastFrameNumber = thisFrameNumber;
+    }
+
+    // Update scene graph for this camera (can happen multiple times per frame)
+    _updateSceneGraph(camera);
+
+    // Auto-track nodes
+    AutoTrackingSceneNodes::iterator atsni, atsniend;
+    atsniend = mAutoTrackingSceneNodes.end();
+    for (atsni = mAutoTrackingSceneNodes.begin(); atsni != atsniend; ++atsni)
+    {
+        (*atsni)->_autoTrack();
+    }
+    // Auto-track camera if required
+    camera->_autoTrack();
+
+
+    // Are we using any shadows at all?
+    if (isShadowTechniqueInUse() && 
+        mIlluminationStage != IRS_RENDER_TO_TEXTURE &&
+		vp->getShadowsEnabled() &&
+		mFindVisibleObjects)
+    {
+        // Locate any lights which could be affecting the frustum
+        findLightsAffectingFrustum(camera);
+        if (isShadowTechniqueTextureBased())
+        {
+            // *******
+            // WARNING
+            // *******
+            // This call will result in re-entrant calls to this method
+            // therefore anything which comes before this is NOT 
+            // guaranteed persistent. Make sure that anything which 
+            // MUST be specific to this camera / target is done 
+            // AFTER THIS POINT
+            prepareShadowTextures(camera, vp);
+            // reset the cameras because of the re-entrant call
+            mCameraInProgress = camera;
+        }
+    }
+
+    // Invert vertex winding?
+    if (camera->isReflected())
+    {
+        mDestRenderSystem->setInvertVertexWinding(true);
+    }
+    else
+    {
+        mDestRenderSystem->setInvertVertexWinding(false);
+    }
+
+    // Tell params about viewport
+    mAutoParamDataSource.setCurrentViewport(vp);
+    // Set the viewport
+    setViewport(vp);
+
+    // Tell params about camera
+    mAutoParamDataSource.setCurrentCamera(camera);
+    // Set autoparams for finite dir light extrusion
+    mAutoParamDataSource.setShadowDirLightExtrusionDistance(mShadowDirLightExtrudeDist);
+
+    // Tell params about current ambient light
+    mAutoParamDataSource.setAmbientLightColour(mAmbientLight);
+	// Tell rendersystem
+	mDestRenderSystem->setAmbientLight(mAmbientLight.r, mAmbientLight.g, mAmbientLight.b);
+
+    // Tell params about render target
+    mAutoParamDataSource.setCurrentRenderTarget(vp->getTarget());
+
+
+    // Set camera window clipping planes (if any)
+    if (mDestRenderSystem->getCapabilities()->hasCapability(RSC_USER_CLIP_PLANES))
+    {
+        if (camera->isWindowSet())  
+        {
+            const std::vector<Plane>& planeList = 
+                camera->getWindowPlanes();
+            for (ushort i = 0; i < 4; ++i)
+            {
+                mDestRenderSystem->enableClipPlane(i, true);
+                mDestRenderSystem->setClipPlane(i, planeList[i]);
+            }
+        }
+        else
+        {
+            for (ushort i = 0; i < 4; ++i)
+            {
+                mDestRenderSystem->enableClipPlane(i, false);
+            }
+        }
+    }
+
+	// Prepare render queue for receiving new objects
+#ifdef GAMETOOLS_ILLUMINATION_MODULE 
+	if (mFindVisibleObjects)
+		prepareRenderQueue();
+#else
+		prepareRenderQueue();
+#endif
+
+
+    if (mFindVisibleObjects)
+    {
+        // Parse the scene and tag visibles
+        _findVisibleObjects(camera, 
+            mIlluminationStage == IRS_RENDER_TO_TEXTURE? true : false);
+    }
+    // Add overlays, if viewport deems it
+    if (vp->getOverlaysEnabled() && mIlluminationStage != IRS_RENDER_TO_TEXTURE)
+    {
+        OverlayManager::getSingleton()._queueOverlaysForRendering(camera, getRenderQueue(), vp);
+    }
+    // Queue skies, if viewport seems it
+    if (vp->getSkiesEnabled() && mFindVisibleObjects && mIlluminationStage != IRS_RENDER_TO_TEXTURE)
+    {
+        _queueSkiesForRendering(camera);
+    }
+
+
+    mDestRenderSystem->_beginGeometryCount();
+    // Begin the frame
+    mDestRenderSystem->_beginFrame();
+
+    // Set rasterisation mode
+    mDestRenderSystem->_setPolygonMode(camera->getPolygonMode());
+
+	// Set initial camera state
+	mDestRenderSystem->_setProjectionMatrix(mCameraInProgress->getProjectionMatrixRS());
+	mDestRenderSystem->_setViewMatrix(mCameraInProgress->getViewMatrix(true));
+
+    // Render scene content 
+    _renderVisibleObjects();
+
+    // End frame
+    mDestRenderSystem->_endFrame();
+
+    // Notify camera or vis faces
+    camera->_notifyRenderedFaces(mDestRenderSystem->_getFaceCount());
+
+
+
+}
+
+
+//-----------------------------------------------------------------------
+void SceneManager::_setDestinationRenderSystem(RenderSystem* sys)
+{
+    mDestRenderSystem = sys;
+
+}
+
+
+//-----------------------------------------------------------------------
+void SceneManager::setWorldGeometry(const String& filename)
+{
+    // This default implementation cannot handle world geometry
+    OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
+        "World geometry is not supported by the generic SceneManager.",
+        "SceneManager::setWorldGeometry");
+}
+//-----------------------------------------------------------------------
+void SceneManager::setWorldGeometry(DataStreamPtr& stream, 
+	const String& typeName)
+{
+    // This default implementation cannot handle world geometry
+    OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
+        "World geometry is not supported by the generic SceneManager.",
+        "SceneManager::setWorldGeometry");
+}
+
+//-----------------------------------------------------------------------
+bool SceneManager::materialLess::operator() (const Material* x, const Material* y) const
+{
+    // If x transparent and y not, x > y (since x has to overlap y)
+    if (x->isTransparent() && !y->isTransparent())
+    {
+        return false;
+    }
+    // If y is transparent and x not, x < y
+    else if (!x->isTransparent() && y->isTransparent())
+    {
+        return true;
+    }
+    else
+    {
+        // Otherwise don't care (both transparent or both solid)
+        // Just arbitrarily use pointer
+        return x < y;
+    }
+
+}
+
+//-----------------------------------------------------------------------
+void SceneManager::setSkyPlane(
+                               bool enable,
+                               const Plane& plane,
+                               const String& materialName,
+                               Real gscale,
+                               Real tiling,
+                               bool drawFirst,
+                               Real bow, 
+                               int xsegments, int ysegments, 
+                               const String& groupName)
+{
+    if (enable)
+    {
+        String meshName = mName + "SkyPlane";
+        mSkyPlane = plane;
+
+        MaterialPtr m = MaterialManager::getSingleton().getByName(materialName);
+        if (m.isNull())
+        {
+            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 
+                "Sky plane material '" + materialName + "' not found.",
+                "SceneManager::setSkyPlane");
+        }
+        // Make sure the material doesn't update the depth buffer
+        m->setDepthWriteEnabled(false);
+        // Ensure loaded
+        m->load();
+
+        mSkyPlaneDrawFirst = drawFirst;
+
+        // Set up the plane
+        MeshPtr planeMesh = MeshManager::getSingleton().getByName(meshName);
+        if (!planeMesh.isNull())
+        {
+            // Destroy the old one
+            MeshManager::getSingleton().remove(planeMesh->getHandle());
+        }
+
+        // Create up vector
+        Vector3 up = plane.normal.crossProduct(Vector3::UNIT_X);
+        if (up == Vector3::ZERO)
+            up = plane.normal.crossProduct(-Vector3::UNIT_Z);
+
+        // Create skyplane
+        if( bow > 0 )
+        {
+            // Build a curved skyplane
+            planeMesh = MeshManager::getSingleton().createCurvedPlane(
+                meshName, groupName, plane, gscale * 100, gscale * 100, gscale * bow * 100, 
+                xsegments, ysegments, false, 1, tiling, tiling, up);
+        }
+        else
+        {
+            planeMesh = MeshManager::getSingleton().createPlane(
+                meshName, groupName, plane, gscale * 100, gscale * 100, xsegments, ysegments, false, 
+                1, tiling, tiling, up);
+        }
+
+        // Create entity 
+        if (mSkyPlaneEntity)
+        {
+            // destroy old one, do it by name for speed
+            destroyEntity(meshName);
+        }
+        // Create, use the same name for mesh and entity
+        mSkyPlaneEntity = createEntity(meshName, meshName);
+        mSkyPlaneEntity->setMaterialName(materialName);
+        mSkyPlaneEntity->setCastShadows(false);
+
+        // Create node and attach
+        if (!mSkyPlaneNode)
+        {
+            mSkyPlaneNode = createSceneNode(meshName + "Node");
+        }
+        else
+        {
+            mSkyPlaneNode->detachAllObjects();
+        }
+        mSkyPlaneNode->attachObject(mSkyPlaneEntity);
+
+    }
+	mSkyPlaneEnabled = enable;
+	mSkyPlaneGenParameters.skyPlaneBow = bow;
+	mSkyPlaneGenParameters.skyPlaneScale = gscale;
+	mSkyPlaneGenParameters.skyPlaneTiling = tiling;
+	mSkyPlaneGenParameters.skyPlaneXSegments = xsegments;
+	mSkyPlaneGenParameters.skyPlaneYSegments = ysegments;
+}
+//-----------------------------------------------------------------------
+void SceneManager::setSkyBox(
+                             bool enable,
+                             const String& materialName,
+                             Real distance,
+                             bool drawFirst,
+                             const Quaternion& orientation,
+                             const String& groupName)
+{
+    if (enable)
+    {
+        MaterialPtr m = MaterialManager::getSingleton().getByName(materialName);
+        if (m.isNull())
+        {
+            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 
+                "Sky box material '" + materialName + "' not found.",
+                "SceneManager::setSkyBox");
+        }
+        // Make sure the material doesn't update the depth buffer
+        m->setDepthWriteEnabled(false);
+        // Ensure loaded
+        m->load();
+        // Also clamp texture, don't wrap (otherwise edges can get filtered)
+        m->getBestTechnique()->getPass(0)->getTextureUnitState(0)->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
+
+
+        mSkyBoxDrawFirst = drawFirst;
+
+        // Create node 
+        if (!mSkyBoxNode)
+        {
+            mSkyBoxNode = createSceneNode("SkyBoxNode");
+        }
+        else
+        {
+            mSkyBoxNode->detachAllObjects();
+        }
+
+        MaterialManager& matMgr = MaterialManager::getSingleton();
+        // Set up the box (6 planes)
+        for (int i = 0; i < 6; ++i)
+        {
+            MeshPtr planeMesh = createSkyboxPlane((BoxPlane)i, distance, orientation, groupName);
+            String entName = mName + "SkyBoxPlane" + StringConverter::toString(i);
+
+            // Create entity 
+            if (mSkyBoxEntity[i])
+            {
+                // destroy old one, do it by name for speed
+                destroyEntity(entName);
+            }
+            mSkyBoxEntity[i] = createEntity(entName, planeMesh->getName());
+            mSkyBoxEntity[i]->setCastShadows(false);
+            // Have to create 6 materials, one for each frame
+            // Used to use combined material but now we're using queue we can't split to change frame
+            // This doesn't use much memory because textures aren't duplicated
+            MaterialPtr boxMat = matMgr.getByName(entName);
+            if (boxMat.isNull())
+            {
+                // Create new by clone
+                boxMat = m->clone(entName);
+                boxMat->load();
+            }
+            else
+            {
+                // Copy over existing
+                m->copyDetailsTo(boxMat);
+                boxMat->load();
+            }
+            // Set active frame
+            boxMat->getBestTechnique()->getPass(0)->getTextureUnitState(0)
+                ->setCurrentFrame(i);
+
+            mSkyBoxEntity[i]->setMaterialName(boxMat->getName());
+
+            // Attach to node
+            mSkyBoxNode->attachObject(mSkyBoxEntity[i]);
+        } // for each plane
+
+    }
+	mSkyBoxEnabled = enable;
+	mSkyBoxGenParameters.skyBoxDistance = distance;
+}
+//-----------------------------------------------------------------------
+void SceneManager::setSkyDome(
+                              bool enable,
+                              const String& materialName,
+                              Real curvature,
+                              Real tiling,
+                              Real distance,
+                              bool drawFirst,
+                              const Quaternion& orientation,
+                              int xsegments, int ysegments, int ySegmentsToKeep,
+                              const String& groupName)
+{
+    if (enable)
+    {
+        MaterialPtr m = MaterialManager::getSingleton().getByName(materialName);
+        if (m.isNull())
+        {
+            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 
+                "Sky dome material '" + materialName + "' not found.",
+                "SceneManager::setSkyDome");
+        }
+        // Make sure the material doesn't update the depth buffer
+        m->setDepthWriteEnabled(false);
+        // Ensure loaded
+        m->load();
+
+        mSkyDomeDrawFirst = drawFirst;
+
+        // Create node 
+        if (!mSkyDomeNode)
+        {
+            mSkyDomeNode = createSceneNode("SkyDomeNode");
+        }
+        else
+        {
+            mSkyDomeNode->detachAllObjects();
+        }
+
+        // Set up the dome (5 planes)
+        for (int i = 0; i < 5; ++i)
+        {
+            MeshPtr planeMesh = createSkydomePlane((BoxPlane)i, curvature, 
+                tiling, distance, orientation, xsegments, ysegments, 
+                i!=BP_UP ? ySegmentsToKeep : -1, groupName);
+
+            String entName = "SkyDomePlane" + StringConverter::toString(i);
+
+            // Create entity 
+            if (mSkyDomeEntity[i])
+            {
+                // destroy old one, do it by name for speed
+                destroyEntity(entName);
+            }
+            mSkyDomeEntity[i] = createEntity(entName, planeMesh->getName());
+            mSkyDomeEntity[i]->setMaterialName(m->getName());
+            mSkyDomeEntity[i]->setCastShadows(false);
+
+            // Attach to node
+            mSkyDomeNode->attachObject(mSkyDomeEntity[i]);
+        } // for each plane
+
+    }
+	mSkyDomeEnabled = enable;
+	mSkyDomeGenParameters.skyDomeCurvature = curvature;
+	mSkyDomeGenParameters.skyDomeDistance = distance;
+	mSkyDomeGenParameters.skyDomeTiling = tiling;
+	mSkyDomeGenParameters.skyDomeXSegments = xsegments;
+	mSkyDomeGenParameters.skyDomeYSegments = ysegments;
+	mSkyDomeGenParameters.skyDomeYSegments_keep = ySegmentsToKeep;
+}
+//-----------------------------------------------------------------------
+MeshPtr SceneManager::createSkyboxPlane(
+                                      BoxPlane bp,
+                                      Real distance,
+                                      const Quaternion& orientation,
+                                      const String& groupName)
+{
+    Plane plane;
+    String meshName;
+    Vector3 up;
+
+    meshName = mName + "SkyBoxPlane_";
+    // Set up plane equation
+    plane.d = distance;
+    switch(bp)
+    {
+    case BP_FRONT:
+        plane.normal = Vector3::UNIT_Z;
+        up = Vector3::UNIT_Y;
+        meshName += "Front";
+        break;
+    case BP_BACK:
+        plane.normal = -Vector3::UNIT_Z;
+        up = Vector3::UNIT_Y;
+        meshName += "Back";
+        break;
+    case BP_LEFT:
+        plane.normal = Vector3::UNIT_X;
+        up = Vector3::UNIT_Y;
+        meshName += "Left";
+        break;
+    case BP_RIGHT:
+        plane.normal = -Vector3::UNIT_X;
+        up = Vector3::UNIT_Y;
+        meshName += "Right";
+        break;
+    case BP_UP:
+        plane.normal = -Vector3::UNIT_Y;
+        up = Vector3::UNIT_Z;
+        meshName += "Up";
+        break;
+    case BP_DOWN:
+        plane.normal = Vector3::UNIT_Y;
+        up = -Vector3::UNIT_Z;
+        meshName += "Down";
+        break;
+    }
+    // Modify by orientation
+    plane.normal = orientation * plane.normal;
+    up = orientation * up;
+
+
+    // Check to see if existing plane
+    MeshManager& mm = MeshManager::getSingleton();
+    MeshPtr planeMesh = mm.getByName(meshName);
+    if(!planeMesh.isNull())
+    {
+        // destroy existing
+        mm.remove(planeMesh->getHandle());
+    }
+    // Create new
+    Real planeSize = distance * 2;
+    const int BOX_SEGMENTS = 1;
+    planeMesh = mm.createPlane(meshName, groupName, plane, planeSize, planeSize, 
+        BOX_SEGMENTS, BOX_SEGMENTS, false, 1, 1, 1, up);
+
+    //planeMesh->_dumpContents(meshName);
+
+    return planeMesh;
+
+}
+//-----------------------------------------------------------------------
+MeshPtr SceneManager::createSkydomePlane(
+                                       BoxPlane bp,
+                                       Real curvature,
+                                       Real tiling,
+                                       Real distance,
+                                       const Quaternion& orientation,
+                                       int xsegments, int ysegments, int ysegments_keep, 
+                                       const String& groupName)
+{
+
+    Plane plane;
+    String meshName;
+    Vector3 up;
+
+    meshName = mName + "SkyDomePlane_";
+    // Set up plane equation
+    plane.d = distance;
+    switch(bp)
+    {
+    case BP_FRONT:
+        plane.normal = Vector3::UNIT_Z;
+        up = Vector3::UNIT_Y;
+        meshName += "Front";
+        break;
+    case BP_BACK:
+        plane.normal = -Vector3::UNIT_Z;
+        up = Vector3::UNIT_Y;
+        meshName += "Back";
+        break;
+    case BP_LEFT:
+        plane.normal = Vector3::UNIT_X;
+        up = Vector3::UNIT_Y;
+        meshName += "Left";
+        break;
+    case BP_RIGHT:
+        plane.normal = -Vector3::UNIT_X;
+        up = Vector3::UNIT_Y;
+        meshName += "Right";
+        break;
+    case BP_UP:
+        plane.normal = -Vector3::UNIT_Y;
+        up = Vector3::UNIT_Z;
+        meshName += "Up";
+        break;
+    case BP_DOWN:
+        // no down
+        return MeshPtr();
+    }
+    // Modify by orientation
+    plane.normal = orientation * plane.normal;
+    up = orientation * up;
+
+    // Check to see if existing plane
+    MeshManager& mm = MeshManager::getSingleton();
+    MeshPtr planeMesh = mm.getByName(meshName);
+    if(!planeMesh.isNull())
+    {
+        // destroy existing
+        mm.remove(planeMesh->getHandle());
+    }
+    // Create new
+    Real planeSize = distance * 2;
+    planeMesh = mm.createCurvedIllusionPlane(meshName, groupName, plane, 
+        planeSize, planeSize, curvature, 
+        xsegments, ysegments, false, 1, tiling, tiling, up, 
+        orientation, HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, HardwareBuffer::HBU_STATIC_WRITE_ONLY, 
+        false, false, ysegments_keep);
+
+    //planeMesh->_dumpContents(meshName);
+
+    return planeMesh;
+
+}
+
+
+//-----------------------------------------------------------------------
+void SceneManager::_updateSceneGraph(Camera* cam)
+{
+	// Process queued needUpdate calls 
+	Node::processQueuedUpdates();
+
+    // Cascade down the graph updating transforms & world bounds
+    // In this implementation, just update from the root
+    // Smarter SceneManager subclasses may choose to update only
+    //   certain scene graph branches
+    mSceneRoot->_update(true, false);
+
+
+}
+//-----------------------------------------------------------------------
+void SceneManager::_findVisibleObjects(Camera* cam, bool onlyShadowCasters)
+{
+    // Tell nodes to find, cascade down all nodes
+    mSceneRoot->_findVisibleObjects(cam, getRenderQueue(), true, 
+        mDisplayNodes, onlyShadowCasters);
+
+}
+//-----------------------------------------------------------------------
+void SceneManager::_renderVisibleObjects(void)
+{
+	RenderQueueInvocationSequence* invocationSequence = 
+		mCurrentViewport->_getRenderQueueInvocationSequence();
+	// Use custom sequence only if we're not doing the texture shadow render
+	// since texture shadow render should not be interfered with by suppressing
+	// render state changes for example
+	if (invocationSequence && mIlluminationStage != IRS_RENDER_TO_TEXTURE)
+	{
+		renderVisibleObjectsCustomSequence(invocationSequence);
+	}
+	else
+	{
+		renderVisibleObjectsDefaultSequence();
+	}
+}
+//-----------------------------------------------------------------------
+void SceneManager::renderVisibleObjectsCustomSequence(RenderQueueInvocationSequence* seq)
+{
+	RenderQueueInvocationIterator invocationIt = seq->iterator();
+	while (invocationIt.hasMoreElements())
+	{
+		RenderQueueInvocation* invocation = invocationIt.getNext();
+		uint8 qId = invocation->getRenderQueueGroupID();
+		// Skip this one if not to be processed
+		if (!isRenderQueueToBeProcessed(qId))
+			continue;
+
+
+		bool repeatQueue = false;
+		const String& invocationName = invocation->getInvocationName();
+		RenderQueueGroup* queueGroup = getRenderQueue()->getQueueGroup(qId);
+		do // for repeating queues
+		{
+			// Fire queue started event
+			if (fireRenderQueueStarted(qId, invocationName))
+			{
+				// Someone requested we skip this queue
+				break;
+			}
+
+			// Invoke it
+			invocation->invoke(queueGroup, this);
+
+			// Fire queue ended event
+			if (fireRenderQueueEnded(qId, invocationName))
+			{
+				// Someone requested we repeat this queue
+				repeatQueue = true;
+			}
+			else
+			{
+				repeatQueue = false;
+			}
+		} while (repeatQueue);
+
+
+	}
+}
+//-----------------------------------------------------------------------
+void SceneManager::renderVisibleObjectsDefaultSequence(void)
+{
+    // Render each separate queue
+    RenderQueue::QueueGroupIterator queueIt = getRenderQueue()->_getQueueGroupIterator();
+
+    // NB only queues which have been created are rendered, no time is wasted
+    //   parsing through non-existent queues (even though there are 10 available)
+
+    while (queueIt.hasMoreElements())
+    {
+        // Get queue group id
+        uint8 qId = queueIt.peekNextKey();
+		RenderQueueGroup* pGroup = queueIt.getNext();
+		// Skip this one if not to be processed
+		if (!isRenderQueueToBeProcessed(qId))
+			continue;
+
+
+        bool repeatQueue = false;
+        do // for repeating queues
+        {
+            // Fire queue started event
+			if (fireRenderQueueStarted(qId, 
+				mIlluminationStage == IRS_RENDER_TO_TEXTURE ? 
+					RenderQueueInvocation::RENDER_QUEUE_INVOCATION_SHADOWS : 
+					StringUtil::BLANK))
+            {
+                // Someone requested we skip this queue
+                break;
+            }
+
+			_renderQueueGroupObjects(pGroup, QueuedRenderableCollection::OM_PASS_GROUP);
+
+            // Fire queue ended event
+			if (fireRenderQueueEnded(qId, 
+				mIlluminationStage == IRS_RENDER_TO_TEXTURE ? 
+					RenderQueueInvocation::RENDER_QUEUE_INVOCATION_SHADOWS : 
+					StringUtil::BLANK))
+            {
+                // Someone requested we repeat this queue
+                repeatQueue = true;
+            }
+            else
+            {
+                repeatQueue = false;
+            }
+        } while (repeatQueue);
+
+    } // for each queue group
+
+}
+//-----------------------------------------------------------------------
+void SceneManager::renderAdditiveStencilShadowedQueueGroupObjects(
+	RenderQueueGroup* pGroup, 
+	QueuedRenderableCollection::OrganisationMode om)
+{
+    RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator();
+    LightList lightList;
+
+    while (groupIt.hasMoreElements())
+    {
+        RenderPriorityGroup* pPriorityGrp = groupIt.getNext();
+
+        // Sort the queue first
+        pPriorityGrp->sort(mCameraInProgress);
+
+        // Clear light list
+        lightList.clear();
+
+        // Render all the ambient passes first, no light iteration, no lights
+        renderObjects(pPriorityGrp->getSolidsBasic(), om, false, &lightList);
+        // Also render any objects which have receive shadows disabled
+        renderObjects(pPriorityGrp->getSolidsNoShadowReceive(), om, true);
+
+
+        // Now iterate per light
+        // Iterate over lights, render all volumes to stencil
+        LightList::const_iterator li, liend;
+        liend = mLightsAffectingFrustum.end();
+
+        for (li = mLightsAffectingFrustum.begin(); li != liend; ++li)
+        {
+            Light* l = *li;
+            // Set light state
+
+            if (l->getCastShadows())
+            {
+                // Clear stencil
+                mDestRenderSystem->clearFrameBuffer(FBT_STENCIL);
+                renderShadowVolumesToStencil(l, mCameraInProgress);
+                // turn stencil check on
+                mDestRenderSystem->setStencilCheckEnabled(true);
+                // NB we render where the stencil is equal to zero to render lit areas
+                mDestRenderSystem->setStencilBufferParams(CMPF_EQUAL, 0);
+            }
+
+            // render lighting passes for this light
+            if (lightList.empty())
+                lightList.push_back(l);
+            else
+                lightList[0] = l;
+            renderObjects(pPriorityGrp->getSolidsDiffuseSpecular(), om, false, &lightList);
+
+            // Reset stencil params
+            mDestRenderSystem->setStencilBufferParams();
+            mDestRenderSystem->setStencilCheckEnabled(false);
+            mDestRenderSystem->_setDepthBufferParams();
+
+        }// for each light
+
+
+        // Now render decal passes, no need to set lights as lighting will be disabled
+        renderObjects(pPriorityGrp->getSolidsDecal(), om, false);
+
+
+    }// for each priority
+
+    // Iterate again - variable name changed to appease gcc.
+    RenderQueueGroup::PriorityMapIterator groupIt2 = pGroup->getIterator();
+    while (groupIt2.hasMoreElements())
+    {
+        RenderPriorityGroup* pPriorityGrp = groupIt2.getNext();
+
+        // Do transparents (always descending sort)
+        renderObjects(pPriorityGrp->getTransparents(), 
+			QueuedRenderableCollection::OM_SORT_DESCENDING, true);
+
+    }// for each priority
+
+
+}
+//-----------------------------------------------------------------------
+void SceneManager::renderModulativeStencilShadowedQueueGroupObjects(
+	RenderQueueGroup* pGroup, 
+	QueuedRenderableCollection::OrganisationMode om)
+{
+    /* For each light, we need to render all the solids from each group, 
+    then do the modulative shadows, then render the transparents from
+    each group.
+    Now, this means we are going to reorder things more, but that it required
+    if the shadows are to look correct. The overall order is preserved anyway,
+    it's just that all the transparents are at the end instead of them being
+    interleaved as in the normal rendering loop. 
+    */
+    // Iterate through priorities
+    RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator();
+
+    while (groupIt.hasMoreElements())
+    {
+        RenderPriorityGroup* pPriorityGrp = groupIt.getNext();
+
+        // Sort the queue first
+        pPriorityGrp->sort(mCameraInProgress);
+
+        // Do (shadowable) solids
+        renderObjects(pPriorityGrp->getSolidsBasic(), om, true);
+    }
+
+
+    // Iterate over lights, render all volumes to stencil
+    LightList::const_iterator li, liend;
+    liend = mLightsAffectingFrustum.end();
+
+    for (li = mLightsAffectingFrustum.begin(); li != liend; ++li)
+    {
+        Light* l = *li;
+        if (l->getCastShadows())
+        {
+            // Clear stencil
+            mDestRenderSystem->clearFrameBuffer(FBT_STENCIL);
+            renderShadowVolumesToStencil(l, mCameraInProgress);
+            // render full-screen shadow modulator for all lights
+            _setPass(mShadowModulativePass);
+            // turn stencil check on
+            mDestRenderSystem->setStencilCheckEnabled(true);
+            // NB we render where the stencil is not equal to zero to render shadows, not lit areas
+            mDestRenderSystem->setStencilBufferParams(CMPF_NOT_EQUAL, 0);
+            renderSingleObject(mFullScreenQuad, mShadowModulativePass, false);
+            // Reset stencil params
+            mDestRenderSystem->setStencilBufferParams();
+            mDestRenderSystem->setStencilCheckEnabled(false);
+            mDestRenderSystem->_setDepthBufferParams();
+        }
+
+    }// for each light
+
+    // Iterate again - variable name changed to appease gcc.
+    RenderQueueGroup::PriorityMapIterator groupIt2 = pGroup->getIterator();
+    while (groupIt2.hasMoreElements())
+    {
+        RenderPriorityGroup* pPriorityGrp = groupIt2.getNext();
+
+        // Do non-shadowable solids
+        renderObjects(pPriorityGrp->getSolidsNoShadowReceive(), om, true);
+
+    }// for each priority
+
+
+    // Iterate again - variable name changed to appease gcc.
+    RenderQueueGroup::PriorityMapIterator groupIt3 = pGroup->getIterator();
+    while (groupIt3.hasMoreElements())
+    {
+        RenderPriorityGroup* pPriorityGrp = groupIt3.getNext();
+
+        // Do transparents (always descending sort)
+        renderObjects(pPriorityGrp->getTransparents(), 
+			QueuedRenderableCollection::OM_SORT_DESCENDING, true);
+
+    }// for each priority
+
+}
+//-----------------------------------------------------------------------
+void SceneManager::renderTextureShadowCasterQueueGroupObjects(
+	RenderQueueGroup* pGroup, 
+	QueuedRenderableCollection::OrganisationMode om)
+{
+    static LightList nullLightList;
+    // This is like the basic group render, except we skip all transparents
+    // and we also render any non-shadowed objects
+    // Note that non-shadow casters will have already been eliminated during
+    // _findVisibleObjects
+
+    // Iterate through priorities
+    RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator();
+
+    // Override auto param ambient to force vertex programs and fixed function to 
+	if (isShadowTechniqueAdditive())
+	{
+		// Use simple black / white mask if additive
+		mAutoParamDataSource.setAmbientLightColour(ColourValue::Black);
+		mDestRenderSystem->setAmbientLight(0, 0, 0);
+	}
+	else
+	{
+		// Use shadow colour as caster colour if modulative
+		mAutoParamDataSource.setAmbientLightColour(mShadowColour);
+		mDestRenderSystem->setAmbientLight(mShadowColour.r, mShadowColour.g, mShadowColour.b);
+	}
+
+    while (groupIt.hasMoreElements())
+    {
+        RenderPriorityGroup* pPriorityGrp = groupIt.getNext();
+
+        // Sort the queue first
+        pPriorityGrp->sort(mCameraInProgress);
+
+        // Do solids, override light list incase any vertex programs use them
+        renderObjects(pPriorityGrp->getSolidsBasic(), om, false, &nullLightList);
+        renderObjects(pPriorityGrp->getSolidsNoShadowReceive(), om, false, &nullLightList);
+		// Do transparents that cast shadows
+		renderTransparentShadowCasterObjects(
+				pPriorityGrp->getTransparents(), 
+				QueuedRenderableCollection::OM_SORT_DESCENDING, 
+				false, &nullLightList);
+
+
+    }// for each priority
+
+    // reset ambient light
+    mAutoParamDataSource.setAmbientLightColour(mAmbientLight);
+    mDestRenderSystem->setAmbientLight(mAmbientLight.r, mAmbientLight.g, mAmbientLight.b);
+}
+//-----------------------------------------------------------------------
+void SceneManager::renderModulativeTextureShadowedQueueGroupObjects(
+	RenderQueueGroup* pGroup, 
+	QueuedRenderableCollection::OrganisationMode om)
+{
+    /* For each light, we need to render all the solids from each group, 
+    then do the modulative shadows, then render the transparents from
+    each group.
+    Now, this means we are going to reorder things more, but that it required
+    if the shadows are to look correct. The overall order is preserved anyway,
+    it's just that all the transparents are at the end instead of them being
+    interleaved as in the normal rendering loop. 
+    */
+    // Iterate through priorities
+    RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator();
+
+    while (groupIt.hasMoreElements())
+    {
+        RenderPriorityGroup* pPriorityGrp = groupIt.getNext();
+
+        // Sort the queue first
+        pPriorityGrp->sort(mCameraInProgress);
+
+        // Do solids
+        renderObjects(pPriorityGrp->getSolidsBasic(), om, true);
+        renderObjects(pPriorityGrp->getSolidsNoShadowReceive(), om, true);
+    }
+
+
+    // Iterate over lights, render received shadows
+    // only perform this if we're in the 'normal' render stage, to avoid
+    // doing it during the render to texture
+    if (mIlluminationStage == IRS_NONE)
+    {
+        mIlluminationStage = IRS_RENDER_RECEIVER_PASS;
+
+        LightList::iterator i, iend;
+        ShadowTextureList::iterator si, siend;
+        iend = mLightsAffectingFrustum.end();
+        siend = mShadowTextures.end();
+        for (i = mLightsAffectingFrustum.begin(), si = mShadowTextures.begin();
+            i != iend && si != siend; ++i)
+        {
+            Light* l = *i;
+
+            if (!l->getCastShadows())
+                continue;
+
+			// Store current shadow texture
+            mCurrentShadowTexture = si->getPointer();
+			// Get camera for current shadow texture
+            Camera *cam = mCurrentShadowTexture->getBuffer()->getRenderTarget()->getViewport(0)->getCamera();
+            // Hook up receiver texture
+			Pass* targetPass = mShadowTextureCustomReceiverPass ?
+				mShadowTextureCustomReceiverPass : mShadowReceiverPass;
+            targetPass->getTextureUnitState(0)->setTextureName(
+                mCurrentShadowTexture->getName());
+            // Hook up projection frustum
+            targetPass->getTextureUnitState(0)->setProjectiveTexturing(true, cam);
+            mAutoParamDataSource.setTextureProjector(cam);
+            // if this light is a spotlight, we need to add the spot fader layer
+            if (l->getType() == Light::LT_SPOTLIGHT)
+            {
+				// remove all TUs except 0 & 1 
+				// (only an issue if additive shadows have been used)
+				while(targetPass->getNumTextureUnitStates() > 2)
+					targetPass->removeTextureUnitState(2);
+
+                // Add spot fader if not present already
+                if (targetPass->getNumTextureUnitStates() == 2 && 
+					targetPass->getTextureUnitState(1)->getTextureName() == 
+						"spot_shadow_fade.png")
+				{
+					// Just set 
+					TextureUnitState* t = 
+						targetPass->getTextureUnitState(1);
+					t->setProjectiveTexturing(true, cam);
+				}
+                else
+				{
+					// Remove any non-conforming spot layers
+					while(targetPass->getNumTextureUnitStates() > 1)
+						targetPass->removeTextureUnitState(1);
+
+                    TextureUnitState* t = 
+                        mShadowReceiverPass->createTextureUnitState("spot_shadow_fade.png");
+                    t->setProjectiveTexturing(true, cam);
+                    t->setColourOperation(LBO_ADD);
+                    t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
+                }
+            }
+            else 
+            {
+				// remove all TUs except 0 including spot
+				while(targetPass->getNumTextureUnitStates() > 1)
+	                targetPass->removeTextureUnitState(1);
+
+            }
+			// Set lighting / blending modes
+			targetPass->setSceneBlending(SBF_DEST_COLOUR, SBF_ZERO);
+			targetPass->setLightingEnabled(false);
+
+            targetPass->_load();
+
+			// Fire pre-receiver event
+			fireShadowTexturesPreReceiver(l, cam);
+
+            renderTextureShadowReceiverQueueGroupObjects(pGroup, om);
+
+            ++si;
+
+        }// for each light
+
+        mIlluminationStage = IRS_NONE;
+
+    }
+
+    // Iterate again - variable name changed to appease gcc.
+    RenderQueueGroup::PriorityMapIterator groupIt3 = pGroup->getIterator();
+    while (groupIt3.hasMoreElements())
+    {
+        RenderPriorityGroup* pPriorityGrp = groupIt3.getNext();
+
+        // Do transparents (always descending)
+        renderObjects(pPriorityGrp->getTransparents(), 
+			QueuedRenderableCollection::OM_SORT_DESCENDING, true);
+
+    }// for each priority
+
+}
+//-----------------------------------------------------------------------
+void SceneManager::renderAdditiveTextureShadowedQueueGroupObjects(
+	RenderQueueGroup* pGroup, 
+	QueuedRenderableCollection::OrganisationMode om)
+{
+	RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator();
+	LightList lightList;
+
+	while (groupIt.hasMoreElements())
+	{
+		RenderPriorityGroup* pPriorityGrp = groupIt.getNext();
+
+		// Sort the queue first
+		pPriorityGrp->sort(mCameraInProgress);
+
+		// Clear light list
+		lightList.clear();
+
+		// Render all the ambient passes first, no light iteration, no lights
+		renderObjects(pPriorityGrp->getSolidsBasic(), om, false, &lightList);
+		// Also render any objects which have receive shadows disabled
+		renderObjects(pPriorityGrp->getSolidsNoShadowReceive(), om, true);
+
+
+		// only perform this next part if we're in the 'normal' render stage, to avoid
+		// doing it during the render to texture
+		if (mIlluminationStage == IRS_NONE)
+		{
+			// Iterate over lights, render masked
+			LightList::const_iterator li, liend;
+			ShadowTextureList::iterator si, siend;
+			liend = mLightsAffectingFrustum.end();
+			siend = mShadowTextures.end();
+            si = mShadowTextures.begin();
+
+			for (li = mLightsAffectingFrustum.begin(); li != liend; ++li)
+			{
+				Light* l = *li;
+
+				if (l->getCastShadows() && si != siend)
+				{
+					// Store current shadow texture
+					mCurrentShadowTexture = si->getPointer();
+					// Get camera for current shadow texture
+					Camera *cam = mCurrentShadowTexture->getBuffer()->getRenderTarget()->getViewport(0)->getCamera();
+					// Hook up receiver texture
+					Pass* targetPass = mShadowTextureCustomReceiverPass ?
+						mShadowTextureCustomReceiverPass : mShadowReceiverPass;
+					targetPass->getTextureUnitState(0)->setTextureName(
+						mCurrentShadowTexture->getName());
+					// Hook up projection frustum
+					targetPass->getTextureUnitState(0)->setProjectiveTexturing(true, cam);
+					mAutoParamDataSource.setTextureProjector(cam);
+					// Remove any spot fader layer
+					if (targetPass->getNumTextureUnitStates() > 1 && 
+						targetPass->getTextureUnitState(1)->getTextureName() 
+							== "spot_shadow_fade.png")
+					{
+						// remove spot fader layer (should only be there if
+						// we previously used modulative shadows)
+						targetPass->removeTextureUnitState(1);
+					}
+					// Set lighting / blending modes
+					targetPass->setSceneBlending(SBF_ONE, SBF_ONE);
+					targetPass->setLightingEnabled(true);
+					targetPass->_load();
+
+					// increment shadow texture since used
+					++si;
+
+					mIlluminationStage = IRS_RENDER_RECEIVER_PASS;
+
+				}
+				else
+				{
+					mIlluminationStage = IRS_NONE;
+
+				}
+
+                // render lighting passes for this light
+                if (lightList.empty())
+                    lightList.push_back(l);
+                else
+                    lightList[0] = l;
+				renderObjects(pPriorityGrp->getSolidsDiffuseSpecular(), om, false, &lightList);
+
+			}// for each light
+
+			mIlluminationStage = IRS_NONE;
+
+			// Now render decal passes, no need to set lights as lighting will be disabled
+			renderObjects(pPriorityGrp->getSolidsDecal(), om, false);
+
+		}
+
+
+	}// for each priority
+
+	// Iterate again - variable name changed to appease gcc.
+	RenderQueueGroup::PriorityMapIterator groupIt2 = pGroup->getIterator();
+	while (groupIt2.hasMoreElements())
+	{
+		RenderPriorityGroup* pPriorityGrp = groupIt2.getNext();
+
+		// Do transparents (always descending sort)
+		renderObjects(pPriorityGrp->getTransparents(), 
+			QueuedRenderableCollection::OM_SORT_DESCENDING, true);
+
+	}// for each priority
+
+}
+//-----------------------------------------------------------------------
+void SceneManager::renderTextureShadowReceiverQueueGroupObjects(
+	RenderQueueGroup* pGroup, 
+	QueuedRenderableCollection::OrganisationMode om)
+{
+    static LightList nullLightList;
+
+    // Iterate through priorities
+    RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator();
+
+    // Override auto param ambient to force vertex programs to go full-bright
+    mAutoParamDataSource.setAmbientLightColour(ColourValue::White);
+    mDestRenderSystem->setAmbientLight(1, 1, 1);
+
+    while (groupIt.hasMoreElements())
+    {
+        RenderPriorityGroup* pPriorityGrp = groupIt.getNext();
+
+        // Do solids, override light list incase any vertex programs use them
+        renderObjects(pPriorityGrp->getSolidsBasic(), om, false, &nullLightList);
+
+        // Don't render transparents or passes which have shadow receipt disabled
+
+    }// for each priority
+
+    // reset ambient
+    mAutoParamDataSource.setAmbientLightColour(mAmbientLight);
+    mDestRenderSystem->setAmbientLight(mAmbientLight.r, mAmbientLight.g, mAmbientLight.b);
+
+}
+//-----------------------------------------------------------------------
+void SceneManager::SceneMgrQueuedRenderableVisitor::visit(const Renderable* r)
+{
+	// Give SM a chance to eliminate
+	if (targetSceneMgr->validateRenderableForRendering(mUsedPass, r))
+	{
+		// Render a single object, this will set up auto params if required
+		targetSceneMgr->renderSingleObject(r, mUsedPass, autoLights, manualLightList);
+	}
+}
+//-----------------------------------------------------------------------
+bool SceneManager::SceneMgrQueuedRenderableVisitor::visit(const Pass* p)
+{
+	// Give SM a chance to eliminate this pass
+	if (!targetSceneMgr->validatePassForRendering(p))
+		return false;
+
+	// Set pass, store the actual one used
+	mUsedPass = targetSceneMgr->_setPass(p);
+
+
+	return true;
+}
+//-----------------------------------------------------------------------
+void SceneManager::SceneMgrQueuedRenderableVisitor::visit(const RenderablePass* rp)
+{
+	// Skip this one if we're in transparency cast shadows mode & it doesn't
+	// Don't need to implement this one in the other visit methods since
+	// transparents are never grouped, always sorted
+	if (transparentShadowCastersMode && 
+		!rp->pass->getParent()->getParent()->getTransparencyCastsShadows())
+		return;
+
+	// Give SM a chance to eliminate
+	if (targetSceneMgr->validateRenderableForRendering(rp->pass, rp->renderable))
+	{
+		targetSceneMgr->_setPass(rp->pass);
+		targetSceneMgr->renderSingleObject(rp->renderable, rp->pass, autoLights, 
+			manualLightList);
+	}
+}
+//-----------------------------------------------------------------------
+bool SceneManager::validatePassForRendering(const Pass* pass)
+{
+    // Bypass if we're doing a texture shadow render and 
+    // this pass is after the first (only 1 pass needed for modulative shadow texture)
+	// Also bypass if passes above the first if render state changes are
+	// suppressed since we're not actually using this pass data anyway
+    if (!mSuppressShadows && mCurrentViewport->getShadowsEnabled() &&
+		isShadowTechniqueModulative() &&
+		(mIlluminationStage == IRS_RENDER_TO_TEXTURE ||
+        mIlluminationStage == IRS_RENDER_RECEIVER_PASS ||
+		mSuppressRenderStateChanges) && 
+        pass->getIndex() > 0)
+    {
+        return false;
+    }
+
+#ifdef GAMETOOLS_ILLUMINATION_MODULE
+	if(!pass->isActive())
+		return false;
+#endif
+
+    return true;
+}
+//-----------------------------------------------------------------------
+bool SceneManager::validateRenderableForRendering(const Pass* pass, const Renderable* rend)
+{
+    // Skip this renderable if we're doing modulative texture shadows, it casts shadows
+    // and we're doing the render receivers pass and we're not self-shadowing
+    if (!mSuppressShadows && mCurrentViewport->getShadowsEnabled() &&
+		isShadowTechniqueTextureBased() && 
+        mIlluminationStage == IRS_RENDER_RECEIVER_PASS && 
+        rend->getCastsShadows() && !mShadowTextureSelfShadow && 
+		isShadowTechniqueModulative())
+    {
+        return false;
+    }
+
+    return true;
+
+}
+//-----------------------------------------------------------------------
+void SceneManager::renderObjects(const QueuedRenderableCollection& objs, 
+								 QueuedRenderableCollection::OrganisationMode om, 
+								 bool doLightIteration, 
+                                 const LightList* manualLightList)
+{
+	mActiveQueuedRenderableVisitor->autoLights = doLightIteration;
+	mActiveQueuedRenderableVisitor->manualLightList = manualLightList;
+	mActiveQueuedRenderableVisitor->transparentShadowCastersMode = false;
+	// Use visitor
+	objs.acceptVisitor(mActiveQueuedRenderableVisitor, om);
+}
+//-----------------------------------------------------------------------
+void SceneManager::_renderQueueGroupObjects(RenderQueueGroup* pGroup, 
+										   QueuedRenderableCollection::OrganisationMode om)
+{
+	bool doShadows = 
+		pGroup->getShadowsEnabled() && 
+		mCurrentViewport->getShadowsEnabled() && 
+		!mSuppressShadows && !mSuppressRenderStateChanges;
+	
+    if (doShadows && mShadowTechnique == SHADOWTYPE_STENCIL_ADDITIVE)
+    {
+        // Additive stencil shadows in use
+        renderAdditiveStencilShadowedQueueGroupObjects(pGroup, om);
+    }
+    else if (doShadows && mShadowTechnique == SHADOWTYPE_STENCIL_MODULATIVE)
+    {
+        // Modulative stencil shadows in use
+        renderModulativeStencilShadowedQueueGroupObjects(pGroup, om);
+    }
+    else if (isShadowTechniqueTextureBased())
+    {
+        // Modulative texture shadows in use
+        if (mIlluminationStage == IRS_RENDER_TO_TEXTURE)
+        {
+            // Shadow caster pass
+            if (mCurrentViewport->getShadowsEnabled() &&
+                !mSuppressShadows && !mSuppressRenderStateChanges)
+            {
+                renderTextureShadowCasterQueueGroupObjects(pGroup, om);
+            }
+        }
+        else
+        {
+            // Ordinary + receiver pass
+            if (doShadows)
+			{
+				// Receiver pass(es)
+				if (isShadowTechniqueAdditive())
+				{
+					// Additive
+					renderAdditiveTextureShadowedQueueGroupObjects(pGroup, om);
+				}
+				else
+				{
+					// Modulative
+            		renderModulativeTextureShadowedQueueGroupObjects(pGroup, om);
+				}
+			}
+			else
+				renderBasicQueueGroupObjects(pGroup, om);
+        }
+    }
+    else
+    {
+        // No shadows, ordinary pass
+        renderBasicQueueGroupObjects(pGroup, om);
+    }
+
+
+}
+//-----------------------------------------------------------------------
+void SceneManager::renderBasicQueueGroupObjects(RenderQueueGroup* pGroup, 
+												QueuedRenderableCollection::OrganisationMode om)
+{
+    // Basic render loop
+    // Iterate through priorities
+    RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator();
+
+    while (groupIt.hasMoreElements())
+    {
+        RenderPriorityGroup* pPriorityGrp = groupIt.getNext();
+
+        // Sort the queue first
+        pPriorityGrp->sort(mCameraInProgress);
+
+        // Do solids
+        renderObjects(pPriorityGrp->getSolidsBasic(), om, true);
+        // Do transparents (always descending)
+        renderObjects(pPriorityGrp->getTransparents(), 
+			QueuedRenderableCollection::OM_SORT_DESCENDING, true);
+
+
+    }// for each priority
+}
+//-----------------------------------------------------------------------
+void SceneManager::renderTransparentShadowCasterObjects(
+	const QueuedRenderableCollection& objs, 
+	QueuedRenderableCollection::OrganisationMode om, bool doLightIteration,
+	const LightList* manualLightList)
+{
+	mActiveQueuedRenderableVisitor->transparentShadowCastersMode = true;
+	mActiveQueuedRenderableVisitor->autoLights = doLightIteration;
+	mActiveQueuedRenderableVisitor->manualLightList = manualLightList;
+	
+	// Sort descending (transparency)
+	objs.acceptVisitor(mActiveQueuedRenderableVisitor, 
+		QueuedRenderableCollection::OM_SORT_DESCENDING);
+
+	mActiveQueuedRenderableVisitor->transparentShadowCastersMode = false;
+}
+//-----------------------------------------------------------------------
+void SceneManager::renderSingleObject(const Renderable* rend, const Pass* pass, 
+                                      bool doLightIteration, const LightList* manualLightList)
+{
+    unsigned short numMatrices;
+    static RenderOperation ro;
+    static LightList localLightList;
+
+    // Set up rendering operation
+    // I know, I know, const_cast is nasty but otherwise it requires all internal
+    // state of the Renderable assigned to the rop to be mutable
+    const_cast<Renderable*>(rend)->getRenderOperation(ro);
+    ro.srcRenderable = rend;
+
+    // Set world transformation
+    rend->getWorldTransforms(mTempXform);
+    numMatrices = rend->getNumWorldTransforms();
+    if (numMatrices > 1)
+    {
+        mDestRenderSystem->_setWorldMatrices(mTempXform, numMatrices);
+    }
+    else
+    {
+        mDestRenderSystem->_setWorldMatrix(*mTempXform);
+    }
+
+    // Issue view / projection changes if any
+    useRenderableViewProjMode(rend);
+
+    if (!mSuppressRenderStateChanges)
+    {
+        bool passSurfaceAndLightParams = true;
+
+        if (pass->isProgrammable())
+        {
+            // Tell auto params object about the renderable change
+            mAutoParamDataSource.setCurrentRenderable(rend);
+            pass->_updateAutoParamsNoLights(mAutoParamDataSource);
+            if (pass->hasVertexProgram())
+            {
+                passSurfaceAndLightParams = pass->getVertexProgram()->getPassSurfaceAndLightStates();
+            }
+        }
+
+        // Reissue any texture gen settings which are dependent on view matrix
+        Pass::ConstTextureUnitStateIterator texIter =  pass->getTextureUnitStateIterator();
+        size_t unit = 0;
+        while(texIter.hasMoreElements())
+        {
+            TextureUnitState* pTex = texIter.getNext();
+            if (pTex->hasViewRelativeTextureCoordinateGeneration())
+            {
+                mDestRenderSystem->_setTextureUnitSettings(unit, *pTex);
+            }
+            ++unit;
+        }
+
+        // Sort out normalisation
+        mDestRenderSystem->setNormaliseNormals(rend->getNormaliseNormals());
+
+        // Set up the solid / wireframe override
+		// Precedence is Camera, Object, Material
+		// Camera might not override object if not overrideable
+		PolygonMode reqMode = pass->getPolygonMode();
+		if (rend->getPolygonModeOverrideable())
+		{
+            PolygonMode camPolyMode = mCameraInProgress->getPolygonMode();
+			// check camera detial only when render detail is overridable
+			if (reqMode > camPolyMode)
+			{
+				// only downgrade detail; if cam says wireframe we don't go up to solid
+				reqMode = camPolyMode;
+			}
+		}
+		mDestRenderSystem->_setPolygonMode(reqMode);
+
+		mDestRenderSystem->setClipPlanes(rend->getClipPlanes());
+
+		if (doLightIteration)
+		{
+			// Here's where we issue the rendering operation to the render system
+			// Note that we may do this once per light, therefore it's in a loop
+			// and the light parameters are updated once per traversal through the
+			// loop
+			const LightList& rendLightList = rend->getLights();
+			bool iteratePerLight = pass->getIteratePerLight();
+			size_t numIterations = iteratePerLight ? rendLightList.size() : 1;
+			const LightList* pLightListToUse;
+			for (size_t i = 0; i < numIterations; ++i)
+			{
+				// Determine light list to use
+				if (iteratePerLight)
+				{
+					// Change the only element of local light list to be
+					// the light at index i
+					localLightList.clear();
+					// Check whether we need to filter this one out
+					if (pass->getRunOnlyForOneLightType() && 
+						pass->getOnlyLightType() != rendLightList[i]->getType())
+					{
+						// Skip
+						continue;
+					}
+
+					localLightList.push_back(rendLightList[i]);
+					pLightListToUse = &localLightList;
+				}
+				else
+				{
+					// Use complete light list
+					pLightListToUse = &rendLightList;
+				}
+
+
+				// Do we need to update GPU program parameters?
+				if (pass->isProgrammable())
+				{
+					// Update any automatic gpu params for lights
+					// Other bits of information will have to be looked up
+					mAutoParamDataSource.setCurrentLightList(pLightListToUse);
+					pass->_updateAutoParamsLightsOnly(mAutoParamDataSource);
+					// NOTE: We MUST bind parameters AFTER updating the autos
+					// TEST
+					if (pass->hasVertexProgram())
+					{
+						mDestRenderSystem->bindGpuProgramParameters(GPT_VERTEX_PROGRAM, 
+							pass->getVertexProgramParameters());
+					}
+					if (pass->hasFragmentProgram())
+					{
+						mDestRenderSystem->bindGpuProgramParameters(GPT_FRAGMENT_PROGRAM, 
+							pass->getFragmentProgramParameters());
+					}
+				}
+				// Do we need to update light states? 
+				// Only do this if fixed-function vertex lighting applies
+				if (pass->getLightingEnabled() && passSurfaceAndLightParams)
+				{
+					mDestRenderSystem->_useLights(*pLightListToUse, pass->getMaxSimultaneousLights());
+				}
+				// issue the render op		
+				// nfz: check for gpu_multipass
+				mDestRenderSystem->setCurrentPassIterationCount(pass->getPassIterationCount());
+				mDestRenderSystem->_render(ro);
+			} // possibly iterate per light
+		}
+		else // no automatic light processing
+		{
+			// Do we need to update GPU program parameters?
+			if (pass->isProgrammable())
+			{
+				// Do we have a manual light list?
+				if (manualLightList)
+				{
+					// Update any automatic gpu params for lights
+					mAutoParamDataSource.setCurrentLightList(manualLightList);
+					pass->_updateAutoParamsLightsOnly(mAutoParamDataSource);
+				}
+
+				if (pass->hasVertexProgram())
+				{
+					mDestRenderSystem->bindGpuProgramParameters(GPT_VERTEX_PROGRAM, 
+						pass->getVertexProgramParameters());
+				}
+				if (pass->hasFragmentProgram())
+				{
+					mDestRenderSystem->bindGpuProgramParameters(GPT_FRAGMENT_PROGRAM, 
+						pass->getFragmentProgramParameters());
+				}
+			}
+
+			// Use manual lights if present, and not using vertex programs that don't use fixed pipeline
+			if (manualLightList && 
+				pass->getLightingEnabled() && passSurfaceAndLightParams)
+			{
+				mDestRenderSystem->_useLights(*manualLightList, pass->getMaxSimultaneousLights());
+			}
+			// issue the render op		
+			// nfz: set up multipass rendering
+			mDestRenderSystem->setCurrentPassIterationCount(pass->getPassIterationCount());
+			mDestRenderSystem->_render(ro);
+		}
+
+	}
+	else // mSuppressRenderStateChanges
+	{
+		// Just render
+		mDestRenderSystem->setCurrentPassIterationCount(1);
+		mDestRenderSystem->_render(ro);
+	}
+	
+    // Reset view / projection changes if any
+    resetViewProjMode();
+
+}
+//-----------------------------------------------------------------------
+void SceneManager::setAmbientLight(const ColourValue& colour)
+{
+    mAmbientLight = colour;
+}
+//-----------------------------------------------------------------------
+const ColourValue& SceneManager::getAmbientLight(void) const
+{
+    return mAmbientLight;
+}
+//-----------------------------------------------------------------------
+ViewPoint SceneManager::getSuggestedViewpoint(bool random)
+{
+    // By default return the origin
+    ViewPoint vp;
+    vp.position = Vector3::ZERO;
+    vp.orientation = Quaternion::IDENTITY;
+    return vp;
+}
+//-----------------------------------------------------------------------
+void SceneManager::setFog(FogMode mode, const ColourValue& colour, Real density, Real start, Real end)
+{
+    mFogMode = mode;
+    mFogColour = colour;
+    mFogStart = start;
+    mFogEnd = end;
+    mFogDensity = density;
+}
+//-----------------------------------------------------------------------
+FogMode SceneManager::getFogMode(void) const
+{
+    return mFogMode;
+}
+//-----------------------------------------------------------------------
+const ColourValue& SceneManager::getFogColour(void) const
+{
+    return mFogColour;
+}
+//-----------------------------------------------------------------------
+Real SceneManager::getFogStart(void) const
+{
+    return mFogStart;
+}
+//-----------------------------------------------------------------------
+Real SceneManager::getFogEnd(void) const
+{
+    return mFogEnd;
+}
+//-----------------------------------------------------------------------
+Real SceneManager::getFogDensity(void) const
+{
+    return mFogDensity;
+}
+//-----------------------------------------------------------------------
+BillboardSet* SceneManager::createBillboardSet(const String& name, unsigned int poolSize)
+{
+	NameValuePairList params;
+	params["poolSize"] = StringConverter::toString(poolSize);
+	return static_cast<BillboardSet*>(
+		createMovableObject(name, BillboardSetFactory::FACTORY_TYPE_NAME, &params));
+}
+//-----------------------------------------------------------------------
+BillboardSet* SceneManager::getBillboardSet(const String& name)
+{
+	return static_cast<BillboardSet*>(
+		getMovableObject(name, BillboardSetFactory::FACTORY_TYPE_NAME));
+}
+//-----------------------------------------------------------------------
+void SceneManager::destroyBillboardSet(BillboardSet* set)
+{
+	destroyMovableObject(set);
+}
+//-----------------------------------------------------------------------
+void SceneManager::destroyBillboardSet(const String& name)
+{
+	destroyMovableObject(name, BillboardSetFactory::FACTORY_TYPE_NAME);
+}
+//-----------------------------------------------------------------------
+void SceneManager::setDisplaySceneNodes(bool display)
+{
+    mDisplayNodes = display;
+}
+//-----------------------------------------------------------------------
+Animation* SceneManager::createAnimation(const String& name, Real length)
+{
+    // Check name not used
+    if (mAnimationsList.find(name) != mAnimationsList.end())
+    {
+        OGRE_EXCEPT(
+            Exception::ERR_DUPLICATE_ITEM,
+            "An animation with the name " + name + " already exists",
+            "SceneManager::createAnimation" );
+    }
+
+    Animation* pAnim = new Animation(name, length);
+    mAnimationsList[name] = pAnim;
+    return pAnim;
+}
+//-----------------------------------------------------------------------
+Animation* SceneManager::getAnimation(const String& name) const
+{
+    AnimationList::const_iterator i = mAnimationsList.find(name);
+    if (i == mAnimationsList.end())
+    {
+        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 
+            "Cannot find animation with name " + name, 
+            "SceneManager::getAnimation");
+    }
+    return i->second;
+}
+//-----------------------------------------------------------------------
+void SceneManager::destroyAnimation(const String& name)
+{
+    // Also destroy any animation states referencing this animation
+	mAnimationStates.removeAnimationState(name);
+
+    AnimationList::iterator i = mAnimationsList.find(name);
+    if (i == mAnimationsList.end())
+    {
+        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 
+            "Cannot find animation with name " + name, 
+            "SceneManager::getAnimation");
+    }
+
+    // Free memory
+    delete i->second;
+
+    mAnimationsList.erase(i);
+
+
+}
+//-----------------------------------------------------------------------
+void SceneManager::destroyAllAnimations(void)
+{
+    // Destroy all states too, since they cannot reference destroyed animations
+    destroyAllAnimationStates();
+
+    AnimationList::iterator i;
+    for (i = mAnimationsList.begin(); i != mAnimationsList.end(); ++i)
+    {
+        // destroy
+        delete i->second;
+    }
+    mAnimationsList.clear();
+}
+//-----------------------------------------------------------------------
+AnimationState* SceneManager::createAnimationState(const String& animName)
+{
+
+    // Get animation, this will throw an exception if not found
+    Animation* anim = getAnimation(animName);
+
+    // Create new state
+	return mAnimationStates.createAnimationState(animName, 0, anim->getLength());
+
+}
+//-----------------------------------------------------------------------
+AnimationState* SceneManager::getAnimationState(const String& animName) 
+{
+	return mAnimationStates.getAnimationState(animName);
+
+}
+//-----------------------------------------------------------------------
+void SceneManager::destroyAnimationState(const String& name)
+{
+	mAnimationStates.removeAnimationState(name);
+}
+//-----------------------------------------------------------------------
+void SceneManager::destroyAllAnimationStates(void)
+{
+    mAnimationStates.removeAllAnimationStates();
+}
+//-----------------------------------------------------------------------
+void SceneManager::_applySceneAnimations(void)
+{
+    ConstEnabledAnimationStateIterator stateIt = mAnimationStates.getEnabledAnimationStateIterator();
+
+    while (stateIt.hasMoreElements())
+    {
+        const AnimationState* state = stateIt.getNext();
+        Animation* anim = getAnimation(state->getAnimationName());
+
+        // Reset any nodes involved
+        // NB this excludes blended animations
+        Animation::NodeTrackIterator nodeTrackIt = anim->getNodeTrackIterator();
+        while(nodeTrackIt.hasMoreElements())
+        {
+            Node* nd = nodeTrackIt.getNext()->getAssociatedNode();
+            nd->resetToInitialState();
+        }
+
+        Animation::NumericTrackIterator numTrackIt = anim->getNumericTrackIterator();
+        while(numTrackIt.hasMoreElements())
+        {
+            numTrackIt.getNext()->getAssociatedAnimable()->resetToBaseValue();
+        }
+
+        // Apply the animation
+        anim->apply(state->getTimePosition(), state->getWeight());
+    }
+
+
+}
+//---------------------------------------------------------------------
+void SceneManager::manualRender(RenderOperation* rend, 
+                                Pass* pass, Viewport* vp, const Matrix4& worldMatrix, 
+                                const Matrix4& viewMatrix, const Matrix4& projMatrix, 
+                                bool doBeginEndFrame) 
+{
+    mDestRenderSystem->_setViewport(vp);
+    mDestRenderSystem->_setWorldMatrix(worldMatrix);
+    mDestRenderSystem->_setViewMatrix(viewMatrix);
+    mDestRenderSystem->_setProjectionMatrix(projMatrix);
+
+    if (doBeginEndFrame)
+        mDestRenderSystem->_beginFrame();
+
+    _setPass(pass);
+    mDestRenderSystem->_render(*rend);
+
+    if (doBeginEndFrame)
+        mDestRenderSystem->_endFrame();
+
+}
+//---------------------------------------------------------------------
+void SceneManager::useRenderableViewProjMode(const Renderable* pRend)
+{
+    // Check view matrix
+    bool useIdentityView = pRend->useIdentityView();
+    if (useIdentityView)
+    {
+        // Using identity view now, change it
+        mDestRenderSystem->_setViewMatrix(Matrix4::IDENTITY);
+        mResetIdentityView = true;
+    }
+
+    bool useIdentityProj = pRend->useIdentityProjection();
+    if (useIdentityProj)
+    {
+        // Use identity projection matrix, still need to take RS depth into account.
+        Matrix4 mat;
+        mDestRenderSystem->_convertProjectionMatrix(Matrix4::IDENTITY, mat);
+        mDestRenderSystem->_setProjectionMatrix(mat);
+
+        mResetIdentityProj = true;
+    }
+
+    
+}
+//---------------------------------------------------------------------
+void SceneManager::resetViewProjMode(void)
+{
+    if (mResetIdentityView)
+    {
+        // Coming back to normal from identity view
+        mDestRenderSystem->_setViewMatrix(mCameraInProgress->getViewMatrix(true));
+        mResetIdentityView = false;
+    }
+    
+    if (mResetIdentityProj)
+    {
+        // Coming back from flat projection
+        mDestRenderSystem->_setProjectionMatrix(mCameraInProgress->getProjectionMatrixRS());
+        mResetIdentityProj = false;
+    }
+    
+
+}
+//---------------------------------------------------------------------
+void SceneManager::_queueSkiesForRendering(Camera* cam)
+{
+    // Update nodes
+    // Translate the box by the camera position (constant distance)
+    if (mSkyPlaneNode)
+    {
+        // The plane position relative to the camera has already been set up
+        mSkyPlaneNode->setPosition(cam->getDerivedPosition());
+    }
+
+    if (mSkyBoxNode)
+    {
+        mSkyBoxNode->setPosition(cam->getDerivedPosition());
+    }
+
+    if (mSkyDomeNode)
+    {
+        mSkyDomeNode->setPosition(cam->getDerivedPosition());
+    }
+
+    uint8 qid;
+    if (mSkyPlaneEnabled)
+    {
+        qid = mSkyPlaneDrawFirst? 
+RENDER_QUEUE_SKIES_EARLY : RENDER_QUEUE_SKIES_LATE;
+        getRenderQueue()->addRenderable(mSkyPlaneEntity->getSubEntity(0), qid, OGRE_RENDERABLE_DEFAULT_PRIORITY);
+    }
+
+    uint plane;
+    if (mSkyBoxEnabled)
+    {
+        qid = mSkyBoxDrawFirst? 
+RENDER_QUEUE_SKIES_EARLY : RENDER_QUEUE_SKIES_LATE;
+
+        for (plane = 0; plane < 6; ++plane)
+        {
+            getRenderQueue()->addRenderable(
+                mSkyBoxEntity[plane]->getSubEntity(0), qid, OGRE_RENDERABLE_DEFAULT_PRIORITY);
+        }
+    }
+
+    if (mSkyDomeEnabled)
+    {
+        qid = mSkyDomeDrawFirst? 
+RENDER_QUEUE_SKIES_EARLY : RENDER_QUEUE_SKIES_LATE;
+
+        for (plane = 0; plane < 5; ++plane)
+        {
+            getRenderQueue()->addRenderable(
+                mSkyDomeEntity[plane]->getSubEntity(0), qid, OGRE_RENDERABLE_DEFAULT_PRIORITY);
+        }
+    }
+}
+//---------------------------------------------------------------------
+void SceneManager::addRenderQueueListener(RenderQueueListener* newListener)
+{
+    mRenderQueueListeners.push_back(newListener);
+}
+//---------------------------------------------------------------------
+void SceneManager::removeRenderQueueListener(RenderQueueListener* delListener)
+{
+    RenderQueueListenerList::iterator i, iend;
+    iend = mRenderQueueListeners.end();
+    for (i = mRenderQueueListeners.begin(); i != iend; ++i)
+    {
+        if (*i == delListener)
+        {
+            mRenderQueueListeners.erase(i);
+            break;
+        }
+    }
+
+}
+//---------------------------------------------------------------------
+void SceneManager::addShadowListener(ShadowListener* newListener)
+{
+    mShadowListeners.push_back(newListener);
+}
+//---------------------------------------------------------------------
+void SceneManager::removeShadowListener(ShadowListener* delListener)
+{
+    ShadowListenerList::iterator i, iend;
+    iend = mShadowListeners.end();
+    for (i = mShadowListeners.begin(); i != iend; ++i)
+    {
+        if (*i == delListener)
+        {
+            mShadowListeners.erase(i);
+            break;
+        }
+    }
+
+}
+//---------------------------------------------------------------------
+bool SceneManager::fireRenderQueueStarted(uint8 id, const String& invocation)
+{
+    RenderQueueListenerList::iterator i, iend;
+    bool skip = false;
+
+    iend = mRenderQueueListeners.end();
+    for (i = mRenderQueueListeners.begin(); i != iend; ++i)
+    {
+        (*i)->renderQueueStarted(id, invocation, skip);
+    }
+    return skip;
+}
+//---------------------------------------------------------------------
+bool SceneManager::fireRenderQueueEnded(uint8 id, const String& invocation)
+{
+    RenderQueueListenerList::iterator i, iend;
+    bool repeat = false;
+
+    iend = mRenderQueueListeners.end();
+    for (i = mRenderQueueListeners.begin(); i != iend; ++i)
+    {
+        (*i)->renderQueueEnded(id, invocation, repeat);
+    }
+    return repeat;
+}
+//---------------------------------------------------------------------
+void SceneManager::fireShadowTexturesUpdated(size_t numberOfShadowTextures)
+{
+    ShadowListenerList::iterator i, iend;
+
+    iend = mShadowListeners.end();
+    for (i = mShadowListeners.begin(); i != iend; ++i)
+    {
+        (*i)->shadowTexturesUpdated(numberOfShadowTextures);
+    }
+}
+//---------------------------------------------------------------------
+void SceneManager::fireShadowTexturesPreCaster(Light* light, Camera* camera)
+{
+    ShadowListenerList::iterator i, iend;
+
+    iend = mShadowListeners.end();
+    for (i = mShadowListeners.begin(); i != iend; ++i)
+    {
+        (*i)->shadowTextureCasterPreViewProj(light, camera);
+    }
+}
+//---------------------------------------------------------------------
+void SceneManager::fireShadowTexturesPreReceiver(Light* light, Frustum* f)
+{
+    ShadowListenerList::iterator i, iend;
+
+    iend = mShadowListeners.end();
+    for (i = mShadowListeners.begin(); i != iend; ++i)
+    {
+        (*i)->shadowTextureReceiverPreViewProj(light, f);
+    }
+}
+//---------------------------------------------------------------------
+void SceneManager::setViewport(Viewport* vp)
+{
+    mCurrentViewport = vp;
+    // Set viewport in render system
+    mDestRenderSystem->_setViewport(vp);
+	// Set the active material scheme for this viewport
+	MaterialManager::getSingleton().setActiveScheme(vp->getMaterialScheme());
+}
+//---------------------------------------------------------------------
+void SceneManager::showBoundingBoxes(bool bShow) 
+{
+    mShowBoundingBoxes = bShow;
+}
+//---------------------------------------------------------------------
+bool SceneManager::getShowBoundingBoxes() const
+{
+    return mShowBoundingBoxes;
+}
+//---------------------------------------------------------------------
+void SceneManager::_notifyAutotrackingSceneNode(SceneNode* node, bool autoTrack)
+{
+    if (autoTrack)
+    {
+        mAutoTrackingSceneNodes.insert(node);
+    }
+    else
+    {
+        mAutoTrackingSceneNodes.erase(node);
+    }
+}
+//---------------------------------------------------------------------
+void SceneManager::setShadowTechnique(ShadowTechnique technique)
+{
+    mShadowTechnique = technique;
+    if (isShadowTechniqueStencilBased())
+    {
+        // Firstly check that we  have a stencil
+        // Otherwise forget it
+        if (!mDestRenderSystem->getCapabilities()->hasCapability(RSC_HWSTENCIL))
+        {
+            LogManager::getSingleton().logMessage(
+                "WARNING: Stencil shadows were requested, but this device does not "
+                "have a hardware stencil. Shadows disabled.");
+            mShadowTechnique = SHADOWTYPE_NONE;
+        }
+        else if (mShadowIndexBuffer.isNull())
+        {
+            // Create an estimated sized shadow index buffer
+            mShadowIndexBuffer = HardwareBufferManager::getSingleton().
+                createIndexBuffer(HardwareIndexBuffer::IT_16BIT, 
+                mShadowIndexBufferSize, 
+                HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE, 
+                false);
+            // tell all meshes to prepare shadow volumes
+            MeshManager::getSingleton().setPrepareAllMeshesForShadowVolumes(true);
+        }
+	}
+
+    if (isShadowTechniqueTextureBased())
+    {
+        createShadowTextures(mShadowTextureSize, mShadowTextureCount, mShadowTextureFormat);
+    }
+    else
+    {
+        // Destroy shadow textures to optimise resource usage
+        destroyShadowTextures();
+    }
+
+}
+//---------------------------------------------------------------------
+void SceneManager::_suppressShadows(bool suppress)
+{
+	mSuppressShadows = suppress;
+}
+//---------------------------------------------------------------------
+void SceneManager::_suppressRenderStateChanges(bool suppress)
+{
+	mSuppressRenderStateChanges = suppress;
+}
+//---------------------------------------------------------------------
+void SceneManager::updateRenderQueueSplitOptions(void)
+{
+	if (isShadowTechniqueStencilBased())
+	{
+		// Casters can always be receivers
+		getRenderQueue()->setShadowCastersCannotBeReceivers(false);
+	}
+	else // texture based
+	{
+		getRenderQueue()->setShadowCastersCannotBeReceivers(!mShadowTextureSelfShadow);
+	}
+
+	if (isShadowTechniqueAdditive() && mCurrentViewport->getShadowsEnabled())
+	{
+		// Additive lighting, we need to split everything by illumination stage
+		getRenderQueue()->setSplitPassesByLightingType(true);
+	}
+	else
+	{
+		getRenderQueue()->setSplitPassesByLightingType(false);
+	}
+
+	if (isShadowTechniqueInUse() && mCurrentViewport->getShadowsEnabled())
+	{
+		// Tell render queue to split off non-shadowable materials
+		getRenderQueue()->setSplitNoShadowPasses(true);
+	}
+	else
+	{
+		getRenderQueue()->setSplitNoShadowPasses(false);
+	}
+
+
+}
+//---------------------------------------------------------------------
+void SceneManager::updateRenderQueueGroupSplitOptions(RenderQueueGroup* group, 
+	bool suppressShadows, bool suppressRenderState)
+{
+	if (isShadowTechniqueStencilBased())
+	{
+		// Casters can always be receivers
+		group->setShadowCastersCannotBeReceivers(false);
+	}
+	else if (isShadowTechniqueTextureBased()) 
+	{
+		group->setShadowCastersCannotBeReceivers(!mShadowTextureSelfShadow);
+	}
+
+	if (!suppressShadows && mCurrentViewport->getShadowsEnabled() &&
+		isShadowTechniqueAdditive())
+	{
+		// Additive lighting, we need to split everything by illumination stage
+		group->setSplitPassesByLightingType(true);
+	}
+	else
+	{
+		group->setSplitPassesByLightingType(false);
+	}
+
+	if (!suppressShadows && mCurrentViewport->getShadowsEnabled() 
+		&& isShadowTechniqueInUse())
+	{
+		// Tell render queue to split off non-shadowable materials
+		group->setSplitNoShadowPasses(true);
+	}
+	else
+	{
+		group->setSplitNoShadowPasses(false);
+	}
+
+
+}
+//---------------------------------------------------------------------
+void SceneManager::findLightsAffectingFrustum(const Camera* camera)
+{
+    // Basic iteration for this SM
+    mLightsAffectingFrustum.clear();
+    Sphere sphere;
+	MovableObjectIterator it = 
+		getMovableObjectIterator(LightFactory::FACTORY_TYPE_NAME);
+    while(it.hasMoreElements())
+    {
+        Light* l = static_cast<Light*>(it.getNext());
+		if (l->isVisible())
+		{
+			if (l->getType() == Light::LT_DIRECTIONAL)
+			{
+				// Always visible
+				mLightsAffectingFrustum.push_back(l);
+			}
+			else
+			{
+				// NB treating spotlight as point for simplicity
+				// Just see if the lights attenuation range is within the frustum
+				sphere.setCenter(l->getDerivedPosition());
+				sphere.setRadius(l->getAttenuationRange());
+				if (camera->isVisible(sphere))
+				{
+					mLightsAffectingFrustum.push_back(l);
+				}
+
+			}
+		}
+    }
+
+}
+//---------------------------------------------------------------------
+bool SceneManager::ShadowCasterSceneQueryListener::queryResult(
+    MovableObject* object)
+{
+    if (object->getCastShadows() && object->isVisible() && 
+		mSceneMgr->isRenderQueueToBeProcessed(object->getRenderQueueGroup()))
+    {
+        if (mFarDistSquared)
+        {
+            // Check object is within the shadow far distance
+            Vector3 toObj = object->getParentNode()->_getDerivedPosition() 
+                - mCamera->getDerivedPosition();
+            Real radius = object->getWorldBoundingSphere().getRadius();
+            Real dist =  toObj.squaredLength();               
+            if (dist - (radius * radius) > mFarDistSquared)
+            {
+                // skip, beyond max range
+                return true;
+            }
+        }
+
+        // If the object is in the frustum, we can always see the shadow
+        if (mCamera->isVisible(object->getWorldBoundingBox()))
+        {
+            mCasterList->push_back(object);
+            return true;
+        }
+
+        // Otherwise, object can only be casting a shadow into our view if
+        // the light is outside the frustum (or it's a directional light, 
+        // which are always outside), and the object is intersecting
+        // on of the volumes formed between the edges of the frustum and the
+        // light
+        if (!mIsLightInFrustum || mLight->getType() == Light::LT_DIRECTIONAL)
+        {
+            // Iterate over volumes
+            PlaneBoundedVolumeList::const_iterator i, iend;
+            iend = mLightClipVolumeList->end();
+            for (i = mLightClipVolumeList->begin(); i != iend; ++i)
+            {
+                if (i->intersects(object->getWorldBoundingBox()))
+                {
+                    mCasterList->push_back(object);
+                    return true;
+                }
+
+            }
+
+        }
+    }
+    return true;
+}
+//---------------------------------------------------------------------
+bool SceneManager::ShadowCasterSceneQueryListener::queryResult(
+    SceneQuery::WorldFragment* fragment)
+{
+    // don't deal with world geometry
+    return true;
+}
+//---------------------------------------------------------------------
+const SceneManager::ShadowCasterList& SceneManager::findShadowCastersForLight(
+    const Light* light, const Camera* camera)
+{
+    mShadowCasterList.clear();
+
+    if (light->getType() == Light::LT_DIRECTIONAL)
+    {
+        // Basic AABB query encompassing the frustum and the extrusion of it
+        AxisAlignedBox aabb;
+        const Vector3* corners = camera->getWorldSpaceCorners();
+        Vector3 min, max;
+        Vector3 extrude = light->getDerivedDirection() * -mShadowDirLightExtrudeDist;
+        // do first corner
+        min = max = corners[0];
+        min.makeFloor(corners[0] + extrude);
+        max.makeCeil(corners[0] + extrude);
+        for (size_t c = 1; c < 8; ++c)
+        {
+            min.makeFloor(corners[c]);
+            max.makeCeil(corners[c]);
+            min.makeFloor(corners[c] + extrude);
+            max.makeCeil(corners[c] + extrude);
+        }
+        aabb.setExtents(min, max);
+
+        if (!mShadowCasterAABBQuery)
+            mShadowCasterAABBQuery = createAABBQuery(aabb);
+        else
+            mShadowCasterAABBQuery->setBox(aabb);
+        // Execute, use callback
+        mShadowCasterQueryListener->prepare(false, 
+            &(light->_getFrustumClipVolumes(camera)), 
+            light, camera, &mShadowCasterList, mShadowFarDistSquared);
+        mShadowCasterAABBQuery->execute(mShadowCasterQueryListener);
+
+
+    }
+    else
+    {
+        Sphere s(light->getDerivedPosition(), light->getAttenuationRange());
+        // eliminate early if camera cannot see light sphere
+        if (camera->isVisible(s))
+        {
+            if (!mShadowCasterSphereQuery)
+                mShadowCasterSphereQuery = createSphereQuery(s);
+            else
+                mShadowCasterSphereQuery->setSphere(s);
+
+            // Determine if light is inside or outside the frustum
+            bool lightInFrustum = camera->isVisible(light->getDerivedPosition());
+            const PlaneBoundedVolumeList* volList = 0;
+            if (!lightInFrustum)
+            {
+                // Only worth building an external volume list if
+                // light is outside the frustum
+                volList = &(light->_getFrustumClipVolumes(camera));
+            }
+
+            // Execute, use callback
+            mShadowCasterQueryListener->prepare(lightInFrustum, 
+                volList, light, camera, &mShadowCasterList, mShadowFarDistSquared);
+            mShadowCasterSphereQuery->execute(mShadowCasterQueryListener);
+
+        }
+
+    }
+
+
+    return mShadowCasterList;
+}
+//---------------------------------------------------------------------
+void SceneManager::initShadowVolumeMaterials(void)
+{
+    /* This should have been set in the SceneManager constructor, but if you
+       created the SceneManager BEFORE the Root object, you will need to call
+       SceneManager::_setDestinationRenderSystem manually.
+     */
+    assert( mDestRenderSystem );
+
+    if (mShadowMaterialInitDone)
+        return;
+
+    if (!mShadowDebugPass)
+    {
+        MaterialPtr matDebug = 
+            MaterialManager::getSingleton().getByName("Ogre/Debug/ShadowVolumes");
+        if (matDebug.isNull())
+        {
+            // Create
+            matDebug = MaterialManager::getSingleton().create(
+                "Ogre/Debug/ShadowVolumes", 
+                ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME);
+            mShadowDebugPass = matDebug->getTechnique(0)->getPass(0);
+            mShadowDebugPass->setSceneBlending(SBT_ADD); 
+            mShadowDebugPass->setLightingEnabled(false);
+            mShadowDebugPass->setDepthWriteEnabled(false);
+            TextureUnitState* t = mShadowDebugPass->createTextureUnitState();
+            t->setColourOperationEx(LBX_MODULATE, LBS_MANUAL, LBS_CURRENT, 
+                ColourValue(0.7, 0.0, 0.2));
+            mShadowDebugPass->setCullingMode(CULL_NONE);
+
+            if (mDestRenderSystem->getCapabilities()->hasCapability(
+                RSC_VERTEX_PROGRAM))
+            {
+                ShadowVolumeExtrudeProgram::initialise();
+
+                // Enable the (infinite) point light extruder for now, just to get some params
+                mShadowDebugPass->setVertexProgram(
+                    ShadowVolumeExtrudeProgram::programNames[ShadowVolumeExtrudeProgram::POINT_LIGHT]);
+                mInfiniteExtrusionParams = 
+                    mShadowDebugPass->getVertexProgramParameters();
+                mInfiniteExtrusionParams->setAutoConstant(0, 
+                    GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
+                mInfiniteExtrusionParams->setAutoConstant(4, 
+                    GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE);
+            }	
+            matDebug->compile();
+
+        }
+        else
+        {
+            mShadowDebugPass = matDebug->getTechnique(0)->getPass(0);
+
+            if (mDestRenderSystem->getCapabilities()->hasCapability(RSC_VERTEX_PROGRAM))
+            {
+                mInfiniteExtrusionParams = mShadowDebugPass->getVertexProgramParameters();
+            }
+        }
+    }
+
+    if (!mShadowStencilPass)
+    {
+
+        MaterialPtr matStencil = MaterialManager::getSingleton().getByName(
+            "Ogre/StencilShadowVolumes");
+        if (matStencil.isNull())
+        {
+            // Init
+            matStencil = MaterialManager::getSingleton().create(
+                "Ogre/StencilShadowVolumes",
+                ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME);
+            mShadowStencilPass = matStencil->getTechnique(0)->getPass(0);
+
+            if (mDestRenderSystem->getCapabilities()->hasCapability(
+                RSC_VERTEX_PROGRAM))
+            {
+
+                // Enable the finite point light extruder for now, just to get some params
+                mShadowStencilPass->setVertexProgram(
+                    ShadowVolumeExtrudeProgram::programNames[ShadowVolumeExtrudeProgram::POINT_LIGHT_FINITE]);
+                mFiniteExtrusionParams = 
+                    mShadowStencilPass->getVertexProgramParameters();
+                mFiniteExtrusionParams->setAutoConstant(0, 
+                    GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
+                mFiniteExtrusionParams->setAutoConstant(4, 
+                    GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE);
+                // Note extra parameter
+                mFiniteExtrusionParams->setAutoConstant(5, 
+                    GpuProgramParameters::ACT_SHADOW_EXTRUSION_DISTANCE);
+            }
+            matStencil->compile();
+            // Nothing else, we don't use this like a 'real' pass anyway,
+            // it's more of a placeholder
+        }
+        else
+        {
+            mShadowStencilPass = matStencil->getTechnique(0)->getPass(0);
+
+            if (mDestRenderSystem->getCapabilities()->hasCapability(RSC_VERTEX_PROGRAM))
+            {
+                mFiniteExtrusionParams = mShadowStencilPass->getVertexProgramParameters();
+            }
+        }
+    }
+
+
+
+
+    if (!mShadowModulativePass)
+    {
+
+        MaterialPtr matModStencil = MaterialManager::getSingleton().getByName(
+            "Ogre/StencilShadowModulationPass");
+        if (matModStencil.isNull())
+        {
+            // Init
+            matModStencil = MaterialManager::getSingleton().create(
+                "Ogre/StencilShadowModulationPass",
+                ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME);
+            mShadowModulativePass = matModStencil->getTechnique(0)->getPass(0);
+            mShadowModulativePass->setSceneBlending(SBF_DEST_COLOUR, SBF_ZERO); 
+            mShadowModulativePass->setLightingEnabled(false);
+            mShadowModulativePass->setDepthWriteEnabled(false);
+            mShadowModulativePass->setDepthCheckEnabled(false);
+            TextureUnitState* t = mShadowModulativePass->createTextureUnitState();
+            t->setColourOperationEx(LBX_MODULATE, LBS_MANUAL, LBS_CURRENT, 
+                mShadowColour);
+            mShadowModulativePass->setCullingMode(CULL_NONE);
+        }
+        else
+        {
+            mShadowModulativePass = matModStencil->getTechnique(0)->getPass(0);
+        }
+    }
+
+    // Also init full screen quad while we're at it
+    if (!mFullScreenQuad)
+    {
+        mFullScreenQuad = new Rectangle2D();
+        mFullScreenQuad->setCorners(-1,1,1,-1);
+    }
+
+    // Also init shadow caster material for texture shadows
+    if (!mShadowCasterPlainBlackPass)
+    {
+        MaterialPtr matPlainBlack = MaterialManager::getSingleton().getByName(
+            "Ogre/TextureShadowCaster");
+        if (matPlainBlack.isNull())
+        {
+            matPlainBlack = MaterialManager::getSingleton().create(
+                "Ogre/TextureShadowCaster",
+                ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME);
+            mShadowCasterPlainBlackPass = matPlainBlack->getTechnique(0)->getPass(0);
+            // Lighting has to be on, because we need shadow coloured objects
+            // Note that because we can't predict vertex programs, we'll have to
+            // bind light values to those, and so we bind White to ambient
+            // reflectance, and we'll set the ambient colour to the shadow colour
+            mShadowCasterPlainBlackPass->setAmbient(ColourValue::White);
+            mShadowCasterPlainBlackPass->setDiffuse(ColourValue::Black);
+            mShadowCasterPlainBlackPass->setSelfIllumination(ColourValue::Black);
+            mShadowCasterPlainBlackPass->setSpecular(ColourValue::Black);
+			// Override fog
+			mShadowCasterPlainBlackPass->setFog(true, FOG_NONE);
+            // no textures or anything else, we will bind vertex programs
+            // every so often though
+        }
+        else
+        {
+            mShadowCasterPlainBlackPass = matPlainBlack->getTechnique(0)->getPass(0);
+        }
+    }
+
+    if (!mShadowReceiverPass)
+    {
+        MaterialPtr matShadRec = MaterialManager::getSingleton().getByName(
+            "Ogre/TextureShadowReceiver");
+        if (matShadRec.isNull())			
+        {
+            matShadRec = MaterialManager::getSingleton().create(
+                "Ogre/TextureShadowReceiver",
+                ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME);
+            mShadowReceiverPass = matShadRec->getTechnique(0)->getPass(0);
+			// Don't set lighting and blending modes here, depends on additive / modulative
+            TextureUnitState* t = mShadowReceiverPass->createTextureUnitState();
+            t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
+        }
+        else
+        {
+            mShadowReceiverPass = matShadRec->getTechnique(0)->getPass(0);
+        }
+    }
+
+    // Set up spot shadow fade texture (loaded from code data block)
+    TexturePtr spotShadowFadeTex = 
+        TextureManager::getSingleton().getByName("spot_shadow_fade.png");
+    if (spotShadowFadeTex.isNull())
+    {
+        // Load the manual buffer into an image (don't destroy memory!
+        DataStreamPtr stream(
+			new MemoryDataStream(SPOT_SHADOW_FADE_PNG, SPOT_SHADOW_FADE_PNG_SIZE, false));
+        Image img;
+        img.load(stream, "png");
+        spotShadowFadeTex = 
+            TextureManager::getSingleton().loadImage(
+			"spot_shadow_fade.png", ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME, 
+			img, TEX_TYPE_2D);
+    }
+
+    mShadowMaterialInitDone = true;
+}
+//---------------------------------------------------------------------
+const Pass* SceneManager::deriveShadowCasterPass(const Pass* pass)
+{
+	if (isShadowTechniqueTextureBased())
+    {
+		Pass* retPass = mShadowTextureCustomCasterPass ? 
+			mShadowTextureCustomCasterPass : mShadowCasterPlainBlackPass;
+
+		
+		// Special case alpha-blended passes
+		if ((pass->getSourceBlendFactor() == SBF_SOURCE_ALPHA && 
+			pass->getDestBlendFactor() == SBF_ONE_MINUS_SOURCE_ALPHA) 
+			|| pass->getAlphaRejectFunction() != CMPF_ALWAYS_PASS)
+		{
+			// Alpha blended passes must retain their transparency
+			retPass->setAlphaRejectSettings(pass->getAlphaRejectFunction(), 
+				pass->getAlphaRejectValue());
+			retPass->setSceneBlending(pass->getSourceBlendFactor(), pass->getDestBlendFactor());
+			retPass->getParent()->getParent()->setTransparencyCastsShadows(true);
+
+			// So we allow the texture units, but override the colour functions
+			// Copy texture state, shift up one since 0 is shadow texture
+			size_t origPassTUCount = pass->getNumTextureUnitStates();
+			for (size_t t = 0; t < origPassTUCount; ++t)
+			{
+				TextureUnitState* tex;
+				if (retPass->getNumTextureUnitStates() <= t)
+				{
+					tex = retPass->createTextureUnitState();
+				}
+				else
+				{
+					tex = retPass->getTextureUnitState(t);
+				}
+				// copy base state
+				(*tex) = *(pass->getTextureUnitState(t));
+				// override colour function
+				tex->setColourOperationEx(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT,
+					isShadowTechniqueAdditive()? ColourValue::Black : mShadowColour);
+
+			}
+			// Remove any extras
+			while (retPass->getNumTextureUnitStates() > origPassTUCount)
+			{
+				retPass->removeTextureUnitState(origPassTUCount);
+			}
+
+		}
+		else
+		{
+			// reset
+			retPass->setSceneBlending(SBT_REPLACE);
+			retPass->setAlphaRejectFunction(CMPF_ALWAYS_PASS);
+			while (retPass->getNumTextureUnitStates() > 0)
+			{
+				retPass->removeTextureUnitState(0);
+			}
+		}
+
+		// Propagate culling modes
+		retPass->setCullingMode(pass->getCullingMode());
+		retPass->setManualCullingMode(pass->getManualCullingMode());
+		
+
+		if (!pass->getShadowCasterVertexProgramName().empty())
+		{
+			// Have to merge the shadow caster vertex program in
+			retPass->setVertexProgram(
+				pass->getShadowCasterVertexProgramName());
+			const GpuProgramPtr& prg = retPass->getVertexProgram();
+			// Load this program if not done already
+			if (!prg->isLoaded())
+				prg->load();
+			// Copy params
+			retPass->setVertexProgramParameters(
+				pass->getShadowCasterVertexProgramParameters());
+			if (retPass == mShadowTextureCustomCasterPass)
+			{
+				// mark that we've overridden the standard
+				mShadowTextureCasterVPDirty = true;
+			}
+			// Also have to hack the light autoparams, that is done later
+		}
+		else 
+		{
+			retPass->setVertexProgram(StringUtil::BLANK);
+			if (mShadowTextureCasterVPDirty)
+			{
+				// reset
+				mShadowTextureCustomCasterPass->setVertexProgram(
+					mShadowTextureCustomCasterVertexProgram);
+				if(mShadowTextureCustomCasterPass->hasVertexProgram())
+				{
+					mShadowTextureCustomCasterPass->setVertexProgramParameters(
+						mShadowTextureCustomCasterVPParams);
+
+				}
+				mShadowTextureCasterVPDirty = false;
+			}
+		}
+		return retPass;
+	}
+	else
+	{
+        return pass;
+    }
+
+}
+//---------------------------------------------------------------------
+const Pass* SceneManager::deriveShadowReceiverPass(const Pass* pass)
+{
+
+    if (isShadowTechniqueTextureBased())
+    {
+		Pass* retPass = mShadowTextureCustomReceiverPass ? 
+			mShadowTextureCustomReceiverPass : mShadowReceiverPass;
+
+		if (pass->hasVertexProgram())
+		{
+			// Have to merge the receiver vertex program in
+			retPass->setVertexProgram(
+				pass->getShadowReceiverVertexProgramName());
+			// Did this result in a new vertex program?
+			if (retPass->hasVertexProgram())
+			{
+				const GpuProgramPtr& prg = retPass->getVertexProgram();
+				// Load this program if required
+				if (!prg->isLoaded())
+					prg->load();
+				// Copy params
+				retPass->setVertexProgramParameters(
+					pass->getShadowReceiverVertexProgramParameters());
+
+				if (retPass == mShadowTextureCustomReceiverPass)
+				{
+					// mark that we've overridden the standard
+					mShadowTextureReceiverVPDirty = true;
+				}
+			}
+			// Also have to hack the light autoparams, that is done later
+		}
+		else
+		{
+			retPass->setVertexProgram(StringUtil::BLANK);
+		}
+
+		bool resetFragmentProgram = true;
+        size_t keepTUCount;
+		// If additive, need lighting parameters & standard programs
+		if (isShadowTechniqueAdditive())
+		{
+			keepTUCount = 1;
+			retPass->setLightingEnabled(true);
+			retPass->setAmbient(pass->getAmbient());
+			retPass->setSelfIllumination(pass->getSelfIllumination());
+			retPass->setDiffuse(pass->getDiffuse());
+			retPass->setSpecular(pass->getSpecular());
+			retPass->setShininess(pass->getShininess());
+			retPass->setIteratePerLight(pass->getIteratePerLight(), 
+				pass->getRunOnlyForOneLightType(), pass->getOnlyLightType());
+
+            // We need to keep alpha rejection settings
+            retPass->setAlphaRejectSettings(pass->getAlphaRejectFunction(),
+                pass->getAlphaRejectValue());
+            // Copy texture state, shift up one since 0 is shadow texture
+            size_t origPassTUCount = pass->getNumTextureUnitStates();
+            for (size_t t = 0; t < origPassTUCount; ++t)
+            {
+                size_t targetIndex = t+1;
+                TextureUnitState* tex;
+                if (retPass->getNumTextureUnitStates() <= targetIndex)
+                {
+                    tex = retPass->createTextureUnitState();
+                }
+                else
+                {
+                    tex = retPass->getTextureUnitState(targetIndex);
+                }
+                (*tex) = *(pass->getTextureUnitState(t));
+            }
+            keepTUCount = origPassTUCount + 1;
+
+			// Will also need fragment programs since this is a complex light setup
+			if (pass->hasFragmentProgram())
+			{
+				String fragName = pass->getShadowReceiverFragmentProgramName();
+				GpuProgramParametersSharedPtr params;
+				if (!fragName.empty())
+				{
+					resetFragmentProgram = false;
+
+					params = pass->getShadowReceiverFragmentProgramParameters();
+
+					retPass->setFragmentProgram(fragName);
+					const GpuProgramPtr& prg = retPass->getFragmentProgram();
+					// Load this program if required
+					if (!prg->isLoaded())
+						prg->load();
+					// Copy params
+					retPass->setFragmentProgramParameters(params);
+
+					// Did we bind a shadow vertex program?
+					if (pass->hasVertexProgram() && !retPass->hasVertexProgram())
+					{
+						// We didn't bind a receiver-specific program, so bind the original
+						retPass->setVertexProgram(pass->getVertexProgramName());
+						const GpuProgramPtr& prg = retPass->getVertexProgram();
+						// Load this program if required
+						if (!prg->isLoaded())
+							prg->load();
+						// Copy params
+						retPass->setVertexProgramParameters(
+							pass->getVertexProgramParameters());
+
+						if (retPass == mShadowTextureCustomReceiverPass)
+						{
+							// mark that we've overridden the standard
+							mShadowTextureReceiverVPDirty = true;
+						}
+					}
+				} // valid shadow fragment program
+			} // ori pass has fragment program
+			
+		}// additive lighting
+		else
+		{
+			// need to keep spotlight fade etc
+			keepTUCount = retPass->getNumTextureUnitStates();
+		}
+
+		// reset fragment program
+		if (resetFragmentProgram)
+		{
+			retPass->setFragmentProgram(StringUtil::BLANK);
+		}
+        // Remove any extra texture units
+        while (retPass->getNumTextureUnitStates() > keepTUCount)
+        {
+            retPass->removeTextureUnitState(keepTUCount);
+        }
+
+		// reset vertex program
+		if (retPass->hasVertexProgram() && !pass->hasVertexProgram())
+		{
+			// reset
+			retPass->setVertexProgram("");
+
+			if (mShadowTextureReceiverVPDirty)
+			{
+				// reset
+				mShadowTextureCustomReceiverPass->setVertexProgram(
+					mShadowTextureCustomReceiverVertexProgram);
+				if(mShadowTextureCustomReceiverPass->hasVertexProgram())
+				{
+					mShadowTextureCustomReceiverPass->setVertexProgramParameters(
+						mShadowTextureCustomReceiverVPParams);
+
+				}
+				mShadowTextureReceiverVPDirty = false;
+			}
+		}
+
+		retPass->_load();
+
+		return retPass;
+	}
+	else
+	{
+        return pass;
+    }
+
+}
+//---------------------------------------------------------------------
+void SceneManager::renderShadowVolumesToStencil(const Light* light, const Camera* camera)
+{
+    // Get the shadow caster list
+    const ShadowCasterList& casters = findShadowCastersForLight(light, camera);
+    // Check there are some shadow casters to render
+    if (casters.empty())
+    {
+        // No casters, just do nothing
+        return;
+    }
+
+    // Set up scissor test (point & spot lights only)
+    bool scissored = false;
+    if (light->getType() != Light::LT_DIRECTIONAL && 
+        mDestRenderSystem->getCapabilities()->hasCapability(RSC_SCISSOR_TEST))
+    {
+        // Project the sphere onto the camera
+        Real left, right, top, bottom;
+        Sphere sphere(light->getDerivedPosition(), light->getAttenuationRange());
+        if (camera->projectSphere(sphere, &left, &top, &right, &bottom))
+        {
+            scissored = true;
+            // Turn normalised device coordinates into pixels
+            int iLeft, iTop, iWidth, iHeight;
+            mCurrentViewport->getActualDimensions(iLeft, iTop, iWidth, iHeight);
+            size_t szLeft, szRight, szTop, szBottom;
+
+            szLeft = (size_t)(iLeft + ((left + 1) * 0.5 * iWidth));
+            szRight = (size_t)(iLeft + ((right + 1) * 0.5 * iWidth));
+            szTop = (size_t)(iTop + ((-top + 1) * 0.5 * iHeight));
+            szBottom = (size_t)(iTop + ((-bottom + 1) * 0.5 * iHeight));
+
+            mDestRenderSystem->setScissorTest(true, szLeft, szTop, szRight, szBottom);
+        }
+    }
+
+    mDestRenderSystem->unbindGpuProgram(GPT_FRAGMENT_PROGRAM);
+
+    // Can we do a 2-sided stencil?
+    bool stencil2sided = false;
+    if (mDestRenderSystem->getCapabilities()->hasCapability(RSC_TWO_SIDED_STENCIL) && 
+        mDestRenderSystem->getCapabilities()->hasCapability(RSC_STENCIL_WRAP))
+    {
+        // enable
+        stencil2sided = true;
+    }
+
+    // Do we have access to vertex programs?
+    bool extrudeInSoftware = true;
+    bool finiteExtrude = !mShadowUseInfiniteFarPlane || 
+        !mDestRenderSystem->getCapabilities()->hasCapability(RSC_INFINITE_FAR_PLANE);
+    if (mDestRenderSystem->getCapabilities()->hasCapability(RSC_VERTEX_PROGRAM))
+    {
+        extrudeInSoftware = false;
+        // attach the appropriate extrusion vertex program
+        // Note we never unset it because support for vertex programs is constant
+        mShadowStencilPass->setVertexProgram(
+            ShadowVolumeExtrudeProgram::getProgramName(light->getType(), finiteExtrude, false)
+            , false);
+        // Set params
+        if (finiteExtrude)
+        {
+            mShadowStencilPass->setVertexProgramParameters(mFiniteExtrusionParams);
+        }
+        else
+        {
+            mShadowStencilPass->setVertexProgramParameters(mInfiniteExtrusionParams);
+        }
+        if (mDebugShadows)
+        {
+            mShadowDebugPass->setVertexProgram(
+                ShadowVolumeExtrudeProgram::getProgramName(light->getType(), finiteExtrude, true)
+                , false);
+            // Set params
+            if (finiteExtrude)
+            {
+                mShadowDebugPass->setVertexProgramParameters(mFiniteExtrusionParams);
+            }
+            else
+            {
+                mShadowDebugPass->setVertexProgramParameters(mInfiniteExtrusionParams);
+            }
+        }
+
+        mDestRenderSystem->bindGpuProgram(mShadowStencilPass->getVertexProgram()->_getBindingDelegate());
+
+    }
+    else
+    {
+        mDestRenderSystem->unbindGpuProgram(GPT_VERTEX_PROGRAM);
+    }
+
+    // Add light to internal list for use in render call
+    LightList lightList;
+    // const_cast is forgiveable here since we pass this const
+    lightList.push_back(const_cast<Light*>(light));
+
+    // Turn off colour writing and depth writing
+    mDestRenderSystem->_setColourBufferWriteEnabled(false, false, false, false);
+	mDestRenderSystem->_disableTextureUnitsFrom(0);
+    mDestRenderSystem->_setDepthBufferParams(true, false, CMPF_LESS);
+    mDestRenderSystem->setStencilCheckEnabled(true);
+
+    // Calculate extrusion distance
+    // Use direction light extrusion distance now, just form optimize code
+    // generate a little, point/spot light will up to date later
+    Real extrudeDist = mShadowDirLightExtrudeDist;
+
+    // Figure out the near clip volume
+    const PlaneBoundedVolume& nearClipVol = 
+        light->_getNearClipVolume(camera);
+
+    // Now iterate over the casters and render
+    ShadowCasterList::const_iterator si, siend;
+    siend = casters.end();
+
+
+	// Now iterate over the casters and render
+	for (si = casters.begin(); si != siend; ++si)
+	{
+        ShadowCaster* caster = *si;
+		bool zfailAlgo = camera->isCustomNearClipPlaneEnabled();
+		unsigned long flags = 0;
+
+        if (light->getType() != Light::LT_DIRECTIONAL)
+        {
+            extrudeDist = caster->getPointExtrusionDistance(light); 
+        }
+
+        if (!extrudeInSoftware && !finiteExtrude)
+        {
+            // hardware extrusion, to infinity (and beyond!)
+            flags |= SRF_EXTRUDE_TO_INFINITY;
+        }
+
+		// Determine whether zfail is required
+        if (nearClipVol.intersects(caster->getWorldBoundingBox()))
+        {
+            // We use zfail for this object only because zfail
+	        // compatible with zpass algorithm
+			zfailAlgo = true;
+            // We need to include the light and / or dark cap
+            // But only if they will be visible
+            if(camera->isVisible(caster->getLightCapBounds()))
+            {
+                flags |= SRF_INCLUDE_LIGHT_CAP;
+            }
+			// zfail needs dark cap 
+			// UNLESS directional lights using hardware extrusion to infinity
+			// since that extrudes to a single point
+			if(!((flags & SRF_EXTRUDE_TO_INFINITY) && 
+				light->getType() == Light::LT_DIRECTIONAL) &&
+				camera->isVisible(caster->getDarkCapBounds(*light, extrudeDist)))
+			{
+				flags |= SRF_INCLUDE_DARK_CAP;
+			}
+        }
+		else
+		{
+			// In zpass we need a dark cap if
+			// 1: infinite extrusion on point/spotlight sources in modulative shadows
+			//    mode, since otherwise in areas where there is no depth (skybox)
+			//    the infinitely projected volume will leave a dark band
+			// 2: finite extrusion on any light source since glancing angles
+			//    can peek through the end and shadow objects behind incorrectly
+			if ((flags & SRF_EXTRUDE_TO_INFINITY) && 
+				light->getType() != Light::LT_DIRECTIONAL && 
+				isShadowTechniqueModulative() && 
+				camera->isVisible(caster->getDarkCapBounds(*light, extrudeDist)))
+			{
+				flags |= SRF_INCLUDE_DARK_CAP;
+			}
+			else if (!(flags & SRF_EXTRUDE_TO_INFINITY) && 
+				camera->isVisible(caster->getDarkCapBounds(*light, extrudeDist)))
+			{
+				flags |= SRF_INCLUDE_DARK_CAP;
+			}
+
+		}
+
+        // Get shadow renderables			
+        ShadowCaster::ShadowRenderableListIterator iShadowRenderables =
+            caster->getShadowVolumeRenderableIterator(mShadowTechnique,
+            light, &mShadowIndexBuffer, extrudeInSoftware, 
+            extrudeDist, flags);
+
+        // Render a shadow volume here
+        //  - if we have 2-sided stencil, one render with no culling
+        //  - otherwise, 2 renders, one with each culling method and invert the ops
+        setShadowVolumeStencilState(false, zfailAlgo, stencil2sided);
+        renderShadowVolumeObjects(iShadowRenderables, mShadowStencilPass, &lightList, flags,
+            false, zfailAlgo, stencil2sided);
+        if (!stencil2sided)
+        {
+            // Second pass
+            setShadowVolumeStencilState(true, zfailAlgo, false);
+            renderShadowVolumeObjects(iShadowRenderables, mShadowStencilPass, &lightList, flags,
+                true, zfailAlgo, false);
+        }
+
+        // Do we need to render a debug shadow marker?
+        if (mDebugShadows)
+        {
+            // reset stencil & colour ops
+            mDestRenderSystem->setStencilBufferParams();
+            mShadowDebugPass->getTextureUnitState(0)->
+                setColourOperationEx(LBX_MODULATE, LBS_MANUAL, LBS_CURRENT,
+                zfailAlgo ? ColourValue(0.7, 0.0, 0.2) : ColourValue(0.0, 0.7, 0.2));
+            _setPass(mShadowDebugPass);
+            renderShadowVolumeObjects(iShadowRenderables, mShadowDebugPass, &lightList, flags,
+                true, false, false);
+            mDestRenderSystem->_setColourBufferWriteEnabled(false, false, false, false);
+            mDestRenderSystem->_setDepthBufferFunction(CMPF_LESS);
+        }
+    }
+
+    // revert colour write state
+    mDestRenderSystem->_setColourBufferWriteEnabled(true, true, true, true);
+    // revert depth state
+    mDestRenderSystem->_setDepthBufferParams();
+
+    mDestRenderSystem->setStencilCheckEnabled(false);
+
+    mDestRenderSystem->unbindGpuProgram(GPT_VERTEX_PROGRAM);
+
+    if (scissored)
+    {
+        // disable scissor test
+        mDestRenderSystem->setScissorTest(false);
+    }
+
+}
+//---------------------------------------------------------------------
+void SceneManager::renderShadowVolumeObjects(ShadowCaster::ShadowRenderableListIterator iShadowRenderables,
+                                             Pass* pass,
+                                             const LightList *manualLightList,
+                                             unsigned long flags,
+                                             bool secondpass, bool zfail, bool twosided)
+{
+    // ----- SHADOW VOLUME LOOP -----
+    // Render all shadow renderables with same stencil operations
+    while (iShadowRenderables.hasMoreElements())
+    {
+        ShadowRenderable* sr = iShadowRenderables.getNext();
+
+        // omit hidden renderables
+        if (sr->isVisible())
+        {
+            // render volume, including dark and (maybe) light caps
+            renderSingleObject(sr, pass, false, manualLightList);
+
+            // optionally render separate light cap
+            if (sr->isLightCapSeparate() && (flags & SRF_INCLUDE_LIGHT_CAP))
+            {
+                ShadowRenderable* lightCap = sr->getLightCapRenderable();
+                assert(lightCap && "Shadow renderable is missing a separate light cap renderable!");
+
+                // We must take care with light caps when we could 'see' the back facing
+                // triangles directly:
+                //   1. The front facing light caps must render as always fail depth
+                //      check to avoid 'depth fighting'.
+                //   2. The back facing light caps must use normal depth function to
+                //      avoid break the standard depth check
+                //
+                // TODO:
+                //   1. Separate light caps rendering doesn't need for the 'closed'
+                //      mesh that never touch the near plane, because in this instance,
+                //      we couldn't 'see' any back facing triangles directly. The
+                //      'closed' mesh must determinate by edge list builder.
+                //   2. There still exists 'depth fighting' bug with coplane triangles
+                //      that has opposite facing. This usually occur when use two side
+                //      material in the modeling tools and the model exporting tools
+                //      exporting double triangles to represent this model. This bug
+                //      can't fixed in GPU only, there must has extra work on edge list
+                //      builder and shadow volume generater to fix it.
+                //
+                if (twosided)
+                {
+                    // select back facing light caps to render
+                    mDestRenderSystem->_setCullingMode(CULL_ANTICLOCKWISE);
+                    // use normal depth function for back facing light caps
+                    renderSingleObject(lightCap, pass, false, manualLightList);
+
+                    // select front facing light caps to render
+                    mDestRenderSystem->_setCullingMode(CULL_CLOCKWISE);
+                    // must always fail depth check for front facing light caps
+                    mDestRenderSystem->_setDepthBufferFunction(CMPF_ALWAYS_FAIL);
+                    renderSingleObject(lightCap, pass, false, manualLightList);
+
+                    // reset depth function
+                    mDestRenderSystem->_setDepthBufferFunction(CMPF_LESS);
+                    // reset culling mode
+                    mDestRenderSystem->_setCullingMode(CULL_NONE);
+                }
+                else if ((secondpass || zfail) && !(secondpass && zfail))
+                {
+                    // use normal depth function for back facing light caps
+                    renderSingleObject(lightCap, pass, false, manualLightList);
+                }
+                else
+                {
+                    // must always fail depth check for front facing light caps
+                    mDestRenderSystem->_setDepthBufferFunction(CMPF_ALWAYS_FAIL);
+                    renderSingleObject(lightCap, pass, false, manualLightList);
+
+                    // reset depth function
+                    mDestRenderSystem->_setDepthBufferFunction(CMPF_LESS);
+                }
+            }
+        }
+    }
+}
+//---------------------------------------------------------------------
+void SceneManager::setShadowVolumeStencilState(bool secondpass, bool zfail, bool twosided)
+{
+    // Determinate the best stencil operation
+    StencilOperation incrOp, decrOp;
+    if (mDestRenderSystem->getCapabilities()->hasCapability(RSC_STENCIL_WRAP))
+    {
+        incrOp = SOP_INCREMENT_WRAP;
+        decrOp = SOP_DECREMENT_WRAP;
+    }
+    else
+    {
+        incrOp = SOP_INCREMENT;
+        decrOp = SOP_DECREMENT;
+    }
+
+    // First pass, do front faces if zpass
+    // Second pass, do back faces if zpass
+    // Invert if zfail
+    // this is to ensure we always increment before decrement
+    // When two-sided stencil, always pass front face stencil
+    // operation parameters and the inverse of them will happen
+    // for back faces
+    if ( !twosided && ((secondpass || zfail) && !(secondpass && zfail)) )
+    {
+        mDestRenderSystem->_setCullingMode(
+            twosided? CULL_NONE : CULL_ANTICLOCKWISE);
+        mDestRenderSystem->setStencilBufferParams(
+            CMPF_ALWAYS_PASS, // always pass stencil check
+            0, // no ref value (no compare)
+            0xFFFFFFFF, // no mask
+            SOP_KEEP, // stencil test will never fail
+            zfail ? incrOp : SOP_KEEP, // back face depth fail
+            zfail ? SOP_KEEP : decrOp, // back face pass
+            twosided
+            );
+    }
+    else
+    {
+        mDestRenderSystem->_setCullingMode(
+            twosided? CULL_NONE : CULL_CLOCKWISE);
+        mDestRenderSystem->setStencilBufferParams(
+            CMPF_ALWAYS_PASS, // always pass stencil check
+            0, // no ref value (no compare)
+            0xFFFFFFFF, // no mask
+            SOP_KEEP, // stencil test will never fail
+            zfail ? decrOp : SOP_KEEP, // front face depth fail
+            zfail ? SOP_KEEP : incrOp, // front face pass
+            twosided
+            );
+    }
+}
+//---------------------------------------------------------------------
+void SceneManager::setShadowColour(const ColourValue& colour)
+{
+    mShadowColour = colour;
+
+    // Change shadow material setting only when it's prepared,
+    // otherwise, it'll set up while preparing shadow materials.
+    if (mShadowModulativePass)
+    {
+        mShadowModulativePass->getTextureUnitState(0)->setColourOperationEx(
+            LBX_MODULATE, LBS_MANUAL, LBS_CURRENT, colour);
+    }
+}
+//---------------------------------------------------------------------
+const ColourValue& SceneManager::getShadowColour(void) const
+{
+    return mShadowColour;
+}
+//---------------------------------------------------------------------
+void SceneManager::setShadowFarDistance(Real distance)
+{
+    mShadowFarDist = distance;
+    mShadowFarDistSquared = distance * distance;
+}
+//---------------------------------------------------------------------
+void SceneManager::setShadowDirectionalLightExtrusionDistance(Real dist)
+{
+    mShadowDirLightExtrudeDist = dist;
+}
+//---------------------------------------------------------------------
+Real SceneManager::getShadowDirectionalLightExtrusionDistance(void) const
+{
+    return mShadowDirLightExtrudeDist;
+}
+//---------------------------------------------------------------------
+void SceneManager::setShadowIndexBufferSize(size_t size)
+{
+    if (!mShadowIndexBuffer.isNull() && size != mShadowIndexBufferSize)
+    {
+        // re-create shadow buffer with new size
+        mShadowIndexBuffer = HardwareBufferManager::getSingleton().
+            createIndexBuffer(HardwareIndexBuffer::IT_16BIT, 
+            mShadowIndexBufferSize, 
+            HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE, 
+            false);
+    }
+    mShadowIndexBufferSize = size;
+}
+//---------------------------------------------------------------------
+void SceneManager::setShadowTextureSize(unsigned short size)
+{
+    // possibly recreate
+    createShadowTextures(size, mShadowTextureCount, mShadowTextureFormat);
+    mShadowTextureSize = size;
+}
+//---------------------------------------------------------------------
+void SceneManager::setShadowTextureCount(unsigned short count)
+{
+    // possibly recreate
+    createShadowTextures(mShadowTextureSize, count, mShadowTextureFormat);
+    mShadowTextureCount = count;
+}
+//---------------------------------------------------------------------
+void SceneManager::setShadowTexturePixelFormat(PixelFormat fmt)
+{
+	// possibly recreate
+	createShadowTextures(mShadowTextureSize, mShadowTextureCount, fmt);
+	mShadowTextureFormat = fmt;
+}
+//---------------------------------------------------------------------
+void SceneManager::setShadowTextureSettings(unsigned short size, 
+	unsigned short count, PixelFormat fmt)
+{
+    if (!mShadowTextures.empty() && 
+        (count != mShadowTextureCount ||
+        size != mShadowTextureSize ||
+		fmt != mShadowTextureFormat))
+    {
+        // recreate
+        createShadowTextures(size, count, fmt);
+    }
+    mShadowTextureCount = count;
+    mShadowTextureSize = size;
+	mShadowTextureFormat = fmt;
+}
+//---------------------------------------------------------------------
+void SceneManager::setShadowTextureSelfShadow(bool selfShadow) 
+{ 
+	mShadowTextureSelfShadow = selfShadow;
+	if (isShadowTechniqueTextureBased())
+		getRenderQueue()->setShadowCastersCannotBeReceivers(!selfShadow);
+}
+//---------------------------------------------------------------------
+void SceneManager::setShadowTextureCasterMaterial(const String& name)
+{
+	if (name.empty())
+	{
+		mShadowTextureCustomCasterPass = 0;
+	}
+	else
+	{
+		MaterialPtr mat = MaterialManager::getSingleton().getByName(name);
+		if (mat.isNull())
+		{
+			OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
+				"Cannot locate material called '" + name + "'", 
+				"SceneManager::setShadowTextureCasterMaterial");
+		}
+		mat->load();
+		mShadowTextureCustomCasterPass = mat->getBestTechnique()->getPass(0);
+		if (mShadowTextureCustomCasterPass->hasVertexProgram())
+		{
+			// Save vertex program and params in case we have to swap them out
+			mShadowTextureCustomCasterVertexProgram = 
+				mShadowTextureCustomCasterPass->getVertexProgramName();
+			mShadowTextureCustomCasterVPParams = 
+				mShadowTextureCustomCasterPass->getVertexProgramParameters();
+			mShadowTextureCasterVPDirty = false;
+
+		}
+	}
+}
+//---------------------------------------------------------------------
+void SceneManager::setShadowTextureReceiverMaterial(const String& name)
+{
+	if (name.empty())
+	{
+		mShadowTextureCustomReceiverPass = 0;
+	}
+	else
+	{
+		MaterialPtr mat = MaterialManager::getSingleton().getByName(name);
+		if (mat.isNull())
+		{
+			OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
+				"Cannot locate material called '" + name + "'", 
+				"SceneManager::setShadowTextureReceiverMaterial");
+		}
+		mat->load();
+		mShadowTextureCustomReceiverPass = mat->getBestTechnique()->getPass(0);
+		if (mShadowTextureCustomReceiverPass->hasVertexProgram())
+		{
+			// Save vertex program and params in case we have to swap them out
+			mShadowTextureCustomReceiverVertexProgram = 
+				mShadowTextureCustomReceiverPass->getVertexProgramName();
+			mShadowTextureCustomReceiverVPParams = 
+				mShadowTextureCustomReceiverPass->getVertexProgramParameters();
+			mShadowTextureReceiverVPDirty = false;
+
+		}
+	}
+}
+//---------------------------------------------------------------------
+void SceneManager::createShadowTextures(unsigned short size,
+	unsigned short count, PixelFormat fmt)
+{
+    static const String baseName = "Ogre/ShadowTexture";
+
+    if (!isShadowTechniqueTextureBased() ||
+        !mShadowTextures.empty() && 
+        count == mShadowTextureCount &&
+        size == mShadowTextureSize && 
+		fmt == mShadowTextureFormat)
+    {
+        // no change
+        return;
+    }
+
+
+    // destroy existing
+	destroyShadowTextures();
+
+    // Recreate shadow textures
+    for (unsigned short t = 0; t < count; ++t)
+    {
+        String targName = baseName + StringConverter::toString(t);
+        String camName = baseName + "Cam" + StringConverter::toString(t);
+        String matName = baseName + "Mat" + StringConverter::toString(t);
+
+		// try to get existing texture first, since we share these between
+		// potentially multiple SMs
+		TexturePtr shadowTex = TextureManager::getSingleton().getByName(targName);
+		if (shadowTex.isNull())
+		{
+			shadowTex = TextureManager::getSingleton().createManual(
+				targName, 
+				ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME, 
+				TEX_TYPE_2D, size, size, 0, mShadowTextureFormat, 
+				TU_RENDERTARGET);
+		}
+		else if (shadowTex->getWidth() != size 
+			|| shadowTex->getHeight() != size
+			|| shadowTex->getFormat() != mShadowTextureFormat)
+		{
+			StringUtil::StrStreamType s;
+			s << "Warning: shadow texture #" << t << " is shared "
+				<< "between scene managers but the sizes / formats "
+				<< "do not agree. Consider rationalising your scene manager "
+				<< "shadow texture settings.";
+			LogManager::getSingleton().logMessage(s.str());
+		}
+				
+		// Ensure texture loaded
+		shadowTex->load();
+
+		RenderTexture *shadowRTT = shadowTex->getBuffer()->getRenderTarget();
+
+		// Create camera for this texture, but note that we have to rebind
+		// in prepareShadowTextures to coexist with multiple SMs
+		Camera* cam = createCamera(camName);
+        cam->setAspectRatio(1.0f);
+		// Don't use rendering distance for light cameras; we don't want shadows
+		// for visible objects disappearing, especially for directional lights
+		cam->setUseRenderingDistance(false);
+		mShadowTextureCameras.push_back(cam);
+		
+        // Create a viewport, if not there already
+		if (shadowRTT->getNumViewports() == 0)
+		{
+			// Note camera assignment is transient when multiple SMs
+			Viewport *v = shadowRTT->addViewport(cam);
+			v->setClearEveryFrame(true);
+			// remove overlays
+			v->setOverlaysEnabled(false);
+		}
+		
+        // Don't update automatically - we'll do it when required
+        shadowRTT->setAutoUpdated(false);
+        
+        mShadowTextures.push_back(shadowTex);
+
+
+        // Also create corresponding Material used for rendering this shadow
+        MaterialPtr mat = MaterialManager::getSingleton().getByName(matName);
+        if (mat.isNull())
+        {
+            mat = MaterialManager::getSingleton().create(
+                matName, ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME);
+        }
+        else
+        {
+            mat->getTechnique(0)->getPass(0)->removeAllTextureUnitStates();
+        }
+        // create texture unit referring to render target texture
+        TextureUnitState* texUnit = 
+            mat->getTechnique(0)->getPass(0)->createTextureUnitState(targName);
+        // set projective based on camera
+        texUnit->setProjectiveTexturing(true, cam);
+        texUnit->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
+        mat->touch();
+
+    }
+}
+//---------------------------------------------------------------------
+void SceneManager::destroyShadowTextures(void)
+{
+    ShadowTextureList::iterator i, iend;
+    ShadowTextureCameraList::iterator ci;
+    iend = mShadowTextures.end();
+    ci = mShadowTextureCameras.begin();
+    for (i = mShadowTextures.begin(); i != iend; ++i, ++ci)
+    {
+        TexturePtr &shadowTex = *i;
+		// If the reference count on this texture is 1 over the resource system
+		// overhead, then we can remove the texture
+		if (shadowTex.useCount() == 
+			ResourceGroupManager::RESOURCE_SYSTEM_NUM_REFERENCE_COUNTS + 1)
+		{
+	        // destroy texture
+    	    TextureManager::getSingleton().remove(shadowTex->getName());
+		}
+
+		// Always destroy camera since they are local to this SM
+   		destroyCamera(*ci);
+    }
+    mShadowTextures.clear();
+	mShadowTextureCameras.clear();
+
+        
+}
+//---------------------------------------------------------------------
+void SceneManager::prepareShadowTextures(Camera* cam, Viewport* vp)
+{
+    // Set the illumination stage, prevents recursive calls
+    IlluminationRenderStage savedStage = mIlluminationStage;
+    mIlluminationStage = IRS_RENDER_TO_TEXTURE;
+
+    // Determine far shadow distance
+    Real shadowDist = mShadowFarDist;
+    if (!shadowDist)
+    {
+        // need a shadow distance, make one up
+        shadowDist = cam->getNearClipDistance() * 300;
+    }
+	Real shadowOffset = shadowDist * mShadowTextureOffset;
+    // Precalculate fading info
+	Real shadowEnd = shadowDist + shadowOffset;
+	Real fadeStart = shadowEnd * mShadowTextureFadeStart;
+	Real fadeEnd = shadowEnd * mShadowTextureFadeEnd;
+	// set fogging to hide the shadow edge 
+	// Additive lighting needs fading too (directional)
+	mShadowReceiverPass->setFog(true, FOG_LINEAR, ColourValue::White, 
+		0, fadeStart, fadeEnd);
+
+    // Iterate over the lights we've found, max out at the limit of light textures
+
+    LightList::iterator i, iend;
+    ShadowTextureList::iterator si, siend;
+	ShadowTextureCameraList::iterator ci;
+    iend = mLightsAffectingFrustum.end();
+    siend = mShadowTextures.end();
+	ci = mShadowTextureCameras.begin();
+    for (i = mLightsAffectingFrustum.begin(), si = mShadowTextures.begin();
+        i != iend && si != siend; ++i)
+    {
+        Light* light = *i;
+
+        // Skip non-shadowing lights
+        if (!light->getCastShadows())
+            continue;
+
+		TexturePtr &shadowTex = *si;
+        RenderTarget *shadowRTT = shadowTex->getBuffer()->getRenderTarget();
+        Viewport *shadowView = shadowRTT->getViewport(0);
+        Camera *texCam = *ci;
+		// rebind camera, incase another SM in use which has switched to its cam
+		shadowView->setCamera(texCam);
+        
+        Vector3 pos, dir;
+
+        // Directional lights 
+        if (light->getType() == Light::LT_DIRECTIONAL)
+        {
+            // set up the shadow texture
+            // Set ortho projection
+            texCam->setProjectionType(PT_ORTHOGRAPHIC);
+            // set easy FOV and near dist so that texture covers far dist
+            texCam->setFOVy(Degree(90));
+            texCam->setNearClipDistance(shadowDist);
+
+            // Calculate look at position
+            // We want to look at a spot shadowOffset away from near plane
+            // 0.5 is a litle too close for angles
+            Vector3 target = cam->getDerivedPosition() + 
+                (cam->getDerivedDirection() * shadowOffset);
+
+            // Calculate direction, which same as directional light direction
+            dir = - light->getDerivedDirection(); // backwards since point down -z
+            dir.normalise();
+
+            // Calculate position
+            // We want to be in the -ve direction of the light direction
+            // far enough to project for the dir light extrusion distance
+            pos = target + dir * mShadowDirLightExtrudeDist;
+
+            // Round local x/y position based on a world-space texel; this helps to reduce
+            // jittering caused by the projection moving with the camera
+            // Viewport is 2 * near clip distance across (90 degree fov)
+            Real worldTexelSize = (texCam->getNearClipDistance() * 20) / mShadowTextureSize;
+            pos.x -= fmod(pos.x, worldTexelSize);
+            pos.y -= fmod(pos.y, worldTexelSize);
+            pos.z -= fmod(pos.z, worldTexelSize);
+        }
+        // Spotlight
+        else if (light->getType() == Light::LT_SPOTLIGHT)
+        {
+            // Set perspective projection
+            texCam->setProjectionType(PT_PERSPECTIVE);
+            // set FOV slightly larger than the spotlight range to ensure coverage
+            texCam->setFOVy(light->getSpotlightOuterAngle()*1.2);
+            // set near clip the same as main camera, since they are likely
+            // to both reflect the nature of the scene
+            texCam->setNearClipDistance(cam->getNearClipDistance());
+
+            // Calculate position, which same as spotlight position
+            pos = light->getDerivedPosition();
+
+            // Calculate direction, which same as spotlight direction
+            dir = - light->getDerivedDirection(); // backwards since point down -z
+            dir.normalise();
+        }
+        // Point light
+        else
+        {
+            // Set perspective projection
+            texCam->setProjectionType(PT_PERSPECTIVE);
+            // Use 120 degree FOV for point light to ensure coverage more area
+            texCam->setFOVy(Degree(120));
+            // set near clip the same as main camera, since they are likely
+            // to both reflect the nature of the scene
+            texCam->setNearClipDistance(cam->getNearClipDistance());
+
+            // Calculate look at position
+            // We want to look at a spot shadowOffset away from near plane
+            // 0.5 is a litle too close for angles
+            Vector3 target = cam->getDerivedPosition() + 
+                (cam->getDerivedDirection() * shadowOffset);
+
+            // Calculate position, which same as point light position
+            pos = light->getDerivedPosition();
+
+            dir = (pos - target); // backwards since point down -z
+            dir.normalise();
+        }
+
+        // Finally set position
+        texCam->setPosition(pos);
+
+        // Calculate orientation based on direction calculated above
+        /*
+        // Next section (camera oriented shadow map) abandoned
+        // Always point in the same direction, if we don't do this then
+        // we get 'shadow swimming' as camera rotates
+        // As it is, we get swimming on moving but this is less noticeable
+
+        // calculate up vector, we want it aligned with cam direction
+        Vector3 up = cam->getDerivedDirection();
+        // Check it's not coincident with dir
+        if (up.dotProduct(dir) >= 1.0f)
+        {
+        // Use camera up
+        up = cam->getUp();
+        }
+        */
+        Vector3 up = Vector3::UNIT_Y;
+        // Check it's not coincident with dir
+        if (Math::Abs(up.dotProduct(dir)) >= 1.0f)
+        {
+            // Use camera up
+            up = Vector3::UNIT_Z;
+        }
+        // cross twice to rederive, only direction is unaltered
+        Vector3 left = dir.crossProduct(up);
+        left.normalise();
+        up = dir.crossProduct(left);
+        up.normalise();
+        // Derive quaternion from axes
+        Quaternion q;
+        q.FromAxes(left, up, dir);
+        texCam->setOrientation(q);
+
+        // Setup background colour
+        shadowView->setBackgroundColour(ColourValue::White);
+
+		// Fire shadow caster update, callee can alter camera settings
+		fireShadowTexturesPreCaster(light, texCam);
+
+        // Update target
+        shadowRTT->update();
+
+        ++si; // next shadow texture
+		++ci; // next camera
+    }
+    // Set the illumination stage, prevents recursive calls
+    mIlluminationStage = savedStage;
+
+	fireShadowTexturesUpdated(
+		std::min(mLightsAffectingFrustum.size(), mShadowTextures.size()));
+}
+//---------------------------------------------------------------------
+StaticGeometry* SceneManager::createStaticGeometry(const String& name)
+{
+	// Check not existing
+	if (mStaticGeometryList.find(name) != mStaticGeometryList.end())
+	{
+		OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM, 
+			"StaticGeometry with name '" + name + "' already exists!", 
+			"SceneManager::createStaticGeometry");
+	}
+	StaticGeometry* ret = new StaticGeometry(this, name);
+	mStaticGeometryList[name] = ret;
+	return ret;
+}
+//---------------------------------------------------------------------
+StaticGeometry* SceneManager::getStaticGeometry(const String& name) const
+{
+	StaticGeometryList::const_iterator i = mStaticGeometryList.find(name);
+	if (i == mStaticGeometryList.end())
+	{
+		OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 
+			"StaticGeometry with name '" + name + "' not found", 
+			"SceneManager::createStaticGeometry");
+	}
+	return i->second;
+}
+//---------------------------------------------------------------------
+void SceneManager::destroyStaticGeometry(StaticGeometry* geom)
+{
+	destroyStaticGeometry(geom->getName());
+}
+//---------------------------------------------------------------------
+void SceneManager::destroyStaticGeometry(const String& name)
+{
+	StaticGeometryList::iterator i = mStaticGeometryList.find(name);
+	if (i != mStaticGeometryList.end())
+	{
+		delete i->second;
+		mStaticGeometryList.erase(i);
+	}
+
+}
+//---------------------------------------------------------------------
+void SceneManager::destroyAllStaticGeometry(void)
+{
+	StaticGeometryList::iterator i, iend;
+	iend = mStaticGeometryList.end();
+	for (i = mStaticGeometryList.begin(); i != iend; ++i)
+	{
+		delete i->second;
+	}
+	mStaticGeometryList.clear();
+}
+//---------------------------------------------------------------------
+AxisAlignedBoxSceneQuery* 
+SceneManager::createAABBQuery(const AxisAlignedBox& box, unsigned long mask)
+{
+    DefaultAxisAlignedBoxSceneQuery* q = new DefaultAxisAlignedBoxSceneQuery(this);
+    q->setBox(box);
+    q->setQueryMask(mask);
+    return q;
+}
+//---------------------------------------------------------------------
+SphereSceneQuery* 
+SceneManager::createSphereQuery(const Sphere& sphere, unsigned long mask)
+{
+    DefaultSphereSceneQuery* q = new DefaultSphereSceneQuery(this);
+    q->setSphere(sphere);
+    q->setQueryMask(mask);
+    return q;
+}
+//---------------------------------------------------------------------
+PlaneBoundedVolumeListSceneQuery* 
+SceneManager::createPlaneBoundedVolumeQuery(const PlaneBoundedVolumeList& volumes, 
+                                            unsigned long mask)
+{
+    DefaultPlaneBoundedVolumeListSceneQuery* q = new DefaultPlaneBoundedVolumeListSceneQuery(this);
+    q->setVolumes(volumes);
+    q->setQueryMask(mask);
+    return q;
+}
+
+//---------------------------------------------------------------------
+RaySceneQuery* 
+SceneManager::createRayQuery(const Ray& ray, unsigned long mask)
+{
+    DefaultRaySceneQuery* q = new DefaultRaySceneQuery(this);
+    q->setRay(ray);
+    q->setQueryMask(mask);
+    return q;
+}
+//---------------------------------------------------------------------
+IntersectionSceneQuery* 
+SceneManager::createIntersectionQuery(unsigned long mask)
+{
+
+    DefaultIntersectionSceneQuery* q = new DefaultIntersectionSceneQuery(this);
+    q->setQueryMask(mask);
+    return q;
+}
+//---------------------------------------------------------------------
+void SceneManager::destroyQuery(SceneQuery* query)
+{
+    delete query;
+}
+//---------------------------------------------------------------------
+SceneManager::MovableObjectMap* 
+SceneManager::getMovableObjectMap(const String& typeName)
+{
+	MovableObjectCollectionMap::iterator i = 
+		mMovableObjectCollectionMap.find(typeName);
+	if (i == mMovableObjectCollectionMap.end())
+	{
+		// create
+		MovableObjectMap* newMap = new MovableObjectMap();
+		mMovableObjectCollectionMap[typeName] = newMap;
+		return newMap;
+	}
+	else
+	{
+		return i->second;
+	}
+}
+//---------------------------------------------------------------------
+MovableObject* SceneManager::createMovableObject(const String& name, 
+	const String& typeName, const NameValuePairList* params)
+{
+	MovableObjectFactory* factory = 
+		Root::getSingleton().getMovableObjectFactory(typeName);
+	// Check for duplicate names
+	MovableObjectMap* objectMap = getMovableObjectMap(typeName);
+
+	if (objectMap->find(name) != objectMap->end())
+	{
+		OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM, 
+			"An object of type '" + typeName + "' with name '" + name
+			+ "' already exists.", 
+			"SceneManager::createMovableObject");
+	}
+
+	MovableObject* newObj = factory->createInstance(name, this, params);
+	(*objectMap)[name] = newObj;
+
+	return newObj;
+
+}
+//---------------------------------------------------------------------
+void SceneManager::destroyMovableObject(const String& name, const String& typeName)
+{
+	MovableObjectMap* objectMap = getMovableObjectMap(typeName);
+	MovableObjectFactory* factory = 
+		Root::getSingleton().getMovableObjectFactory(typeName);
+
+	MovableObjectMap::iterator mi = objectMap->find(name);
+	if (mi != objectMap->end())
+	{
+		factory->destroyInstance(mi->second);
+		objectMap->erase(mi);
+	}
+
+}
+//---------------------------------------------------------------------
+void SceneManager::destroyAllMovableObjectsByType(const String& typeName)
+{
+	MovableObjectMap* objectMap = getMovableObjectMap(typeName);
+	MovableObjectFactory* factory = 
+		Root::getSingleton().getMovableObjectFactory(typeName);
+	MovableObjectMap::iterator i = objectMap->begin();
+	for (; i != objectMap->end(); ++i)
+	{
+		// Only destroy our own
+		if (i->second->_getManager() == this)
+		{
+			factory->destroyInstance(i->second);
+		}
+	}
+	objectMap->clear();
+
+}
+//---------------------------------------------------------------------
+void SceneManager::destroyAllMovableObjects(void)
+{
+	MovableObjectCollectionMap::iterator ci = mMovableObjectCollectionMap.begin();
+
+	for(;ci != mMovableObjectCollectionMap.end(); ++ci)
+	{
+		if (Root::getSingleton().hasMovableObjectFactory(ci->first))
+		{
+			// Only destroy if we have a factory instance; otherwise must be injected
+			MovableObjectFactory* factory = 
+				Root::getSingleton().getMovableObjectFactory(ci->first);
+			MovableObjectMap::iterator i = ci->second->begin();
+			for (; i != ci->second->end(); ++i)
+			{
+				if (i->second->_getManager() == this)
+				{
+					factory->destroyInstance(i->second);
+				}
+			}
+		}
+		ci->second->clear();
+	}
+
+}
+//---------------------------------------------------------------------
+MovableObject* SceneManager::getMovableObject(const String& name, const String& typeName)
+{
+	
+	MovableObjectMap* objectMap = getMovableObjectMap(typeName);
+	MovableObjectMap::iterator mi = objectMap->find(name);
+	if (mi == objectMap->end())
+	{
+		OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 
+			"Object named '" + name + "' does not exist.", 
+			"SceneManager::getMovableObject");
+	}
+	return mi->second;
+	
+}
+//---------------------------------------------------------------------
+SceneManager::MovableObjectIterator 
+SceneManager::getMovableObjectIterator(const String& typeName)
+{
+	MovableObjectMap* objectMap = getMovableObjectMap(typeName);
+
+	return MovableObjectIterator(objectMap->begin(), objectMap->end());
+}
+//---------------------------------------------------------------------
+void SceneManager::destroyMovableObject(MovableObject* m)
+{
+	destroyMovableObject(m->getName(), m->getMovableType());
+}
+//---------------------------------------------------------------------
+void SceneManager::injectMovableObject(MovableObject* m)
+{
+	MovableObjectMap* objectMap = getMovableObjectMap(m->getMovableType());
+	(*objectMap)[m->getName()] = m;
+}
+//---------------------------------------------------------------------
+void SceneManager::extractMovableObject(const String& name, const String& typeName)
+{
+	MovableObjectMap* objectMap = getMovableObjectMap(typeName);
+	MovableObjectMap::iterator mi = objectMap->find(name);
+	if (mi != objectMap->end())
+	{
+		// no delete
+		objectMap->erase(mi);
+	}
+
+}
+//---------------------------------------------------------------------
+void SceneManager::extractMovableObject(MovableObject* m)
+{
+	extractMovableObject(m->getName(), m->getMovableType());
+}
+//---------------------------------------------------------------------
+void SceneManager::extractAllMovableObjectsByType(const String& typeName)
+{
+	MovableObjectMap* objectMap = getMovableObjectMap(typeName);
+	// no deletion
+	objectMap->clear();
+
+}
+//---------------------------------------------------------------------
+void SceneManager::_injectRenderWithPass(Pass *pass, Renderable *rend)
+{
+	// render something as if it came from the current queue
+    const Pass *usedPass = _setPass(pass);
+    renderSingleObject(rend, usedPass, false);
+}
+//---------------------------------------------------------------------
+RenderSystem *SceneManager::getDestinationRenderSystem()
+{
+	return mDestRenderSystem;
+}
+
+}
Index: OGRE/trunk/ogre_changes/Ogre1.2/RenderSystems/Direct3D9/include/OgreD3D9RenderSystem.h
===================================================================
--- OGRE/trunk/ogre_changes/Ogre1.2/RenderSystems/Direct3D9/include/OgreD3D9RenderSystem.h	(revision 768)
+++ OGRE/trunk/ogre_changes/Ogre1.2/RenderSystems/Direct3D9/include/OgreD3D9RenderSystem.h	(revision 768)
@@ -0,0 +1,332 @@
+/*
+-----------------------------------------------------------------------------
+This source file is part of OGRE
+    (Object-oriented Graphics Rendering Engine)
+For the latest info, see http://ogre.sourceforge.net/
+
+Copyright (c) 2000-2005 The OGRE Team
+Also see acknowledgements in Readme.html
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+#ifndef __D3D9RENDERSYSTEM_H__
+#define __D3D9RENDERSYSTEM_H__
+
+#include "OgreD3D9Prerequisites.h"
+#include "OgreString.h"
+#include "OgreStringConverter.h"
+#include "OgreRenderSystem.h"
+#include "OgreD3D9Mappings.h"
+
+#include "OgreNoMemoryMacros.h"
+#include <d3d9.h>
+#include <d3dx9.h>
+#include <dxerr9.h>
+#include "OgreMemoryMacros.h"
+
+namespace Ogre 
+{
+#define MAX_LIGHTS 8
+
+	class D3D9DriverList;
+	class D3D9Driver;
+
+	/**
+	Implementation of DirectX9 as a rendering system.
+	*/
+	class D3D9RenderSystem : public RenderSystem
+	{
+	private:
+		/// Direct3D
+		LPDIRECT3D9			mpD3D;
+		/// Direct3D rendering device
+		LPDIRECT3DDEVICE9	mpD3DDevice;
+		
+		// Stored options
+		ConfigOptionMap mOptions;
+		/// full-screen multisampling antialiasing type
+		D3DMULTISAMPLE_TYPE mFSAAType;
+		/// full-screen multisampling antialiasing level
+		DWORD mFSAAQuality;
+
+		/// instance
+		HINSTANCE mhInstance;
+
+		/// List of D3D drivers installed (video cards)
+		D3D9DriverList* mDriverList;
+		/// Currently active driver
+		D3D9Driver* mActiveD3DDriver;
+		/// Device caps.
+		D3DCAPS9 mCaps;
+		/// NVPerfHUD allowed?
+		bool mUseNVPerfHUD;
+
+		/// structure holding texture unit settings for every stage
+		struct sD3DTextureStageDesc
+		{
+			/// the type of the texture
+			D3D9Mappings::eD3DTexType texType;
+			/// wich texCoordIndex to use
+			size_t coordIndex;
+			/// type of auto tex. calc. used
+			TexCoordCalcMethod autoTexCoordType;
+            /// Frustum, used if the above is projection
+            const Frustum *frustum;
+			/// texture 
+			IDirect3DBaseTexture9 *pTex;
+		}
+#ifdef GAMETOOLS_ILLUMINATION_MODULE
+		mTexStageDesc[OGRE_MAX_TEXTURE_LAYERS + 4];
+#else
+		mTexStageDesc[OGRE_MAX_TEXTURE_LAYERS];
+#endif
+
+		// Array of up to 8 lights, indexed as per API
+		// Note that a null value indeicates a free slot
+		Light* mLights[MAX_LIGHTS];
+
+		D3D9DriverList* getDirect3DDrivers(void);
+		void refreshD3DSettings(void);
+		void freeDevice(void);
+
+		inline bool compareDecls( D3DVERTEXELEMENT9* pDecl1, D3DVERTEXELEMENT9* pDecl2, size_t size );
+
+
+		void initInputDevices(void);
+		void processInputDevices(void);
+		void setD3D9Light( size_t index, Light* light );
+		
+		// state management methods, very primitive !!!
+		HRESULT __SetRenderState(D3DRENDERSTATETYPE state, DWORD value);
+		HRESULT __SetSamplerState(DWORD sampler, D3DSAMPLERSTATETYPE type, DWORD value);
+		HRESULT __SetTextureStageState(DWORD stage, D3DTEXTURESTAGESTATETYPE type, DWORD value);
+
+		HRESULT __SetFloatRenderState(D3DRENDERSTATETYPE state, Real value)
+		{
+#if OGRE_DOUBLE_PRECISION == 1
+			float temp = static_cast<float>(value);
+			return __SetRenderState(state, *((LPDWORD)(&temp)));
+#else
+			return __SetRenderState(state, *((LPDWORD)(&value)));
+#endif
+		}
+
+		/// return anisotropy level
+		DWORD _getCurrentAnisotropy(size_t unit);
+		/// check if a FSAA is supported
+		bool _checkMultiSampleQuality(D3DMULTISAMPLE_TYPE type, DWORD *outQuality, D3DFORMAT format, UINT adapterNum, D3DDEVTYPE deviceType, BOOL fullScreen);
+		/// set FSAA
+		void _setFSAA(D3DMULTISAMPLE_TYPE type, DWORD qualityLevel);
+		
+		D3D9HardwareBufferManager* mHardwareBufferManager;
+		D3D9GpuProgramManager* mGpuProgramManager;
+        //D3D9HLSLProgramFactory* mHLSLProgramFactory;
+
+		size_t mLastVertexSourceCount;
+
+
+        /// Internal method for populating the capabilities structure
+        void initCapabilities(void);
+
+        void convertVertexShaderCaps(void);
+        void convertPixelShaderCaps(void);
+
+        unsigned short mCurrentLights;
+        /// Saved last view matrix
+        Matrix4 mViewMatrix;
+
+		// What follows is a set of duplicated lists just to make it
+		// easier to deal with lost devices
+		
+		/// Primary window, the one used to create the device
+		D3D9RenderWindow* mPrimaryWindow;
+
+		typedef std::vector<D3D9RenderWindow*> SecondaryWindowList;
+		// List of additional windows after the first (swap chains)
+		SecondaryWindowList mSecondaryWindows;
+
+		bool mDeviceLost;
+		bool mBasicStatesInitialised;
+
+		/** Mapping of texture format -> DepthStencil. Used as cache by _getDepthStencilFormatFor
+		*/
+		typedef HashMap<unsigned int, D3DFORMAT> DepthStencilHash;
+		DepthStencilHash mDepthStencilHash;
+
+		/** Mapping of depthstencil format -> depthstencil buffer
+			Keep one depthstencil buffer around for every format that is used, it must be large
+			enough to hold the largest rendering target.
+			This is used as cache by _getDepthStencilFor.
+		*/
+		typedef std::pair<D3DFORMAT, D3DMULTISAMPLE_TYPE> ZBufferFormat;
+		struct ZBufferRef
+		{
+			IDirect3DSurface9 *surface;
+			size_t width, height;
+		};
+		typedef std::map<ZBufferFormat, ZBufferRef> ZBufferHash;
+		ZBufferHash mZBufferHash;
+	public:
+		// constructor
+		D3D9RenderSystem( HINSTANCE hInstance );
+		// destructor
+		~D3D9RenderSystem();
+
+		virtual void initConfigOptions(void);
+
+		// Overridden RenderSystem functions
+		ConfigOptionMap& getConfigOptions(void);
+		String validateConfigOptions(void);
+		RenderWindow* initialise( bool autoCreateWindow, const String& windowTitle = "OGRE Render Window"  );
+		/// @copydoc RenderSystem::createRenderWindow
+		RenderWindow* createRenderWindow(const String &name, unsigned int width, unsigned int height, 
+			bool fullScreen, const NameValuePairList *miscParams = 0);
+
+		/// @copydoc RenderSystem::createRenderTexture
+		RenderTexture * createRenderTexture( const String & name, unsigned int width, unsigned int height,
+		 	TextureType texType = TEX_TYPE_2D, PixelFormat internalFormat = PF_X8R8G8B8, 
+			const NameValuePairList *miscParams = 0 ); 
+
+		/// @copydoc RenderSystem::createMultiRenderTarget
+		virtual MultiRenderTarget * createMultiRenderTarget(const String & name);
+
+		String getErrorDescription( long errorNumber ) const;
+		const String& getName(void) const;
+		// Low-level overridden members
+		void setConfigOption( const String &name, const String &value );
+		void reinitialise();
+		void shutdown();
+		void setAmbientLight( float r, float g, float b );
+		void setShadingType( ShadeOptions so );
+		void setLightingEnabled( bool enabled );
+		void destroyRenderTarget(const String& name);
+		VertexElementType getColourVertexElementType(void) const;
+		void setStencilCheckEnabled(bool enabled);
+        void setStencilBufferParams(CompareFunction func = CMPF_ALWAYS_PASS, 
+            uint32 refValue = 0, uint32 mask = 0xFFFFFFFF, 
+            StencilOperation stencilFailOp = SOP_KEEP, 
+            StencilOperation depthFailOp = SOP_KEEP,
+            StencilOperation passOp = SOP_KEEP, 
+            bool twoSidedOperation = false);
+        void setNormaliseNormals(bool normalise);
+
+		// Low-level overridden members, mainly for internal use
+        void _useLights(const LightList& lights, unsigned short limit);
+		void _setWorldMatrix( const Matrix4 &m );
+		void _setViewMatrix( const Matrix4 &m );
+		void _setProjectionMatrix( const Matrix4 &m );
+		void _setSurfaceParams( const ColourValue &ambient, const ColourValue &diffuse, const ColourValue &specular, const ColourValue &emissive, Real shininess, TrackVertexColourType tracking );
+		void _setPointSpritesEnabled(bool enabled);
+		void _setPointParameters(Real size, bool attenuationEnabled, 
+			Real constant, Real linear, Real quadratic, Real minSize, Real maxSize);
+		void _setTexture( size_t unit, bool enabled, const String &texname );
+        void _setTextureCoordSet( size_t unit, size_t index );
+        void _setTextureCoordCalculation(size_t unit, TexCoordCalcMethod m, 
+            const Frustum* frustum = 0);
+		void _setTextureBlendMode( size_t unit, const LayerBlendModeEx& bm );
+        void _setTextureAddressingMode(size_t stage, const TextureUnitState::UVWAddressingMode& uvw);
+        void _setTextureBorderColour(size_t stage, const ColourValue& colour);
+		void _setTextureMatrix( size_t unit, const Matrix4 &xform );
+		void _setSceneBlending( SceneBlendFactor sourceFactor, SceneBlendFactor destFactor );
+		void _setAlphaRejectSettings( CompareFunction func, unsigned char value );
+		void _setViewport( Viewport *vp );
+		void _beginFrame(void);
+		void _endFrame(void);
+		void _setCullingMode( CullingMode mode );
+		void _setDepthBufferParams( bool depthTest = true, bool depthWrite = true, CompareFunction depthFunction = CMPF_LESS_EQUAL );
+		void _setDepthBufferCheckEnabled( bool enabled = true );
+		void _setColourBufferWriteEnabled(bool red, bool green, bool blue, bool alpha);
+		void _setDepthBufferWriteEnabled(bool enabled = true);
+		void _setDepthBufferFunction( CompareFunction func = CMPF_LESS_EQUAL );
+		void _setDepthBias(ushort bias);
+		void _setFog( FogMode mode = FOG_NONE, const ColourValue& colour = ColourValue::White, Real expDensity = 1.0, Real linearStart = 0.0, Real linearEnd = 1.0 );
+		void _convertProjectionMatrix(const Matrix4& matrix,
+            Matrix4& dest, bool forGpuProgram = false);
+		void _makeProjectionMatrix(const Radian& fovy, Real aspect, Real nearPlane, Real farPlane, 
+            Matrix4& dest, bool forGpuProgram = false);
+		void _makeProjectionMatrix(Real left, Real right, Real bottom, Real top, Real nearPlane, 
+            Real farPlane, Matrix4& dest, bool forGpuProgram = false);
+		void _makeOrthoMatrix(const Radian& fovy, Real aspect, Real nearPlane, Real farPlane, 
+            Matrix4& dest, bool forGpuProgram = false);
+        void _applyObliqueDepthProjection(Matrix4& matrix, const Plane& plane, 
+            bool forGpuProgram);
+		void _setPolygonMode(PolygonMode level);
+        void _setTextureUnitFiltering(size_t unit, FilterType ftype, FilterOptions filter);
+		void _setTextureLayerAnisotropy(size_t unit, unsigned int maxAnisotropy);
+		void setVertexDeclaration(VertexDeclaration* decl);
+		void setVertexBufferBinding(VertexBufferBinding* binding);
+        void _render(const RenderOperation& op);
+        /** See
+          RenderSystem
+         */
+        void bindGpuProgram(GpuProgram* prg);
+        /** See
+          RenderSystem
+         */
+        void unbindGpuProgram(GpuProgramType gptype);
+        /** See
+          RenderSystem
+         */
+        void bindGpuProgramParameters(GpuProgramType gptype, GpuProgramParametersSharedPtr params);
+        /** See
+          RenderSystem
+         */
+        void bindGpuProgramPassIterationParameters(GpuProgramType gptype);
+        /** See
+          RenderSystem
+         */
+        void setClipPlanes(const PlaneList& clipPlanes);
+
+        void setScissorTest(bool enabled, size_t left = 0, size_t top = 0, size_t right = 800, size_t bottom = 600);
+        void clearFrameBuffer(unsigned int buffers, 
+            const ColourValue& colour = ColourValue::Black, 
+            Real depth = 1.0f, unsigned short stencil = 0);
+		void setClipPlane (ushort index, Real A, Real B, Real C, Real D);
+		void enableClipPlane (ushort index, bool enable);
+        HardwareOcclusionQuery* createHardwareOcclusionQuery(void);
+        Real getHorizontalTexelOffset(void);
+        Real getVerticalTexelOffset(void);
+        Real getMinimumDepthInputValue(void);
+        Real getMaximumDepthInputValue(void);
+
+		/** D3D specific method to restore a lost device. */
+		void restoreLostDevice(void);
+		/** D3D specific method to return whether the device has been lost. */
+		bool isDeviceLost(void);
+		/** Notify that a device has been lost */
+		void _notifyDeviceLost(void);
+
+		/** Check which depthStencil formats can be used with a certain pixel format,
+			and return the best suited.
+		*/
+		D3DFORMAT _getDepthStencilFormatFor(D3DFORMAT fmt);
+
+		/** Get a depth stencil surface that is compatible with an internal pixel format and
+			multisample type.
+			@returns A directx surface, or 0 if there is no compatible depthstencil possible.
+		*/
+		IDirect3DSurface9* _getDepthStencilFor(D3DFORMAT fmt, D3DMULTISAMPLE_TYPE multisample, size_t width, size_t height);
+
+		/** Clear all cached depth stencil surfaces
+		*/
+		void _cleanupDepthStencils();
+
+#ifdef GAMETOOLS_ILLUMINATION_MODULE
+		virtual void _setTextureUnitSettings(size_t texUnit, TextureUnitState& tl);
+#endif
+	};
+}
+#endif
Index: OGRE/trunk/ogre_changes/Ogre1.2/RenderSystems/Direct3D9/src/OgreD3D9RenderSystem.cpp
===================================================================
--- OGRE/trunk/ogre_changes/Ogre1.2/RenderSystems/Direct3D9/src/OgreD3D9RenderSystem.cpp	(revision 768)
+++ OGRE/trunk/ogre_changes/Ogre1.2/RenderSystems/Direct3D9/src/OgreD3D9RenderSystem.cpp	(revision 768)
@@ -0,0 +1,3253 @@
+/*
+-----------------------------------------------------------------------------
+This source file is part of OGRE
+    (Object-oriented Graphics Rendering Engine)
+For the latest info, see http://ogre.sourceforge.net/
+
+Copyright (c) 2000-2005 The OGRE Team
+Also see acknowledgements in Readme.html
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+#include "OgreD3D9RenderSystem.h"
+#include "OgreD3D9Prerequisites.h"
+#include "OgreD3D9DriverList.h"
+#include "OgreD3D9Driver.h"
+#include "OgreD3D9VideoModeList.h"
+#include "OgreD3D9VideoMode.h"
+#include "OgreD3D9RenderWindow.h"
+#include "OgreD3D9TextureManager.h"
+#include "OgreD3D9Texture.h"
+#include "OgreLogManager.h"
+#include "OgreLight.h"
+#include "OgreMath.h"
+#include "OgreD3D9HardwareBufferManager.h"
+#include "OgreD3D9HardwareIndexBuffer.h"
+#include "OgreD3D9HardwareVertexBuffer.h"
+#include "OgreD3D9VertexDeclaration.h"
+#include "OgreD3D9GpuProgram.h"
+#include "OgreD3D9GpuProgramManager.h"
+//#include "OgreD3D9HLSLProgramFactory.h"
+#include "OgreHighLevelGpuProgramManager.h"
+#include "OgreD3D9HardwareOcclusionQuery.h"
+#include "OgreFrustum.h"
+#include "OgreD3D9MultiRenderTarget.h"
+
+
+namespace Ogre 
+{
+
+	//---------------------------------------------------------------------
+	D3D9RenderSystem::D3D9RenderSystem( HINSTANCE hInstance )
+	{
+		OgreGuard( "D3D9RenderSystem::D3D9RenderSystem" );
+		LogManager::getSingleton().logMessage( "D3D9 : " + getName() + " created." );
+
+		// set the instance being passed 
+		mhInstance = hInstance;
+
+		// set pointers to NULL
+		mpD3D = NULL;
+		mpD3DDevice = NULL;
+		mDriverList = NULL;
+		mActiveD3DDriver = NULL;
+        mTextureManager = NULL;
+        mHardwareBufferManager = NULL;
+		mGpuProgramManager = NULL;
+		mPrimaryWindow = NULL;
+		mDeviceLost = false;
+		mBasicStatesInitialised = false;
+		mUseNVPerfHUD = false;
+        //mHLSLProgramFactory = NULL;
+
+		// init lights
+		for(int i = 0; i < MAX_LIGHTS; i++ )
+			mLights[i] = 0;
+
+		// Create our Direct3D object
+		if( NULL == (mpD3D = Direct3DCreate9(D3D_SDK_VERSION)) )
+			OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Failed to create Direct3D9 object", "D3D9RenderSystem::D3D9RenderSystem" );
+
+		// set config options defaults
+		initConfigOptions();
+
+		// fsaa options
+		mFSAAType = D3DMULTISAMPLE_NONE;
+		mFSAAQuality = 0;
+
+#ifdef GAMETOOLS_ILLUMINATION_MODULE
+		for (size_t n = 0; n < OGRE_MAX_TEXTURE_LAYERS + 4; n++)
+		{
+			mTexStageDesc[n].autoTexCoordType = TEXCALC_NONE;
+			mTexStageDesc[n].coordIndex = 0;
+			mTexStageDesc[n].texType = D3D9Mappings::D3D_TEX_TYPE_NORMAL;
+			mTexStageDesc[n].pTex = 0;
+		}
+#else
+		// set stages desc. to defaults
+		for (size_t n = 0; n < OGRE_MAX_TEXTURE_LAYERS; n++)
+		{
+			mTexStageDesc[n].autoTexCoordType = TEXCALC_NONE;
+			mTexStageDesc[n].coordIndex = 0;
+			mTexStageDesc[n].texType = D3D9Mappings::D3D_TEX_TYPE_NORMAL;
+			mTexStageDesc[n].pTex = 0;
+		}
+#endif
+
+		mLastVertexSourceCount = 0;
+
+        mCurrentLights = 0;
+
+		// Enumerate events
+		mEventNames.push_back("DeviceLost");
+		mEventNames.push_back("DeviceRestored");
+
+
+		OgreUnguard();
+	}
+	//---------------------------------------------------------------------
+	D3D9RenderSystem::~D3D9RenderSystem()
+	{
+		OgreGuard( "D3D9RenderSystem::~D3D9RenderSystem" );
+        shutdown();
+
+		
+		
+		SAFE_DELETE( mDriverList );
+		SAFE_DELETE( mTextureManager );
+        SAFE_DELETE(mHardwareBufferManager);
+        //SAFE_DELETE(mHLSLProgramFactory);
+		SAFE_DELETE(mGpuProgramManager);
+		SAFE_RELEASE( mpD3D );
+
+		LogManager::getSingleton().logMessage( "D3D9 : " + getName() + " destroyed." );
+		OgreUnguard();
+	}
+	//---------------------------------------------------------------------
+	const String& D3D9RenderSystem::getName() const
+	{
+		static String strName( "Direct3D9 Rendering Subsystem");
+		return strName;
+	}
+	//---------------------------------------------------------------------
+	D3D9DriverList* D3D9RenderSystem::getDirect3DDrivers()
+	{
+		if( !mDriverList )
+			mDriverList = new D3D9DriverList( mpD3D );
+
+		return mDriverList;
+	}
+	//---------------------------------------------------------------------
+	bool D3D9RenderSystem::_checkMultiSampleQuality(D3DMULTISAMPLE_TYPE type, DWORD *outQuality, D3DFORMAT format, UINT adapterNum, D3DDEVTYPE deviceType, BOOL fullScreen)
+	{
+		HRESULT hr;
+		hr = mpD3D->CheckDeviceMultiSampleType( 
+				adapterNum, 
+				deviceType, 
+				format, 
+				fullScreen, 
+				type, 
+				outQuality);
+
+		if (SUCCEEDED(hr))
+			return true;
+		else
+			return false;
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::initConfigOptions()
+	{
+		OgreGuard( "D3D9RenderSystem::initConfigOptions" );
+
+		D3D9DriverList* driverList;
+		D3D9Driver* driver;
+
+		ConfigOption optDevice;
+		ConfigOption optVideoMode;
+		ConfigOption optFullScreen;
+		ConfigOption optVSync;
+		ConfigOption optAA;
+		ConfigOption optFPUMode;
+		ConfigOption optNVPerfHUD;
+
+		driverList = this->getDirect3DDrivers();
+
+		optDevice.name = "Rendering Device";
+		optDevice.currentValue = "";
+		optDevice.possibleValues.clear();
+		optDevice.immutable = false;
+
+		optVideoMode.name = "Video Mode";
+		optVideoMode.currentValue = "800 x 600 @ 32-bit colour";
+		optVideoMode.immutable = false;
+
+		optFullScreen.name = "Full Screen";
+		optFullScreen.possibleValues.push_back( "Yes" );
+		optFullScreen.possibleValues.push_back( "No" );
+		optFullScreen.currentValue = "Yes";
+		optFullScreen.immutable = false;
+
+		for( unsigned j=0; j < driverList->count(); j++ )
+		{
+			driver = driverList->item(j);
+			optDevice.possibleValues.push_back( driver->DriverDescription() );
+			// Make first one default
+			if( j==0 )
+				optDevice.currentValue = driver->DriverDescription();
+		}
+
+		optVSync.name = "VSync";
+		optVSync.immutable = false;
+		optVSync.possibleValues.push_back( "Yes" );
+		optVSync.possibleValues.push_back( "No" );
+		optVSync.currentValue = "No";
+
+		optAA.name = "Anti aliasing";
+		optAA.immutable = false;
+		optAA.possibleValues.push_back( "None" );
+		optAA.currentValue = "None";
+
+		optFPUMode.name = "Floating-point mode";
+#if OGRE_DOUBLE_PRECISION
+		optFPUMode.currentValue = "Consistent";
+#else
+		optFPUMode.currentValue = "Fastest";
+#endif
+		optFPUMode.possibleValues.clear();
+		optFPUMode.possibleValues.push_back("Fastest");
+		optFPUMode.possibleValues.push_back("Consistent");
+		optFPUMode.immutable = false;
+
+		optNVPerfHUD.currentValue = "No";
+		optNVPerfHUD.immutable = false;
+		optNVPerfHUD.name = "Allow NVPerfHUD";
+		optNVPerfHUD.possibleValues.push_back( "Yes" );
+		optNVPerfHUD.possibleValues.push_back( "No" );
+
+		mOptions[optDevice.name] = optDevice;
+		mOptions[optVideoMode.name] = optVideoMode;
+		mOptions[optFullScreen.name] = optFullScreen;
+		mOptions[optVSync.name] = optVSync;
+		mOptions[optAA.name] = optAA;
+		mOptions[optFPUMode.name] = optFPUMode;
+		mOptions[optNVPerfHUD.name] = optNVPerfHUD;
+
+		refreshD3DSettings();
+
+		OgreUnguard();
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::refreshD3DSettings()
+	{
+		OgreGuard( "D3D9RenderSystem::refreshD3DSettings" );
+
+		ConfigOption* optVideoMode;
+		D3D9Driver* driver = 0;
+		D3D9VideoMode* videoMode;
+
+		ConfigOptionMap::iterator opt = mOptions.find( "Rendering Device" );
+		if( opt != mOptions.end() )
+		{
+			for( unsigned j=0; j < getDirect3DDrivers()->count(); j++ )
+			{
+				driver = getDirect3DDrivers()->item(j);
+				if( driver->DriverDescription() == opt->second.currentValue )
+					break;
+			}
+
+			if (driver)
+			{
+				opt = mOptions.find( "Video Mode" );
+				optVideoMode = &opt->second;
+				optVideoMode->possibleValues.clear();
+				// get vide modes for this device
+				for( unsigned k=0; k < driver->getVideoModeList()->count(); k++ )
+				{
+					videoMode = driver->getVideoModeList()->item( k );
+					optVideoMode->possibleValues.push_back( videoMode->getDescription() );
+				}
+			}
+		}
+
+		OgreUnguard();
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::setConfigOption( const String &name, const String &value )
+	{
+		OgreGuard( "D3D9RenderSystem::setConfigOption" );
+
+        StringUtil::StrStreamType str;
+        str << "D3D9 : RenderSystem Option: " << name << " = " << value;
+		LogManager::getSingleton().logMessage(str.str());
+
+		// Find option
+		ConfigOptionMap::iterator it = mOptions.find( name );
+
+		// Update
+		if( it != mOptions.end() )
+			it->second.currentValue = value;
+		else
+		{
+            str.str(StringUtil::BLANK);
+            str << "Option named '" << name << "' does not exist.";
+			OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS, str.str(), "D3D9RenderSystem::setConfigOption" );
+		}
+
+		// Refresh other options if D3DDriver changed
+		if( name == "Rendering Device" )
+			refreshD3DSettings();
+
+		if( name == "Full Screen" )
+		{
+			// Video mode is applicable
+			it = mOptions.find( "Video Mode" );
+			if (it->second.currentValue == "")
+				it->second.currentValue = "800 x 600 @ 32-bit colour";
+		}
+
+		if( name == "Anti aliasing" )
+		{
+			if (value == "None")
+				_setFSAA(D3DMULTISAMPLE_NONE, 0);
+			else 
+			{
+				D3DMULTISAMPLE_TYPE fsaa = D3DMULTISAMPLE_NONE;
+				DWORD level = 0;
+
+				if (StringUtil::startsWith(value, "NonMaskable", false))
+				{
+					fsaa = D3DMULTISAMPLE_NONMASKABLE;
+					size_t pos = value.find_last_of(" ");
+					String sNum = value.substr(pos + 1);
+					level = StringConverter::parseInt(sNum);
+					level -= 1;
+				}
+				else if (StringUtil::startsWith(value, "Level", false))
+				{
+					size_t pos = value.find_last_of(" ");
+					String sNum = value.substr(pos + 1);
+					fsaa = (D3DMULTISAMPLE_TYPE)StringConverter::parseInt(sNum);
+				}
+
+				_setFSAA(fsaa, level);
+			}
+		}
+
+		if( name == "VSync" )
+		{
+			if (value == "Yes")
+				mVSync = true;
+			else
+				mVSync = false;
+		}
+
+		if( name == "Allow NVPerfHUD" )
+		{
+			if (value == "Yes")
+				mUseNVPerfHUD = true;
+			else
+				mUseNVPerfHUD = false;
+		}
+
+		if( name == "Video Mode" )
+		{
+			ConfigOption* optFSAA;
+			it = mOptions.find( "Anti aliasing" );
+			optFSAA = &it->second;
+			optFSAA->possibleValues.clear();
+			optFSAA->possibleValues.push_back("None");
+
+			it = mOptions.find("Rendering Device");
+			D3D9Driver *driver = getDirect3DDrivers()->item(it->second.currentValue);
+			if (driver)
+			{
+				it = mOptions.find("Video Mode");
+				D3D9VideoMode *videoMode = driver->getVideoModeList()->item(it->second.currentValue);
+				if (videoMode)
+				{
+					// get non maskable FSAA for this VMODE
+					DWORD numLevels = 0;
+					bool bOK = this->_checkMultiSampleQuality(
+						D3DMULTISAMPLE_NONMASKABLE, 
+						&numLevels, 
+						videoMode->getFormat(), 
+						driver->getAdapterNumber(),
+						D3DDEVTYPE_HAL,
+						TRUE);
+					if (bOK && numLevels > 0)
+					{
+						for (DWORD n = 0; n < numLevels; n++)
+							optFSAA->possibleValues.push_back("NonMaskable " + StringConverter::toString(n + 1));
+					}
+
+					// set maskable levels supported
+					for (unsigned int n = 2; n < 17; n++)
+					{
+						bOK = this->_checkMultiSampleQuality(
+							(D3DMULTISAMPLE_TYPE)n, 
+							&numLevels, 
+							videoMode->getFormat(), 
+							driver->getAdapterNumber(),
+							D3DDEVTYPE_HAL,
+							TRUE);
+						if (bOK)
+							optFSAA->possibleValues.push_back("Level " + StringConverter::toString(n));
+					}
+				}
+			}
+		}
+
+		OgreUnguard();
+	}
+	//---------------------------------------------------------------------
+	String D3D9RenderSystem::validateConfigOptions()
+	{
+		ConfigOptionMap::iterator it;
+		
+		// check if video mode is selected
+		it = mOptions.find( "Video Mode" );
+		if( it->second.currentValue == "" )
+			return "A video mode must be selected.";
+
+		it = mOptions.find( "Rendering Device" );
+		bool foundDriver = false;
+		D3D9DriverList* driverList = getDirect3DDrivers();
+		for( ushort j=0; j < driverList->count(); j++ )
+		{
+			if( driverList->item(j)->DriverDescription() == it->second.currentValue )
+			{
+				foundDriver = true;
+				break;
+			}
+		}
+
+		if (!foundDriver)
+		{
+			// Just pick the first driver
+			setConfigOption("Rendering Device", driverList->item(0)->DriverDescription());
+			return "Your DirectX driver name has changed since the last time you ran OGRE; "
+				"the 'Rendering Device' has been changed.";
+		}
+
+        it = mOptions.find( "VSync" );
+		if( it->second.currentValue == "Yes" )
+			mVSync = true;
+		else
+			mVSync = false;
+
+		return "";
+	}
+	//---------------------------------------------------------------------
+	ConfigOptionMap& D3D9RenderSystem::getConfigOptions()
+	{
+		// return a COPY of the current config options
+		return mOptions;
+	}
+	//---------------------------------------------------------------------
+	RenderWindow* D3D9RenderSystem::initialise( bool autoCreateWindow, const String& windowTitle )
+	{
+		RenderWindow* autoWindow = NULL;
+		LogManager::getSingleton().logMessage( "D3D9 : Subsystem Initialising" );
+
+		// Init using current settings
+		mActiveD3DDriver = NULL;
+		ConfigOptionMap::iterator opt = mOptions.find( "Rendering Device" );
+		for( unsigned j=0; j < getDirect3DDrivers()->count(); j++ )
+		{
+			if( getDirect3DDrivers()->item(j)->DriverDescription() == opt->second.currentValue )
+			{
+				mActiveD3DDriver = getDirect3DDrivers()->item(j);
+				break;
+			}
+		}
+
+		if( !mActiveD3DDriver )
+			OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS, "Problems finding requested Direct3D driver!", "D3D9RenderSystem::initialise" );
+
+		if( autoCreateWindow )
+		{
+			bool fullScreen;
+			opt = mOptions.find( "Full Screen" );
+			if( opt == mOptions.end() )
+				Exception( Exception::ERR_INTERNAL_ERROR, "Can't find full screen option!", "D3D9RenderSystem::initialise" );
+			fullScreen = opt->second.currentValue == "Yes";
+
+			D3D9VideoMode* videoMode = NULL;
+			unsigned int width, height;
+			String temp;
+
+			opt = mOptions.find( "Video Mode" );
+			if( opt == mOptions.end() )
+				Exception( Exception::ERR_INTERNAL_ERROR, "Can't find Video Mode option!", "D3D9RenderSystem::initialise" );
+
+			for( unsigned j=0; j < mActiveD3DDriver->getVideoModeList()->count(); j++ )
+			{
+				temp = mActiveD3DDriver->getVideoModeList()->item(j)->getDescription();
+				if( temp == opt->second.currentValue )
+				{
+					videoMode = mActiveD3DDriver->getVideoModeList()->item(j);
+					break;
+				}
+			}
+
+			if( !videoMode )
+				OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Can't find requested video mode.", "D3D9RenderSystem::initialise" );
+
+			width = videoMode->getWidth();
+			height = videoMode->getHeight();
+			
+			NameValuePairList miscParams;
+			miscParams["colourDepth"] = StringConverter::toString(videoMode->getColourDepth());
+			miscParams["FSAA"] = StringConverter::toString(mFSAAType);
+			miscParams["FSAAQuality"] = StringConverter::toString(mFSAAQuality);
+			miscParams["vsync"] = StringConverter::toString(mVSync);
+			miscParams["useNVPerfHUD"] = StringConverter::toString(mUseNVPerfHUD);
+
+			autoWindow = this->createRenderWindow( windowTitle, width, height, 
+				fullScreen, &miscParams );
+
+            // If we have 16bit depth buffer enable w-buffering.
+            assert( autoWindow );
+            if ( autoWindow->getColourDepth() == 16 ) 
+            { 
+                mWBuffer = true;
+            } 
+            else 
+            {
+                mWBuffer = false;
+            }
+		}
+
+        LogManager::getSingleton().logMessage("***************************************");
+
+		LogManager::getSingleton().logMessage("*** D3D9 : Subsystem Initialised OK ***");
+        LogManager::getSingleton().logMessage("***************************************");
+
+		// call superclass method
+		RenderSystem::initialise( autoCreateWindow );
+
+
+		return autoWindow;
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::_setFSAA(D3DMULTISAMPLE_TYPE type, DWORD qualityLevel)
+	{
+		if (!mpD3DDevice)
+		{
+			mFSAAType = type;
+			mFSAAQuality = qualityLevel;
+		}
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::reinitialise()
+	{
+		LogManager::getSingleton().logMessage( "D3D9 : Reinitialising" );
+		this->shutdown();
+		this->initialise( true );
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::shutdown()
+	{
+		RenderSystem::shutdown();
+		freeDevice();
+		SAFE_DELETE( mDriverList );
+		mActiveD3DDriver = NULL;
+		mpD3DDevice = NULL;
+		mBasicStatesInitialised = false;
+		LogManager::getSingleton().logMessage("D3D9 : Shutting down cleanly.");
+	}
+	//---------------------------------------------------------------------
+	RenderWindow* D3D9RenderSystem::createRenderWindow(const String &name, 
+		unsigned int width, unsigned int height, bool fullScreen,
+		const NameValuePairList *miscParams)
+	{
+
+		OgreGuard( "D3D9RenderSystem::createRenderWindow" );
+
+		// Check we're not creating a secondary window when the primary
+		// was fullscreen
+		if (mPrimaryWindow && mPrimaryWindow->isFullScreen())
+		{
+			OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 
+				"Cannot create secondary windows when the primary is full screen",
+				"D3D9RenderSystem::createRenderWindow");
+		}
+		if (mPrimaryWindow && fullScreen)
+		{
+			OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 
+				"Cannot create full screen secondary windows",
+				"D3D9RenderSystem::createRenderWindow");
+		}
+		
+		// Log a message
+		std::stringstream ss;
+		ss << "D3D9RenderSystem::createRenderWindow \"" << name << "\", " <<
+			width << "x" << height << " ";
+		if(fullScreen)
+			ss << "fullscreen ";
+		else
+			ss << "windowed ";
+		if(miscParams)
+		{
+			ss << " miscParams: ";
+			NameValuePairList::const_iterator it;
+			for(it=miscParams->begin(); it!=miscParams->end(); ++it)
+			{
+				ss << it->first << "=" << it->second << " ";
+			}
+			LogManager::getSingleton().logMessage(ss.str());
+		}
+		
+		String msg;
+
+		// Make sure we don't already have a render target of the 
+		// sam name as the one supplied
+		if( mRenderTargets.find( name ) != mRenderTargets.end() )
+		{
+			msg = "A render target of the same name '" + name + "' already "
+				"exists.  You cannot create a new window with this name.";
+			OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, msg, "D3D9RenderSystem::createRenderWindow" );
+		}
+
+		RenderWindow* win = new D3D9RenderWindow(mhInstance, mActiveD3DDriver, 
+			mPrimaryWindow ? mpD3DDevice : 0);
+
+		win->create( name, width, height, fullScreen, miscParams);
+
+		attachRenderTarget( *win );
+
+		// If this is the first window, get the D3D device and create the texture manager
+		if( !mPrimaryWindow )
+		{
+			mPrimaryWindow = (D3D9RenderWindow *)win;
+			win->getCustomAttribute( "D3DDEVICE", &mpD3DDevice );
+
+			// Create the texture manager for use by others
+			mTextureManager = new D3D9TextureManager( mpD3DDevice );
+            // Also create hardware buffer manager
+            mHardwareBufferManager = new D3D9HardwareBufferManager(mpD3DDevice);
+
+			// Create the GPU program manager
+			mGpuProgramManager = new D3D9GpuProgramManager(mpD3DDevice);
+            // create & register HLSL factory
+            //mHLSLProgramFactory = new D3D9HLSLProgramFactory();
+            //HighLevelGpuProgramManager::getSingleton().addFactory(mHLSLProgramFactory);
+            mGpuProgramManager->_pushSyntaxCode("hlsl");
+
+
+            // Initialise the capabilities structures
+            initCapabilities();
+
+		}
+		else
+		{
+			mSecondaryWindows.push_back(static_cast<D3D9RenderWindow *>(win));
+		}
+
+		OgreUnguardRet( win );
+	}
+    //---------------------------------------------------------------------
+    void D3D9RenderSystem::initCapabilities(void)
+    {
+		// get caps
+		mpD3DDevice->GetDeviceCaps( &mCaps );
+
+        // Check for hardware stencil support
+		LPDIRECT3DSURFACE9 pSurf;
+		D3DSURFACE_DESC surfDesc;
+		mpD3DDevice->GetDepthStencilSurface(&pSurf);
+		pSurf->GetDesc(&surfDesc);
+		pSurf->Release();
+
+		if (surfDesc.Format == D3DFMT_D24S8 || surfDesc.Format == D3DFMT_D24X8)
+		{
+			mCapabilities->setCapability(RSC_HWSTENCIL);
+			// Actually, it's always 8-bit
+			mCapabilities->setStencilBufferBitDepth(8);
+
+		}
+
+		// Set number of texture units
+		mCapabilities->setNumTextureUnits(mCaps.MaxSimultaneousTextures);
+        // Anisotropy?
+        if (mCaps.MaxAnisotropy > 1)
+            mCapabilities->setCapability(RSC_ANISOTROPY);
+        // Automatic mipmap generation?
+        if (mCaps.Caps2 & D3DCAPS2_CANAUTOGENMIPMAP)
+            mCapabilities->setCapability(RSC_AUTOMIPMAP);
+        // Blending between stages supported
+        mCapabilities->setCapability(RSC_BLENDING);
+        // Dot 3
+        if (mCaps.TextureOpCaps & D3DTEXOPCAPS_DOTPRODUCT3)
+            mCapabilities->setCapability(RSC_DOT3);
+        // Cube map
+        if (mCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP)
+            mCapabilities->setCapability(RSC_CUBEMAPPING);
+
+        // We always support compression, D3DX will decompress if device does not support
+        mCapabilities->setCapability(RSC_TEXTURE_COMPRESSION);
+        mCapabilities->setCapability(RSC_TEXTURE_COMPRESSION_DXT);
+
+        // We always support VBOs
+        mCapabilities->setCapability(RSC_VBO);
+
+        // Scissor test
+        if (mCaps.RasterCaps & D3DPRASTERCAPS_SCISSORTEST)
+            mCapabilities->setCapability(RSC_SCISSOR_TEST);
+
+        // Two-sided stencil
+        if (mCaps.StencilCaps & D3DSTENCILCAPS_TWOSIDED)
+            mCapabilities->setCapability(RSC_TWO_SIDED_STENCIL);
+
+        // stencil wrap
+        if ((mCaps.StencilCaps & D3DSTENCILCAPS_INCR) && 
+            (mCaps.StencilCaps & D3DSTENCILCAPS_DECR))
+            mCapabilities->setCapability(RSC_STENCIL_WRAP);
+
+        // Check for hardware occlusion support
+        if ( ( mpD3DDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION,  NULL ) ) == D3D_OK )	
+        {
+            mCapabilities->setCapability(RSC_HWOCCLUSION);
+        }
+        convertVertexShaderCaps();
+        convertPixelShaderCaps();
+
+		// User clip planes
+        if (mCaps.MaxUserClipPlanes > 0)
+		{
+			mCapabilities->setCapability(RSC_USER_CLIP_PLANES);
+		}
+
+		// UBYTE4 type?
+		if (mCaps.DeclTypes & D3DDTCAPS_UBYTE4)
+		{
+			mCapabilities->setCapability(RSC_VERTEX_FORMAT_UBYTE4);
+		}
+
+		// Infinite projection?
+		// We have no capability for this, so we have to base this on our
+		// experience and reports from users
+		// Non-vertex program capable hardware does not appear to support it
+		if (mCapabilities->hasCapability(RSC_VERTEX_PROGRAM))
+		{
+			// GeForce4 Ti (and presumably GeForce3) does not
+			// render infinite projection properly, even though it does in GL
+            // So exclude all cards prior to the FX range from doing infinite
+            const D3DADAPTER_IDENTIFIER9& adapterID = mActiveD3DDriver->getAdapterIdentifier();
+			if (adapterID.VendorId != 0x10DE || // not nVidia
+				!((adapterID.DeviceId >= 0x200 && adapterID.DeviceId <= 0x20F) || //gf3
+				  (adapterID.DeviceId >= 0x250 && adapterID.DeviceId <= 0x25F) || //gf4ti
+				  (adapterID.DeviceId >= 0x280 && adapterID.DeviceId <= 0x28F) || //gf4ti
+				  (adapterID.DeviceId >= 0x170 && adapterID.DeviceId <= 0x18F) || //gf4 go
+				  (adapterID.DeviceId >= 0x280 && adapterID.DeviceId <= 0x28F)))  //gf4ti go
+			{
+				mCapabilities->setCapability(RSC_INFINITE_FAR_PLANE);
+			}
+			
+		}
+		
+		// 3D textures?
+		if (mCaps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP)
+		{
+			mCapabilities->setCapability(RSC_TEXTURE_3D);
+		}
+		
+        // non-power-of-two texturs always supported
+        mCapabilities->setCapability(RSC_NON_POWER_OF_2_TEXTURES);
+
+		// We always support rendertextures bigger than the frame buffer
+        mCapabilities->setCapability(RSC_HWRENDER_TO_TEXTURE);
+
+		// Determine if any floating point texture format is supported
+		D3DFORMAT floatFormats[6] = {D3DFMT_R16F, D3DFMT_G16R16F, 
+			D3DFMT_A16B16G16R16F, D3DFMT_R32F, D3DFMT_G32R32F, 
+			D3DFMT_A32B32G32R32F};
+		LPDIRECT3DSURFACE9 bbSurf;
+		mPrimaryWindow->getCustomAttribute("DDBACKBUFFER", &bbSurf);
+		D3DSURFACE_DESC bbSurfDesc;
+		bbSurf->GetDesc(&bbSurfDesc);
+		
+		for (int i = 0; i < 6; ++i)
+		{
+			if (SUCCEEDED(mpD3D->CheckDeviceFormat(D3DADAPTER_DEFAULT, 
+				D3DDEVTYPE_HAL, bbSurfDesc.Format, 
+				0, D3DRTYPE_TEXTURE, floatFormats[i])))
+			{
+				mCapabilities->setCapability(RSC_TEXTURE_FLOAT);
+				break;
+			}
+			
+		}
+		
+		// Number of render targets
+		mCapabilities->setNumMultiRenderTargets(std::min((ushort)mCaps.NumSimultaneousRTs, (ushort)OGRE_MAX_MULTIPLE_RENDER_TARGETS));
+
+		//
+		if(mCaps.PrimitiveMiscCaps & D3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS)
+		{
+			LogManager::getSingleton().logMessage("Multiple render targets with independent bit depths supported");
+		}
+
+		// Point size
+		mCapabilities->setMaxPointSize(mCaps.MaxPointSize);
+		
+
+		Log* defaultLog = LogManager::getSingleton().getDefaultLog();
+		if (defaultLog)
+		{
+			mCapabilities->log(defaultLog);
+		}
+    }
+    //---------------------------------------------------------------------
+    void D3D9RenderSystem::convertVertexShaderCaps(void)
+    {
+        ushort major, minor;
+        major = static_cast<ushort>((mCaps.VertexShaderVersion & 0x0000FF00) >> 8);
+        minor = static_cast<ushort>(mCaps.VertexShaderVersion & 0x000000FF);
+
+        bool vs2x = false;
+        bool vs2a = false;
+
+        // Special case detection for vs_2_x/a support
+        if (major >= 2)
+        {
+            if ((mCaps.VS20Caps.Caps & D3DVS20CAPS_PREDICATION) &&
+                (mCaps.VS20Caps.DynamicFlowControlDepth > 0) &&
+                (mCaps.VS20Caps.NumTemps >= 12))
+            {
+                vs2x = true;
+            }
+
+            if ((mCaps.VS20Caps.Caps & D3DVS20CAPS_PREDICATION) &&
+                (mCaps.VS20Caps.DynamicFlowControlDepth > 0) &&
+                (mCaps.VS20Caps.NumTemps >= 13))
+            {
+                vs2a = true;
+            }
+        }
+
+        // Populate max version & params
+        switch (major)
+        {
+        case 1:
+            mCapabilities->setMaxVertexProgramVersion("vs_1_1");
+            // No boolean params allowed
+            mCapabilities->setVertexProgramConstantBoolCount(0);
+            // No integer params allowed
+            mCapabilities->setVertexProgramConstantIntCount(0);
+            // float params, always 4D
+            mCapabilities->setVertexProgramConstantFloatCount(mCaps.MaxVertexShaderConst);
+           
+            break;
+        case 2:
+            if (vs2a)
+            {
+                mCapabilities->setMaxVertexProgramVersion("vs_2_a");
+            }
+            else if (vs2x)
+            {
+                mCapabilities->setMaxVertexProgramVersion("vs_2_x");
+            }
+            else
+            {
+                mCapabilities->setMaxVertexProgramVersion("vs_2_0");
+            }
+            // 16 boolean params allowed
+            mCapabilities->setVertexProgramConstantBoolCount(16);
+            // 16 integer params allowed, 4D
+            mCapabilities->setVertexProgramConstantIntCount(16);
+            // float params, always 4D
+            mCapabilities->setVertexProgramConstantFloatCount(mCaps.MaxVertexShaderConst);
+            break;
+        case 3:
+            mCapabilities->setMaxVertexProgramVersion("vs_3_0");
+            // 16 boolean params allowed
+            mCapabilities->setVertexProgramConstantBoolCount(16);
+            // 16 integer params allowed, 4D
+            mCapabilities->setVertexProgramConstantIntCount(16);
+            // float params, always 4D
+            mCapabilities->setVertexProgramConstantFloatCount(mCaps.MaxVertexShaderConst);
+            break;
+        default:
+            mCapabilities->setMaxVertexProgramVersion("");
+            break;
+        }
+
+        // populate syntax codes in program manager (no breaks in this one so it falls through)
+        switch(major)
+        {
+        case 3:
+            mGpuProgramManager->_pushSyntaxCode("vs_3_0");
+        case 2:
+            if (vs2x)
+                mGpuProgramManager->_pushSyntaxCode("vs_2_x");
+            if (vs2a)
+                mGpuProgramManager->_pushSyntaxCode("vs_2_a");
+
+            mGpuProgramManager->_pushSyntaxCode("vs_2_0");
+        case 1:
+            mGpuProgramManager->_pushSyntaxCode("vs_1_1");
+            mCapabilities->setCapability(RSC_VERTEX_PROGRAM);
+        }
+    }
+    //---------------------------------------------------------------------
+    void D3D9RenderSystem::convertPixelShaderCaps(void)
+    {
+        ushort major, minor;
+        major = static_cast<ushort>((mCaps.PixelShaderVersion & 0x0000FF00) >> 8);
+        minor = static_cast<ushort>(mCaps.PixelShaderVersion & 0x000000FF);
+
+		bool ps2a = false;
+        bool ps2b = false;
+        bool ps2x = false;
+
+        // Special case detection for ps_2_x/a/b support
+        if (major >= 2)
+        {
+			if ((mCaps.PS20Caps.Caps & D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT) &&
+                (mCaps.PS20Caps.NumTemps >= 32))
+            {
+                ps2b = true;
+            }
+
+	        if ((mCaps.PS20Caps.Caps & D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT) &&
+                (mCaps.PS20Caps.Caps & D3DPS20CAPS_NODEPENDENTREADLIMIT) &&
+                (mCaps.PS20Caps.Caps & D3DPS20CAPS_ARBITRARYSWIZZLE) &&
+				(mCaps.PS20Caps.Caps & D3DPS20CAPS_GRADIENTINSTRUCTIONS) &&
+				(mCaps.PS20Caps.Caps & D3DPS20CAPS_PREDICATION) &&
+                (mCaps.PS20Caps.NumTemps >= 22))
+	        {
+                ps2a = true;
+			}
+
+            // Does this enough?
+            if (ps2a || ps2b)
+            {
+                ps2x = true;
+            }
+        }
+
+        switch (major)
+        {
+        case 1:
+            switch(minor)
+            {
+            case 1:
+                mCapabilities->setMaxFragmentProgramVersion("ps_1_1");
+                break;
+            case 2:
+                mCapabilities->setMaxFragmentProgramVersion("ps_1_2");
+                break;
+            case 3:
+                mCapabilities->setMaxFragmentProgramVersion("ps_1_3");
+                break;
+            case 4:
+                mCapabilities->setMaxFragmentProgramVersion("ps_1_4");
+                break;
+            }
+            // no boolean params allowed
+            mCapabilities->setFragmentProgramConstantBoolCount(0);
+            // no integer params allowed
+            mCapabilities->setFragmentProgramConstantIntCount(0);
+            // float params, always 4D
+            // NB in ps_1_x these are actually stored as fixed point values,
+            // but they are entered as floats
+            mCapabilities->setFragmentProgramConstantFloatCount(8);
+            break;
+        case 2:
+			if (ps2a)
+            {
+                mCapabilities->setMaxFragmentProgramVersion("ps_2_a");
+            }
+			else if (ps2b)
+            {
+                mCapabilities->setMaxFragmentProgramVersion("ps_2_b");
+            }
+			else if (ps2x)
+            {
+                mCapabilities->setMaxFragmentProgramVersion("ps_2_x");
+            }
+            else
+            {
+                mCapabilities->setMaxFragmentProgramVersion("ps_2_0");
+            }
+            // 16 boolean params allowed
+            mCapabilities->setFragmentProgramConstantBoolCount(16);
+            // 16 integer params allowed, 4D
+            mCapabilities->setFragmentProgramConstantIntCount(16);
+            // float params, always 4D
+            mCapabilities->setFragmentProgramConstantFloatCount(32);
+            break;
+        case 3:
+            if (minor > 0)
+            {
+                mCapabilities->setMaxFragmentProgramVersion("ps_3_x");
+            }
+            else
+            {
+                mCapabilities->setMaxFragmentProgramVersion("ps_3_0");
+            }
+            // 16 boolean params allowed
+            mCapabilities->setFragmentProgramConstantBoolCount(16);
+            // 16 integer params allowed, 4D
+            mCapabilities->setFragmentProgramConstantIntCount(16);
+            // float params, always 4D
+            mCapabilities->setFragmentProgramConstantFloatCount(224);
+            break;
+        default:
+            mCapabilities->setMaxFragmentProgramVersion("");
+            break;
+        }
+
+        // populate syntax codes in program manager (no breaks in this one so it falls through)
+        switch(major)
+        {
+        case 3:
+            if (minor > 0)
+                mGpuProgramManager->_pushSyntaxCode("ps_3_x");
+
+            mGpuProgramManager->_pushSyntaxCode("ps_3_0");
+        case 2:
+            if (ps2x)
+                mGpuProgramManager->_pushSyntaxCode("ps_2_x");
+            if (ps2a)
+                mGpuProgramManager->_pushSyntaxCode("ps_2_a");
+            if (ps2b)
+                mGpuProgramManager->_pushSyntaxCode("ps_2_b");
+
+            mGpuProgramManager->_pushSyntaxCode("ps_2_0");
+        case 1:
+            if (major > 1 || minor >= 4)
+                mGpuProgramManager->_pushSyntaxCode("ps_1_4");
+            if (major > 1 || minor >= 3)
+                mGpuProgramManager->_pushSyntaxCode("ps_1_3");
+            if (major > 1 || minor >= 2)
+                mGpuProgramManager->_pushSyntaxCode("ps_1_2");
+            
+            mGpuProgramManager->_pushSyntaxCode("ps_1_1");
+            mCapabilities->setCapability(RSC_FRAGMENT_PROGRAM);
+        }
+    }
+	//-----------------------------------------------------------------------
+	MultiRenderTarget * D3D9RenderSystem::createMultiRenderTarget(const String & name)
+	{
+		MultiRenderTarget *retval;
+		retval = new D3D9MultiRenderTarget(name);
+		attachRenderTarget(*retval);
+
+		return retval;
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::destroyRenderTarget(const String& name)
+	{
+		// Check in specialised lists
+		if (mPrimaryWindow->getName() == name)
+		{
+			// We're destroying the primary window, so reset device and window
+			mPrimaryWindow = 0;
+		}
+		else
+		{
+			// Check secondary windows
+			SecondaryWindowList::iterator sw;
+			for (sw = mSecondaryWindows.begin(); sw != mSecondaryWindows.end(); ++sw)
+			{
+				if ((*sw)->getName() == name)
+				{
+					mSecondaryWindows.erase(sw);
+					break;
+				}
+			}
+		}
+		// Do the real removal
+		RenderSystem::destroyRenderTarget(name);
+
+		// Did we destroy the primary?
+		if (!mPrimaryWindow)
+		{
+			// device is no longer valid, so free it all up
+			freeDevice();
+		}
+
+	}
+	//-----------------------------------------------------------------------
+	void D3D9RenderSystem::freeDevice(void)
+	{
+		if (mpD3DDevice)
+		{
+			// Set all texture units to nothing to release texture surfaces
+			_disableTextureUnitsFrom(0);
+			// Unbind any vertex streams to avoid memory leaks
+			for (unsigned int i = 0; i < mLastVertexSourceCount; ++i)
+			{
+				HRESULT hr = mpD3DDevice->SetStreamSource(i, NULL, 0, 0);
+			}
+			// Clean up depth stencil surfaces
+			_cleanupDepthStencils();
+			SAFE_RELEASE(mpD3DDevice);
+			mActiveD3DDriver->setD3DDevice(NULL);
+			mpD3DDevice = 0;
+
+		}
+
+
+	}
+	//---------------------------------------------------------------------
+	String D3D9RenderSystem::getErrorDescription( long errorNumber ) const
+	{
+		const String errMsg = DXGetErrorDescription9( errorNumber );
+		return errMsg;
+	}
+    //---------------------------------------------------------------------
+	VertexElementType D3D9RenderSystem::getColourVertexElementType(void) const
+	{
+		return VET_COLOUR_ARGB;
+	}
+   	//---------------------------------------------------------------------
+	void D3D9RenderSystem::_convertProjectionMatrix(const Matrix4& matrix,
+        Matrix4& dest, bool forGpuProgram)
+    {
+        dest = matrix;
+
+        // Convert depth range from [-1,+1] to [0,1]
+        dest[2][0] = (dest[2][0] + dest[3][0]) / 2;
+        dest[2][1] = (dest[2][1] + dest[3][1]) / 2;
+        dest[2][2] = (dest[2][2] + dest[3][2]) / 2;
+        dest[2][3] = (dest[2][3] + dest[3][3]) / 2;
+
+        if (!forGpuProgram)
+        {
+            // Convert right-handed to left-handed
+            dest[0][2] = -dest[0][2];
+            dest[1][2] = -dest[1][2];
+            dest[2][2] = -dest[2][2];
+            dest[3][2] = -dest[3][2];
+        }
+    }
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::_makeProjectionMatrix(const Radian& fovy, Real aspect, Real nearPlane, 
+        Real farPlane, Matrix4& dest, bool forGpuProgram)
+	{
+        Radian theta ( fovy * 0.5 );
+		Real h = 1 / Math::Tan(theta);
+		Real w = h / aspect;
+		Real q, qn;
+        if (farPlane == 0)
+        {
+            q = 1 - Frustum::INFINITE_FAR_PLANE_ADJUST;
+            qn = nearPlane * (Frustum::INFINITE_FAR_PLANE_ADJUST - 1);
+        }
+        else
+        {
+            q = farPlane / ( farPlane - nearPlane );
+            qn = -q * nearPlane;
+        }
+
+		dest = Matrix4::ZERO;
+		dest[0][0] = w;
+		dest[1][1] = h;
+
+        if (forGpuProgram)
+        {
+            dest[2][2] = -q;
+		    dest[3][2] = -1.0f;
+        }
+        else
+        {
+            dest[2][2] = q;
+            dest[3][2] = 1.0f;
+        }
+
+        dest[2][3] = qn;
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::_makeOrthoMatrix(const Radian& fovy, Real aspect, Real nearPlane, Real farPlane, 
+		Matrix4& dest, bool forGpuProgram )
+	{
+        Radian thetaY (fovy / 2.0f);
+        Real tanThetaY = Math::Tan(thetaY);
+
+        //Real thetaX = thetaY * aspect;
+        Real tanThetaX = tanThetaY * aspect; //Math::Tan(thetaX);
+        Real half_w = tanThetaX * nearPlane;
+        Real half_h = tanThetaY * nearPlane;
+        Real iw = 1.0 / half_w;
+        Real ih = 1.0 / half_h;
+        Real q;
+        if (farPlane == 0)
+        {
+            q = 0;
+        }
+        else
+        {
+            q = 1.0 / (farPlane - nearPlane);
+        }
+
+        dest = Matrix4::ZERO;
+        dest[0][0] = iw;
+        dest[1][1] = ih;
+        dest[2][2] = q;
+        dest[2][3] = -nearPlane / (farPlane - nearPlane);
+        dest[3][3] = 1;
+
+        if (forGpuProgram)
+        {
+            dest[2][2] = -dest[2][2];
+        }
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::setAmbientLight( float r, float g, float b )
+	{
+		HRESULT hr = __SetRenderState( D3DRS_AMBIENT, D3DCOLOR_COLORVALUE( r, g, b, 1.0f ) );
+		if( FAILED( hr ) )
+			OGRE_EXCEPT( hr, "Failed to set render stat D3DRS_AMBIENT", "D3D9RenderSystem::setAmbientLight" );
+	}
+	//---------------------------------------------------------------------
+    void D3D9RenderSystem::_useLights(const LightList& lights, unsigned short limit)
+    {
+        LightList::const_iterator i, iend;
+        iend = lights.end();
+        unsigned short num = 0;
+        for (i = lights.begin(); i != iend && num < limit; ++i, ++num)
+        {
+            setD3D9Light(num, *i);
+        }
+        // Disable extra lights
+        for (; num < mCurrentLights; ++num)
+        {
+            setD3D9Light(num, NULL);
+        }
+        mCurrentLights = std::min(limit, static_cast<unsigned short>(lights.size()));
+
+    }
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::setShadingType( ShadeOptions so )
+	{
+		HRESULT hr = __SetRenderState( D3DRS_SHADEMODE, D3D9Mappings::get(so) );
+		if( FAILED( hr ) )
+			OGRE_EXCEPT( hr, "Failed to set render stat D3DRS_SHADEMODE", "D3D9RenderSystem::setShadingType" );
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::setLightingEnabled( bool enabled )
+	{
+		HRESULT hr;
+		if( FAILED( hr = __SetRenderState( D3DRS_LIGHTING, enabled ) ) )
+			OGRE_EXCEPT( hr, "Failed to set render state D3DRS_LIGHTING", "D3D9RenderSystem::setLightingEnabled" );
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::setD3D9Light( size_t index, Light* lt )
+	{
+		HRESULT hr;
+
+		D3DLIGHT9 d3dLight;
+		ZeroMemory( &d3dLight, sizeof(d3dLight) );
+
+        if (!lt)
+        {
+            if( FAILED( hr = mpD3DDevice->LightEnable( index, FALSE) ) )
+			    OGRE_EXCEPT( hr, "Unable to disable light", "D3D9RenderSystem::setD3D9Light" );
+        }
+        else
+        {
+			switch( lt->getType() )
+			{
+			case Light::LT_POINT:
+				d3dLight.Type = D3DLIGHT_POINT;
+				break;
+
+			case Light::LT_DIRECTIONAL:
+				d3dLight.Type = D3DLIGHT_DIRECTIONAL;
+				break;
+
+			case Light::LT_SPOTLIGHT:
+				d3dLight.Type = D3DLIGHT_SPOT;
+				d3dLight.Falloff = lt->getSpotlightFalloff();
+				d3dLight.Theta = lt->getSpotlightInnerAngle().valueRadians();
+				d3dLight.Phi = lt->getSpotlightOuterAngle().valueRadians();
+				break;
+			}
+
+			ColourValue col;
+			col = lt->getDiffuseColour();
+			d3dLight.Diffuse = D3DXCOLOR( col.r, col.g, col.b, col.a );
+
+			col = lt->getSpecularColour();
+			d3dLight.Specular = D3DXCOLOR( col.r, col.g, col.b, col.a );
+
+			Vector3 vec;
+			if( lt->getType() != Light::LT_DIRECTIONAL )
+			{
+				vec = lt->getDerivedPosition();
+				d3dLight.Position = D3DXVECTOR3( vec.x, vec.y, vec.z );
+			}
+			if( lt->getType() != Light::LT_POINT )
+			{
+				vec = lt->getDerivedDirection();
+				d3dLight.Direction = D3DXVECTOR3( vec.x, vec.y, vec.z );
+			}
+
+			d3dLight.Range = lt->getAttenuationRange();
+			d3dLight.Attenuation0 = lt->getAttenuationConstant();
+			d3dLight.Attenuation1 = lt->getAttenuationLinear();
+			d3dLight.Attenuation2 = lt->getAttenuationQuadric();
+
+			if( FAILED( hr = mpD3DDevice->SetLight( index, &d3dLight ) ) )
+				OGRE_EXCEPT( hr, "Unable to set light details", "D3D9RenderSystem::setD3D9Light" );
+
+            if( FAILED( hr = mpD3DDevice->LightEnable( index, TRUE ) ) )
+			    OGRE_EXCEPT( hr, "Unable to enable light", "D3D9RenderSystem::setD3D9Light" );
+        }
+
+
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::_setViewMatrix( const Matrix4 &m )
+	{
+        // save latest view matrix
+        mViewMatrix = m;
+        mViewMatrix[2][0] = -mViewMatrix[2][0];
+        mViewMatrix[2][1] = -mViewMatrix[2][1];
+        mViewMatrix[2][2] = -mViewMatrix[2][2];
+        mViewMatrix[2][3] = -mViewMatrix[2][3];
+
+        D3DXMATRIX d3dmat = D3D9Mappings::makeD3DXMatrix( mViewMatrix );
+
+		HRESULT hr;
+		if( FAILED( hr = mpD3DDevice->SetTransform( D3DTS_VIEW, &d3dmat ) ) )
+			OGRE_EXCEPT( hr, "Cannot set D3D9 view matrix", "D3D9RenderSystem::_setViewMatrix" );
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::_setProjectionMatrix( const Matrix4 &m )
+	{
+		D3DXMATRIX d3dMat = D3D9Mappings::makeD3DXMatrix( m );
+
+		if( mActiveRenderTarget->requiresTextureFlipping() )
+        {
+            // Invert transformed y
+            d3dMat._12 = - d3dMat._12;
+			d3dMat._22 = - d3dMat._22;
+            d3dMat._32 = - d3dMat._32;
+            d3dMat._42 = - d3dMat._42;
+        }
+
+		HRESULT hr;
+		if( FAILED( hr = mpD3DDevice->SetTransform( D3DTS_PROJECTION, &d3dMat ) ) )
+			OGRE_EXCEPT( hr, "Cannot set D3D9 projection matrix", "D3D9RenderSystem::_setProjectionMatrix" );
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::_setWorldMatrix( const Matrix4 &m )
+	{
+		D3DXMATRIX d3dMat = D3D9Mappings::makeD3DXMatrix( m );
+
+		HRESULT hr;
+		if( FAILED( hr = mpD3DDevice->SetTransform( D3DTS_WORLD, &d3dMat ) ) )
+			OGRE_EXCEPT( hr, "Cannot set D3D9 world matrix", "D3D9RenderSystem::_setWorldMatrix" );
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::_setSurfaceParams( const ColourValue &ambient, const ColourValue &diffuse,
+		const ColourValue &specular, const ColourValue &emissive, Real shininess,
+        TrackVertexColourType tracking )
+	{
+		
+		D3DMATERIAL9 material;
+		material.Diffuse = D3DXCOLOR( diffuse.r, diffuse.g, diffuse.b, diffuse.a );
+		material.Ambient = D3DXCOLOR( ambient.r, ambient.g, ambient.b, ambient.a );
+		material.Specular = D3DXCOLOR( specular.r, specular.g, specular.b, specular.a );
+		material.Emissive = D3DXCOLOR( emissive.r, emissive.g, emissive.b, emissive.a );
+		material.Power = shininess;
+
+		HRESULT hr = mpD3DDevice->SetMaterial( &material );
+		if( FAILED( hr ) )
+			OGRE_EXCEPT( hr, "Error setting D3D material", "D3D9RenderSystem::_setSurfaceParams" );
+
+
+		if(tracking != TVC_NONE) 
+        {
+            __SetRenderState(D3DRS_COLORVERTEX, TRUE);
+            __SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, (tracking&TVC_AMBIENT)?D3DMCS_COLOR1:D3DMCS_MATERIAL);
+            __SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, (tracking&TVC_DIFFUSE)?D3DMCS_COLOR1:D3DMCS_MATERIAL);
+            __SetRenderState(D3DRS_SPECULARMATERIALSOURCE, (tracking&TVC_SPECULAR)?D3DMCS_COLOR1:D3DMCS_MATERIAL);
+            __SetRenderState(D3DRS_EMISSIVEMATERIALSOURCE, (tracking&TVC_EMISSIVE)?D3DMCS_COLOR1:D3DMCS_MATERIAL);
+        } 
+        else 
+        {
+            __SetRenderState(D3DRS_COLORVERTEX, FALSE);               
+        }
+        
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::_setPointParameters(Real size, 
+		bool attenuationEnabled, Real constant, Real linear, Real quadratic,
+		Real minSize, Real maxSize)
+    {
+		if(attenuationEnabled)
+		{
+			// scaling required
+			__SetRenderState(D3DRS_POINTSCALEENABLE, TRUE);
+			__SetFloatRenderState(D3DRS_POINTSCALE_A, constant);
+			__SetFloatRenderState(D3DRS_POINTSCALE_B, linear);
+			__SetFloatRenderState(D3DRS_POINTSCALE_C, quadratic);
+		}
+		else
+		{
+			// no scaling required
+			__SetRenderState(D3DRS_POINTSCALEENABLE, FALSE);
+		}
+		__SetFloatRenderState(D3DRS_POINTSIZE, size);
+		__SetFloatRenderState(D3DRS_POINTSIZE_MIN, minSize);
+		if (maxSize == 0.0f)
+			maxSize = mCapabilities->getMaxPointSize();
+		__SetFloatRenderState(D3DRS_POINTSIZE_MAX, maxSize);
+
+
+    }
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::_setPointSpritesEnabled(bool enabled)
+	{
+		if (enabled)
+		{
+			__SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE);
+		}
+		else
+		{
+			__SetRenderState(D3DRS_POINTSPRITEENABLE, FALSE);
+		}
+	}
+
+	
+#ifdef GAMETOOLS_ILLUMINATION_MODULE
+	void D3D9RenderSystem::_setTexture( size_t stage, bool enabled, const String &texname )
+	{
+		int newstage = stage;
+		if(stage >= OGRE_MAX_TEXTURE_LAYERS)
+		{
+			stage -= OGRE_MAX_TEXTURE_LAYERS;		
+			newstage = stage + 1 + D3DDMAPSAMPLER;		
+		}
+
+		
+		HRESULT hr;
+		D3D9TexturePtr dt = TextureManager::getSingleton().getByName(texname);
+		if (enabled && !dt.isNull())
+		{
+            // note used
+            dt->touch();
+
+			IDirect3DBaseTexture9 *pTex = dt->getTexture();
+			if (mTexStageDesc[stage].pTex != pTex)
+			{
+				hr = mpD3DDevice->SetTexture(newstage, pTex);
+				if( hr != S_OK )
+				{
+					String str = "Unable to set texture '" + texname + "' in D3D9";
+					OGRE_EXCEPT( hr, str, "D3D9RenderSystem::_setTexture" );
+				}
+				
+				// set stage desc.
+				mTexStageDesc[stage].pTex = pTex;
+				mTexStageDesc[stage].texType = D3D9Mappings::get(dt->getTextureType());
+			}
+		}
+		else
+		{
+			if (mTexStageDesc[stage].pTex != 0)
+			{
+				hr = mpD3DDevice->SetTexture(stage, 0);
+				if( hr != S_OK )
+				{
+					String str = "Unable to disable texture '" + texname + "' in D3D9";
+					OGRE_EXCEPT( hr, str, "D3D9RenderSystem::_setTexture" );
+				}
+			}
+
+			hr = this->__SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_DISABLE);
+			if( hr != S_OK )
+			{
+				String str = "Unable to disable texture '" + texname + "' in D3D9";
+				OGRE_EXCEPT( hr, str, "D3D9RenderSystem::_setTexture" );
+			}
+
+			// set stage desc. to defaults
+			mTexStageDesc[stage].pTex = 0;
+			mTexStageDesc[stage].autoTexCoordType = TEXCALC_NONE;
+			mTexStageDesc[stage].coordIndex = 0;
+			mTexStageDesc[stage].texType = D3D9Mappings::D3D_TEX_TYPE_NORMAL;
+		}
+	}
+#else
+	void D3D9RenderSystem::_setTexture( size_t stage, bool enabled, const String &texname )
+	{
+		HRESULT hr;
+		D3D9TexturePtr dt = TextureManager::getSingleton().getByName(texname);
+		if (enabled && !dt.isNull())
+		{
+            // note used
+            dt->touch();
+
+			IDirect3DBaseTexture9 *pTex = dt->getTexture();
+			if (mTexStageDesc[stage].pTex != pTex)
+			{
+				hr = mpD3DDevice->SetTexture(stage, pTex);
+				if( hr != S_OK )
+				{
+					String str = "Unable to set texture '" + texname + "' in D3D9";
+					OGRE_EXCEPT( hr, str, "D3D9RenderSystem::_setTexture" );
+				}
+				
+				// set stage desc.
+				mTexStageDesc[stage].pTex = pTex;
+				mTexStageDesc[stage].texType = D3D9Mappings::get(dt->getTextureType());
+			}
+		}
+		else
+		{
+			if (mTexStageDesc[stage].pTex != 0)
+			{
+				hr = mpD3DDevice->SetTexture(stage, 0);
+				if( hr != S_OK )
+				{
+					String str = "Unable to disable texture '" + texname + "' in D3D9";
+					OGRE_EXCEPT( hr, str, "D3D9RenderSystem::_setTexture" );
+				}
+			}
+
+			hr = this->__SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_DISABLE);
+			if( hr != S_OK )
+			{
+				String str = "Unable to disable texture '" + texname + "' in D3D9";
+				OGRE_EXCEPT( hr, str, "D3D9RenderSystem::_setTexture" );
+			}
+
+			// set stage desc. to defaults
+			mTexStageDesc[stage].pTex = 0;
+			mTexStageDesc[stage].autoTexCoordType = TEXCALC_NONE;
+			mTexStageDesc[stage].coordIndex = 0;
+			mTexStageDesc[stage].texType = D3D9Mappings::D3D_TEX_TYPE_NORMAL;
+		}
+	}
+#endif
+
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::_setTextureCoordSet( size_t stage, size_t index )
+	{
+		#ifdef GAMETOOLS_ILLUMINATION_MODULE
+		if(stage >= OGRE_MAX_TEXTURE_LAYERS) 
+			stage -= OGRE_MAX_TEXTURE_LAYERS;
+		#endif
+
+		HRESULT hr;
+        // Record settings
+        mTexStageDesc[stage].coordIndex = index;
+
+		hr = __SetTextureStageState( stage, D3DTSS_TEXCOORDINDEX, D3D9Mappings::get(mTexStageDesc[stage].autoTexCoordType, mCaps) | index );
+		if( FAILED( hr ) )
+			OGRE_EXCEPT( hr, "Unable to set texture coord. set index", "D3D8RenderSystem::_setTextureCoordSet" );
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::_setTextureCoordCalculation( size_t stage, TexCoordCalcMethod m,
+        const Frustum* frustum)
+	{
+		#ifdef GAMETOOLS_ILLUMINATION_MODULE
+		if(stage >= OGRE_MAX_TEXTURE_LAYERS) 
+			stage -= OGRE_MAX_TEXTURE_LAYERS;
+		#endif
+
+		HRESULT hr;
+		// record the stage state
+		mTexStageDesc[stage].autoTexCoordType = m;
+        mTexStageDesc[stage].frustum = frustum;
+
+		hr = __SetTextureStageState( stage, D3DTSS_TEXCOORDINDEX, D3D9Mappings::get(m, mCaps) | mTexStageDesc[stage].coordIndex );
+		if(FAILED(hr))
+			OGRE_EXCEPT( hr, "Unable to set texture auto tex.coord. generation mode", "D3D8RenderSystem::_setTextureCoordCalculation" );
+	}
+    //---------------------------------------------------------------------
+	void D3D9RenderSystem::_setTextureMatrix( size_t stage, const Matrix4& xForm )
+	{	
+		#ifdef GAMETOOLS_ILLUMINATION_MODULE
+		if(stage >= OGRE_MAX_TEXTURE_LAYERS) 
+			stage -= OGRE_MAX_TEXTURE_LAYERS;
+		#endif
+
+		HRESULT hr;
+		D3DXMATRIX d3dMat; // the matrix we'll maybe apply
+		Matrix4 newMat = xForm; // the matrix we'll apply after conv. to D3D format
+		// Cache texcoord calc method to register
+		TexCoordCalcMethod autoTexCoordType = mTexStageDesc[stage].autoTexCoordType;
+
+		if (autoTexCoordType == TEXCALC_ENVIRONMENT_MAP)
+        {
+            if (mCaps.VertexProcessingCaps & D3DVTXPCAPS_TEXGEN_SPHEREMAP)
+            {
+                /** Invert the texture for the spheremap */
+                Matrix4 ogreMatEnvMap = Matrix4::IDENTITY;
+			    // set env_map values
+			    ogreMatEnvMap[1][1] = -1.0f;
+			    // concatenate with the xForm
+			    newMat = newMat.concatenate(ogreMatEnvMap);
+            }
+            else
+            {
+		        /* If envmap is applied, but device doesn't support spheremap,
+		        then we have to use texture transform to make the camera space normal
+		        reference the envmap properly. This isn't exactly the same as spheremap
+		        (it looks nasty on flat areas because the camera space normals are the same)
+		        but it's the best approximation we have in the absence of a proper spheremap */
+			    // concatenate with the xForm
+                newMat = newMat.concatenate(Matrix4::CLIPSPACE2DTOIMAGESPACE);
+            }
+		}
+
+        // If this is a cubic reflection, we need to modify using the view matrix
+        if (autoTexCoordType == TEXCALC_ENVIRONMENT_MAP_REFLECTION)
+        {
+            // Get transposed 3x3
+            // We want to transpose since that will invert an orthonormal matrix ie rotation
+            Matrix4 ogreViewTransposed;
+            ogreViewTransposed[0][0] = mViewMatrix[0][0];
+            ogreViewTransposed[0][1] = mViewMatrix[1][0];
+            ogreViewTransposed[0][2] = mViewMatrix[2][0];
+            ogreViewTransposed[0][3] = 0.0f;
+
+            ogreViewTransposed[1][0] = mViewMatrix[0][1];
+            ogreViewTransposed[1][1] = mViewMatrix[1][1];
+            ogreViewTransposed[1][2] = mViewMatrix[2][1];
+            ogreViewTransposed[1][3] = 0.0f;
+
+            ogreViewTransposed[2][0] = mViewMatrix[0][2];
+            ogreViewTransposed[2][1] = mViewMatrix[1][2];
+            ogreViewTransposed[2][2] = mViewMatrix[2][2];
+            ogreViewTransposed[2][3] = 0.0f;
+
+            ogreViewTransposed[3][0] = 0.0f;
+            ogreViewTransposed[3][1] = 0.0f;
+            ogreViewTransposed[3][2] = 0.0f;
+            ogreViewTransposed[3][3] = 1.0f;
+            
+            newMat = newMat.concatenate(ogreViewTransposed);
+        }
+
+        if (autoTexCoordType == TEXCALC_PROJECTIVE_TEXTURE)
+        {
+            // Derive camera space to projector space transform
+            // To do this, we need to undo the camera view matrix, then 
+            // apply the projector view & projection matrices
+            newMat = mViewMatrix.inverse();
+            newMat = mTexStageDesc[stage].frustum->getViewMatrix() * newMat;
+            newMat = mTexStageDesc[stage].frustum->getProjectionMatrix() * newMat;
+            newMat = Matrix4::CLIPSPACE2DTOIMAGESPACE * newMat;
+            newMat = xForm * newMat;
+        }
+
+		// need this if texture is a cube map, to invert D3D's z coord
+		if (autoTexCoordType != TEXCALC_NONE &&
+            autoTexCoordType != TEXCALC_PROJECTIVE_TEXTURE)
+		{
+            newMat[2][0] = -newMat[2][0];
+            newMat[2][1] = -newMat[2][1];
+            newMat[2][2] = -newMat[2][2];
+            newMat[2][3] = -newMat[2][3];
+		}
+
+        // convert our matrix to D3D format
+		d3dMat = D3D9Mappings::makeD3DXMatrix(newMat);
+
+		// set the matrix if it's not the identity
+		if (!D3DXMatrixIsIdentity(&d3dMat))
+		{
+            /* It's seems D3D automatically add a texture coordinate with value 1,
+            and fill up the remaining texture coordinates with 0 for the input
+            texture coordinates before pass to texture coordinate transformation.
+
+               NOTE: It's difference with D3DDECLTYPE enumerated type expand in
+            DirectX SDK documentation!
+
+               So we should prepare the texcoord transform, make the transformation
+            just like standardized vector expand, thus, fill w with value 1 and
+            others with 0.
+            */
+            if (autoTexCoordType == TEXCALC_NONE)
+            {
+                /* FIXME: The actually input texture coordinate dimensions should
+                be determine by texture coordinate vertex element. Now, just trust
+                user supplied texture type matchs texture coordinate vertex element.
+                */
+                if (mTexStageDesc[stage].texType == D3D9Mappings::D3D_TEX_TYPE_NORMAL)
+                {
+                    /* It's 2D input texture coordinate:
+
+                      texcoord in vertex buffer     D3D expanded to     We are adjusted to
+                                                -->                 -->
+                                (u, v)               (u, v, 1, 0)          (u, v, 0, 1)
+                    */
+                    std::swap(d3dMat._31, d3dMat._41);
+                    std::swap(d3dMat._32, d3dMat._42);
+                    std::swap(d3dMat._33, d3dMat._43);
+                    std::swap(d3dMat._34, d3dMat._44);
+                }
+            }
+            else
+            {
+                // All texgen generate 3D input texture coordinates.
+            }
+
+			// tell D3D the dimension of tex. coord.
+			int texCoordDim = D3DTTFF_COUNT2;
+            if (mTexStageDesc[stage].autoTexCoordType == TEXCALC_PROJECTIVE_TEXTURE)
+            {
+                /* We want texcoords (u, v, w, q) always get divided by q, but D3D
+                projected texcoords is divided by the last element (in the case of
+                2D texcoord, is w). So we tweak the transform matrix, transform the
+                texcoords with w and q swapped: (u, v, q, w), and then D3D will
+                divide u, v by q. The w and q just ignored as it wasn't used by
+                rasterizer.
+                */
+			    switch (mTexStageDesc[stage].texType)
+			    {
+			    case D3D9Mappings::D3D_TEX_TYPE_NORMAL:
+                    std::swap(d3dMat._13, d3dMat._14);
+                    std::swap(d3dMat._23, d3dMat._24);
+                    std::swap(d3dMat._33, d3dMat._34);
+                    std::swap(d3dMat._43, d3dMat._44);
+
+                    texCoordDim = D3DTTFF_PROJECTED | D3DTTFF_COUNT3;
+                    break;
+
+			    case D3D9Mappings::D3D_TEX_TYPE_CUBE:
+			    case D3D9Mappings::D3D_TEX_TYPE_VOLUME:
+                    // Yes, we support 3D projective texture.
+				    texCoordDim = D3DTTFF_PROJECTED | D3DTTFF_COUNT4;
+                    break;
+                }
+            }
+            else
+            {
+			    switch (mTexStageDesc[stage].texType)
+			    {
+			    case D3D9Mappings::D3D_TEX_TYPE_NORMAL:
+				    texCoordDim = D3DTTFF_COUNT2;
+				    break;
+			    case D3D9Mappings::D3D_TEX_TYPE_CUBE:
+			    case D3D9Mappings::D3D_TEX_TYPE_VOLUME:
+				    texCoordDim = D3DTTFF_COUNT3;
+                    break;
+			    }
+            }
+
+			hr = __SetTextureStageState( stage, D3DTSS_TEXTURETRANSFORMFLAGS, texCoordDim );
+			if (FAILED(hr))
+				OGRE_EXCEPT( hr, "Unable to set texture coord. dimension", "D3D9RenderSystem::_setTextureMatrix" );
+
+			hr = mpD3DDevice->SetTransform( (D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0 + stage), &d3dMat );
+			if (FAILED(hr))
+				OGRE_EXCEPT( hr, "Unable to set texture matrix", "D3D9RenderSystem::_setTextureMatrix" );
+		}
+		else
+		{
+			// disable all of this
+			hr = __SetTextureStageState( stage, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );
+			if( FAILED( hr ) )
+				OGRE_EXCEPT( hr, "Error setting texture matrix", "D3D9RenderSystem::_setTextureMatrix" );
+
+			// set the identity matrix
+			hr = mpD3DDevice->SetTransform( (D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0 + stage), &d3dMat );
+			if( FAILED( hr ) )
+				OGRE_EXCEPT( hr, "Error setting texture matrix", "D3D9RenderSystem::_setTextureMatrix" );
+		}
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::_setTextureAddressingMode( size_t stage, 
+		const TextureUnitState::UVWAddressingMode& uvw )
+	{
+		#ifdef GAMETOOLS_ILLUMINATION_MODULE
+		if(stage >= OGRE_MAX_TEXTURE_LAYERS) 
+			stage -= OGRE_MAX_TEXTURE_LAYERS;
+		#endif
+
+		HRESULT hr;
+		if( FAILED( hr = __SetSamplerState( stage, D3DSAMP_ADDRESSU, D3D9Mappings::get(uvw.u) ) ) )
+			OGRE_EXCEPT( hr, "Failed to set texture addressing mode for U", "D3D9RenderSystem::_setTextureAddressingMode" );
+		if( FAILED( hr = __SetSamplerState( stage, D3DSAMP_ADDRESSV, D3D9Mappings::get(uvw.v) ) ) )
+			OGRE_EXCEPT( hr, "Failed to set texture addressing mode for V", "D3D9RenderSystem::_setTextureAddressingMode" );
+		if( FAILED( hr = __SetSamplerState( stage, D3DSAMP_ADDRESSW, D3D9Mappings::get(uvw.w) ) ) )
+			OGRE_EXCEPT( hr, "Failed to set texture addressing mode for W", "D3D9RenderSystem::_setTextureAddressingMode" );
+	}
+    //-----------------------------------------------------------------------------
+    void D3D9RenderSystem::_setTextureBorderColour(size_t stage,
+        const ColourValue& colour)
+    {
+		#ifdef GAMETOOLS_ILLUMINATION_MODULE
+		if(stage >= OGRE_MAX_TEXTURE_LAYERS) 
+			stage -= OGRE_MAX_TEXTURE_LAYERS;
+		#endif
+
+		HRESULT hr;
+		if( FAILED( hr = __SetSamplerState( stage, D3DSAMP_BORDERCOLOR, colour.getAsARGB()) ) )
+			OGRE_EXCEPT( hr, "Failed to set texture border colour", "D3D9RenderSystem::_setTextureBorderColour" );
+    }
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::_setTextureBlendMode( size_t stage, const LayerBlendModeEx& bm )
+	{
+		#ifdef GAMETOOLS_ILLUMINATION_MODULE
+		if(stage >= OGRE_MAX_TEXTURE_LAYERS) 
+			stage -= OGRE_MAX_TEXTURE_LAYERS;
+		#endif
+
+		HRESULT hr = S_OK;
+		D3DTEXTURESTAGESTATETYPE tss;
+		D3DCOLOR manualD3D;
+
+
+		// choose type of blend.
+		if( bm.blendType == LBT_COLOUR )
+			tss = D3DTSS_COLOROP;
+		else if( bm.blendType == LBT_ALPHA )
+			tss = D3DTSS_ALPHAOP;
+		else
+			OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 
+			"Invalid blend type", "D3D9RenderSystem::_setTextureBlendMode");
+
+		// set manual factor if required by operation
+		if (bm.operation == LBX_BLEND_MANUAL)
+		{
+			hr = __SetRenderState( D3DRS_TEXTUREFACTOR, D3DXCOLOR(0.0, 0.0, 0.0,  bm.factor) );
+			if (FAILED(hr))
+				OGRE_EXCEPT( hr, "Failed to set manual factor", "D3D9RenderSystem::_setTextureBlendMode" );
+		}
+		// set operation
+		hr = __SetTextureStageState( stage, tss, D3D9Mappings::get(bm.operation, mCaps) );
+		if (FAILED(hr))
+			OGRE_EXCEPT( hr, "Failed to set operation", "D3D9RenderSystem::_setTextureBlendMode" );
+
+		// choose source 1
+		if( bm.blendType == LBT_COLOUR )
+		{
+			tss = D3DTSS_COLORARG1;
+			manualD3D = D3DXCOLOR( bm.colourArg1.r, bm.colourArg1.g, bm.colourArg1.b, bm.colourArg1.a );
+			mManualBlendColours[stage][0] = bm.colourArg1;
+		}
+		else if( bm.blendType == LBT_ALPHA )
+		{
+			tss = D3DTSS_ALPHAARG1;
+			manualD3D = D3DXCOLOR( mManualBlendColours[stage][0].r, 
+				mManualBlendColours[stage][0].g, 
+				mManualBlendColours[stage][0].b, bm.alphaArg1 );
+		}
+		else
+		{
+			OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 
+				"Invalid blend type", "D3D9RenderSystem::_setTextureBlendMode");
+		}
+		// Set manual factor if required
+		if (bm.source1 == LBS_MANUAL)
+		{
+			hr = __SetRenderState( D3DRS_TEXTUREFACTOR, manualD3D );
+			if (FAILED(hr))
+				OGRE_EXCEPT( hr, "Failed to set manual factor", "D3D9RenderSystem::_setTextureBlendMode" );
+		}
+		// set source 1
+		hr = __SetTextureStageState( stage, tss, D3D9Mappings::get(bm.source1) );
+		if (FAILED(hr))
+			OGRE_EXCEPT( hr, "Failed to set source1", "D3D9RenderSystem::_setTextureBlendMode" );
+		
+		// choose source 2
+		if( bm.blendType == LBT_COLOUR )
+		{
+			tss = D3DTSS_COLORARG2;
+			manualD3D = D3DXCOLOR( bm.colourArg2.r, bm.colourArg2.g, bm.colourArg2.b, bm.colourArg2.a );
+			mManualBlendColours[stage][1] = bm.colourArg1;
+		}
+		else if( bm.blendType == LBT_ALPHA )
+		{
+			tss = D3DTSS_ALPHAARG2;
+			manualD3D = D3DXCOLOR( mManualBlendColours[stage][1].r, 
+				mManualBlendColours[stage][1].g, 
+				mManualBlendColours[stage][1].b, 
+				bm.alphaArg2 );
+		}
+		// Set manual factor if required
+		if (bm.source2 == LBS_MANUAL)
+		{
+			hr = __SetRenderState( D3DRS_TEXTUREFACTOR, manualD3D );
+			if (FAILED(hr))
+				OGRE_EXCEPT( hr, "Failed to set manual factor", "D3D9RenderSystem::_setTextureBlendMode" );
+		}
+		// Now set source 2
+		hr = __SetTextureStageState( stage, tss, D3D9Mappings::get(bm.source2) );
+		if (FAILED(hr))
+			OGRE_EXCEPT( hr, "Failed to set source 2", "D3D9RenderSystem::_setTextureBlendMode" );
+
+		// Set interpolation factor if lerping
+		if (bm.operation == LBX_BLEND_DIFFUSE_COLOUR && 
+			mCaps.TextureOpCaps & D3DTEXOPCAPS_LERP)
+		{
+			// choose source 0 (lerp factor)
+			if( bm.blendType == LBT_COLOUR )
+			{
+				tss = D3DTSS_COLORARG0;
+			}
+			else if( bm.blendType == LBT_ALPHA )
+			{
+				tss = D3DTSS_ALPHAARG0;
+			}
+			hr = __SetTextureStageState(stage, tss, D3DTA_DIFFUSE);
+
+			if (FAILED(hr))
+				OGRE_EXCEPT( hr, "Failed to set lerp source 0", 
+					"D3D9RenderSystem::_setTextureBlendMode" );
+
+		}
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::_setSceneBlending( SceneBlendFactor sourceFactor, SceneBlendFactor destFactor )
+	{
+		HRESULT hr;
+		if( sourceFactor == SBF_ONE && destFactor == SBF_ZERO)
+		{
+			if (FAILED(hr = __SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE)))
+				OGRE_EXCEPT( hr, "Failed to set alpha blending option", "D3D9RenderSystem::_setSceneBlending" );
+		}
+		else
+		{
+			if (FAILED(hr = __SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE)))
+				OGRE_EXCEPT( hr, "Failed to set alpha blending option", "D3D9RenderSystem::_setSceneBlending" );
+			if( FAILED( hr = __SetRenderState( D3DRS_SRCBLEND, D3D9Mappings::get(sourceFactor) ) ) )
+				OGRE_EXCEPT( hr, "Failed to set source blend", "D3D9RenderSystem::_setSceneBlending" );
+			if( FAILED( hr = __SetRenderState( D3DRS_DESTBLEND, D3D9Mappings::get(destFactor) ) ) )
+				OGRE_EXCEPT( hr, "Failed to set destination blend", "D3D9RenderSystem::_setSceneBlending" );
+		}
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::_setAlphaRejectSettings( CompareFunction func, unsigned char value )
+	{
+		HRESULT hr;
+        if (func != CMPF_ALWAYS_PASS)
+        {
+            if( FAILED( hr = __SetRenderState( D3DRS_ALPHATESTENABLE,  TRUE ) ) )
+    			OGRE_EXCEPT( hr, "Failed to enable alpha testing", 
+                "D3D9RenderSystem::_setAlphaRejectSettings" );
+        }
+        else
+        {
+            if( FAILED( hr = __SetRenderState( D3DRS_ALPHATESTENABLE,  FALSE ) ) )
+    			OGRE_EXCEPT( hr, "Failed to disable alpha testing", 
+                "D3D9RenderSystem::_setAlphaRejectSettings" );
+        }
+        // Set always just be sure
+		if( FAILED( hr = __SetRenderState( D3DRS_ALPHAFUNC, D3D9Mappings::get(func) ) ) )
+			OGRE_EXCEPT( hr, "Failed to set alpha reject function", "D3D9RenderSystem::_setAlphaRejectSettings" );
+		if( FAILED( hr = __SetRenderState( D3DRS_ALPHAREF, value ) ) )
+			OGRE_EXCEPT( hr, "Failed to set render state D3DRS_ALPHAREF", "D3D9RenderSystem::_setAlphaRejectSettings" );
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::_setCullingMode( CullingMode mode )
+	{
+		HRESULT hr;
+        bool flip = ((mActiveRenderTarget->requiresTextureFlipping() && !mInvertVertexWinding) ||
+                (!mActiveRenderTarget->requiresTextureFlipping() && mInvertVertexWinding));
+
+		if( FAILED (hr = __SetRenderState(D3DRS_CULLMODE, 
+            D3D9Mappings::get(mode, flip))) )
+			OGRE_EXCEPT( hr, "Failed to set culling mode", "D3D9RenderSystem::_setCullingMode" );
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::_setDepthBufferParams( bool depthTest, bool depthWrite, CompareFunction depthFunction )
+	{
+		_setDepthBufferCheckEnabled( depthTest );
+		_setDepthBufferWriteEnabled( depthWrite );
+		_setDepthBufferFunction( depthFunction );
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::_setDepthBufferCheckEnabled( bool enabled )
+	{
+		HRESULT hr;
+
+		if( enabled )
+		{
+			// Use w-buffer if available and enabled
+			if( mWBuffer && mCaps.RasterCaps & D3DPRASTERCAPS_WBUFFER )
+				hr = __SetRenderState( D3DRS_ZENABLE, D3DZB_USEW );
+			else
+				hr = __SetRenderState( D3DRS_ZENABLE, D3DZB_TRUE );
+		}
+		else
+			hr = __SetRenderState( D3DRS_ZENABLE, D3DZB_FALSE );
+
+		if( FAILED( hr ) )
+			OGRE_EXCEPT( hr, "Error setting depth buffer test state", "D3D9RenderSystem::_setDepthBufferCheckEnabled" );
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::_setDepthBufferWriteEnabled( bool enabled )
+	{
+		HRESULT hr;
+
+		if( FAILED( hr = __SetRenderState( D3DRS_ZWRITEENABLE, enabled ) ) )
+			OGRE_EXCEPT( hr, "Error setting depth buffer write state", "D3D9RenderSystem::_setDepthBufferWriteEnabled" );
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::_setDepthBufferFunction( CompareFunction func )
+	{
+		HRESULT hr;
+		if( FAILED( hr = __SetRenderState( D3DRS_ZFUNC, D3D9Mappings::get(func) ) ) )
+			OGRE_EXCEPT( hr, "Error setting depth buffer test function", "D3D9RenderSystem::_setDepthBufferFunction" );
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::_setDepthBias(ushort bias)
+	{
+		float bias_float = static_cast<float>(-bias);
+		// scale down - certainly needed for nVidia
+		bias_float /= 250000.0f;
+		HRESULT hr = __SetRenderState(D3DRS_DEPTHBIAS, *(DWORD*)&bias_float);
+		if (FAILED(hr))
+			OGRE_EXCEPT(hr, "Error setting depth bias", "D3D9RenderSystem::_setDepthBias");
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::_setColourBufferWriteEnabled(bool red, bool green, 
+		bool blue, bool alpha)
+	{
+		DWORD val = 0;
+		if (red) 
+			val |= D3DCOLORWRITEENABLE_RED;
+		if (green)
+			val |= D3DCOLORWRITEENABLE_GREEN;
+		if (blue)
+			val |= D3DCOLORWRITEENABLE_BLUE;
+		if (alpha)
+			val |= D3DCOLORWRITEENABLE_ALPHA;
+		HRESULT hr = __SetRenderState(D3DRS_COLORWRITEENABLE, val); 
+		if (FAILED(hr))
+			OGRE_EXCEPT(hr, "Error setting colour write enable flags", 
+			"D3D9RenderSystem::_setColourBufferWriteEnabled");
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::_setFog( FogMode mode, const ColourValue& colour, Real densitiy, Real start, Real end )
+	{
+		HRESULT hr;
+
+		D3DRENDERSTATETYPE fogType, fogTypeNot;
+
+		if (mCaps.RasterCaps & D3DPRASTERCAPS_FOGTABLE)
+		{
+			fogType = D3DRS_FOGTABLEMODE;
+			fogTypeNot = D3DRS_FOGVERTEXMODE;
+		}
+		else
+		{
+			fogType = D3DRS_FOGVERTEXMODE;
+			fogTypeNot = D3DRS_FOGTABLEMODE;
+		}
+
+		if( mode == FOG_NONE)
+		{
+			// just disable
+			hr = __SetRenderState(fogType, D3DFOG_NONE );
+			hr = __SetRenderState(D3DRS_FOGENABLE, FALSE);
+		}
+		else
+		{
+			// Allow fog
+			hr = __SetRenderState( D3DRS_FOGENABLE, TRUE );
+			hr = __SetRenderState( fogTypeNot, D3DFOG_NONE );
+			hr = __SetRenderState( fogType, D3D9Mappings::get(mode) );
+
+			hr = __SetRenderState( D3DRS_FOGCOLOR, colour.getAsARGB() );
+			hr = __SetFloatRenderState( D3DRS_FOGSTART, start );
+			hr = __SetFloatRenderState( D3DRS_FOGEND, end );
+			hr = __SetFloatRenderState( D3DRS_FOGDENSITY, densitiy );
+		}
+
+		if( FAILED( hr ) )
+			OGRE_EXCEPT( hr, "Error setting render state", "D3D9RenderSystem::_setFog" );
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::_setPolygonMode(PolygonMode level)
+	{
+		HRESULT hr = __SetRenderState(D3DRS_FILLMODE, D3D9Mappings::get(level));
+		if (FAILED(hr))
+			OGRE_EXCEPT(hr, "Error setting polygon mode.", "D3D9RenderSystem::setPolygonMode");
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::setStencilCheckEnabled(bool enabled)
+	{
+		// Allow stencilling
+		HRESULT hr = __SetRenderState(D3DRS_STENCILENABLE, enabled);
+		if (FAILED(hr))
+			OGRE_EXCEPT(hr, "Error enabling / disabling stencilling.",
+			"D3D9RenderSystem::setStencilCheckEnabled");
+	}
+    //---------------------------------------------------------------------
+    void D3D9RenderSystem::setStencilBufferParams(CompareFunction func, 
+        uint32 refValue, uint32 mask, StencilOperation stencilFailOp, 
+        StencilOperation depthFailOp, StencilOperation passOp, 
+        bool twoSidedOperation)
+    {
+        HRESULT hr;
+        bool flip;
+
+        // 2-sided operation
+        if (twoSidedOperation)
+        {
+            if (!mCapabilities->hasCapability(RSC_TWO_SIDED_STENCIL))
+                OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "2-sided stencils are not supported",
+                    "D3D9RenderSystem::setStencilBufferParams");
+            hr = __SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE);
+		    if (FAILED(hr))
+			    OGRE_EXCEPT(hr, "Error setting 2-sided stencil mode.",
+			    "D3D9RenderSystem::setStencilBufferParams");
+            // NB: We should always treat CCW as front face for consistent with default
+            // culling mode. Therefore, we must take care with two-sided stencil settings.
+            flip = (mInvertVertexWinding && mActiveRenderTarget->requiresTextureFlipping()) ||
+                   (!mInvertVertexWinding && !mActiveRenderTarget->requiresTextureFlipping());
+
+            // Set alternative versions of ops
+            // fail op
+            hr = __SetRenderState(D3DRS_CCW_STENCILFAIL, D3D9Mappings::get(stencilFailOp, !flip));
+            if (FAILED(hr))
+                OGRE_EXCEPT(hr, "Error setting stencil fail operation (2-sided).",
+                "D3D9RenderSystem::setStencilBufferParams");
+
+            // depth fail op
+            hr = __SetRenderState(D3DRS_CCW_STENCILZFAIL, D3D9Mappings::get(depthFailOp, !flip));
+            if (FAILED(hr))
+                OGRE_EXCEPT(hr, "Error setting stencil depth fail operation (2-sided).",
+                "D3D9RenderSystem::setStencilBufferParams");
+
+            // pass op
+            hr = __SetRenderState(D3DRS_CCW_STENCILPASS, D3D9Mappings::get(passOp, !flip));
+            if (FAILED(hr))
+                OGRE_EXCEPT(hr, "Error setting stencil pass operation (2-sided).",
+                "D3D9RenderSystem::setStencilBufferParams");
+        }
+        else
+        {
+            hr = __SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE);
+		    if (FAILED(hr))
+			    OGRE_EXCEPT(hr, "Error setting 1-sided stencil mode.",
+			    "D3D9RenderSystem::setStencilBufferParams");
+            flip = false;
+        }
+
+        // func
+        hr = __SetRenderState(D3DRS_STENCILFUNC, D3D9Mappings::get(func));
+		if (FAILED(hr))
+			OGRE_EXCEPT(hr, "Error setting stencil buffer test function.",
+			"D3D9RenderSystem::setStencilBufferParams");
+
+        // reference value
+        hr = __SetRenderState(D3DRS_STENCILREF, refValue);
+		if (FAILED(hr))
+			OGRE_EXCEPT(hr, "Error setting stencil buffer reference value.",
+			"D3D9RenderSystem::setStencilBufferParams");
+
+        // mask
+        hr = __SetRenderState(D3DRS_STENCILMASK, mask);
+		if (FAILED(hr))
+			OGRE_EXCEPT(hr, "Error setting stencil buffer mask.",
+			"D3D9RenderSystem::setStencilBufferParams");
+
+		// fail op
+        hr = __SetRenderState(D3DRS_STENCILFAIL, D3D9Mappings::get(stencilFailOp, flip));
+		if (FAILED(hr))
+			OGRE_EXCEPT(hr, "Error setting stencil fail operation.",
+			"D3D9RenderSystem::setStencilBufferParams");
+
+        // depth fail op
+        hr = __SetRenderState(D3DRS_STENCILZFAIL, D3D9Mappings::get(depthFailOp, flip));
+		if (FAILED(hr))
+			OGRE_EXCEPT(hr, "Error setting stencil depth fail operation.",
+			"D3D9RenderSystem::setStencilBufferParams");
+
+        // pass op
+        hr = __SetRenderState(D3DRS_STENCILPASS, D3D9Mappings::get(passOp, flip));
+		if (FAILED(hr))
+			OGRE_EXCEPT(hr, "Error setting stencil pass operation.",
+			"D3D9RenderSystem::setStencilBufferParams");
+	}
+	//---------------------------------------------------------------------
+    void D3D9RenderSystem::_setTextureUnitFiltering(size_t unit, FilterType ftype, 
+        FilterOptions filter)
+	{		
+		#ifdef GAMETOOLS_ILLUMINATION_MODULE
+		if(unit >= OGRE_MAX_TEXTURE_LAYERS) 
+			unit -= OGRE_MAX_TEXTURE_LAYERS;
+		#endif
+
+		HRESULT hr;
+		D3D9Mappings::eD3DTexType texType = mTexStageDesc[unit].texType;
+        hr = __SetSamplerState( unit, D3D9Mappings::get(ftype), 
+            D3D9Mappings::get(ftype, filter, mCaps, texType));
+		if (FAILED(hr))
+			OGRE_EXCEPT(hr, "Failed to set texture filter ", "D3D9RenderSystem::_setTextureUnitFiltering");
+	}
+    //---------------------------------------------------------------------
+	DWORD D3D9RenderSystem::_getCurrentAnisotropy(size_t unit)
+	{
+		DWORD oldVal;
+		mpD3DDevice->GetSamplerState(unit, D3DSAMP_MAXANISOTROPY, &oldVal);
+			return oldVal;
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::_setTextureLayerAnisotropy(size_t unit, unsigned int maxAnisotropy)
+	{
+		#ifdef GAMETOOLS_ILLUMINATION_MODULE
+		if(unit >= OGRE_MAX_TEXTURE_LAYERS) 
+			unit -= OGRE_MAX_TEXTURE_LAYERS;
+		#endif
+
+		if ((DWORD)maxAnisotropy > mCaps.MaxAnisotropy)
+			maxAnisotropy = mCaps.MaxAnisotropy;
+
+		if (_getCurrentAnisotropy(unit) != maxAnisotropy)
+			__SetSamplerState( unit, D3DSAMP_MAXANISOTROPY, maxAnisotropy );
+	}
+	//---------------------------------------------------------------------
+	HRESULT D3D9RenderSystem::__SetRenderState(D3DRENDERSTATETYPE state, DWORD value)
+	{
+		HRESULT hr;
+		DWORD oldVal;
+
+		if ( FAILED( hr = mpD3DDevice->GetRenderState(state, &oldVal) ) )
+			return hr;
+		if ( oldVal == value )
+			return D3D_OK;
+		else
+			return mpD3DDevice->SetRenderState(state, value);
+	}
+	//---------------------------------------------------------------------
+	HRESULT D3D9RenderSystem::__SetSamplerState(DWORD sampler, D3DSAMPLERSTATETYPE type, DWORD value)
+	{
+		HRESULT hr;
+		DWORD oldVal;
+
+		if ( FAILED( hr = mpD3DDevice->GetSamplerState(sampler, type, &oldVal) ) )
+			return hr;
+		if ( oldVal == value )
+			return D3D_OK;
+		else
+			return mpD3DDevice->SetSamplerState(sampler, type, value);
+	}
+	//---------------------------------------------------------------------
+	HRESULT D3D9RenderSystem::__SetTextureStageState(DWORD stage, D3DTEXTURESTAGESTATETYPE type, DWORD value)
+	{
+		HRESULT hr;
+		DWORD oldVal;
+		
+		if ( FAILED( hr = mpD3DDevice->GetTextureStageState(stage, type, &oldVal) ) )
+			return hr;
+		if ( oldVal == value )
+			return D3D_OK;
+		else
+			return mpD3DDevice->SetTextureStageState(stage, type, value);
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::_setViewport( Viewport *vp )
+	{
+		if( vp != mActiveViewport || vp->_isUpdated() )
+		{
+			mActiveViewport = vp;
+			mActiveRenderTarget = vp->getTarget();
+
+			// ok, it's different, time to set render target and viewport params
+			D3DVIEWPORT9 d3dvp;
+			HRESULT hr;
+
+			// Set render target
+			RenderTarget* target;
+			target = vp->getTarget();
+
+			// Retrieve render surfaces (up to OGRE_MAX_MULTIPLE_RENDER_TARGETS)
+			LPDIRECT3DSURFACE9 pBack[OGRE_MAX_MULTIPLE_RENDER_TARGETS];
+			memset(pBack, 0, sizeof(pBack));
+			target->getCustomAttribute( "DDBACKBUFFER", &pBack );
+			if (!pBack[0])
+				return;
+
+			LPDIRECT3DSURFACE9 pDepth = NULL;
+			target->getCustomAttribute( "D3DZBUFFER", &pDepth );
+			if (!pDepth)
+			{
+				/// No depth buffer provided, use our own
+				/// Request a depth stencil that is compatible with the format, multisample type and
+				/// dimensions of the render target.
+				D3DSURFACE_DESC srfDesc;
+				if(FAILED(pBack[0]->GetDesc(&srfDesc)))
+					return; // ?
+				pDepth = _getDepthStencilFor(srfDesc.Format, srfDesc.MultiSampleType, srfDesc.Width, srfDesc.Height);
+			}
+			// Bind render targets
+			uint count = mCapabilities->numMultiRenderTargets();
+			for(uint x=0; x<count; ++x)
+			{
+				hr = mpD3DDevice->SetRenderTarget(x, pBack[x]);
+				if (FAILED(hr))
+				{
+					String msg = DXGetErrorDescription9(hr);
+					OGRE_EXCEPT( hr, "Failed to setRenderTarget : " + msg, "D3D9RenderSystem::_setViewport" );
+				}
+			}
+			hr = mpD3DDevice->SetDepthStencilSurface(pDepth);
+			if (FAILED(hr))
+			{
+				String msg = DXGetErrorDescription9(hr);
+				OGRE_EXCEPT( hr, "Failed to setDepthStencil : " + msg, "D3D9RenderSystem::_setViewport" );
+			}
+
+			_setCullingMode( mCullingMode );
+
+			// set viewport dimensions
+			d3dvp.X = vp->getActualLeft();
+			d3dvp.Y = vp->getActualTop();
+			d3dvp.Width = vp->getActualWidth();
+			d3dvp.Height = vp->getActualHeight();
+            if (target->requiresTextureFlipping())
+            {
+                // Convert "top-left" to "bottom-left"
+                d3dvp.Y = target->getHeight() - d3dvp.Height - d3dvp.Y;
+            }
+
+			// Z-values from 0.0 to 1.0 (TODO: standardise with OpenGL)
+			d3dvp.MinZ = 0.0f;
+			d3dvp.MaxZ = 1.0f;
+
+			if( FAILED( hr = mpD3DDevice->SetViewport( &d3dvp ) ) )
+				OGRE_EXCEPT( hr, "Failed to set viewport.", "D3D9RenderSystem::_setViewport" );
+
+			vp->_clearUpdatedFlag();
+		}
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::_beginFrame()
+	{
+		OgreGuard( "D3D9RenderSystem::_beginFrame" );
+
+		HRESULT hr;
+
+		if( !mActiveViewport )
+			OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Cannot begin frame - no viewport selected.", "D3D9RenderSystem::_beginFrame" );
+
+		// Clear the viewport if required
+		if( mActiveViewport->getClearEveryFrame() )
+		{
+            clearFrameBuffer(mActiveViewport->getClearBuffers(), 
+                mActiveViewport->getBackgroundColour());
+		}
+
+		if( FAILED( hr = mpD3DDevice->BeginScene() ) )
+		{
+			String msg = DXGetErrorDescription9(hr);
+			OGRE_EXCEPT( hr, "Error beginning frame :" + msg, "D3D9RenderSystem::_beginFrame" );
+		}
+
+		if(!mBasicStatesInitialised)
+		{
+			// First-time 
+			// setup some defaults
+			// Allow specular
+			hr = __SetRenderState(D3DRS_SPECULARENABLE, TRUE);
+			if (FAILED(hr))
+			{
+				String msg = DXGetErrorDescription9(hr);
+				OGRE_EXCEPT(hr, "Error enabling alpha blending option : " + msg, "D3D9RenderSystem::_beginFrame");
+			}
+			mBasicStatesInitialised = true;
+		}
+
+		OgreUnguard();
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::_endFrame()
+	{
+		OgreGuard( "D3D9RenderSystem::_endFrame" );
+
+		HRESULT hr;
+		if( FAILED( hr = mpD3DDevice->EndScene() ) )
+			OGRE_EXCEPT( hr, "Error ending frame", "D3D9RenderSystem::_endFrame" );
+
+		OgreUnguard();
+	}
+	//---------------------------------------------------------------------
+	inline bool D3D9RenderSystem::compareDecls( D3DVERTEXELEMENT9* pDecl1, D3DVERTEXELEMENT9* pDecl2, size_t size )
+	{
+		for( size_t i=0; i < size; i++ )
+		{
+			if( pDecl1[i].Method != pDecl2[i].Method ||
+				pDecl1[i].Offset != pDecl2[i].Offset ||
+				pDecl1[i].Stream != pDecl2[i].Stream ||
+				pDecl1[i].Type != pDecl2[i].Type ||
+				pDecl1[i].Usage != pDecl2[i].Usage ||
+				pDecl1[i].UsageIndex != pDecl2[i].UsageIndex)
+			{
+				return false;
+			}
+		}
+
+		return true;
+	}
+    //---------------------------------------------------------------------
+	void D3D9RenderSystem::setVertexDeclaration(VertexDeclaration* decl)
+	{
+		// Guard
+		OgreGuard ("D3D9RenderSystem::setVertexDeclaration");
+        HRESULT hr;
+
+        D3D9VertexDeclaration* d3ddecl = 
+            static_cast<D3D9VertexDeclaration*>(decl);
+
+        if (FAILED(hr = mpD3DDevice->SetVertexDeclaration(d3ddecl->getD3DVertexDeclaration())))
+        {
+            OGRE_EXCEPT(hr, "Unable to set D3D9 vertex declaration", 
+                "D3D9RenderSystem::setVertexDeclaration");
+        }
+
+        // UnGuard
+		OgreUnguard();
+	}
+    //---------------------------------------------------------------------
+	void D3D9RenderSystem::setVertexBufferBinding(VertexBufferBinding* binding)
+	{
+		// Guard
+		OgreGuard ("D3D9RenderSystem::setVertexBufferBinding");
+
+        HRESULT hr;
+
+        // TODO: attempt to detect duplicates
+        const VertexBufferBinding::VertexBufferBindingMap& binds = binding->getBindings();
+        VertexBufferBinding::VertexBufferBindingMap::const_iterator i, iend;
+        iend = binds.end();
+        for (i = binds.begin(); i != iend; ++i)
+        {
+            const D3D9HardwareVertexBuffer* d3d9buf = 
+                static_cast<const D3D9HardwareVertexBuffer*>(i->second.get());
+            hr = mpD3DDevice->SetStreamSource(
+                static_cast<UINT>(i->first),
+                d3d9buf->getD3D9VertexBuffer(),
+                0, // no stream offset, this is handled in _render instead
+                static_cast<UINT>(d3d9buf->getVertexSize()) // stride
+                );
+            if (FAILED(hr))
+            {
+                OGRE_EXCEPT(hr, "Unable to set D3D9 stream source for buffer binding", 
+                    "D3D9RenderSystem::setVertexBufferBinding");
+            }
+
+
+        }
+
+		// Unbind any unused sources
+		for (size_t unused = binds.size(); unused < mLastVertexSourceCount; ++unused)
+		{
+			
+            hr = mpD3DDevice->SetStreamSource(static_cast<UINT>(unused), NULL, 0, 0);
+            if (FAILED(hr))
+            {
+                OGRE_EXCEPT(hr, "Unable to reset unused D3D9 stream source", 
+                    "D3D9RenderSystem::setVertexBufferBinding");
+            }
+			
+		}
+		mLastVertexSourceCount = binds.size();
+		
+
+		
+        // UnGuard
+		OgreUnguard();
+	}
+    //---------------------------------------------------------------------
+    void D3D9RenderSystem::_render(const RenderOperation& op)
+	{
+		// Guard
+		OgreGuard ("D3D9RenderSystem::_render");
+
+        // Exit immediately if there is nothing to render
+        // This caused a problem on FireGL 8800
+        if (op.vertexData->vertexCount == 0)
+            return;
+
+        // Call super class
+		RenderSystem::_render(op);
+
+        // To think about: possibly remove setVertexDeclaration and 
+        // setVertexBufferBinding from RenderSystem since the sequence is
+        // a bit too D3D9-specific?
+		setVertexDeclaration(op.vertexData->vertexDeclaration);
+        setVertexBufferBinding(op.vertexData->vertexBufferBinding);
+
+		// Determine rendering operation
+		D3DPRIMITIVETYPE primType = D3DPT_TRIANGLELIST;
+		DWORD primCount = 0;
+        switch( op.operationType )
+		{
+        case RenderOperation::OT_POINT_LIST:
+			primType = D3DPT_POINTLIST;
+			primCount = (DWORD)(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount);
+			break;
+
+		case RenderOperation::OT_LINE_LIST:
+			primType = D3DPT_LINELIST;
+			primCount = (DWORD)(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount) / 2;
+			break;
+
+		case RenderOperation::OT_LINE_STRIP:
+			primType = D3DPT_LINESTRIP;
+			primCount = (DWORD)(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount) - 1;
+			break;
+
+		case RenderOperation::OT_TRIANGLE_LIST:
+			primType = D3DPT_TRIANGLELIST;
+			primCount = (DWORD)(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount) / 3;
+			break;
+
+		case RenderOperation::OT_TRIANGLE_STRIP:
+			primType = D3DPT_TRIANGLESTRIP;
+			primCount = (DWORD)(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount) - 2;
+			break;
+
+		case RenderOperation::OT_TRIANGLE_FAN:
+			primType = D3DPT_TRIANGLEFAN;
+			primCount = (DWORD)(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount) - 2;
+			break;
+		}
+
+        if (!primCount)
+			return;
+
+		// Issue the op
+        HRESULT hr;
+		if( op.useIndexes )
+		{
+            D3D9HardwareIndexBuffer* d3dIdxBuf = 
+                static_cast<D3D9HardwareIndexBuffer*>(op.indexData->indexBuffer.get());
+			hr = mpD3DDevice->SetIndices( d3dIdxBuf->getD3DIndexBuffer() );
+			if (FAILED(hr))
+            {
+				OGRE_EXCEPT( hr, "Failed to set index buffer", "D3D9RenderSystem::_render" );
+            }
+
+            do
+            {
+                // do indexed draw operation
+			    hr = mpD3DDevice->DrawIndexedPrimitive(
+                    primType, 
+                    static_cast<INT>(op.vertexData->vertexStart), 
+                    0, // Min vertex index - assume we can go right down to 0 
+                    static_cast<UINT>(op.vertexData->vertexCount), 
+                    static_cast<UINT>(op.indexData->indexStart), 
+                    static_cast<UINT>(primCount)
+                    );
+
+            } while (updatePassIterationRenderState());
+		}
+		else
+        {
+            // nfz: gpu_iterate
+            do
+            {
+                // Unindexed, a little simpler!
+			    hr = mpD3DDevice->DrawPrimitive(
+                    primType, 
+                    static_cast<UINT>(op.vertexData->vertexStart), 
+                    static_cast<UINT>(primCount)
+                    ); 
+
+            } while (updatePassIterationRenderState());
+        } 
+
+		if( FAILED( hr ) )
+		{
+			String msg = DXGetErrorDescription9(hr);
+			OGRE_EXCEPT( hr, "Failed to DrawPrimitive : " + msg, "D3D9RenderSystem::_render" );
+		}
+        
+        // UnGuard
+		OgreUnguard();
+
+	}
+    //---------------------------------------------------------------------
+    void D3D9RenderSystem::setNormaliseNormals(bool normalise)
+    {
+        __SetRenderState(D3DRS_NORMALIZENORMALS, 
+            normalise ? TRUE : FALSE);
+    }
+	//---------------------------------------------------------------------
+    void D3D9RenderSystem::bindGpuProgram(GpuProgram* prg)
+    {
+        HRESULT hr;
+        switch (prg->getType())
+        {
+        case GPT_VERTEX_PROGRAM:
+            hr = mpD3DDevice->SetVertexShader(
+                static_cast<D3D9GpuVertexProgram*>(prg)->getVertexShader());
+            if (FAILED(hr))
+            {
+                OGRE_EXCEPT(hr, "Error calling SetVertexShader", "D3D9RenderSystem::bindGpuProgram");
+            }
+            break;
+        case GPT_FRAGMENT_PROGRAM:
+            hr = mpD3DDevice->SetPixelShader(
+                static_cast<D3D9GpuFragmentProgram*>(prg)->getPixelShader());
+            if (FAILED(hr))
+            {
+                OGRE_EXCEPT(hr, "Error calling SetPixelShader", "D3D9RenderSystem::bindGpuProgram");
+            }
+            break;
+        };
+        
+        RenderSystem::bindGpuProgram(prg);
+
+    }
+	//---------------------------------------------------------------------
+    void D3D9RenderSystem::unbindGpuProgram(GpuProgramType gptype)
+    {
+        HRESULT hr;
+        switch(gptype)
+        {
+        case GPT_VERTEX_PROGRAM:
+            mActiveVertexGpuProgramParameters.setNull();
+            hr = mpD3DDevice->SetVertexShader(NULL);
+            if (FAILED(hr))
+            {
+                OGRE_EXCEPT(hr, "Error resetting SetVertexShader to NULL", 
+                    "D3D9RenderSystem::unbindGpuProgram");
+            }
+            break;
+        case GPT_FRAGMENT_PROGRAM:
+            mActiveFragmentGpuProgramParameters.setNull();
+            hr = mpD3DDevice->SetPixelShader(NULL);
+            if (FAILED(hr))
+            {
+                OGRE_EXCEPT(hr, "Error resetting SetPixelShader to NULL", 
+                    "D3D9RenderSystem::unbindGpuProgram");
+            }
+            break;
+        };
+        RenderSystem::unbindGpuProgram(gptype);
+    }
+	//---------------------------------------------------------------------
+    void D3D9RenderSystem::bindGpuProgramParameters(GpuProgramType gptype, 
+        GpuProgramParametersSharedPtr params)
+    {
+        HRESULT hr;
+        unsigned int index;
+        GpuProgramParameters::IntConstantIterator intIt = params->getIntConstantIterator();
+        GpuProgramParameters::RealConstantIterator realIt = params->getRealConstantIterator();
+
+        switch(gptype)
+        {
+        case GPT_VERTEX_PROGRAM:
+            mActiveVertexGpuProgramParameters = params;
+            // Bind floats
+            if (params->hasRealConstantParams())
+            {
+                // Iterate over params and set the relevant ones
+                index = 0;
+                while (realIt.hasMoreElements())
+                {
+                    const GpuProgramParameters::RealConstantEntry* e = realIt.peekNextPtr();
+                    if (e->isSet)
+                    {
+                        if (FAILED(hr = mpD3DDevice->SetVertexShaderConstantF(
+                            index, e->val, 1)))
+                        {
+                            OGRE_EXCEPT(hr, "Unable to upload vertex shader float parameters", 
+                                "D3D9RenderSystem::bindGpuProgramParameters");
+                        }
+                    }
+                    index++;
+                    realIt.moveNext();
+                }
+            }
+            // Bind ints
+            if (params->hasIntConstantParams())
+            {
+                // Iterate over params and set the relevant ones
+                index = 0;
+                while (intIt.hasMoreElements())
+                {
+                    const GpuProgramParameters::IntConstantEntry* e = intIt.peekNextPtr();
+                    if (e->isSet)
+                    {
+                        if (FAILED(hr = mpD3DDevice->SetVertexShaderConstantI(
+                            index, e->val, 1)))
+                        {
+                            OGRE_EXCEPT(hr, "Unable to upload vertex shader float parameters", 
+                                "D3D9RenderSystem::bindGpuProgramParameters");
+                        }
+                    }
+                    index++;
+                    intIt.moveNext();
+                }
+            }
+            break;
+        case GPT_FRAGMENT_PROGRAM:
+            mActiveFragmentGpuProgramParameters = params;
+            // Bind floats
+            if (params->hasRealConstantParams())
+            {
+                // Iterate over params and set the relevant ones
+                index = 0;
+                while (realIt.hasMoreElements())
+                {
+                    const GpuProgramParameters::RealConstantEntry* e = realIt.peekNextPtr();
+                    if (e->isSet)
+                    {
+                        /*
+                        // TEST
+                        LogManager::getSingleton().logMessage(
+                            "  Set Constant " + StringConverter::toString(index) + " to float4(" +
+                            StringConverter::toString(e->val[0]) + ", " + 
+                            StringConverter::toString(e->val[1]) + ", " + 
+                            StringConverter::toString(e->val[2]) + ", " + 
+                            StringConverter::toString(e->val[3]) + ")"); 
+                        */
+
+                        if (FAILED(hr = mpD3DDevice->SetPixelShaderConstantF(
+                            index, e->val, 1)))
+                        {
+                            OGRE_EXCEPT(hr, "Unable to upload pixel shader float parameters", 
+                                "D3D9RenderSystem::bindGpuProgramParameters");
+                        }
+                    }
+                    index++;
+                    realIt.moveNext();
+                }
+            }
+            // Bind ints
+            if (params->hasIntConstantParams())
+            {
+                // Iterate over params and set the relevant ones
+                index = 0;
+                while (intIt.hasMoreElements())
+                {
+                    const GpuProgramParameters::IntConstantEntry* e = intIt.peekNextPtr();
+                    if (e->isSet)
+                    {
+                        if (FAILED(hr = mpD3DDevice->SetPixelShaderConstantI(
+                            index, e->val, 1)))
+                        {
+                            OGRE_EXCEPT(hr, "Unable to upload pixel shader float parameters", 
+                                "D3D9RenderSystem::bindGpuProgramParameters");
+                        }
+                    }
+                    index++;
+                    intIt.moveNext();
+                }
+            }
+            break;
+        };
+    }
+	//---------------------------------------------------------------------
+    void D3D9RenderSystem::bindGpuProgramPassIterationParameters(GpuProgramType gptype)
+    {
+
+        HRESULT hr;
+        GpuProgramParameters::RealConstantEntry* realEntry;
+
+        switch(gptype)
+        {
+        case GPT_VERTEX_PROGRAM:
+            realEntry = mActiveVertexGpuProgramParameters->getPassIterationEntry();
+            if (realEntry)
+            {
+                if (FAILED(hr = mpD3DDevice->SetVertexShaderConstantF(
+                        mActiveVertexGpuProgramParameters->getPassIterationEntryIndex(), realEntry->val, 1)))
+                {
+                    OGRE_EXCEPT(hr, "Unable to upload vertex shader multi pass parameters", 
+                    "D3D9RenderSystem::bindGpuProgramMultiPassParameters");
+                }
+            }
+            break;
+
+        case GPT_FRAGMENT_PROGRAM:
+            realEntry = mActiveFragmentGpuProgramParameters->getPassIterationEntry();
+            if (realEntry)
+            {
+                if (FAILED(hr = mpD3DDevice->SetPixelShaderConstantF(
+                        mActiveFragmentGpuProgramParameters->getPassIterationEntryIndex(), realEntry->val, 1)))
+                {
+                    OGRE_EXCEPT(hr, "Unable to upload pixel shader multi pass parameters", 
+                    "D3D9RenderSystem::bindGpuProgramMultiPassParameters");
+                }
+            }
+            break;
+
+        }
+    }
+    //---------------------------------------------------------------------
+    void D3D9RenderSystem::setClipPlanes(const PlaneList& clipPlanes)
+    {
+        size_t i;
+        size_t numClipPlanes;
+        float dx9ClipPlane[4];
+        DWORD mask = 0;
+        HRESULT hr;
+
+        numClipPlanes = clipPlanes.size();
+        for (i = 0; i < numClipPlanes; ++i)
+        {
+            const Plane& plane = clipPlanes[i];
+
+            dx9ClipPlane[0] = plane.normal.x;
+            dx9ClipPlane[1] = plane.normal.y;
+            dx9ClipPlane[2] = plane.normal.z;
+            dx9ClipPlane[3] = plane.d;
+
+            hr = mpD3DDevice->SetClipPlane(i, dx9ClipPlane);
+            if (FAILED(hr))
+            {
+                OGRE_EXCEPT(hr, "Unable to set clip plane", 
+                    "D3D9RenderSystem::setClipPlanes");
+            }
+
+            mask |= (1 << i);
+        }
+
+        hr = __SetRenderState(D3DRS_CLIPPLANEENABLE, mask);
+        if (FAILED(hr))
+        {
+            OGRE_EXCEPT(hr, "Unable to set render state for clip planes", 
+                "D3D9RenderSystem::setClipPlanes");
+        }
+    }
+	//---------------------------------------------------------------------
+    void D3D9RenderSystem::setScissorTest(bool enabled, size_t left, size_t top, size_t right,
+        size_t bottom)
+    {
+        HRESULT hr;
+        if (enabled)
+        {
+            if (FAILED(hr = __SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE)))
+            {
+                OGRE_EXCEPT(hr, "Unable to enable scissor rendering state; " + getErrorDescription(hr), 
+                    "D3D9RenderSystem::setScissorTest");
+            }
+            RECT rect;
+            rect.left = left;
+            rect.top = top;
+            rect.bottom = bottom;
+            rect.right = right;
+            if (FAILED(hr = mpD3DDevice->SetScissorRect(&rect)))
+            {
+                OGRE_EXCEPT(hr, "Unable to set scissor rectangle; " + getErrorDescription(hr), 
+                    "D3D9RenderSystem::setScissorTest");
+            }
+        }
+        else
+        {
+            if (FAILED(hr = __SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE)))
+            {
+                OGRE_EXCEPT(hr, "Unable to disable scissor rendering state; " + getErrorDescription(hr), 
+                    "D3D9RenderSystem::setScissorTest");
+            }
+        }
+    }
+    //---------------------------------------------------------------------
+    void D3D9RenderSystem::clearFrameBuffer(unsigned int buffers, 
+        const ColourValue& colour, Real depth, unsigned short stencil)
+    {
+        DWORD flags = 0;
+        if (buffers & FBT_COLOUR)
+        {
+            flags |= D3DCLEAR_TARGET;
+        }
+        if (buffers & FBT_DEPTH)
+        {
+            flags |= D3DCLEAR_ZBUFFER;
+        }
+        // Only try to clear the stencil buffer if supported
+        if (buffers & FBT_STENCIL && mCapabilities->hasCapability(RSC_HWSTENCIL))
+        {
+            flags |= D3DCLEAR_STENCIL;
+        }
+        HRESULT hr;
+        if( FAILED( hr = mpD3DDevice->Clear( 
+            0, 
+            NULL, 
+            flags,
+            colour.getAsARGB(), 
+            depth, 
+            stencil ) ) )
+        {
+            String msg = DXGetErrorDescription9(hr);
+            OGRE_EXCEPT( hr, "Error clearing frame buffer : " 
+                + msg, "D3D9RenderSystem::clearFrameBuffer" );
+        }
+    }
+    //---------------------------------------------------------------------
+    void D3D9RenderSystem::_makeProjectionMatrix(Real left, Real right, 
+        Real bottom, Real top, Real nearPlane, Real farPlane, Matrix4& dest,
+        bool forGpuProgram)
+    {
+        // Correct position for off-axis projection matrix
+        if (!forGpuProgram)
+        {
+            Real offsetX = left + right;
+            Real offsetY = top + bottom;
+
+            left -= offsetX;
+            right -= offsetX;
+            top -= offsetY;
+            bottom -= offsetY;
+        }
+
+        Real width = right - left;
+        Real height = top - bottom;
+        Real q, qn;
+        if (farPlane == 0)
+        {
+            q = 1 - Frustum::INFINITE_FAR_PLANE_ADJUST;
+            qn = nearPlane * (Frustum::INFINITE_FAR_PLANE_ADJUST - 1);
+        }
+        else
+        {
+            q = farPlane / ( farPlane - nearPlane );
+            qn = -q * nearPlane;
+        }
+        dest = Matrix4::ZERO;
+        dest[0][0] = 2 * nearPlane / width;
+        dest[0][2] = (right+left) / width;
+        dest[1][1] = 2 * nearPlane / height;
+        dest[1][2] = (top+bottom) / height;
+        if (forGpuProgram)
+        {
+            dest[2][2] = -q;
+            dest[3][2] = -1.0f;
+        }
+        else
+        {
+            dest[2][2] = q;
+            dest[3][2] = 1.0f;
+        }
+        dest[2][3] = qn;
+    }
+
+    // ------------------------------------------------------------------
+    void D3D9RenderSystem::setClipPlane (ushort index, Real A, Real B, Real C, Real D)
+    {
+        float plane[4] = { A, B, C, D };
+        mpD3DDevice->SetClipPlane (index, plane);
+    }
+
+    // ------------------------------------------------------------------
+    void D3D9RenderSystem::enableClipPlane (ushort index, bool enable)
+    {
+        DWORD prev;
+        mpD3DDevice->GetRenderState(D3DRS_CLIPPLANEENABLE, &prev);
+        __SetRenderState(D3DRS_CLIPPLANEENABLE, prev | (1 << index));
+    }
+    //---------------------------------------------------------------------
+    HardwareOcclusionQuery* D3D9RenderSystem::createHardwareOcclusionQuery(void)
+    {
+		D3D9HardwareOcclusionQuery* ret = new D3D9HardwareOcclusionQuery (mpD3DDevice); 
+		mHwOcclusionQueries.push_back(ret);
+		return ret;
+    }
+    //---------------------------------------------------------------------
+    Real D3D9RenderSystem::getHorizontalTexelOffset(void)
+    {
+        // D3D considers the origin to be in the center of a pixel
+        return -0.5f;
+    }
+    //---------------------------------------------------------------------
+    Real D3D9RenderSystem::getVerticalTexelOffset(void)
+    {
+        // D3D considers the origin to be in the center of a pixel
+        return -0.5f;
+    }
+    //---------------------------------------------------------------------
+    void D3D9RenderSystem::_applyObliqueDepthProjection(Matrix4& matrix, const Plane& plane, 
+        bool forGpuProgram)
+    {
+        // Thanks to Eric Lenyel for posting this calculation at www.terathon.com
+
+        // Calculate the clip-space corner point opposite the clipping plane
+        // as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and
+        // transform it into camera space by multiplying it
+        // by the inverse of the projection matrix
+
+        /* generalised version
+        Vector4 q = matrix.inverse() * 
+            Vector4(Math::Sign(plane.normal.x), Math::Sign(plane.normal.y), 1.0f, 1.0f);
+        */
+        Vector4 q;
+        q.x = Math::Sign(plane.normal.x) / matrix[0][0];
+        q.y = Math::Sign(plane.normal.y) / matrix[1][1];
+        q.z = 1.0F; 
+        // flip the next bit from Lengyel since we're right-handed
+        if (forGpuProgram)
+        {
+            q.w = (1.0F - matrix[2][2]) / matrix[2][3];
+        }
+        else
+        {
+            q.w = (1.0F + matrix[2][2]) / matrix[2][3];
+        }
+
+        // Calculate the scaled plane vector
+        Vector4 clipPlane4d(plane.normal.x, plane.normal.y, plane.normal.z, plane.d);
+        Vector4 c = clipPlane4d * (1.0F / (clipPlane4d.dotProduct(q)));
+
+        // Replace the third row of the projection matrix
+        matrix[2][0] = c.x;
+        matrix[2][1] = c.y;
+        // flip the next bit from Lengyel since we're right-handed
+        if (forGpuProgram)
+        {
+            matrix[2][2] = c.z; 
+        }
+        else
+        {
+            matrix[2][2] = -c.z; 
+        }
+        matrix[2][3] = c.w;        
+    }
+    //---------------------------------------------------------------------
+    Real D3D9RenderSystem::getMinimumDepthInputValue(void)
+    {
+        // Range [0.0f, 1.0f]
+        return 0.0f;
+    }
+    //---------------------------------------------------------------------
+    Real D3D9RenderSystem::getMaximumDepthInputValue(void)
+    {
+        // Range [0.0f, 1.0f]
+        // D3D inverts even identity view matrices, so maximum INPUT is -1.0
+        return -1.0f;
+    }
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::restoreLostDevice(void)
+	{
+		// Release all non-managed resources
+
+		// Cleanup depth stencils
+		_cleanupDepthStencils();
+
+		// Set all texture units to nothing
+		_disableTextureUnitsFrom(0);
+
+		// Unbind any vertex streams
+		for (size_t i = 0; i < mLastVertexSourceCount; ++i)
+		{
+			mpD3DDevice->SetStreamSource(i, NULL, 0, 0);
+		}
+        mLastVertexSourceCount = 0;
+
+        // Release all automatic temporary buffers and free unused
+        // temporary buffers, so we doesn't need to recreate them,
+        // and they will reallocate on demand. This save a lot of
+        // release/recreate of non-managed vertex buffers which
+        // wasn't need at all.
+        mHardwareBufferManager->_releaseBufferCopies(true);
+
+		// We have to deal with non-managed textures and vertex buffers
+		// GPU programs don't have to be restored
+		static_cast<D3D9TextureManager*>(mTextureManager)->releaseDefaultPoolResources();
+		static_cast<D3D9HardwareBufferManager*>(mHardwareBufferManager)
+			->releaseDefaultPoolResources();
+
+		// release additional swap chains (secondary windows)
+		SecondaryWindowList::iterator sw;
+		for (sw = mSecondaryWindows.begin(); sw != mSecondaryWindows.end(); ++sw)
+		{
+			(*sw)->destroyD3DResources();
+		}
+
+		// Reset the device, using the primary window presentation params
+		HRESULT hr = mpD3DDevice->Reset(
+			mPrimaryWindow->getPresentationParameters());
+
+		if (hr == D3DERR_DEVICELOST)
+		{
+			// Don't continue
+			return;
+		}
+		else if (FAILED(hr))
+		{
+			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 
+				"Cannot reset device! " + getErrorDescription(hr), 
+				"D3D9RenderWindow::restoreLostDevice" );
+		}
+
+		// will have lost basic states
+		mBasicStatesInitialised = false;
+        mVertexProgramBound = false;
+        mFragmentProgramBound = false;
+
+
+		// recreate additional swap chains
+		for (sw = mSecondaryWindows.begin(); sw != mSecondaryWindows.end(); ++sw)
+		{
+			(*sw)->createD3DResources();
+		}
+
+		// Recreate all non-managed resources
+		static_cast<D3D9TextureManager*>(mTextureManager)
+			->recreateDefaultPoolResources();
+		static_cast<D3D9HardwareBufferManager*>(mHardwareBufferManager)
+			->recreateDefaultPoolResources();
+			
+		LogManager::getSingleton().logMessage("!!! Direct3D Device successfully restored.");
+
+		mDeviceLost = false;
+
+		fireEvent("DeviceRestored");
+
+	}
+	//---------------------------------------------------------------------
+	bool D3D9RenderSystem::isDeviceLost(void)
+	{
+		return mDeviceLost;
+	}
+	//---------------------------------------------------------------------
+	void D3D9RenderSystem::_notifyDeviceLost(void)
+	{
+		LogManager::getSingleton().logMessage("!!! Direct3D Device Lost!");
+		mDeviceLost = true;
+		// will have lost basic states
+		mBasicStatesInitialised = false;
+
+		fireEvent("DeviceLost");
+	}
+
+	//---------------------------------------------------------------------
+	// Formats to try, in decreasing order of preference
+	D3DFORMAT ddDepthStencilFormats[]={
+		D3DFMT_D24FS8,
+		D3DFMT_D24S8,
+		D3DFMT_D24X4S4,
+		D3DFMT_D24X8,
+		D3DFMT_D15S1,
+		D3DFMT_D16,
+		D3DFMT_D32
+	};
+#define NDSFORMATS (sizeof(ddDepthStencilFormats)/sizeof(D3DFORMAT))
+	
+	D3DFORMAT D3D9RenderSystem::_getDepthStencilFormatFor(D3DFORMAT fmt)
+	{
+		/// Check if result is cached
+		DepthStencilHash::iterator i = mDepthStencilHash.find((unsigned int)fmt);
+		if(i != mDepthStencilHash.end())
+			return i->second;
+		/// If not, probe with CheckDepthStencilMatch
+		D3DFORMAT dsfmt = D3DFMT_UNKNOWN;
+
+		/// Get description of primary render target
+		LPDIRECT3DSURFACE9 mSurface = mPrimaryWindow->getRenderSurface();
+		D3DSURFACE_DESC srfDesc;
+
+		if(!FAILED(mSurface->GetDesc(&srfDesc)))
+		{
+			/// Probe all depth stencil formats
+			/// Break on first one that matches
+			for(size_t x=0; x<NDSFORMATS; ++x)
+			{
+                // Verify that the depth format exists
+                if (mpD3D->CheckDeviceFormat(
+                    mActiveD3DDriver->getAdapterNumber(),
+                    D3DDEVTYPE_HAL,
+                    srfDesc.Format,
+                    D3DUSAGE_DEPTHSTENCIL,
+                    D3DRTYPE_SURFACE,
+                    ddDepthStencilFormats[x]) != D3D_OK)
+                {
+                    continue;
+                }
+                // Verify that the depth format is compatible
+				if(mpD3D->CheckDepthStencilMatch(
+					mActiveD3DDriver->getAdapterNumber(),
+					D3DDEVTYPE_HAL, srfDesc.Format,
+					fmt, ddDepthStencilFormats[x]) == D3D_OK)
+				{
+					dsfmt = ddDepthStencilFormats[x];
+					break;
+				}
+			}
+		}
+		/// Cache result
+		mDepthStencilHash[(unsigned int)fmt] = dsfmt;
+		return dsfmt;
+	}
+	IDirect3DSurface9* D3D9RenderSystem::_getDepthStencilFor(D3DFORMAT fmt, D3DMULTISAMPLE_TYPE multisample, size_t width, size_t height)
+	{
+		D3DFORMAT dsfmt = _getDepthStencilFormatFor(fmt);
+		if(dsfmt == D3DFMT_UNKNOWN)
+			return 0;
+		IDirect3DSurface9 *surface = 0;
+
+		/// Check if result is cached
+		ZBufferFormat zbfmt(dsfmt, multisample);
+		ZBufferHash::iterator i = mZBufferHash.find(zbfmt);
+		if(i != mZBufferHash.end())
+		{
+			/// Check if size is larger or equal
+			if(i->second.width >= width && i->second.height >= height)
+			{
+				surface = i->second.surface;
+			} 
+			else
+			{
+				/// If not, destroy current buffer
+				i->second.surface->Release();
+				mZBufferHash.erase(i);
+			}
+		}
+		if(!surface)
+		{
+			/// If not, create the depthstencil surface
+			HRESULT hr = mpD3DDevice->CreateDepthStencilSurface( 
+				width, 
+				height, 
+				dsfmt, 
+				multisample, 
+				NULL, 
+				TRUE,  // discard true or false?
+				&surface, 
+				NULL);
+			if(FAILED(hr))
+			{
+				String msg = DXGetErrorDescription9(hr);
+				OGRE_EXCEPT( hr, "Error CreateDepthStencilSurface : " + msg, "D3D9RenderSystem::_getDepthStencilFor" );
+			}
+			/// And cache it
+			ZBufferRef zb;
+			zb.surface = surface;
+			zb.width = width;
+			zb.height = height;
+			mZBufferHash[zbfmt] = zb;
+		}
+		return surface;
+	}
+	void D3D9RenderSystem::_cleanupDepthStencils()
+	{
+		for(ZBufferHash::iterator i = mZBufferHash.begin(); i != mZBufferHash.end(); ++i)
+		{
+			/// Release buffer
+			i->second.surface->Release();
+		}
+		mZBufferHash.clear();
+	}
+
+	
+	#ifdef GAMETOOLS_ILLUMINATION_MODULE
+		void D3D9RenderSystem::_setTextureUnitSettings(size_t texUnit, TextureUnitState& tl)
+		{
+			int newUnit = texUnit;
+			if(tl.isVertexTexture())
+				newUnit = OGRE_MAX_TEXTURE_LAYERS + texUnit;
+
+			RenderSystem::_setTextureUnitSettings(newUnit, tl);
+		}
+	#endif
+}
