News
DirectX
Links
Contact Me

In Association with Amazon.com
In Association with Amazon.ca

$5 via PayPal


Direct3D Lesson 2b



Direct3D Lesson 2b:Your First Polygons
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 );

}