Transparent GDI Sprite Library

Use basic Windows GDI functions to draw fast-moving transparent sprites

Blob ScreenSaver Demonstration

This VB library aims to make it simple to add fast, animated graphics using transparent sprites, something which is either missing or dismally slow using VB's standard methods. The source code provides a complete screen saver, and a simpler (and somewhat smaller) sample which animates a large number of asteroids around a non-firing, invunerable spaceship. These demonstrate how the sprite library can be quickly incorporated into an application.

Transparent bitmaps are not only used for games or screen savers; Windows uses them extensively for icons and also the ImageList common control has built in functions specifically for creating transparent bitmaps.

Drawing Bitmaps Transparently

There are three methods to draw a bitmap transparently. The first is to write custom drawing code which loops through all the bits in the bitmap and only draws pixels which aren't the background colour of the bitmap. The second is to use the TransparentBlt API call added to Windows 98/2000 and later operating systems. Both of these methods are fine, but if you need code which runs under every OS then another technique is needed.

The third method is to take advantage of the API BitBlt method. The grunt of BitBlt is implemented in the graphics card driver and is usually extremely quick (even under Windows 95). To make use of it to draw transparently, we need to process the bitmap to create what are know as the Sprite and the Mask bitmaps to draw with.

Creating Sprites and Masks

To create a sprite and a mask you need to do three things:

  1. Choose a colour in the bitmap you want to be transparent.
  2. Create a monochrome bitmap which is black where the bitmap should be transparent and white otherwise (this is called the mask).
  3. Change the bitmap colour to white in the transparent area (this becomes the sprite).

Having done this, the bitmap can be drawn transparently in two BitBlt operations:

  1. OR the Mask bitmap with the background.
    This sets the background pixels to white where the sprite should be drawn (where the mask is white) but leaves them unaffected otherwise. (since 0 or 0 = 0, 1 or 0 = 1, 0 or 1 = 1, 1 or 1= 1).
  2. AND the Sprite bitmap over the area you've just ORed the mask into.
    Where the Sprite is white (the transparent area) there is no effect - it leaves the background pixels unaffected, but where the background has been coloured white by the mask the bitmap itself is drawn. (since 0 and 0 = 0, 1 and 0 = 0, 0 and 1 = 1, 1 and 1 = 1)

Thus the bitmap can be drawn transparently. The following series of pictures shows the process in detail:

Creating Sprite and Mask from the Bitmap

Creating the Sprite and Mask from a bitmap

ORing the Mask onto the Background

ORing the Mask onto the background

ANDing the Sprite to get the Transparency Effect

ANDing the Sprite onto the prepared background

That demonstrates the way to achieve transparent sprites, but you can do more if you want truly flicker-free drawing.

Achieving Flicker-Free Animation

When moving sprites, it becomes necessary to redraw the previous background under the sprite before moving it to its new position (unless you want to obtain a trail effect). This makes flicker a problem - generally you have to draw an area where the new sprite will be with the background and then draw the sprite in its new position over the top. This almost always results in flickering.

To prevent this occuring, you can create a buffer (normally called a Stage) to make all the changes in, maintaining the screen with the sprite in place for as long as possible. When it comes to redrawing the sprite in its new position, you can then make a minimum of calls to transfer the new position and erase the old position simultaneously. You don't get any flicker this way because all the updates you do are draw an image in which the new sprite is in place.

The code loop for this type of animation with my sprite library is always as follows:

  1. Restore the background behind the sprite into the stage.
  2. Move the sprite to its new position, and store the background behind the sprite. The stored background can be used to restore the background next time round the loop.
  3. Draw the sprite in its new position on the stage using the transparent draw method.
  4. Finally, copy the old and the new sprite positions from the stage to the screen. Here if the old sprite position is close to the new sprite position, we can minimise the amount of drawing by drawing both at the same time.

The loop is shown pictorially below:

Initial Position

Initial Position

Restore the background behind the sprites into the stage

This step is repeating for all other sprites in the scene:

Restoring Background

Move the sprite to its new position in the stage

At this point the previous background area behind the sprite is stored so it can be restored next time round the loop. Note the background could be modified at this point if we wanted, provided you remember which rectangles have been updated so they can be copied in at the last point in the loop.

Moving the Sprite Position

Draw The Sprite Transparently

Repeat for all sprites in the screen onto the stage:

Drawing Sprites Onto Stage

Finally, Copy All Changes to the Screen

Ideally you can minimise the number of changes which need to be drawn. In this case the changed sprite and the background can be drawn together:

Copying Changes onto the screen

Check it Out

That's the principle of the sprite library. The code shows how to achieve all the above effects using GDI calls. The mask creation routine in the code is quite neat and can easily be pulled out and used elsewhere. This technique makes mask creation very quick: to do it, you first create a monochrome DC (using CreateCompatibleDC with a hDC of 0) and then select a monochrome bitmap into it. Use SetBkColor to set the back 'colour' of the monochrome DC to the colour you want to be the mask colour, and then when you BitBlt any bitmap into it, Windows automatically maps all pixels of this colour to black. You just need to invert it to get the mask.

To Install BlobSaver

If you want to try BlobSaver as a screen saver, just copy BlobSaver.scr, all the associated gif files and backdrop.jpg into your Windows directory. You can modify the images used to display the backdrop, or the sprite images with your own files by editing the registry entries which the screen saver creates under

   HKEY_CURRENT_USER\Software\vbaccelerator\Blob Saver

The sprite files should split into 7x5 images to display correctly.