Google
 

Thursday, October 30, 2008

BaseCamera Class

As I have said before, this is identical to my XNA camera. I know, not the best camera in the world, but this is the base of other cameras I will be producing later. So, as before we have a header file and cpp file.

The header looks like this:
#include <d3d9.h> 
#include <d3dx9.h>

#include "RandomChaos3DUtility.h"

#pragma once

class
BaseCamera
{
public:
BaseCamera(void);
BaseCamera(LPDIRECT3DDEVICE9 *p_dx_Device,D3DXVECTOR3 pos,D3DXVECTOR3 worldUp,D3DXQUATERNION rot, UINT width,UINT height);
~BaseCamera(void);

D3DXMATRIX GetView();
D3DXMATRIX GetProjection();

void Update();

void Translate(D3DXVECTOR3 distance);
void Rotate(D3DXVECTOR3 axis, float angle);

void SetPosition(D3DXVECTOR3 newPos);
void SetTarget(D3DXVECTOR3 newTarget);
void SetRotation(D3DXQUATERNION newRotation);

UINT Width;
UINT Height;

D3DXVECTOR3 GetPosition(void);

protected:
LPDIRECT3DDEVICE9 *graphicsDevice;

D3DXVECTOR3 position;
D3DXVECTOR3 target;
D3DXVECTOR3 worldUpVector;
D3DXQUATERNION rotation;

D3DXMATRIX view;
D3DXMATRIX projection;
};



The ctor and dtor are there as expected, then two methods to get the cameras View and Projection Matrix, an update method, translate and rotate then methods to set the position, target and rotation, height and width (for the viewport)  and finally a method to get the camera position. Then the protected members.

The methods look like this:

#include "RandomChaos3DCamera.h"

BaseCamera::BaseCamera(void)
{
position = D3DXVECTOR3(0,0,0);
worldUpVector = D3DXVECTOR3(0,1,0);
rotation = D3DXQUATERNION(0,0,0,1);
}
BaseCamera::BaseCamera(LPDIRECT3DDEVICE9 *Device,D3DXVECTOR3 pos, D3DXVECTOR3 worldUp, D3DXQUATERNION rot,UINT width,UINT height)
{
graphicsDevice = Device;
position = pos;
worldUpVector = worldUp;
rotation = rot;
Width = width;
Height = height;
}
BaseCamera::~BaseCamera(void)
{
}
D3DXMATRIX BaseCamera::GetProjection()
{
return projection;
}
D3DXMATRIX BaseCamera::GetView()
{
return view;
}
void BaseCamera::Update()
{
D3DXMATRIX rotMat;
D3DXMATRIX posMat;

D3DXMatrixRotationQuaternion(&rotMat,&rotation);
D3DXMatrixTranslation(&posMat,position.x,position.y,position.z);

D3DXMatrixMultiply(&rotMat,&rotMat,&posMat);
float md = D3DXMatrixDeterminant(&rotMat);

D3DXMatrixInverse(&view,&md,&rotMat);
D3DXMatrixPerspectiveFovRH(&projection, D3DX_PI/3.0, (float)Width/(float)Height, 1, 10000);
}
void BaseCamera::Translate(D3DXVECTOR3 distance)
{
RC3DUtility::Translate(&position,distance,&rotation);

Update();

}
void BaseCamera::Rotate(D3DXVECTOR3 axis, float angle)
{
RC3DUtility::Rotate(&rotation,axis,angle,&rotation);
Update();
}
void BaseCamera::SetPosition(D3DXVECTOR3 newPos)
{
position = newPos;
}
void BaseCamera::SetRotation(D3DXQUATERNION newRotation)
{
rotation = newRotation;
}
D3DXVECTOR3 BaseCamera::GetPosition(void)
{
return position;
}



Not sure what else to add here, it is pretty simple stuff, the only method of real note is the Update method as this is where the View and Projection Matrices are set, but this is done exactly the same as before in my XNA Camera class.

This post has been a bit light I know, the terrain class will be next and then the main.cpp, this will show how it all hangs together and in that last post I will put up a solution to download so you can have a play with it.

As ever C&C are welcome :)

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
{
public:
RC3DUtility(void);
~RC3DUtility(void);

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;
LPDIRECTINPUTDEVICE8 keyboard;
};



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)

InitializeDevice


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);
}

D3DPRESENT_PARAMETERS dx_PresParams;
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;
else
if
( val < min )
val = min;

return val;
}
void RC3DUtility::Rotate(D3DXQUATERNION *outRotation, D3DXVECTOR3 axis, float angle, D3DXQUATERNION *rotation)
{
D3DXQUATERNION outRot;
D3DXQuaternionRotationAxis(&outRot,&axis,angle);

D3DXQuaternionMultiply(outRotation,&outRot,rotation);
}
void RC3DUtility::Translate(D3DXVECTOR3 *outPosition, D3DXVECTOR3 distance, D3DXQUATERNION *rotation)
{
D3DXVECTOR3 outPos;
D3DXMATRIX rotMat;

D3DXMatrixRotationQuaternion(&rotMat,rotation);
D3DXVec3TransformCoord(&outPos,&distance,&rotMat);

*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.

Tuesday, October 28, 2008

Nice Terrain in C++

And now I have my XNA terrain shader in my C++ terrain implementation. Again, no source yet, just wanted to post my progress so far. My next post I will start to put some code up. I am going to miss out the window creation code as this can be found in Riemers C++ tutorial, my method for creating the graphics device how ever is a little different and so I will post that.

It is not much different with how Riemer does it, but I had issues with his method, but this is going to be down to the fact that YOU the developer need to detect the capabilities of the graphics card your software is going to run on.

I may at some point post some code on how to go about detecting the card settings you can use at run time, what I will probably do is break down and simplify (if I can) the samples that can be found with the DirecX9 SDK.

Anyway, this is what my C++ terrain implementation looks like:

Monday, October 27, 2008

The Adventure Begins

Sorry, but no code in this post, I want to clean it up a bit and get my ful lterrain shader into the mix first.

What you can see in this clip though is my camera class and a basic terrain object. These classes are pretty much the same as the ones I have written in XNA just ported to C++, the shader is a simple blinn-phong shader.

So, this is what it looks like at the moment:

Thursday, October 16, 2008

Not been here for a while....

Well, it's been a while since I last posted here. As I am sure you know ALL my XNA blogging now occurs over at the XNA-UK User Group

I love XNA, in fact I am totally addicted to it and it has become something of an obsession so much so I decided this week to have a break and look at something else. So I have taken a look at using C++ with DirectX9....I know, not much different is it..

So what I intend to do with this old XNA blog is use it to blog about my journey. What I intend to do is port the things I have done in XNA over to C++. I have not coded in C++ for over 4 years, so I am waking up a very old and wrinkly part of my brain. I actually thought it was dead (not the whole brain, just the C++ bit), but it turns out to have a bit of life in it after all.

My first look at this lead me to a great opening tutorial by Riemer Grootjans which is similar to his XNA tutorial on terrain, but it's in C++ and it starts here.

So having got that under my belt and understood I have started my XNA port......

My next post will be my take on the tutorial and how I have created a camera class like the one I use in XNA.

As ever, your comments and critique are important to me, not just for debating the posts but for me to learn to, so please don't be shy with your remarks.