Direct3D Lesson 6: Texture Mapping Our first change is to define a global Texture object. Later we'll load our image into it. ```//A texture is an image that is to be 'applied' to a polygon/triangle. By 'painting' //our triangles with images we can achieve some amazing effects. LPDIRECT3DTEXTURE8 g_texture=NULL; ``` Next we modify our vertex definition: ```//We add 2 floats to our vertex structure to store the texture coordinates. //tu & tv represent the location of the texture that should be mapped to this //vertex. tu can be thought of as the x-coordinate of the texture, and tv as //the y-coordinate. So if a vertex was to be mapped to the top left of a texture // you would set tu & tv to (0,0). Note-Texture coordinates range from 0.0 (left, or top) // to 1.0 (right, or bottom). //NOTE:Since we want our texture to provide all of our colour information we don't have //a diffuse component in our vertex definition. struct my_vertex{ FLOAT x, y, z; // The untransformed position for the vertex. FLOAT tu, tv; // The texture coordinates }; ``` Since we've modified the definition of our vertex, we have to update out vertex definition macro: ```//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_XYZ specifies that the vertex will have coordinate given in model space. //D3DFVF_TEX1 specifies that 1 set of texture coordinates will be provided as well. #define D3D8T_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_TEX1) ``` Now we modify the vertex array that defines our cube, we need to add the texture coordinates for each vertex. We also delete the vertices that did hold our pyramid, we don't need it in this tutorial. ```//The last 2 floats in this structure are the texture coordinates. As mentioned //before, their values range from 0.0 to 1.0. Our texture is a solid square and //we want to map it on to the cube so that each cube face is covered by the texture. //Looking at the front face of our cube, we see that (-1,1) is the top left of the //face, so we set its texture coordinates to (0,0), the top left of the texture. //Similarly, since vertex (1,-1) is the bottom right position, we set it to the //bottom right (1,1) of the texture. my_vertex g_vertices[] ={ { -1.0f, -1.0f, -1.0f, 0.0f, 1.0f }, //Front face { -1.0f, 1.0f, -1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, -1.0f, 1.0f, 0.0f }, { 1.0f, 1.0f, -1.0f, 1.0f, 0.0f }, { 1.0f, -1.0f, -1.0f, 1.0f, 1.0f }, { -1.0f, -1.0f, -1.0f, 0.0f, 1.0f }, { 1.0f, -1.0f, 1.0f, 0.0f, 1.0f }, //Back face { 1.0f, 1.0f, 1.0f, 0.0f, 0.0f }, { -1.0f, 1.0f, 1.0f, 1.0f, 0.0f }, { -1.0f, 1.0f, 1.0f, 1.0f, 0.0f }, { -1.0f, -1.0f, 1.0f, 1.0f, 1.0f }, { 1.0f, -1.0f, 1.0f, 0.0f, 1.0f }, { -1.0f, 1.0f, -1.0f, 0.0f, 1.0f }, //Top face { -1.0f, 1.0f, 1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f, 0.0f }, { 1.0f, 1.0f, -1.0f, 1.0f, 1.0f }, { -1.0f, 1.0f, -1.0f, 0.0f, 1.0f }, { 1.0f, -1.0f, -1.0f, 0.0f, 1.0f }, //Bottom face { 1.0f, -1.0f, 1.0f, 0.0f, 0.0f }, { -1.0f, -1.0f, 1.0f, 1.0f, 0.0f }, { -1.0f, -1.0f, 1.0f, 1.0f, 0.0f }, { -1.0f, -1.0f, -1.0f, 1.0f, 1.0f }, { 1.0f, -1.0f, -1.0f, 0.0f, 1.0f }, { -1.0f, -1.0f, 1.0f, 0.0f, 1.0f }, //Left face { -1.0f, 1.0f, 1.0f, 0.0f, 0.0f }, { -1.0f, 1.0f, -1.0f, 1.0f, 0.0f }, { -1.0f, 1.0f, -1.0f, 1.0f, 0.0f }, { -1.0f, -1.0f, -1.0f, 1.0f, 1.0f }, { -1.0f, -1.0f, 1.0f, 0.0f, 1.0f }, { 1.0f, -1.0f, -1.0f, 0.0f, 1.0f }, //Right face { 1.0f, 1.0f, -1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f, 0.0f }, { 1.0f, -1.0f, 1.0f, 1.0f, 1.0f }, { 1.0f, -1.0f, -1.0f, 0.0f, 1.0f }, }; ``` Since we are allocating a new resource, we modify kill_scene() to make sure it gets freed. ``` if(g_texture){ g_texture->Release(); g_texture=NULL; } ``` A couple of changes get made in init_scene(). First we have to tell Direct3D how to use our texture. By default D3D uses the vertex colours, now we want the vertex colours ignored and our texture to be used. ``` //The following SetTextureStageState calls determine how textures will //be applied to your objects in all of the following Draw operations. //D3DTSS_COLOROP specifies how the colour of each pixel will be determined //In this case it's set to D3DTOP_SELECTARG1 which means we look to the //setting of D3DTSS_COLORARG1 to determine the colour. g_d3d_device->SetTextureStageState(0,D3DTSS_COLOROP, D3DTOP_SELECTARG1); //D3DTSS_COLORARG1 is set to D3DTA_TEXTURE which means the colour is //entirely taken from the texture and nothing else. Alternately we could //have set D3DTA_DIFFUSE and then the colour would have come from our //vertex colour, completely ignoring the texture. g_d3d_device->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE); //We don't want to use Alpha Blending (Transparency) so we make sure it's //turned off for extra speed. g_d3d_device->SetTextureStageState(0,D3DTSS_ALPHAOP, D3DTOP_DISABLE); //The MAGFILTER specifies how the texture should be filtered when it's //drawn larger than it's real size, MINFILTER is for when it's drawn smaller //than it's real size. //The 2 most common choices are D3DTEXF_LINEAR & D3DTEXF_POINT. Linear //filtering is smoother but is also more expensive, point is fast but //generally doesn't look as good. g_d3d_device->SetTextureStageState(0,D3DTSS_MAGFILTER, D3DTEXF_LINEAR); g_d3d_device->SetTextureStageState(0,D3DTSS_MINFILTER, D3DTEXF_LINEAR); ``` Also in init_scene() we load our texture: ``` //Given a pointer to our device and a file name for our bitmap, //this function loads our texture and set g_texture to point to it. hr=D3DXCreateTextureFromFile( g_d3d_device, "DH.bmp",&g_texture); if(FAILED(hr)){ FatalError("Error loading texture"); } ``` Now we make 2 small additions to render(). Before we draw anything: ``` //Here we set our texture to be the current texture in the first texture 'stage' //There can be up to 8 textures and they can be blended in a variety of ways. //For now we only need one. g_d3d_device->SetTexture( 0, g_texture ); ``` And after we've finished drawing: ``` //After drawing, empty the first texture stage. When you SetTexture a texture //Direct3D adds to it's internal reference count, this prevents a texture from //being released when it's still being used. //When you're done drawing it's a good idea to set all of your texture stages to NULL //so your textures can be released when they should be. g_d3d_device->SetTexture(0,NULL); ```