Immediate Mode: Textures
By: Carl Warwick [Email] [Web: Freeride Designs]
Written: July 11 2000
Contents
Introduction
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.
Declarations
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.
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
ddsd.lFlags
=
DDSD_CAPS
Or
DDSD_TEXTURESTAGE
Or
DDSD_PIXELFORMAT
'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
Next
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
Else
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)
Else
Set
SurfaceObject
=
DD.CreateSurfaceFromFile(sFile,
ddsd)
End If
Set
CreateTextureSurface
=
SurfaceObject
'Colour key
Dim
ddckColourKey
As
DDCOLORKEY
Dim
ddpf
As
DDPIXELFORMAT
'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 |
|
|
|
Conclusions
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
|