jimbobmcgee
asked on
C++/DX9 Beginner: Simple cube app not displaying cube (Code included)
I'm basically working through the tutorials on a DX9 book, trying to stay afloat with a limited knowledge of C++. I have my Window creation and Direct3D initialisation working and am now moving on to displaying a coloured cube. However, when I execute my program, the cube does not appear.
The basic structure of my WinMain() is:
- Create window (returning HWND)
- Init DX9 (returning IDirect3DDevice9*)
- Load cube vertexes/indexes into buffers (returning bool) (bool createCubeObject() -- see below)
- Enter MessageLoop
- Handle WM_QUIT
- Handle WM_xxx
- Display cube (bool doDisplayScene() -- see below)
- End MessageLoop
- Cleanup (void killBuffers() -- see below)
The buffers seem to be created, the Device->Clear's as expected, but the cube does not display. I expect it's just a scope error but I can't seem to spot it.
Either way, the code follows:
//// DIRECTIVES ////////////////////////// ////////// ////////// ////////// ///////
#include <d3dx9.h>
#include ".\initGlobals.h"
////////////////////////// ////////// ////////// ////////// ////////// ////////// ///
//// PROTOTYPES ////////////////////////// ////////// ////////// ////////// ///////
bool createCubeObject(IDirect3D Device9 *device);
bool doDisplayBuffer(IDirect3DD evice9 *device);
void killBuffers();
////////////////////////// ////////// ////////// ////////// ////////// ////////// ///
//// USER DEFINED TYPES ////////////////////////// ////////// ////////// /////////
struct Vertex
{
Vertex(){}
Vertex(float x, float y, float z)
{
x = x; y = y; z = z;
c = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
}
Vertex(float x, float y, float z, float r, float g, float b, float a)
{
x = x; y = y; z = z;
c = D3DXCOLOR(r, g, b, a);
}
float x, y, z;
DWORD c;
static const DWORD fvf;
};
const DWORD Vertex::fvf = (D3DFVF_XYZ | D3DFVF_DIFFUSE);
////////////////////////// ////////// ////////// ////////// ////////// ////////// ///
//// PRIVATE VARIABLES ////////////////////////// ////////// ////////// //////////
static IDirect3DVertexBuffer9 *D3DVertexBuffer = 0;
static IDirect3DIndexBuffer9 *D3DIndexBuffer = 0;
////////////////////////// ////////// ////////// ////////// ////////// ////////// ///
bool createCubeObject(IDirect3D Device9 *device)
{
Vertex *v;
WORD *i;
//// CREATE MEMORY BUFFERS TO STORE CUBE GEOMETRY /////////////////////////
if (device->CreateVertexBuffe r(8 * sizeof(Vertex),
D3DUSAGE_WRITEONLY,
Vertex::fvf,
D3DPOOL_MANAGED,
&D3DVertexBuffer,
0) != D3D_OK)
{
MessageBox(NULL, "Cannot create vertex buffer", "Error", MB_ICONSTOP | MB_OK);
return false;
}
if (device->CreateIndexBuffer (36 * sizeof(WORD),
D3DUSAGE_WRITEONLY,
D3DFMT_INDEX16,
D3DPOOL_MANAGED,
&D3DIndexBuffer,
0) != D3D_OK)
{
MessageBox(NULL, "Cannot create vertex buffer", "Error", MB_ICONSTOP | MB_OK);
return false;
}
////////////////////////// ////////// ////////// ////////// ////////// /////////
//// STORE CUBE POINT GEOMETRY ////////////////////////// ////////// ////////
D3DVertexBuffer->Lock(0, 0, (void**)&v, 0);
v[0] = Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
v[1] = Vertex(-1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f);
v[2] = Vertex( 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 1.0f);
v[3] = Vertex( 1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
v[4] = Vertex(-1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f);
v[5] = Vertex(-1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
v[6] = Vertex( 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f);
v[7] = Vertex( 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f);
D3DVertexBuffer->Unlock();
////////////////////////// ////////// ////////// ////////// ////////// /////////
//// STORE FACE GEOMETRY ////////////////////////// ////////// ////////// ////
D3DIndexBuffer->Lock(0, 0, (void**)&i, 0);
i[0] = 0; i[1] = 1; i[2] = 2; // ) Front
i[3] = 0; i[4] = 2; i[5] = 3; // ) face
i[6] = 4; i[7] = 6; i[8] = 5; // ) Back
i[9] = 4; i[10] = 7; i[11] = 6; // ) face
i[12] = 4; i[13] = 5; i[14] = 1; // ) Left
i[15] = 4; i[16] = 1; i[17] = 0; // ) face
i[18] = 3; i[19] = 2; i[20] = 6; // ) Right
i[21] = 3; i[22] = 6; i[23] = 7; // ) face
i[24] = 1; i[25] = 5; i[26] = 6; // ) Top
i[27] = 1; i[28] = 6; i[29] = 2; // ) face
i[30] = 4; i[31] = 0; i[32] = 3; // ) Bottom
i[33] = 4; i[34] = 3; i[35] = 7; // ) face
D3DIndexBuffer->Unlock();
////////////////////////// ////////// ////////// ////////// ////////// /////////
return true;
}
bool doDisplayBuffer(IDirect3DD evice9 *device)
{
if ((D3DVertexBuffer == 0) || (D3DIndexBuffer == 0))
{
MessageBox(NULL, "Display buffers empty", "Error", MB_ICONINFORMATION | MB_OK);
return false;
}
//If buffers not populated, don't do anything
//// INITIALISE IMAGE STREAM ////////////////////////// ////////// //////////
device->Clear(0, 0, //No dirty rectangles
D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, //Things to clear
0xffffffff, //Colour to clear to
1.0f, 0); //Reset Z-Buffer & Stencil
device->SetStreamSource(0, D3DVertexBuffer, 0, sizeof(Vertex));
device->SetIndices(D3DInde xBuffer);
device->SetFVF(Vertex::fvf );
////////////////////////// ////////// ////////// ////////// ////////// /////////
//// PLACE/TARGET CAMERA ////////////////////////// ////////// ////////// ////
D3DXVECTOR3 vCamPos( 0.0f, 0.0f, -5.0f);
D3DXVECTOR3 vCamAim( 0.0f, 0.0f, 0.0f);
D3DXVECTOR3 vCamUp ( 0.0f, 1.0f, 0.0f);
D3DXMATRIX mView, mProj, mWorld;
D3DXMatrixLookAtLH (&mView, &vCamPos, &vCamAim, &vCamUp);
D3DXMatrixIdentity (&mWorld);
D3DXMatrixPerspectiveFovLH (&mProj,
D3DX_PI * 0.5f, //Field of View (90deg)
(float)(giScrWidth / giScrHeight), //Aspect ratio
1.0f, 1000.0f); //Distance to near/far
device->SetTransform(D3DTS _VIEW, &mView);
device->SetTransform(D3DTS _PROJECTIO N, &mProj);
device->SetTransform(D3DTS _WORLD, &mWorld);
////////////////////////// ////////// ////////// ////////// ////////// /////////
//// DRAW PRIMITIVES ////////////////////////// ////////// ////////// ////////
device->BeginScene();
device->DrawIndexedPrimiti ve(D3DPT_T RIANGLELIS T, //Type of primitives
0, //Base vertex adder
0, 8, //Start vertex / # vertices
0, 12); //Start index / # primitives
device->EndScene();
device->Present(0, 0, 0, 0);
////////////////////////// ////////// ////////// ////////// ////////// /////////
return true;
}
void killBuffers(void)
{
if (D3DVertexBuffer != 0) D3DVertexBuffer->Release() ;
if (D3DIndexBuffer != 0) D3DIndexBuffer->Release();
}
If anyone can spot it, I'd be most grateful.
Thanks
J.
The basic structure of my WinMain() is:
- Create window (returning HWND)
- Init DX9 (returning IDirect3DDevice9*)
- Load cube vertexes/indexes into buffers (returning bool) (bool createCubeObject() -- see below)
- Enter MessageLoop
- Handle WM_QUIT
- Handle WM_xxx
- Display cube (bool doDisplayScene() -- see below)
- End MessageLoop
- Cleanup (void killBuffers() -- see below)
The buffers seem to be created, the Device->Clear's as expected, but the cube does not display. I expect it's just a scope error but I can't seem to spot it.
Either way, the code follows:
//// DIRECTIVES //////////////////////////
#include <d3dx9.h>
#include ".\initGlobals.h"
//////////////////////////
//// PROTOTYPES //////////////////////////
bool createCubeObject(IDirect3D
bool doDisplayBuffer(IDirect3DD
void killBuffers();
//////////////////////////
//// USER DEFINED TYPES //////////////////////////
struct Vertex
{
Vertex(){}
Vertex(float x, float y, float z)
{
x = x; y = y; z = z;
c = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
}
Vertex(float x, float y, float z, float r, float g, float b, float a)
{
x = x; y = y; z = z;
c = D3DXCOLOR(r, g, b, a);
}
float x, y, z;
DWORD c;
static const DWORD fvf;
};
const DWORD Vertex::fvf = (D3DFVF_XYZ | D3DFVF_DIFFUSE);
//////////////////////////
//// PRIVATE VARIABLES //////////////////////////
static IDirect3DVertexBuffer9 *D3DVertexBuffer = 0;
static IDirect3DIndexBuffer9 *D3DIndexBuffer = 0;
//////////////////////////
bool createCubeObject(IDirect3D
{
Vertex *v;
WORD *i;
//// CREATE MEMORY BUFFERS TO STORE CUBE GEOMETRY /////////////////////////
if (device->CreateVertexBuffe
D3DUSAGE_WRITEONLY,
Vertex::fvf,
D3DPOOL_MANAGED,
&D3DVertexBuffer,
0) != D3D_OK)
{
MessageBox(NULL, "Cannot create vertex buffer", "Error", MB_ICONSTOP | MB_OK);
return false;
}
if (device->CreateIndexBuffer
D3DUSAGE_WRITEONLY,
D3DFMT_INDEX16,
D3DPOOL_MANAGED,
&D3DIndexBuffer,
0) != D3D_OK)
{
MessageBox(NULL, "Cannot create vertex buffer", "Error", MB_ICONSTOP | MB_OK);
return false;
}
//////////////////////////
//// STORE CUBE POINT GEOMETRY //////////////////////////
D3DVertexBuffer->Lock(0, 0, (void**)&v, 0);
v[0] = Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
v[1] = Vertex(-1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f);
v[2] = Vertex( 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 1.0f);
v[3] = Vertex( 1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
v[4] = Vertex(-1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f);
v[5] = Vertex(-1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
v[6] = Vertex( 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f);
v[7] = Vertex( 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f);
D3DVertexBuffer->Unlock();
//////////////////////////
//// STORE FACE GEOMETRY //////////////////////////
D3DIndexBuffer->Lock(0, 0, (void**)&i, 0);
i[0] = 0; i[1] = 1; i[2] = 2; // ) Front
i[3] = 0; i[4] = 2; i[5] = 3; // ) face
i[6] = 4; i[7] = 6; i[8] = 5; // ) Back
i[9] = 4; i[10] = 7; i[11] = 6; // ) face
i[12] = 4; i[13] = 5; i[14] = 1; // ) Left
i[15] = 4; i[16] = 1; i[17] = 0; // ) face
i[18] = 3; i[19] = 2; i[20] = 6; // ) Right
i[21] = 3; i[22] = 6; i[23] = 7; // ) face
i[24] = 1; i[25] = 5; i[26] = 6; // ) Top
i[27] = 1; i[28] = 6; i[29] = 2; // ) face
i[30] = 4; i[31] = 0; i[32] = 3; // ) Bottom
i[33] = 4; i[34] = 3; i[35] = 7; // ) face
D3DIndexBuffer->Unlock();
//////////////////////////
return true;
}
bool doDisplayBuffer(IDirect3DD
{
if ((D3DVertexBuffer == 0) || (D3DIndexBuffer == 0))
{
MessageBox(NULL, "Display buffers empty", "Error", MB_ICONINFORMATION | MB_OK);
return false;
}
//If buffers not populated, don't do anything
//// INITIALISE IMAGE STREAM //////////////////////////
device->Clear(0, 0, //No dirty rectangles
D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, //Things to clear
0xffffffff, //Colour to clear to
1.0f, 0); //Reset Z-Buffer & Stencil
device->SetStreamSource(0,
device->SetIndices(D3DInde
device->SetFVF(Vertex::fvf
//////////////////////////
//// PLACE/TARGET CAMERA //////////////////////////
D3DXVECTOR3 vCamPos( 0.0f, 0.0f, -5.0f);
D3DXVECTOR3 vCamAim( 0.0f, 0.0f, 0.0f);
D3DXVECTOR3 vCamUp ( 0.0f, 1.0f, 0.0f);
D3DXMATRIX mView, mProj, mWorld;
D3DXMatrixLookAtLH (&mView, &vCamPos, &vCamAim, &vCamUp);
D3DXMatrixIdentity (&mWorld);
D3DXMatrixPerspectiveFovLH
D3DX_PI * 0.5f, //Field of View (90deg)
(float)(giScrWidth / giScrHeight), //Aspect ratio
1.0f, 1000.0f); //Distance to near/far
device->SetTransform(D3DTS
device->SetTransform(D3DTS
device->SetTransform(D3DTS
//////////////////////////
//// DRAW PRIMITIVES //////////////////////////
device->BeginScene();
device->DrawIndexedPrimiti
0, //Base vertex adder
0, 8, //Start vertex / # vertices
0, 12); //Start index / # primitives
device->EndScene();
device->Present(0, 0, 0, 0);
//////////////////////////
return true;
}
void killBuffers(void)
{
if (D3DVertexBuffer != 0) D3DVertexBuffer->Release()
if (D3DIndexBuffer != 0) D3DIndexBuffer->Release();
}
If anyone can spot it, I'd be most grateful.
Thanks
J.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Hehehe, I'm a VB6 man myself -- but I thought I'd take the plunge into C++ and DirectX in one go, as it's unlikely that I'll use either independantly.
It turns out that the book I'm using to learn Direct3D (Luna, Frank -- Introduction to 3D Game Programming with DirectX 9.0) has an interesting publishing error that sees all underscore characters removed from the code samples.
Since Luna prefixes his class members with an underscore, the line, x = x; y = y; z = z (that I'd copied from the book and, as such, couldn't spot) actually read _x = x; _y = y; _z = z. But I chose the 'this' approach because I don't like starting variable names with anything other than a letter...
It has been suggested that VC++6.0 might ignore such lines as x = x in some attempt to (optimise/have the final say/ruin your day/delete as appropriate) but I don't know if that's true...
I hate pointers -- give me ByRef and ByVal any day!!
It turns out that the book I'm using to learn Direct3D (Luna, Frank -- Introduction to 3D Game Programming with DirectX 9.0) has an interesting publishing error that sees all underscore characters removed from the code samples.
Since Luna prefixes his class members with an underscore, the line, x = x; y = y; z = z (that I'd copied from the book and, as such, couldn't spot) actually read _x = x; _y = y; _z = z. But I chose the 'this' approach because I don't like starting variable names with anything other than a letter...
It has been suggested that VC++6.0 might ignore such lines as x = x in some attempt to (optimise/have the final say/ruin your day/delete as appropriate) but I don't know if that's true...
I hate pointers -- give me ByRef and ByVal any day!!
It may do that in optimizing. Even if those lines were left in there after compiled, it would not compile properly because the variable would not be assigned to the actual object, hence the pointer. I'm not a fan of C++, probably due to lack of experience Delphi though offers inline assembly, and is many many times faster than VB.
VB is much worse if you enable optimisation. It will take a line like this:
X=X*(Y+(Z/X)*(Z/Y))/360
and disregard any order that you want to perform the calculations.
While testing in the IDE the program runs flawlessly, compile it and everything goes haywire.
It is documented in the KB, but you'd think with the 11 or 12 service packs that have been released since VB5 then VB6 they would have decided to fix this.
Instead the option is just leave it alone, and not to use compiler optimisation.
I guess a seasoned C++ programmer would have known that they were pointers right off, as in any language it wouldn't make sense to perform those assignments, unless you wanted to eat a couple of instruction cycles.
>>But I chose the 'this' approach because I don't like starting variable names with anything other than a letter...
THIS is a keyword in C++ it is longhand for the _ character, it isn't really part of the variable name though.
VB is much worse if you enable optimisation. It will take a line like this:
X=X*(Y+(Z/X)*(Z/Y))/360
and disregard any order that you want to perform the calculations.
While testing in the IDE the program runs flawlessly, compile it and everything goes haywire.
It is documented in the KB, but you'd think with the 11 or 12 service packs that have been released since VB5 then VB6 they would have decided to fix this.
Instead the option is just leave it alone, and not to use compiler optimisation.
I guess a seasoned C++ programmer would have known that they were pointers right off, as in any language it wouldn't make sense to perform those assignments, unless you wanted to eat a couple of instruction cycles.
>>But I chose the 'this' approach because I don't like starting variable names with anything other than a letter...
THIS is a keyword in C++ it is longhand for the _ character, it isn't really part of the variable name though.
ASKER
x = x; y = y; z = z;
should read
this->x = x; this->y = y; this->z = z;
As a side game, however, the first person who even acknowledges this question can have all the points...
J.