public void CompileIlluminationPasses()
{
ClearIlluminationPasses();
// don't need to split transparent passes since they are rendered seperately
if ( this.IsTransparent )
{
return;
}
// start off with ambient passes
IlluminationStage stage = IlluminationStage.Ambient;
bool hasAmbient = false;
for ( int i = 0; i < _passes.Count; /* increment in logic */)
{
Pass pass = (Pass)_passes[ i ];
IlluminationPass iPass;
switch ( stage )
{
case IlluminationStage.Ambient:
// keep looking for ambient only
if ( pass.IsAmbientOnly )
{
iPass = new IlluminationPass();
iPass.OriginalPass = pass;
iPass.Pass = pass;
iPass.Stage = stage;
_illuminationPasses.Add( iPass );
hasAmbient = true;
// progress to the next pass
i++;
}
else
{
// split off any ambient part
if ( pass.Ambient.CompareTo( ColorEx.Black ) != 0 ||
pass.Emissive.CompareTo( ColorEx.Black ) != 0 )
{
Pass newPass = new Pass( this, pass.Index );
pass.CopyTo( newPass );
// remove any texture units
newPass.RemoveAllTextureUnitStates();
// also remove any fragment program
if ( newPass.HasFragmentProgram )
{
newPass.SetFragmentProgram( "" );
}
// We have to leave vertex program alone (if any) and
// just trust that the author is using light bindings, which
// we will ensure there are none in the ambient pass
newPass.Diffuse = ColorEx.Black;
newPass.Specular = ColorEx.Black;
// if ambient and emissive are zero, then color write isn't needed
if ( newPass.Ambient.CompareTo( ColorEx.Black ) == 0 &&
newPass.Emissive.CompareTo( ColorEx.Black ) == 0 )
{
newPass.ColorWriteEnabled = false;
}
iPass = new IlluminationPass();
iPass.DestroyOnShutdown = true;
iPass.OriginalPass = pass;
iPass.Pass = newPass;
iPass.Stage = stage;
_illuminationPasses.Add( iPass );
hasAmbient = true;
}
if ( !hasAmbient )
{
// make up a new basic pass
Pass newPass = new Pass( this, pass.Index );
pass.CopyTo( newPass );
newPass.Ambient = ColorEx.Black;
newPass.Diffuse = ColorEx.Black;
iPass = new IlluminationPass();
iPass.DestroyOnShutdown = true;
iPass.OriginalPass = pass;
iPass.Pass = newPass;
iPass.Stage = stage;
_illuminationPasses.Add( iPass );
hasAmbient = true;
}
// this means we are done with ambients, progress to per-light
stage = IlluminationStage.PerLight;
}
break;
case IlluminationStage.PerLight:
if ( pass.IteratePerLight )
{
// if this is per-light already, use it directly
iPass = new IlluminationPass();
iPass.DestroyOnShutdown = false;
iPass.OriginalPass = pass;
iPass.Pass = pass;
iPass.Stage = stage;
_illuminationPasses.Add( iPass );
// progress to the next pass
i++;
}
else
{
// split off per-light details (can only be done for one)
if ( pass.LightingEnabled &&
( pass.Diffuse.CompareTo( ColorEx.Black ) != 0 ||
pass.Specular.CompareTo( ColorEx.Black ) != 0 ) )
{
// copy existing pass
Pass newPass = new Pass( this, pass.Index );
pass.CopyTo( newPass );
newPass.RemoveAllTextureUnitStates();
// also remove any fragment program
if ( newPass.HasFragmentProgram )
{
newPass.SetFragmentProgram( "" );
}
// Cannot remove vertex program, have to assume that
// it will process diffuse lights, ambient will be turned off
newPass.Ambient = ColorEx.Black;
newPass.Emissive = ColorEx.Black;
// must be additive
newPass.SetSceneBlending( SceneBlendFactor.One, SceneBlendFactor.One );
iPass = new IlluminationPass();
iPass.DestroyOnShutdown = true;
iPass.OriginalPass = pass;
iPass.Pass = newPass;
iPass.Stage = stage;
_illuminationPasses.Add( iPass );
}
// This means the end of per-light passes
stage = IlluminationStage.Decal;
}
break;
case IlluminationStage.Decal:
// We just want a 'lighting off' pass to finish off
// and only if there are texture units
if ( pass.TextureUnitStageCount > 0 )
{
if ( !pass.LightingEnabled )
{
// we assume this pass already combines as required with the scene
iPass = new IlluminationPass();
iPass.DestroyOnShutdown = false;
iPass.OriginalPass = pass;
iPass.Pass = pass;
iPass.Stage = stage;
_illuminationPasses.Add( iPass );
}
else
{
// Copy the pass and tweak away the lighting parts
Pass newPass = new Pass( this, pass.Index );
pass.CopyTo( newPass );
newPass.Ambient = ColorEx.Black;
newPass.Diffuse = ColorEx.Black;
newPass.Specular = ColorEx.Black;
newPass.Emissive = ColorEx.Black;
newPass.LightingEnabled = false;
// modulate
newPass.SetSceneBlending( SceneBlendFactor.DestColor, SceneBlendFactor.Zero );
// there is nothing we can do about vertex & fragment
// programs here, so people will just have to make their
// programs friendly-like if they want to use this technique
iPass = new IlluminationPass();
iPass.DestroyOnShutdown = true;
iPass.OriginalPass = pass;
iPass.Pass = newPass;
iPass.Stage = stage;
_illuminationPasses.Add( iPass );
}
}
// always increment on decal, since nothing more to do with this pass
i++;
break;
}
}
_compiledIlluminationPasses = true;
}