diff --git a/Mipmaps/Mipmaps.csproj b/Mipmaps/Mipmaps.csproj new file mode 100644 index 0000000..2868e63 --- /dev/null +++ b/Mipmaps/Mipmaps.csproj @@ -0,0 +1,17 @@ + + + + + + + + + Exe + net7.0 + enable + x64 + + + + + diff --git a/Mipmaps/MipmapsGame.cs b/Mipmaps/MipmapsGame.cs new file mode 100644 index 0000000..09b7664 --- /dev/null +++ b/Mipmaps/MipmapsGame.cs @@ -0,0 +1,194 @@ +using MoonWorks; +using MoonWorks.Graphics; +using MoonWorks.Math.Float; +using System.Runtime.InteropServices; + +namespace MoonWorks.Test +{ + class RenderTexture3DGame : Game + { + private GraphicsPipeline pipeline; + private Buffer vertexBuffer; + private Buffer indexBuffer; + private Texture texture; + + private Sampler[] samplers = new Sampler[5]; + + private float scale = 0.5f; + private int currentSamplerIndex = 0; + private Color[] colors = new Color[] + { + Color.Red, + Color.Green, + Color.Blue, + Color.Yellow, + }; + + private struct VertexUniforms + { + public Matrix4x4 TransformMatrix; + + public VertexUniforms(Matrix4x4 transformMatrix) + { + TransformMatrix = transformMatrix; + } + } + + private string GetSamplerString(int index) + { + switch (index) + { + case 0: + return "PointClamp"; + case 1: + return "LinearClamp"; + case 2: + return "PointClamp with Mip LOD Bias = 0.25"; + case 3: + return "PointClamp with Min LOD = 1"; + case 4: + return "PointClamp with Max LOD = 1"; + default: + throw new System.Exception("Unknown sampler!"); + } + } + + public RenderTexture3DGame() : base(TestUtils.GetStandardWindowCreateInfo(), TestUtils.GetStandardFrameLimiterSettings(), 60, true) + { + Logger.LogInfo("Press Left and Right to shrink/expand the scale of the quad"); + Logger.LogInfo("Press Down to cycle through sampler states"); + Logger.LogInfo(GetSamplerString(currentSamplerIndex)); + + // Load the shaders + ShaderModule vertShaderModule = new ShaderModule(GraphicsDevice, TestUtils.GetShaderPath("TexturedQuadVertWithMatrix")); + ShaderModule fragShaderModule = new ShaderModule(GraphicsDevice, TestUtils.GetShaderPath("TexturedQuadFrag")); + + // Create the graphics pipeline + GraphicsPipelineCreateInfo pipelineCreateInfo = TestUtils.GetStandardGraphicsPipelineCreateInfo( + MainWindow.SwapchainFormat, + vertShaderModule, + fragShaderModule + ); + pipelineCreateInfo.VertexInputState = VertexInputState.CreateSingleBinding(); + pipelineCreateInfo.VertexShaderInfo = GraphicsShaderInfo.Create(vertShaderModule, "main", 0); + pipelineCreateInfo.FragmentShaderInfo.SamplerBindingCount = 1; + pipeline = new GraphicsPipeline(GraphicsDevice, pipelineCreateInfo); + + // Create samplers + SamplerCreateInfo samplerCreateInfo = SamplerCreateInfo.PointClamp; + samplers[0] = new Sampler(GraphicsDevice, samplerCreateInfo); + + samplerCreateInfo = SamplerCreateInfo.LinearClamp; + samplers[1] = new Sampler(GraphicsDevice, samplerCreateInfo); + + samplerCreateInfo = SamplerCreateInfo.PointClamp; + samplerCreateInfo.MipLodBias = 0.25f; + samplers[2] = new Sampler(GraphicsDevice, samplerCreateInfo); + + samplerCreateInfo = SamplerCreateInfo.PointClamp; + samplerCreateInfo.MinLod = 1; + samplers[3] = new Sampler(GraphicsDevice, samplerCreateInfo); + + samplerCreateInfo = SamplerCreateInfo.PointClamp; + samplerCreateInfo.MaxLod = 1; + samplers[4] = new Sampler(GraphicsDevice, samplerCreateInfo); + + // Create and populate the GPU resources + vertexBuffer = Buffer.Create(GraphicsDevice, BufferUsageFlags.Vertex, 4); + indexBuffer = Buffer.Create(GraphicsDevice, BufferUsageFlags.Index, 6); + texture = Texture.CreateTexture2D( + GraphicsDevice, + MainWindow.Width, + MainWindow.Height, + TextureFormat.R8G8B8A8, + TextureUsageFlags.ColorTarget | TextureUsageFlags.Sampler, + 4 + ); + + CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); + cmdbuf.SetBufferData( + vertexBuffer, + new PositionTextureVertex[] + { + new PositionTextureVertex(new Vector3(-1, -1, 0), new Vector2(0, 0)), + new PositionTextureVertex(new Vector3(1, -1, 0), new Vector2(1, 0)), + new PositionTextureVertex(new Vector3(1, 1, 0), new Vector2(1, 1)), + new PositionTextureVertex(new Vector3(-1, 1, 0), new Vector2(0, 1)), + } + ); + cmdbuf.SetBufferData( + indexBuffer, + new ushort[] + { + 0, 1, 2, + 0, 2, 3, + } + ); + + // Clear each mip level to a different color + for (uint i = 0; i < texture.LevelCount; i += 1) + { + ColorAttachmentInfo attachmentInfo = new ColorAttachmentInfo + { + Texture = texture, + ClearColor = colors[i], + Depth = 0, + Layer = 0, + Level = i, + LoadOp = LoadOp.Clear, + StoreOp = StoreOp.Store, + SampleCount = SampleCount.One, + }; + cmdbuf.BeginRenderPass(attachmentInfo); + cmdbuf.EndRenderPass(); + } + + GraphicsDevice.Submit(cmdbuf); + } + + protected override void Update(System.TimeSpan delta) + { + if (TestUtils.CheckButtonDown(Inputs, TestUtils.ButtonType.Left)) + { + scale = System.MathF.Max(0.01f, scale - 0.01f); + } + + if (TestUtils.CheckButtonDown(Inputs, TestUtils.ButtonType.Right)) + { + scale = System.MathF.Min(1f, scale + 0.01f); + } + + if (TestUtils.CheckButtonPressed(Inputs, TestUtils.ButtonType.Bottom)) + { + currentSamplerIndex = (currentSamplerIndex + 1) % samplers.Length; + Logger.LogInfo(GetSamplerString(currentSamplerIndex)); + } + } + + protected override void Draw(double alpha) + { + VertexUniforms vertUniforms = new VertexUniforms(Matrix4x4.CreateScale(scale, scale, 1)); + + CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); + Texture? backbuffer = cmdbuf.AcquireSwapchainTexture(MainWindow); + if (backbuffer != null) + { + cmdbuf.BeginRenderPass(new ColorAttachmentInfo(backbuffer, Color.Black)); + cmdbuf.BindGraphicsPipeline(pipeline); + cmdbuf.BindVertexBuffers(vertexBuffer); + cmdbuf.BindIndexBuffer(indexBuffer, IndexElementSize.Sixteen); + cmdbuf.BindFragmentSamplers(new TextureSamplerBinding(texture, samplers[currentSamplerIndex])); + uint vertParamOffset = cmdbuf.PushVertexShaderUniforms(vertUniforms); + cmdbuf.DrawIndexedPrimitives(0, 0, 2, vertParamOffset, 0); + cmdbuf.EndRenderPass(); + } + GraphicsDevice.Submit(cmdbuf); + } + + public static void Main(string[] args) + { + RenderTexture3DGame game = new RenderTexture3DGame(); + game.Run(); + } + } +} diff --git a/MoonWorksGraphicsTests.sln b/MoonWorksGraphicsTests.sln index 917fe76..8702199 100644 --- a/MoonWorksGraphicsTests.sln +++ b/MoonWorksGraphicsTests.sln @@ -49,6 +49,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RenderTexture3D", "RenderTe EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RenderTextureCube", "RenderTextureCube\RenderTextureCube.csproj", "{D7A8452F-123F-4965-8716-9E39F677A831}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mipmaps", "Mipmaps\Mipmaps.csproj", "{35DF0819-2373-4A8D-91E5-B143994FB63B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -147,6 +149,10 @@ Global {D7A8452F-123F-4965-8716-9E39F677A831}.Debug|x64.Build.0 = Debug|x64 {D7A8452F-123F-4965-8716-9E39F677A831}.Release|x64.ActiveCfg = Release|Any CPU {D7A8452F-123F-4965-8716-9E39F677A831}.Release|x64.Build.0 = Release|Any CPU + {35DF0819-2373-4A8D-91E5-B143994FB63B}.Debug|x64.ActiveCfg = Debug|x64 + {35DF0819-2373-4A8D-91E5-B143994FB63B}.Debug|x64.Build.0 = Debug|x64 + {35DF0819-2373-4A8D-91E5-B143994FB63B}.Release|x64.ActiveCfg = Release|Any CPU + {35DF0819-2373-4A8D-91E5-B143994FB63B}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/README.md b/README.md index 395ab35..145dd0d 100644 --- a/README.md +++ b/README.md @@ -83,3 +83,7 @@ Fades through 2D slices of a 3D render texture. Tests binding and sampling 3D re **RenderTextureCube** Displays a cubemap generated by rendering to a cube render target. Tests binding and sampling cube render textures. + +**Mipmaps** + +Displays a quad that can be scaled to reveal various mip levels. The mips are solid colors, generated by clearing various levels of the texture. Tests rendering to mipmap levels of a texture and rendering mipmaps.