Skip to content

Instantly share code, notes, and snippets.

@thatcosmonaut
Last active March 17, 2022 06:42
Show Gist options
  • Select an option

  • Save thatcosmonaut/07436e267629450da04d9cd2aba623eb to your computer and use it in GitHub Desktop.

Select an option

Save thatcosmonaut/07436e267629450da04d9cd2aba623eb to your computer and use it in GitHub Desktop.
MoonWorks Sprite Batch Sample
public struct Position2DTextureVertex
{
public Vector2 Position;
public Vector2 TexCoord;
public Position2DTextureVertex(Vector2 position, Vector2 texcoord)
{
Position = position;
TexCoord = texcoord;
}
}
using MoonWorks.Graphics;
using MoonWorks.Math;
namespace SamuraiGunn2
{
public struct SpriteSubBatch
{
public uint VertexOffset;
public uint VertexCount;
public TextureSamplerBinding Binding;
}
public class SpriteBatch
{
public const int MAX_SPRITES = 1024;
private const int MAX_VERTICES = MAX_SPRITES * 4;
private const int MAX_INDICES = MAX_SPRITES * 6;
private Buffer VertexBuffer { get; }
private Buffer IndexBuffer { get; }
private readonly Position3DTextureVertex[] Vertices;
private static readonly ushort[] Indices = GenerateIndexArray();
private uint VertexCount { get; set; } = 0;
private SpriteSubBatch[] spriteSubBatches = new SpriteSubBatch[1];
private uint spriteSubBatchCount = 0;
public SpriteBatch(GraphicsDevice graphicsDevice)
{
Vertices = new Position3DTextureVertex[MAX_VERTICES];
VertexBuffer = Buffer.Create<Position3DTextureVertex>(graphicsDevice, BufferUsageFlags.Vertex, MAX_VERTICES);
IndexBuffer = Buffer.Create<ushort>(graphicsDevice, BufferUsageFlags.Index, MAX_INDICES);
var commandBuffer = graphicsDevice.AcquireCommandBuffer();
commandBuffer.SetBufferData(IndexBuffer, Indices);
graphicsDevice.Submit(commandBuffer);
}
public void Start(TextureSamplerBinding binding)
{
End();
if (spriteSubBatches.Length == spriteSubBatchCount)
{
System.Array.Resize(ref spriteSubBatches, spriteSubBatches.Length * 2);
}
spriteSubBatches[spriteSubBatchCount].VertexCount = 0;
spriteSubBatches[spriteSubBatchCount].VertexOffset = VertexCount;
spriteSubBatches[spriteSubBatchCount].Binding = binding;
spriteSubBatchCount += 1;
}
public void Add(Sprite sprite, float depth, Matrix3x2 transform)
{
var offset = new Vector2(sprite.FrameRect.X, sprite.FrameRect.Y);
Vertices[VertexCount].Position = new Vector3(Vector2.Transform(Vector2.Zero - offset, transform), depth);
Vertices[VertexCount].TexCoord = sprite.UV.LeftTop;
Vertices[VertexCount + 1].Position = new Vector3(Vector2.Transform(new Vector2(0, sprite.SliceRect.H) - offset, transform), depth);
Vertices[VertexCount + 1].TexCoord = sprite.UV.LeftBottom;
Vertices[VertexCount + 2].Position = new Vector3(Vector2.Transform(new Vector2(sprite.SliceRect.W, 0) - offset, transform), depth);
Vertices[VertexCount + 2].TexCoord = sprite.UV.RightTop;
Vertices[VertexCount + 3].Position = new Vector3(Vector2.Transform(new Vector2(sprite.SliceRect.W, sprite.SliceRect.H) - offset, transform), depth);
Vertices[VertexCount + 3].TexCoord = sprite.UV.RightBottom;
VertexCount += 4;
}
public void PushVertexData(CommandBuffer commandBuffer)
{
End();
commandBuffer.SetBufferData(VertexBuffer, Vertices, 0, 0, VertexCount);
}
private void End()
{
if (spriteSubBatchCount > 0)
{
spriteSubBatches[spriteSubBatchCount - 1].VertexCount = VertexCount - spriteSubBatches[spriteSubBatchCount - 1].VertexOffset;
}
}
public void Draw(CommandBuffer commandBuffer, uint vertexParamOffset = 0, uint fragmentParamOffset = 0)
{
commandBuffer.BindVertexBuffers(VertexBuffer);
commandBuffer.BindIndexBuffer(IndexBuffer, IndexElementSize.Sixteen);
for (var i = 0; i < spriteSubBatchCount; i += 1)
{
var spriteSubBatch = spriteSubBatches[i];
commandBuffer.BindFragmentSamplers(spriteSubBatch.Binding);
commandBuffer.DrawIndexedPrimitives(
spriteSubBatch.VertexOffset,
0,
spriteSubBatch.VertexCount / 2,
vertexParamOffset,
fragmentParamOffset
);
}
spriteSubBatchCount = 0;
VertexCount = 0;
}
private static ushort[] GenerateIndexArray()
{
var result = new ushort[MAX_INDICES];
for (int i = 0, j = 0; i < MAX_INDICES; i += 6, j += 4)
{
result[i] = (ushort)j;
result[i + 1] = (ushort)(j + 1);
result[i + 2] = (ushort)(j + 2);
result[i + 3] = (ushort)(j + 2);
result[i + 4] = (ushort)(j + 1);
result[i + 5] = (ushort)(j + 3);
}
return result;
}
}
}
public struct UV
{
public Vector2 Position { get; }
public Vector2 Dimensions { get; }
public Vector2 TopLeft { get; }
public Vector2 TopRight { get; }
public Vector2 BottomLeft { get; }
public Vector2 BottomRight { get; }
public UV(Vector2 position, Vector2 dimensions)
{
Position = position;
Dimensions = dimensions;
TopLeft = Position;
TopRight = Position + new Vector2(Dimensions.X, 0);
BottomLeft = Position + new Vector2(0, Dimensions.Y);
BottomRight = Position + new Vector2(Dimensions.X, Dimensions.Y);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment