In the last lesson we drew a simple sprite. However, if you did the exercises,
you would have found that this was quite limited a tool. In this lesson we
will look into additional things we can do with sprites to make them more usable
in a game display.
More specifically, we will learn how to do transparency with textures, in addition to making semi-transparent sprites for
cool display effects.
In case you haven't studied color-keys before, a color-key is a single color in
a texture which always appears invisible (a.k.a. doesn't actually appear at all).
In short, it eliminates the annoying black border around the images drawn.
If you think back to the Direct3D Basics Tutorial, you might recall
advanced texture
handling. The first of these lessons (Lesson 12) covers the color-key in textures
applied to 3D objects. However, sprites also use textures, and if you load
a texture with a color-key, and apply it to a sprite,
the same effect results!
I will not re-cover the function here. If you wish to review it, look at Lesson
12 in the Direct3D Basics Tutorial, which covers color-keys specifically, or look
in the documentation at D3DXCreateTextureFromFileEx() for the full function description.
However, there is another element which I have not covered yet, but which is quite
simple. Remember this?
d3dspt->Begin(NULL); // begin sprite drawing
This is the function called when you are ready to draw sprites. However, to
use color-keys, we need to add a flag into that single parameter. The flag
we will use is D3DXSPRITE_ALPHABLEND, making the command look like this:
d3dspt->Begin(D3DXSPRITE_ALPHABLEND); // begin sprite drawing with
transparency
Adding this flag allows us to draw sprites both with color-keys and with semi-transpancy.
Instead of explaining everything about color-keys all over again, I am simply going to show you an
example of using color-keys with sprites. We will take the finished program
form the last lesson and allow the image to use a color-key.
The image in the last lesson's program would have looked like this if we had given it a colored
background:

Image 2.1 - Panel1.png Displayed Against a Colored Background
This just won't do. To load the texture with a color-key, we have to do this:
D3DXCreateTextureFromFileEx(d3ddev, // the device pointer
L"Panel2.png", // the new file name
D3DX_DEFAULT, // default width
D3DX_DEFAULT, // default height
D3DX_DEFAULT, // no mip mapping
NULL, // regular usage
D3DFMT_A8R8G8B8, // 32-bit pixels with alpha
D3DPOOL_MANAGED, // typical memory handling
D3DX_DEFAULT, // no filtering
D3DX_DEFAULT, // no mip filtering
D3DCOLOR_XRGB(255, 0, 255), // the hot-pink color key
NULL, // no image info struct
NULL, // not using 256 colors
&sprite); // load to sprite
If we use the D3DXSPRITE_ALPHABLEND flag and replace the D3DXCreateTextureFromFile() function with this code, we will instead
get this result:

Image 2.2 - Panel2.png Displayed with Alpha
Well, at least that looks mildly appropriate for a game. Let's make it even better!
If you look at the DirectXTutorial layout from an artistic viewpoint you can imagine
that it is probably supposed to be semi-transparent, meaning that if an object were to appear behind
it, it would still be somewhat visible, like this:

Image 2.3 - DirectX vs DirectXTutorial
This is a very powerful effect, and is key in making a good game display.
The way to create this effect is extraordinarily simple. All we need to do
is include alpha into the function Draw(), like this:
d3dspt->Draw(sprite, NULL, ¢er, &position, D3DCOLOR_ARGB(127,
255, 255, 255));
This makes the sprite appear 50% blended with the background. If we did this,
the image would be shown like this:

Image 2.4 - The Panel Drawn with Semi-Transparency
Let's take the last lesson's program and make the image appear semi-transparent
and eliminate the black border. Then let's look at how it might be if the
background color changed continuously.
[
Show Code]
// include the basic windows header files and the Direct3D header file
#include <windows.h>
#include <windowsx.h>
#include <d3d9.h>
#include <d3dx9.h>
// define the screen resolution and keyboard macros
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEY_UP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)
// include the Direct3D Library file
#pragma comment (lib, "d3d9.lib")
#pragma comment (lib, "d3dx9.lib")
// global declarations
LPDIRECT3D9 d3d; // the pointer to our Direct3D interface
LPDIRECT3DDEVICE9 d3ddev; // the pointer to the device class
LPD3DXSPRITE d3dspt; // the pointer to our Direct3D Sprite interface
// sprite declarations
LPDIRECT3DTEXTURE9 sprite; // the pointer to the sprite
// function prototypes
void initD3D(HWND hWnd); // sets up and initializes Direct3D
void render_frame(void); // renders a single frame
void cleanD3D(void); // closes Direct3D and releases memory
// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
HWND hWnd;
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = L"WindowClass";
RegisterClassEx(&wc);
hWnd = CreateWindowEx(NULL, L"WindowClass", L"Our Direct3D Program",
WS_EX_TOPMOST | WS_POPUP, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT,
NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow);
// set up and initialize Direct3D
initD3D(hWnd);
// enter the main loop:
MSG msg;
while(TRUE)
{
DWORD starting_point = GetTickCount();
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
render_frame();
// check the 'escape' key
if(KEY_DOWN(VK_ESCAPE))
PostMessage(hWnd, WM_DESTROY, 0, 0);
while ((GetTickCount() - starting_point) < 25);
}
// clean up DirectX and COM
cleanD3D();
return msg.wParam;
}
// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
} break;
}
return DefWindowProc (hWnd, message, wParam, lParam);
}
// this function initializes and prepares Direct3D for use
void initD3D(HWND hWnd)
{
d3d = Direct3DCreate9(D3D_SDK_VERSION);
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = FALSE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hWnd;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferWidth = SCREEN_WIDTH;
d3dpp.BackBufferHeight = SCREEN_HEIGHT;
// create a device class using this information and the info from
the d3dpp stuct
d3d->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp,
&d3ddev);
D3DXCreateSprite(d3ddev, &d3dspt); // create
the Direct3D Sprite object
D3DXCreateTextureFromFileEx(d3ddev, // the device
pointer
L"Panel2.png", // the new file name
D3DX_DEFAULT, // default width
D3DX_DEFAULT, // default height
D3DX_DEFAULT, // no mip mapping
NULL, // regular usage
D3DFMT_A8R8G8B8, // 32-bit pixels with
alpha
D3DPOOL_MANAGED, // typical memory handling
D3DX_DEFAULT, // no filtering
D3DX_DEFAULT, // no mip filtering
D3DCOLOR_XRGB(255, 0, 255), // the hot-pink
color key
NULL, // no image info struct
NULL, // not using 256 colors
&sprite); // load to sprite
return;
}
// this is the function used to render a single frame
void render_frame(void)
{
// clear the window to a bright red
d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(255, 0, 0),
1.0f, 0);
d3ddev->BeginScene(); // begins the 3D scene
d3dspt->Begin(D3DXSPRITE_ALPHABLEND);
// // begin sprite drawing with transparency
// draw the sprite
D3DXVECTOR3 center(0.0f, 0.0f, 0.0f); // center at the
upper-left corner
D3DXVECTOR3 position(50.0f, 50.0f, 0.0f); // position
at 50, 50 with no depth
d3dspt->Draw(sprite, NULL, ¢er, &position, D3DCOLOR_ARGB(127,
255, 255, 255));
d3dspt->End(); // end sprite drawing
d3ddev->EndScene(); // ends the 3D scene
d3ddev->Present(NULL, NULL, NULL, NULL);
return;
}
// this is the function that cleans up Direct3D and COM
void cleanD3D(void)
{
sprite->Release();
d3ddev->Release();
d3d->Release();
return;
}
For this example you will need the new version of the Panel, called "Panel2.png".
The only difference is that the background is hot pink. If you really can't
stand this color, then just change the image and the code to have a different color-key.
If you add the new image and run the code, you will get something like this:

Image 2.5 - Panel2.png Displayed With Transparency
Now we are starting to get somewhere with sprites. However, even this isn't
all there is to it. These two techniques are vital necessities for creating
good game displays, and you should become well-practiced with them. As usual,
I recommend doing these exercises before moving on:
1. If you know how, create a 3D model and draw it behind Panel2.
2. Change the semi-transparency to 75% transparent. Now 45%.
3. Make the blue border fully opaque, but leave the rest transparent
(Hint:
make it into two sprites).
Up next, we have an exciting lesson.
Next Lesson: Animation
GO! GO! GO!
© 2006-2009 DirectXTutorial.com. All Rights Reserved.