Managed DirectX Tutorial 1 – Creation of a Direct 3D device and GDI+ rendering

SETTING UP A DIRECTX DEVICE

Here you’ll learn how to setup a simple directx device in C# (and C++/CLI). If you have any experience with C++ or DirectX it will be just a warm up for you, if you don’t, it will be a simple tutorial that you read in 15 minutes.
If it was easy to setup a device in C++, in managed code it’s even easier to do it. Let’s start by creating a new windows form. Next follows the device setup and creation.
In this part you need to know mainly two things: the presentation parameters and the device. Let’s start by explaining the later one: the device is the main “interface” with the graphics system in your computer. It is responsible for rendering triangles, lines, etc., creating resources, shaders, etc. and other useful stuff; the presentation parameters hold the data that describes the setup of device, such as indicating if an application is running in windowed mode or not, the device’s window and the handle to the respective window, etc.
Let’s start by setting up the PresentParameters structure:

PresentParameters presentParams = new PresentParameters();
presentParams.IsWindowed = true;
presentParams.SwapEffect = SwapEffect.Discard;
  • The first parameter, IsWindowed, indicates that we are running the application in windowed mode, this means that we’re rendering to a window (or part of it) instead of rendering to the screen (full screen mode).
  • The second parameter, SwapEffect, indicates that we do not want DirectX to do any special operation when a swap is made between the back buffer and the actual screen buffer.

Note: When rendering some stuff using DirectX you are not actually drawing it to the screen. DirectX (as well as OpenGL) has the capability of drawing to a back buffer. This buffer will hold the final image and then it will be copied to the screen buffer.

DEVICE CREATION

Since you have some presentation parameters set, let’s have a look at the creation of the device:

device = new Device(0, DeviceType.Hardware, this.Handle, CreateFlags.HardwareVertexProcessing, presentParams);

Here we indicate the physical device (0 is default, the type of the device, the handle that we want to use to render our window, some flags for the creation of the device and our presentation parameters.

Now, here there is one thing that it’s interesting, what handle do we provide to the device?
In the .net framework, all components have the Handle property that returns a handle to that component. Well, if you want to create a device that will use a panel as its render scene, we give the panel’s handle to the device or if we want a form to have our scene, we give the form’s handle. This is very useful if we want to use part of a window as a DirectX scene and other part with contents of a regular windows application with buttons, textboxes and labels.

DEVICE MANIPULATION

The device is created, let’s proceed to some action… let’s clear the contents of our scene:

device.Clear(ClearFlags.Target, Color.DarkSlateBlue, 1.0f, 0);

In this command we’re clearing the render target (that’s what we’re indicating in the first field, think of it as our offscreen buffer for now), with the color provided in the second argument and the other two arguments you can ignore them for now.

LAST STEP

The final step is where we indicate that we want to see what we’ve been doing, that is, we want to see the contents of the back buffer.

device.Present();

Although there might be some unexplained stuff here, you might get the basic idea on how to set a new device.

PUTTING IT ALL TOGETHER

We saw how to create a device and clear it, now we’ll see how to put this all together in a managed application. Step by step:

  • Create a new project.
  • Create a new Form (if you don’t have one already), I named it DXSampleForm:
public partial class DxSampleForm : Form
{
	public DxSampleForm()
	{
		InitializeComponent();
	}
}
  • Add a new private member of type Device:
private Device device;
  • Create a method called InitializeDevice where you create the present parameters structure and the device. Call this method after the InitializeComponent in the constructor:
public DxSampleForm()
{
	InitializeComponent();
	InitializeDevice();
}

public void InitializeDevice()
{
	PresentParameters presentParams = new PresentParameters();
	presentParams.IsWindowed = true;
	presentParams.SwapEffect = SwapEffect.Discard;

	device = new Device(0, DeviceType.Hardware, this.Handle, CreateFlags.HardwareVertexProcessing,
		presentParams);
}
  • Override the OnPainBackground and do the DirectX rendering:
protected override void OnPaintBackground(System.Windows.Forms.PaintEventArgs e)
{
	device.Clear(ClearFlags.Target, Color.DarkSlateBlue, 1.0f, 0);
	device.Present();
}

Why the OnPaintBackground and not the OnPaint you may ask?
Simple, overriding the OnPaintBackground can spare us of some problems in future if we ever need to use GDI+ or if we need to have components in the middle of the area where we’re rendering our scene.

Note: Don’t forget that when you use managed DirectX, you’ll have to reference a(some) DLL(s). For this tutorial you only need the Microsoft.DirectX.DLL.

As you can see it’s very simple to create a DirectX sample using the framework .net. It takes only 12 lines of code made by you to have a rendered window.

FAQ

Q: How can I render to a panel?
A: Use the panel’s handle as the handle when creating the device. Example:

device = new Device(0, DeviceType.Hardware, panel.Handle, CreateFlags.HardwareVertexProcessing, presentParams);

Q: I want to draw some buttons and stuff over my DirectX render scene, is it possible?
A: Sure, just be careful to call the DirectX render methods in the OnPaintBackground instead of the OnPaint. As for the components, just drag them in the designer or add them by hand.
Q: How can I use GDI+ with DirectX?
A: First make sure you specify in your present parameters that you want to be able to lock the back buffer:

presentParams.PresentFlag = PresentFlag.LockableBackBuffer;

After that you need to access the back buffer. To do so, you use the GetBackBuffer method where you indicate the swap chain (0 by default) and the index of the back buffer. From this surface you can create a Graphics object that you can use to do your GDI+ drawings:

Microsoft.DirectX.Direct3D.Surface backbuffer;
backbuffer = device.GetBackBuffer(0, 0);
Graphics graphics = backbuffer.GetGraphics();
graphics.DrawRectangle(Pens.Beige, 10, 20, 50, 60);
backbuffer.ReleaseGraphics();
backbuffer.Dispose();

And we reached the end of this tutorial. Next time I’ll show you how to render to two separate areas in a form. This is usually used in editors. Let me know if you find/have any bugs/questions/comments/suggestions. See ya till next time! 😉

managed_directx1

Download Files:

C# and C++/CLI versions
You’re free to use this code as long as you don’t blame me for any changes/bugs that were introduced and don’t demand anything from me. Only download it if you accept these conditions.

References:

http://msdn.microsoft.com/directx/ – Microsoft DirectX Development Center
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_m/directx/directx9m.asp – DirectX 9.0 for Managed Code
http://pluralsight.com/wiki/default.aspx/Craig.DirectX/Direct3DTutorialIndex.html – Direct3DTutorialIndex

Next Tutorial

Tagged , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *