Skip to content

Instantly share code, notes, and snippets.

@axefrog
Last active March 30, 2018 13:19
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save axefrog/6972449 to your computer and use it in GitHub Desktop.
Save axefrog/6972449 to your computer and use it in GitHub Desktop.
Game Dev Samples
using System;
using System.Windows.Forms;
using SharpDX;
using SharpDX.D3DCompiler;
using SharpDX.Direct3D;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using SharpDX.Windows;
using Buffer = SharpDX.Direct3D11.Buffer;
using Device = SharpDX.Direct3D11.Device;
namespace SharpDx2
{
class Game : IDisposable
{
private RenderForm _form;
private Device _device;
private SwapChain _swapChain;
private Viewport _viewport;
private DeviceContext _context;
private RenderTargetView _renderTarget;
private VertexShader _vertexShader;
private PixelShader _pixelShader;
private ShaderSignature _inputSignature;
private DataStream _vertices;
private Buffer _vertexBuffer;
private InputLayout _layout;
[STAThread]
public static void Main()
{
using (var game = new Game())
{
game.Initialize();
game.Run();
}
}
public void Initialize()
{
_form = new RenderForm("SharpDX : Hello, Triangle");
_form.Width = 800;
_form.Height = 600;
_form.AllowUserResizing = true;
_form.KeyDown += (sender, e) =>
{
// handle the transition between full-screen and windowed mode
if (_swapChain != null && e.Alt && e.KeyCode == Keys.Enter)
_swapChain.IsFullScreen = !_swapChain.IsFullScreen;
};
var description = new SwapChainDescription
{
BufferCount = 1, // because the desktop window is an implicit front buffer, we only need one buffer here
IsWindowed = true, // always start in windowed mode (can change later)
SwapEffect = SwapEffect.Discard, // discard because I don't need to preserve the buffer contents after presentation
OutputHandle = _form.Handle, // the window on which we'll be doing our rendering
Usage = Usage.RenderTargetOutput, // the buffer is to be rendered to the render target (as opposed to using it for shader input)
Flags = SwapChainFlags.AllowModeSwitch, // allows me to resize and switch between windowed and full-screen mode
ModeDescription = new ModeDescription(0, 0, new Rational(60, 1), Format.R8G8B8A8_UNorm), // display mode for the swap chain (dimensions, refresh rate, pixel format)
SampleDescription = new SampleDescription(1, 0) // specifies antialiasing preferences: samples per pixel, anti aliasing quality level
};
Device.CreateWithSwapChain(
DriverType.Hardware, // we explicitly want to use only a hardware device, not a software device
DeviceCreationFlags.BgraSupport, // force the the device creation to fail if BGRA support is missing
description, out _device, out _swapChain
);
// The context is like a GDI graphics context, but specific to the types of things you render using Direct3D.
// It is possible to render to different contexts in different threads. We don't care about that right now, so this is all we need.
_context = _device.ImmediateContext;
// Apparently DXGI doesn't play nicely with WinForms when switching between windowed and full-screen mode, so we handle that case manually
using(var factory = _swapChain.GetParent<Factory>())
factory.MakeWindowAssociation(_form.Handle, WindowAssociationFlags.IgnoreAltEnter);
// The viewport specifies the bounds of our rendering. What's rendered here will be projected onto the render target (the back buffer, in this case).
_viewport = new Viewport(0, 0, _form.ClientSize.Width, _form.ClientSize.Height);
// The rasterizer is one of the the stages in the pipeline - we have to set the viewport for that stage so it knows the bounds inside which to render
_context.Rasterizer.SetViewport(_viewport);
// We have to get a reference to the back buffer from the swap chain, because that's where we'll be rendering onto. What we get back though is just
// a reference though, and though RenderTargetView constructs itself using information from the resource, we dispose the resource when done because
// the RenderTargetView constructor doesn't need it anymore.
using(var resource = SharpDX.Direct3D11.Resource.FromSwapChain<Texture2D>(_swapChain, 0))
_renderTarget = new RenderTargetView(_device, resource);
// The output merger combines all the pixel data and sends it to the render target(s)
_context.OutputMerger.SetTargets(_renderTarget);
// This is our conduit into video memory for building up a mesh
_vertices = new DataStream(12*3, true, true);
// Prepare the three vertices of our triangle
_vertices.Write(new Vector3(0.0f, 0.5f, 0.5f));
_vertices.Write(new Vector3(0.5f, -0.5f, 0.5f));
_vertices.Write(new Vector3(-0.5f, -0.5f, 0.5f));
// We have to seek back to position 0, ready for Direct3D to read from the stream
_vertices.Position = 0;
// Prepares a buffer specifically to contain vertex data, ready to be loaded into the pipeline
_vertexBuffer = new Buffer(_device, _vertices, 12*3, ResourceUsage.Default,
BindFlags.VertexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);
// Compile our shaders, which will get the vertices into the correct screen coordinates and display the pixels with the correct colours
var shaders = Resources.shaders; // I have stored the shader program in a resx file, to make loading it easier
using(var bytecode = ShaderBytecode.Compile(shaders, "VShader", "vs_4_0"))
{
_inputSignature = ShaderSignature.GetInputSignature(bytecode);
_vertexShader = new VertexShader(_device, bytecode);
}
using(var bytecode = ShaderBytecode.Compile(shaders, "PShader", "ps_4_0"))
_pixelShader = new PixelShader(_device, bytecode);
// Get the inputs to provide to the vertex shader
var elements = new[] { new InputElement("POSITION", 0, Format.R32G32B32_Float, 0) };
_layout = new InputLayout(_device, _inputSignature, elements);
_context.InputAssembler.InputLayout = _layout;
_context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
_context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(_vertexBuffer, 12, 0));
_context.VertexShader.Set(_vertexShader);
_context.PixelShader.Set(_pixelShader);
}
public void Run()
{
RenderLoop.Run(_form, MainLoop);
}
private void MainLoop()
{
_context.ClearRenderTargetView(_renderTarget, new Color4(Color3.White));
_context.Draw(3, 0);
_swapChain.Present(0, PresentFlags.None);
}
public void Dispose()
{
_vertices.Close();
_vertexBuffer.Dispose();
_layout.Dispose();
_inputSignature.Dispose();
_vertexShader.Dispose();
_pixelShader.Dispose();
_renderTarget.Dispose();
_swapChain.Dispose();
_device.Dispose();
_form.Dispose();
}
}
}
float4 VShader(float4 position : POSITION) : SV_POSITION
{
return position;
}
float4 PShader(float4 position : SV_POSITION) : SV_Target
{
return float4(1.0f, 1.0f, 0.0f, 1.0f);
}
@HeegyuKim
Copy link

Thank you 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment