Skip to content

Instantly share code, notes, and snippets.

@TinkerWorX
Created April 18, 2020 13:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save TinkerWorX/049860022a125c79f3c8bcb2b7473817 to your computer and use it in GitHub Desktop.
Save TinkerWorX/049860022a125c79f3c8bcb2b7473817 to your computer and use it in GitHub Desktop.
public class TileAtlas : IReadOnlyList<Rectangle>
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Rectangle IndexToRectangle(int index, int stride, int tileSize) => new Rectangle((index % stride) * tileSize, (index / stride) * tileSize, tileSize, tileSize);
private readonly int stride;
private readonly int colorCount;
public TileAtlas(GraphicsDevice graphicsDevice, int tileSize, int atlasSize = 4096)
{
this.stride = atlasSize / tileSize;
this.colorCount = (int)Math.Pow(tileSize, 2);
this.Capacity = (int)Math.Pow(this.stride, 2);
this.TileSize = tileSize;
this.Texture = new Texture2D(graphicsDevice, atlasSize, atlasSize, false, SurfaceFormat.Color);
this.Add(Enumerable.Repeat(Color.Transparent, this.colorCount).ToArray());
}
public int TileSize { get; }
public Texture2D Texture { get; }
public int Capacity { get; }
public int Count { get; private set; }
public Rectangle this[int index]
{
get
{
if (index < 0 || index >= this.Capacity)
{
throw new IndexOutOfRangeException();
}
return IndexToRectangle(index, this.stride, this.TileSize);
}
}
public int Add(Color[] data)
{
var index = this.Count;
if (index >= this.Capacity)
{
throw new InvalidOperationException("TileAtlas is at max capacity.");
}
this.Count++;
this.Texture.SetData(0, IndexToRectangle(index, this.stride, this.TileSize), data, 0, this.colorCount);
return index;
}
public (int firstId, int lastId) AddSet(Texture2D texture)
{
var colors = new Color[this.colorCount];
var tilesWide = texture.Width / this.TileSize;
var tilesHigh = texture.Height / this.TileSize;
int? firstIndex = null;
int? lastIndex = null;
for (var y = 0; y < tilesHigh; y++)
{
for (var x = 0; x < tilesWide; x++)
{
var rect = IndexToRectangle((y * tilesWide) + x, tilesWide, this.TileSize);
texture.GetData(0, rect, colors, 0, this.colorCount);
if (!firstIndex.HasValue)
{
lastIndex = firstIndex = this.Add(colors);
}
else
{
lastIndex = this.Add(colors);
}
}
}
return (firstIndex.Value, lastIndex.Value);
}
public void Set(int index, Color[] data)
{
if (index < 0 || index >= this.Capacity)
{
throw new ArgumentOutOfRangeException(nameof(index));
}
this.Texture.SetData(0, IndexToRectangle(index, this.stride, this.TileSize), data, 0, this.colorCount);
}
public void Clear()
{
this.Count = 1;
}
public IEnumerator<Rectangle> GetEnumerator()
{
for (var i = 0; i < this.Count; i++)
{
yield return IndexToRectangle(i, this.stride, this.TileSize);
}
}
IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment