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