Wednesday, October 29, 2008

Device Creation (and other bits) in C++

OK, this is not as strait forward as it is in XNA :P What I have done to help me out is create a utility class. This class holds a few methods at the moment and at the time of posting, the header file looks like this:

class RC3DUtility

LPDIRECT3DDEVICE9 InitializeDevice(HWND hwnd,UINT width,UINT height);
HWND CreateNewWindow(LPCTSTR str_Title,int int_XPos, int int_YPos, int int_Width, int int_Height,WNDPROC callBack);

LPDIRECTINPUTDEVICE8 InitializeKeyboard(HWND hwnd);

static float Clamp(float val,float min,float max);

static void Translate(D3DXVECTOR3 *outPosition,D3DXVECTOR3 distance,D3DXQUATERNION *rotation);
static void Rotate(D3DXQUATERNION *outRotation,D3DXVECTOR3 axis, float angle,D3DXQUATERNION *rotation);

LPDIRECT3DDEVICE9 graphicsDevice;

As you can see we have a constructor and corresponding destructor. A method to create and initialise the graphics driver, a method to create a window the application will run in, a method to initialise the keyboards for input, my own Clamp method (could not find one natively, though there must be one....), translate and rotate methods so I don't have to have these methods in each of my game objects. and finally, two members; a graphics device and an input device for the keyboard.

So there is a fair bit in here already, but once I have these out of the way, we can get onto some more interesting stuff....

The most important of the lot is InitializeDevice, this is the method that is going to give you your graphics device and allow you to draw your stuff. (I know, the window creation is important, but as I said in the last post, this is covered in Riemers tutorial so I wont cover it here)


LPDIRECT3DDEVICE9 RC3DUtility::InitializeDevice(HWND hwnd, UINT width,UINT height) 
LPDIRECT3D9 dx_Object;

dx_Object = Direct3DCreate9(D3D_SDK_VERSION);
if (dx_Object == NULL)
MessageBox(hwnd,"DirectX Runtime library not installed!","InitializeDevice()",MB_OK);

ZeroMemory(&dx_PresParams, sizeof(dx_PresParams));

dx_PresParams.Windowed = TRUE;
dx_PresParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
dx_PresParams.BackBufferFormat = D3DFMT_UNKNOWN;
dx_PresParams.BackBufferHeight = height;
dx_PresParams.EnableAutoDepthStencil = TRUE;
dx_PresParams.AutoDepthStencilFormat = D3DFMT_D16;
dx_PresParams.BackBufferWidth = width;

if (FAILED(dx_Object->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &dx_PresParams, &graphicsDevice)))
if (FAILED(dx_Object->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &dx_PresParams, &graphicsDevice)))
if (FAILED(dx_Object->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &dx_PresParams, &graphicsDevice)))
MessageBox(hwnd,"Failed to create graphics device!","InitializeDevice()",MB_OK);

graphicsDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
graphicsDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
graphicsDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);

return graphicsDevice;

Again similar to Riemers code, but a few differences. Setting up the interface and presentation parameters is pretty much the same, but when creating the device I have added another layer. My laptop successfully created the device with the original code, but it's performance sucked. I found that I needed a combination of the two methods to get decent performance. So the method does a hardware  driver and hardware vertex processing, if this fails it tries a hardware driver, software vertex processing (works for my laptop) and if that fails it then tries a reference rasteriser with software vertex processing (also works on my laptop but sux). I guess you could also try a ref & hardware vertex processing to.

I guess what I am trying to illustrate here is that to get your software to run on another PC, and run well, you really need to detect the capabilities of the card you are about to run on. So for your own stuff running on you PC you will be fine to write what you like, BUT if you want your game to run well on another system you are going to have to write some code to get the optimal settings for the system you are running on. Now, I am totally new to this, so I am guessing this is an art in it's self, but the SDK comes with some nice code samples that do just this. I don't know how well they work, but they seem to do the job on my PC. If I do get into this then I will post my implementation of graphics card capabilities detection routines.

Again, the keyboard initialisation code is the same as before, but the other three methods look like this:

float RC3DUtility::Clamp(float val, float min, float max)
if( val > max )
val = max;
( val < min )
val = min;

return val;
void RC3DUtility::Rotate(D3DXQUATERNION *outRotation, D3DXVECTOR3 axis, float angle, D3DXQUATERNION *rotation)

void RC3DUtility::Translate(D3DXVECTOR3 *outPosition, D3DXVECTOR3 distance, D3DXQUATERNION *rotation)


*outPosition += outPos;

So, this is the start, my next post will show the camera class I have created, again, it is pretty much a direct copy of my XNA camera class. I know this post is probably not going to get you going, but it's a start. Once I have put the camera code up and the terrain class I'll put up a downloadable solution you can run and see how it all hangs together.

My C++ is pretty rusty I know, and I am totally new to DirectX in C++ but, as ever, your comments and criticisms are welcome.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.