2019-08-09 15:15:22 +02:00
using System.Collections.Generic ;
using System.Linq ;
using Microsoft.Xna.Framework ;
using Microsoft.Xna.Framework.Graphics ;
2019-08-11 21:38:03 +02:00
using MLEM.Extensions ;
2019-11-02 14:53:59 +01:00
using MLEM.Misc ;
2019-08-09 15:15:22 +02:00
namespace MLEM.Textures {
2020-05-21 17:21:34 +02:00
/// <summary>
/// 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.
/// </summary>
2020-03-21 00:49:43 +01:00
public class NinePatch : GenericDataHolder {
2019-08-09 15:15:22 +02:00
2020-05-21 17:21:34 +02:00
/// <summary>
/// The texture region of this nine patch
/// </summary>
2019-08-09 15:15:22 +02:00
public readonly TextureRegion Region ;
2020-05-21 17:21:34 +02:00
/// <summary>
/// The padding in each direction that marks where the outline area stops
/// </summary>
2019-12-14 14:00:12 +01:00
public readonly Padding Padding ;
2020-05-21 17:21:34 +02:00
/// <summary>
/// The nine patches that result from the <see cref="Padding"/>
/// </summary>
2019-08-09 15:15:22 +02:00
public readonly Rectangle [ ] SourceRectangles ;
2020-05-21 17:21:34 +02:00
/// <summary>
/// Creates a new nine patch from a texture and a padding
/// </summary>
/// <param name="texture">The texture to use</param>
/// <param name="padding">The padding that marks where the outline area stops</param>
2019-12-14 14:00:12 +01:00
public NinePatch ( TextureRegion texture , Padding padding ) {
2019-08-09 15:15:22 +02:00
this . Region = texture ;
2019-12-14 14:00:12 +01:00
this . Padding = padding ;
2019-08-09 15:15:22 +02:00
this . SourceRectangles = this . CreateRectangles ( this . Region . Area ) . ToArray ( ) ;
}
2020-05-21 17:21:34 +02:00
/// <summary>
/// Creates a new nine patch from a texture and a padding
/// </summary>
/// <param name="texture">The texture to use</param>
/// <param name="paddingLeft">The padding on the left edge</param>
/// <param name="paddingRight">The padding on the right edge</param>
/// <param name="paddingTop">The padding on the top edge</param>
/// <param name="paddingBottom">The padding on the bottom edge</param>
2019-12-14 14:00:12 +01:00
public NinePatch ( TextureRegion texture , int paddingLeft , int paddingRight , int paddingTop , int paddingBottom ) :
this ( texture , new Padding ( paddingLeft , paddingRight , paddingTop , paddingBottom ) ) {
}
2020-05-21 17:21:34 +02:00
/// <inheritdoc cref="NinePatch(TextureRegion, int, int, int, int)"/>
2019-08-09 15:15:22 +02:00
public NinePatch ( Texture2D texture , int paddingLeft , int paddingRight , int paddingTop , int paddingBottom ) :
this ( new TextureRegion ( texture ) , paddingLeft , paddingRight , paddingTop , paddingBottom ) {
}
2020-05-21 17:21:34 +02:00
/// <summary>
/// Creates a new nine patch from a texture and a uniform padding
/// </summary>
/// <param name="texture">The texture to use</param>
/// <param name="padding">The padding that each edge should have</param>
2019-08-10 21:37:10 +02:00
public NinePatch ( Texture2D texture , int padding ) : this ( new TextureRegion ( texture ) , padding ) {
}
2020-05-21 17:21:34 +02:00
/// <inheritdoc cref="NinePatch(TextureRegion, int)"/>
2019-08-09 15:15:22 +02:00
public NinePatch ( TextureRegion texture , int padding ) : this ( texture , padding , padding , padding , padding ) {
}
2020-05-21 17:21:34 +02:00
private IEnumerable < Rectangle > CreateRectangles ( Rectangle area , float patchScale = 1 ) {
2019-11-02 14:53:59 +01:00
return this . CreateRectangles ( ( RectangleF ) area , patchScale ) . Select ( r = > ( Rectangle ) r ) ;
}
2020-05-21 17:21:34 +02:00
internal IEnumerable < RectangleF > CreateRectangles ( RectangleF area , float patchScale = 1 ) {
2020-04-26 16:10:32 +02:00
var pl = this . Padding . Left * patchScale ;
var pr = this . Padding . Right * patchScale ;
var pt = this . Padding . Top * patchScale ;
var pb = this . Padding . Bottom * patchScale ;
2019-08-09 15:15:22 +02:00
2019-08-11 21:38:03 +02:00
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 ;
2019-11-02 14:53:59 +01:00
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 ) ;
2019-08-09 15:15:22 +02:00
}
}
2020-05-21 17:21:34 +02:00
/// <summary>
/// A set of extensions that allow for <see cref="NinePatch"/> rendering
/// </summary>
2019-08-09 15:15:22 +02:00
public static class NinePatchExtensions {
2020-05-21 17:21:34 +02:00
/// <summary>
/// Draws a nine patch area using the given sprite batch
/// </summary>
/// <param name="batch">The batch to draw with</param>
/// <param name="texture">The nine patch to draw</param>
/// <param name="destinationRectangle">The area that should be covered by this nine patch</param>
/// <param name="color">The color to use</param>
/// <param name="rotation">The rotation</param>
/// <param name="origin">The origin position</param>
/// <param name="effects">The effects that the sprite should have</param>
/// <param name="layerDepth">The depth</param>
/// <param name="patchScale">The scale of each area of the nine patch</param>
2019-11-02 14:53:59 +01:00
public static void Draw ( this SpriteBatch batch , NinePatch texture , RectangleF destinationRectangle , Color color , float rotation , Vector2 origin , SpriteEffects effects , float layerDepth , float patchScale = 1 ) {
2019-08-11 21:38:03 +02:00
var dest = texture . CreateRectangles ( destinationRectangle , patchScale ) ;
2019-08-09 15:15:22 +02:00
var count = 0 ;
foreach ( var rect in dest ) {
2019-08-09 19:28:48 +02:00
if ( ! rect . IsEmpty )
batch . Draw ( texture . Region . Texture , rect , texture . SourceRectangles [ count ] , color , rotation , origin , effects , layerDepth ) ;
2019-08-09 15:15:22 +02:00
count + + ;
}
}
2020-05-21 17:21:34 +02:00
/// <inheritdoc cref="Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch,MLEM.Textures.NinePatch,MLEM.Misc.RectangleF,Microsoft.Xna.Framework.Color,float,Microsoft.Xna.Framework.Vector2,Microsoft.Xna.Framework.Graphics.SpriteEffects,float,float)"/>
2019-11-02 14:53:59 +01:00
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 ) ;
}
2020-05-21 17:21:34 +02:00
/// <inheritdoc cref="Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch,MLEM.Textures.NinePatch,MLEM.Misc.RectangleF,Microsoft.Xna.Framework.Color,float,Microsoft.Xna.Framework.Vector2,Microsoft.Xna.Framework.Graphics.SpriteEffects,float,float)"/>
2019-11-02 14:53:59 +01:00
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 ) ;
}
2020-05-21 17:21:34 +02:00
/// <inheritdoc cref="Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch,MLEM.Textures.NinePatch,MLEM.Misc.RectangleF,Microsoft.Xna.Framework.Color,float,Microsoft.Xna.Framework.Vector2,Microsoft.Xna.Framework.Graphics.SpriteEffects,float,float)"/>
2019-08-11 21:38:03 +02:00
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 ) ;
2019-08-09 15:15:22 +02:00
}
}
}