using System;
using Chernobyl.Collections.Generic.Event;
using Chernobyl.Event;
using Chernobyl.Graphics.Texture;
using Chernobyl.Mathematics.Geometry;
using Microsoft.Xna.Framework.Graphics;
namespace Chernobyl.Graphics.Xna.Controllers
{
///
/// Used to control an XNA 2D texture.
///
class XnaTexture2D : Rectangle, ITexture2D
{
///
/// Constructor.
///
/// The services class that contains the
/// dependencies to inject into this instance.
/// The width of the texture in pixels.
/// The height of the texture in pixels.
/// The number of mipmap levels to generate.
/// The format of the texture data.
public XnaTexture2D(IEventCollection services, uint width, uint height, uint mipmapLevels, TextureFormat textureFormat)
: base(0, 0, 0, 0)
{
TextureFormat = textureFormat;
PixelCount = width * height;
GraphicsDeviceSetter graphicsDeviceSetter = new GraphicsDeviceSetter(this, width, height, mipmapLevels);
services.OfType(graphicsDeviceSetter.SetGraphicsDeviceAndConfigure);
}
///
/// Constructor.
///
/// The services class that contains the
/// dependencies to inject into this instance.
/// The XNA texture that this texture should use.
public XnaTexture2D(IEventCollection services, Microsoft.Xna.Framework.Graphics.Texture2D texture)
: base(0, 0, 0, 0)
{
XnaTexture = texture;
Configure();
}
///
/// Configures some common parameters.
///
public void Configure()
{
Width = XnaTexture.Width;
Height = XnaTexture.Height;
PixelCount = (uint)(Width * Height);
IsReady = true;
}
///
/// Disposes of the texture controller used by this
/// 2D texture.
///
public void Dispose()
{
if (XnaTexture != null)
XnaTexture.Dispose();
}
///
/// A type used to retrieve the from an
/// and set it on an .
///
struct GraphicsDeviceSetter
{
///
/// Initializes a new instance of the
/// struct.
///
/// The texture to set the
/// on and invoke
/// on.
/// The width of the texture in pixels.
/// The height of the texture in pixels.
/// The number of mipmap levels to generate.
public GraphicsDeviceSetter(XnaTexture2D texture, uint width, uint height, uint mipmapLevels)
: this()
{
Texture = texture;
Width = width;
Height = height;
MipmapLevels = mipmapLevels;
}
///
/// The method that is invoked by the
/// instance when the has been set.
///
/// The service that was requested.
public void SetGraphicsDeviceAndConfigure(GraphicsDevice service)
{
Texture.XnaTexture =
new Microsoft.Xna.Framework.Graphics.Texture2D(service, (int)Width, (int)Height, (int)MipmapLevels,
TextureUsage.AutoGenerateMipMap, Texture._surfaceFormat);
Texture.Configure();
}
///
/// The texture to set the on and
/// invoke on.
///
XnaTexture2D Texture { get; set; }
///
/// The width of the texture in pixels.
///
uint Width { get; set; }
///
/// The height of the texture in pixels.
///
uint Height { get; set; }
///
/// The number of mipmap levels to generate.
///
uint MipmapLevels { get; set; }
}
///
/// Sets the data from the array passed in into the texture at mipmap
/// level 0.
///
/// The type of data to set into the texture.
/// The data to set into the texture.
/// Thrown if this XNA texture has
/// not been fully configured.
public void Set(TData[] data) where TData : struct
{
if (IsReady == false)
throw new NotReadyException("The texture data cannot be set " +
"because the XNA texture has not been fully configured.");
XnaTexture.SetData(data);
if(DataChanged != null)
DataChanged(this, new TextureDataEventArgs(new TextureDataEventArgs.Modification(0, PixelCount)));
}
///
/// Set the raw texture data into the texture, starting at the beginning of
/// the texture and ending at , at mipmap
/// level 0.
///
/// The data type of the texture data.
/// The data to set.
/// The starting element in at which to start copying data.
/// The number of elements to copy over from .
/// Thrown if this XNA texture has
/// not been fully configured.
public void Set(TData[] data, uint startIndex, uint elementCount) where TData : struct
{
if (IsReady == false)
throw new NotReadyException("The texture data cannot be set " +
"because the XNA texture has not been fully configured.");
XnaTexture.SetData(data, (int)startIndex, (int)elementCount, SetDataOptions.None);
if (DataChanged != null)
DataChanged(this, new TextureDataEventArgs(new TextureDataEventArgs.Modification(startIndex, elementCount)));
}
///
/// Sets the texture data.
///
/// The data type of the texture data.
/// The mipmap level to place the data into.
/// The region or area of the texture to place the data into. If
/// is null then the entire texture will be set to the passed in data.
/// The data to set.
/// The starting element in at which to start copying data.
/// The number of elements to copy over from .
/// Thrown if this XNA texture has
/// not been fully configured.
public void Set(uint mipmapLevel, Rectangle setSection, TData[] data, uint startIndex, uint elementCount) where TData : struct
{
if (IsReady == false)
throw new NotReadyException("The texture data cannot be set " +
"because the XNA texture has not been fully configured.");
if (setSection != null)
{
XnaTexture.SetData((int)mipmapLevel, new Microsoft.Xna.Framework.Rectangle((int)setSection.LeftSide, (int)setSection.Bottom, (int)setSection.Width, (int)setSection.Height), data, (int)startIndex, (int)elementCount, SetDataOptions.None);
if (DataChanged != null)
DataChanged(this, new TextureDataEventArgs(new TextureDataEventArgs.Modification(setSection, (uint)Width)));
}
else
{
XnaTexture.SetData((int)mipmapLevel, null, data, (int)startIndex, (int)elementCount, SetDataOptions.None);
if (DataChanged != null)
DataChanged(this, new TextureDataEventArgs(new TextureDataEventArgs.Modification(startIndex, elementCount)));
}
}
///
/// Gets the texture data.
///
/// The data type of the texture data.
/// The mipmap level to get the data from.
/// The region or area of the texture to get the data from. If
/// is null then the entire texture will be will be placed into .
/// The array that is to be filled with the texture data.
/// The index in the array to start copying the data from the texture.
/// The number of elements to copy over from the texture.
/// Thrown if this XNA texture has
/// not been fully configured.
public void Get(uint mipmapLevel, Rectangle getSection, out TData[] data, uint startIndex, uint elementCount) where TData : struct
{
if (IsReady == false)
throw new NotReadyException("The texture data cannot be " +
"retrieved because the XNA texture has not been fully configured.");
data = new TData[elementCount];
if (getSection != null)
XnaTexture.GetData((int)mipmapLevel, new Microsoft.Xna.Framework.Rectangle((int)getSection.LeftSide, (int)getSection.Bottom, (int)getSection.Width, (int)getSection.Height), data, (int)startIndex, (int)elementCount);
else
XnaTexture.GetData((int)mipmapLevel, null, data, (int)startIndex, (int)elementCount);
}
///
/// Retrieves all of the raw data in the texture at mipmap level 0.
///
/// The data type of the texture data.
/// The array that is to be filled with the texture data. This
/// array must be of a size that is large enough to receive all of the texture data.
/// Thrown if this XNA texture has
/// not been fully configured.
public void Get(TData[] data) where TData : struct
{
if (IsReady == false)
throw new NotReadyException("The texture data cannot be " +
"retrieved because the XNA texture has not been fully configured.");
XnaTexture.GetData(data);
}
///
/// Gets the raw texture data at mipmap level zero.
///
/// The data type of the texture data.
/// The array that is to be filled with the texture data.
/// The index in the array to start copying the data from the texture.
/// The number of elements to copy over from the texture.
/// Thrown if this XNA texture has
/// not been fully configured.
public void Get(out TData[] data, uint startIndex, uint elementCount) where TData : struct
{
if (IsReady == false)
throw new NotReadyException("The texture data cannot be " +
"retrieved because the XNA texture has not been fully configured.");
data = new TData[elementCount];
XnaTexture.GetData(data, (int)startIndex, (int)elementCount);
}
///
/// Invoked right after a change to the data of the texture has been made.
///
public event EventHandler DataChanged;
///
/// True if this texture has been loaded, false if otherwise.
///
public bool IsReady
{
get { return _isReady; }
set
{
bool wasReady = _isReady;
_isReady = value;
if (_becameReady != null && wasReady == false && _isReady == true)
_becameReady(this, EventArgs.Empty);
}
}
///
/// An event that is thrown right after this
/// has been loaded or readied. If an event handler is assigned to this
/// event after it has become ready, then that event handler will be
/// immediately invoked.
///
public event EventHandler BecameReady
{
add
{
if (IsReady == true)
value(this, EventArgs.Empty);
_becameReady += value;
}
remove { _becameReady -= value; }
}
///
/// The number of pixels in the entire texture.
///
public uint PixelCount { get; private set; }
///
/// The number of levels for mipmaps
///
public uint MipmapLevelsCount { get { return (uint)XnaTexture.LevelCount; } }
///
/// The XNA texture used to represent this texture.
///
public Microsoft.Xna.Framework.Graphics.Texture2D XnaTexture { get; set; }
///
/// The that controls the 3D API texture (such
/// as XNA, DirectX, OpenGL, etc) or null if this
/// does not have a controller.
///
public ITexture2D Controller { get { return null; } }
///
/// The that controls the 3D API texture (such
/// as XNA, DirectX, OpenGL, etc) or null if this
/// does not have a controller.
///
ITexture ITexture.Controller { get { return null; } }
///
/// Gets/sets the format of this texture.
///
TextureFormat TextureFormat
{
get {return Utility.ToTextureFormat(_surfaceFormat);}
set { _surfaceFormat = Utility.ToSurfaceFormat(value); }
}
///
/// The XNA texture format.
///
SurfaceFormat _surfaceFormat;
///
/// The backing field to .
///
bool _isReady;
///
/// The backing field to .
///
EventHandler _becameReady;
}
}