Graphics Programming using Allegro

Double Buffering, Painting a Frame with Color

Published:  September 4, 2008
by Richard G. Baldwin

File:  Allegro00135


Preface

General

This lesson is part of a series (see Resources) designed to teach you how to use Allegro to do graphics programming in C++.  My purpose in writing the series is to provide lecture and lab material for a course titled Game Development Using C++ that I teach at Austin Community College in Austin, Texas.  However, if you have stumbled upon this series and you find it useful, you are welcome to study it.

Viewing tip

I recommend that you open another copy of this document in a separate browser window and use the following links to easily find and view the figures and listings while you are reading about them.

Figures

Listings

Supplemental material

I recommend that you also study the other lessons in my extensive collection of online programming tutorials.  You will find a consolidated index at www.DickBaldwin.com.

Preview

In this lesson, (as in the previous lesson number 130, see Resources), I will show you how to control the color of each individual pixel in an image, producing visual effects such as that shown in Figure 1 where every pixel is a different color.

Figure 1. Screen output for PutPixel02.

Very slow execution speed

The execution of the program named PutPixel01 in the previous lesson was very slow because the program code drew the colored pixels directly onto the computer screen.  For most computers, you could see the change in the color of the pixels progress down the image from top to bottom when you ran the program.

Use of an off-screen buffer

In this lesson, I will show you how to use an off-screen bitmap buffer to dramatically improve the speed of the program.  In particular, the drawing will be performed on an off-screen bitmap buffer in memory.  Then a function named blit will be called to copy the image from the buffer to the screen very quickly.  This technique will be used for most of the programs that produce screen graphics in future lessons in this series.

Discussion and sample code

This is an update to the program named PutPixel01 from the previous lesson number 130 titled Controlling Individual Pixels, Painting a Frame with Color (see Resources).

This program illustrates a very powerful technique for writing program code to control the color of each pixel in an onscreen image.

An off-screen bitmap buffer

An off-screen bitmap buffer with dimensions of 256x256 is created in memory.  Nested for loops are used to set the color values for each pixel in the buffer.

An onscreen graphics window with dimensions of 256x256 is also created.  Once the color values for all of the pixels in the off-screen bitmap buffer have been set, the blit function is called to copy the contents of the bitmap buffer to the onscreen window.

A dramatic improvement in speed

The use of this process causes the onscreen image to be painted very rapidly, even with the maximum color depth of 32.  The color produced by the code in the nested for loops is displayed in the onscreen window almost as soon as the program is started. Unlike the program in the previous lesson, there is no visible delay while waiting for the onscreen image to be painted.

Press any key...

Pressing any key causes the program to terminate.

Beginning of the program

As is my custom, I will explain this program in fragments.  You can view a complete listing of the program in Listing 6 near the end of the lesson.

The program begins in Listing 1.

Listing 1. Beginning of the program named PutPixel02.
#include <allegro.h>

int main(){
  allegro_init();//Allegro initialization
  install_keyboard();//Set up for keyboard input
  //Need to set the color depth before setting the
  // graphics mode.
  set_color_depth(32);
  //Set the graphics mode to a 256x256-pixel window.
  set_gfx_mode(GFX_AUTODETECT_WINDOWED,256,256,0,0);

Creation of an off-screen bitmap buffer

Listing 2 begins by declaring a pointer variable named buffer capable of pointing to a BITMAP.

Listing 2. Creation of an off-screen bitmap buffer.
  BITMAP *buffer = NULL;

  buffer = create_bitmap(256,256);

Then Listing 2 calls the create_bitmap function to create a bitmap in memory with dimensions of 256x256.  The documentation for the create_bitmappoints out:

"The image memory will not be cleared, so it will probably contain garbage: you should clear the bitmap before using it.";

Set pixel colors in the off-screen bitmap

Listing 3 uses a pair of nested for loops to cycle through the rows and columns of pixels in the off-screen bitmap setting the color values for each individual pixel.

Listing 3. Set pixel colors in the off-screen bitmap.
  for(int row = 0;row < 255;row++){
    for(int column = 0;column < 255;column++){
      putpixel(buffer,column,row,makecol(column,row,128));
    }//end loop row
  }//end loop on column

Similar to code in the previous lesson

This code is similar to code in the program in the previous lesson.  However, there is one major difference.  When the putpixel function was called in the previous lesson, the pointer named screen was passed as the first parameter.  This caused the new pixel color values to be written directly in the onscreen bitmap image.

A significant improvement in speed

Listing 3 also calls the putpixel function inside the inner loop.  However, in this case, the pointer named buffer is passed as the first parameter in place of the pointer named screen.  This causes the new pixel color values to be written into the off-screen bitmap buffer instead of writing them directly onto the screen.

Writing to memory is much faster...

Writing to memory is much faster than writing to the screen.  The thousands of calls to the putpixel function in Listing 3 execute very quickly, allowing the outer loop in Listing 3 to terminate very quickly.  This largely explains the significant improvement in speed provided by this program relative to the program in the previous lesson.

Copy the off-screen bitmap buffer to the screen

Listing 4 calls the blit function to copy the contents of the off-screen bitmap buffer to the screen.

Listing 4. Copy the off-screen bitmap buffer to the screen.
  blit(buffer,screen,0,0,0,0,256,256);

Copy a rectangular area of pixels between bitmaps

The blit function copies a rectangular area from a source bitmap to a destination bitmap.  The call to the blit function in Listing 4 copies the entire off-screen (source) bitmap to the screen (destination) bitmap, but that isn't necessary.  A rectangular portion of a source bitmap can be copied to an arbitrary location in a destination bitmap and both bitmaps can be stored in off-screen memory buffers.

The third and fourth parameters in the call to blit in Listing 4 specify the coordinates of the upper-left corner of the rectangle in the source bitmap that will be copied to the destination bitmap.  The fifth and sixth parameters specify the coordinates of the upper-left corner in the destination bitmap to which the rectangle of pixel values will be copied.  The last two parameters specify the width and height of the rectangle in pixels.

Speed considerations

The documentation for the blit function discusses speed issues in detail, but in virtually all cases, producing an off-screen image and calling the blit function to copy the image onto the screen will be significantly faster than constructing the image directly on the screen one pixel at a time.

Destroying the off-screen bitmap buffer

With one exception, the code in Listing 5 is the same as corresponding code in the program in the previous lesson.  That exception is the call to the destroy_bitmap function in Listing 5.

Listing 5. Destroying the off-screen bitmap buffer.
  //Block and wait until the user presses a key.
  readkey();
  //Destroy bitmap to avoid memory leaks.
  destroy_bitmap(buffer);

  return 0;//Return 0 to indicate a successful run....
}//end main function
END_OF_MAIN

To make a long story short, the call to destroy_bitmap frees the memory currently occupied by the bitmap in memory, making that memory available for other uses.

Memory leaks

I have seen several documents on the web that say you should always call the destroy_bitmap function for every memory bitmap that you create to avoid memory leaks.  I have long believed (perhaps erroneously) that all of the memory used by a program is returned to the operating system when the program terminates.  If so, the call to destroy_bitmap in Listing 5 is overkill, because the call is made immediately before the program terminates.  However, I decided to err on the side of caution and make the call to destroy_bitmap anyway.

Each memory bitmap created by a program can consume a large amount of memory.  If a program creates and uses multiple memory bitmaps during its execution, it is probably a very good idea to destroy each bitmap when it is no longer needed.  Otherwise, the program may run out of memory during its execution, particularly if a large number of large bitmaps are used.

The end of the program

Listing 5 signals the end of the program.  When the user presses any key, the memory bitmap will be destroyed, the main function will return, and the program will terminate.

Summary

In this program, I showed you how to use an off-screen bitmap buffer to significantly improve the speed of manipulating and displaying bitmap images.  This technique is very powerful and will be used for most of the programs that produce screen graphics in future lessons in this series.

Complete program listing

A complete listing of the program discussed in this lesson is shown in Listing 6.

Listing 6. Source code for PutPixel02.
/*Project PutPixel02
This is an upgrade of the project named PutPixel01.

The purpose of this project is to illustrate a relatively
advanced approach to writing code to control the color of
each pixel on the screen.

An off-screen bitmap buffer with dimensions of 256x256 is
created.  Nested for loops are used to set the value of
each pixel in the buffer.  The color ranges from mid-
intensity blue in the upper left corner to yellow in the
lower right corner.

An onscreen window with dimensions of 256x256 is also
created.

The color of each pixel in the buffer is set. Then the
blit function is called to copy the contents of the
buffer to the onscreen window. As a result, the entire
program runs very rapidly, even with a color depth of 32.
The color produced by the code in the nested for loops is
displayed in the onscreen window as soon as that window
appears on the screen. There is no visible delay waiting
for the onscreen window to be painted.

Pressing any key causes the program to terminate.
*/
#include <allegro.h>

int main(){
  allegro_init();//Allegro initialization
  install_keyboard();//Set up for keyboard input
  //Need to set the color depth before setting the
  // graphics mode.
  set_color_depth(32);
  //Set the graphics mode to a 256x256-pixel window.
  set_gfx_mode(GFX_AUTODETECT_WINDOWED,256,256,0,0);
  
  //Declare a pointer variable named buffer that can be
  // used to point to a BITMAP.
  BITMAP *buffer = NULL;
  //Create an empty bitmap and store its address in buffer
  buffer = create_bitmap(256,256);
  
  //Cycle through the buffer bitmap setting the color of
  // each pixel individually.
  for(int row = 0;row < 255;row++){
    for(int column = 0;column < 255;column++){
      putpixel(buffer,column,row,makecol(column,row,128));
    }//end loop row
  }//end loop on column
  
  //Call the blit function to copy the off-screen buffer
  // contents to the screen.
  blit(buffer, screen, 0,0,0,0,256,256);
  
  //Block and wait until the user presses a key.
  readkey();

  //Destroy bitmap to avoid memory leaks.
  destroy_bitmap(buffer);

  return 0;//Return 0 to indicate a successful run.
}//end main function
END_OF_MAIN()

 

Resources


Copyright

Copyright 2008, Richard G. Baldwin.  Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.

About the author

Richard Baldwin is a college professor (at Austin Community College in Austin, TX) and private consultant whose primary focus is a combination of Java, C#, and XML. In addition to the many platform and/or language independent benefits of Java and C# applications, he believes that a combination of Java, C#, and XML will become the primary driving force in the delivery of structured information on the Web.

Richard has participated in numerous consulting projects and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas.  He is the author of Baldwin's Programming Tutorials, which have gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.

In addition to his programming expertise, Richard has many years of practical experience in Digital Signal Processing (DSP).  His first job after he earned his Bachelor's degree was doing DSP in the Seismic Research Department of Texas Instruments.  (TI is still a world leader in DSP.)  In the following years, he applied his programming and DSP expertise to other interesting areas including sonar and underwater acoustics.

Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.

Baldwin@DickBaldwin.com

-end-