Page 1 of 1

DirectX Introduction: Win32 Primer and Initializing DirectX 9

#1 v0rtex  Icon User is offline

  • Caffeine: db "Never Enough!"
  • member icon

Reputation: 223
  • View blog
  • Posts: 773
  • Joined: 02-June 10

Posted 16 June 2012 - 12:05 AM

DirectX Introduction: Win32 Primer and Initializing DirectX 9:

Hey and welcome to the wonderful world of DirectX Game Programming. This is the first of a couple of tutorials that will aim to teach the basics of DirectX so that even novice C/C++ programmers can create games! In part 1 of this series, I will show you how to set up a window that is suitable for DirectX games and then how to initialize DirectX itself, this may sound a bit boring but it is necessary before we can jump into better stuff! The saying: "One must learn to walk before they run" is especially true in DirectX or you will just write read-only code and will not know what is going on! DirectX works only on windows so I am sorry for the Mac and Linux users but you can try take a look at OpenGL as an alternative.

So enough for introductions, lets dive in:


Win32 Primer:

If you have never done any Windows programming before than do not worry as You only need a basic windows application setup before you have an environment that is suitable for DirectX API/Lib to take over.

I am sure you are getting bored now, so let's dive into our windows program and then I will dissect it and show you how it all works:


Our First Windows Program

#include <Windows.h>
#include <iostream>
using namespace std;

const string WINDOWTITLE = "Hello Windows";

/* 
 * The window event callback function (WinProc)
 */

LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
//WinProc recieves and handles messages, it is a callback function that handles all of the messages sent to the main program window.

	switch (message) {
	case WM_PAINT:
		{
		//get the dimensions of the window
		RECT rt;
		GetClientRect(hWnd, &rt);

		//start drawing on device context
		PAINTSTRUCT ps;
		HDC hdc = BeginPaint(hWnd, &ps);
		
		//draw some text
		DrawText(hdc, WINDOWTITLE.c_str(), WINDOWTITLE.length(), &rt, DT_CENTER);

			//stop drawing
		EndPaint(hWnd, &ps);
		break;
		}

	case WM_DESTROY:
	PostQuitMessage(0);
	break;

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


/* 
 * Helper function to create the window and refresh it
 */

bool createInstance(HINSTANCE hInstance, int nCmdShow)
	//HINSTANCE passes the program instance that it recieves from windows
{

//create a new window
HWND hWnd = CreateWindow ( 
	WINDOWTITLE.c_str(), //window class
	WINDOWTITLE.c_str(), // title bar
	WS_OVERLAPPEDWINDOW, //window style
	CW_USEDEFAULT, CW_USEDEFAULT, //position of window (x, y)
	640, 480, //size of window
	NULL, //parent window (not used)
	NULL, //menu (not used)
	hInstance, //application instance
	NULL);
	
//was there an error in creating the window?
if (hWnd == 0) return 0;

//Display the window
ShowWindow(hWnd,nCmdShow);
UpdateWindow(hWnd); //sends a WM_PAINT message to the window handler, telling the window to draw itself (internal communication is common in windows programming)
return 1; //return true, everything went ok
	
}


/* 
 * Entry point for a windows program
 */ 

int WINAPI WinMain(HINSTANCE hInstance,
	               HINSTANCE hPrevInstance,
				   LPSTR lpCmdLine,
				   int nCmdShow)
{

	//set the new window's properties
	WNDCLASSEX wc;
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = (WNDPROC) WinProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hInstance;
	wc.hIcon = NULL;
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
	wc.lpszMenuName = NULL;
	wc.lpszClassName = WINDOWTITLE.c_str();
	wc.hIconSm = NULL;
	RegisterClassEx(&wc);

		if (!createInstance(hInstance,nCmdShow)) return 0; //createInstance is a helper function that basically creates the program window
// ^ test if something went wrong creating the window, if so then exit


//main message loop
MSG msg;
		while (GetMessage(&msg, NULL,0, 0))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);

		}
return msg.wParam;
}



Ok, now just compile that in your IDE (I am using Visual Studio 2010 Express) and you will have a windows application with some text in the middle of the top part of the screen that says: "Hello Windows".

Like so:


Posted Image

Windows Messaging

Before we start dissecting our first Windows program, You must have a basic understanding of the messaging system.

Windows Programs are event-driven. In other-wards Windows uses system-wide messages to communicate, i.e.: Messages that are seen by the entire system.

Windows messages are small packets of data sent by the operating system to running programs that tells the program that an event has occurred. An event is for example, a key press or that the program's window has been redrawn etc...

All windows messages consist of three parts essentially:
Window Handle, Instance Identifier and Message Type.

A Handle is essentially a reference for the operating system. It allows the system resources to know what you are referring to when it is passed in an API call. A window handle is normally wrapped in an instance of a class such as HWND which in this case is a handle to a Win32 window.

Program code is stored in a single memory space in Windows (note variables and program data are stored individual spaces). A instance refers to this space so that the Windows system can run our program.


Message Type simply refers to whether or not the message is system defined or application defined. See this for more on the topic.

Each windows program is handed any event that occurs and dependent on the program code, will either handle the event or give it back to the message stream.

Why is a windows messaging system necessary? Well a easy way to think about it is to think of it as the nervous system within one's body. Without a nervous system, our brain would not be able to perceive what is happening to us, we would not feel pain for example as there would be no way for our brain to receive the message that the nervous system would send as there are no pathways. The Windows Messaging system is similar, events for example an input event such as a key press from the keyboard is relayed via the message stream to the our program via the OS. If we need the message then we deal with it if not we ignore it.


Dissecting the program

The most important part of our windows program is the function WinMain. It is the initial entry point of our application and the OS calls this function when starting the window. The job of WinMain is to set up the program, and then to set up the main message loop for the program.

The definition for our WinMain function is as follows:


int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)



The first parameter - HINSTANCE hInstance - identifies the instance of the program being called.

The second parameter - HINSTANCE hPrevInstance - identifies the previous instance of the program, if hPrevInstance is NULL then this is the first instance of the program. It is generally routine to check if the hInstance is the same as hPrevInstance as you do not want the same two instances running at once and if that is the case, then you normally kill hPrevInstance.

The third parameter is a string that contains the command-line parameters passed to the program (if any).

The fourth parameter specifies how the program window is to be displayed.

There is a essential part in WinMain which is where we set the window's properties namely by creating a WNDCLASS object wc and registering our form with windows. This details of the properties are listed in the comments, but take another look:


	//set the new window's properties
	WNDCLASSEX wc; 
	wc.cbSize = sizeof(WNDCLASSEX); 
	wc.style = CS_HREDRAW | CS_VREDRAW; //this is necessary to ensure that the window is redrawn if the width or height of the window is changed
	wc.lpfnWndProc = (WNDPROC) WinProc; //Here we set our message handler namely to our WinProc function, without this our window cannot handle messages as it has no means to do so
	wc.cbClsExtra = 0; //add extra bytes of memory to a windows procedure, not needed in this case
	wc.cbWndExtra = 0; //add extra bytes of memory to a windows procedure, not needed in this case
	wc.hInstance = hInstance; //set the instance of our window
	wc.hIcon = NULL; //set the window icon 
	wc.hCursor = LoadCursor(NULL, IDC_ARROW); //set the window's cursor
	wc.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH); //set the background colour (white in this case)
	wc.lpszMenuName = NULL; //set's the menu, we do not use a menu as of now
	wc.lpszClassName = WINDOWTITLE.c_str(); //sets the class name, this is essential as it gives the window a specific class name and is used for message handling along with hWnd
	wc.hIconSm = NULL;  
	RegisterClassEx(&wc); //register the window with Windows



You can look here for a more detailed summary.

We set the following window's properties which are fairly standard for a windows program:

WinMain is simple enough and is kind of the same as the main function in a console program.

Okay now the next fundamental function is a callback function called WinProc.

The WinProc function is created so that our program has a means of handling the input/messages that the Windows system sends to it.

The WinProc function looks like this:

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


The first parameter - HWND hWnd - is the window handle.

The second parameter - UINT message - is the message that is being sent to the window callback procedure.

The WPARAM and LPARAM parameters contain extra information about certain messages. You do not need to worry about this for now.

The logic behind the WinProc function is easy enough, lets review the code:


LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
//WinProc recieves and handles messages, it is a callback function that handles all of the messages sent to the main program window.

	switch (message) {
	case WM_PAINT:
		{
		//get the dimensions of the window
		RECT windowDimensions;
		GetClientRect(hWnd, &windowDimensions);

		//start drawing on device context
		PAINTSTRUCT ps;
		HDC hdc = BeginPaint(hWnd, &ps);
		
		//draw some text
		DrawText(hdc, WINDOWTITLE.c_str(), WINDOWTITLE.length(), &windowDimensions, DT_CENTER);

			//stop drawing
		EndPaint(hWnd, &ps);
		break;
		}

	case WM_DESTROY:
	PostQuitMessage(0);
	break;

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



We used a switch statement to handle the various messages that we want to. (You could use if statements but I find this easier). Here we have handled two messages WM_PAINT and WM_DESTROY .

WM_PAINT refers to actually drawing in our window. We first get the dimensions of the screen and store them in a RECT variable as this is necessary for our DrawText() function. We then use a PAINTSTRUCT variable which is used to start and stop a screen update. We then create a variable hdc that receives the device context that we are going to draw onto. We then use the DrawText function to draw some text to the screen and once we are done, we then use the EndPaint() function and pass our window handle and the PAINTSTRUCT, this unlocks the device again. The device is "locked" so to speak during the period when we are drawing text so that the screen does not refresh and we might get interrupted whilst painting, do not be too worried about this. It is just an aesthetic feature to make our first window program more interesting.

The WM_DESTROY message tells the window that is it time to exit. We simply close the game loop and PostQuitMessage(0); which essentially tells Windows that our program exited successfully and no errors occurred.

If there are messages that we have not used, we throw them back to the message stream with:
return DefWindowProc(hWnd, message, wParam, lParam);

Whew! We are going at a fast pace as this stuff is rather easy? You may not understand it all now but you will hopefully understand it as you use it in the next couple of tutorials.

WinProc and WinMain work together to handle application events such as responding to key input.

Here is a nice way to think about how these two functions work together:


Spoiler


Now let's dissect createInstance. It is not an essential function like WinProc or WinMain and it's code could be in our WinMain function but it is easier to look at this way :)

Here is the code:



/* 
 * Helper function to create the window 
 */

bool createInstance(HINSTANCE hInstance, int nCmdShow)
	//HINSTANCE passes the program instance that it recieves from windows
{

//create a new window
HWND hWnd = CreateWindow ( 
	WINDOWTITLE.c_str(), //window class
	WINDOWTITLE.c_str(), // title bar
	WS_OVERLAPPEDWINDOW, //window style
	CW_USEDEFAULT, CW_USEDEFAULT, //position of window (x, y)
	640, 480, //size of window
	NULL, //parent window (not used)
	NULL, //menu (not used)
	hInstance, //application instance
	NULL);
	
//was there an error in creating the window?
if (hWnd == 0) return 0;

//Display the window
ShowWindow(hWnd,nCmdShow);
UpdateWindow(hWnd); //sends a WM_PAINT message to the window handler, telling the window to draw itself (internal communication is common in windows programming)
return 1; //return true, everything went ok
	
}



The definition for this function that we used is:

 bool createInstance (HINSTANCE hInstance, int nCmdShow) 


The two parameters are easy enough:
The first parameter - HINSTANCE hInstance - is passed by WinMain with the program instance that it receives from windows (i.e. the instance that is running).

The second parameter - int nCmdShow - is passed by WinMain which WinMain receives from Windows. It contains extra properties such as SW_HIDE (hide the window), but we do not use it for now.

The rest of the application is fairly simple enough. We create a handle to the window that we are going to create and then we set basic properties such as dimension of the window, title bar etc... We then check if there was any errors whilst creating the window handle if so we return 0 (or false) otherwise we display the window using the ShowWindow and UpdateWindow functions. If all went well, we update WinMain that the Window was created successfully by returning 1 (or true).

createInstance in essence creates our user interface.


Making it all work together

Finally we must make all our functions work together to run our program effectively, the onus is placed on WinMain, take another look at the function:



/* 
 * Entry point for a windows program
 */ 

int WINAPI WinMain(HINSTANCE hInstance,
	               HINSTANCE hPrevInstance,
				   LPSTR lpCmdLine,
				   int nCmdShow)
{

	//set the new window's properties
	WNDCLASSEX wc; 
	wc.cbSize = sizeof(WNDCLASSEX); 
	wc.style = CS_HREDRAW | CS_VREDRAW; //this is necessary to ensure that the window is redrawn if the width or height of the window is changed
	wc.lpfnWndProc = (WNDPROC) WinProc; //Here we set our message handler namely to our WinProc function, without this our window cannot handle messages as it has no means to do so
	wc.cbClsExtra = 0; //add extra bytes of memory to a windows procedure, not needed in this case
	wc.cbWndExtra = 0; //add extra bytes of memory to a windows procedure, not needed in this case
	wc.hInstance = hInstance; //set the instance of our window
	wc.hIcon = NULL; //set the window icon 
	wc.hCursor = LoadCursor(NULL, IDC_ARROW); //set the window's cursor
	wc.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH); //set the background colour (white in this case)
	wc.lpszMenuName = NULL; //set's the menu, we do not use a menu as of now
	wc.lpszClassName = WINDOWTITLE.c_str(); //sets the class name, this is essential as it gives the window a specific class name and is used for message handling along with hWnd
	wc.hIconSm = NULL;  
	RegisterClassEx(&wc); //register the window with Windows

		if (!createInstance(hInstance,nCmdShow)) return 0; //createInstance is a helper function that basically creates the program window
// ^ test if something went wrong creating the window, if so then exit


//main message loop
MSG msg;
		while (GetMessage(&msg, NULL,0, 0))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);

		}
return msg.wParam;
}



The logic is pretty simple, we first set up the window's properties and then we create the window by calling createInstance. If something went wrong, we return a value of 0 to indicate that program execution failed otherwise we get into our message loop. This message loop is event-driven in otherwards it will keep running whilst events are occuring then it will handle the messages appropriately. note that the MSG variable contains the actual data concerning the messages.

NOTE: You may get a error when using c_str(), the workaround is to make sure your project is using multi-byte settings and not unicode, in VS2010, You would simply go:
Project -> Properties -> Configuration Properties: General -> Charachter Set and select use multi-byte charachter set.

That's it for our basic Win32 Primer and I hope it has helped!


Initializing DirectX:

Now that we have the basics of windows out of the way, we can begin looking at how to setup the DirectX SDK.

DirectX is basically just an API (Application Programming Interface) that provides an interface to the low-level hardware and provides us with the tools necessary so that we can develop games without the use of the API or GDI. DirectX is much faster than the latter solution too!

DirectX is closely integrated with Windows and will not work on any other O/S as it relies on the basic libraries in the Windows API to run.

Let's go over some of the DirectX components that we will end up using:

  • Direct3D -This is the rendering component that provides access to the video card and renders our 2D or 3D Graphics!
  • DirectSound - This is the older audio component that was used to play audio, we will use XACT.
  • XACT - This is the new audio system that DirectX provides, it is also used in the XNA Game Studio SDK.
  • DirectInput - This is the component of DirectX that handles recieving input from peripheral devices such as the keyboard, mouse etc...


Now that you have a basic overview, You must first actually install DirectX. The SDK can be downloaded from here.
Simply install it like a normal application once downloaded.

Okay we will now get to creating a program that initializes DirectX and creates a Direct3D Device. A Direct3D Device gives you access to the video card's primary surface.

In order to actually use Direct3D or DirectX. You must include the relevant headers, in this case. You must include: d3d9.h like so: #include <d3d9.h>

In order to access these headers, you must include the relevant libraries, either via the use of the pragma preprocessor directive or by actually configuring your IDE. If you are using Visual Studio 2010 Express then this tutorial is essential (or just google how to as there are numerous tutorials on how to do this) to learning how to configure the DirectX SDK so that you can use it.

Direct3D Interfaces:

In order to use Direct3D, you must have at minimum two variables, one for the Direct3D interface itself and one for the graphics device that you are using. In DirectX9, the direct3D interface is declared like so:

LPDIRECT3D9 d3d = NULL;



whilst the graphics device (or object) is declared like so:

LPDIRECT3DDEVICE9 d3ddev = NULL;



The LPDIRECT3D9 object is the object that controls all rendering whilst the LPDIRECT3DDEVICE9 simply gives us access to the graphics card. The prefix LP indicates that this is a Long Pointer which operate exactly the same as regular pointer on 32 bit machines. For more, you can try take a look at this.

(Excuse me for all the links in this tutorial but I would have to write practically an entire book if I tried to explain every miniscule detail.)

Now that we have a d3d variable, we must intialize it like so:

d3d = Direct3DCreate9(D3D_SDK_VERSION); //D3D_SDK_VERSION is stored in d3d9.h




We can now use the CreateDevice function to create the device upon which Direct3D will display output namely d3ddev like so:

d3d-> CreateDevice(
D3DADAPTER_DEFAULT, //use default video card
D3DDEVTYPE_HAL, //use the hardware renderer
hWnd, //our current window handle
D3DCREATE_SOFTWARE_VERTEXPROCESSING, 
&d3dpp, //D3DPRESENT_PARAMETERS
&d3ddev); //graphics device



You may have noticed that we passed by reference, a variable called d3dpp. What is this? You ask?

Well d3dpp refers to D3DPRESENT_PARAMETERS which refers to the device parameters or more specifically how the window will be presented when we use the Present() method (more on this later).

We first define this struct before using it like so:

D3DPRESENT_PARAMETERS d3dpp;



We then clear out the memory so that no anomalies occur like so:
ZeroMemory(&d3dpp, sizeof(d3dpp));



There are a lot of options for the D3DPRESENT_PARAMETERS but we use the following:

 d3dpp.Windowed = TRUE; //set to TRUE for windowed mode
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; //swapping method for our back buffer 
    d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8; //sets the format of our back buffer
    d3dpp.BackBufferCount = 1; //sets number of backbuffers
    d3dpp.BackBufferWidth = SCREENW; //sets width of backbuffer
    d3dpp.BackBufferHeight = SCREENH; //sets height of backbuffer
    d3dpp.hDeviceWindow = window; //specifies current window 



For a more in-depth review of the options, look here.


Well that is the basics, that will set up our DIRECT3D and DIRECT3DDEVICE interfaces but what good is this doing us now? Well at the moment, nothing... (Nothing will even be shown on the window)

Making the Direct3D Device do something

We have a Game_Update function that actually makes use of what Direct3D setup, take a look at it here:

/*
 * Game update function
 */
void Game_Update(HWND hwnd)
{
    //make sure the Direct3D device is valid
    if (!d3ddev) return;

    //clear the backbuffer to bright blue
    d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(,0,255), 1.0f, 0);
    
    //start rendering
    if (d3ddev->BeginScene())
    {
        //do something?
    
        //stop rendering
        d3ddev->EndScene();

        //copy back buffer on the screen
        d3ddev->Present(NULL, NULL, NULL, NULL);
    }

} 



We first off make sure that our Direct3D device is initialized correctly.
We then call a function called clear and what this literally does is clear the back buffer to a colour. In this case, we clear it to red but you could clear it to any colour really (black - 0,0,0 is common). The purpose of this is so that upon new frame is drawn, the backbuffer is cleared completely so that we do not end up with graphical artifacts or stuff that we did not mean to redraw.

We then begin rendering by rendering BeginScene() and then we stop rendering with EndScene(). At the moment we are not rendering any bitmaps etc but this is necessary in order to actually render to the graphics device' back buffer. We finally call a function called Present() and this copies our back buffer to the front buffer which is then displayed on the screen.

The last part is a function called Game_End(HWND hwnd):


void Game_End(HWND hwnd)
{
    //display close message
    MessageBox(hwnd, "Program is about to end", "Game_End", MB_OK);

    //free memory
    if (d3ddev) d3ddev->Release();
    if (d3d) d3d->Release();
}




We simply use a MessageBox to display to the user that our program is going to end and then we free the memory so that our Direct3D interfaces do not point to nothing. The Game_End function is called when a WM_DESTROY message occurs and this occurs by default when the user clicks the "X" button on the top of the frame.

Double-Buffering
You probably heard me babble on about backbuffer and front buffer's here and there, well this is a method that we use called double-buffering which is used to display smooth graphics. A simple explanation of this concept is the following:

We draw whatever we need to draw to a back buffer and then when we have drawn what we needed to, to the back buffer we can copy it straight to the front buffer of our graphics device and thus it will be displayed on the screen as one complete image. If we used a single buffer and only drew to that then the problem is that as we drew more, the user would see the actual objects being drawn which would result in flickering etc...

Here is a image so that you get what I mean:

Posted Image

Time to run it for yourself!

Ok hopefully you have had the patience to wade through all this text but for now let's actually create your first DirectX 9.0c program! Here is the code:

#include <windows.h>
#include <d3d9.h>
#include <time.h>
#include <iostream>
using namespace std;

//program settings
const string WINDOWTITLE = "Direct3D_Windowed";
const int SCREENW = 1024;
const int SCREENH = 768;

//Direct3D objects
LPDIRECT3D9 d3d = NULL; //d3d 
LPDIRECT3DDEVICE9 d3ddev = NULL; //d3d device

bool gameover = false;

/* 
 * Helper function to create the window 
 */

HWND createInstance(HINSTANCE hInstance, int nCmdShow)
	//HINSTANCE passes the program instance that it recieves from windows
{

//create a new window
HWND hWnd = CreateWindow ( 
	WINDOWTITLE.c_str(), //window class
	WINDOWTITLE.c_str(), // title bar
	WS_OVERLAPPEDWINDOW, //window style
	CW_USEDEFAULT, CW_USEDEFAULT, //position of window (x, y)
	640, 480, //size of window
	NULL, //parent window (not used)
	NULL, //menu (not used)
	hInstance, //application instance
	NULL);
	
//was there an error in creating the window?
if (hWnd == 0) return 0;

//Display the window
ShowWindow(hWnd,nCmdShow);
UpdateWindow(hWnd); //sends a WM_PAINT message to the window handler, telling the window to draw itself (internal communication is common in windows programming)
return hWnd; //return the window so that our Direct3D Device can work with it!
	
}



/*
 * Direct3D_Init, this is where we initialize our various DirectX components or in this case Direct3D
 */


bool Direct3D_Init(HWND window)
{
    MessageBox(window, "Game_Init", "BREAKPOINT", 0);

    //initialize Direct3D
    d3d = Direct3DCreate9(D3D_SDK_VERSION);
    if (d3d == NULL)
    {
        MessageBox(window, "Error initializing Direct3D", "Error", MB_OK);
        return 0;
    }

    //set Direct3D presentation parameters
    D3DPRESENT_PARAMETERS d3dpp; 
    ZeroMemory(&d3dpp, sizeof(d3dpp));
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
    d3dpp.BackBufferCount = 1;
    d3dpp.BackBufferWidth = SCREENW;
    d3dpp.BackBufferHeight = SCREENH;
    d3dpp.hDeviceWindow = window;

    //create Direct3D device
    d3d->CreateDevice(
        D3DADAPTER_DEFAULT, 
        D3DDEVTYPE_HAL, 
        window,
        D3DCREATE_SOFTWARE_VERTEXPROCESSING,
        &d3dpp, 
        &d3ddev);

    if (d3ddev == NULL)
    {
        MessageBox(window, "Error creating Direct3D device", "Error", MB_OK);
        return 0;
    }

    return true;
}

/**
 ** Game update function
 **/
void Game_Update(HWND hwnd)
{
    //make sure the Direct3D device is valid
    if (!d3ddev) return;

    //clear the backbuffer to bright green
    d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(255,0,0), 1.0f, 0);
    
    //start rendering
    if (d3ddev->BeginScene())
    {
        //do something?
    
        //stop rendering
        d3ddev->EndScene();

        //copy back buffer on the screen
        d3ddev->Present(NULL, NULL, NULL, NULL);
    }

}

/*
 * Game shutdown function
 */
void Game_End(HWND hwnd)
{
    //display close message
    MessageBox(hwnd, "Program is about to end", "Game_End", MB_OK);

    //free memory
    if (d3ddev) d3ddev->Release();
    if (d3d) d3d->Release();
}


/*
 * Windows event handling function
 */
LRESULT WINAPI WinProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
    switch( msg )
    {
        case WM_DESTROY:
            gameover = true;
            PostQuitMessage(0);
            return 0;
    }
    return DefWindowProc( hWnd, msg, wParam, lParam );
}

/*
 * Main Windows entry function
 */

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    //set the new window's properties
    WNDCLASSEX wc;
    wc.cbSize = sizeof(WNDCLASSEX); 
    wc.style         = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc   = (WNDPROC)WinProc;
    wc.cbClsExtra     = 0;
    wc.cbWndExtra     = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = NULL;
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = WINDOWTITLE.c_str();
    wc.hIconSm       = NULL;
    RegisterClassEx(&wc);

   //create the window
	HWND window = createInstance(hInstance,nCmdShow);
	if (window == NULL) return 0;
    
    //initialize Direct3D 
    if (!Direct3D_Init(window)) return 0;


    // main message loop
    MSG message;
    while (!gameover)
    {
        if (PeekMessage(&message, NULL, 0, 0, PM_REMOVE)) 
        {
            TranslateMessage(&message);
            DispatchMessage(&message); 
        }

        Game_Update(window);
    }

    Game_End(window);

    return message.wParam;
}




You should get an output like this:

Posted Image

And that's it for the basics on Windows Programming and how to Initialize DirectX. I may have omitted a couple of things to keep this tutorial shorter but I will explain them in the next few tutorials if necessary. I hope this tutorial has helped you! I will publish a couple more on the basics and in the end maybe publish a tutorial on how to make a simple game with DirectX. Thanks for your time.

--v0rtex

This post has been edited by v0rtex: 18 June 2012 - 06:16 AM


Is This A Good Question/Topic? 3
  • +

Replies To: DirectX Introduction: Win32 Primer and Initializing DirectX 9

#2 alpha_x  Icon User is offline

  • D.I.C Head

Reputation: 6
  • View blog
  • Posts: 55
  • Joined: 03-May 11

Posted 18 June 2012 - 06:18 AM

Nice work :^: Looking forward to the next one!
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1