using Chernobyl.Collections.Generic.Event; using Chernobyl.Dependency; using Chernobyl.Event; using Chernobyl.Graphics.Material.Shader.Parameters; using Chernobyl.Graphics.Material.Shader.Parameters.Semantics; using Chernobyl.Graphics.Texture; using Chernobyl.Graphics.Xna.Controllers; using Chernobyl.Graphics.Xna.Controllers.Shaders; using Chernobyl.Mathematics; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; namespace Chernobyl.Graphics.Xna.Effects { /// /// XNA's BasicEffect wrapped around an XnaEffect. /// public class BasicEffect : XnaEffect { /// /// Constructor. /// /// The service object to retrieve the services from. public BasicEffect(IEventCollection services) : base(services) { Services = services; services.Inject(this); } /// /// Disposes of the XNA basic effect. /// public override void Dispose() { if (_xnaEffect != null) _xnaEffect.Dispose(); } /// /// Called before the draw method. /// public override void PreDraw() { if (_xnaEffect != null) { ////////////////////////////////////////////////////////////////////////// // Set required parameters of the effect ////////////////////////////////////////////////////////////////////////// Matrix tempMatrix; // view Utility.ToXNAMatrix(out tempMatrix, ViewMatrix.Value); _xnaEffect.Parameters[ViewMatrixName].SetValue(tempMatrix); // world Utility.ToXNAMatrix(out tempMatrix, WorldMatrix.Value); _xnaEffect.Parameters[WorldMatrixName].SetValue(tempMatrix); // projection Utility.ToXNAMatrix(out tempMatrix, ProjectionMatrix.Value); _xnaEffect.Parameters[ProjectionMatrixName].SetValue(tempMatrix); //_xnaEffect.VertexColorEnabled = true; ////////////////////////////////////////////////////////////////////////// // make sure we are aware of all changes to the matrices ////////////////////////////////////////////////////////////////////////// ViewMatrix.ValueChanged += OnViewMatrixChanged; WorldMatrix.ValueChanged += OnWorldMatrixChanged; ProjectionMatrix.ValueChanged += OnProjectionMatrixChanged; _xnaEffect.Begin(); } } /// /// Called when the effect should render itself /// and it's children drawables. /// public override uint Draw() { uint result = 0; if (_xnaEffect != null) { foreach (EffectPass pass in _xnaEffect.CurrentTechnique.Passes) { pass.Begin(); // draw all of the children result = base.Draw(); pass.End(); } } return result; } /// /// Called after the draw method. /// public override void PostDraw() { if (_xnaEffect != null) { _xnaEffect.End(); ViewMatrix.ValueChanged -= OnViewMatrixChanged; WorldMatrix.ValueChanged -= OnWorldMatrixChanged; ProjectionMatrix.ValueChanged -= OnProjectionMatrixChanged; } } /// /// Converts the XNA to a Chernobyl /// . /// /// The to convert. /// /// The converted or null if the /// parameter could not be converted. /// protected override IShaderParameter ParameterConverter(EffectParameter param) { IShaderParameter chernobylParam = null; if (param == _xnaEffect.Parameters[BasicTextureName]) { Microsoft.Xna.Framework.Graphics.Texture2D xnaTexture = param.GetValueTexture2D(); ITexture texture = xnaTexture == null ? null : new XnaTexture2D(Services, xnaTexture); chernobylParam = new ColorTextureParameter(Services, new XnaTextureParameter(Services, this, param, texture, param.Name)); } return chernobylParam; } /// /// The parameter used to set the view matrix. /// [Inject] public IViewMatrixParameter ViewMatrix { get { return _viewMatrix; } set { _viewMatrix = value; IsReady = CheckIfReady(); } } /// /// The parameter used to set the world matrix. /// [Inject] public IWorldMatrixParameter WorldMatrix { get { return _worldMatrix; } set { _worldMatrix = value; IsReady = CheckIfReady(); } } /// /// The parameter used to set the projection matrix. /// [Inject] public IProjectionMatrixParameter ProjectionMatrix { get { return _projectionMatrix; } set { _projectionMatrix = value; IsReady = CheckIfReady(); } } /// /// The instance used by XNA to manage /// content produced by the content pipeline. /// [Inject] public ContentManager Content { get { return _content; } set { _content = value; // dispose of the old XNA effect if (_xnaEffect != null) _xnaEffect.Dispose(); Effect = _xnaEffect = _content.Load(SimpleEffectFileName); IsReady = CheckIfReady(); } } /// /// Called when the view matrix is changed during rendering. /// /// The sender of the event. /// The event arguments. void OnViewMatrixChanged(object sender, ValueChangedEventArgs e) { Matrix matrix; Utility.ToXNAMatrix(out matrix, e.NewValue); _xnaEffect.Parameters[ViewMatrixName].SetValue(matrix); _xnaEffect.CommitChanges(); } /// /// Called when the world matrix is changed during rendering. /// /// The sender of the event. /// The event arguments. void OnWorldMatrixChanged(object sender, ValueChangedEventArgs e) { Matrix matrix; Utility.ToXNAMatrix(out matrix, e.NewValue); _xnaEffect.Parameters[WorldMatrixName].SetValue(matrix); _xnaEffect.CommitChanges(); } /// /// Called when the projection matrix is changed during rendering. /// /// The sender of the event. /// The event arguments. void OnProjectionMatrixChanged(object sender, ValueChangedEventArgs e) { Matrix matrix; Utility.ToXNAMatrix(out matrix, e.NewValue); _xnaEffect.Parameters[ProjectionMatrixName].SetValue(matrix); _xnaEffect.CommitChanges(); } /// /// Determines whether this instance is ready and returns a value /// indicating that readiness. /// /// True if this instance is ready, false if otherwise. protected override bool CheckIfReady() { return (base.CheckIfReady() == true && ViewMatrix != null && WorldMatrix != null && ProjectionMatrix != null && Content != null); } /// /// The name of the simple effect file used by this instance. /// const string SimpleEffectFileName = "simple_effect"; /// /// The name of the projection matrix in the simple effect file. /// const string WorldMatrixName = "World"; /// /// The name of the projection matrix in the simple effect file. /// const string ViewMatrixName = "View"; /// /// The name of the projection matrix in the simple effect file. /// const string ProjectionMatrixName = "Projection"; /// /// The name of the basic texture used as a color texture. /// const string BasicTextureName = "BasicTexture"; /// /// The instance that gives out services for use by this type and takes /// services from this type for use by other systems. /// IEventCollection Services { get; set; } /// /// The XNA basic effect that provides actual rendering. /// Effect _xnaEffect; /// /// The backing field to . /// IViewMatrixParameter _viewMatrix; /// /// The backing field to . /// IWorldMatrixParameter _worldMatrix; /// /// The backing field to . /// IProjectionMatrixParameter _projectionMatrix; /// /// The backing field to . /// ContentManager _content; } }