GetTextureUnitState() public method

Gets a reference to the TextureUnitState for this pass at the specified indx.
public GetTextureUnitState ( int index ) : TextureUnitState
index int Index of the state to retreive.
return TextureUnitState
Example #1
0
		public override bool PreAddToRenderState( TargetRenderState targetRenderState, Pass srcPass, Pass dstPass )
		{
			//count the number of texture units we need to process
			int validTexUnits = 0;
			for ( int i = 0; i < srcPass.TextureUnitStatesCount; i++ )
			{
				if ( IsProcessingNeeded( srcPass.GetTextureUnitState( i ) ) )
				{
					validTexUnits++;
				}
			}

			SetTextureUnitCount( validTexUnits );

			//Build texture stage sub states
			for ( int i = 0; i < srcPass.TextureUnitStatesCount; i++ )
			{
				TextureUnitState texUnitState = srcPass.GetTextureUnitState( i );
				if ( IsProcessingNeeded( texUnitState ) )
				{
					SetTextureUnit( i, texUnitState );
				}
			}

			return true;
		}
Example #2
0
		/// <summary>
		///		Internal utility method for rendering a single object.
		/// </summary>
		/// <param name="renderable">The renderable to issue to the pipeline.</param>
		/// <param name="pass">The pass which is being used.</param>
		/// <param name="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>
		/// <param name="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.</param>
		protected virtual void RenderSingleObject( IRenderable renderable,
												   Pass pass,
												   bool doLightIteration,
												   LightList manualLightList )
		{
			ushort numMatrices = 0;

			// grab the current scene detail level
			PolygonMode camPolyMode = this.cameraInProgress.PolygonMode;

			// get the world matrices and the count
			renderable.GetWorldTransforms( this.xform );
			numMatrices = renderable.NumWorldTransforms;

			// set the world matrices in the render system
			if ( numMatrices > 1 )
			{
				this.targetRenderSystem.SetWorldMatrices( this.xform, numMatrices );
			}
			else
			{
				this.targetRenderSystem.WorldMatrix = this.xform[ 0 ];
			}

			// issue view/projection changes (if any)
			this.UseRenderableViewProjection( renderable );

			if ( !this.suppressRenderStateChanges )
			{
				bool passSurfaceAndLightParams = true;
				if ( pass.IsProgrammable )
				{
					// Tell auto params object about the renderable change
					this.autoParamDataSource.Renderable = renderable;
					pass.UpdateAutoParamsNoLights( this.autoParamDataSource );
					if ( pass.HasVertexProgram )
					{
						passSurfaceAndLightParams = pass.VertexProgram.PassSurfaceAndLightStates;
					}
				}

				// issue texture units that depend on updated view matrix
				// reflective env mapping is one case
				for ( int i = 0; i < pass.TextureUnitStageCount; i++ )
				{
					TextureUnitState texUnit = pass.GetTextureUnitState( i );

					if ( texUnit.HasViewRelativeTexCoordGen )
					{
					    targetRenderSystem.SetTextureUnitSettings( i, texUnit );
					    //this.targetRenderSystem.SetTextureUnit( i, texUnit, !pass.HasFragmentProgram );
					}
				}

				// Normalize normals
				bool thisNormalize = renderable.NormalizeNormals;

				if ( thisNormalize != normalizeNormals )
				{
					this.targetRenderSystem.NormalizeNormals = thisNormalize;
					normalizeNormals = thisNormalize;
				}

				// Set up the solid / wireframe override
				PolygonMode requestedMode = pass.PolygonMode;
				if ( renderable.PolygonModeOverrideable == true )
				{
					// check camera detial only when render detail is overridable
					if ( requestedMode > camPolyMode )
					{
						// only downgrade detail; if cam says wireframe we don't go up to solid
						requestedMode = camPolyMode;
					}
				}

				if ( requestedMode != this.lastPolyMode )
				{
					this.targetRenderSystem.PolygonMode = requestedMode;
					this.lastPolyMode = requestedMode;
				}

				// TODO: Add ClipPlanes to RenderSystem.cs
				// This is removed in OGRE 1.6.0... no need to port - J. Price
				//targetRenderSystem.ClipPlanes = renderable.ClipPlanes;

				// get the renderables render operation
				op = renderable.RenderOperation;
				// TODO: Add srcRenderable to RenderOperation.cs
				//op.srcRenderable = renderable;

				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
					LightList rendLightList = renderable.Lights;
					bool iteratePerLight = pass.IteratePerLight;
					int numIterations = iteratePerLight ? rendLightList.Count : 1;
					LightList lightListToUse = null;

					for ( int i = 0; i < numIterations; i++ )
					{
						// determine light list to use
						if ( iteratePerLight )
						{
							localLightList.Clear();

							// check whether we need to filter this one out
							if ( pass.RunOnlyOncePerLightType && pass.OnlyLightType != rendLightList[ i ].Type )
							{
								// skip this one
								continue;
							}

							localLightList.Add( rendLightList[ i ] );
							lightListToUse = localLightList;
						}
						else
						{
							// use complete light list
							lightListToUse = rendLightList;
						}

						if ( pass.IsProgrammable )
						{
							// Update any automatic gpu params for lights
							// Other bits of information will have to be looked up
							this.autoParamDataSource.SetCurrentLightList( lightListToUse );
							pass.UpdateAutoParamsLightsOnly( this.autoParamDataSource );

						    UpdateGpuProgramParameters( pass );
						}

						// Do we need to update light states?
						// Only do this if fixed-function vertex lighting applies
						if ( pass.LightingEnabled && passSurfaceAndLightParams )
						{
							this.targetRenderSystem.UseLights( lightListToUse, pass.MaxSimultaneousLights );
						}
                        this.targetRenderSystem.CurrentPassIterationCount = pass.IterationCount;
						// issue the render op
						this.targetRenderSystem.Render( op );
					} // iterate per light
				}
				else
				{
					// do we need to update GPU program parameters?
					if ( pass.IsProgrammable )
					{
						// do we have a manual light list
						if ( manualLightList != null )
						{
							// Update any automatic gpu params for lights
							// Other bits of information will have to be looked up
							this.autoParamDataSource.SetCurrentLightList( manualLightList );
							pass.UpdateAutoParamsLightsOnly( this.autoParamDataSource );
						}

					    UpdateGpuProgramParameters( pass );
					}

					// Use manual lights if present, and not using vertex programs
					if ( manualLightList != null && pass.LightingEnabled && passSurfaceAndLightParams )
					{
						this.targetRenderSystem.UseLights( manualLightList, pass.MaxSimultaneousLights );
					}
                    this.targetRenderSystem.CurrentPassIterationCount = pass.IterationCount;
					// issue the render op
					this.targetRenderSystem.Render( op );
				}
			}
			else
			{
				// suppressRenderStateChanges
				// Just render
                this.targetRenderSystem.CurrentPassIterationCount = 1;
				this.targetRenderSystem.Render( op );
			}

			// Reset view / projection changes if any
			this.ResetViewProjectionMode();
		}
Example #3
0
		/// <summary>Internal method for setting up the renderstate for a rendering pass.</summary>
		/// <param name="pass">The Pass details to set.</param>
		/// <param name="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.
		/// </param>
		/// <param name="shadowDerivation">
		///    If false, disables the derivation of shadow passes from original passes
		/// </param>
		/// <returns>
		///		A Pass object that was used instead of the one passed in, can
		///		happen when rendering shadow passes
		///	</returns>
		public virtual Pass SetPass( Pass pass, bool evenIfSuppressed, bool shadowDerivation )
		{
			if ( !this.suppressRenderStateChanges || evenIfSuppressed )
			{
				if ( this.illuminationStage == IlluminationRenderStage.RenderToTexture && shadowDerivation )
				{
					// Derive a special shadow caster pass from this one
					pass = this.DeriveShadowCasterPass( pass );
				}
				else if ( this.illuminationStage == IlluminationRenderStage.RenderReceiverPass )
				{
					pass = this.DeriveShadowReceiverPass( pass );
				}

				//TODO :autoParamDataSource.SetPass( pass );

				bool passSurfaceAndLightParams = true;

				if ( pass.HasVertexProgram )
				{
					this.targetRenderSystem.BindGpuProgram( pass.VertexProgram.BindingDelegate );
					// bind parameters later since they can be per-object
					// does the vertex program want surface and light params passed to rendersystem?
					passSurfaceAndLightParams = pass.VertexProgram.PassSurfaceAndLightStates;
				}
				else
				{
					// Unbind program?
					if ( this.targetRenderSystem.IsGpuProgramBound( GpuProgramType.Vertex ) )
					{
						this.targetRenderSystem.UnbindGpuProgram( GpuProgramType.Vertex );
					}
					// Set fixed-function vertex parameters
				}

				if ( passSurfaceAndLightParams )
				{
					// Set surface reflectance properties, only valid if lighting is enabled
					if ( pass.LightingEnabled )
					{
						this.targetRenderSystem.SetSurfaceParams( pass.Ambient,
																  pass.Diffuse,
																  pass.Specular,
																  pass.Emissive,
																  pass.Shininess,
																  pass.VertexColorTracking );
					}
					// #if NOT_IN_OGRE
					else
					{
						// even with lighting off, we need ambient set to white
						this.targetRenderSystem.SetSurfaceParams( ColorEx.White,
																  ColorEx.Black,
																  ColorEx.Black,
																  ColorEx.Black,
																  0,
																  TrackVertexColor.None );
					}
					// #endif
					// Dynamic lighting enabled?
					this.targetRenderSystem.LightingEnabled = pass.LightingEnabled;
				}

				// Using a fragment program?
				if ( pass.HasFragmentProgram )
				{
					this.targetRenderSystem.BindGpuProgram( pass.FragmentProgram.BindingDelegate );
					// bind parameters later since they can be per-object
				}
				else
				{
					// Unbind program?
					if ( this.targetRenderSystem.IsGpuProgramBound( GpuProgramType.Fragment ) )
					{
						this.targetRenderSystem.UnbindGpuProgram( GpuProgramType.Fragment );
					}
				}
				// Set fixed-function fragment settings

				//We need to set 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, they maybe accessed by gpu program via
				//"state.fog.XXX".

				// New fog params can either be from scene or from material

				// jsw - set the fog for both fixed function and fragment programs
				ColorEx newFogColor;
				FogMode newFogMode;
				float newFogDensity, newFogStart, newFogEnd;

				// does the pass want to override the fog mode?
				if ( pass.FogOverride )
				{
					// New fog params from material
					newFogMode = pass.FogMode;
					newFogColor = pass.FogColor;
					newFogDensity = pass.FogDensity;
					newFogStart = pass.FogStart;
					newFogEnd = pass.FogEnd;
				}
				else
				{
					// New fog params from scene
					newFogMode = this.fogMode;
					newFogColor = this.fogColor;
					newFogDensity = this.fogDensity;
					newFogStart = this.fogStart;
					newFogEnd = this.fogEnd;
				}

				// set fog params
                /*
				float fogScale = 1f;
				if ( newFogMode == FogMode.None )
				{
					fogScale = 0f;
				}
                 */

				// set fog using the render system
				this.targetRenderSystem.SetFog( newFogMode, newFogColor, newFogDensity, newFogStart, newFogEnd );

				// Tell params about ORIGINAL fog
				// Need to be able to override fixed function fog, but still have
				// original fog parameters available to a shader that chooses to use
				// TODO: autoParamDataSource.SetFog( fogMode, fogColor, fogDensity, fogStart, fogEnd );

				// The rest of the settings are the same no matter whether we use programs or not

				// Set scene blending
				this.targetRenderSystem.SetSceneBlending( pass.SourceBlendFactor, pass.DestinationBlendFactor );

				// TODO : Set point parameters
				//targetRenderSystem.SetPointParameters(
				//                                        pass.PointSize,
				//                                        pass.IsPointAttenuationEnabled,
				//                                        pass.PointAttenuationConstant,
				//                                        pass.PointAttenuationLinear,
				//                                        pass.PointAttenuationQuadratic,
				//                                        pass.PointMinSize,
				//                                        pass.PointMaxSize
				//                                        );

				//targetRenderSystem.PointSpritesEnabled = pass.PointSpritesEnabled;

				// TODO : Reset the shadow texture index for each pass
				//foreach ( TextureUnitState textureUnit in pass.TextureUnitStates )
				//{
				//}

				// set all required texture units for this pass, and disable ones not being used
				int numTextureUnits = this.targetRenderSystem.Capabilities.TextureUnitCount;
				if ( pass.HasFragmentProgram  && pass.FragmentProgram.IsSupported )
				{
					numTextureUnits = pass.FragmentProgram.SamplerCount;
				}
				else if ( Config.MaxTextureLayers < this.targetRenderSystem.Capabilities.TextureUnitCount )
				{
					numTextureUnits = Config.MaxTextureLayers;
				}

				for ( int i = 0; i < numTextureUnits; i++ )
				{
					if ( i < pass.TextureUnitStageCount )
					{
						TextureUnitState texUnit = pass.GetTextureUnitState( i );
					    targetRenderSystem.SetTextureUnitSettings( i, texUnit );
						//this.targetRenderSystem.SetTextureUnit( i, texUnit, !pass.HasFragmentProgram );
					}
					else
					{
						// disable this unit
						if ( !pass.HasFragmentProgram )
						{
							this.targetRenderSystem.DisableTextureUnit( i );
						}
					}
				}

                // Disable remaining texture units
                targetRenderSystem.DisableTextureUnitsFrom(pass.TextureUnitStageCount);

				// Depth Settings
				this.targetRenderSystem.DepthBufferWriteEnabled = pass.DepthWrite;
				this.targetRenderSystem.DepthBufferCheckEnabled = pass.DepthCheck;
				this.targetRenderSystem.DepthBufferFunction = pass.DepthFunction;
				this.targetRenderSystem.SetDepthBias(pass.DepthBiasConstant);

				// Aplha Reject Settings
				this.targetRenderSystem.SetAlphaRejectSettings( pass.AlphaRejectFunction, (byte)pass.AlphaRejectValue, pass.IsAlphaToCoverageEnabled );

				// Color Write
				// right now only using on/off, not per channel
				bool colWrite = pass.ColorWriteEnabled;
				this.targetRenderSystem.SetColorBufferWriteEnabled( colWrite, colWrite, colWrite, colWrite );

				// Culling Mode
				this.targetRenderSystem.CullingMode = pass.CullingMode;

				// Shading mode
                //this.targetRenderSystem.ShadingMode = pass.ShadingMode;

				// Polygon Mode
				this.targetRenderSystem.PolygonMode = pass.PolygonMode;

				// set pass number
				this.autoParamDataSource.PassNumber = pass.Index;
			}

			return pass;
		}
Example #4
0
		/// <summary>
		///		Internal method for turning a regular pass into a shadow receiver pass.
		/// </summary>
		/// <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.
		/// </remarks>
		/// <param name="pass"></param>
		/// <returns></returns>
		protected virtual Pass DeriveShadowReceiverPass( Pass pass )
		{
			if ( this.IsShadowTechniqueTextureBased )
			{
				Pass retPass;
				if ( pass.Parent.ShadowReceiverMaterial != null )
				{
					retPass = pass.Parent.ShadowReceiverMaterial.GetBestTechnique().GetPass( 0 );
				}
				else
				{
					retPass = ( this.shadowTextureCustomReceiverPass != null ? this.shadowTextureCustomReceiverPass : this.shadowReceiverPass );
				}

				// Does incoming pass have a custom shadow receiver program?
				if ( pass.ShadowReceiverVertexProgramName != "" )
				{
					retPass.SetVertexProgram( pass.ShadowReceiverVertexProgramName );
					GpuProgram prg = retPass.VertexProgram;
					// Load this program if not done already
					if ( !prg.IsLoaded )
					{
						prg.Load();
					}
					// Copy params
					retPass.VertexProgramParameters = pass.ShadowReceiverVertexProgramParameters;
					// Also have to hack the light autoparams, that is done later
				}
				else
				{
					if ( retPass == this.shadowTextureCustomReceiverPass )
					{
						if ( this.shadowTextureCustomReceiverPass.VertexProgramName != this.shadowTextureCustomReceiverVertexProgram )
						{
							this.shadowTextureCustomReceiverPass.SetVertexProgram( this.shadowTextureCustomReceiverVertexProgram );
							if ( retPass.HasVertexProgram )
							{
								retPass.VertexProgramParameters = this.shadowTextureCustomReceiverVPParams;
							}
						}
					}
					else
					{
						retPass.SetVertexProgram( "" );
					}
				}
				int keepTUCount;
				// If additive, need lighting parameters & standard programs
				if ( this.IsShadowTechniqueAdditive )
				{
					keepTUCount = 1;
					retPass.LightingEnabled = true;
					retPass.Ambient = pass.Ambient;
					retPass.SelfIllumination = pass.SelfIllumination;
					retPass.Diffuse = pass.Diffuse;
					retPass.Specular = pass.Specular;
					retPass.Shininess = pass.Shininess;
					retPass.SetRunOncePerLight( pass.IteratePerLight,
												pass.RunOnlyOncePerLightType,
												pass.OnlyLightType );
					// We need to keep alpha rejection settings
					retPass.SetAlphaRejectSettings( pass.AlphaRejectFunction, pass.AlphaRejectValue );
					// Copy texture state, shift up one since 0 is shadow texture
					int origPassTUCount = pass.TextureUnitStageCount;
					for ( int t = 0; t < origPassTUCount; ++t )
					{
						int targetIndex = t + 1;
						TextureUnitState tex = ( retPass.TextureUnitStageCount <= targetIndex
													 ?
														 retPass.CreateTextureUnitState()
													 :
														 retPass.GetTextureUnitState( targetIndex ) );
						pass.GetTextureUnitState( t ).CopyTo( tex );
						// If programmable, have to adjust the texcoord sets too
						// D3D insists that texcoordsets match tex unit in programmable mode
						if ( retPass.HasVertexProgram )
							tex.TextureCoordSet = targetIndex;
					}
					keepTUCount = origPassTUCount + 1;
				}
				else
				{
					// need to keep spotlight fade etc
					keepTUCount = retPass.TextureUnitStageCount;
				}

				// Will also need fragment programs since this is a complex light setup
				if ( pass.ShadowReceiverFragmentProgramName != "" )
				{
					// Have to merge the shadow receiver vertex program in
					retPass.SetFragmentProgram( pass.ShadowReceiverFragmentProgramName );
					GpuProgram prg = retPass.FragmentProgram;
					// Load this program if not done already
					if ( !prg.IsLoaded )
					{
						prg.Load();
					}
					// Copy params
					retPass.FragmentProgramParameters = pass.ShadowReceiverFragmentProgramParameters;
					// 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.VertexProgramName );
						prg = retPass.VertexProgram;
						// Load this program if required
						if ( !prg.IsLoaded )
						{
							prg.Load();
						}
						// Copy params
						retPass.VertexProgramParameters = pass.VertexProgramParameters;
					}
				}
				else
				{
					// Reset any merged fragment programs from last time
					if ( retPass == this.shadowTextureCustomReceiverPass )
					{
						// reset fp?
						if ( retPass.FragmentProgramName != this.shadowTextureCustomReceiverFragmentProgram )
						{
							retPass.SetFragmentProgram( this.shadowTextureCustomReceiverFragmentProgram );
							if ( retPass.HasFragmentProgram )
							{
								retPass.FragmentProgramParameters = this.shadowTextureCustomReceiverFPParams;
							}
						}
					}
					else
					{
						// Standard shadow receiver pass, reset to no fp
						retPass.SetFragmentProgram( "" );
					}
				}

				// Remove any extra texture units
				while ( retPass.TextureUnitStageCount > keepTUCount )
				{
					retPass.RemoveTextureUnitState( keepTUCount );
				}
				retPass.Load();
				return retPass;
			}
			else
			{
				return pass;
			}
		}
Example #5
0
		/// <summary>
		///		Internal method for turning a regular pass into a shadow caster pass.
		/// </summary>
		/// <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.
		/// </remarks>
		/// <param name="pass"></param>
		/// <returns></returns>
		protected virtual Pass DeriveShadowCasterPass( Pass pass )
		{
			if ( this.IsShadowTechniqueTextureBased )
			{
				Pass retPass;
				if ( pass.Parent.ShadowCasterMaterial != null )
				{
					retPass = pass.Parent.ShadowCasterMaterial.GetBestTechnique().GetPass( 0 );
				}
				else
				{
					retPass = ( this.shadowTextureCustomCasterPass != null ? this.shadowTextureCustomCasterPass : this.shadowCasterPlainBlackPass );
				}

				// Special case alpha-blended passes
				if ( ( pass.SourceBlendFactor == SceneBlendFactor.SourceAlpha &&
					   pass.DestinationBlendFactor == SceneBlendFactor.OneMinusSourceAlpha )
					|| pass.AlphaRejectFunction != CompareFunction.AlwaysPass )
				{
					// Alpha blended passes must retain their transparency
					retPass.SetAlphaRejectSettings( pass.AlphaRejectFunction, pass.AlphaRejectValue );
					retPass.SetSceneBlending( pass.SourceBlendFactor, pass.DestinationBlendFactor );
					retPass.Parent.Parent.TransparencyCastsShadows = true;

					// So we allow the texture units, but override the color functions
					// Copy texture state, shift up one since 0 is shadow texture
					int origPassTUCount = pass.TextureUnitStageCount;
					for ( int t = 0; t < origPassTUCount; ++t )
					{
						TextureUnitState tex;
						if ( retPass.TextureUnitStageCount <= t )
						{
							tex = retPass.CreateTextureUnitState();
						}
						else
						{
							tex = retPass.GetTextureUnitState( t );
						}
						// copy base state
						pass.GetTextureUnitState( t ).CopyTo( tex );
						// override colour function
						tex.SetColorOperationEx( LayerBlendOperationEx.Source1, LayerBlendSource.Manual, LayerBlendSource.Current, this.IsShadowTechniqueAdditive ? ColorEx.Black : shadowColor );
					}
					// Remove any extras
					while ( retPass.TextureUnitStageCount > origPassTUCount )
					{
						retPass.RemoveTextureUnitState( origPassTUCount );
					}
				}
				else
				{
					// reset
					retPass.SetSceneBlending( SceneBlendType.Replace );
					retPass.AlphaRejectFunction = CompareFunction.AlwaysPass;
					while ( retPass.TextureUnitStageCount > 0 )
					{
						retPass.RemoveTextureUnitState( 0 );
					}
				}

				// Propogate culling modes
				retPass.CullingMode = pass.CullingMode;
				retPass.ManualCullingMode = pass.ManualCullingMode;

				// Does incoming pass have a custom shadow caster program?
				if ( pass.ShadowCasterVertexProgramName != "" )
				{
					retPass.SetVertexProgram( pass.ShadowCasterVertexProgramName, false );
					GpuProgram prg = retPass.VertexProgram;
					// Load this program if not done already
					if ( !prg.IsLoaded )
					{
						prg.Load();
					}
					// Copy params
					retPass.VertexProgramParameters = pass.ShadowCasterVertexProgramParameters;
					// Also have to hack the light autoparams, that is done later
				}
				else
				{
					// reset vp?
					if ( retPass == this.shadowTextureCustomCasterPass )
					{
						if ( retPass.VertexProgramName != this.shadowTextureCustomCasterVertexProgram )
						{
							this.shadowTextureCustomCasterPass.SetVertexProgram( this.shadowTextureCustomCasterVertexProgram );
							if ( retPass.HasVertexProgram )
							{
								retPass.VertexProgramParameters = this.shadowTextureCustomCasterVPParams;
							}
						}
					}
					else
					{
						// Standard shadow caster pass, reset to no vp
						retPass.SetVertexProgram( "" );
					}
				}

				return retPass;
			}
			else
			{
				return pass;
			}
		}
Example #6
0
		/// <summary>Internal method for setting up the renderstate for a rendering pass.</summary>
		/// <param name="pass">The Pass details to set.</param>
		/// <param name="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.
		/// </param>
		/// <param name="shadowDerivation">
		///    If false, disables the derivation of shadow passes from original passes
		/// </param>
		/// <returns>
		///		A Pass object that was used instead of the one passed in, can
		///		happen when rendering shadow passes
		///	</returns>
		public virtual Pass SetPass( Pass pass, bool evenIfSuppressed, bool shadowDerivation )
		{
			//If using late material resolving, swap now.
			if ( IsLateMaterialResolving )
			{
				Technique lateTech = pass.Parent.Parent.GetBestTechnique();
				if ( lateTech.PassCount > pass.Index )
				{
					pass = lateTech.GetPass( pass.Index );
				}
				//Should we warn or throw an exception if an illegal state was achieved?
			}

			if ( !this.suppressRenderStateChanges || evenIfSuppressed )
			{
				if ( this.illuminationStage == IlluminationRenderStage.RenderToTexture && shadowDerivation )
				{
					// Derive a special shadow caster pass from this one
					pass = DeriveShadowCasterPass( pass );
				}
				else if ( this.illuminationStage == IlluminationRenderStage.RenderReceiverPass )
				{
					pass = DeriveShadowReceiverPass( pass );
				}

				// Tell params about current pass
				this.autoParamDataSource.CurrentPass = pass;

				bool passSurfaceAndLightParams = true;
				bool passFogParams = true;

				if ( pass.HasVertexProgram )
				{
					this.targetRenderSystem.BindGpuProgram( pass.VertexProgram.BindingDelegate );
					// bind parameters later 
					// does the vertex program want surface and light params passed to rendersystem?
					passSurfaceAndLightParams = pass.VertexProgram.PassSurfaceAndLightStates;
				}
				else
				{
					// Unbind program?
					if ( this.targetRenderSystem.IsGpuProgramBound( GpuProgramType.Vertex ) )
					{
						this.targetRenderSystem.UnbindGpuProgram( GpuProgramType.Vertex );
					}
					// Set fixed-function vertex parameters
				}

				if ( pass.HasGeometryProgram )
				{
					this.targetRenderSystem.BindGpuProgram( pass.GeometryProgram.BindingDelegate );
					// bind parameters later 
				}
				else
				{
					// Unbind program?
					if ( this.targetRenderSystem.IsGpuProgramBound( GpuProgramType.Geometry ) )
					{
						this.targetRenderSystem.UnbindGpuProgram( GpuProgramType.Geometry );
					}
					// Set fixed-function vertex parameters
				}

				if ( passSurfaceAndLightParams )
				{
					// Set surface reflectance properties, only valid if lighting is enabled
					if ( pass.LightingEnabled )
					{
						this.targetRenderSystem.SetSurfaceParams( pass.Ambient, pass.Diffuse, pass.Specular, pass.SelfIllumination,
																  pass.Shininess, pass.VertexColorTracking );
					}
						// #if NOT_IN_OGRE
					else
					{
						// even with lighting off, we need ambient set to white
						this.targetRenderSystem.SetSurfaceParams( ColorEx.White, ColorEx.Black, ColorEx.Black, ColorEx.Black, 0,
																  TrackVertexColor.None );
					}
					// #endif

					// Dynamic lighting enabled?
					this.targetRenderSystem.LightingEnabled = pass.LightingEnabled;
				}

				// Using a fragment program?
				if ( pass.HasFragmentProgram )
				{
					this.targetRenderSystem.BindGpuProgram( pass.FragmentProgram.BindingDelegate );
					// bind parameters later 
					passFogParams = pass.FragmentProgram.PassFogStates;
				}
				else
				{
					// Unbind program?
					if ( this.targetRenderSystem.IsGpuProgramBound( GpuProgramType.Fragment ) )
					{
						this.targetRenderSystem.UnbindGpuProgram( GpuProgramType.Fragment );
					}

					// Set fixed-function fragment settings
				}

				if ( passFogParams )
				{
					// New fog params can either be from scene or from material
					FogMode newFogMode;
					ColorEx newFogColour;
					Real newFogStart, newFogEnd, newFogDensity;
					if ( pass.FogOverride )
					{
						// New fog params from material
						newFogMode = pass.FogMode;
						newFogColour = pass.FogColor;
						newFogStart = pass.FogStart;
						newFogEnd = pass.FogEnd;
						newFogDensity = pass.FogDensity;
					}
					else
					{
						// New fog params from scene
						newFogMode = this.fogMode;
						newFogColour = this.fogColor;
						newFogStart = this.fogStart;
						newFogEnd = this.fogEnd;
						newFogDensity = this.fogDensity;
					}

					/* 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".
					*/
					this.targetRenderSystem.SetFog( newFogMode, newFogColour, newFogDensity, newFogStart, newFogEnd );
				}

				// Tell params about ORIGINAL fog
				// Need to be able to override fixed function fog, but still have
				// original fog parameters available to a shader that chooses to use
				this.autoParamDataSource.SetFog( this.fogMode, this.fogColor, this.fogDensity, this.fogStart, this.fogEnd );

				// The rest of the settings are the same no matter whether we use programs or not

				// Set scene blending
				if ( pass.HasSeparateSceneBlending )
				{
					this.targetRenderSystem.SetSeparateSceneBlending( pass.SourceBlendFactor, pass.DestinationBlendFactor,
																	  pass.SourceBlendFactorAlpha, pass.DestinationBlendFactorAlpha,
																	  pass.SceneBlendingOperation,
																	  pass.HasSeparateSceneBlendingOperations
																		? pass.SceneBlendingOperation
																		: pass.SceneBlendingOperationAlpha );
				}
				else
				{
					if ( pass.HasSeparateSceneBlendingOperations )
					{
						this.targetRenderSystem.SetSeparateSceneBlending( pass.SourceBlendFactor, pass.DestinationBlendFactor,
																		  pass.SourceBlendFactor, pass.DestinationBlendFactor,
																		  pass.SceneBlendingOperation, pass.SceneBlendingOperationAlpha );
					}
					else
					{
						this.targetRenderSystem.SetSceneBlending( pass.SourceBlendFactor, pass.DestinationBlendFactor,
																  pass.SceneBlendingOperation );
					}
				}

				//TODO Set point parameters
				//this.targetRenderSystem.SetPointParameters(
				//    pass.PointSize,
				//    pass.IsPointAttenuationEnabled,
				//    pass.PointAttenuationConstant,
				//    pass.PointAttenuationLinear,
				//    pass.PointAttenuationQuadratic,
				//    pass.PointMinSize,
				//    pass.PointMaxSize
				//    );

				if ( this.targetRenderSystem.Capabilities.HasCapability( Capabilities.PointSprites ) )
				{
					this.targetRenderSystem.PointSpritesEnabled = pass.PointSpritesEnabled;
				}

				//targetRenderSystem.PointSpritesEnabled = pass.PointSpritesEnabled;

				// TODO : Reset the shadow texture index for each pass
				//foreach ( TextureUnitState textureUnit in pass.TextureUnitStates )
				//{
				//}

				// set all required texture units for this pass, and disable ones not being used
				var numTextureUnits = this.targetRenderSystem.Capabilities.TextureUnitCount;
				if ( pass.HasFragmentProgram && pass.FragmentProgram.IsSupported )
				{
					// Axiom: This effectivley breaks GLSL.
					// besides this routine aint existing (anymore?) in 1.7.2
					// an upgrade of the scenemanager is recommended
					//numTextureUnits = pass.FragmentProgram.SamplerCount;
				}
				else if ( Config.MaxTextureLayers < this.targetRenderSystem.Capabilities.TextureUnitCount )
				{
					numTextureUnits = Config.MaxTextureLayers;
				}

				for ( var i = 0; i < numTextureUnits; i++ )
				{
					if ( i < pass.TextureUnitStatesCount )
					{
						var texUnit = pass.GetTextureUnitState( i );
						this.targetRenderSystem.SetTextureUnitSettings( i, texUnit );
						//this.targetRenderSystem.SetTextureUnit( i, texUnit, !pass.HasFragmentProgram );
					}
					else
					{
						// disable this unit
						if ( !pass.HasFragmentProgram )
						{
							this.targetRenderSystem.DisableTextureUnit( i );
						}
					}
				}

				// Disable remaining texture units
				this.targetRenderSystem.DisableTextureUnitsFrom( pass.TextureUnitStatesCount );

				// Depth Settings
				this.targetRenderSystem.DepthBufferWriteEnabled = pass.DepthWrite;
				this.targetRenderSystem.DepthBufferCheckEnabled = pass.DepthCheck;
				this.targetRenderSystem.DepthBufferFunction = pass.DepthFunction;
				this.targetRenderSystem.SetDepthBias( pass.DepthBiasConstant );

				// Aplha Reject Settings
				this.targetRenderSystem.SetAlphaRejectSettings( pass.AlphaRejectFunction, (byte)pass.AlphaRejectValue,
																pass.IsAlphaToCoverageEnabled );

				// Color Write
				// right now only using on/off, not per channel
				var colWrite = pass.ColorWriteEnabled;
				this.targetRenderSystem.SetColorBufferWriteEnabled( colWrite, colWrite, colWrite, colWrite );

				// Culling Mode
				this.targetRenderSystem.CullingMode = pass.CullingMode;

				// Shading mode
				//this.targetRenderSystem.ShadingMode = pass.ShadingMode;

				// Polygon Mode
				this.targetRenderSystem.PolygonMode = pass.PolygonMode;

				// set pass number
				this.autoParamDataSource.PassNumber = pass.Index;
			}

			return pass;
		}
        /// <summary>Internal method for setting up the renderstate for a rendering pass.</summary>
        /// <param name="pass">The Pass details to set.</param>
        /// <param name="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.
        /// </param>
        /// <param name="shadowDerivation">
        ///    If false, disables the derivation of shadow passes from original passes
        /// </param>
        /// <returns>
        ///		A Pass object that was used instead of the one passed in, can
        ///		happen when rendering shadow passes
        ///	</returns>
        protected virtual Pass SetPass(Pass pass, bool evenIfSuppressed, bool shadowDerivation)
        {
            setPassMeter.Enter();

            targetRenderSystem.BeginProfileEvent(ColorEx.Green, "SetPass: Material = " + pass.Parent.Parent.Name);
            totalSetPassCalls++;
            if (!suppressRenderStateChanges || evenIfSuppressed) {
                if (illuminationStage == IlluminationRenderStage.RenderToTexture && shadowDerivation) {
                        // Derive a special shadow caster pass from this one
                    pass = DeriveShadowCasterPass(pass);
                } else if (illuminationStage == IlluminationRenderStage.RenderModulativePass) {
                    pass = DeriveShadowReceiverPass(pass);
                }

                // Tell params about current pass
                autoParamDataSource.CurrentPass = pass;

                bool passSurfaceAndLightParams = true;

                //setPassShadersMeter.Enter();
                if (pass.HasVertexProgram) {
                    targetRenderSystem.BindGpuProgram(pass.VertexProgram.BindingDelegate);
                    // bind parameters later since they can be per-object
                    // does the vertex program want surface and light params passed to rendersystem?
                    passSurfaceAndLightParams = pass.VertexProgram.PassSurfaceAndLightStates;
                } else {
                    // Unbind program?
                    if (targetRenderSystem.IsGpuProgramBound(GpuProgramType.Vertex)) {
                        targetRenderSystem.UnbindGpuProgram(GpuProgramType.Vertex);
                    }
                    // Set fixed-function vertex parameters
                }

                // Using a fragment program?
                if (pass.HasFragmentProgram)
                {
                    targetRenderSystem.BindGpuProgram(pass.FragmentProgram.BindingDelegate);
                    // bind parameters later since they can be per-object
                }
                else
                {
                    // Unbind program?
                    if (targetRenderSystem.IsGpuProgramBound(GpuProgramType.Fragment))
                    {
                        targetRenderSystem.UnbindGpuProgram(GpuProgramType.Fragment);
                    }
                }
                //setPassShadersMeter.Exit();

                //setPassLightingFogMeter.Enter();

                if (passSurfaceAndLightParams) {
                    // Set surface reflectance properties, only valid if lighting is enabled
                    if (pass.LightingEnabled) {
                        targetRenderSystem.SetSurfaceParams(pass.Ambient,
                                                            pass.Diffuse,
                                                            pass.Specular,
                                                            pass.Emissive,
                                                            pass.Shininess,
                                                            pass.VertexColorTracking);
            // #if NOT
                    } else {
                        // even with lighting off, we need ambient set to white
                        targetRenderSystem.SetSurfaceParams(ColorEx.White,
                                                            ColorEx.Black,
                                                            ColorEx.Black,
                                                            ColorEx.Black,
                                                            0,
                                                            TrackVertexColor.None);
            // #endif
                    }
                    // Dynamic lighting enabled?
                    targetRenderSystem.LightingEnabled = pass.LightingEnabled;
                }

                // Set fixed-function fragment settings

                // Fog (assumes we want pixel fog which is the usual)
                // New fog params can either be from scene or from material

                // jsw - set the fog for both fixed function and fragment programs
                ColorEx newFogColor;
                FogMode newFogMode;
                float newFogDensity, newFogStart, newFogEnd;

                // does the pass want to override the fog mode?
                if (pass.FogOverride) {
                    // New fog params from material
                    newFogMode = pass.FogMode;
                    newFogColor = pass.FogColor;
                    newFogDensity = pass.FogDensity;
                    newFogStart = pass.FogStart;
                    newFogEnd = pass.FogEnd;
                } else {
                    // New fog params from scene
                    newFogMode = fogMode;
                    newFogColor = fogColor;
                    newFogDensity = fogDensity;
                    newFogStart = fogStart;
                    newFogEnd = fogEnd;
                }

                // set fog params
                float fogScale = 1f;
                if (newFogMode == FogMode.None)
                    fogScale = 0f;

                // set fog using the render system
                targetRenderSystem.SetFog(newFogMode, newFogColor, newFogDensity, newFogStart, newFogEnd);

                // Tell params about ORIGINAL fog Need to be able to
                // override fixed function fog, but still have
                // original fog parameters available to a shader than
                // chooses to use
                autoParamDataSource.SetFog(fogMode, fogColor, fogStart, fogEnd, fogScale);

                //setPassLightingFogMeter.Exit();

                //setPassEarlyCommonMeter.Enter();

                // The rest of the settings are the same no matter whether we use programs or not

                // Set scene blending
                targetRenderSystem.SetSceneBlending(pass.SourceBlendFactor, pass.DestBlendFactor);

                // Set point parameters
                targetRenderSystem.SetPointParameters(pass.PointSize,
                                                      pass.PointAttenuationEnabled,
                                                      pass.PointAttenuationConstant,
                                                      pass.PointAttenuationLinear,
                                                      pass.PointAttenuationQuadratic,
                                                      pass.PointMinSize,
                                                      pass.PointMaxSize);

                targetRenderSystem.PointSpritesEnabled = pass.PointSpritesEnabled;

                //setPassEarlyCommonMeter.Exit();
                // Texture unit settings

                //setPassTexturesMeter.Enter();
                // set all required texture units for this pass, and disable ones not being used
                int numTextureUnits;
                if (pass.HasFragmentProgram) {
                    numTextureUnits = pass.FragmentProgram.SamplerCount;
                } else {
                    numTextureUnits = targetRenderSystem.Caps.TextureUnitCount;
                }

                int shadowTexIndex = pass.StartLight;
                for (int i = 0; i < numTextureUnits; i++) {
                    if (i < pass.NumTextureUnitStages)
                    {
                        TextureUnitState texUnit = pass.GetTextureUnitState(i);

                        // If we couldn't load the texture, skip it
                        if (texUnit.Blank)
                            continue;

                        if (pass.RunOncePerLight &&
                            IsShadowTechniqueTextureBased &&
                            texUnit.ContentType == TextureContentType.Shadow)
                        {
                            // Need to bind the correct shadow texture, based on the start light
                            // Even though the light list can change per object, our restrictions
                            // say that when texture shadows are enabled, the lights up to the
                            // number of texture shadows will be fixed for all objects
                            // to match the shadow textures that have been generated
                            // see ShadowListener::sortLightsAffectingFrustum and
                            // MovableObject::Listener::objectQueryLights
                            // Note that light iteration throws the indexes out so we don't bind here
                            // if that's the case, we have to bind when lights are iterated
                            // in renderSingleObject
                            Texture shadowTex;
                            if (shadowTexIndex < shadowTextures.Count)
                            {
                                shadowTex = shadowTextures[shadowTexIndex];
                                // Hook up projection frustum
                                Camera cam = shadowTex.GetBuffer().GetRenderTarget().GetViewport(0).Camera;
                                // Only set fixed-function projection if no vertex program
                                if (!pass.HasVertexProgram)
                                    texUnit.SetProjectiveTexturing(true, cam);
                                autoParamDataSource.SetTextureProjector(cam, shadowTexIndex);
                            }
                            else
                            {
                                // Use fallback 'null' shadow texture
                                // no projection since all uniform colour anyway
                                shadowTex = nullShadowTexture;
                                texUnit.SetProjectiveTexturing(false, null);
                                autoParamDataSource.SetTextureProjector(null, shadowTexIndex);

                            }
                            texUnit.SetTexturePtr(shadowTex);
                            shadowTexIndex++;
                        }
                        targetRenderSystem.SetTextureUnit(i, texUnit, !pass.HasFragmentProgram);
                    }
                    else
                    {
                        if (pass.HasFragmentProgram)
                        {

                            targetRenderSystem.SetTextureCoordSet(i, i);
                        }
                        else
                        {
                            // Disable the ones that the pass doesn't use.
                            targetRenderSystem.DisableTextureUnit(i);
                        }
                    }
                }

                //setPassTexturesMeter.Exit();

                //setPassLateCommonMeter.Enter();
                // Set up non-texture related material settings
                // Depth Settings
                targetRenderSystem.DepthFunction = pass.DepthFunction;
                targetRenderSystem.DepthCheck = pass.DepthCheck;
                targetRenderSystem.DepthWrite = pass.DepthWrite;
                targetRenderSystem.SetDepthBias(pass.DepthBiasConstant, pass.DepthBiasSlopeScale);

                // Alpha-reject settings
                targetRenderSystem.SetAlphaRejectSettings(pass.AlphaRejectFunction, (byte)pass.AlphaRejectValue);

                // Color Write
                // right now only using on/off, not per channel
                bool colWrite = pass.ColorWrite;
                targetRenderSystem.SetColorBufferWriteEnabled(colWrite, colWrite, colWrite, colWrite);

                // Culling Mode
                if (IsShadowTechniqueTextureBased &&
                    illuminationStage == IlluminationRenderStage.RenderToTexture &&
                    shadowCasterRenderBackFaces &&
                    pass.CullMode == CullingMode.Clockwise) {
                    // render back faces into shadow caster, can help with depth comparison
                    targetRenderSystem.CullingMode = CullingMode.CounterClockwise;
                }
                else
                    targetRenderSystem.CullingMode = pass.CullMode;

                // Shading mode
                targetRenderSystem.ShadingMode = pass.ShadingMode;

                // Polygon mode
                targetRenderSystem.RasterizationMode = pass.SceneDetail;

                //setPassLateCommonMeter.Exit();

                // set pass number
                autoParamDataSource.PassNumber = pass.Index;
            }

            targetRenderSystem.EndProfileEvent();
            setPassMeter.Exit();
            return pass;
        }
        /// <summary>
        ///		Internal utility method for rendering a single object.
        /// </summary>
        /// <param name="renderable">The renderable to issue to the pipeline.</param>
        /// <param name="pass">The pass which is being used.</param>
        /// <param name="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>
        /// <param name="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.</param>
        protected virtual void RenderSingleObject(IRenderable renderable, Pass pass, 
			bool doLightIteration, List<Light> manualLightList)
        {
            targetRenderSystem.BeginProfileEvent(ColorEx.Red, "RenderSingleObject: Material = " + renderable.Material.Name);

            ushort numMatrices = 0;

            // grab the current scene detail level
            SceneDetailLevel camDetailLevel = cameraInProgress.SceneDetail;

            // 			// update auto params if this is a programmable pass
            // 			if(pass.IsProgrammable) {
            // 				autoParamDataSource.Renderable = renderable;
            // 				pass.UpdateAutoParamsNoLights(autoParamDataSource);
            // 			}

            // get the world matrices and the count
            renderable.GetWorldTransforms(xform);
            numMatrices = renderable.NumWorldTransforms;

            // set the world matrices in the render system
            if(numMatrices > 1) {
                targetRenderSystem.SetWorldMatrices(xform, numMatrices);
            }
            else {
                targetRenderSystem.WorldMatrix = xform[0];
            }

            // issue view/projection changes (if any)
            UseRenderableViewProjection(renderable);

            if (!suppressRenderStateChanges) {
                bool passSurfaceAndLightParams = true;
                if (pass.IsProgrammable) {
                    // Tell auto params object about the renderable change
                    autoParamDataSource.Renderable = renderable;
                    // Tell auto params object about the world matrices, eliminated query from renderable again
                    autoParamDataSource.SetWorldMatrices(xform, numMatrices);
                    pass.UpdateAutoParamsNoLights(autoParamDataSource);
                    if (pass.HasVertexProgram)
                        passSurfaceAndLightParams = pass.VertexProgram.PassSurfaceAndLightStates;
                }

                // issue texture units that depend on updated view matrix
                // reflective env mapping is one case
                for(int i = 0; i < pass.NumTextureUnitStages; i++) {
                    TextureUnitState texUnit = pass.GetTextureUnitState(i);

                    if(texUnit.HasViewRelativeTexCoordGen) {
                        targetRenderSystem.SetTextureUnit(i, texUnit, !pass.HasFragmentProgram);
                    }
                }

                // Normalize normals
                bool thisNormalize = renderable.NormalizeNormals;

                if(thisNormalize != normalizeNormals) {
                    targetRenderSystem.NormalizeNormals = thisNormalize;
                    normalizeNormals = thisNormalize;
                }

                // Set up the solid / wireframe override
                SceneDetailLevel requestedDetail = renderable.RenderDetail;
                if (requestedDetail != lastDetailLevel || requestedDetail != camDetailLevel) {
                    if (requestedDetail > camDetailLevel) {
                        // only downgrade detail; if cam says wireframe we don't go up to solid
                        requestedDetail = camDetailLevel;
                    }
                    targetRenderSystem.RasterizationMode = requestedDetail;
                    lastDetailLevel = requestedDetail;

                }

                // TODO: Add ClipPlanes to RenderSystem.cs
                //targetRenderSystem.ClipPlanes = renderable.ClipPlanes;

                // get the renderables render operation
                renderable.GetRenderOperation(op);
                // TODO: Add srcRenderable to RenderOperation.cs
                //op.srcRenderable = renderable;

                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
                    doLightMeter.Enter();
                    if (MeterManager.Collecting) {
                        string s = string.Format("Rendering material '{0}'", renderable.Material.Name);
                        if (renderable is SubEntity) {
                            SubEntity subEntity = (SubEntity)renderable;
                            s += string.Format(", SubMesh '{0}', Entity '{1}'", subEntity.SubMesh.Name, subEntity.Parent.Name);
                        }
                        MeterManager.AddInfoEvent(s);
                    }

                    List<Light> rendLightList = renderable.Lights;
                    bool iteratePerLight = pass.RunOncePerLight;
                    int startLight = pass.StartLight;
                    int lightsLeft = iteratePerLight ? rendLightList.Count - startLight : 1;
                    List<Light> lightListToUse = null;
                    int lightIndex = startLight;

                    while (lightsLeft > 0) {
                        // determine light list to use
                        if(iteratePerLight) {
                            localLightList.Clear();
                            int lightsPerIteration = pass.LightsPerIteration;
                            int numShadowTextureLights = 0;
                            int lightsConsidered = 0;
                            for (int i=0; i<lightsPerIteration && lightIndex < rendLightList.Count; i++,lightIndex++,lightsLeft--) {
                                // check whether we need to filter this one out
                                lightsConsidered++;
                                if(pass.RunOnlyForOneLightType && pass.OnlyLightType != rendLightList[lightIndex].Type)
                                    // skip this one
                                    continue;
                                localLightList.Add(rendLightList[lightIndex]);
                                // potentially need to update content_type shadow texunit
                                // corresponding to this light
                                if (IsShadowTechniqueTextureBased && lightIndex < shadowTextures.Count) {
                                    // link the numShadowTextureLights'th shadow texture unit
                                    int tuindex = pass.GetTextureUnitWithContentTypeIndex(
                                        TextureContentType.Shadow, numShadowTextureLights);
                                    if (tuindex < pass.NumTextureUnitStages) {
                                        TextureUnitState tu = pass.GetTextureUnitState(tuindex);
                                        tu.SetTexturePtr(shadowTextures[lightIndex]);
                                        Camera cam = shadowTextures[lightIndex].GetBuffer().GetRenderTarget().GetViewport(0).Camera;
                                        if (!pass.HasVertexProgram)
                                            tu.SetProjectiveTexturing(true, cam);
                                        autoParamDataSource.SetTextureProjector(cam, numShadowTextureLights);
                                        ++numShadowTextureLights;
                                        // Have to set TU on rendersystem right now, although
                                        // autoparams will be set later
                                        targetRenderSystem.SetTextureUnit(tuindex, tu, !pass.HasFragmentProgram);
                                    }
                                }
                            }
                            // Did we run out of lights before slots? e.g. 5 lights, 2 per iteration
                            if (lightsPerIteration != lightsConsidered)
                                lightsLeft = 0;
                            lightListToUse = localLightList;
                        }
                        else {
                            if (startLight != 0) {
                                if (startLight >= rendLightList.Count) {
                                    lightsLeft = 0;
                                    break;
                                }
                                else {
                                    localLightList.Clear();
                                    for (int i=startLight; i<rendLightList.Count; i++)
                                        localLightList.Add(rendLightList[i]);
                                    lightListToUse = localLightList;
                                }
                            }
                            else
                                // use complete light list
                                lightListToUse = rendLightList;
                            lightsLeft = 0;
                        }

                        if(pass.IsProgrammable) {
                            // Update any automatic gpu params for lights
                            // Other bits of information will have to be looked up
                            updateAutoParmsMeter.Enter();
                            autoParamDataSource.SetCurrentLightList(lightListToUse);
                            pass.UpdateAutoParamsLightsOnly(autoParamDataSource);
                            updateAutoParmsMeter.Exit();

                            // note: parameters must be bound after auto params are updated
                            setGpuParmsMeter.Enter();
                            if(pass.HasVertexProgram) {
                                if (MeterManager.Collecting)
                                    MeterManager.AddInfoEvent("Vertex Program " + pass.VertexProgramName);
                                targetRenderSystem.BindGpuProgramParameters(GpuProgramType.Vertex, pass.VertexProgramParameters);
                            }
                            if(pass.HasFragmentProgram) {
                                if (MeterManager.Collecting)
                                    MeterManager.AddInfoEvent("Fragment Program " + pass.FragmentProgramName);
                                targetRenderSystem.BindGpuProgramParameters(GpuProgramType.Fragment, pass.FragmentProgramParameters);
                            }
                            setGpuParmsMeter.Exit();
                        }

                        // Do we need to update light states?
                        // Only do this if fixed-function vertex lighting applies
                        if(pass.LightingEnabled && passSurfaceAndLightParams) {
                            //useLightsMeter.Enter();
                            targetRenderSystem.UseLights(lightListToUse, pass.MaxLights);
                            //useLightsMeter.Exit();
                        }
                        // issue the render op
                        renderOpMeter.Enter();
                        targetRenderSystem.Render(op);
                        renderOpMeter.Exit();
                    } // iterate per light
                    doLightMeter.Exit();
                }
                else {
                    // do we need to update GPU program parameters?
                    if(pass.IsProgrammable) {
                        // do we have a manual light list
                        if(manualLightList != null) {
                            // Update any automatic gpu params for lights
                            // Other bits of information will have to be looked up
                            autoParamDataSource.SetCurrentLightList(manualLightList);
                            pass.UpdateAutoParamsLightsOnly(autoParamDataSource);
                        }

                        // note: parameters must be bound after auto params are updated
                        if(pass.HasVertexProgram) {
                            targetRenderSystem.BindGpuProgramParameters(GpuProgramType.Vertex, pass.VertexProgramParameters);
                        }

                        if(pass.HasFragmentProgram) {
                             targetRenderSystem.BindGpuProgramParameters(GpuProgramType.Fragment, pass.FragmentProgramParameters);
                        }
                    }

                    // Use manual lights if present, and not using vertex programs
                    if(manualLightList != null && pass.LightingEnabled && passSurfaceAndLightParams) {
                        targetRenderSystem.UseLights(manualLightList, pass.MaxLights);
                    }

                    // issue the render op
                    renderOpMeter.Enter();
                    targetRenderSystem.Render(op);
                    renderOpMeter.Exit();
                }
            }
            else { // suppressRenderStateChanges
                // Just render
                renderOpMeter.Enter();
                targetRenderSystem.Render(op);
                renderOpMeter.Exit();
            }

            // Reset view / projection changes if any
            ResetViewProjMode();

            targetRenderSystem.EndProfileEvent();
        }
        /// <summary>
        ///		Internal method for turning a regular pass into a shadow receiver pass.
        /// </summary>
        /// <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. 
        /// </remarks>
        /// <param name="pass"></param>
        /// <returns></returns>
        protected virtual Pass DeriveShadowReceiverPass(Pass pass)
        {
            if (IsShadowTechniqueTextureBased) {
                Pass retPass = (shadowTextureCustomReceiverPass != null ?
                                shadowTextureCustomReceiverPass : shadowReceiverPass);
                // Does incoming pass have a custom shadow receiver program?
                if (pass.ShadowReceiverVertexProgramName != "") {
                    retPass.SetVertexProgram(pass.ShadowReceiverVertexProgramName);
                    GpuProgram prg = retPass.VertexProgram;
                    // Load this program if not done already
                    if (!prg.IsLoaded)
                        prg.Load();
                    // Copy params
                    retPass.VertexProgramParameters = pass.ShadowReceiverVertexProgramParameters;
                    // Also have to hack the light autoparams, that is done later
                }
                else {
                    if (retPass == shadowTextureCustomReceiverPass) {
                        if (shadowTextureCustomReceiverPass.VertexProgramName !=
                            shadowTextureCustomReceiverVertexProgram) {
                            shadowTextureCustomReceiverPass.SetVertexProgram(shadowTextureCustomReceiverVertexProgram);
                            if (retPass.HasVertexProgram)
                                retPass.VertexProgramParameters = shadowTextureCustomReceiverVPParams;
                        }
                    }
                    else
                        retPass.SetVertexProgram("");
                }
                int keepTUCount;
                // If additive, need lighting parameters & standard programs
                if (IsShadowTechniqueAdditive) {
                    keepTUCount = 1;
                    retPass.LightingEnabled = true;
                    retPass.Ambient = pass.Ambient;
                    retPass.Diffuse = pass.Diffuse;
                    retPass.Specular = pass.Specular;
                    retPass.Shininess = pass.Shininess;
                    retPass.SetRunNTimesPerLight(pass.RunOncePerLight,
                                                pass.PassIterationCount,
                                                pass.LightsPerIteration,
                                                pass.RunOnlyForOneLightType,
                                                pass.OnlyLightType);
                    int origPassTUCount = pass.NumTextureUnitStages;
                    for (int t = 0; t < origPassTUCount; ++t) {
                        int targetIndex = t+1;
                        TextureUnitState tex = (retPass.NumTextureUnitStages <= targetIndex ?
                                                retPass.CreateTextureUnitState() :
                                                retPass.GetTextureUnitState(targetIndex));
                        pass.GetTextureUnitState(t).CopyTo(tex);
                    }
                    keepTUCount = origPassTUCount + 1;
                    // Will also need fragment programs since this is a complex light setup
                    if (pass.ShadowReceiverFragmentProgramName != "") {
                        // Have to merge the shadow receiver vertex program in
                        retPass.SetFragmentProgram(pass.ShadowReceiverFragmentProgramName);
                        GpuProgram prg = retPass.FragmentProgram;
                        // Load this program if not done already
                        if (!prg.IsLoaded)
                            prg.Load();
                        // Copy params
                        retPass.FragmentProgramParameters = pass.ShadowReceiverFragmentProgramParameters;
                        // 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.VertexProgramName);
                            prg = retPass.VertexProgram;
                            // Load this program if required
                            if (!prg.IsLoaded)
                                prg.Load();
                            // Copy params
                            retPass.VertexProgramParameters = pass.VertexProgramParameters;
                        }
                    }
                    else {
                        // Reset any merged fragment programs from last time
                        if (retPass == shadowTextureCustomReceiverPass) {
                            // reset fp?
                            if (retPass.FragmentProgramName != shadowTextureCustomReceiverFragmentProgram) {
                                retPass.SetFragmentProgram(shadowTextureCustomReceiverFragmentProgram);
                                if(retPass.HasFragmentProgram)
                                    retPass.FragmentProgramParameters = shadowTextureCustomReceiverFPParams;
                            }
                        }
                        else
                            // Standard shadow receiver pass, reset to no fp
                            retPass.SetFragmentProgram("");
                    }
                }
                // additive lighting
                else
                    // need to keep spotlight fade etc
                    keepTUCount = retPass.NumTextureUnitStages;

                // Remove any extra texture units
                while (retPass.NumTextureUnitStages > keepTUCount)
                    retPass.RemoveTextureUnitState(keepTUCount);
                retPass.Load();
                return retPass;
            }
            else
                return pass;
        }
        /// <summary>
        ///		Internal method for turning a regular pass into a shadow caster pass.
        /// </summary>
        /// <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. 
        /// </remarks>
        /// <param name="pass"></param>
        /// <returns></returns>
        protected virtual Pass DeriveShadowCasterPass(Pass pass)
        {
            if (IsShadowTechniqueTextureBased)
            {
                Pass retPass = (shadowTextureCustomCasterPass != null ?
                                shadowTextureCustomCasterPass : shadowCasterPlainBlackPass);
                retPass.CullMode = pass.CullMode;
                retPass.ManualCullMode = pass.ManualCullMode;
                // Does incoming pass have a custom shadow caster program?
                if (pass.ShadowCasterVertexProgramName != "")
                {
                    retPass.SetVertexProgram(pass.ShadowCasterVertexProgramName);
                    GpuProgram prg = retPass.VertexProgram;
                    // Load this program if not done already
                    if (!prg.IsLoaded)
                        prg.Load();
                    // Copy params
                    retPass.VertexProgramParameters = pass.ShadowCasterVertexProgramParameters;
                    // Also have to hack the light autoparams, that is done later
                }
                else
                {
                    // reset vp?
                    if (retPass == shadowTextureCustomCasterPass)
                    {
                        if (retPass.VertexProgramName != shadowTextureCustomCasterVertexProgram)
                        {
                            shadowTextureCustomCasterPass.SetVertexProgram(shadowTextureCustomCasterVertexProgram);
                            if (retPass.HasVertexProgram)
                                retPass.VertexProgramParameters = shadowTextureCustomCasterVPParams;
                        }
                    }
                    else
                        // Standard shadow caster pass, reset to no vp
                        retPass.SetVertexProgram("");
                }

                int keepTUCount = 0;

                // Material specifies a caster fragment program
                if (pass.ShadowCasterFragmentProgramName != "")
                {
                    // If the material specifies a fragment program, then we need to copy the
                    // TextureUnitStates from the original pass.
                    int origPassTUCount = pass.NumTextureUnitStages;
                    for (int t = 0; t < origPassTUCount; ++t)
                    {
                        TextureUnitState tex = (retPass.NumTextureUnitStages <= t ?
                                                retPass.CreateTextureUnitState() :
                                                retPass.GetTextureUnitState(t));
                        pass.GetTextureUnitState(t).CopyTo(tex);
                    }
                    keepTUCount = origPassTUCount;

                    // Have to merge the shadow caster vertex program in
                    retPass.SetFragmentProgram(pass.ShadowCasterFragmentProgramName);
                    GpuProgram prg = retPass.FragmentProgram;
                    // Load this program if not done already
                    if (!prg.IsLoaded)
                        prg.Load();
                    // Copy params
                    retPass.FragmentProgramParameters = pass.ShadowCasterFragmentProgramParameters;
                    // Did we bind a shadow vertex program?
                    if (pass.HasVertexProgram && !retPass.HasVertexProgram)
                    {
                        // We didn't bind a caster-specific program, so bind the original
                        retPass.SetVertexProgram(pass.VertexProgramName);
                        prg = retPass.VertexProgram;
                        // Load this program if required
                        if (!prg.IsLoaded)
                            prg.Load();
                        // Copy params
                        retPass.VertexProgramParameters = pass.VertexProgramParameters;
                    }
                }
                else
                {
                    // Reset any merged fragment programs from last time
                    if (retPass == shadowTextureCustomCasterPass)
                    {
                        // reset fp?
                        if (retPass.FragmentProgramName != shadowTextureCustomCasterFragmentProgram)
                        {
                            retPass.SetFragmentProgram(shadowTextureCustomCasterFragmentProgram);
                            if (retPass.HasFragmentProgram)
                                retPass.FragmentProgramParameters = shadowTextureCustomCasterFPParams;
                        }
                    }
                    else
                        // Standard shadow caster pass, reset to no fp
                        retPass.SetFragmentProgram("");
                }

                // Remove any extra texture units
                while (retPass.NumTextureUnitStages > keepTUCount)
                {
                    retPass.RemoveTextureUnitState(keepTUCount);
                }

                // make sure we turn off alpha rejection
                targetRenderSystem.SetAlphaRejectSettings(CompareFunction.AlwaysPass, 0);

                retPass.Load();

                return retPass;
            }
            else
            {
                return pass;
            }
        }
        /// <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;
                }
            }
        }