Skip to content

Instantly share code, notes, and snippets.

@axefrog
Created October 22, 2013 16:58
Show Gist options
  • Select an option

  • Save axefrog/7104217 to your computer and use it in GitHub Desktop.

Select an option

Save axefrog/7104217 to your computer and use it in GitHub Desktop.
Not quite sure why resizing the window causes the polygon edges to become a bit jagged.
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 _vertexStream;
private Buffer _vertexBuffer;
private InputLayout _layout;
[STAThread]
public static void Main()
{
using (var game = new Game())
{
game.Initialize();
game.Run();
}
}
struct Vertex
{
public Vertex(float x, float y, float z, float r, float g, float b, float a)
{
Position = new Vector3(x, y, z);
Color = new Color4(r, g, b, a);
}
public Vector3 Position;
public Color4 Color;
}
public void Initialize()
{
_form = new RenderForm("SharpDX : Hello 3D");
_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;
};
_form.ResizeEnd += (sender, e) =>
{
if (_swapChain == null)
return;
_renderTarget.Dispose();
_swapChain.ResizeBuffers(_swapChain.Description.BufferCount, _form.Width, _form.Height, _swapChain.Description.ModeDescription.Format, _swapChain.Description.Flags);
using (var resource = SharpDX.Direct3D11.Resource.FromSwapChain<Texture2D>(_swapChain, 0))
_renderTarget = new RenderTargetView(_device, resource);
_viewport = new Viewport(0, 0, _form.ClientSize.Width, _form.ClientSize.Height);
_context.Rasterizer.SetViewport(_viewport);
_context.OutputMerger.SetTargets(_renderTarget);
};
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(4, 4) // 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);
// Prepare the vertices of our shape
var vertices = new[]
{
new Vertex(0.0f, 0.5f, 0.5f, 1, 0, 0, 1),
new Vertex(0.5f, -0.5f, 0.5f, 0, 1, 0, 1),
new Vertex(-0.5f, -0.5f, 0.5f, 0, 0, 1, 1),
new Vertex(-0.0f, -0.5f, 0.5f, 1, 0, 0, 1),
new Vertex(0.2f, -0.9f, 0.5f, 0, 1, 0, 1),
new Vertex(-0.2f, -0.9f, 0.5f, 0, 0, 1, 1),
};
// This is our conduit into video memory for building up a mesh
const int vertexSize = 12 + 16;
_vertexStream = new DataStream(vertexSize * vertices.Length, true, true);
// Write the vertices to the stream
foreach(var vertex in vertices)
_vertexStream.Write(vertex);
// We have to seek back to position 0, ready for Direct3D to read from the stream
_vertexStream.Position = 0;
// Prepares a buffer specifically to contain vertex data, ready to be loaded into the pipeline
_vertexBuffer = new Buffer(_device, _vertexStream, vertexSize * vertices.Length, 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, 0, InputClassification.PerVertexData, 0),
new InputElement("COLOR", 0, Format.R32G32B32A32_Float, 12, 0),
};
_layout = new InputLayout(_device, _inputSignature, elements);
_context.InputAssembler.InputLayout = _layout;
_context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
_context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(_vertexBuffer, vertexSize, 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.Black));
_context.Draw(6, 0);
_swapChain.Present(0, PresentFlags.None);
}
public void Dispose()
{
_vertexStream.Close();
_vertexBuffer.Dispose();
_layout.Dispose();
_inputSignature.Dispose();
_vertexShader.Dispose();
_pixelShader.Dispose();
_renderTarget.Dispose();
_swapChain.Dispose();
_device.Dispose();
_form.Dispose();
}
}
}
struct VOut
{
float4 position : SV_POSITION;
float4 color : COLOR;
};
VOut VShader(float4 position : POSITION, float4 color: COLOR)
{
VOut output;
output.position = position;
output.color = color;
return output;
}
float4 PShader(float4 position : SV_POSITION, float4 color: COLOR) : SV_Target
{
return color;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment