Struct recording a pass which can be used for a specific illumination stage.
This structure is used to record categorized 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 categorized properly.
Example #1
0
		/// <summary>
		///		Internal method for splitting the passes into illumination passes.
		/// </summary>
		public void CompileIlluminationPasses()
		{
			ClearIlluminationPasses();

			// don't need to split transparent passes since they are rendered seperately
			if ( this.IsTransparent )
			{
				return;
			}

			// start off with ambient passes
			IlluminationStage stage = IlluminationStage.Ambient;

			bool hasAmbient = false;

			for ( int i = 0; i < _passes.Count; /* increment in logic */)
			{
				Pass pass = (Pass)_passes[ i ];
				IlluminationPass iPass;

				switch ( stage )
				{
					case IlluminationStage.Ambient:
						// keep looking for ambient only
						if ( pass.IsAmbientOnly )
						{
							iPass = new IlluminationPass();
							iPass.OriginalPass = pass;
							iPass.Pass = pass;
							iPass.Stage = stage;
							_illuminationPasses.Add( iPass );
							hasAmbient = true;

							// progress to the next pass
							i++;
						}
						else
						{
							// split off any ambient part
							if ( pass.Ambient.CompareTo( ColorEx.Black ) != 0 ||
								pass.Emissive.CompareTo( ColorEx.Black ) != 0 )
							{

								Pass newPass = new Pass( this, pass.Index );
								pass.CopyTo( newPass );

								// remove any texture units
								newPass.RemoveAllTextureUnitStates();

								// also remove any fragment program
								if ( newPass.HasFragmentProgram )
								{
									newPass.SetFragmentProgram( "" );
								}

								// We have to leave vertex program alone (if any) and
								// just trust that the author is using light bindings, which 
								// we will ensure there are none in the ambient pass
								newPass.Diffuse = ColorEx.Black;
								newPass.Specular = ColorEx.Black;

								// if ambient and emissive are zero, then color write isn't needed
								if ( newPass.Ambient.CompareTo( ColorEx.Black ) == 0 &&
									newPass.Emissive.CompareTo( ColorEx.Black ) == 0 )
								{

									newPass.ColorWriteEnabled = false;
								}

								iPass = new IlluminationPass();
								iPass.DestroyOnShutdown = true;
								iPass.OriginalPass = pass;
								iPass.Pass = newPass;
								iPass.Stage = stage;

								_illuminationPasses.Add( iPass );
								hasAmbient = true;
							}

							if ( !hasAmbient )
							{
								// make up a new basic pass
								Pass newPass = new Pass( this, pass.Index );
								pass.CopyTo( newPass );

								newPass.Ambient = ColorEx.Black;
								newPass.Diffuse = ColorEx.Black;

								iPass = new IlluminationPass();
								iPass.DestroyOnShutdown = true;
								iPass.OriginalPass = pass;
								iPass.Pass = newPass;
								iPass.Stage = stage;
								_illuminationPasses.Add( iPass );
								hasAmbient = true;
							}

							// this means we are done with ambients, progress to per-light
							stage = IlluminationStage.PerLight;
						}

						break;

					case IlluminationStage.PerLight:
						if ( pass.IteratePerLight )
						{
							// if this is per-light already, use it directly
							iPass = new IlluminationPass();
							iPass.DestroyOnShutdown = false;
							iPass.OriginalPass = pass;
							iPass.Pass = pass;
							iPass.Stage = stage;
							_illuminationPasses.Add( iPass );

							// progress to the next pass
							i++;
						}
						else
						{
							// split off per-light details (can only be done for one)
							if ( pass.LightingEnabled &&
								( pass.Diffuse.CompareTo( ColorEx.Black ) != 0 ||
								pass.Specular.CompareTo( ColorEx.Black ) != 0 ) )
							{

								// copy existing pass
								Pass newPass = new Pass( this, pass.Index );
								pass.CopyTo( newPass );

								newPass.RemoveAllTextureUnitStates();

								// also remove any fragment program
								if ( newPass.HasFragmentProgram )
								{
									newPass.SetFragmentProgram( "" );
								}

								// Cannot remove vertex program, have to assume that
								// it will process diffuse lights, ambient will be turned off
								newPass.Ambient = ColorEx.Black;
								newPass.Emissive = ColorEx.Black;

								// must be additive
								newPass.SetSceneBlending( SceneBlendFactor.One, SceneBlendFactor.One );

								iPass = new IlluminationPass();
								iPass.DestroyOnShutdown = true;
								iPass.OriginalPass = pass;
								iPass.Pass = newPass;
								iPass.Stage = stage;

								_illuminationPasses.Add( iPass );
							}

							// This means the end of per-light passes
							stage = IlluminationStage.Decal;
						}

						break;

					case IlluminationStage.Decal:
						// We just want a 'lighting off' pass to finish off
						// and only if there are texture units
						if ( pass.TextureUnitStageCount > 0 )
						{
							if ( !pass.LightingEnabled )
							{
								// we assume this pass already combines as required with the scene
								iPass = new IlluminationPass();
								iPass.DestroyOnShutdown = false;
								iPass.OriginalPass = pass;
								iPass.Pass = pass;
								iPass.Stage = stage;
								_illuminationPasses.Add( iPass );
							}
							else
							{
								// Copy the pass and tweak away the lighting parts
								Pass newPass = new Pass( this, pass.Index );
								pass.CopyTo( newPass );
								newPass.Ambient = ColorEx.Black;
								newPass.Diffuse = ColorEx.Black;
								newPass.Specular = ColorEx.Black;
								newPass.Emissive = ColorEx.Black;
								newPass.LightingEnabled = false;
								// modulate
								newPass.SetSceneBlending( SceneBlendFactor.DestColor, SceneBlendFactor.Zero );

								// there is nothing we can do about vertex & fragment
								// programs here, so people will just have to make their
								// programs friendly-like if they want to use this technique
								iPass = new IlluminationPass();
								iPass.DestroyOnShutdown = true;
								iPass.OriginalPass = pass;
								iPass.Pass = newPass;
								iPass.Stage = stage;
								_illuminationPasses.Add( iPass );
							}
						}

						// always increment on decal, since nothing more to do with this pass
						i++;

						break;
				}
			}

			_compiledIlluminationPasses = true;
		}
        /// <summary>
        ///		Internal method for splitting the passes into illumination passes.
        /// </summary>
        public void CompileIlluminationPasses()
        {
            ClearIlluminationPasses();

            // don't need to split transparent passes since they are rendered seperately
            if(this.IsTransparent) {
                return;
            }

            // start off with ambient passes
            IlluminationStage stage = IlluminationStage.Ambient;

            bool hasAmbient = false;

            for(int i = 0; i < passes.Count; /* increment in logic */) {
                Pass pass = (Pass)passes[i];
                IlluminationPass iPass;

                switch(stage) {
                    case IlluminationStage.Ambient:
                        // keep looking for ambient only
                        if(pass.IsAmbientOnly) {
                            iPass = new IlluminationPass();
                            iPass.OriginalPass = pass;
                            iPass.Pass = pass;
                            iPass.Stage = stage;
                            illuminationPasses.Add(iPass);
                            hasAmbient = true;

                            // progress to the next pass
                            i++;
                        }
                        else {
                            // split off any ambient part
                            if(pass.Ambient.CompareTo(ColorEx.Black) != 0 ||
                               pass.Emissive.CompareTo(ColorEx.Black) != 0 ||
                               pass.AlphaRejectFunction != CompareFunction.AlwaysPass) {

                                Pass newPass = new Pass(this, pass.Index);
                                pass.CopyTo(newPass);
                                if (newPass.AlphaRejectFunction != CompareFunction.AlwaysPass) {
                                    // Alpha rejection passes must retain their transparency, so
                                    // we allow the texture units, but override the colour functions
                                    for (int tindex = 0; tindex < newPass.NumTextureUnitStages; tindex++)
                                    {
                                        TextureUnitState tus = newPass.GetTextureUnitState(tindex);
                                        tus.SetColorOperationEx(LayerBlendOperationEx.Source1, LayerBlendSource.Current, LayerBlendSource.Current);
                                    }
                                }
                                else
                                    // remove any texture units
                                    newPass.RemoveAllTextureUnitStates();

                                // also remove any fragment program
                                if(newPass.HasFragmentProgram) {
                                    newPass.SetFragmentProgram("");
                                }

                                // We have to leave vertex program alone (if any) and
                                // just trust that the author is using light bindings, which
                                // we will ensure there are none in the ambient pass
                                newPass.Diffuse = new ColorEx(newPass.Diffuse.a, 0f, 0f, 0f); // Preserving alpha
                                newPass.Specular = ColorEx.Black;

                                // Calculate hash value for new pass, because we are compiling
                                // illumination passes on demand, which will loss hash calculate
                                // before it add to render queue first time.
                                newPass.RecalculateHash();

                                iPass = new IlluminationPass();
                                iPass.DestroyOnShutdown = true;
                                iPass.OriginalPass = pass;
                                iPass.Pass = newPass;
                                iPass.Stage = stage;

                                illuminationPasses.Add(iPass);
                                hasAmbient = true;
                            }

                            if(!hasAmbient) {
                                // make up a new basic pass
                                Pass newPass = new Pass(this, pass.Index);
                                pass.CopyTo(newPass);

                                newPass.Ambient = ColorEx.Black;
                                newPass.Diffuse = ColorEx.Black;

                                // Calculate hash value for new pass, because we are compiling
                                // illumination passes on demand, which will loss hash calculate
                                // before it add to render queue first time.
                                newPass.RecalculateHash();

                                iPass = new IlluminationPass();
                                iPass.DestroyOnShutdown = true;
                                iPass.OriginalPass = pass;
                                iPass.Pass = newPass;
                                iPass.Stage = stage;
                                illuminationPasses.Add(iPass);
                                hasAmbient = true;
                            }

                            // this means we are done with ambients, progress to per-light
                            stage = IlluminationStage.PerLight;
                        }

                        break;

                    case IlluminationStage.PerLight:
                        if(pass.RunOncePerLight) {
                            // if this is per-light already, use it directly
                            iPass = new IlluminationPass();
                            iPass.DestroyOnShutdown = false;
                            iPass.OriginalPass = pass;
                            iPass.Pass = pass;
                            iPass.Stage = stage;
                            illuminationPasses.Add(iPass);

                            // progress to the next pass
                            i++;
                        }
                        else {
                            // split off per-light details (can only be done for one)
                            if(pass.LightingEnabled &&
                                (pass.Diffuse.CompareTo(ColorEx.Black) != 0 ||
                                pass.Specular.CompareTo(ColorEx.Black) != 0)) {

                                // copy existing pass
                                Pass newPass = new Pass(this, pass.Index);
                                pass.CopyTo(newPass);

                                if (newPass.AlphaRejectFunction != CompareFunction.AlwaysPass) {
                                    // Alpha rejection passes must retain their transparency, so
                                    // we allow the texture units, but override the colour functions
                                    for (int tindex = 0; tindex < newPass.NumTextureUnitStages; tindex++)
                                    {
                                        TextureUnitState tus = newPass.GetTextureUnitState(tindex);
                                        tus.SetColorOperationEx(LayerBlendOperationEx.Source1, LayerBlendSource.Current, LayerBlendSource.Current);
                                    }
                                }
                                else
                                    // remove any texture units
                                    newPass.RemoveAllTextureUnitStates();

                                // also remove any fragment program
                                if(newPass.HasFragmentProgram) {
                                    newPass.SetFragmentProgram("");
                                }

                                // Cannot remove vertex program, have to assume that
                                // it will process diffuse lights, ambient will be turned off
                                newPass.Ambient = ColorEx.Black;
                                newPass.Emissive = ColorEx.Black;

                                // must be additive
                                newPass.SetSceneBlending(SceneBlendFactor.One, SceneBlendFactor.One);

                                iPass = new IlluminationPass();
                                iPass.DestroyOnShutdown = true;
                                iPass.OriginalPass = pass;
                                iPass.Pass = newPass;
                                iPass.Stage = stage;

                                illuminationPasses.Add(iPass);
                            }

                            // This means the end of per-light passes
                            stage = IlluminationStage.Decal;
                        }

                        break;

                    case IlluminationStage.Decal:
                        // We just want a 'lighting off' pass to finish off
                        // and only if there are texture units
                        if(pass.NumTextureUnitStages > 0) {
                            if(!pass.LightingEnabled) {
                                // we assume this pass already combines as required with the scene
                                iPass = new IlluminationPass();
                                iPass.DestroyOnShutdown = false;
                                iPass.OriginalPass = pass;
                                iPass.Pass = pass;
                                iPass.Stage = stage;
                                illuminationPasses.Add(iPass);
                            }
                            else {
                                // Copy the pass and tweak away the lighting parts
                                Pass newPass = new Pass(this, pass.Index);
                                pass.CopyTo(newPass);
                                newPass.Ambient = ColorEx.Black;
                                newPass.Diffuse = new ColorEx(newPass.Diffuse.a, 0f, 0f, 0f); // Preserving alpha
                                newPass.Specular = ColorEx.Black;
                                newPass.Emissive = ColorEx.Black;
                                newPass.LightingEnabled = false;
                                // modulate
                                newPass.SetSceneBlending(SceneBlendFactor.DestColor, SceneBlendFactor.Zero);

                                // Calculate hash value for new pass, because we are compiling
                                // illumination passes on demand, which will loss hash calculate
                                // before it add to render queue first time.
                                newPass.RecalculateHash();

                                // there is nothing we can do about vertex & fragment
                                // programs here, so people will just have to make their
                                // programs friendly-like if they want to use this technique
                                iPass = new IlluminationPass();
                                iPass.DestroyOnShutdown = true;
                                iPass.OriginalPass = pass;
                                iPass.Pass = newPass;
                                iPass.Stage = stage;
                                illuminationPasses.Add(iPass);
                            }
                        }

                        // always increment on decal, since nothing more to do with this pass
                        i++;

                        break;
                }
            }
        }