using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using System; using System.Collections.Generic; using System.Linq; namespace RecrownedAthenaeum.SpecialTypes { /// /// Holds information about an image file that contains various textures in various regions in the file. /// public class TextureAtlas : IDisposable { private Texture2D texture; private bool disposed; private Dictionary dictionaryOfRegions = new Dictionary(); /// /// Given a name, can return a . /// /// Name of to obtain. /// based off name. public Region this[string name] { get { if (name != null && dictionaryOfRegions.ContainsKey(name)) return dictionaryOfRegions[name]; else throw new KeyNotFoundException("Given key \"" + name + "\" does not exist."); } } /// /// Creates a texture atlas with given main texture as well as an array of to represent locations of which textures reside within the atlas. Region names will be used to refer to the regions within the dictionary. /// /// The texture representing the overall atlas. /// The sub regions that represent the individual textures. public TextureAtlas(Texture2D texture, Region[] regions) { this.texture = texture; foreach (Region region in regions) { dictionaryOfRegions.Add(region.name, region); } } /// /// Creates a texture region given a dictionary of regions keyed to strings that can be used to refer to them. /// /// The texture representing the overall atlas. /// public TextureAtlas(Texture2D texture, Dictionary dictionaryOfRegions) { this.texture = texture; this.dictionaryOfRegions = dictionaryOfRegions; } /// /// Draw the region given by a string in the atlas onto a destination rectangle. /// /// Name of region to draw. /// SpriteBatch to be used. /// The location to draw this region. /// Color to use. /// Rotation of texture drawn. /// Origin used by rotation. public void Draw(string name, SpriteBatch batch, Rectangle destination, Color color = default(Color), float rotation = 0, Vector2 origin = new Vector2()) { dictionaryOfRegions[name].Draw(batch, destination, color, rotation, origin); } /// /// Creates or obtains a previously created texture of a region. /// /// Name of region. /// graphics device to be used. /// The texture from the region. public Texture2D ObtainRegionAsTexture(string name, GraphicsDevice graphicsDevice) { return dictionaryOfRegions[name].AsTexture2D(graphicsDevice); } /// /// Disposes unmanaged resources for the texture atlas. /// public void Dispose() { Dispose(true); } /// /// Overridable disposal method. /// /// Only true if user calls public virtual void Dispose(bool disposing) { disposed = true; if (!disposed && disposing) { texture.Dispose(); for (int i = 0; i < dictionaryOfRegions.Count; i++) { Region region = dictionaryOfRegions.ElementAt(i).Value; if (!region.Disposed) { dictionaryOfRegions.ElementAt(i).Value.Dispose(); } } dictionaryOfRegions.Clear(); } } /// /// Destructor. /// ~TextureAtlas() { Dispose(false); } /// /// A region of a . /// public class Region : IComparable, ISpecialDrawable, IDisposable { /// /// The name of the region. Mostly used to be refered to within the context of a . /// public readonly string name; /// /// The location and dimensions of where the original texture resides on the texture representing the atlas. /// public readonly Rectangle sourceRectangle; readonly NinePatch ninepatch; Texture2D atlasTexture; Texture2D regionTexture; /// /// If region has already been disposed. /// public bool Disposed { get; private set; } /// /// A specified region in a texture atlas. /// /// Name of region. /// The location of the region on the atlas. /// A definition for the region. /// The texture that holds the image data for the atlas. public Region(string name, Rectangle sourceRegion, NinePatch ninePatch, Texture2D atlasTexture) { this.atlasTexture = atlasTexture ?? throw new ArgumentNullException("Name parameters can be null."); this.name = name ?? throw new ArgumentNullException("Name parameters can be null."); this.sourceRectangle = sourceRegion; this.ninepatch = ninePatch; } /// /// Draws the region. If ninepatch, rotation and origin are ignored. /// /// The batch to use. Should be began. /// The destination rectangle to draw to. /// The color to use. /// Rotation of the final drawing. Ignored if is a 9patch. /// The origin of the drawing. Ignored if is a 9patch. public void Draw(SpriteBatch batch, Rectangle destination, Color color, float rotation = 0, Vector2 origin = default(Vector2)) { if (Disposed) throw new ObjectDisposedException(GetType().Name); if (ninepatch != null) { ninepatch.Draw(batch, destination); } else { batch.Draw(atlasTexture, destination, sourceRectangle, color, rotation, origin, SpriteEffects.None, 0f); } } /// /// Create or obtains a previously created texture of this region. /// /// The graphics device to use to create the texture. /// The texture of the region. public Texture2D AsTexture2D(GraphicsDevice graphicsDevice) { if (Disposed) throw new ObjectDisposedException(GetType().Name); if (regionTexture == null) { Color[] data = new Color[sourceRectangle.Width * sourceRectangle.Height]; regionTexture = new Texture2D(graphicsDevice, sourceRectangle.Width, sourceRectangle.Height); atlasTexture.GetData(0, sourceRectangle, data, 0, sourceRectangle.Width * sourceRectangle.Height); regionTexture.SetData(data); } return regionTexture; } /// /// Compares this region to another in terms of name. /// /// The other region to compare to in terms of name. /// Less than one if precedes, greater than one if after, 0 if same. public int CompareTo(Region other) { return name.CompareTo(other); } /// /// Call this to dispose. /// public void Dispose() { if (Disposed) throw new ObjectDisposedException(GetType().Name); Dispose(true); GC.SuppressFinalize(this); } /// /// Overridable dispose. /// /// Whether or not this was a user made call. public virtual void Dispose(bool disposing) { if (disposing && !Disposed) { regionTexture?.Dispose(); } Disposed = true; } /// /// Destructor. /// ~Region() { Dispose(false); } } } }