using System.Collections.Specialized;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace MonoGame.Extended.Graphics.Effects
{
///
/// An that uses the standard chain of matrix transformations to represent a 3D object on a 2D
/// monitor.
///
///
///
public abstract class MatrixChainEffect : Effect, IMatrixChainEffect
{
///
/// The bitmask for use with indicating wether , , or has changed in the last frame.
///
protected static int DirtyWorldViewProjectionBitMask = BitVector32.CreateMask();
///
/// The bitmask for use with indicating wether to use a default projection matrix or a custom projection matrix.
///
protected static int UseDefaultProjectionBitMask = BitVector32.CreateMask(DirtyWorldViewProjectionBitMask);
///
/// The dirty flags associated with this .
///
protected BitVector32 Flags;
private Matrix _projection = Matrix.Identity;
private Matrix _view = Matrix.Identity;
private Matrix _world = Matrix.Identity;
private EffectParameter _matrixParameter;
///
/// Gets or sets the model-to-world .
///
///
/// The model-to-world .
///
public Matrix World
{
get { return _world; }
set { SetWorld(ref value); }
}
///
/// Gets or sets the world-to-view .
///
///
/// The world-to-view .
///
public Matrix View
{
get { return _view; }
set { SetView(ref value); }
}
///
/// Gets or sets the view-to-projection .
///
///
/// The view-to-projection .
///
public Matrix Projection
{
get { return _projection; }
set { SetProjection(ref value); }
}
///
/// Initializes a new instance of the class.
///
/// The graphics device.
/// The effect code.
protected MatrixChainEffect(GraphicsDevice graphicsDevice, byte[] byteCode)
: base(graphicsDevice, byteCode)
{
Initialize();
}
///
/// Initializes a new instance of the class.
///
/// The clone source.
protected MatrixChainEffect(Effect cloneSource)
: base(cloneSource)
{
Initialize();
}
private void Initialize()
{
Flags[UseDefaultProjectionBitMask] = true;
_matrixParameter = Parameters["WorldViewProjection"];
}
///
/// Sets the model-to-world .
///
/// The model-to-world .
public void SetWorld(ref Matrix world)
{
_world = world;
Flags[DirtyWorldViewProjectionBitMask] = true;
}
///
/// Sets the world-to-view .
///
/// The world-to-view .
public void SetView(ref Matrix view)
{
_view = view;
Flags[DirtyWorldViewProjectionBitMask] = true;
}
///
/// Sets the view-to-projection .
///
/// The view-to-projection .
public void SetProjection(ref Matrix projection)
{
_projection = projection;
Flags[DirtyWorldViewProjectionBitMask] = true;
Flags[UseDefaultProjectionBitMask] = false;
}
///
/// Computes derived parameter values immediately before applying the effect.
///
protected override void OnApply()
{
base.OnApply();
// ReSharper disable once InvertIf
if (Flags[DirtyWorldViewProjectionBitMask] || Flags[UseDefaultProjectionBitMask])
{
if (Flags[UseDefaultProjectionBitMask])
{
var viewport = GraphicsDevice.Viewport;
_projection = Matrix.CreateOrthographicOffCenter(0, viewport.Width, viewport.Height, 0, 0, -1);
}
Matrix worldViewProjection;
Matrix.Multiply(ref _world, ref _view, out worldViewProjection);
Matrix.Multiply(ref worldViewProjection, ref _projection, out worldViewProjection);
_matrixParameter.SetValue(worldViewProjection);
Flags[DirtyWorldViewProjectionBitMask] = false;
}
}
}
}