(edit) Code was too long for forum. I'm splitting it in 1/2
I'm currently working on a Direct3D class that simplifies D3D, so I can use it to make games, applications, etc.
I started on it yesterday, got it to work so it draw triangles with a different color on each vertex, and made a function that draws 2 triangles to make a quadrilateral(or at least something with 4 vertexes).
Now, before I started on making textures for the triangles/quads, I put better error handling in. Everything seemed fine. So I went and started a few changes, so I could have textures. I changed this line:
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW |D3DFVF_DIFFUSE )
to
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ |D3DFVF_TEX1 )
I updated the structure. I ran the program to see if it still worked(which it shouldn't), and it didn't, so everything went as planned. I updated the rest of the program, and when I was done, bad things happened. I went and put debug info all around the program(in addition to the message box that popped up whenever a function failed), and tried to determine the source of the problem. A few hours later, I found that for some reason, the device was lost as soon as it was created(or at least when I tried to render triangles). Interestingly, the device wasn't lost before a particular function was called, but when it was called, at the start of the function(before any code was really executed there), it was lost.
Here's the full code to the program. I think I broke it more than it was before, but does anyone have any idea what's wrong with it:
Main header file:
#include <windows.h>
#include <vector>
#include <d3d9.h>
#include <d3dx9.h>
#define DIRECTINPUT_VERSION 0x0800
#include <dinput.h>
#include <time.h>
#include <stdio.h>
using namespace std;
extern HWND hwnd;
extern HINSTANCE hinstance;
extern bool running;
char *GetError(int error);
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW |D3DFVF_DIFFUSE )
struct VERTEX
{
FLOAT x, y, z, rhw; // The transformed position for the vertex
DWORD color; // The vertex color
};
class Direct3D {
IDirect3D9 *d3d;
IDirect3DDevice9 *d3ddevice;
D3DDISPLAYMODE displaymode;
int error;
LPDIRECT3DVERTEXBUFFER9 vertex_buffer;
vector<IDirect3DTexture9 *> surfaces;
public:
Initialize(void);
void StartRender(void);
void DrawTriangle(VERTEX[3]);
void DrawSquare(VERTEX[4]);
int LoadSprite(char *file);
void DrawSprite(int,int,int,int,int);
void EndRender(void);
void UnloseDevice(void);
void ErrorHandle(int,char *);
~Direct3D(void);
bool Check(void);
};
class DirectInput {
IDirectInput8 *dinput;
IDirectInputDevice8 *keyboard;
IDirectInputDevice8 *mouse;
DIDEVCAPS mouse_data;
DIDEVCAPS keyboard_data;
unsigned char *buffer;
HANDLE mouse_event;
DIMOUSESTATE mouse_state;
public:
int mouse_x,mouse_y;
Initialize(void);
int KeyPressed(int);
int MousePressed(int);
void Update();
~DirectInput(void);
};
Direct3D class:
#include "main.h"
/**************************
Some comments:
1. I use ErrorHandle() alot here. It can be confusing to understand what a section of code is doing when it's like this:
ErrorHandle(function here,"Message);
All it does it check the return value of function for errors, and does what it needs. Tab the left and right of the
ErrorHandle function if it's difficult to understand the code since it's packed between a Errorhandle( and a ,"message");
2. What this code is, is the source code for a Direct3D class.
**************************/
Direct3D::Initialize(void) {
error = 0;
char *message = NULL;
if (NULL == (d3d = Direct3DCreate9(D3D_SDK_VERSION))) {//Creates D3D object
MessageBox(NULL,"Couldn't create D3D","Error",0);
running = false;//Program can't work if D3D isn't working
}
if (running) {
if (FAILED(d3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&displaymode))) {
MessageBox(NULL,"Couldn't get info on your display mode adapter.","Environment = teh screwed",0);
running = false;
}
D3DPRESENT_PARAMETERS d3dpp; //Get parameters working
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = FALSE;
d3dpp.SwapEffect = D3DSWAPEFFECT_FLIP;
d3dpp.BackBufferFormat = displaymode.Format;
d3dpp.BackBufferWidth = 640;
d3dpp.BackBufferHeight = 480;
d3dpp.BackBufferCount = 2;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.MultiSampleQuality = 0;
d3dpp.hDeviceWindow = hwnd;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
d3dpp.Flags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
d3dpp.FullScreen_RefreshRateInHz = 0;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
if (running) {
//Test if we can make a HAL device
if (SUCCEEDED(error = d3d->CheckDeviceType(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,displaymode.Format,displaymode.Format,TRUE))) {
if( FAILED( error = d3d->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,//Make device for D3D
D3DCREATE_SOFTWARE_VERTEXPROCESSING,&d3dpp, &d3ddevice ) ) ) {//Continuing...
message = GetError(error);
MessageBox(NULL,"D3D device initialization failed",message,0);
running = false;
}
} else {
message = GetError(error);
MessageBox(NULL,"Hardware Abstraction Layer device can't be made on your comp",message,0);
running = false;
}
}
}
error = d3ddevice->CreateVertexBuffer(3*sizeof(VERTEX),0,D3DFVF_CUSTOMVERTEX,D3DPOOL_DEFAULT,&vertex_buffer,NULL);
ErrorHandle(error,"Couldn't create vertex buffers");
// We're going to handle lighting ourselves, for now
d3ddevice->SetRenderState( D3DRS_LIGHTING, FALSE );
// Turn on the zbuffer
d3ddevice->SetRenderState( D3DRS_ZENABLE, TRUE );
if (!running) {
MessageBox(NULL,"Code ain't working. Direct3D ain't working. No game for you!","Exiting...",0);
PostQuitMessage(0);
}
}
Direct3D::~Direct3D(void) {
if( d3ddevice != NULL)
d3ddevice->Release();
if( d3d != NULL)
d3d->Release();
}
void Direct3D::StartRender(void) {
d3ddevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );
error = d3ddevice->BeginScene();
ErrorHandle(error,"Couldn't start the render");
}
char *GetError(int error) {
switch (error) {
case D3DERR_INVALIDCALL: return "Invalid function call";
case D3DERR_NOTAVAILABLE: return "Comp sucks too much to make device";
case D3DERR_OUTOFVIDEOMEMORY: return "No more memory for comp. Get a new video card.";
case E_OUTOFMEMORY: return "No more memory for comp. Grab some more RAM somewhere.";
case D3D_OK: return "Everything went fine. Error function called for no reason. This is prolly' a bug if displayed.";
case D3DERR_DRIVERINTERNALERROR: return "Driver had an internal error. Might wanna' fix that, cause' this game ain't workin' till' you do";
case D3DERR_DEVICELOST: return "Lost the device";
}
return "Unknown error occured.";
}
void Direct3D::DrawTriangle(VERTEX vertexes[3]) {
VOID* pVertices;
//Lock vertex buffers
ErrorHandle(vertex_buffer->Lock( 0, sizeof(VERTEX)*3, (void**)&pVertices, 0 ),"I couldn't lock the vertex buffers.");
memcpy( pVertices, vertexes, sizeof(VERTEX)*3 );
//Unlock the vertex buffers, set stream sources, set FVF, and draw primitives. Pass return value to error handler.
ErrorHandle(vertex_buffer->Unlock(),"I couldn't unlock vertex buffers. They don't like me....");
ErrorHandle(d3ddevice->SetStreamSource( 0, vertex_buffer, 0, sizeof(VERTEX) ),"I couldn't set stream source");
ErrorHandle(d3ddevice->SetFVF( D3DFVF_CUSTOMVERTEX ),"I couldn't set Flexible Vertex Format(FVF) for vertexes");
ErrorHandle(d3ddevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 1 ),"Couldn't draw triangles");
}
void Direct3D::EndRender(void) {
ErrorHandle(d3ddevice->EndScene(),"Couldn't end rendering.");
ErrorHandle(d3ddevice->Present(NULL,NULL,NULL,NULL),"Couldn't draw vertexes on screen");
}
void Direct3D::DrawSquare(VERTEX vertexes[4]) {
VERTEX temp[3];
temp[0] = vertexes[0];
temp[1] = vertexes[1];
temp[2] = vertexes[2];
DrawTriangle(temp);
temp[0] = vertexes[1];
temp[1] = vertexes[0];
temp[2] = vertexes[3];
DrawTriangle(temp);
}
int Direct3D::LoadSprite(char *file) {
IDirect3DTexture9 *surface;
if (FAILED(error = D3DXCreateTextureFromFile(d3ddevice,file,&surface))) {
running = false;
MessageBox(NULL,"Couldn't load sprite",GetError(error),0);
}
return surfaces.size();
surfaces.push_back(surface);
}
void Direct3D::DrawSprite(int number,int x,int y, int width,int height) {
}
bool Direct3D::Check(void) {
if (FAILED(d3ddevice->TestCooperativeLevel())) return true;
return false;
}
void Direct3D::ErrorHandle(int error,char *message) {
bool normal = false;
switch (error) {
case D3DERR_INVALIDCALL: normal = true;break;
case D3DERR_NOTAVAILABLE:normal = true;break;
case D3DERR_OUTOFVIDEOMEMORY:normal = true;break;
case E_OUTOFMEMORY:normal = true;break;
case D3D_OK:break;
case D3DERR_DRIVERINTERNALERROR:normal = true;break;
case D3DERR_DEVICELOST: normal = true;break;
default: normal = true;break;
}
if (normal) {
running = false;
MessageBox(hwnd,message,GetError(error),0);
}
}
DirectInput class(probably unrelated, but it's still part of the code):