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