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); + } } }