This tutorial is part of a Collection: 01. DirectX 9 - Braynzar Soft Tutorials
2670
views
05. Start Drawing!
Now that we have all the initialization out of the way, we can start drawing polygons!
Alright, now that we have Direct3D initialized, lets start drawing! In the world of Direct3D, everything is made up of triangles, like atoms make up everything in our world. So thats what we'll start with, drawing triangles. Triangles are defined by three vertices, one for each corner. The line between the vertices is called the edge. Vertices are a point in space, with optional additional properties. We tell Direct3D what the format of our vertices will be by setting a custom Flexible Vertex Format(FVF). The FVF could inlclude the spacial x,y,z coordinates, vertex normals, color, or texture coordinates. We will start by initializing two Vertex Buffers, one for a triangle and one for a square. A Vertex Buffer is used to store a chunk of memory containing vertex data to the Video Ram. Rendering data from the video memory is done faster than rendering from system memory. IDirect3DVertexBuffer9* TriangleVertexBuffer = 0; IDirect3DVertexBuffer9* SquareVertexBuffer = 0; After that, we will creat a vertex structure, then define a Flexible Vertex Format. Our Vertex structure will only hold the location for now, next lesson we will discuss color. Note: When you define the FVF, make sure you define it in the same order as your Vertex Structure. like if your vertex structure started with the x,y,z coords, then the color property, you should define your FVF with D3DFVF_XYZ then D3DFVF_DIFFUSE. struct Vertex { float x, y, z; }; const DWORD VertexFVF = D3DFVF_XYZ; Now we will set up our Vertex Buffers and store the triangle and square vertex data inside of them. We will do this inside of the SetupScene() function we created in the initialize direct3d lessons. This is what the Vertex Buffer class looks like: HRESULT IDirect3DDevice9::CreateVertexBuffer( UINT Length, DWORD Usage, DWORD FVF, D3DPOOL Pool IDirect3DVertexBuffer9** ppVertexBuffer, HANDLE* pSharedHandle ); Length - This is the number of bytes we want to store. If we wanted to store 3 vertices, we would set this to 3 * sizeof(Vertex). sizeof(Vertex) is the size of our Vertex Structure. Usage - Additional properties of how the buffer will be used. Can be set to 0 or one or more of the D3DUSAGE_ flags. We will only be writing to the buffer, as it speeds the processing up. FVF - This is the Flexible Vertex Format we defined earlier. Pool - Memory pool that buffer is placed in. ppVertexBuffer - Pointer we initialized earlier to receive the created index buffer. d3dDevice->CreateVertexBuffer( 3 * sizeof(Vertex), D3DUSAGE_WRITEONLY, VertexFVF, D3DPOOL_MANAGED, &TriangleVertexBuffer, 0); d3dDevice->CreateVertexBuffer( 4 * sizeof(Vertex), D3DUSAGE_WRITEONLY, VertexFVF, D3DPOOL_MANAGED, &SquareVertexBuffer, 0); We have created the Vertex Buffers, now we need to fill them up with our triangle geometry data. To do this, we must get a pointer to the memory contents of the buffer by Locking it. After we are done with it we need to unlock the buffer. The following is the lock method. HRESULT IDirect3DVertexBuffer9::Lock( UINT OffsetToLock, UINT SizeToLock, BYTE** ppbData, DWORD Flags ); OffsetToLock - Bytes from the start of the vertex buffers memory to start the lock. SizeToLock - Size in bytes to lock starting from the OffsetToLock. ppbData - Pointer to the start of the locked memory. Flags - Flags describing how to lock the buffer. Can be 0 or one or more of the following flags. After we lock the buffer, we define our triangle geometry, then we unlock the buffer when we are done. Vertex* vertices; TriangleVertexBuffer->Lock(0, 0, (void**)&vertices, 0); vertices[0].x =-0.5f; //Left vertex vertices[0].y = 0.0f; vertices[0].z = 0.0f; vertices[1].x = 0.0f; //Top vertex vertices[1].y = 0.5f; vertices[1].z = 0.0f; vertices[2].x = 0.5f; //Right vertex vertices[2].y = 0.0f; vertices[2].z = 0.0f; TriangleVertexBuffer->Unlock(); SquareVertexBuffer->Lock(0, 0, (void**)&vertices, 0); vertices[0].x =-0.5f; vertices[0].y = 0.5f; vertices[0].z = 0.0f; vertices[1].x = 0.5f; vertices[1].y = 0.5f; vertices[1].z = 0.0f; vertices[2].x =-0.5f; vertices[2].y =-0.5f; vertices[2].z = 0.0f; vertices[3].x = 0.5f; vertices[3].y =-0.5f; vertices[3].z = 0.0f; SquareVertexBuffer->Unlock(); The last thing we will do in our SetupScene() function is set the render state to render our geometry in WIREFRAME mode. Direct3D uses Render States to determine how your geometry will be rendered. Once you set a render state, it will stay that value until you change it again. You can change render states with the following method. HRESULT IDirect3DDevice9::SetRenderState( D3DRENDERSTATETYPE State, DWORD Value ); State - State to change Value - Value of the new state We'll talk more about render states in a later tutorial. d3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); We are done with our SetupScene() function, so now we'll move onto the CleanUpScene() function. In this function, we only have two lines of code for now. These line will release the memory that was stored in the vertex buffers. If we didn't release the memory our application uses, it would cause a memory leak and may crash your computer when you exit the program. To release our Vertex Buffers memory, we will use the method IDirect3DVertexBuffer9->Release() TriangleVertexBuffer->Release(); SquareVertexBuffer->Release(); The only thing left to do now is prepare to render our triangle and square data, then display our triangle and square. We will add the code in the RenderScene() function, right after the line d3dDevice->BeginScene(); and before the line d3dDevice->EndScene();. We start by setting the stream source, that is, where our vertex buffer is so we can feed the geometry to the rendering pipeline. HRESULT IDirect3DDevice9::SetStreamSource( UINT StreamNumber, IDirect3DVertexBuffer9* pStreamData, UINT OffsetInBytes, UINT Stride ); StreamNumber - Used for multiple streams. we don't have multiple streams so we set it to 0. pStreamData - Pointer to our Vertex Buffer that we want to stream. OffsetInBytes - Bytes from the start of the vertex buffer to start from. To use anything other than 0, you should check your device capabilities with the D3DCAPS9 structure. Stride - The size of our vertex structure. Then we need to set the Flexible Vertex Format(FVF). d3dDevice->SetStreamSource(0, TriangleVertexBuffer, 0, sizeof(Vertex)); d3dDevice->SetFVF(VertexFVF); After we do that, we draw our Primitive using the DrawPrimitive method. This method takes the vertex data from the SetStreamSource and displays it on the screen. HRESULT IDirect3DDevice9::DrawPrimitive( D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount ); PrimitiveType - This is the type of primitive we want to draw. We are going to draw triangles, so we us D3DPT_TRIANGLELIST. But if we wanted, we could use points or lines. StartVertex - Starting point in the vertex stream. This gives us the option of only rendering part of whats in the vertex buffer. PrimitiveCount - The number of primitives to draw. d3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 1); Thats it! For the drawing part anyway. I didn't add in the part where it checks for a 'T' or 'S' on the keyboard cause you should be able to figure that out. The 'T' is for Triangle and 'S' is for Square. Hope you learned a thing or two! If you have any comments on these tutorials, you should definitely contact us at the bottom. I wanna know what people think, do these tutorials suck or are they helpfull? even just saying suck or helpfull would be nice. haha, have fun! Here's the final code: main.cpp ... ... //bool to turn triangle on and off bool displaytriangle = false; //bool to turn square on and off bool displaysquare = true; IDirect3DVertexBuffer9* TriangleVertexBuffer = 0; IDirect3DVertexBuffer9* SquareVertexBuffer = 0; ... ... //Vertex structure struct Vertex { float x, y, z; }; //Define the Flexible vertex format const DWORD VertexFVF = D3DFVF_XYZ; ... ... bool SetupScene(){ //Set up our Scene d3dDevice->CreateVertexBuffer( //Create a new vertex buffer 3 * sizeof(Vertex), //Size of new vertex buffer D3DUSAGE_WRITEONLY, //Access instructions VertexFVF, //Vertex format D3DPOOL_MANAGED, //How to manage memory &TriangleVertexBuffer, //Pointer to store data to 0); d3dDevice->CreateVertexBuffer( 4 * sizeof(Vertex), D3DUSAGE_WRITEONLY, VertexFVF, D3DPOOL_MANAGED, &SquareVertexBuffer, 0); Vertex* vertices; //Create pointer to Vertex structure //Lock vertex Buffer TriangleVertexBuffer->Lock(0, 0, (void**)&vertices, 0); vertices[0].x =-0.5f; //Left vertex vertices[0].y = 0.0f; vertices[0].z = 0.0f; vertices[1].x = 0.0f; //Top vertex vertices[1].y = 0.5f; vertices[1].z = 0.0f; vertices[2].x = 0.5f; //Right vertex vertices[2].y = 0.0f; vertices[2].z = 0.0f; TriangleVertexBuffer->Unlock(); //UnLock vertex buffer //Lock vertex buffer SquareVertexBuffer->Lock(0, 0, (void**)&vertices, 0); vertices[0].x =-0.5f; vertices[0].y = 0.5f; vertices[0].z = 0.0f; vertices[1].x = 0.5f; vertices[1].y = 0.5f; vertices[1].z = 0.0f; vertices[2].x =-0.5f; vertices[2].y =-0.5f; vertices[2].z = 0.0f; vertices[3].x = 0.5f; vertices[3].y =-0.5f; vertices[3].z = 0.0f; SquareVertexBuffer->Unlock(); //UnLock vertex buffer //Use lines to create polygons d3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); return true; } //Release memory void CleanUpScene(){ TriangleVertexBuffer->Release(); SquareVertexBuffer->Release(); return; } //Renders a single frame bool RenderScene(float timeDelta) { if( d3dDevice ) { //Clear the window to 0x00000000 (black) d3dDevice->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000077, 1.0f, 0); d3dDevice->BeginScene(); //Start drawing our scene if(displaytriangle == true){ //Defines the source and start of the triangle data d3dDevice->SetStreamSource(0, TriangleVertexBuffer, 0, sizeof(Vertex)); d3dDevice->SetFVF(VertexFVF); //Set the flexible vertex format d3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 1); //draw the polygon } if(displaysquare == true){ d3dDevice->SetStreamSource(0, SquareVertexBuffer, 0, sizeof(Vertex)); d3dDevice->SetFVF(VertexFVF); d3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,0,2); } d3dDevice->EndScene(); //Stop drawing our scene d3dDevice->Present(0, 0, 0, 0); //Display our newly created scene } return true; } ... ...
Sign in to comment