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
      Miscellaneous

DirectX Graphics: 2D Graphics Part 2
Author : Jack Hoxley
Written : 30th November 2000
Contact : [Email]
Download : Graph_04.Zip [8 Kb]


Contents of this lesson:
1. Introduction
2. Some more theory
3. Loading A Texture and displaying it
4. Transparencies


1. Introduction

Welcome back to the fourth lesson on learning DirectX graphics. I've decided to alter the way I'm writing things; This tutorial was originally going to include a basic look at texturing for 2D primatives. But I realised that it'd be very similiar to the later lesson I'd planned on introducing textures; so rather than do two half lessons, it's all going to be done here - well the basics anyway. Ignore my ramblings if this is a long time after 7th December....

Textures in Direct3D are a massive topic, EVERY game that you play on your computer will use lots and lots of textures - almost everything that's rendered is likely to be textured in some way. Textures add incredible realism to an object - something that shape and colour would never be able to achieve.

Simple texturing, once learned, is extremely simple and you'll be able to do it in your sleep within a few lessons; but you HAVE TO understand the basics in order to get anywhere with the clever stuff a little later on. Texture blending, animation and skinning all come under the heading of textures - and without the basic knowledge you can never hope to realise that dream of writing the next Quake 3 engine (if that's what you think of).

Enough talk, time to learn some theory.... hehe


2. Some more Theory

It wouldn't surprise me if you were getting bored of all the theory you're learning - but if you have any intentions of getting good with DirectX theory will be your best friend (maybe). The main things that you'll need to know before we get started are outlined below:

What is a texture?
A texture is a 2D bitmap that is loaded into memory and then mapped across triangles. Up till this point you will have seen coloured triangles - where the colour is there will be part of a texture. Textures tend to take up large amounts of memory if either large in number or large in size - which is one of the main reasons why we've seen the rapid increase in on-board memory for 3D accelerators.

Texture Coordinates
Texture coordinates are NOT in pixels - remember that. All texture coordinates are on a 0.0 to 1.0 scale; were 0.0 is the minimum value (pixel 0) and 1.0 is the maximum (255 for a 256x256 texture, 511 for a 512x512 texture and so on...). If you have to still use pixels for your measurements you can use a simple formula to convert : TexCoord = (1 / MaxTexSize) * PixelCoord; which if you work it out is perfect : (1/256) * 128 = 0.5 (correct, as 128 is half way between them). This isn't greatly difficult, more of something to remember; specifying 256 as a texture coordinate will either not work or give you some really really weird results....

Texture Sizes
Textures sizes are often a real pain in the back side. All sizes must be 2^n that is, any integer value to the power of n: 2^1, 2^2, 2^3, 2^4 and so on.... This means that textures get larger and larger as the integer goes up - which becomes awkward if you wish to use an 800x800 textures (nearest values are 512x512 or 1024x1024). Another thing to note - it's usually impractical to use textures greater than 256x256 in size. Some hardware doesn't support it, other hardware just runs much slower when using large textures. Also, be practical when drawing your textures - there is NO point in designing a super detailed texture that's always going to be seen as very very small on screen - the detail will never be visible (as well as it being slow to map large textures onto small triangles).

Lighting
Whilst we haven't really covered lighting yet (and we're not going to here) you should bare in mind that lighting has an affect on how the textures will be seen. This will be demonstrated in this lesson by the colours of the vertices that make up the triangles. In the previous lesson we gave each vertex a colour, this colour is basically light; and the texture will be tinted according to the vertex colour. For example; a green vertex will make the texture appear green....


3. Loading a Texture and displaying it

So, you want to play around with textures now. We're going to modify our Lesson 03 code so that instead of nice colourful shapes we get nice textured shapes. This first part is extremely easy actually; but you'll see how it gets more complicated later on....

First, we need two new declarations to be added:

Dim D3DX As D3DX8 '//A helper library
Dim Texture As Direct3DTexture8

Not too complicated really; the D3DX8 object is something that you'll come across again and again in the future - so I may as well introduce it. D3DX is a helper class, it has lots and lots of useful functions included in it to make certain tasks easier. The main ones being shape (Geometry) creation, Mesh manipulation, texture loading and some simple maths things - such as bounding boxes and ray intersections (which aren't really that simple).

Second, we need to add a few lines into our initialisation function:

'This next line can go after we create the DirectX
'Object and the Direct3DDevice8 object


Set D3DX = New D3DX8 '//Create our helper library...

'Either way, the above line must come before this line....

'//We now want to load our texture;

Set Texture = D3DX.CreateTextureFromFile(D3DDevice, App.Path & "\ExampleTexture.bmp")

Assuming alls-well, we now have a texture loaded into memory. At this level it's not really very complicated at all; the D3DX.CreateTextureFromFile is a very simple call to use, and I'd be very surprised if anyone out there could get it wrong! Later on we'll be using CreateTextureFromFileEx - which allows us much more control over things - at the expense of being much more complicated....

The penultimate thing we need to do is reconfigure our geometry for texture coordinates. In this particular instance, when we're dealing with squares, creating texture coordinates is extremely easy. Assuming you want the square to have the entire texture you just set corners 1,2,3 to have U or V components of 1.0 (yes, U and V - just think of them as X and Y). Should you end up with more obscure shapes it'll get much more complicated:

Even the above diagram for the pentagon may well be wrong - It's how I'd do it, but depending on
the positions of you're vertices you may well need them to be different.

To alter the coordinates we just pass the values in the last two parameters of the CreateTLVertex( ) function that we saw in the last lesson. For our square we need the lines to look like this:

'vertex 0
TriStrip(0) = CreateTLVertex(10, 10, 0, 1, RGB(255, 255, 255), 0, 0, 0)
            
'vertex 1
TriStrip(1) = CreateTLVertex(210, 10, 0, 1, RGB(255, 0, 0), 0, 1, 0)
            
'vertex 2
TriStrip(2) = CreateTLVertex(10, 210, 0, 1, RGB(0, 255, 0), 0, 0, 1)
            
'vertex 3
TriStrip(3) = CreateTLVertex(210, 210, 0, 1, RGB(0, 0, 255), 0, 1, 1)

The code above is the same as the square we set up in the last lesson; but with the added texture coordinates.

Finally we need to render our primatives using the texture we just loaded. This is extremely simple actually - as shown by the following code:

D3DDevice.SetTexture 0, Texture '//Tell the device which texture we want to use...
D3DDevice.DrawPrimitiveUP D3DPT_TRIANGLESTRIP, 2, TriStrip(0), Len(TriStrip(0))

The second line you should already know about, the first one is hardly very complicated. The "0" parameter can be replaced with different values when you do multiple texture blending and other special texture effects - but right now we dont want to play around with that stuff. You should see, as you're result something looking like this:

[Cut down and 75% of full size]

You may well notice in the above picture that a) we have two squares, b) they're different colours. In the sample code for this lesson it actually creates two squares to illustrate the next point, but as the code is almost identical I didn't put it in above. The point is that lighting/vertex colours affect the way that textures are displayed. Normally the texture is grey (like the right-hand square), but when you apply the texture to a triangle where the vertices are not white we get this colorisation. This is the basis of Direct3D lighting - It alters the vertex colour which in turn alters the texture. This can be incredibly useful to you, whilst white vertices result in a normal texture, grey vertices will darken the texture; coloured ones, as you can see, colorise the final texture. There is one thing that you must bare in mind - if there is no green around a green vertex then the resulting colour will be black. You should be aware of how colours are generated - red green and blue components, if the colour at a vertex is 0.5 (half) then all the pixels nearby will have each colour channel halved (making it darker). What happens when the texture is almost all red, yet the light is green? The light multiplies all red and blue components by 0 and all green components by 0.75 (or whatever value); which will mean that the red part of the texture will be multipled by 0, which will give 0, the blue will be multiplied by 0, as there is no blue anyway we're left with blue; finally the green is multiplied by 0.75 - but a red texture has no green, so it's 0*0.75, which again results in 0 - the final colour being 0,0,0 - black. There are ways around this, but we'll discuss them in a later lesson (about lighting).


4. Transparencies

At this point you should be perfectly capable of creating a 2D game using Direct3D8 - it would probably be quite basic, but it's not impossible. You can create 2D geometry and you can apply textures to it. The final thing that you need to know about textures in order to do nice 2D graphics is transparencies.

Transparencies are where the renderer doesn't render part of a texture based on the colour. This allows you to create incredibly detailed textures without incredibly high triangle/vertex counts. You could quite easily create a circle shape with triangles, yet you'd need 100's of them; using transparencies you could make a texture with transparent parts and apply it to a square (with only 2 triangles remember) and it would look the same (or better).

To use transparencies we must first add three new lines into our initialisation function:

D3DDevice.SetRenderState D3DRS_SRCBLEND, D3DBLEND_SRCALPHA
D3DDevice.SetRenderState D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA
D3DDevice.SetRenderState D3DRS_ALPHABLENDENABLE, True

These three lines allow you to use transparent textures; first we tell Direct3D what type of transparencies we want (there are a few possible options) then we enable the usage of alpha blending. First thing to note - Alpha blending is a fairly advanced topic - it just so happens that we need it to do transparencies; but we'll come back to it later on in more detail. Another thing to note is that we enable it's usage from the start; this adds a slight performance overhead to our program - it's much better to leave it disabled and only turn it on when you need it (ie, on before the DrawPrimativeUP call, and off again afterwards). As you will find out later, when you use different types of SRCBLEND and DESTBLEND factors it'll affect all textures and rendering; so having it on all the time is not a great idea...

Now, to load in a transparent texture we need to use a new function - this time more complicated than the original one.

'//Choose one of the following depending on what you
'   should need. Other colours can be made up, but these
'   ones should be okay for most uses...


'ColorKeyVal = &HFF000000 '//Black
'ColorKeyVal = &HFFFF0000 '//Red

ColorKeyVal = &HFF00FF00 '//Green
'ColorKeyVal = &HFF0000FF '//Blue
'ColorKeyVal = &HFFFF00FF '//Magenta
'ColorKeyVal = &HFFFFFF00 '//Yellow
'ColorKeyVal = &HFF00FFFF '//Cyan
'ColorKeyVal = &HFFFFFFFF '//White


Set TransTexture = D3DX.CreateTextureFromFileEx(D3DDevice, App.Path & "\transtexture.bmp", 64, 64, _
                                                                            D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, _
                                                                            D3DPOOL_MANAGED, D3DX_FILTER_POINT, _
                                                                            D3DX_FILTER_POINT, ColorKeyVal, _
                                                                            ByVal 0, ByVal 0)

Not too complicated really. The first part is just for convenience - by commenting and uncommenting these lines you can use different colours as the transparent one. The D3DX.CreateTextureFromFileEx function has quite a few parameters, you should get to know this function, as it is quite likely that you'll use this function for almost all of your texture loading.

object.CreateTextureFromFileEx( _ 
    Device As Direct3DDevice8, _ 
    SrcFile As String, _ 
    Width As Long, _ 
    Height As Long, _ 
    MipLevels As Long, _ 
    Usage As Long, _ 
    Format As CONST_D3DFORMAT, _ 
    Pool As CONST_D3DPOOL, _ 
    Filter As Long, _ 
    MipFilter As Long, _ 
    ColorKey As Long, _ 
    SrcInfo As Any _ 
    Palette As Any) As Direct3DTexture8

From the top then:

Object : An initialised D3DX8 object.
Device : Your 3D rendering Device
SrcFile : A string indicating where the texture is to be loaded from
Width : width in pixels, if specified it must be a valid power of 2 value (64, 128, 256 and so on...). You can use "D3DX_DEFAULT" to let Direct3D decide what size to load it as (whatever size it was saved at)
Height : Same as width, but for the height (funny that)
MipLevels : How many mip-map levels are generated; these will be discussed later on in this series. For now just leave it as D3DX_DEFAULT (A complete chain is created) or 1 (Only 1 level is generated) where 1 will require the least amount of memory.
Usage : You can make this texture a render target (useful for some special effects) but for normal use make this value 0.
Format : What format the surface is in; same as when you specify what backbuffer format you want during initialisation. If you're doing anything clever you may well need to know what this format is; but most of the time just leave it as "D3DFMT_UNKNOWN"
Pool : Whereabouts this memory should be allocated; certain areas have less space and different areas are faster for different uses. D3DPOOL_MANAGED should be suitable for most uses, other uses will be explained later on in this series.
Filter : What texture filter we want to use. This only really affects things that are stretched or squashed - which when you move into proper 3D will happen to almost every texture used. Normally you'll want to use D3DX_FILTER_LINEAR , but for simple things you can use D3DX_FILTER_POINT and for best quality you can use D3DX_FILTER_TRIANGLE. Experiment with them as you choose - some look better than others in certain situations
MipFilter : Same as the above argument, but for mip maps. These will be explained later on in the series.
ColorKey : What colour is going to be transparent black. This is a 32 bit ARGB code - best represented by a hexidecimal number. You should be familiar with RGB notation (3 sets of 2 figures (0 to 9) or letters (A to F)); this value is basically &HFF<normal rgb val>. All it does is make all pixels of the specified colour fully transparent.
SrcInfo : Allows you to specify a D3DXIMAGE_INFO structure giving any information about the source file - height, width, depth and format. Not really needed - leave as "ByVal 0"
Palette : Leave as ByVal 0. Palettes are on the way out, with the ever increasing hardware (even the now "old" cards support better) capabilites there is very little speed advantage to be gained by using them - and they look pretty rubbish anyway.

Thats about all folks!

I strongly advise you to get familiar with ALL the information covered in this lesson; there's quite a lot of important stuff to digest - almost all of it important if you want to advance you're knowledge of DirectX8 graphics.


You can download the source code and see it working - as well as modifying it and playing around. Grab it from the top of this page....

Assuming you've swallowed all of this it's onto Lesson 05 : Basic 3D Geometry

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