Update README.md to include project description, developer documentation links, and license information.
CI / build-test (push) Successful in 1m6s
CI / build-test (push) Successful in 1m6s
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace MrGameEng.Graphics;
|
||||
|
||||
/// <summary>One sprite queued for rendering this frame.</summary>
|
||||
public struct SpriteInstance
|
||||
{
|
||||
/// <summary>Texture region to draw. Never null for submitted instances.</summary>
|
||||
public Texture2DRegion Region;
|
||||
|
||||
/// <summary>World-space (or screen-space) center of the quad.</summary>
|
||||
public Vector2 Center;
|
||||
|
||||
/// <summary>Half extents after scaling, in pixels. May be negative for negative scale.</summary>
|
||||
public Vector2 HalfSize;
|
||||
|
||||
/// <summary>Rotation in radians, clockwise.</summary>
|
||||
public float Rotation;
|
||||
|
||||
/// <summary>Tint color.</summary>
|
||||
public Color Color;
|
||||
|
||||
/// <summary>Mirroring flags.</summary>
|
||||
public SpriteFlip Flip;
|
||||
|
||||
/// <summary>Render layer the instance belongs to.</summary>
|
||||
public byte Layer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// CPU side of the renderer: collects <see cref="SpriteInstance"/>s with their sort keys
|
||||
/// and orders them layer → depth → texture. Allocation-free after warm-up
|
||||
/// (arrays grow geometrically and are reused across frames).
|
||||
/// </summary>
|
||||
public sealed class SpriteBatcher
|
||||
{
|
||||
private SpriteInstance[] _instances;
|
||||
private ulong[] _keys;
|
||||
private int[] _order;
|
||||
private int _count;
|
||||
|
||||
/// <summary>Creates a batcher with the given initial capacity.</summary>
|
||||
public SpriteBatcher(int initialCapacity = 2048)
|
||||
{
|
||||
_instances = new SpriteInstance[initialCapacity];
|
||||
_keys = new ulong[initialCapacity];
|
||||
_order = new int[initialCapacity];
|
||||
}
|
||||
|
||||
/// <summary>Number of sprites submitted this frame.</summary>
|
||||
public int Count => _count;
|
||||
|
||||
/// <summary>Queues one sprite.</summary>
|
||||
public void Submit(in SpriteInstance instance, ulong sortKey)
|
||||
{
|
||||
if (_count == _instances.Length)
|
||||
{
|
||||
Grow();
|
||||
}
|
||||
|
||||
_instances[_count] = instance;
|
||||
_keys[_count] = sortKey;
|
||||
_count++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sorts all submitted sprites and returns their indices in draw order.
|
||||
/// Valid until the next <see cref="Clear"/>.
|
||||
/// </summary>
|
||||
public ReadOnlySpan<int> Sort()
|
||||
{
|
||||
for (var i = 0; i < _count; i++)
|
||||
{
|
||||
_order[i] = i;
|
||||
}
|
||||
|
||||
Array.Sort(_keys, _order, 0, _count);
|
||||
return _order.AsSpan(0, _count);
|
||||
}
|
||||
|
||||
/// <summary>Returns the instance at <paramref name="index"/> (an index from <see cref="Sort"/>).</summary>
|
||||
public ref readonly SpriteInstance this[int index] => ref _instances[index];
|
||||
|
||||
/// <summary>Resets the batcher for the next frame. Keeps allocated capacity.</summary>
|
||||
public void Clear() => _count = 0;
|
||||
|
||||
private void Grow()
|
||||
{
|
||||
var capacity = _instances.Length * 2;
|
||||
Array.Resize(ref _instances, capacity);
|
||||
Array.Resize(ref _keys, capacity);
|
||||
Array.Resize(ref _order, capacity);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user