 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 ); } ```