Creating a Window for drawing our D3D scene
Back to Direct3D Tutorial Index
Welcome to what I hope will be the first of many DirectX tutorials. Today I will show you
how to create a basic window using Direct3D which is Microsofts 3D API and rivals the
OpenGL API. By the end of this tutorial you will have a window with a black background
running from your graphics card, but using the Software version of Vertex Processing because
it is supported on all systems. Although when I get up to that, I will also tell you how to use
your graphics card for Vertex Processing.
This tutorial has working code for window creation, although it is not explained, it is recommended that
you have some prior knowledge in the area of Win32 Application Window creation. I will have a tutorial
on this in the C++ section of my site at: http://www.swiftless.cdadc.com
So lets get started.
--------------------------------------------------------------------------------------------------
Section 1: Headers, Libraries and Global Variables
All the basic Direct 3D related calls that we will make will be derived from d3d9.h
These include basic geometry, view setup, lighting, fog and other basic implementations.
#include <dx/d3d9.h>
Now the reason I could not get the DirectX code to work from the DirectX SDK was because
this line was missing. So here it is, I am setting up the Direct 3D library, d3d9.h
#pragma comment(lib,"d3d9.lib")
Now we need two global variables for our project to run. These are:
LPDIRECT3D9 g_pD3D = NULL;
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;
The first one, g_pD3D is used to set up our Direct 3D device while the second, g_pd3dDevice is
used to set up our rendering device.
--------------------------------------------------------------------------------------------------
Section 2: Initialization
To initialize Direct 3D, I am using the function init which takes the paramter hWnd which is a
HWND for a window. If you knew a windows HWND, you could effectively draw your scene on that
maybe draw it to your desktop window for your own custom 3D wallpaper, which would be fully
interactive depending on what you decide for it to do. But here we will just use
our own window, so back to the tutorial...
void init( HWND hWnd )
{
First off, we need to set our Direct 3D device, we are going to set it to the currently installed
SDK version of Direct 3D. So we call:
g_pD3D = Direct3DCreate9( D3D_SDK_VERSION );
which will Create a Direct 3D device using version 9 of Direct 3D. This can be changed when working
with previous versions of Direct 3D.
Now we are going to set up are Direct 3D parameters. So first we need to set a variable to hold
our Direct 3D parameters, in the format of D3DPRESENT_PARAMETERS.
D3DPRESENT_PARAMETERS d3dpp;
Next we call the ZeroMemory function to give our program some needed memory. (not 100% sure on this :P )
ZeroMemory( &d3dpp, sizeof(d3dpp) );
Then we determine if our Direct 3D program is windowed, selecting FALSE will cause an error..
d3dpp.Windowed = TRUE;
Next we tell Direct 3D that when it swaps a buffer, to discard the unwanted buffer.
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
Finally we are setting the Back Buffer Format to D3DFMT_UNKNOWN, this means that it will use our current
displays color depth.
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
And the last call in our init function will finally Create the Direct 3D device.
This is setting the adapter to our default, which means that it is using our default monitor, D3DDEVTYPE_HAL
is telling it to use our graphics hardware, setting it to D3DDEVTYPE_SW will use software if your computer
has support for it. Alternatively there is also a setting called D3DDEVTYPE_REF, but I am not sure of how
this works.
Then the parameter: D3DCREATE_SOFTWARE_VERTEXPROCESSING tells our device to use software for the processing
of vertices, you can change it to D3DCREATE_HARDWARE_VERTEXPROCESSING if your graphics card supports it.
If your card supports the hardware processing of vertices, then you should notice a huge increase in the
performance of your application.
g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice );
}
-----------------------------------------------------------------------------------------------------
Section 3: Cleanup
This little function here releases our Direct 3D and rendering devices to clear up memory and efficiently
shut down our application.
void Cleanup (void)
{
if( g_pd3dDevice != NULL)
{
g_pd3dDevice->Release();
}
if( g_pD3D != NULL)
{
g_pD3D->Release();
}
}
-----------------------------------------------------------------------------------------------------
Section 4: Rendering our Scene
This function here is where we will call all of our drawing commands.
void Render (void)
{
This first call will clear our D3D target window to a specified color.
The last 2 parameters declare if we are to use the Z buffer and Stencil buffer. Currently the Z buffer
is enabled with the value of 1, and the Stencil buffer is disabled with a value of 0.
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1, 0 );
Next we call the command to Begin drawing our Scene.
g_pd3dDevice->BeginScene();
Then after we have drawn everything, we call to End the Scene.
g_pd3dDevice->EndScene();
Then we empty our present rendering device.
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}
-----------------------------------------------------------------------------------------------------
Section 5: Window message handling
This function is your Win32 application message handler, with our modifications to show Direct 3D.
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_DESTROY:
When the window is destroyed / closed, we call our Cleanup function.
Cleanup();
PostQuitMessage( 0 );
return 0;
case WM_PAINT:
And when our window is painted / drawn, we call the function to Render our scene.
Render();
ValidateRect( hWnd, NULL );
return 0;
}
return DefWindowProc( hWnd, msg, wParam, lParam );
}
-----------------------------------------------------------------------------------------------------
Section 6: Creating the window.
Here is our WinMain function, which is essential for the use of a Win32 application. Inside are our commands
to create our window and set up rendering to it with Direct 3D.
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
{
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, "A Basic Window", NULL };
RegisterClassEx( &wc );
This function creates our window with the caption: A Basic Window, position at 100,100 on the
screen and 500 x 500 pixels in size.
HWND hWnd = CreateWindow( "A Basic Window", "A Basic Window", WS_OVERLAPPEDWINDOW, 100, 100, 500, 500, NULL, NULL, wc.hInstance, NULL );
Now we call our init function to initialize Direct 3D to our windows hWnd.
init( hWnd );
ShowWindow( hWnd, SW_SHOWDEFAULT );
UpdateWindow( hWnd );
MSG msg;
while( GetMessage( &msg, NULL, 0, 0 ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
UnregisterClass( "A Basic Window", wc.hInstance );
return 0;
}
---------------------------------------------------------------------------------------------------
And that is the core to a Direct 3D program. I hope you have found this useful. I have tried to keep
the code to the bare essentials and comment it to an understandable level.
If you have any questions in regard to this tutorial, please email me at swiftless@gmail.com
#include <dx/d3d9.h>
#pragma comment(lib,"d3d9.lib")
LPDIRECT3D9 g_pD3D = NULL;
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;
void init( HWND hWnd )
{
g_pD3D = Direct3DCreate9( D3D_SDK_VERSION );
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice );
}
void Cleanup (void)
{
if( g_pd3dDevice != NULL)
{
g_pd3dDevice->Release();
}
if( g_pD3D != NULL)
{
g_pD3D->Release();
}
}
void Render (void)
{
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1, 0 );
g_pd3dDevice->BeginScene();
g_pd3dDevice->EndScene();
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_DESTROY:
Cleanup();
PostQuitMessage( 0 );
return 0;
case WM_PAINT:
Render();
ValidateRect( hWnd, NULL );
return 0;
}
return DefWindowProc( hWnd, msg, wParam, lParam );
}
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
{
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, "A Basic Window", NULL };
RegisterClassEx( &wc );
HWND hWnd = CreateWindow( "A Basic Window", "A Basic Window", WS_OVERLAPPEDWINDOW, 100, 100, 500, 500, NULL, NULL, wc.hInstance, NULL );
init( hWnd );
ShowWindow( hWnd, SW_SHOWDEFAULT );
UpdateWindow( hWnd );
MSG msg;
while( GetMessage( &msg, NULL, 0, 0 ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
UnregisterClass( "A Basic Window", wc.hInstance );
return 0;
}
Download C++ Source Code for this Tutorial |