DirectX 9.0c Tutorial 1

Creating a basic render window

In this tutorial we explore how to create a DirectX render window. The render windows is the basic staging area for your DirectX environment. It is what displays 2D, 3D, and text based graphics on to the screen.

To start with, you will need to download and install the DirectX SDK available from Microsoft (Link to the current DirectX SDK).

Prerequisties

Project type: Windows
Include files: d3d9.h
Library files: d3d9.lib



The Render Window

This project builds upon the code found at Windows Tutorial 2 - Creating a basic window. Feel free to review that tutorial, as we wont be going into the fundamentals in basic window creation here.

Firstly, we will create a Direct 3D object and device.

IDirect3D9 *md3dObject; IDirect3DDevice9 *md3dDevice;

The md3dObject points our application to DirectX itself & the md3dDevice will be used to communicate with our graphics adapter.

Now we can tell DirectX what version of SDK we want to use. As there are many iterations of updates for DirectX9.0c, our application needs to reference the correct DLL's at runtime.

md3dObject=Direct3DCreate9(D3D_SDK_VERSION);
Fortunately, we can take the easy way out and specify D3D_SDK_VERSION, which will make the compiler work out for itself what version of DirectX SDK we have installed (or choose to use - as you can have as many different versions of SDK installed on our system, but don't stress about this for the time being).

An important thing to note is that IDirect3D9 and IDirect3DDevice9 are COM objects, which must be cleaned up (memory released) at the end of program execution. If we forget to do this, the memory used will not be freed up until you reboot you PC.

This is called a 'memory leak' and is the souorce of all evil for C++ coders. The amount of memory leaked here would be pretty insignificant. But, over the duration of a more complex application memory leaks can quickly add up and cause your system to grind to a halt.

A rough and general rule is that anything with 'IDirect3D' infront of it, needs to be cleaned up. More on how to clean up later.

The next step that is required, is to fill out a D3DPRESENT_PARAMETERS structure. This defines various important settings like pixel format, anti-aliasing, the window we are assigning DirectX to act upon ect..

D3DPRESENT_PARAMETERS d3dpp;
d3dpp.AutoDepthStencilFormat=D3DFMT_D24S8;
d3dpp.BackBufferCount=1;
d3dpp.BackBufferFormat=D3DFMT_X8R8G8B8;
d3dpp.BackBufferWidth=640;
d3dpp.BackBufferHeight=480;					
d3dpp.Windowed=true;
d3dpp.EnableAutoDepthStencil=D3DFMT_D24S8;
d3dpp.Flags=0;
d3dpp.FullScreen_RefreshRateInHz=D3DPRESENT_RATE_DEFAULT;
d3dpp.hDeviceWindow=hWnd;
d3dpp.MultiSampleQuality=0;
d3dpp.MultiSampleType=D3DMULTISAMPLE_NONE;
d3dpp.PresentationInterval=D3DPRESENT_INTERVAL_IMMEDIATE;
d3dpp.SwapEffect=D3DSWAPEFFECT_DISCARD;


There are many parameters here, but it is important that we fill these out carefully, as things may not look right (or even display at all) if we don't be carefull.

Most of the parameters are faily self explanatory, but we have provided a link to the MSDN documentation at the end of this tutorial for further reading.

Finally, we create our Direct3D device.
md3dObject->CreateDevice(D3DADAPTER_DEFAULT,
	D3DDEVTYPE_HAL,
	hWnd,
	D3DCREATE_HARDWARE_VERTEXPROCESSING|D3DCREATE_PUREDEVICE,
	&d3dpp,
	&md3dDevice);
Most modern graphics cards will handle the forth paramter D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE with no problem. But, some older graphics cards will require this parameter to be replaced with D3DCREATE_SOFTWARE_VERTEXPROCESSING. If your system can play reasonably modern games, then you wont have a problem.

Note: All DirectX calls have the ability to return an error code. So, it is worth checking each call in your application to make sure that the function succeeds. We have left error checking out of this tutorial for ease of reading. But, for any commercial grade application, this is a must.

Cleaning up DirectX after use if very important to avoid the dreaded memory leak.

In this case all we need to do to clean up is to put the following statements, before we 'return' to the operating system.
md3dDevice->Release();
md3dObject->Release();
Now go ahead and compile the full source and see what happens.

The Final Output

All going to plan, you should have a screen that looks the same as the one below.

DirectX 9.0c render window


The Full Code

#include <windows.h>
#include <d3d9.h>

#pragma comment(lib,"d3d9.lib")

LRESULT CALLBACK WinProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR lpCmdLine,int nShowCmd)
{
	WNDCLASSEX wClass;
	ZeroMemory(&wClass,sizeof(WNDCLASSEX));
	wClass.cbClsExtra=NULL;
	wClass.cbSize=sizeof(WNDCLASSEX);
	wClass.cbWndExtra=NULL;
	wClass.hbrBackground=(HBRUSH)COLOR_WINDOW;
	wClass.hCursor=LoadCursor(NULL,IDC_ARROW);
	wClass.hIcon=NULL;
	wClass.hIconSm=NULL;
	wClass.hInstance=hInst;
	wClass.lpfnWndProc=(WNDPROC)WinProc;
	wClass.lpszClassName="Window Class";
	wClass.lpszMenuName=NULL;
	wClass.style=CS_HREDRAW|CS_VREDRAW;

	if(!RegisterClassEx(&wClass))
	{
		int nResult=GetLastError();
		MessageBox(NULL,
			"Window class creation failed",
			"Window Class Failed",
			MB_ICONERROR);
	}

	HWND hWnd=CreateWindowEx(NULL,
			"Window Class",
			"Windows application",
			WS_OVERLAPPEDWINDOW,
			200,
			200,
			640,
			480,
			NULL,
			NULL,
			hInst,
			NULL);

	if(!hWnd)
	{
		int nResult=GetLastError();

		MessageBox(NULL,
			"Window creation failed",
			"Window Creation Failed",
			MB_ICONERROR);
	}

	ShowWindow(hWnd,nShowCmd);

	IDirect3D9 *md3dObject;
	IDirect3DDevice9 *md3dDevice;
	md3dObject=Direct3DCreate9(D3D_SDK_VERSION);

	D3DPRESENT_PARAMETERS d3dpp;
	d3dpp.AutoDepthStencilFormat=D3DFMT_D24S8;
	d3dpp.BackBufferCount=1;
	d3dpp.BackBufferFormat=D3DFMT_X8R8G8B8;
	d3dpp.BackBufferHeight=640;
	d3dpp.BackBufferWidth=480;
	d3dpp.Windowed=true;
	d3dpp.EnableAutoDepthStencil=D3DFMT_D24S8;
	d3dpp.Flags=0;
	d3dpp.FullScreen_RefreshRateInHz=D3DPRESENT_RATE_DEFAULT;
	d3dpp.hDeviceWindow=hWnd;
	d3dpp.MultiSampleQuality=0;
	d3dpp.MultiSampleType=D3DMULTISAMPLE_NONE;
	d3dpp.PresentationInterval=D3DPRESENT_INTERVAL_IMMEDIATE;
	d3dpp.SwapEffect=D3DSWAPEFFECT_DISCARD;

	md3dObject->CreateDevice(D3DADAPTER_DEFAULT,
			D3DDEVTYPE_HAL,
			hWnd,
			D3DCREATE_HARDWARE_VERTEXPROCESSING|D3DCREATE_PUREDEVICE,
			&d3dpp,
			&md3dDevice);
	
	MSG msg;
	ZeroMemory(&msg,sizeof(MSG));

	while(GetMessage(&msg,NULL,0,0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);

		md3dDevice->Clear(0,
			0,
			D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
			D3DCOLOR_XRGB(50,100,255),
			1.0f,
			0);
		md3dDevice->BeginScene();
		md3dDevice->EndScene();
		md3dDevice->Present(0,0,0,0);
	}

	md3dDevice->Release();
	md3dObject->Release();

	return 0;
}

LRESULT CALLBACK WinProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
	switch(msg)
	{
		case WM_DESTROY:
		{
			PostQuitMessage(0);
			return 0;
		}
		break;
	}

	return DefWindowProc(hWnd,msg,wParam,lParam);
}


Things to try

Try changing the color of the render window background, to something that you like.
md3dDevice->Clear(0,
		0,
		D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
		D3DCOLOR_XRGB(AAA,BBB,CCC),
		1.0f,
		0);


Additional informaton

For additional information we have provided the following links.

Microsoft DirectX SDK - Download the latest DirectX SDK
MSDN - Detailed explanation of D3DPRESENT_PARAMETERS parameters


Next tutorial

Tutorial 2 - Coming soon!