2019-09-11 20:50:21 +02:00
using System.Collections.Generic ;
using Microsoft.Xna.Framework ;
using Microsoft.Xna.Framework.Graphics ;
2020-03-21 00:49:43 +01:00
using MLEM.Misc ;
2019-09-11 20:50:21 +02:00
namespace MLEM.Textures {
2020-05-21 17:21:34 +02:00
/// <summary>
/// This class represents an atlas of <see cref="TextureRegion"/> 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.
/// </summary>
2020-03-21 00:49:43 +01:00
public class UniformTextureAtlas : GenericDataHolder {
2019-09-11 20:50:21 +02:00
2020-05-21 17:21:34 +02:00
/// <summary>
2020-12-19 14:34:30 +01:00
/// The <see cref="TextureRegion"/> that this uniform texture atlas uses as its basis.
/// In most cases, <see cref="Region"/> has the full area of the underlying <see cref="Texture"/>.
2020-05-21 17:21:34 +02:00
/// </summary>
2020-12-19 14:34:30 +01:00
public readonly TextureRegion Region ;
2020-05-21 17:21:34 +02:00
/// <summary>
/// The amount of sub-regions this atlas has in the x direction
/// </summary>
2019-09-11 20:50:21 +02:00
public readonly int RegionAmountX ;
2020-05-21 17:21:34 +02:00
/// <summary>
/// The amount of sub-regions this atlas has in the y direction
/// </summary>
2019-09-11 20:50:21 +02:00
public readonly int RegionAmountY ;
2020-05-21 17:21:34 +02:00
/// <summary>
/// The width of each region, based on the texture's width and the amount of regions
/// </summary>
2019-12-05 20:43:31 +01:00
public readonly int RegionWidth ;
2020-05-21 17:21:34 +02:00
/// <summary>
/// The height of reach region, based on the texture's height and the amount of regions
/// </summary>
2019-12-05 20:43:31 +01:00
public readonly int RegionHeight ;
2020-05-21 17:21:34 +02:00
/// <summary>
2020-12-19 14:34:30 +01:00
/// The texture to use for this atlas.
/// Note that <see cref="Region"/> stores the actual area that we depend on.
/// </summary>
public Texture2D Texture = > this . Region . Texture ;
/// <summary>
2020-05-21 17:21:34 +02:00
/// Returns the <see cref="TextureRegion"/> at this texture atlas's given index.
/// The index is zero-based, where rows come first and columns come second.
/// </summary>
/// <param name="index">The zero-based texture index</param>
2020-01-03 15:51:31 +01:00
public TextureRegion this [ int index ] = > this [ index % this . RegionAmountX , index / this . RegionAmountX ] ;
2020-05-21 17:21:34 +02:00
/// <summary>
/// Returns the <see cref="TextureRegion"/> at this texture atlas' given region position
/// </summary>
/// <param name="point">The region's x and y location</param>
2019-12-05 20:43:31 +01:00
public TextureRegion this [ Point point ] = > this [ new Rectangle ( point , new Point ( 1 , 1 ) ) ] ;
2020-05-21 17:21:34 +02:00
/// <inheritdoc cref="this[Point]"/>
2019-09-11 20:50:21 +02:00
public TextureRegion this [ int x , int y ] = > this [ new Point ( x , y ) ] ;
2020-05-21 17:21:34 +02:00
/// <summary>
/// Returns the <see cref="TextureRegion"/> at this texture atlas' given region position and size.
/// Note that the region size is not in pixels, but in region units.
/// </summary>
/// <param name="rect">The region's area</param>
2019-12-05 20:43:31 +01:00
public TextureRegion this [ Rectangle rect ] = > this . GetOrAddRegion ( rect ) ;
2020-05-21 17:21:34 +02:00
/// <inheritdoc cref="this[Rectangle]"/>
2019-12-05 20:43:31 +01:00
public TextureRegion this [ int x , int y , int width , int height ] = > this [ new Rectangle ( x , y , width , height ) ] ;
2019-09-11 20:50:21 +02:00
2019-12-05 20:43:31 +01:00
private readonly Dictionary < Rectangle , TextureRegion > regions = new Dictionary < Rectangle , TextureRegion > ( ) ;
2019-09-11 20:50:21 +02:00
2020-05-21 17:21:34 +02:00
/// <summary>
2020-12-19 14:34:30 +01:00
/// Creates a new uniform texture atlas with the given texture region and region amount.
/// This atlas will only ever pull information from the given <see cref="TextureRegion"/> and never exit the region's bounds.
2020-05-21 17:21:34 +02:00
/// </summary>
2020-12-19 14:34:30 +01:00
/// <param name="region">The texture region to use for this atlas</param>
2020-05-21 17:21:34 +02:00
/// <param name="regionAmountX">The amount of texture regions in the x direction</param>
/// <param name="regionAmountY">The amount of texture regions in the y direction</param>
2020-12-19 14:34:30 +01:00
public UniformTextureAtlas ( TextureRegion region , int regionAmountX , int regionAmountY ) {
this . Region = region ;
2019-09-11 20:50:21 +02:00
this . RegionAmountX = regionAmountX ;
this . RegionAmountY = regionAmountY ;
2020-12-19 14:34:30 +01:00
this . RegionWidth = region . Width / regionAmountX ;
this . RegionHeight = region . Height / regionAmountY ;
}
/// <summary>
/// Creates a new uniform texture atlas with the given texture and region amount.
/// </summary>
/// <param name="texture">The texture to use for this atlas</param>
/// <param name="regionAmountX">The amount of texture regions in the x direction</param>
/// <param name="regionAmountY">The amount of texture regions in the y direction</param>
public UniformTextureAtlas ( Texture2D texture , int regionAmountX , int regionAmountY ) :
this ( new TextureRegion ( texture ) , regionAmountX , regionAmountY ) {
2019-12-05 20:43:31 +01:00
}
2019-09-11 20:50:21 +02:00
2019-12-05 20:43:31 +01:00
private TextureRegion GetOrAddRegion ( Rectangle rect ) {
if ( this . regions . TryGetValue ( rect , out var region ) )
return region ;
2020-12-19 14:34:30 +01:00
region = new TextureRegion ( this . Region ,
2019-12-05 20:43:31 +01:00
rect . X * this . RegionWidth , rect . Y * this . RegionHeight ,
rect . Width * this . RegionWidth , rect . Height * this . RegionHeight ) ;
this . regions . Add ( rect , region ) ;
return region ;
2019-09-11 20:50:21 +02:00
}
}
}