/// <summary>
        ///		Render a group rendering only shadow receivers.
        /// </summary>
        /// <param name="group">Render queue group.</param>
        protected virtual void RenderTextureShadowReceiverQueueGroupObjects(RenderQueueGroup group)
        {
            // Override auto param ambient to force vertex programs to go full-bright
            autoParamDataSource.AmbientLight = ColorEx.White;
            targetRenderSystem.AmbientLight = ColorEx.White;

            // Iterate through priorities
            for(int i = 0; i < group.NumPriorityGroups; i++) {
                RenderPriorityGroup priorityGroup = group.GetPriorityGroup(i);

                // Do solids, override light list in case any vertex programs use them
                RenderSolidObjects(priorityGroup.solidPasses, false, nullLightList);

                // Don't render transparents or passes which have shadow receipt disabled

            }// for each priority

            // reset ambient
            autoParamDataSource.AmbientLight = ambientColor;
            targetRenderSystem.AmbientLight = ambientColor;
        }
        /// <summary>
        ///		Render a group with the added complexity of additive texture shadows.
        /// </summary>
        /// <param name="group">Render queue group.</param>
        void RenderAdditiveTextureShadowedQueueGroupObjects(RenderQueueGroup group)
        {
            List<Light> tempLightList = new List<Light>();
            for(int i = 0; i < group.NumPriorityGroups; i++) {
                RenderPriorityGroup priorityGroup = group.GetPriorityGroup(i);

                // Sort the queue first
                priorityGroup.Sort(cameraInProgress);

                // Clear light list
                tempLightList.Clear();

                // Render all the ambient passes first, no light iteration, no lights
                RenderSolidObjects(priorityGroup.solidPasses, false, tempLightList);
                // Also render any objects which have receive shadows disabled
                renderingNoShadowQueue = true;
                RenderSolidObjects(priorityGroup.solidPassesNoShadow, true);
                renderingNoShadowQueue = false;

                // only perform this next part if we're in the 'normal' render stage, to avoid
                // doing it during the render to texture
                if (illuminationStage == IlluminationRenderStage.None) {

                    ICollection<MovableObject> lightList = GetMovableObjectCollection("Light");
                    List<Light> lightList2 = new List<Light>();
                    foreach (Light l in lightList)
                        lightList2.Add(l);
                    lightList2.Sort();

                    // Iterate over lights, render masked
                    for (int li = 0, sti = 0; li < lightsAffectingFrustum.Count; li++) {
                        Light light = lightsAffectingFrustum[li];
                        // Set light state
                        if (light.CastShadows && sti < shadowTextures.Count) {
                            Texture shadowTex = shadowTextures[sti];
                            // Get camera for current shadow texture
                            Camera camera = shadowTex.GetBuffer().GetRenderTarget().GetViewport(0).Camera;
                            // Hook up receiver texture
                            Pass targetPass = shadowTextureCustomReceiverPass != null ?
                                shadowTextureCustomReceiverPass : shadowReceiverPass;
                            targetPass.GetTextureUnitState(0).SetTextureName(shadowTex.Name);
                            // Hook up projection frustum
                            targetPass.GetTextureUnitState(0).SetProjectiveTexturing(true, camera);
                            autoParamDataSource.TextureProjector = camera;
                            // Remove any spot fader layer
                            if (targetPass.NumTextureUnitStages > 1 &&
                                targetPass.GetTextureUnitState(1).TextureName == "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(SceneBlendFactor.One, SceneBlendFactor.One);
                            targetPass.LightingEnabled = true;
                            targetPass.Load();
                            // increment shadow texture since used
                            ++sti;
                            illuminationStage = IlluminationRenderStage.RenderModulativePass;
                        }
                        else {
                            illuminationStage = IlluminationRenderStage.None;
                        }

                        // render lighting passes for this light
                        if (tempLightList.Count == 0)
                            tempLightList.Add(light);
                        else
                            tempLightList[0] = light;

                        RenderSolidObjects(priorityGroup.solidPassesDiffuseSpecular, false, lightList2);

                    }// for each light
                    illuminationStage = IlluminationRenderStage.None;

                    // Now render decal passes, no need to set lights as lighting will be disabled
                    RenderSolidObjects(priorityGroup.solidPassesDecal, false);
                }

            }// for each priority

            for(int i = 0; i < group.NumPriorityGroups; i++) {
                RenderPriorityGroup priorityGroup = group.GetPriorityGroup(i);

                // Do transparents
                RenderTransparentObjects(priorityGroup.transparentPasses, true);
            }// for each priority
        }
        /// <summary>
        ///		Render a group rendering only shadow casters.
        /// </summary>
        /// <param name="group">Render queue group.</param>
        protected virtual void RenderTextureShadowCasterQueueGroupObjects(RenderQueueGroup group)
        {
            // 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

            // Override auto param ambient to force vertex programs and fixed function to
            // use shadow colour
            if (IsShadowTechniqueAdditive) {
                autoParamDataSource.AmbientLight = ColorEx.Black;
                targetRenderSystem.AmbientLight = ColorEx.Black;
            }
            else {
                autoParamDataSource.AmbientLight = shadowColor;
                targetRenderSystem.AmbientLight = shadowColor;
            }

            // Iterate through priorities
            for(int i = 0; i < group.NumPriorityGroups; i++) {
                RenderPriorityGroup priorityGroup = group.GetPriorityGroup(i);

                // Sort the queue first
                priorityGroup.Sort(cameraInProgress);

                // Do solids, override light list in case any vertex programs use them
                RenderSolidObjects(priorityGroup.solidPasses, false, nullLightList);
                renderingNoShadowQueue = true;
                RenderSolidObjects(priorityGroup.solidPassesNoShadow, false, nullLightList);
                renderingNoShadowQueue = false;

                // Do transparents that cast shadows
                RenderTransparentShadowCasterObjects(priorityGroup.transparentPasses, false, nullLightList);
            }// for each priority

            // reset ambient light
            autoParamDataSource.AmbientLight = ambientColor;
            targetRenderSystem.AmbientLight = ambientColor;
        }
        /// <summary>
        ///		Render a group with the added complexity of modulative texture shadows.
        /// </summary>
        /// <param name="group">Render queue group.</param>
        protected virtual void RenderModulativeTextureShadowedQueueGroupObjects(RenderQueueGroup group)
        {
            /* 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 is 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
            renderModulativeGroupsMeter.Enter();
            for(int i = 0; i < group.NumPriorityGroups; i++) {
                RenderPriorityGroup priorityGroup = group.GetPriorityGroup(i);

                // Sort the queue first
                priorityGroup.Sort(cameraInProgress);

                // Do solids
                RenderSolidObjects(priorityGroup.solidPasses, true);
                renderingNoShadowQueue = true;
                RenderSolidObjects(priorityGroup.solidPassesNoShadow, true);
                renderingNoShadowQueue = false;
            }
            renderModulativeGroupsMeter.Exit();

            renderModulativeLightsMeter.Enter();
            // 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 (illuminationStage == IlluminationRenderStage.None) {
                illuminationStage = IlluminationRenderStage.RenderModulativePass;

                for (int i = 0, sti = 0;
                    i < lightsAffectingFrustum.Count && sti < shadowTextures.Count; i++) {
                    Light light = lightsAffectingFrustum[i];

                    if (!light.CastShadows)
                        continue;

                    Texture shadowTex = shadowTextures[sti];
                    Camera cam = shadowTex.GetBuffer().GetRenderTarget().GetViewport(0).Camera;

                    // Hook up receiver texture
                    Pass targetPass = shadowTextureCustomReceiverPass != null ?
                        shadowTextureCustomReceiverPass : shadowReceiverPass;
                    targetPass.GetTextureUnitState(0).SetTextureName(shadowTex.Name);
                    // Hook up projection frustum
                    targetPass.GetTextureUnitState(0).SetProjectiveTexturing(true, cam);
                    autoParamDataSource.TextureProjector = cam;

                    // if this light is a spotlight, we need to add the spot fader layer
                    if (light.Type == LightType.Spotlight) {
                        // remove all TUs except 0 & 1
                        // (only an issue if additive shadows have been used)
                        while (targetPass.NumTextureUnitStages > 2)
                            targetPass.RemoveTextureUnitState(2);

                        // Add spot fader if not present already
                        if (targetPass.NumTextureUnitStages == 2 &&
                            targetPass.GetTextureUnitState(1).TextureName == "spot_shadow_fade.png") {
                            // Just set
                            TextureUnitState tex =
                                targetPass.GetTextureUnitState(1);
                            tex.SetProjectiveTexturing(true, cam);
                        }
                        else {
                            // Remove any non-conforming spot layers
                            while (targetPass.NumTextureUnitStages > 1)
                                targetPass.RemoveTextureUnitState(1);

                            TextureUnitState tex =
                                targetPass.CreateTextureUnitState("spot_shadow_fade.png");
                            tex.SetProjectiveTexturing(true, cam);
                            tex.SetColorOperation(LayerBlendOperation.Add);
                            tex.TextureAddressing = TextureAddressing.Clamp;
                        }
                    }
                    else {
                        // remove all TUs except 0 including spot
                        while (targetPass.NumTextureUnitStages > 1)
                            targetPass.RemoveTextureUnitState(1);
                    }

                    // Set lighting / blending modes
                    targetPass.SetSceneBlending(SceneBlendFactor.DestColor, SceneBlendFactor.Zero);
                    targetPass.LightingEnabled = false;

                    targetPass.Load();

                    // Fire pre-reciever event
                    // fireShadowTexturesPreReceiver(light, cam);

                    RenderTextureShadowReceiverQueueGroupObjects(group);
                    ++sti;

                } // for each light

                illuminationStage = IlluminationRenderStage.None;
            }
            renderModulativeLightsMeter.Exit();

            // Iterate again
            for (int i = 0; i < group.NumPriorityGroups; i++) {
                RenderPriorityGroup priorityGroup = group.GetPriorityGroup(i);

                // Do transparents
                RenderTransparentObjects(priorityGroup.transparentPasses, true);
            } // for each priority
        }
        /// <summary>
        ///		Render a group with the added complexity of modulative stencil shadows.
        /// </summary>
        /// <param name="group">Render queue group.</param>
        protected virtual void RenderModulativeStencilShadowedQueueGroupObjects(RenderQueueGroup group)
        {
            /* 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.
            */
            for(int i = 0; i < group.NumPriorityGroups; i++) {
                RenderPriorityGroup priorityGroup = group.GetPriorityGroup(i);

                // sort the group first
                priorityGroup.Sort(cameraInProgress);

                // do solids
                RenderSolidObjects(priorityGroup.solidPasses, true);
            }

            // iterate over lights, rendering all volumes to the stencil buffer
            for(int i = 0; i < lightsAffectingFrustum.Count; i++) {
                Light light = lightsAffectingFrustum[i];

                if(light.CastShadows) {
                    // clear the stencil buffer
                    targetRenderSystem.ClearFrameBuffer(FrameBuffer.Stencil);
                    RenderShadowVolumesToStencil(light, cameraInProgress);

                    // render full-screen shadow modulator for all lights
                    SetPass(shadowModulativePass);

                    // turn the stencil check on
                    targetRenderSystem.StencilCheckEnabled = true;

                    // we render where the stencil is not equal to zero to render shadows, not lit areas
                    targetRenderSystem.SetStencilBufferParams(CompareFunction.NotEqual, 0);
                    RenderSingleObject(fullScreenQuad, shadowModulativePass, false);

                    // reset stencil buffer params
                    targetRenderSystem.SetStencilBufferParams();
                    targetRenderSystem.StencilCheckEnabled = false;
                    targetRenderSystem.SetDepthBufferParams();
                }
            }// for each light

            for(int i = 0; i < group.NumPriorityGroups; i++) {
                RenderPriorityGroup priorityGroup = group.GetPriorityGroup(i);

                // Do non-shadowable solids
                renderingNoShadowQueue = true;
                RenderSolidObjects(priorityGroup.solidPassesNoShadow, true);
                renderingNoShadowQueue = false;
            }// for each priority

            for(int i = 0; i < group.NumPriorityGroups; i++) {
                RenderPriorityGroup priorityGroup = group.GetPriorityGroup(i);

                // Do transparents
                RenderTransparentObjects(priorityGroup.transparentPasses, true);

            } // for each priority
        }
        /// <summary>
        ///		Render a group in the ordinary way
        /// </summary>
        /// <param name="group">Group containing the objects to render.</param>
        protected virtual void RenderBasicQueueGroupObjects(RenderQueueGroup group)
        {
            // Basic render loop
            // Iterate through priorities
            for(int i = 0; i < group.NumPriorityGroups; i++) {
                RenderPriorityGroup priorityGroup = group.GetPriorityGroup(i);

                // Sort the queue first
                priorityGroup.Sort(cameraInProgress);

                // Do solids
                RenderSolidObjects(priorityGroup.solidPasses, true);

                // Do transparents
                RenderTransparentObjects(priorityGroup.transparentPasses, true);
            }// for each priority
        }
        /// <summary>
        ///		Render a group with the added complexity of additive stencil shadows.
        /// </summary>
        /// <param name="group">Render queue group.</param>
        protected virtual void RenderAdditiveStencilShadowedQueueGroupObjects(RenderQueueGroup group)
        {
            List<Light> tempLightList = new List<Light>();

            for(int i = 0; i < group.NumPriorityGroups; i++) {
                RenderPriorityGroup priorityGroup = group.GetPriorityGroup(i);

                // sort the group first
                priorityGroup.Sort(cameraInProgress);

                // Clear light list
                tempLightList.Clear();

                // Render all the ambient passes first, no light iteration, no lights
                illuminationStage = IlluminationRenderStage.Ambient;
                RenderSolidObjects(priorityGroup.solidPasses, false, tempLightList);
                // Also render any objects which have receive shadows disabled
                renderingNoShadowQueue = true;
                RenderSolidObjects(priorityGroup.solidPassesNoShadow, true);
                renderingNoShadowQueue = false;

                // Now iterate per light
                illuminationStage = IlluminationRenderStage.PerLight;

                for (int li = 0; li < lightsAffectingFrustum.Count; li++) {
                    Light light = lightsAffectingFrustum[li];
                    // Set light state

                    if (light.CastShadows) {
                        // Clear stencil
                        targetRenderSystem.ClearFrameBuffer(FrameBuffer.Stencil);
                        RenderShadowVolumesToStencil(light, cameraInProgress);
                        // turn stencil check on
                        targetRenderSystem.StencilCheckEnabled = true;
                        // NB we render where the stencil is equal to zero to render lit areas
                        targetRenderSystem.SetStencilBufferParams(CompareFunction.Equal, 0);
                    }

                    // render lighting passes for this light
                    if (tempLightList.Count == 0) {
                        tempLightList.Add(light);
                    }
                    else {
                        tempLightList[0] = light;
                    }

                    RenderSolidObjects(priorityGroup.solidPassesDiffuseSpecular, false, tempLightList);

                    // Reset stencil params
                    targetRenderSystem.SetStencilBufferParams();
                    targetRenderSystem.StencilCheckEnabled = false;
                    targetRenderSystem.SetDepthBufferParams();

                }// for each light

                // Now render decal passes, no need to set lights as lighting will be disabled
                illuminationStage = IlluminationRenderStage.Decal;
                RenderSolidObjects(priorityGroup.solidPassesDecal, false);

            }// for each priority

            // reset lighting stage
            illuminationStage = IlluminationRenderStage.None;

            // Iterate again
            for(int i = 0; i < group.NumPriorityGroups; i++) {
                RenderPriorityGroup priorityGroup = group.GetPriorityGroup(i);

                // Do transparents
                RenderTransparentObjects(priorityGroup.transparentPasses, true);

            }// for each priority
        }