Axiom.Graphics.Pass.RecalculateHash C# (CSharp) Method

RecalculateHash() private method

Internal method for recalculating the hash code used for sorting passes.
private RecalculateHash ( ) : void
return void
		internal void RecalculateHash()
		{
			/* 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.
		   */
			_hashCode = ( _index << 28 );
			int count = TextureUnitStageCount;

			// Fix from Multiverse
			//    It fixes a problem that was causing rendering passes for a single material to be executed in the wrong order.
			if ( count > 0 && !( (TextureUnitState)textureUnitStates[ 0 ] ).IsBlank )
			{
				_hashCode += ( ( (TextureUnitState)textureUnitStates[ 0 ] ).TextureName.GetHashCode() & ( ( 1 << 14 ) - 1 ) ) << 14;
			}
			if ( count > 1 && !( (TextureUnitState)textureUnitStates[ 1 ] ).IsBlank )
			{
				_hashCode += ( ( (TextureUnitState)textureUnitStates[ 1 ] ).TextureName.GetHashCode() & ( ( 1 << 14 ) - 1 ) );
			}
		}

Usage Example

        /// <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;
                }
            }
        }