using MoonWorks; using MoonWorks.Audio; using MoonWorks.Graphics; using MoonWorks.Input; using MoonWorks.Window; using System.IO; using System.Threading; namespace MoonWorksTest { public class TestGame : Game { ShaderModule passthroughVertexShaderModule; ShaderModule raymarchFragmentShaderModule; RaymarchUniforms raymarchUniforms; Texture woodTexture; Texture noiseTexture; Sampler sampler; Buffer vertexBuffer; Rect renderArea; Rect flip; Color clearColor; Texture mainColorTargetTexture; TextureSlice mainColorTargetTextureSlice; RenderTarget mainColorTarget; RenderPass mainRenderPass; Framebuffer mainFramebuffer; GraphicsPipeline mainGraphicsPipeline; byte[] screenshotPixels; Buffer screenshotBuffer; uint screenShotBufferSize; Thread screenshotThread; StaticSound music; StaticSoundInstance musicInstance; StreamingSoundOgg musicStream; public TestGame(WindowCreateInfo windowCreateInfo, PresentMode presentMode, int targetTimestep = 60, bool debugMode = false) : base(windowCreateInfo, presentMode, targetTimestep, debugMode) { var windowWidth = windowCreateInfo.WindowWidth; var windowHeight = windowCreateInfo.WindowHeight; passthroughVertexShaderModule = new ShaderModule(GraphicsDevice, Path.Combine("Content", "passthrough_vert.spv")); raymarchFragmentShaderModule = new ShaderModule(GraphicsDevice, Path.Combine("Content", "hexagon_grid.spv")); raymarchUniforms.time = 0; raymarchUniforms.padding = 0; raymarchUniforms.resolutionX = windowWidth; raymarchUniforms.resolutionY = windowHeight; woodTexture = Texture.LoadPNG(GraphicsDevice, "Content/woodgrain.png"); noiseTexture = Texture.LoadPNG(GraphicsDevice, "Content/noise.png"); sampler = new Sampler(GraphicsDevice, SamplerCreateInfo.LinearWrap); /* Load Vertex Data */ var vertices = new Vertex[3]; vertices[0].x = -1; vertices[0].y = -1; vertices[0].z = 0; vertices[0].u = 0; vertices[0].v = 1; vertices[1].x = 3; vertices[1].y = -1; vertices[1].z = 0; vertices[1].u = 1; vertices[1].v = 1; vertices[2].x = -1; vertices[2].y = 3; vertices[2].z = 0; vertices[2].u = 0; vertices[2].v = 0; vertexBuffer = new Buffer(GraphicsDevice, BufferUsageFlags.Vertex, 4 * 5 * 3); vertexBuffer.SetData(vertices); /* Render Pass */ renderArea.X = 0; renderArea.Y = 0; renderArea.W = (int) windowWidth; renderArea.H = (int) windowHeight; flip.X = 0; flip.Y = (int) windowHeight; flip.W = (int) windowWidth; flip.H = -(int) windowHeight; clearColor.R = 237; clearColor.G = 41; clearColor.B = 57; clearColor.A = byte.MaxValue; ColorTargetDescription colorTargetDescription = new ColorTargetDescription { Format = TextureFormat.R8G8B8A8, MultisampleCount = SampleCount.One, LoadOp = LoadOp.Clear, StoreOp = StoreOp.Store }; mainRenderPass = new RenderPass(GraphicsDevice, colorTargetDescription); mainColorTargetTexture = Texture.CreateTexture2D( GraphicsDevice, windowWidth, windowHeight, TextureFormat.R8G8B8A8, TextureUsageFlags.ColorTarget ); mainColorTargetTextureSlice = new TextureSlice(mainColorTargetTexture); mainColorTarget = new RenderTarget(GraphicsDevice, mainColorTargetTextureSlice); mainFramebuffer = new Framebuffer( GraphicsDevice, windowWidth, windowHeight, mainRenderPass, null, mainColorTarget ); /* 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 = passthroughVertexShaderModule, EntryPointName = "main", UniformBufferSize = 0 }; ShaderStageState fragmentShaderState = new ShaderStageState { ShaderModule = raymarchFragmentShaderModule, EntryPointName = "main", UniformBufferSize = 16 }; MultisampleState multisampleState = MultisampleState.None; GraphicsPipelineLayoutInfo pipelineLayoutInfo = new GraphicsPipelineLayoutInfo { VertexSamplerBindingCount = 0, FragmentSamplerBindingCount = 2 }; RasterizerState rasterizerState = RasterizerState.CW_CullBack; var vertexBindings = new VertexBinding[1] { new VertexBinding { Binding = 0, InputRate = VertexInputRate.Vertex, Stride = 4 * 5 } }; var vertexAttributes = new VertexAttribute[2] { new VertexAttribute { Binding = 0, Location = 0, Format = VertexElementFormat.Vector3, Offset = 0 }, new VertexAttribute { Binding = 0, Location = 1, Format = VertexElementFormat.Vector2, Offset = 4 * 3 } }; 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 graphicsPipelineCreateInfo = new GraphicsPipelineCreateInfo { ColorBlendState = colorBlendState, DepthStencilState = depthStencilState, VertexShaderState = vertexShaderState, FragmentShaderState = fragmentShaderState, MultisampleState = multisampleState, PipelineLayoutInfo = pipelineLayoutInfo, RasterizerState = rasterizerState, PrimitiveType = PrimitiveType.TriangleList, VertexInputState = vertexInputState, ViewportState = viewportState, RenderPass = mainRenderPass }; mainGraphicsPipeline = new GraphicsPipeline( GraphicsDevice, graphicsPipelineCreateInfo ); screenShotBufferSize = windowWidth * windowHeight * 4; screenshotPixels = new byte[screenShotBufferSize]; screenshotBuffer = new Buffer(GraphicsDevice, 0, screenShotBufferSize); screenshotThread = new Thread(new ThreadStart(SaveScreenshot)); music = StaticSound.LoadOgg(AudioDevice, Path.Combine("Content", "title_screen.ogg")); musicInstance = music.CreateInstance(); // musicInstance.Play(); musicStream = StreamingSoundOgg.Load(AudioDevice, Path.Combine("Content", "title_screen.ogg"), false, true); musicStream.Play(); } protected override void Update(double dt) { raymarchUniforms.time += (float) dt; } protected override void Draw(double dt, double alpha) { var screenshotPressed = Inputs.Keyboard.IsPressed(Keycode.S); var commandBuffer = GraphicsDevice.AcquireCommandBuffer(); commandBuffer.BeginRenderPass( mainRenderPass, mainFramebuffer, renderArea, clearColor ); commandBuffer.BindGraphicsPipeline(mainGraphicsPipeline); var fragmentParamOffset = commandBuffer.PushFragmentShaderParams(raymarchUniforms); commandBuffer.BindVertexBuffers(0, new BufferBinding(vertexBuffer, 0)); commandBuffer.BindFragmentSamplers( new TextureSamplerBinding(woodTexture, sampler), new TextureSamplerBinding(noiseTexture, sampler) ); commandBuffer.DrawPrimitives(0, 1, 0, fragmentParamOffset); commandBuffer.EndRenderPass(); if (screenshotPressed) { commandBuffer.CopyTextureToBuffer(mainColorTargetTextureSlice, screenshotBuffer); } commandBuffer.QueuePresent(mainColorTargetTextureSlice, flip, Filter.Nearest); GraphicsDevice.Submit(commandBuffer); if (screenshotPressed) { screenshotThread.Start(); } } private void SaveScreenshot() { GraphicsDevice.Wait(); screenshotBuffer.GetData(screenshotPixels, screenShotBufferSize); Texture.SavePNG("screenshot.png", 1280, 720, screenshotPixels); } } }