Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
101 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:

5. Drawing a texture

Time to get something on the screen. Two main drawing functions will be used -- BlitD3D() and BlitExD3D(). The only difference between the two is that BlitExD3D() supports colour modulation of all four corners of the quad, while BlitD3D() can only tint the whole quad.

Please be aware that the rotation code provided here is horrible, and should be rewritten. Use it at your own risk.

//Draw a textured quad on the back-buffer
void BlitD3D (IDirect3DTexture9 *texture, RECT *rDest,
    D3DCOLOR vertexColour, float rotate)
{
  TLVERTEX* vertices;

  //Lock the vertex buffer
  vertexBuffer->Lock(0, 0, (void**)&vertices, NULL);

  //Setup vertices
  //A -0.5f modifier is applied to vertex coordinates to match texture
  //and screen coords. Some drivers may compensate for this
  //automatically, but on others texture alignment errors are introduced
  //More information on this can be found in the Direct3D 9 documentation
  vertices[0].colour = vertexColour;
  vertices[0].x = (float) rDest->left - 0.5f;
  vertices[0].y = (float) rDest->top - 0.5f;
  vertices[0].z = 0.0f;
  vertices[0].rhw = 1.0f;
  vertices[0].u = 0.0f;
  vertices[0].v = 0.0f;

  vertices[1].colour = vertexColour;
  vertices[1].x = (float) rDest->right - 0.5f;
  vertices[1].y = (float) rDest->top - 0.5f;
  vertices[1].z = 0.0f;
  vertices[1].rhw = 1.0f;
  vertices[1].u = 1.0f;
  vertices[1].v = 0.0f;

  vertices[2].colour = vertexColour;
  vertices[2].x = (float) rDest->right - 0.5f;
  vertices[2].y = (float) rDest->bottom - 0.5f;
  vertices[2].z = 0.0f;
  vertices[2].rhw = 1.0f;
  vertices[2].u = 1.0f;
  vertices[2].v = 1.0f;

  vertices[3].colour = vertexColour;
  vertices[3].x = (float) rDest->left - 0.5f;
  vertices[3].y = (float) rDest->bottom - 0.5f;
  vertices[3].z = 0.0f;
  vertices[3].rhw = 1.0f;
  vertices[3].u = 0.0f;
  vertices[3].v = 1.0f;

  //Handle rotation
  if (rotate != 0)
  {
    RECT rOrigin;
    float centerX, centerY;

    //Find center of destination rectangle
    centerX = (float)(rDest->left + rDest->right) / 2;
    centerY = (float)(rDest->top + rDest->bottom) / 2;

    //Translate destination rect to be centered on the origin
    rOrigin.top = rDest->top - (int)(centerY);
    rOrigin.bottom = rDest->bottom - (int)(centerY);
    rOrigin.left = rDest->left - (int)(centerX);
    rOrigin.right = rDest->right - (int)(centerX);

    //Rotate vertices about the origin
    bufferVertices[index].x = rOrigin.left * cosf(rotate) -
                              rOrigin.top * sinf(rotate);
    bufferVertices[index].y = rOrigin.left * sinf(rotate) +
                              rOrigin.top * cosf(rotate);

    bufferVertices[index + 1].x = rOrigin.right * cosf(rotate) -
                                  rOrigin.top * sinf(rotate);
    bufferVertices[index + 1].y = rOrigin.right * sinf(rotate) +
                                  rOrigin.top * cosf(rotate);

    bufferVertices[index + 2].x = rOrigin.right * cosf(rotate) -
                                  rOrigin.bottom * sinf(rotate);
    bufferVertices[index + 2].y = rOrigin.right * sinf(rotate) +
                                  rOrigin.bottom * cosf(rotate);

    bufferVertices[index + 3].x = rOrigin.left * cosf(rotate) -
                                  rOrigin.bottom * sinf(rotate);
    bufferVertices[index + 3].y = rOrigin.left * sinf(rotate) +
                                  rOrigin.bottom * cosf(rotate);

    //Translate vertices to proper position
    bufferVertices[index].x += centerX;
    bufferVertices[index].y += centerY;
    bufferVertices[index + 1].x += centerX;
    bufferVertices[index + 1].y += centerY;
    bufferVertices[index + 2].x += centerX;
    bufferVertices[index + 2].y += centerY;
    bufferVertices[index + 3].x += centerX;
    bufferVertices[index + 3].y += centerY;
  }

  //Unlock the vertex buffer
  vertexBuffer->Unlock();

  //Set texture
  DEVICE->SetTexture (0, texture);

  //Draw image
  DEVICE->DrawPrimitive (D3DPT_TRIANGLEFAN, 0, 2);
}

NOTE: Replace DEVICE with the name of your IDirect3DDevice9* object

Here's a description of the arguments passed to the function:

texture - A pointer to the texture to use on the quad. Whatever is passed here will show up on screen.

rDest - A rectangle containing the screen coordinates of the quad. If the rectangle is of a different size than the texture, the image will be scaled.

vertexColour - The colour used to tint the quad in 32-bit 0xAARRGGBB format. A value of 0xFFFFFFFF will not modify the appearance of the texture.

fRotate - How much the quad should be rotated about its center. The value should be in radians. A value of 0 will, of course, not rotate the quad at all.

The extended blitting function follows:

//Draw a textured quad on the back-buffer
void BlitExD3D (IDirect3DTexture9 *texture, RECT *rDest,
    D3DCOLOR *vertexColours /* -> D3DCOLOR[4] */, float rotate)
{
  TLVERTEX* vertices;

  //Lock the vertex buffer
  vertexBuffer->Lock(0, 0, (void**)&vertices, NULL);

  //Setup vertices
  //A -0.5f modifier is applied to vertex coordinates to match texture
  //and screen coords. Some drivers may compensate for this
  //automatically, but on others texture alignment errors are introduced
  //More information on this can be found in the Direct3D 9 documentation
  vertices[0].colour = vertexColours[0];
  vertices[0].x = (float) rDest->left - 0.5f;
  vertices[0].y = (float) rDest->top - 0.5f;
  vertices[0].z = 0.0f;
  vertices[0].rhw = 1.0f;
  vertices[0].u = 0.0f;
  vertices[0].v = 0.0f;

  vertices[1].colour = vertexColours[1];
  vertices[1].x = (float) rDest->right - 0.5f;
  vertices[1].y = (float) rDest->top - 0.5f;
  vertices[1].z = 0.0f;
  vertices[1].rhw = 1.0f;
  vertices[1].u = 1.0f;
  vertices[1].v = 0.0f;

  vertices[2].colour = vertexColours[2];
  vertices[2].x = (float) rDest->right - 0.5f;
  vertices[2].y = (float) rDest->bottom - 0.5f;
  vertices[2].z = 0.0f;
  vertices[2].rhw = 1.0f;
  vertices[2].u = 1.0f;
  vertices[2].v = 1.0f;

  vertices[3].colour = vertexColours[3];
  vertices[3].x = (float) rDest->left - 0.5f;
  vertices[3].y = (float) rDest->bottom - 0.5f;
  vertices[3].z = 0.0f;
  vertices[3].rhw = 1.0f;
  vertices[3].u = 0.0f;
  vertices[3].v = 1.0f;

  //Handle rotation
  if (rotate != 0)
  {
    RECT rOrigin;
    float centerX, centerY;

    //Find center of destination rectangle
    centerX = (float)(rDest->left + rDest->right) / 2;
    centerY = (float)(rDest->top + rDest->bottom) / 2;

    //Translate destination rect to be centered on the origin
    rOrigin.top = rDest->top - (int)(centerY);
    rOrigin.bottom = rDest->bottom - (int)(centerY);
    rOrigin.left = rDest->left - (int)(centerX);
    rOrigin.right = rDest->right - (int)(centerX);

    //Rotate vertices about the origin
    bufferVertices[index].x = rOrigin.left * cosf(rotate) -
                              rOrigin.top * sinf(rotate);
    bufferVertices[index].y = rOrigin.left * sinf(rotate) +
                              rOrigin.top * cosf(rotate);

    bufferVertices[index + 1].x = rOrigin.right * cosf(rotate) -
                                  rOrigin.top * sinf(rotate);
    bufferVertices[index + 1].y = rOrigin.right * sinf(rotate) +
                                  rOrigin.top * cosf(rotate);

    bufferVertices[index + 2].x = rOrigin.right * cosf(rotate) -
                                  rOrigin.bottom * sinf(rotate);
    bufferVertices[index + 2].y = rOrigin.right * sinf(rotate) +
                                  rOrigin.bottom * cosf(rotate);

    bufferVertices[index + 3].x = rOrigin.left * cosf(rotate) -
                                  rOrigin.bottom * sinf(rotate);
    bufferVertices[index + 3].y = rOrigin.left * sinf(rotate) +
                                  rOrigin.bottom * cosf(rotate);

    //Translate vertices to proper position
    bufferVertices[index].x += centerX;
    bufferVertices[index].y += centerY;
    bufferVertices[index + 1].x += centerX;
    bufferVertices[index + 1].y += centerY;
    bufferVertices[index + 2].x += centerX;
    bufferVertices[index + 2].y += centerY;
    bufferVertices[index + 3].x += centerX;
    bufferVertices[index + 3].y += centerY;
  }

  //Unlock the vertex buffer
  vertexBuffer->Unlock();

  //Set texture
  DEVICE->SetTexture (0, texture);

  //Draw image
  DEVICE->DrawPrimitive (D3DPT_TRIANGLEFAN, 0, 2);
}

NOTE: Replace DEVICE with the name of your IDirect3DDevice9* object

The only argument here that is different from the BlitD3D() function is vertexColours.

vertexColours must be a pointer to a D3DCOLOR array of size 4. The indices of the array correspond to the numbers of the vertices in the kick-ass diagram provided at the beginning of this article. Each vertex in the quad will have its colour and alpha modulated based on its corresponding value in vertexColours.



The CTexture class

Contents
  The concept
  Initialization code
  Drawing a texture
  The CTexture class
  Appendix

  Source code
  Printable version
  Discuss this article