Graphics Programming using Allegro

Drawing Primitives

Published:  August 23, 2008
Revised:  August 29, 2008
by Richard G. Baldwin

File:  Allegro00120


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

Allegro provides a large library of functions for drawing primitives such as lines, circles, triangles, fills, etc.  (See Resources.)

In this lesson, I will teach you how to use the following functions from that library to draw the primitives shown in Figure 1.

Figure 1. Screen output from DrawingPrimitives01.

Discussion and sample code

As usual, I will explain this program in fragments.  A complete listing of the program is provided in Listing 10 near the end of the lesson.

The fragment in Listing 1 shows the beginning of the program including material that you have learned about in earlier lessons.

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

int main(){
  //Do the preliminaries.
  allegro_init();
  install_keyboard();

  set_gfx_mode(GFX_AUTODETECT_WINDOWED,400,400,0,0);

Not all dimensions are possible

Listing 1 calls the set_gfx_mode function passing the mode parameter that produces the 400x400-pixel window shown in Figure 1.

When I discussed this function in earlier lessons, I failed to inform you that it is not possible to create windows for all combinations of width and height.  Some values for width and height result in runtime errors.

Unfortunately, I'm not certain how to determine which dimensions are allowable and which dimensions are not allowable short of experimentation.  Also, I'm not certain that if you find an allowable set of dimensions on one computer that it will be allowable on all computers.

Experimental results

The laptop computer that I am currently using has a screen with a maximum resolution of 1440x900 pixels.  Experimentation indicates that any horizontal dimension that is evenly divisible by four up to 1440 pixels is allowable.  I suspect that the requirement for the horizontal dimension to be divisible by four has something to do with how the data bytes are packed in memory.

Experimentation also indicates that any vertical dimension up to about 880 is allowable on my machine.  There doesn't appear to be a divisible by four requirement for the vertical dimension.  I suspect that the fact that the window has a wide border at the top (see Figure 1) is the thing that causes the limit on the vertical dimension to be less than 900.  The overall size of the window is larger than the specified dimensions which apply to the gray area in Figure 1.  This is particularly true with respect to the vertical dimension.

Set the background color of the window to light gray

Listing 2 calls the clear_to_color function to set the background color of the window to light gray.

Listing 2. Set the background color of the window to light gray.
  clear_to_color(screen,makecol(224,224,224));

The clear_to_color function is straightforward.  The first parameter is a pointer to the bitmap for which the color of all the pixels is to be set.  In this case, that pointer is contained in a global variable named screen in the header file that is included in Listing 1.

The second parameter is an RGB color value of type int.  This value is produced in Listing 2 by calling the makecol function passing the individual red, green, and blue values.  The makecol function combines those values and returns a single integer that represents the mixture of the three colors at the specified intensity levels.

Draw three parallel lines of pixels

Listing 3 uses a for loop and calls the putpixel function three times in succession to draw three parallel lines of red, green, and blue pixels from the bottom left to the top right of the window.

Listing 3. Draw three parallel lines of pixels.
  for(int cnt = 0;cnt < 400;cnt += 3){
    putpixel(screen,cnt,400-cnt,makecol(255,0,0));;
    putpixel(screen,cnt-1,400-cnt-1,makecol(0,255,0));
    putpixel(screen,cnt+1,400-cnt+1,makecol(0,0,255));
  }//end for loop

Only every third pixel is drawn along each line leaving the pixels in between their original color.

Image quality

I am currently running Windows Vista Home Premium edition on an HP laptop computer with a Hyundai monitor attached as a second display device.  The desktop is extended from the laptop onto the Hyundai.  Both displays are set to a resolution of 1440x900 pixels.

The parallel lines of pixels look very distorted when I display Figure 1 on the laptop.  This is particularly in the violet areas.  The lines of pixels look much better when I display them on the Hyundai monitor.  However, the original image that was converted to a jpeg image for Figure 1 looks good on both monitors.  You normally expect to lose some image quality when a bitmapped image is converted to a compressed jpeg format and that seems somehow to be the source of the distortion.  However, I am unable to explain why the distortion is more apparent on the HP screen than on the Hyundai screen.

Draw two concentric red circles

Listing 4 calls the circle function twice in succession to draw two concentric circles that are centered on the center of the window.

Listing 4. Draw two concentric red circles.
  //Inscribe a large red circle in the window.
  circle(screen,200,200,200,makecol(255,0,0));
  
  //Draw another red circle inside of that one.
  circle(screen,200,200,190,makecol(255,0,0));

The circle function requires a pointer to the bitmap followed by the x and y coordinates of the circle.  This is followed by the radius of the circle and the color of the circle.  As you can see from Listing 4, the two circles were drawn with a difference of ten pixels in their respective radii, leaving a gap between the two.

Fill the gap between the two circles with blue

Listing 5 calls the floodfill function to fill the gap between the circles with blue color, leaving the red lines that represent the circles still showing.

Listing 5.  Fill the gap between the two circles with blue.
  floodfill(screen,5,200,makecol(0,0,255));

This function requires a pointer to the bitmap, followed by the x and y coordinates of a point, followed by a color.  The behavior of the function is similar to the behavior of similar features in paint programs, filling the entire area around the point but inside a closed contour with the specified color.  However, the documentation isn't very specific regarding exactly how that area is determined.

Draw a filled circle, a rectangle, and a filled rectangle

Listing 6 draws the green filled circle on the left side of Figure 1.  Then it draws the blue rectangle at the top of Figure 1 followed by the turquoise filled rectangle at the bottom of Figure 1.  (The original gray background shows through the blue rectangle at the top of Figure 1.)

Listing 6. Draw a filled circle, a rectangle, and a filled rectangle.
  //Draw a green filled circle.
  circlefill(screen,100,200,50,makecol(0,255,0));

  //Draw an empty blue rectangle.
  rect(screen,150,75,250,125,makecol(0,0,255));
  
  //Draw a filled rectangle where the color is turquoise
  rectfill(screen,175,250,225,350,makecol(0,255,255));

You should have no difficulty understanding any of these functions, particularly if you take a look at the documentation for drawing primitives.  The coordinate values that are specified for the rectangle and the filled rectangle specify two opposite corners of the rectangle and the sides of the rectangle must be horizontal and vertical.

Draw black horizontal and vertical lines

Listing 7 calls the line function twice in succession to draw black horizontal and vertical lines that divide the window into four quadrants of equal size.

Listing 7. Draw black horizontal and vertical lines.
  line(screen,0,200,400,200,makecol(0,0,0));
  line(screen,200,0,200,400,makecol(0,0,0));

Listing 8 calls the floodfill function four times in succession to fill portions of the four quadrants with yellow and violet color.

Listing 8. Fill the quadrants with yellow and violet color.
  //Fill two of the quadrants with yellow.
  floodfill(screen,100,100,makecol(255,255,0));
  floodfill(screen,300,300,makecol(255,255,0));
  
  //Fill the other two quadrants with violet. //Must be
  // careful to avoid the lines of pixels when specifying
  // the point around which to fill.
  floodfill(screen,90,300,makecol(255,0,255));
  floodfill(screen,300,90,makecol(255,0,255));

By now you should be able to understand this code with no further explanation.

Draw a blue filled triangle, then terminate

Listing 9 calls the triangle function to draw the filled blue triangle on the right in Figure 1.

Listing 9. Draw a blue filled triangle, then terminate.
  triangle(screen,280,180,
                  320,180,
                  300,220,makecol(0,0,255));

  //Block and wait for the user to press any key.
  readkey();

  return 0;
}//end main function
END_OF_MAIN();

Block and wait for user input

The remaining code in Listing 9 blocks and waits for the user to press a key, at which time the program terminates.  You have seen code like this before.

Summary

Allegro provides a large library of functions for drawing primitives such as lines, circles, triangles, fills, etc.  (See Resources.)

In this lesson, I taught you how to use the following functions to draw the primitives shown in Figure 1.

Complete program listing

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

Listing 10. Source code for the project named DrawingPrimitives01.
//Project DrawingPrimitives01
//Draws a variety of shapes, lines, fills, etc., on a
// window.
//See Drawing Primitives at
//http://www.allegro.cc/manual/api/drawing-primitives/
#include <allegro.h>

int main(){
  //Do the preliminaries.
  allegro_init();
  install_keyboard();

  //Set the graphics mode to a window.
  //Note that not all possible combinations of width
  // and height can be used successfully in windowed
  // mode. I'm not certain how to determine which are
  // and which are not allowable short of
  // experimentation.
  set_gfx_mode(GFX_AUTODETECT_WINDOWED,400,400,0,0);

  //Set the background color of the window to light gray
  clear_to_color(screen,makecol(224,224,224));

  //Draw three lines of red, green, and blue pixels from
  // the lower left to the upper right of the window.
  for(int cnt = 0;cnt < 400;cnt += 3){
    putpixel(screen,cnt,400-cnt,makecol(255,0,0));
    putpixel(screen,cnt-1,400-cnt-1,makecol(0,255,0));
    putpixel(screen,cnt+1,400-cnt+1,makecol(0,0,255));
  }//end for loop
  
  //Inscribe a large red circle in the window.
  circle(screen,200,200,200,makecol(255,0,0));
  
  //Draw another red circle inside of that one.
  circle(screen,200,200,190,makecol(255,0,0));
  
  //Fill the area between the two circles with blue.
  floodfill(screen,5,200,makecol(0,0,255));
  
  //Draw a green filled circle.
  circlefill(screen,100,200,50,makecol(0,255,0));

  //Draw an empty blue rectangle.
  rect(screen,150,75,250,125,makecol(0,0,255));
  
  //Draw a filled rectangle where the color is turquoise
  rectfill(screen,175,250,225,350,makecol(0,255,255));

  //Draw black horizontal and vertical lines that
  // divide the window into quadrants of equal size.
  line(screen,0,200,400,200,makecol(0,0,0));
  line(screen,200,0,200,400,makecol(0,0,0));
  
  //Fill two of the quadrants with yellow.
  floodfill(screen,100,100,makecol(255,255,0));
  floodfill(screen,300,300,makecol(255,255,0));
  
  //Fill the other two quadrants with violet. //Must be
  // careful to avoid the lines of pixels when specifying
  // the point around which to fill.
  floodfill(screen,90,300,makecol(255,0,255));
  floodfill(screen,300,90,makecol(255,0,255));

  //Draw a blue filled triangle.
  triangle(screen,280,180,
                  320,180,
                  300,220,makecol(0,0,255));

  //Block and wait for the user to press any key.
  readkey();

  return 0;
}//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-