diff --git a/MLEM/Textures/NinePatch.cs b/MLEM/Textures/NinePatch.cs index 2f1aa3b..cf6ad83 100644 --- a/MLEM/Textures/NinePatch.cs +++ b/MLEM/Textures/NinePatch.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using Microsoft.Xna.Framework; @@ -8,7 +9,8 @@ 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. + /// 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 or tiled, while the outline of the texture will remain at its original size, keeping aspect ratios alive. + /// The nine patch can then be drawn using . /// public class NinePatch : GenericDataHolder { @@ -21,6 +23,10 @@ namespace MLEM.Textures { /// public readonly Padding Padding; /// + /// The that this nine patch should use for drawing + /// + public readonly NinePatchMode Mode; + /// /// The nine patches that result from the /// public readonly Rectangle[] SourceRectangles; @@ -30,9 +36,11 @@ namespace MLEM.Textures { /// /// The texture to use /// The padding that marks where the outline area stops - public NinePatch(TextureRegion texture, Padding padding) { + /// The mode to use for drawing this nine patch, defaults to + public NinePatch(TextureRegion texture, Padding padding, NinePatchMode mode = NinePatchMode.Stretch) { this.Region = texture; this.Padding = padding; + this.Mode = mode; this.SourceRectangles = this.CreateRectangles(this.Region.Area).ToArray(); } @@ -44,13 +52,14 @@ namespace MLEM.Textures { /// 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)) { + /// The mode to use for drawing this nine patch, defaults to + public NinePatch(TextureRegion texture, int paddingLeft, int paddingRight, int paddingTop, int paddingBottom, NinePatchMode mode = NinePatchMode.Stretch) : + this(texture, new Padding(paddingLeft, paddingRight, paddingTop, paddingBottom), mode) { } - /// - public NinePatch(Texture2D texture, int paddingLeft, int paddingRight, int paddingTop, int paddingBottom) : - this(new TextureRegion(texture), paddingLeft, paddingRight, paddingTop, paddingBottom) { + /// + public NinePatch(Texture2D texture, int paddingLeft, int paddingRight, int paddingTop, int paddingBottom, NinePatchMode mode = NinePatchMode.Stretch) : + this(new TextureRegion(texture), paddingLeft, paddingRight, paddingTop, paddingBottom, mode) { } /// @@ -58,15 +67,14 @@ namespace MLEM.Textures { /// /// The texture to use /// The padding that each edge should have - public NinePatch(Texture2D texture, int padding) : this(new TextureRegion(texture), padding) { + /// The mode to use for drawing this nine patch, defaults to + public NinePatch(Texture2D texture, int padding, NinePatchMode mode = NinePatchMode.Stretch) : + this(new TextureRegion(texture), padding, mode) { } - /// - 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); + /// + public NinePatch(TextureRegion texture, int padding, NinePatchMode mode = NinePatchMode.Stretch) : + this(texture, padding, padding, padding, padding, mode) { } internal IEnumerable CreateRectangles(RectangleF area, float patchScale = 1) { @@ -93,6 +101,28 @@ namespace MLEM.Textures { yield return new RectangleF(rightX, bottomY, pr, pb); } + private IEnumerable CreateRectangles(Rectangle area, float patchScale = 1) { + return this.CreateRectangles((RectangleF) area, patchScale).Select(r => (Rectangle) r); + } + + } + + /// + /// An enumeration that represents the modes that a uses to be drawn + /// + public enum NinePatchMode { + + /// + /// The nine resulting patches will each be stretched. + /// This mode is fitting for textures that don't have an intricate design on their edges. + /// + Stretch, + /// + /// The nine resulting paches will be tiled, repeating the texture multiple times. + /// This mode is fitting for textures that have a more complex design on their edges. + /// + Tile + } /// @@ -113,11 +143,27 @@ namespace MLEM.Textures { /// 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 destinations = 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); + foreach (var rect in destinations) { + if (!rect.IsEmpty) { + var src = texture.SourceRectangles[count]; + switch (texture.Mode) { + case NinePatchMode.Stretch: + batch.Draw(texture.Region.Texture, rect, src, color, rotation, origin, effects, layerDepth); + break; + case NinePatchMode.Tile: + var width = src.Width * patchScale; + var height = src.Height * patchScale; + for (var x = 0F; x < rect.Width; x += width) { + for (var y = 0F; y < rect.Height; y += height) { + var size = new Vector2(Math.Min(rect.Width - x, width), Math.Min(rect.Height - y, height)); + batch.Draw(texture.Region.Texture, new RectangleF(rect.Location + new Vector2(x, y), size), new Rectangle(src.Location, (size / patchScale).ToPoint()), color, rotation, origin, effects, layerDepth); + } + } + break; + } + } count++; } }