News
DirectX
Links
Contact Me

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

$5 via PayPal


Direct3D Lesson 2a



Direct3D Lesson 2a:Your First Polygons
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, rhw; // The transformed 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_XYZRHW specifies that the vertex will have
//coordinate given in screen space.
#define D3D8T_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE)


//The x & y values here are given in 'screen space'.  Vertices in screen space
//are referred to as Transformed vertices.  What this means is that the x and y
//coordinates are given as offsets from the top left of the screen. If you change
//these coordinates by adding 50 to each x value, you will move everything to the
//right by 50 pixels.
//With Transformed vertices, the z coordinate doesn't do much.  If you have a Z Buffer
//it determines which objects block other objects, but changing the z coordinate will
//have no other effect.  The visible size (given by the x,y coordinates) is static, so
//even though you can effectively move the object deeper into the screen, it will remain
//the same size.
my_vertex g_triangle_vertices[] ={
    { 125.0f,  50.0f, 0.5f, 1.0f, 0xFFFFFFFF }, // x, y, z, rhw, color
    { 200.0f, 200.0f, 0.5f, 1.0f, 0xFFFFFFFF },
    {  50.0f, 200.0f, 0.5f, 1.0f, 0xFFFFFFFF }
};

//Direct3D does not support a Quad rendering primitive like OpenGL does.  It does have
//Triangle Strips.  In a Triangle Strip, the first 3 vertices form a triangle, and
//then each additional vertex adds a triangle formed by itself and the previous 2
//vertices.  Thus to draw a square we need only 4 vertices.
my_vertex g_square_vertices[] ={
    { 250.0f,  200.0f, 0.5f, 1.0f, 0xFFFFFFFF }, // x, y, z, rhw, color
    { 250.0f,  50.0f,  0.5f, 1.0f, 0xFFFFFFFF },
    { 400.0f,  200.0f, 0.5f, 1.0f, 0xFFFFFFFF },
    { 400.0f,  50.0f,  0.5f, 1.0f, 0xFFFFFFFF }
};

//Vertex buffers are a method of storing vertices to be rendered in an optimized manner.
IDirect3DVertexBuffer8 *g_triangle=NULL;
IDirect3DVertexBuffer8 *g_square=NULL;

We have to add some clean up to our kill_scene function.
// Function:kill_scene
// Whazzit:Clean up any objects we required for rendering.
void kill_scene(void){

   if(g_triangle){
      g_triangle->Release();
      g_triangle=NULL;
   }

   if(g_square){
      g_square->Release();
      g_square=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;

   //As mentioned above, a Vertex Buffer is an optimized storage medium for vertices.
   //Here we create a vertex buffer large enough to hold 3 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(3*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_triangle);       //Pointer to our triangle, after this call
                                                           //It will point to a valid vertex buffer
   if(FAILED(hr)){
      FatalError("Error creating triangle vertex buffer");
   }

   //The only difference between this and the above call is that we're allocating
   //enough space for 4 vertices instead of 3.
   hr=g_d3d_device->CreateVertexBuffer(4*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_square);         //Pointer to our triangle, after this call
                                                           //It will point to a valid vertex buffer
   if(FAILED(hr)){
      FatalError("Error creating square 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_triangle->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_triangle_vertices, sizeof(g_triangle_vertices) );

   //Unlock so Direct3D knows we're done and can do any behind-the-scenes magic required
   g_triangle->Unlock();


   //Now we go through the same process to fill in our VB for the square.
   hr=g_square->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 square buffer");
   }
   
   memcpy(vb_vertices, g_square_vertices, sizeof(g_square_vertices) );

   g_square->Unlock();


}

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;

   //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_triangle,sizeof(my_vertex));

      //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 the active stream to be our square.
      //NOTE: Because of the offsets that DrawPrimitive takes, we could
      //have built the triangle & square into a single VB and still
      //drawn them seperately.
      g_d3d_device->SetStreamSource(0,g_square,sizeof(my_vertex));

      //Now we're drawing a Triangle Strip, 4 vertices to draw 2 triangles.
      g_d3d_device->DrawPrimitive(D3DPT_TRIANGLESTRIP,0,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 );

}