using System;
using System.Collections.Generic;
using System.Diagnostics;
using Chernobyl.Collections.Generic.Event;
using Chernobyl.Dependency;
using Chernobyl.Graphics.Drawing;
using Chernobyl.Graphics.Material;
using Chernobyl.Graphics.Material.Shader.Parameters;
using Chernobyl.Readiness;
using Microsoft.Xna.Framework.Graphics;
namespace Chernobyl.Graphics.Xna.Effects
{
///
/// Represents an XNA effect.
///
public class XnaEffect : Drawable, IEffect
{
///
/// Initializes a new instance of the class.
///
/// The instance that gives out services for use
/// by this type and takes services from this type for use by other systems.
public XnaEffect(IEventCollection services)
{
services.Inject(this);
}
///
/// The XNA effect that gives this effect it's abilities.
///
public Effect Effect { get; set; }
///
/// True if this instance has been readied, false if otherwise.
///
public bool IsReady
{
get { return _isReady; }
protected set
{
bool previousValue = _isReady;
_isReady = value;
if (previousValue == false && _isReady == true &&
_becameReady != null)
_becameReady(this, EventArgs.Empty);
}
}
///
/// An event that is thrown right after this
/// has been readied. If an event handler is added to this event
/// after it has become ready, then that event handler will be
/// invoked immediately.
///
public event EventHandler BecameReady
{
add
{
if (IsReady == true)
value(this, EventArgs.Empty);
_becameReady += value;
}
remove { _becameReady -= value; }
}
///
/// Disposes of the XNA effect held by this class.
///
public virtual void Dispose()
{
Effect.Dispose();
}
///
/// The parameters that the effect takes usually for the purpose of
/// setting variables in a shader.
///
public IEnumerable Parameters
{
get
{
if(_parameters == null)
{
if(IsReady == false)
throw new NotReadyException("Unable to return the " +
"parameters as this instance is not ready. Listen to " +
"IReadyable.BecameReady event on this instance to " +
"know when this instance is ready.");
List parameters = new List(Effect.Parameters.Count);
foreach (EffectParameter effectParameter in Effect.Parameters)
{
IShaderParameter shaderParam = ParameterConverter(effectParameter);
if(shaderParam == null)
{
// the parameter converter method could not handle the
// effect parameter so we are going to try using one
// of the effect parameter converters
Func parameterConverter;
if (EffectParameterConverters.TryGetValue(effectParameter.ParameterType, out parameterConverter) == true)
shaderParam = parameterConverter(effectParameter);
}
if(shaderParam != null)
parameters.Add(shaderParam);
else
{
XnaPlugin.Trace.TraceEvent(TraceEventType.Warning, 0,
"Failed to convert the XNA EffectParameter \"" + effectParameter.Name + "\" to a Chernobyl IShaderParameter. " +
"The \"" + typeof(XnaEffect).FullName + ".ParameterConverter(EffectParameter)\" " +
"method did not convert the XNA EffectParameter and there was no converter for an \"" +
effectParameter.ParameterType + "\" in the \"" + EffectParameterConverters.GetType().FullName +
"\" service.");
}
}
_parameters = parameters;
}
return _parameters;
}
}
///
/// Converts the XNA to a Chernobyl
/// . This method always returns null.
/// Overload it to provide your own functionality.
///
/// The to convert.
/// The converted or null if the
/// parameter could not be converted.
protected virtual IShaderParameter ParameterConverter(EffectParameter param)
{
return null;
}
///
/// A that holds mappings of an
/// to converter methods. These
/// converter methods are responsible for converting the passed in XNA
/// (which of type )
/// to a Chernobyl .
///
[Inject]
public SortedList> EffectParameterConverters
{
get { return _effectParameterConverters; }
set
{
_effectParameterConverters = value;
IsReady = CheckIfReady();
}
}
///
/// Overrides .
///
public IEffect Controller { get; private set; }
///
/// Determines whether this instance is ready and returns a value
/// indicating that readiness.
///
/// True if this instance is ready, false if otherwise.
protected virtual bool CheckIfReady()
{
return (_effectParameterConverters != null);
}
///
/// The backing field to .
///
bool _isReady;
///
/// The backing field to .
///
EventHandler _becameReady;
///
/// The backing field to .
///
IEnumerable _parameters;
///
/// The backing field to .
///
SortedList> _effectParameterConverters;
}
}