using System; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using MoonWorks; using MoonWorks.Graphics; using MoonWorks.Math; using MoonWorks.Window; namespace MoonWorksComputeSpriteBatch { public class TestGame : Game { private RenderTarget mainColorTarget; private GraphicsPipeline spritePipeline; private SpriteBatch spriteBatch; private Texture whitePixel; private Sampler sampler; private const int SPRITECOUNT = SpriteBatch.MAX_SPRITES; private Vector3[] positions = new Vector3[SPRITECOUNT]; private uint windowWidth; private uint windowHeight; private Random random = new Random(); public TestGame(WindowCreateInfo windowCreateInfo, PresentMode presentMode, int targetTimestep = 60, bool debugMode = false) : base(windowCreateInfo, presentMode, targetTimestep, debugMode) { windowWidth = windowCreateInfo.WindowWidth; windowHeight = windowCreateInfo.WindowHeight; var vertexShaderModule = new ShaderModule(GraphicsDevice, Path.Combine(Environment.CurrentDirectory, "Content", "sprite.vert.spv")); var fragmentShaderModule = new ShaderModule(GraphicsDevice, Path.Combine(Environment.CurrentDirectory, "Content", "sprite.frag.spv")); mainColorTarget = RenderTarget.CreateBackedRenderTarget( GraphicsDevice, windowWidth, windowHeight, TextureFormat.R8G8B8A8, false ); /* Pipeline */ ColorTargetBlendState[] colorTargetBlendStates = new ColorTargetBlendState[1] { ColorTargetBlendState.None }; ColorBlendState colorBlendState = new ColorBlendState { LogicOpEnable = false, LogicOp = LogicOp.NoOp, BlendConstants = new BlendConstants(), ColorTargetBlendStates = colorTargetBlendStates }; DepthStencilState depthStencilState = DepthStencilState.Disable; ShaderStageState vertexShaderState = new ShaderStageState { ShaderModule = vertexShaderModule, EntryPointName = "main", UniformBufferSize = (uint)Marshal.SizeOf() }; ShaderStageState fragmentShaderState = new ShaderStageState { ShaderModule = fragmentShaderModule, EntryPointName = "main", UniformBufferSize = 0 }; MultisampleState multisampleState = MultisampleState.None; GraphicsPipelineLayoutInfo pipelineLayoutInfo = new GraphicsPipelineLayoutInfo { VertexSamplerBindingCount = 0, FragmentSamplerBindingCount = 1 }; RasterizerState rasterizerState = RasterizerState.CCW_CullNone; var vertexBindings = new VertexBinding[1] { new VertexBinding { Binding = 0, InputRate = VertexInputRate.Vertex, Stride = (uint) Marshal.SizeOf() } }; var vertexAttributes = new VertexAttribute[3] { new VertexAttribute { Binding = 0, Location = 0, Format = VertexElementFormat.Vector3, Offset = 0 }, new VertexAttribute { Binding = 0, Location = 1, Format = VertexElementFormat.Vector2, Offset = (uint) Marshal.OffsetOf("texcoord") }, new VertexAttribute { Binding = 0, Location = 2, Format = VertexElementFormat.Vector4, Offset = (uint) Marshal.OffsetOf("color") } }; VertexInputState vertexInputState = new VertexInputState { VertexBindings = vertexBindings, VertexAttributes = vertexAttributes }; var viewports = new Viewport[1] { new Viewport { X = 0, Y = 0, W = windowWidth, H = windowHeight, MinDepth = 0, MaxDepth = 1 } }; var scissors = new Rect[1] { new Rect { X = 0, Y = 0, W = (int) windowWidth, H = (int) windowHeight } }; ViewportState viewportState = new ViewportState { Viewports = viewports, Scissors = scissors }; var colorAttachmentDescriptions = new ColorAttachmentDescription[1] { new ColorAttachmentDescription { format = TextureFormat.R8G8B8A8, sampleCount = SampleCount.One } }; GraphicsPipelineAttachmentInfo graphicsPipelineAttachmentInfo = new GraphicsPipelineAttachmentInfo { colorAttachmentDescriptions = colorAttachmentDescriptions, colorAttachmentCount = 1, hasDepthStencilAttachment = false, depthStencilFormat = 0 }; var graphicsPipelineCreateInfo = new GraphicsPipelineCreateInfo { ColorBlendState = colorBlendState, DepthStencilState = depthStencilState, VertexShaderState = vertexShaderState, FragmentShaderState = fragmentShaderState, MultisampleState = multisampleState, PipelineLayoutInfo = pipelineLayoutInfo, RasterizerState = rasterizerState, PrimitiveType = PrimitiveType.TriangleList, VertexInputState = vertexInputState, ViewportState = viewportState, AttachmentInfo = graphicsPipelineAttachmentInfo }; spritePipeline = new GraphicsPipeline(GraphicsDevice, graphicsPipelineCreateInfo); spriteBatch = new SpriteBatch(GraphicsDevice); whitePixel = Texture.CreateTexture2D(GraphicsDevice, 1, 1, TextureFormat.R8G8B8A8, TextureUsageFlags.Sampler); var commandBuffer = GraphicsDevice.AcquireCommandBuffer(); commandBuffer.SetTextureData(whitePixel, new Color[] { Color.White }); GraphicsDevice.Submit(commandBuffer); sampler = new Sampler(GraphicsDevice, SamplerCreateInfo.PointWrap); } protected override void Update(TimeSpan dt) { for (var i = 0; i < SPRITECOUNT; i += 1) { positions[i].X = (float)(random.NextDouble() * windowWidth) - 64; positions[i].Y = (float)(random.NextDouble() * windowHeight) - 64; } } protected override void Draw(TimeSpan dt, double alpha) { var commandBuffer = GraphicsDevice.AcquireCommandBuffer(); var viewProjection = Matrix4x4.CreateLookAt(new Vector3(windowWidth / 2, windowHeight / 2, 1), new Vector3(windowWidth / 2, windowHeight / 2, 0), Vector3.Up) * Matrix4x4.CreateOrthographic(windowWidth, windowHeight, 0.1f, 1000); spriteBatch.Start(whitePixel, sampler); for (var i = 0; i < SPRITECOUNT; i += 1) { var transform = Matrix4x4.CreateTranslation(positions[i]); var color = new Color((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble(), 255f); spriteBatch.Add(new Sprite(new Rect { X = 0, Y = 0, W = 0, H = 0 }, 128, 128), transform, color); } var colorAttachmentInfo = new ColorAttachmentInfo { renderTarget = mainColorTarget, clearColor = Color.Black, loadOp = LoadOp.Clear, storeOp = StoreOp.DontCare }; spriteBatch.Flush(commandBuffer, colorAttachmentInfo, spritePipeline, new CameraUniforms { viewProjectionMatrix = viewProjection }); commandBuffer.QueuePresent(mainColorTarget.TextureSlice, Filter.Nearest, Window); GraphicsDevice.Submit(commandBuffer); } protected override void OnDestroy() { } } }