using System; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; namespace MLEM.Extensions { /// /// A set of extensions for dealing with /// public static class TextureExtensions { /// /// Returns a new instance of which allows easily managing a texture's data with texture coordinates rather than indices. /// When this is used in a using statement, the texture data is automatically stored back in the texture at the end. /// /// The texture whose data to get /// The texture's data public static TextureData GetTextureData(this Texture2D texture) { return new TextureData(texture); } /// /// A struct that represents the data of a texture, accessed through . /// public class TextureData : IDisposable { private readonly Texture2D texture; private readonly Color[] data; private bool dirty; /// /// Returns the color at the given x,y position of the texture, where 0,0 represents the bottom left. /// /// The x coordinate of the texture location /// The y coordinate of the texture location public Color this[int x, int y] { get => this.data[this.ToIndex(x, y)]; set { var index = this.ToIndex(x, y); if (this.data[index] != value) { this.data[index] = value; this.dirty = true; } } } /// public Color this[Point point] { get => this[point.X, point.Y]; set => this[point.X, point.Y] = value; } /// /// Creates a new texture data instance for the given texture. /// Note that this can more easily be invoked using . /// /// The texture whose data to get public TextureData(Texture2D texture) { this.texture = texture; this.data = new Color[texture.Width * texture.Height]; this.texture.GetData(this.data); } /// /// Stores this texture data back into the underlying texture /// public void Store() { if (this.dirty) { this.texture.SetData(this.data); this.dirty = false; } } /// /// Converts the given x,y texture coordinate to the corresponding index in the array. /// /// The x coordinate /// The y coordinate /// The corresponding texture array index /// If the given coordinate is out of bounds public int ToIndex(int x, int y) { if (!this.IsInBounds(x, y)) throw new ArgumentException(); return y * this.texture.Width + x; } /// /// Converts the given index from the array into the corresponding x,y texture coordinate. /// /// The texture array index /// The corresponding texture coordinate /// If the given index is out of bounds public Point FromIndex(int index) { if (index < 0 || index >= this.data.Length) throw new ArgumentException(); return new Point(index % this.texture.Width, index / this.texture.Width); } /// /// Checks if the given x,y texture coordinates is within the bounds of the underlying texture. /// /// The x coordinate /// The y coordinate /// Whether the given coordinate is within bounds of the underlying texture public bool IsInBounds(int x, int y) { return x >= 0 && y >= 0 && x < this.texture.Width && y < this.texture.Height; } /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. public void Dispose() { this.Store(); } } } }