Main Site Links Resources Tutorials
News VB Gaming Code Downloads DirectX 7
Contact Webmaster VB Programming Product Reviews DirectX 8
  General Multimedia Articles DirectX 9

Immediate Mode: Textures
By: Carl Warwick [Email] [Web: Freeride Designs]
Written: July 11 2000



Today I'm going to show you how to load a texture and use it on our pyramid, and we'll use bilinear filtering to make our textures look smooth even if the are stretched or shrunk. We will also set-up 3 lights to light up the pyramid.

This is quite a simple tutorial, loading a texture is very similiar to making a normal surface in DDraw, so most of this should be familiar to you.



Public PyramidVertex(5) As D3DVERTEX    'Array of vertices of the pyramid
Public BaseVertex(3) As D3DVERTEX        'Array of vertices for square base

Public PyramidTexture As DirectDrawSurface7 'Holds the pyramids texture
Public BaseTexture As DirectDrawSurface7 'Holds the base texture

We have two arrays of vertices, one to make our pyramid and one to make the base of our pyramid.

Then we have two DirectDrawSurface7 objects that store the textures.

Making the pyramid

We set up our objects just like normal, but this time we need to set the tu and tv values, these two values are the x and y texture coordinates.

pyramid tex.gif (2048 bytes)

The above image shows a top-down view of our pyramid, the numbers show the texture coordinates (tu, tv) at each vertex. As you can see our square texture will be mapped straight down onto the pyramid. Heres the code to set the vertices, and to create the textures.

Public Sub Initialise_Geometry()
    'Make the Pyramid, Make all the vertices white, so the texture colours
    'don't get messed up.

    Call DX.CreateD3DVertex(0, 5, 0, 0, 1, 0, 0.5, 0.5, PyramidVertex(0))
    Call DX.CreateD3DVertex(0, -5, 10, 0, 0, 1, 0, 0, PyramidVertex(1))
    Call DX.CreateD3DVertex(10, -5, 0, 1, 0, 0, 1, 0, PyramidVertex(2))
    Call DX.CreateD3DVertex(0, -5, -10, 0, 0, -1, 1, 1, PyramidVertex(3))
    Call DX.CreateD3DVertex(-10, -5, 0, -1, 0, 0, 0, 1, PyramidVertex(4))
    Call DX.CreateD3DVertex(0, -5, 10, 0, 0, 1, 0, 0, PyramidVertex(5))
    'Create our texture for the pyramid
    Set PyramidTexture = CreateTextureSurface(App.Path & "\PyramidTexture.bmp", 256, 256)

    'Make the base of the pyramid
    Call DX.CreateD3DVertex(10, -5, 0, 0, -1, 0, 0, 0, BaseVertex(0))
    Call DX.CreateD3DVertex(0, -5, 10, 0, -1, 0, 1, 0, BaseVertex(1))
    Call DX.CreateD3DVertex(0, -5, -10, 0, -1, 0, 0, 1, BaseVertex(2))
    Call DX.CreateD3DVertex(-10, -5, 0, 0, -1, 0, 1, 1, BaseVertex(3))

    'Create our texture for the base
    Set BaseTexture = CreateTextureSurface(App.Path & "\BaseTexture.bmp", 128, 128)

    'Set the Pyramid to its normal size
    ObjectScale = MakeVector(1, 1, 1)
End Sub

Take note of the normals, once again these are used for lighting the object.

Creating the textures

This is my texture creating function.

Public Function CreateTextureSurface(sFile As String, pWidth As Long, pHeight As Long, _
                                                Optional ColKey As Integer = 0) As DirectDrawSurface7

    Dim bOK As Boolean
    Dim enumTex As Direct3DEnumPixelFormats
    Dim sLoadFile As String
    Dim i As Long
    Dim ddsd As DDSURFACEDESC2
    Dim SurfaceObject As DirectDrawSurface7
    Dim Init As Boolean

    'Set our flags to tell the surface its a texture
    'If width and height were specified then make our texture that size,
    'otherwise it will be its normal size

    If ((pHeight <> 0) And (pWidth <> 0)) Then
        ddsd.lFlags = ddsd.lFlags Or DDSD_HEIGHT Or DDSD_WIDTH
        ddsd.lHeight = pHeight
        ddsd.lWidth = pWidth
    End If
    Set enumTex = Device.GetTextureFormatsEnum()

    'check if device supports 16bit surfaces
    For i = 1 To enumTex.GetCount()
        bOK = True
        Call enumTex.GetItem(i, ddsd.ddpfPixelFormat)

        With ddsd.ddpfPixelFormat
            If .lRGBBitCount <> 16 Then bOK = False
        End With
        If bOK = True Then Exit For

    If bOK = False Then
        Debug.Print "Unable to find 16bit surface support on your hardware - exiting"
        Init = False
    End If

    'set some texture surface flags
    If Device.GetDeviceGuid() = "IID_IDirect3DHALDevice" Then
            ddsd.ddsCaps.lCaps = DDSCAPS_TEXTURE
            ddsd.ddsCaps.lCaps2 = DDSCAPS2_TEXTUREMANAGE
            ddsd.lTextureStage = 0
            ddsd.ddsCaps.lCaps = DDSCAPS_TEXTURE
            ddsd.ddsCaps.lCaps2 = 0
            ddsd.lTextureStage = 0
    End If

    'If no filename was passed then create a blank surface
    If sFile = "" Then
        Set SurfaceObject = DD.CreateSurface(ddsd)
        Set SurfaceObject = DD.CreateSurfaceFromFile(sFile, ddsd)
    End If

    Set CreateTextureSurface = SurfaceObject

    'Colour key
    Dim ddckColourKey As DDCOLORKEY
    'Make a Black colorkey
    If ColKey = 1 Then
        ddckColourKey.low = 0
        ddckColourKey.high = 0
        CreateTextureSurface.SetColorKey DDCKEY_SRCBLT, ddckColourKey
    'Make a Magneta Colorkey, rgb(255,0,255)
    ElseIf ColKey = 2 Then
        CreateTextureSurface.GetPixelFormat ddpf
        ddckColourKey.low = ddpf.lBBitMask + ddpf.lRBitMask
        ddckColourKey.high = ddckColourKey.low
        CreateTextureSurface.SetColorKey DDCKEY_SRCBLT, ddckColourKey
    End If
End Function

As I said before, its pretty similar to creating normal DD surfaces, but we must enumerate the surface to make sure it supports 16bit surfaces. We must also set the caps to include DDSCAPS_TEXTURE, this is so that the surface knows it has to store a texture. If we are using a HAL device then its more efficient to let the device manage the textures, this basically means that textures that are going to be used are moved to video memory, and the others are put wherever they fit.

You can specify the size of the texture by passing the width and height variable to the function, but if you want the texture to be the size its saved as then just set these values to zero.

Texture surfaces should have their width and height set to lengths that are powers of 2, eg. 16x16, 32x32, 64x64, 128x128, 256x256 etc. They should also never be larger than 256x256 because most video cards don't support textures larger than this. Its possible to use odd shaped textures, eg. 256x128 or 32x64, but again not all cards support these surfaces, so its best to use square textures.

You should always try to use the smallest texture sizes possible so that you don't use up all the video memory.

If you wish to create a blank texture then just pass it a blank filename ( "" ).

The final thing that this function allows you to do is to set a colorkey to the surface, its possible to use either no color-key (default), black color-key or a magneta [RGB(255,0,255)] color-key. If you don't know what a color-key is then be sure to check the DDraw tutorials.

Bilinear filtering

If you stretch a texture too much over an object then it will look really blocky and horrible, to solve this we will use bilinear filtering. Bilinear filtering just blends the colours from the four closest pixels to get the correct colour when rendering the texture. Heres the nice and simple code to enable the filtering, just 2 lines.

    'Lets use bilinear filtering, very cool
    'MAGFILTER is if the texture is stretched

    Device.SetTextureStageState 0, D3DTSS_MAGFILTER, D3DTFG_LINEAR
    'MINFILTER is if texture is made smaller
    Device.SetTextureStageState 0, D3DTSS_MINFILTER, D3DTFN_LINEAR


There you go, nice and simple isn't it, but its one of those things that you have to know thats why it had its own tutorial. Texture co-ordinates are usually exported with an object, so you don't have to worry about manually setting them all.

The next tutorial will cover loading .x files

Carl Warwick - Freeride Designs

DirectX 4 VB 2000 Jack Hoxley. All rights reserved.
Reproduction of this site and it's contents, in whole or in part, is prohibited,
except where explicitly stated otherwise.
Design by Mateo
Contact Webmaster