# Texture Mapping

CU_Textures.zip (46.1 KiB, 3,873 hits)

Texture mapping is how the objects, characters, etc in games and movies look more realistic. In case you hadn’t noticed, all the tutorials preceding this one rendered geometry that was simply colored. With texture mapping, instead of creating a simple cube with pretty colors, we can slap some pictures of a crate on each side and voila, we have a crate to put in my game. And we all know a game isn’t complete without a crate.

Textures are created from images loaded into the application. The Internet has tons of textures that are free to download or you can make your own in a paint program or go out and take a picture of something. Each image has its own coordinates called texture coordinates. Texture coordinates tell the video drivers what color of the image to render onto the polygon. Texture coordinates are in the range of [0,1]. The point (0,0) is the top left corner of the image and the coordinates increase left to right and top to bottom. We need to specify a unique set of texture coordinates for each vertex because altough two vertices may share the same position, the texture coordinates may need to be different.

Usually, vertex data is created by a modeling program such as Maya, 3ds Max, or Milkshape 3D so you don’t need to code in all the coordinates. You just read in the file and store the data directly into the vertex buffer. However, since we haven’t yet learned how to load in this data, we’ll just do it the old fashion way: by hand.

```struct CUSTOMVERTEX
{
float x, y, z; // Position in 3d space
DWORD color;   // Color
float u, v;    // Texture coordinates

};
CUSTOMVERTEX g_vertices[] =
{
{-1.0f,  1.0f, -1.0f, D3DCOLOR_XRGB( 255, 255, 255 ), 0.0f, 0.0f},
{ 1.0f,  1.0f, -1.0f, D3DCOLOR_XRGB( 255, 255, 255 ), 1.0f, 0.0f},
{ 1.0f, -1.0f, -1.0f, D3DCOLOR_XRGB( 255, 255, 255 ), 1.0f, 1.0f},
{-1.0f,  1.0f, -1.0f, D3DCOLOR_XRGB( 255, 255, 255 ), 0.0f, 0.0f},
{ 1.0f, -1.0f, -1.0f, D3DCOLOR_XRGB( 255, 255, 255 ), 1.0f, 1.0f},
{-1.0f, -1.0f, -1.0f, D3DCOLOR_XRGB( 255, 255, 255 ), 0.0f, 1.0f},
{ 1.0f,  1.0f, -1.0f, D3DCOLOR_XRGB( 255, 255, 255 ), 0.0f, 0.0f},
{ 1.0f,  1.0f,  1.0f, D3DCOLOR_XRGB( 255, 255, 255 ), 1.0f, 0.0f},
{ 1.0f, -1.0f,  1.0f, D3DCOLOR_XRGB( 255, 255, 255 ), 1.0f, 1.0f},
{ 1.0f,  1.0f, -1.0f, D3DCOLOR_XRGB( 255, 255, 255 ), 0.0f, 0.0f},
{ 1.0f, -1.0f,  1.0f, D3DCOLOR_XRGB( 255, 255, 255 ), 1.0f, 1.0f},
{ 1.0f, -1.0f, -1.0f, D3DCOLOR_XRGB( 255, 255, 255 ), 0.0f, 1.0f},
{ 1.0f,  1.0f,  1.0f, D3DCOLOR_XRGB( 255, 255, 255 ), 0.0f, 0.0f},
{-1.0f,  1.0f,  1.0f, D3DCOLOR_XRGB( 255, 255, 255 ), 1.0f, 0.0f},
{-1.0f, -1.0f,  1.0f, D3DCOLOR_XRGB( 255, 255, 255 ), 1.0f, 1.0f},
{ 1.0f,  1.0f,  1.0f, D3DCOLOR_XRGB( 255, 255, 255 ), 0.0f, 0.0f},
{-1.0f, -1.0f,  1.0f, D3DCOLOR_XRGB( 255, 255, 255 ), 1.0f, 1.0f},
{ 1.0f, -1.0f,  1.0f, D3DCOLOR_XRGB( 255, 255, 255 ), 0.0f, 1.0f},
{-1.0f,  1.0f,  1.0f, D3DCOLOR_XRGB( 255, 255, 255 ), 0.0f, 0.0f},
{-1.0f,  1.0f, -1.0f, D3DCOLOR_XRGB( 255, 255, 255 ), 1.0f, 0.0f},
{-1.0f, -1.0f, -1.0f, D3DCOLOR_XRGB( 255, 255, 255 ), 1.0f, 1.0f},
{-1.0f,  1.0f,  1.0f, D3DCOLOR_XRGB( 255, 255, 255 ), 0.0f, 0.0f},
{-1.0f, -1.0f, -1.0f, D3DCOLOR_XRGB( 255, 255, 255 ), 1.0f, 1.0f},
{-1.0f, -1.0f,  1.0f, D3DCOLOR_XRGB( 255, 255, 255 ), 0.0f, 1.0f},
{-1.0f,  1.0f,  1.0f, D3DCOLOR_XRGB(   0,   0, 255 ), 0.0f, 0.0f},
{ 1.0f,  1.0f,  1.0f, D3DCOLOR_XRGB(   0, 255,   0 ), 1.0f, 0.0f},
{ 1.0f,  1.0f, -1.0f, D3DCOLOR_XRGB( 255,   0,   0 ), 1.0f, 1.0f},
{-1.0f,  1.0f,  1.0f, D3DCOLOR_XRGB(   0,   0, 255 ), 0.0f, 0.0f},
{ 1.0f,  1.0f, -1.0f, D3DCOLOR_XRGB( 255,   0,   0 ), 1.0f, 1.0f},
{-1.0f,  1.0f, -1.0f, D3DCOLOR_XRGB( 255, 255,   0 ), 0.0f, 1.0f},
{-1.0f, -1.0f, -1.0f, D3DCOLOR_XRGB( 255, 255, 255 ), 0.0f, 0.0f},
{ 1.0f, -1.0f, -1.0f, D3DCOLOR_XRGB( 255, 255, 255 ), 1.0f, 0.0f},
{ 1.0f, -1.0f,  1.0f, D3DCOLOR_XRGB( 255, 255, 255 ), 1.0f, 1.0f},
{-1.0f, -1.0f, -1.0f, D3DCOLOR_XRGB( 255, 255, 255 ), 0.0f, 0.0f},
{ 1.0f, -1.0f,  1.0f, D3DCOLOR_XRGB( 255, 255, 255 ), 1.0f, 1.0f},
{-1.0f, -1.0f,  1.0f, D3DCOLOR_XRGB( 255, 255, 255 ), 0.0f, 1.0f}

};

```

First we define our vertices. As you can see, it’s a bit tedious not to use a modeling program. Since we’re going to be using textures, we need to adjust our vertex definition to include texture coordinates. Then, we’ll create an array of vertices, each of which contain a position, a color, and a set of texture coordinates. When a vertex has both a color and a texture, the color modulates the texture. When the color is white, the texture will be shown in full color. For any other color, the specified color will be overlaid on top of the texture. For the top of the crate, I specified a few different colors so you can see the effect it has on the texture.

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Summary:
This callback function will be called immediately after the Direct3D device has been created. This is
the best location to create D3DPOOL_MANAGED resources. Resources created here should be released in
the OnDestroyDevice callback.
Parameters:
[in] pDevice – Pointer to a DIRECT3DDEVICE9 instance
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void CGameApp::OnCreateDevice( LPDIRECT3DDEVICE9 pDevice )
{

// Create the buffer
m_VB.CreateBuffer( pDevice, 36, D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1, sizeof( CUSTOMVERTEX ) );
m_VB.SetData( 36, g_vertices, 0 );

char texture[MAX_PATH] = {0};
CUtility::GetMediaFile( “panel.jpg”, texture );
if ( !texture )
{

SHOWERROR( “Unable to find texture file.”, __FILE__, __LINE__ );

}
if ( FAILED( D3DXCreateTextureFromFile( pDevice, texture, &m_pTexture ) ) )
{

SHOWERROR( “Unable to create texture.”, __FILE__, __LINE__ );

}

}

When we create the vertex buffer, we have specify that the vertices hold texture coordinates. We do this by updating the FVF parameter with D3DFVF_TEX1. After creating the vertex buffer and setting its data, we need to load in our texture data into a IDirect3DTexture9 object. We can do this simply by calling D3DXCreateTextureFromFile. There is another function, D3DXCreateTextureFromFileEx, which lets you specify more options for the texture, but to keep things simple, I just use the first function. The D3DXCreateTextureFromFile function loads in the texture data to the IDirect3DTexture9 object, which is the m_pTexture variable shown in the code.

You’ll notice that I get my texture file name with CUtility::GetMediaFile. This is a helper function I adapted from the DirectX SDK. I have extremely shortened it for our purposes, but it will work fine for what we are doing. The GetMediaFile method is useful because applications look for files relative to the executing file. In Visual Studio .NET 2003, when you compile and run a C++ program from inside the IDE, the executable is placed in “/Debug/” by default (if you’re in debug mode) but the program looks for files relative to the location of the project file. However, if you were to run the executable directly by double-clicking on the file in the “/Debug/” folder, the program looks for files relative to the executable file. The GetMediaFile method searches the folders in the vicinity of the executable to find the file you are looking for. Check out the source code to view the CUtility class.

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Summary:
This callback function will be called immediately after the Direct3D device has been created. This is
the best location to create D3DPOOL_DEFAULT resources. Resources created here should be released in
the OnLostDevice callback.
Parameters:
[in] pDevice – Pointer to a DIRECT3DDEVICE9 instance
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void CGameApp::OnResetDevice( LPDIRECT3DDEVICE9 pDevice )
{

// Clip..

pDevice->SetTexture( 0, m_pTexture );

}

Before we render we have to tell DirectX which texture to render the current geometry with. This is done with the IDirect3DDevice9::SetTexture method.

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Summary:
This callback function will be called immediately after the Direct3D device has been destroyed.
Resources created in the OnCreateDevice callback should be released here, which generally includes
all D3DPOOL_MANAGED resources.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void CGameApp::OnDestroyDevice()
{

m_VB.Release();
SAFE_RELEASE( m_pTexture );

}

Don’t forget to be nice and clean up after yourself. D3DXCreateTextureFromFile creates textures in the D3DPOOL_MANAGED memory pool by default so we’ll release it in the OnDestroyDevice method.

As you can see it doesn’t take much to use textures in our programs. With simple geometry, it is easy to write out the vertices by hand. However, as we start using more complex geometry, we will have all the vertex data generated for us by a modeling program.

## 2 thoughts on “Texture Mapping”

### Lukás September 18, 2013 at 4:09 am

Hey i really like your work. but in this tutorial u forgot to write here your CUtility class

### Holosim January 29, 2015 at 10:18 am

Interesting! I posted questions in previous tutorials about break points being triggered in crt0dat.c (from “Rendered Primitives” through “Dynamic Buffers”) and CVertexBuffer.cpp ( from “Vertex and Index Buffers” through “Dynamic Buffers”) because the vertex buffer lock failed. But in this solution, no breakpoints are being triggered.

I’m going to take a good hard look at the differences between these solutions and see if I can’t finally learn what the heck that crt0dat.c business is all about. And maybe get some deeper insight into how vertex buffering works. Best way to learn about something is to break it, right?

Any other insight you might have would be greatly appreciated.
Thanks,
Kyle Simmons

```<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>