using System.Collections.Generic; using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using MLEM.Extensions; using MLEM.Misc; namespace MLEM.Textures { /// /// This class represents a texture with nine areas. /// A nine patch texture is useful if a big area should be covered by a small texture that has a specific outline, like a gui panel texture. The center of the texture will be stretched, while the outline of the texture will remain at its original size, keeping aspect ratios alive. /// public class NinePatch : GenericDataHolder { /// /// The texture region of this nine patch /// public readonly TextureRegion Region; /// /// The padding in each direction that marks where the outline area stops /// public readonly Padding Padding; /// /// The nine patches that result from the /// public readonly Rectangle[] SourceRectangles; /// /// Creates a new nine patch from a texture and a padding /// /// The texture to use /// The padding that marks where the outline area stops public NinePatch(TextureRegion texture, Padding padding) { this.Region = texture; this.Padding = padding; this.SourceRectangles = this.CreateRectangles(this.Region.Area).ToArray(); } /// /// Creates a new nine patch from a texture and a padding /// /// The texture to use /// The padding on the left edge /// The padding on the right edge /// The padding on the top edge /// The padding on the bottom edge public NinePatch(TextureRegion texture, int paddingLeft, int paddingRight, int paddingTop, int paddingBottom) : this(texture, new Padding(paddingLeft, paddingRight, paddingTop, paddingBottom)) { } /// public NinePatch(Texture2D texture, int paddingLeft, int paddingRight, int paddingTop, int paddingBottom) : this(new TextureRegion(texture), paddingLeft, paddingRight, paddingTop, paddingBottom) { } /// /// Creates a new nine patch from a texture and a uniform padding /// /// The texture to use /// The padding that each edge should have public NinePatch(Texture2D texture, int padding) : this(new TextureRegion(texture), padding) { } /// public NinePatch(TextureRegion texture, int padding) : this(texture, padding, padding, padding, padding) { } private IEnumerable CreateRectangles(Rectangle area, float patchScale = 1) { return this.CreateRectangles((RectangleF) area, patchScale).Select(r => (Rectangle) r); } internal IEnumerable CreateRectangles(RectangleF area, float patchScale = 1) { var pl = this.Padding.Left * patchScale; var pr = this.Padding.Right * patchScale; var pt = this.Padding.Top * patchScale; var pb = this.Padding.Bottom * patchScale; var centerW = area.Width - pl - pr; var centerH = area.Height - pt - pb; var leftX = area.X + pl; var rightX = area.X + area.Width - pr; var topY = area.Y + pt; var bottomY = area.Y + area.Height - pb; yield return new RectangleF(area.X, area.Y, pl, pt); yield return new RectangleF(leftX, area.Y, centerW, pt); yield return new RectangleF(rightX, area.Y, pr, pt); yield return new RectangleF(area.X, topY, pl, centerH); yield return new RectangleF(leftX, topY, centerW, centerH); yield return new RectangleF(rightX, topY, pr, centerH); yield return new RectangleF(area.X, bottomY, pl, pb); yield return new RectangleF(leftX, bottomY, centerW, pb); yield return new RectangleF(rightX, bottomY, pr, pb); } } /// /// A set of extensions that allow for rendering /// public static class NinePatchExtensions { /// /// Draws a nine patch area using the given sprite batch /// /// The batch to draw with /// The nine patch to draw /// The area that should be covered by this nine patch /// The color to use /// The rotation /// The origin position /// The effects that the sprite should have /// The depth /// The scale of each area of the nine patch public static void Draw(this SpriteBatch batch, NinePatch texture, RectangleF destinationRectangle, Color color, float rotation, Vector2 origin, SpriteEffects effects, float layerDepth, float patchScale = 1) { var dest = texture.CreateRectangles(destinationRectangle, patchScale); var count = 0; foreach (var rect in dest) { if (!rect.IsEmpty) batch.Draw(texture.Region.Texture, rect, texture.SourceRectangles[count], color, rotation, origin, effects, layerDepth); count++; } } /// public static void Draw(this SpriteBatch batch, NinePatch texture, Rectangle destinationRectangle, Color color, float rotation, Vector2 origin, SpriteEffects effects, float layerDepth, float patchScale = 1) { batch.Draw(texture, (RectangleF) destinationRectangle, color, rotation, origin, effects, layerDepth, patchScale); } /// public static void Draw(this SpriteBatch batch, NinePatch texture, RectangleF destinationRectangle, Color color, float patchScale = 1) { batch.Draw(texture, destinationRectangle, color, 0, Vector2.Zero, SpriteEffects.None, 0, patchScale); } /// public static void Draw(this SpriteBatch batch, NinePatch texture, Rectangle destinationRectangle, Color color, float patchScale = 1) { batch.Draw(texture, destinationRectangle, color, 0, Vector2.Zero, SpriteEffects.None, 0, patchScale); } } }