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
66 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:

Contents
 Getting Started
 Setting Up
 Drawing & Texturing
 Wrapping Up

 Printable version
 Discuss this article
 in the forums


Transparency

As I said before, one easy way of adding transparency is to specify a color key value in the call to D3DXCreateTextureFromFileEx. Another is to use an image that actually has an alpha channel. Either way, specify a texture with some transparency (either with an alpha channel or a color key value) and run the app. You should see no difference. This is because alpha blending is not enabled. To enable alpha blending, add these lines to PostInitialize:

g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,  TRUE);
g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);

The first line enables blending. The next two specify how the blending works. There are many possibilities, but this is the most basic type. The last line sets things up so that changing the alpha component of the vertex colors will fade the entire panel by scaling the texture values. For a more in depth discussion of the available settings, see the SDK. Once these lines are in place, you should see the proper transparency. Try changing the colors of the vertices to see how they affect the panel.

Moving the Panel

By now our panel has many of the visual properties we need, but it's still stuck in the center of our viewport. For a game, you probably want things to move. One obvious way is to relock the vertices and change their positions. DO NOT do this!! Locking is very expensive, involves moving data around, and is unnecessary. A better way is to specify a world transformation matrix to move the points. For many people, matrices may seem a bit scary, but there are a host of D3DX functions that make matrices very easy. For example, to move the panel, add the following code to the beginning of Render2D:

D3DXMATRIX Position;
D3DXMatrixTranslation(&Position, 50.0f, 0.0f, 0.0f);
g_pd3dDevice->SetTransform(D3DTS_WORLD, &Position);

This creates a matrix that moves the panel 50 pixels in the X direction and tells the device to apply that transform. This could be wrapped into a function like MoveTo(X, Y), which I won't actually give the code for. Earlier I said to remember the fact that the vertex code specified the vertices around the origin. Because we did that, translating (moving) the position moves the center of the panel. If you are more comfortable with moving the upper left or some other corner, change the way the vertices are specified. You could also create different coordinate systems by correcting the parameters sent to the MoveTo function. For example, our viewport currently goes from -100 to +100. If I wanted to use MoveTo as if it were going from 0 to 200, I could simply correct for it in my call to D3DXMatrixTranslation by subtracting 100 from the X position. There are many ways to quickly change this to meet your specific needs, but this will provide a good basis for experimentation.

Other Matrix Operations

There are many other matrix operations that will affect the panel. Perhaps the most interesting are scaling and rotation. There are D3DX functions for creating these matrices as well. I'll leave the experimenting up to you, but here are a few hints. Rotation about the Z-axis will create rotation on the screen. Rotating about X and Y will look like you are shrinking Y and X. Also, the way you apply multiple operations is through multiplication and then sending the resulting matrix to the device:

D3DXMATRIX M = M1 * M2 * M3 * M4;
g_pd3dDevice->SetTransform(D3DTS_WORLD, &M);

But, remember that the product of matrix multiplication is dependent on the order of the operands. For instance, Rotation * Position will move the panel and then rotate it. Position * Rotation will cause an orbiting effect. If you string together several matrices and get unexpected results, look closely at the order.

As you become more comfortable, you may want to experiment with things like the texture matrix, which will allow you to transform the texture coordinates. You could also move the view matrix to affect your coordinate system. One thing to remember: locks are very costly, always look to things like matrices before locking your vertex buffers.

Wrapping Up

Looking at all the code listed here, this is really a long, drawn out way to do a blit, but the nice thing is that most of this can be wrapped into tidy functions or classes that make all this a one time cost for long term benefit. Please remember that this is presented in a very bare bones, unoptimized way. There are many ways to package this to get maximum benefit. This method should be the optimal way to create 2D applications on current and coming hardware and also will pay off in terms of the effects that you can implement very easily on top of it. This approach will also help you blend 2D with 3D because, aside from some matrices, the two are the same. The code was easily adapted from 2D work that I did in OpenGL, so you could even write abstract wrappers around the approach to support both APIs. My hope is that this will get people started using DX8 for 2D work. Perhaps in future articles I will talk about more tricks and effects.