diff --git a/MoonWorks.Test.Common/Content/Shaders/Compiled/InstancedSpriteBatch.frag.refresh b/MoonWorks.Test.Common/Content/Shaders/Compiled/InstancedSpriteBatch.frag.refresh
new file mode 100644
index 0000000..ec6a133
Binary files /dev/null and b/MoonWorks.Test.Common/Content/Shaders/Compiled/InstancedSpriteBatch.frag.refresh differ
diff --git a/MoonWorks.Test.Common/Content/Shaders/Compiled/InstancedSpriteBatch.vert.refresh b/MoonWorks.Test.Common/Content/Shaders/Compiled/InstancedSpriteBatch.vert.refresh
index 6e5a784..3e39bfc 100644
Binary files a/MoonWorks.Test.Common/Content/Shaders/Compiled/InstancedSpriteBatch.vert.refresh and b/MoonWorks.Test.Common/Content/Shaders/Compiled/InstancedSpriteBatch.vert.refresh differ
diff --git a/MoonWorks.Test.Common/Content/Shaders/Source/InstancedSpriteBatch.frag b/MoonWorks.Test.Common/Content/Shaders/Source/InstancedSpriteBatch.frag
new file mode 100644
index 0000000..5e44f9b
--- /dev/null
+++ b/MoonWorks.Test.Common/Content/Shaders/Source/InstancedSpriteBatch.frag
@@ -0,0 +1,13 @@
+#version 450
+
+layout(location = 0) in vec2 inTexCoord;
+layout(location = 1) in vec4 inColor;
+
+layout(location = 0) out vec4 FragColor;
+
+layout(binding = 0, set = 1) uniform sampler2D Sampler;
+
+void main()
+{
+ FragColor = texture(Sampler, inTexCoord) * inColor;
+}
diff --git a/MoonWorks.Test.Common/Content/Shaders/Source/InstancedSpriteBatch.vert b/MoonWorks.Test.Common/Content/Shaders/Source/InstancedSpriteBatch.vert
index 43031a4..5134748 100644
--- a/MoonWorks.Test.Common/Content/Shaders/Source/InstancedSpriteBatch.vert
+++ b/MoonWorks.Test.Common/Content/Shaders/Source/InstancedSpriteBatch.vert
@@ -27,19 +27,19 @@ void main()
float c = cos(Rotation);
float s = sin(Rotation);
mat4 Rotation = mat4(
- c, -s, 0, 0,
- s, c, 0, 0,
+ c, s, 0, 0,
+ -s, c, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
);
mat4 Translation = mat4(
- 1, 0, 0, Position.x,
- 0, 1, 0, Position.y,
- 0, 0, 1, Position.z,
- 0, 0, 0, 1
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ Translation.x, Translation.y, Translation.z, 1
);
- mat4 Model = Scale * Rotation * Translation;
- gl_Position = Model * View * Projection * vec4(Position, 1);
+ mat4 Model = Translation * Rotation * Scale;
+ gl_Position = Projection * View * Model * vec4(Position, 1);
outTexCoord = UV[gl_VertexIndex % 4];
outVertexColor = Color;
}
diff --git a/MoonWorks.Test.Common/CopyMoonlibs.targets b/MoonWorks.Test.Common/CopyMoonlibs.targets
index 89671bc..599dc52 100644
--- a/MoonWorks.Test.Common/CopyMoonlibs.targets
+++ b/MoonWorks.Test.Common/CopyMoonlibs.targets
@@ -5,32 +5,20 @@
-
-
- %(RecursiveDir)%(Filename)%(Extension)
- PreserveNewest
-
-
-
- %(RecursiveDir)%(Filename)%(Extension)
- PreserveNewest
-
-
-
-
+
%(RecursiveDir)%(Filename)%(Extension)
PreserveNewest
-
+
%(RecursiveDir)%(Filename)%(Extension)
PreserveNewest
-
+
%(RecursiveDir)%(Filename)%(Extension)
PreserveNewest
-
+
%(RecursiveDir)%(Filename)%(Extension)
PreserveNewest
@@ -48,7 +36,7 @@
%(RecursiveDir)%(Filename)%(Extension)
PreserveNewest
-
+
%(RecursiveDir)%(Filename)%(Extension)
PreserveNewest
diff --git a/SpriteBatch/SpriteBatchGame.cs b/SpriteBatch/SpriteBatchGame.cs
index 8ff102a..712434b 100644
--- a/SpriteBatch/SpriteBatchGame.cs
+++ b/SpriteBatch/SpriteBatchGame.cs
@@ -1,5 +1,6 @@
using System;
using MoonWorks.Graphics;
+using MoonWorks.Math;
using MoonWorks.Math.Float;
namespace MoonWorks.Test
@@ -10,14 +11,23 @@ namespace MoonWorks.Test
Graphics.Buffer quadVertexBuffer;
Graphics.Buffer quadIndexBuffer;
SpriteBatch SpriteBatch;
+ Texture Texture;
+ Sampler Sampler;
+
+ Matrix4x4 View;
+ Matrix4x4 Projection;
+
+ Random Random;
public unsafe SpriteBatchGame() : base(TestUtils.GetStandardWindowCreateInfo(), TestUtils.GetStandardFrameLimiterSettings(), 60, true)
{
+ Random = new Random();
+
ShaderModule vertShaderModule = new ShaderModule(GraphicsDevice, TestUtils.GetShaderPath("InstancedSpriteBatch.vert"));
ShaderModule fragShaderModule = new ShaderModule(GraphicsDevice, TestUtils.GetShaderPath("InstancedSpriteBatch.frag"));
var vertexBufferDescription = VertexBindingAndAttributes.Create(0);
- var instanceBufferDescription = VertexBindingAndAttributes.Create(1, VertexInputRate.Instance);
+ var instanceBufferDescription = VertexBindingAndAttributes.Create(1, 1, VertexInputRate.Instance);
GraphicsPipelineCreateInfo pipelineCreateInfo = TestUtils.GetStandardGraphicsPipelineCreateInfo(
MainWindow.SwapchainFormat,
@@ -25,6 +35,9 @@ namespace MoonWorks.Test
fragShaderModule
);
+ pipelineCreateInfo.VertexShaderInfo = GraphicsShaderInfo.Create(vertShaderModule, "main", 0);
+ pipelineCreateInfo.FragmentShaderInfo = GraphicsShaderInfo.Create(fragShaderModule, "main", 1);
+
pipelineCreateInfo.VertexInputState = new VertexInputState([
vertexBufferDescription,
instanceBufferDescription
@@ -32,6 +45,9 @@ namespace MoonWorks.Test
spriteBatchPipeline = new GraphicsPipeline(GraphicsDevice, pipelineCreateInfo);
+ Texture = Texture.CreateTexture2D(GraphicsDevice, 1, 1, TextureFormat.R8G8B8A8, TextureUsageFlags.Sampler);
+ Sampler = new Sampler(GraphicsDevice, SamplerCreateInfo.PointClamp);
+
quadVertexBuffer = Graphics.Buffer.Create(GraphicsDevice, BufferUsageFlags.Vertex, 4);
quadIndexBuffer = Graphics.Buffer.Create(GraphicsDevice, BufferUsageFlags.Index, 6);
@@ -50,9 +66,40 @@ namespace MoonWorks.Test
var cmdbuf = GraphicsDevice.AcquireCommandBuffer();
cmdbuf.SetBufferData(quadVertexBuffer, new Span(vertices, 4));
cmdbuf.SetBufferData(quadIndexBuffer, new Span(indices, 6));
+ cmdbuf.SetTextureData(Texture, new Color[1] { Color.White });
GraphicsDevice.Submit(cmdbuf);
SpriteBatch = new SpriteBatch(GraphicsDevice);
+
+ // View = Matrix4x4.CreateLookAt(
+ // new Vector3(0, 0, -1),
+ // Vector3.Zero,
+ // Vector3.Up
+ // );
+
+ //View = Matrix4x4.Identity;
+
+ View = Matrix4x4.CreateLookAt(
+ new Vector3(0, 0, 1),
+ Vector3.Zero,
+ Vector3.Up
+ );
+
+ Projection = Matrix4x4.CreateOrthographicOffCenter(
+ 0,
+ MainWindow.Width,
+ MainWindow.Height,
+ 0,
+ 0.01f,
+ 10
+ );
+
+ // Projection = Matrix4x4.CreatePerspectiveFieldOfView(
+ // MathHelper.ToRadians(75f),
+ // (float) MainWindow.Width / MainWindow.Height,
+ // 0.01f,
+ // 1000
+ // );
}
protected override void Update(TimeSpan delta)
@@ -66,21 +113,25 @@ namespace MoonWorks.Test
Texture? swapchain = cmdbuf.AcquireSwapchainTexture(MainWindow);
if (swapchain != null)
{
+ SpriteBatch.Reset();
+
for (var i = 0; i < 1024; i += 1)
{
- SpriteBatch.Add()
+ var position = new Vector3(Random.Next((int) MainWindow.Width), Random.Next((int) MainWindow.Height), 1);
+ SpriteBatch.Add(
+ position,
+ 0f,
+ new Vector2(100, 100),
+ new Color(Random.Next(255), Random.Next(255), Random.Next(255)),
+ new Vector2(0, 0),
+ new Vector2(1, 1)
+ );
}
SpriteBatch.Upload(cmdbuf);
cmdbuf.BeginRenderPass(new ColorAttachmentInfo(swapchain, Color.Black));
- cmdbuf.BindGraphicsPipeline(spriteBatchPipeline);
- cmdbuf.BindVertexBuffers(
- new BufferBinding(quadVertexBuffer, 0),
- new BufferBinding(SpriteBatch.BatchBuffer, 0)
- );
- cmdbuf.BindIndexBuffer(quadIndexBuffer, IndexElementSize.Sixteen);
- cmdbuf.DrawInstancedPrimitives(0, 0, SpriteBatch.Index * 2, SpriteBatch.Index, );
+ SpriteBatch.Render(cmdbuf, spriteBatchPipeline, Texture, Sampler, quadVertexBuffer, quadIndexBuffer, new ViewProjectionMatrices(View, Projection));
cmdbuf.EndRenderPass();
}
GraphicsDevice.Submit(cmdbuf);
@@ -93,6 +144,8 @@ namespace MoonWorks.Test
}
}
+ public readonly record struct ViewProjectionMatrices(Matrix4x4 View, Matrix4x4 Projection);
+
public struct SpriteInstanceData : IVertexType
{
public Vector3 Translation;
@@ -122,7 +175,9 @@ namespace MoonWorks.Test
GraphicsDevice GraphicsDevice;
public Graphics.Buffer BatchBuffer;
SpriteInstanceData[] InstanceDatas;
- int Index;
+ uint Index;
+
+ public uint InstanceCount => Index;
public SpriteBatch(GraphicsDevice graphicsDevice)
{
@@ -132,23 +187,52 @@ namespace MoonWorks.Test
Index = 0;
}
- public void Add(Vector3 position, float rotation, Vector2 size, Color color)
+ public void Reset()
{
+ Index = 0;
+ }
+
+ public void Add(
+ Vector3 position,
+ float rotation,
+ Vector2 size,
+ Color color,
+ Vector2 leftTopUV,
+ Vector2 dimensionsUV
+ ) {
+ var left = leftTopUV.X;
+ var top = leftTopUV.Y;
+ var right = leftTopUV.X + dimensionsUV.X;
+ var bottom = leftTopUV.Y + dimensionsUV.Y;
+
InstanceDatas[Index].Translation = position;
InstanceDatas[Index].Rotation = rotation;
InstanceDatas[Index].Scale = size;
InstanceDatas[Index].Color = color;
- InstanceDatas[Index].UV0 = new Vector2(0, 0);
- InstanceDatas[Index].UV1 = new Vector2(0, 1);
- InstanceDatas[Index].UV2 = new Vector2(1, 0);
- InstanceDatas[Index].UV3 = new Vector2(1, 1);
+ InstanceDatas[Index].UV0 = leftTopUV;
+ InstanceDatas[Index].UV1 = new Vector2(left, bottom);
+ InstanceDatas[Index].UV2 = new Vector2(right, top);
+ InstanceDatas[Index].UV3 = new Vector2(right, bottom);
Index += 1;
}
public void Upload(CommandBuffer commandBuffer)
{
commandBuffer.SetBufferData(BatchBuffer, InstanceDatas, 0, 0, (uint) Index);
- Index = 0;
+ }
+
+ public void Render(CommandBuffer commandBuffer, GraphicsPipeline pipeline, Texture texture, Sampler sampler, Graphics.Buffer quadVertexBuffer, Graphics.Buffer quadIndexBuffer, ViewProjectionMatrices viewProjectionMatrices)
+ {
+ commandBuffer.BindGraphicsPipeline(pipeline);
+ commandBuffer.BindFragmentSamplers(new TextureSamplerBinding(texture, sampler));
+ commandBuffer.BindVertexBuffers(
+ new BufferBinding(quadVertexBuffer, 0),
+ new BufferBinding(BatchBuffer, 0)
+ );
+ commandBuffer.BindIndexBuffer(quadIndexBuffer, IndexElementSize.Sixteen);
+ var vertParamOffset = commandBuffer.PushVertexShaderUniforms(viewProjectionMatrices);
+ commandBuffer.DrawInstancedPrimitives(0, 0, 2, InstanceCount, vertParamOffset, 0);
+
}
}
}