using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using MLEM.Misc; namespace MLEM.Textures { /// /// This class represents an atlas of objects that is uniform. /// Uniform, in this case, means that the texture atlas' size is not determined by the width and height of the texture, but instead by the amount of sub-regions that the atlas has in the x and y direction. /// Using a uniform texture atlas over a regular texture as an atlas allows for texture artists to create higher resolution textures without coordinates becoming off. /// public class UniformTextureAtlas : GenericDataHolder { /// /// The that this uniform texture atlas uses as its basis. /// In most cases, has the full area of the underlying . /// public readonly TextureRegion Region; /// /// The amount of sub-regions this atlas has in the x direction /// public readonly int RegionAmountX; /// /// The amount of sub-regions this atlas has in the y direction /// public readonly int RegionAmountY; /// /// The width of each region, based on the texture's width and the amount of regions /// public readonly int RegionWidth; /// /// The height of reach region, based on the texture's height and the amount of regions /// public readonly int RegionHeight; /// /// The padding that each texture region has around itself, in pixels, which will be taken away from each side of objects created and returned by this texture atlas. /// Creating a texture atlas with padding can be useful if texture bleeding issues occur due to texture coordinate rounding. /// public readonly int RegionPadding; /// /// The texture to use for this atlas. /// Note that stores the actual area that we depend on. /// public Texture2D Texture => this.Region.Texture; /// /// Returns the at this texture atlas's given index. /// The index is zero-based, where rows come first and columns come second. /// /// The zero-based texture index public TextureRegion this[int index] => this[index % this.RegionAmountX, index / this.RegionAmountX]; /// /// Returns the at this texture atlas' given region position /// /// The region's x and y location public TextureRegion this[Point point] => this[new Rectangle(point.X, point.Y, 1, 1)]; /// public TextureRegion this[int x, int y] => this[new Point(x, y)]; /// /// Returns the at this texture atlas' given region position and size. /// Note that the region size is not in pixels, but in region units. /// /// The region's area public TextureRegion this[Rectangle rect] => this.GetOrAddRegion(rect); /// public TextureRegion this[int x, int y, int width, int height] => this[new Rectangle(x, y, width, height)]; private readonly Dictionary regions = new Dictionary(); /// /// Creates a new uniform texture atlas with the given texture region and region amount. /// This atlas will only ever pull information from the given and never exit the region's bounds. /// /// The texture region to use for this atlas /// The amount of texture regions in the x direction /// The amount of texture regions in the y direction /// The padding that each texture region has around itself, in pixels, which will be taken away from each side of objects created and returned by this texture atlas. public UniformTextureAtlas(TextureRegion region, int regionAmountX, int regionAmountY, int regionPadding = 0) { this.Region = region; this.RegionAmountX = regionAmountX; this.RegionAmountY = regionAmountY; this.RegionPadding = regionPadding; this.RegionWidth = region.Width / regionAmountX; this.RegionHeight = region.Height / regionAmountY; } /// /// Creates a new uniform texture atlas with the given texture and region amount. /// /// The texture to use for this atlas /// The amount of texture regions in the x direction /// The amount of texture regions in the y direction /// The padding that each texture region has around itself, in pixels, which will be taken away from each side of objects created and returned by this texture atlas. public UniformTextureAtlas(Texture2D texture, int regionAmountX, int regionAmountY, int regionPadding = 0) : this(new TextureRegion(texture), regionAmountX, regionAmountY, regionPadding) {} /// /// Converts this uniform texture atlas to a and returns the result. /// The resulting list will contain all square 1x1 regions that this uniform texture atlas contains, based on and , with each index containing the at . /// /// The list representation of this uniform texture atlas. public List ToList() { var ret = new List(); for (var i = 0; i < this.RegionAmountX * this.RegionAmountY; i++) ret.Add(this[i]); return ret; } /// /// Converts this uniform texture atlas to a and returns the result. /// The resulting dictionary will contain all square 1x1 regions that this uniform texture atlas contains, based on and , wich each key containing the at . /// /// The dictionary representation of this uniform texture atlas. public Dictionary ToDictionary() { var ret = new Dictionary(); for (var x = 0; x < this.RegionAmountX; x++) { for (var y = 0; y < this.RegionAmountY; y++) ret.Add(new Point(x, y), this[x, y]); } return ret; } private TextureRegion GetOrAddRegion(Rectangle rect) { if (this.regions.TryGetValue(rect, out var region)) return region; region = new TextureRegion(this.Region, rect.X * this.RegionWidth + this.RegionPadding, rect.Y * this.RegionHeight + this.RegionPadding, rect.Width * this.RegionWidth - 2 * this.RegionPadding, rect.Height * this.RegionHeight - 2 * this.RegionPadding); this.regions.Add(rect, region); return region; } } }