Update README.md to include project description, developer documentation links, and license information.
CI / build-test (push) Successful in 1m6s

This commit is contained in:
Leonid Pershin
2026-06-11 04:03:07 +03:00
parent 31aba3aeee
commit ff2231a8ab
72 changed files with 4113 additions and 0 deletions
+94
View File
@@ -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);
}
}