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