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