Search Tips Advanced Search |
| Delphi Graphics and Game Programming Exposed with DirectX 7.0 by John Ayres Wordware Publishing, Inc. ISBN: 1556226373 Pub Date: 12/01/99
Search this book:
Previous | Table of Contents | Next
### Transparency Issues So far, the examples we’ve seen all demonstrate sprite animation against a solid black background. This may work for some games, but what if we wanted to have some sort of cool background graphic behind our sprites, like a starfield or perhaps a forest, mountains, or other type of setting? This not only makes the overall animation more visually stimulating, but it improves its believability and makes the overall gaming experience more realistic. To do this, we need to draw the frames of the sprite image using some technique for displaying the background through the parts of the sprite image that are supposed to be transparent. Figure 6-5 illustrates the difference between a sprite image being displayed with and without transparent pixels. Figure 6-5: Sprite transparency Implementing transparency such as this is another broad topic in graphics programming that’s been widely studied. There are probably hundreds, if not thousands, of methods to display a graphic with transparent areas. The trick is to do it as quickly as possible so it won’t negatively affect the performance of the game. We will examine a few of the most common techniques used to display graphics with transparent pixels. These will include DirectDraw color keying and direct pixel checking.
| Tip: You can potentially optimize your application by including several different methods for blitting graphics in the game engine. It is perfectly normal to have one blitting function for graphics with no transparency (i.e., tiled graphics such as floors, or textures), a separate general blitting function for sprites with transparent pixels, and then perhaps a highly optimized assembly blitter that’s used for displaying graphics when optimum speed is required. The point is that you do not have to use only one blitting technique for all graphics in your game engine; use many blitting techniques for optimization and greater application performance.
#### Color Keying Color keying is the DirectX way of implementing transparency. With color keying, you specify a color that will be transparent. When DirectDraw blits this graphic onto the background, any pixels whose color matches that of the color key will not be drawn to the destination. Thus, the background will “show through” those pixels, as if they were transparent. The effect is similar to a technique that film makers use called blue screen. In a blue screen effect, an actor stands in front of a solid blue background. Later, the film is combined with a background image, which shows through all of the blue areas. Blue, in this case, is considered the color key. Color keying is very easy to implement in DirectX. It’s supported by the HEL, so you know it will always work, and if supported by the hardware, it’s incredibly fast. The only drawback to color keying is in the fact that every pixel in your image that is the color of the color key will be transparent. Thus, that color cannot be used for anything opaque in the image. However, the loss of one useful color out of 256 is easy to live with. Figure 6-6: Color keying Under DirectX, there are actually two types of color keys: source and destination. In source color keying, the source image (the image to be copied) is the one containing the transparent pixels. When the source image is copied onto the destination image, the color keyed pixels in the source image are replaced by the pixels in the destination. With destination color keys, the destination image is the one containing the transparent pixels. When the source image is copied onto the destination image, the color keyed pixels in the destination are replaced by the pixels in the source. In our examples, we will cover only source color keying, as destination color keying is not supported by the HEL and requires hardware support. Setting a Color Key We specify a color key by calling the IDirectDrawSurface4’s SetColorKey method. SetColorKey is defined as:
    function SetColorKey (

    dwFlags: DWORD;                     // indicates the type of color key

    lpDDColorKey: PDDColorKey           // the transparent color(s)

    ): HResult;                         // returns a DirectX error code
The first parameter takes a flag that indicates the behavior of the color key. For our purposes, we’ll set this to DDCKEY_SRCBLT, indicating a source color key. The second parameter is a pointer to a TDDColorKey structure that defines the color or colors to be interpreted as transparent. The TDDColorKey record is defined as:
    TDDColorKey = packed record

      dwColorSpaceLowValue: DWORD;      // low boundary of color space

      dwColorSpaceHighValue: DWORD;     // high boundary of color space

    end;
The values of these fields are specified in the color format of the surface. Since we’re using 256-color (or palettized) surfaces, we simply indicate the index of the color that we wish to be transparent. This record structure allows us to define a range of colors that will be transparent. This is primarily useful when working with video data, as shadows and other slight variations in color due to digitizing the video result in a background that will be a range of colors as opposed to one single color. Game artwork should usually be drawn with only one transparent color, and for our purposes, we will define only one color as transparent by setting both record elements to the same value. In our examples, we’ll only set the color key of surfaces that contain source images to be blitted over a background, such as sprite images. For example, to set the color key of an arbitrary surface to palette index 0, we only need a few lines of code:
    var

      ColorKey: TDDColorKey;

    begin

      ColorKey.dwColorSpaceLowValue  := 0

      ColorKey.dwColorSpaceHighValue := 0

      DirectDrawSurface.SetColorKey(DDCKEY_SRCBLT, @ColorKey);

    end;
| Note: We have implemented a function in the DDUtil unit called DDSetColorKey that allows the developer to set the color key for a surface in one line of code. This function was translated from a similar function in the DirectX SDK. You simply pass in the surface and a color in the form of a TColor. The function uses a complex technique for matching the specified color to a format appropriate for the pixel format of the surface, so the function can be used for surfaces of any color depth.
Using Color Keys Now that we have our color key set up, we can extend the previous sprite example to display the sprite image over a background. After we load the sprite images, we set their color key as described above. Then, when we actually draw the sprite using the BltFast method, we specify the DDBLTFAST_SRCCOLORKEY in its dwTrans parameter to indicate that the source surface has a color key that should be taken into account during the blit. Additionally, we must also load the image to be used as our sprite background. Now, as discussed previously, during the animation cycle we must erase the last frame of the sprite animation. Instead of simply filling the entire surface with black as we did previously, this time we’ll draw the background image into the backbuffer. The background image will fill the entire backbuffer, and thus will erase the last frame of animation. Listing 6-3: Sprite transparency through color keying
    procedure TfrmDXAppMain.FormActivate(Sender: TObject);

    var

      .

      .

      .

      {the color key record}

      ColorKey: TDDColorKey;

    begin

      .

      .

      .

    {create a palette based on the sprite bitmap}

      FPalette := DDLoadPalette(FDirectDraw,

    ExtractFilePath(ParamStr(0))+‘SnakeFrames.bmp’);

      {attach the palette to the primary surface so that it takes effect}

      DXCheck( FPrimarySurface.SetPalette(FPalette) );

      {load in the bitmap containing the background and sprite images}

      FImages := DDLoadBitmap(FDirectDraw, ExtractFilePath(ParamStr(0))+

                              ‘SnakeFrames.bmp’);

      {load the background bitmap}

      FBackground := DDLoadBitmap(FDirectDraw, ExtractFilePath(ParamStr(0))+

                                  ‘Background.bmp’);

      {initialize the color key record...}

      ColorKey.dwColorSpaceLowValue  := 0;

      ColorKey.dwColorSpaceHighValue := 0;

      {...and set the source color key}

      FImages.SetColorKey(DDCKEY_SRCBLT, @ColorKey);

      {initialize the sprite object}

      FSprite := TSprite.Create;

      FSprite.FXPos := DXWIDTH - 90;

      FSprite.FYPos := 215;

      FSprite.FXVel  := -1;

      FSprite.FYVel  := 0;

      FSprite.FCurFrame := 0;

      FSprite.FFrameNum := 5;

      FSprite.FImages := FImages;

      .

      .

      .

    end;

    procedure TfrmDXAppMain.DrawSurfaces;

    var

      SourceRect: TRect

    begin

      {erase the last frame of animation}

      SourceRect := Rect(0, 0, DXWIDTH, DXHEIGHT);

      FBackBuffer.BltFast(0, 0, FBackground, SourceRect,

                          DDBLTFAST_NOCOLORKEY OR DDBLTFAST_WAIT);

      {increment the frame number and update the sprite’s position}

      with FSprite do

      begin

        Inc(FCurFrame);

        {rollover the frame number as necessary}

        if FCurFrame > FFrameNum then

          FCurFrame := 0;

        {add the velocities to the positions. our sprite will only move

         horizontally, so we do not need to bother with the vertical values}

        FXPos := FXPos + FXVel;

        {see if the sprite is moving offscreen, and adjust

         its position accordingly}

        if FXPos < 0 then

          FXPos := DXWIDTH - 90;

        {blit the current frame, taking into account a source color key}

        SourceRect := Rect(FCurFrame*90, 0, (FCurFrame*90)+90, 49);

        FBackBuffer.BltFast(FXPos, FYPos, FImages, SourceRect,

                            DDBLTFAST_SRCCOLORKEY OR DDBLTFAST_WAIT);

      end;

    end;
Previous | Table of Contents | Next

Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.