Because we're using some of the handy functions in the D3DX library, we have to add another library
to be linked. Add this line:
#pragma comment(lib,"d3dx8.lib")
We'll need a few new data structures, here are the definitions for these global items
//Declare a structure to hold a vertex with all the information that we need
struct my_vertex{
FLOAT x, y, z; // The untransformed position for the vertex.
DWORD color; // The vertex color.
};
//A handy little 'macro' for our definition of the vertex. When we use the vertex data
//we have to tell D3D what data we're passing it. D3DFVF_DIFFUSE specifies that the
//vertex will have a colour, the D3DFVF_XYZ specifies that the vertex will have
//coordinate given in model space.
#define D3D8T_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)
//Here we have the vertices for our triangle, followed by those for our square.
//These coordinates are in model space, with 0,0,0 being at their center.
my_vertex g_vertices[] ={
{ 0.0f, 1.0f, 0.0f, 0xFFFFFFFF }, // x, y, z, color
{ 1.0f, -1.0f, 0.0f, 0xFFFFFFFF },
{ -1.0f, -1.0f, 0.0f, 0xFFFFFFFF },
{ -1.0f, -1.0f, 0.0f, 0x00000000 },
{ -1.0f, 1.0f, 0.0f, 0x00000000 },
{ 1.0f, -1.0f, 0.0f, 0x00000000 },
{ 1.0f, 1.0f, 0.0f, 0x00000000 }
};
//Vertex buffers are a method of storing vertices to be rendered in an optimized manner.
IDirect3DVertexBuffer8 *g_vb=NULL;
We have to modify our kill_scene function.
// Function:kill_scene
// Whazzit:Releases all of our D3D resources in the opposite order from their creation.
// Note-Since we initially set the pointers to be NULL, we can safely test them
// for a non-NULL state and we know if they've been created. Thus we never Release
// something we didn't create (which causes bad things to happen).
void kill_scene(void){
if(g_vb){
g_vb->Release();
g_vb=NULL;
}
}
Our init_scene() now has quite a bit of code in it
// Function:init_scene
// Whazzit:One-time preparation of objects required for rendering. In this tutorial we prepare
// 2 objects:a triangle & a square.
void init_scene(void){
HRESULT hr;
unsigned char *vb_vertices;
D3DXMATRIX view_matrix;
D3DXMATRIX matProj;
//Turn off D3D lighting, since we are providing our own vertex colors
//This wasn't required in Lesson 2a, because Transformed Vertices are
//not lit by D3D but by their vertex colors by default. Untransformed
//vertices by default are lit by D3D, since we haven't added any
//lighting, we would see anything if we didn't do this.
g_d3d_device->SetRenderState(D3DRS_LIGHTING,FALSE);
//As mentioned above, a Vertex Buffer is an optimized storage medium for vertices.
//Here we create a vertex buffer large enough to hold 7 vertices. We specify that
//it can only be written to and we allow Direct3D to determine where in memory
//it should be placed.
hr=g_d3d_device->CreateVertexBuffer(7*sizeof(my_vertex), //Size of memory to be allocated
//Number of vertices * size of a vertex
D3DUSAGE_WRITEONLY, //We never need to read from it so
//we specify write only, it's faster
D3D8T_CUSTOMVERTEX, //Our custom vertex specifier (coordinates & a colour)
D3DPOOL_MANAGED, //Tell DirectX to manage the memory of this resource
&g_vb); //Pointer to our Vertex Buffer, after this call
//It will point to a valid vertex buffer
if(FAILED(hr)){
FatalError("Error creating vertex buffer");
}
//Now we have our Vertex Buffers, but they're empty. To put our data into them
//we Lock the Vertex Buffer so Direct3D knows we're modifying it, then we copy
//our data in and Unlock it so Direct3D knows we're done.
hr=g_vb->Lock(0, //Offset, we want to start at the beginning
0, //SizeToLock, 0 means lock the whole thing
&vb_vertices, //If successful, this will point to the data in the VB
0); //Flags, nothing special
if(FAILED(hr)){
FatalError("Error Locking triangle buffer");
}
//vb_vertices now points to our vertices inside the Vertex buffer, so
//to fill in our VB, we copy to vb_vertices.
memcpy(vb_vertices, g_vertices, sizeof(g_vertices) );
//Unlock so Direct3D knows we're done and can do any behind-the-scenes magic required
g_vb->Unlock();
//Here we build our View Matrix, think of it as our camera.
//First we specify that our viewpoint is 8 units back on the Z-axis
//We are looking towards the origin
//And the y-axis is up
D3DXMatrixLookAtLH(&view_matrix,&D3DXVECTOR3( 0.0f, 0.0f,-8.0f ),
&D3DXVECTOR3( 0.0f, 0.0f, 0.0f ),
&D3DXVECTOR3( 0.0f, 1.0f, 0.0f ));
//Since our 'camera' will never move, we can set this once at the
//beginning and never worry about it again
g_d3d_device->SetTransform(D3DTS_VIEW,&view_matrix);
D3DXMatrixPerspectiveFovLH(&matProj, //Result Matrix
D3DX_PI/4,//Field of View, in radians. (PI/4) is typical
((float)g_width / (float)g_height), //Aspect ratio
1.0f, //Near view plane
100.0f ); // Far view plane
//Our Projection matrix won't change either, so we set it now and never touch
//it again.
g_d3d_device->SetTransform( D3DTS_PROJECTION, &matProj );
}
Here's our new render() function
// Function: render
// Whazzit:Clears the screen to a pseudo-random colour, draws a triangle and a square
// and then presents the results.
void render(void){
static unsigned char red=0,green=0,blue=0;
D3DXMATRIX matWorld;
//These will safely overflow when the values go over 255, wrapping back to 0.
red++;
green+=2;
blue+=3;
//Clear the buffer to our new colour.
g_d3d_device->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(red,green,blue), 1.0f, 0 );
//Notify the device that we're ready to render
if(SUCCEEDED(g_d3d_device->BeginScene())){
//Vertex shaders are a complex topic, but you can do some amazing things with them
//For this example we're not creating one, so we tell Direct3D that we're just
//using a plain vertex format.
g_d3d_device->SetVertexShader(D3D8T_CUSTOMVERTEX);
//D3D's rendering functions read from streams. Here we tell D3D that the
//VB we created for our triangle is the stream it should read from.
g_d3d_device->SetStreamSource(0,g_vb,sizeof(my_vertex));
//Translate (move) it 1 unit to the left
D3DXMatrixTranslation(&matWorld,-1.0,0.0f,0.0f);
//Set our World Matrix
g_d3d_device->SetTransform(D3DTS_WORLD,&matWorld );
//After all that setup, actually drawing the triangle is pretty easy.
//We tell it what we're giving it (a Triangle List), where it should
//start reading (0, the beginning), and how many triangles we're drawing(1)
g_d3d_device->DrawPrimitive(D3DPT_TRIANGLELIST,0,1);
//Set up the World Matrix for the square
D3DXMatrixTranslation(&matWorld,1.0,0.0f,0.0f);
g_d3d_device->SetTransform( D3DTS_WORLD, &matWorld );
//Now we're drawing a Triangle Strip, 4 vertices to draw 2 triangles.
//We skip the first 3 vertices since they belong to our triangle
g_d3d_device->DrawPrimitive(D3DPT_TRIANGLESTRIP,3,2);
//Notify the device that we're finished rendering for this frame
g_d3d_device->EndScene();
}
//Show the results
g_d3d_device->Present( NULL, NULL, NULL, NULL );
}
|