Original Post
I'm attempting to do a small project for class using DirectX (as a prelude to using directX on a larger scale next semester). But something isn't working right, and I don't know what. I think (based on some tests) that for some reason the data isn't getting loaded into the buffer properly, and as a result there's nothing to draw. But I'm not sure how I can test that. My code is based, mostly, on source from DirectX Tutorial with some additions from a book on DX I picked up (a timer class). The place where I'm initializing graphics (which includes loading the buffer with the triangle info) is shown below, along with a copy of the program as a whole. If anyone has any ideas, other than going and telling the teacher that 'something is wrong, and we're not going to be able to do it', please let me know. I'd scrap this project and start over from scratch with the book (now that I have it), but I need something to show for my effort right now. And while weeks of studying a book on real time rendering (in a generic sense) and a reasonable understanding of number of DirectX calls is nice, it doesn't mean anything unless I can use it for something other than a scripted out-of-the-book example. The general idea of the following code is to take a basic 'display some triangles' code and tweak it so that it loads the triangles from a data file, along with some basic transformational info to allow for basic animation. Instead of hard-coding the behavior, I wanted to off-load the actual data into an external file and then load it in at runtime. Edit: not sure what I did to stretch things out like this, sorry. Full code: Sample Data File:
void init_graphics(void)
{
// create the vertices using the CUSTOMVERTEX struct
/*CUSTOMVERTEX vertices[] =
{
{ 3.0f, -3.0f, 0.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 0.0f, 3.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ -3.0f, -3.0f, 0.0f, D3DCOLOR_XRGB(255, 0, 0), },
};*/
loadData();
CUSTOMVERTEX *vertices;
vertices=new CUSTOMVERTEX[myTriangles.size()];
for(unsigned int i=0; i<myTriangles.size(); i++)
{
for(int j=0; j<3; j++)
{
vertices.X=myTriangles.pointP[j][0];
vertices.Y=myTriangles.pointP[j][1];
vertices.Z=myTriangles.pointP[j][2];
vertices.COLOR=D3DCOLOR_XRGB(myTriangles.pointC[j][0],myTriangles.pointC[j][0],myTriangles.pointC[j][0]);
}
}
int mySize=3*myTriangles.size()*sizeof(CUSTOMVERTEX);
// create a vertex buffer interface called v_buffer
HRESULT HR=d3ddev->CreateVertexBuffer(mySize,
0,
CUSTOMFVF,
D3DPOOL_MANAGED,
&v_buffer,
NULL);
VOID* pVoid; // a void pointer
// lock v_buffer and load the vertices into it
v_buffer->Lock(0, 0, (void**)&pVoid, 0);
memcpy(pVoid, vertices, sizeof(vertices));
v_buffer->Unlock();
}
#include <fstream>
#include <vector>
#include <windows.h>
#include <windowsx.h>
#include <d3d9.h>
#include <d3dx9.h>
#include "GameTimer.h"//Borrowed from a book on Direct X 10:
/*Introduction to 3D Game Programming with DirectX 10, Frank D. Luna*/
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600
#pragma comment (lib, "d3d9.lib")
#pragma comment (lib, "d3dx9.lib")
LPDIRECT3D9 d3d; // the pointer to our Direct3D interface
LPDIRECT3DDEVICE9 d3ddev; // the pointer to the device class
LPDIRECT3DVERTEXBUFFER9 v_buffer = NULL; // the pointer to the vertex buffer
void initD3D(HWND hWnd); // sets up and initializes Direct3D
void render_frame(float); // renders a single frame
void cleanD3D(void); // closes Direct3D and releases memory
void init_graphics(void); // 3D declarations
GameTimer myTimer;
struct triangle
{
int num;//triangle reference number; ZERO INDEXED
float pointP[3][3];//point position
//float baseRot;//Base rotation <<SHOULDN'T BE NEEDED, BUT CAN BE USED IF NEEDED>>
int pointC[3][3];//point color
float connectionP[4][3];//a list of 4 possible connection points (each point a 3 element array)
int connected[2];//which triangle does this connect to, and which connection point?
};
struct frame
{
int index;//0 indexed value to give each animation a discrete value
std::vector<float> degreeX;//each triangle must be given it's own rotation
std::vector<float> degreeY;//each triangle must be given it's own rotation
std::vector<float> degreeZ;//each triangle must be given it's own rotation
};
struct stage
{
int index;//0 indexed value to indicate which stage
int framePast;//which frame are we coming from?
int frameFuture;//which frame are we headed for?
int time;//how long does the translation take?
};
struct animation
{
std::vector<frame> frames;
std::vector<stage> stages;
};
void loadData();
std::vector<triangle> myTriangles;
animation myAnimation;
D3DXMATRIX triangleTransform(float curPercent, int curTriangle, int curStage);
struct CUSTOMVERTEX {FLOAT X, Y, Z; DWORD COLOR;};
#define CUSTOMFVF (D3DFVF_XYZ | D3DFVF_DIFFUSE)
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
HWND hWnd;
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = L"WindowClass";
RegisterClassEx(&wc);
hWnd = CreateWindowEx(NULL, L"WindowClass", L"Our Direct3D Program",
WS_OVERLAPPEDWINDOW, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT,
NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow);
// set up and initialize Direct3D
initD3D(hWnd);
// enter the main loop:
MSG msg;
myTimer.reset();
while(TRUE)
{
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if(msg.message == WM_QUIT)
break;
myTimer.tick();
render_frame(myTimer.getDeltaTime());
}
// clean up DirectX and COM
cleanD3D();
return msg.wParam;
}
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
} break;
}
return DefWindowProc (hWnd, message, wParam, lParam);
}
void initD3D(HWND hWnd)
{
d3d = Direct3DCreate9(D3D_SDK_VERSION);
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hWnd;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferWidth = SCREEN_WIDTH;
d3dpp.BackBufferHeight = SCREEN_HEIGHT;
d3dpp.EnableAutoDepthStencil = TRUE; // automatically run the z-buffer for us
d3dpp.AutoDepthStencilFormat = D3DFMT_D16; // 16-bit pixel format for the z-buffer
// create a device class using this information and the info from the d3dpp stuct
d3d->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp,
&d3ddev);
init_graphics(); // call the function to initialize the triangle
d3ddev->SetRenderState(D3DRS_LIGHTING, FALSE); // turn off the 3D lighting
d3ddev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); // both sides of the triangles
d3ddev->SetRenderState(D3DRS_ZENABLE, TRUE); // turn on the z-buffer
}
void render_frame(float deltaTime)
{
d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
d3ddev->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
d3ddev->BeginScene();
// select which vertex format we are using
d3ddev->SetFVF(CUSTOMFVF);
// set the view transform
D3DXMATRIX matView; // the view transform matrix
D3DXMatrixLookAtLH(&matView,
&D3DXVECTOR3 (5.0f, 0.0f, 0.0f), // the camera position
&D3DXVECTOR3 (0.0f, 0.0f, 0.0f), // the look-at position
&D3DXVECTOR3 (0.0f, 0.0f, 1.0f)); // the up direction
d3ddev->SetTransform(D3DTS_VIEW, &matView); // set the view transform to matView
// set the projection transform
D3DXMATRIX matProjection; // the projection transform matrix
D3DXMatrixPerspectiveFovLH(&matProjection,
D3DXToRadian(45), // the horizontal field of view
(FLOAT)SCREEN_WIDTH / (FLOAT)SCREEN_HEIGHT, // aspect ratio
1.0f, // the near view-plane
100.0f); // the far view-plane
d3ddev->SetTransform(D3DTS_PROJECTION, &matProjection); // set the projection
// select the vertex buffer to display
d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX));
/*MYCODE*/
//D3DXMATRIX matTranslateA; // a matrix to store the translation for triangle A
//D3DXMATRIX matTranslateB; // a matrix to store the translation for triangle B
//D3DXMATRIX matRotateY; // a matrix to store the rotation for each triangle
static int curStage = 0;
static float curTime=0;
static float stageStart=curTime;
curTime+=deltaTime;
if(curTime>(stageStart+myAnimation.stages[curStage].time))
{
if(curStage==myAnimation.stages.size())
curStage=0;
else
curStage++;
stageStart=curTime;
}
//NOTE:
/*
Triangle X must:
1. do it's own rotation
2. do it's own translation (to connect origin to connection point)
3. do the rotation of X-1
4. do the translation of X-1
5. Repeast 3 and 4 until down to 0
*/
/*// build MULTIPLE matrices to translate the model and one to rotate
// tell Direct3D about each world transform, and then draw another triangle
d3ddev->SetTransform(D3DTS_WORLD, &(matTranslateA * matRotateY));
d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);*/
D3DXMATRIX transformMatrix;
float curPercent=(curTime-stageStart)/myAnimation.stages[curStage].time;
//for(unsigned int i=0; i<myTriangles.size(); i++)
{
//transformMatrix=triangleTransform(curPercent, i, curStage);
// D3DXMatrixRotationX(&transformMatrix,D3DXToRadian(0));
// d3ddev->SetTransform(D3DTS_WORLD, &transformMatrix);
d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);
}
d3ddev->EndScene();
d3ddev->Present(NULL, NULL, NULL, NULL);
}
// this is the function that cleans up Direct3D and COM
void cleanD3D(void)
{
v_buffer->Release(); // close and release the vertex buffer
d3ddev->Release(); // close and release the 3D device
d3d->Release(); // close and release Direct3D
}
void init_graphics(void)
{
// create the vertices using the CUSTOMVERTEX struct
/*CUSTOMVERTEX vertices[] =
{
{ 3.0f, -3.0f, 0.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 0.0f, 3.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ -3.0f, -3.0f, 0.0f, D3DCOLOR_XRGB(255, 0, 0), },
};*/
loadData();
CUSTOMVERTEX *vertices;
vertices=new CUSTOMVERTEX[myTriangles.size()];
for(unsigned int i=0; i<myTriangles.size(); i++)
{
for(int j=0; j<3; j++)
{
vertices.X=myTriangles.pointP[j][0];
vertices.Y=myTriangles.pointP[j][1];
vertices.Z=myTriangles.pointP[j][2];
vertices.COLOR=D3DCOLOR_XRGB(myTriangles.pointC[j][0],myTriangles.pointC[j][0],myTriangles.pointC[j][0]);
}
}
int mySize=3*myTriangles.size()*sizeof(CUSTOMVERTEX);
// create a vertex buffer interface called v_buffer
HRESULT HR=d3ddev->CreateVertexBuffer(mySize,
0,
CUSTOMFVF,
D3DPOOL_MANAGED,
&v_buffer,
NULL);
VOID* pVoid; // a void pointer
// lock v_buffer and load the vertices into it
v_buffer->Lock(0, 0, (void**)&pVoid, 0);
memcpy(pVoid, vertices, sizeof(vertices));
v_buffer->Unlock();
}
void loadData()
{
std::fstream input;
input.open("file.txt", std::ios::in);
int triangleCount;
int frameCount;
int stageCount;
float tempX, tempY, tempZ;
triangle tempTriangle;
frame tempFrame;
stage tempStage;
input >> triangleCount;
for(int i=0; i<triangleCount; i++)
{
input >> tempTriangle.num >>
tempTriangle.pointP[0][0] >> tempTriangle.pointP[0][1] >> tempTriangle.pointP[0][2] >>
tempTriangle.pointP[1][0] >> tempTriangle.pointP[1][1] >> tempTriangle.pointP[1][2] >>
tempTriangle.pointP[2][0] >> tempTriangle.pointP[2][1] >> tempTriangle.pointP[2][2] >>
tempTriangle.pointC[0][0] >> tempTriangle.pointC[0][1] >> tempTriangle.pointC[0][2] >>
tempTriangle.pointC[1][0] >> tempTriangle.pointC[1][1] >> tempTriangle.pointC[1][2] >>
tempTriangle.pointC[2][0] >> tempTriangle.pointC[2][1] >> tempTriangle.pointC[2][2] >>
tempTriangle.connectionP[0][0] >> tempTriangle.connectionP[0][1] >> tempTriangle.connectionP[0][2] >>
tempTriangle.connectionP[1][0] >> tempTriangle.connectionP[1][1] >> tempTriangle.connectionP[1][2] >>
tempTriangle.connectionP[2][0] >> tempTriangle.connectionP[2][1] >> tempTriangle.connectionP[2][2] >>
tempTriangle.connectionP[3][0] >> tempTriangle.connectionP[3][1] >> tempTriangle.connectionP[3][2] >>
tempTriangle.connected[0] >> tempTriangle.connected[1];
myTriangles.push_back(tempTriangle);
}
input >> frameCount;
for (int i=0; i<frameCount; i++)
{
for (int j=0; j<triangleCount; j++)
{
input >> tempX >> tempY >> tempZ;
tempFrame.degreeX.push_back(tempX);
tempFrame.degreeY.push_back(tempY);
tempFrame.degreeZ.push_back(tempZ);
}
tempFrame.index=i;
myAnimation.frames.push_back(tempFrame);
tempFrame.degreeX.clear();
tempFrame.degreeY.clear();
tempFrame.degreeZ.clear();
}
input >> stageCount;
for(int i=0; i<stageCount; i++)
{
input >> tempStage.framePast >> tempStage.frameFuture >> tempStage.time;
tempStage.index=i;
myAnimation.stages.push_back(tempStage);
}
}
D3DXMATRIX triangleTransform(float curPercent, int curTriangle, int curStage)
{
D3DXMATRIX myTransformFinal;
D3DXMATRIX myTranslate;
D3DXMATRIX myRotateX;
D3DXMATRIX myRotateY;
D3DXMATRIX myRotateZ;
float past;
float future;
past=myAnimation.frames[myAnimation.stages[curStage].framePast].degreeX[curTriangle];
future=myAnimation.frames[myAnimation.stages[curStage].framePast].degreeX[curTriangle];
float rotX=(myAnimation.frames[myAnimation.stages[curStage].framePast].degreeX[curTriangle]+(curPercent*(myAnimation.frames[myAnimation.stages[curStage].frameFuture].degreeX[curTriangle]-myAnimation.frames[myAnimation.stages[curStage].framePast].degreeX[curTriangle])));
float rotY=(myAnimation.frames[myAnimation.stages[curStage].framePast].degreeY[curTriangle]+(curPercent*(myAnimation.frames[myAnimation.stages[curStage].frameFuture].degreeY[curTriangle]-myAnimation.frames[myAnimation.stages[curStage].framePast].degreeY[curTriangle])));;
float rotZ=(myAnimation.frames[myAnimation.stages[curStage].framePast].degreeZ[curTriangle]+(curPercent*(myAnimation.frames[myAnimation.stages[curStage].frameFuture].degreeZ[curTriangle]-myAnimation.frames[myAnimation.stages[curStage].framePast].degreeZ[curTriangle])));;
D3DXMatrixRotationX(&myRotateX,D3DXToRadian(rotX));
D3DXMatrixRotationY(&myRotateY,D3DXToRadian(rotY));
D3DXMatrixRotationZ(&myRotateZ,D3DXToRadian(rotZ));
myTransformFinal=myRotateX*myRotateY*myRotateZ;
if(curTriangle!=0)
{
D3DXMatrixTranslation(&myTranslate,
myTriangles[myTriangles[curTriangle].connected[0]].connectionP[myTriangles[curTriangle].connected[1]][0],
myTriangles[myTriangles[curTriangle].connected[0]].connectionP[myTriangles[curTriangle].connected[1]][1],
myTriangles[myTriangles[curTriangle].connected[0]].connectionP[myTriangles[curTriangle].connected[1]][2]);
myTransformFinal*myTranslate*triangleTransform(curPercent, myTriangles[curTriangle].connected[0], curStage);
}
return myTransformFinal;
/*D3DXMatrixTranslation(&matTranslateA, 0.0f, 0.0f, 2.0f);
D3DXMatrixTranslation(&matTranslateB, 0.0f, 0.0f, -2.0f);
D3DXMatrixRotationY(&matRotateY, index); // the front side
myAnimation.frames[myAnimation.stages[curStage].framePast].degreeX
myAnimation.frames[myAnimation.stages[curStage].frameFuture].degreeX*/
//myTriangles.connected[2];//who am I connectd to, then which point
}
2
0 -1 -1 0 -1 0 0 0 0 0 0 0 255 0 255 0 255 0 0 0 0 0 -1 -1 0 -1 0 0 0 0 0 0 0
1 0 0 0 1 -1 0 1 1 0 0 255 0 255 0 0 0 0 255 0 0 0 1 -1 0 0 0 0 1 0 0 1 1
3
0 0 0
0 0 0
90 0 0
45 0 0
180 0 0
90 0 0
4
0 1 1
1 2 1
2 1 2
1 0 3