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