Published: September 17, 2008
by Richard G. Baldwin
File: Allegro00155
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.
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.
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.
This program shows how to write code that will respond when the user presses either the left or right mouse button while pointing to an Allegro graphics window.
The program displays a black 440x500 graphics window as shown in Figure 1.
Figure 1. Screen output from the program named Mouse01.
Press the left mouse button
Pointing to the black area and pressing the left mouse button causes the mouse pointer to disappear and causes a red filled circle to be drawn at the location of the mouse pointer. Several such circles are shown in the upper-left portion of Figure 1.
In all cases, releasing the mouse button causes the mouse pointer to reappear.
Press the right mouse button
Pointing to the black area and pressing the right mouse button causes the mouse pointer to disappear and causes a green filled circle to be drawn at the location of the mouse pointer. Several such circles are shown in the upper-right portion of Figure 1.
Drag the mouse with a button pressed
Dragging slowly while the right or left mouse button is pressed produces a wide red or green line (depending on which button is pressed) that traces out the path of the mouse pointer. Two such lines are shown in the center portion of Figure 1.
Dragging rapidly with a mouse button pressed may produce a non-uniform sequence of red or green filled circles that trace out the path of the mouse pointer. This is illustrated by the red and green circles at the bottom of Figure 1.
Terminating the program
Pressing the Esc key causes the program to terminate.
As is my custom, I will explain this program in fragments. A complete listing of the program is provided in Listing 6 near the end of the lesson.
This program consists of the main function plus two other functions named mouseInfo and draw. The program was designed to avoid the use of global variables.
Beginning of the main function
I will start by explaining the main function, which begins in Listing 1.
Listing 1. Beginning of the main function.
int main(){ //NOTE THE USE OF LOCAL VARIABLES IN PLACE OF GLOBALS BITMAP* screenBuf = NULL; int xCoor = 0; int yCoor = 0; int color = 0; allegro_init(); install_mouse(); install_keyboard(); set_color_depth(32); set_gfx_mode(GFX_AUTODETECT_WINDOWED,440,500,0,0); screenBuf = create_bitmap(440,500); show_mouse(screen); |
There are two statements in Listing 1 that I haven't explained in earlier lessons (see Resources):
The install_mouse function
The documentation for the install_mouse reads partially as shown in Figure 2.
Figure 2. Partial description of the install_mouse function.
Installs the Allegro mouse handler. You must do this before using any other mouse functions. Returns -1 on failure, zero if the mouse handler is already installed (in which case this function does nothing)... |
The show_mouse function
As you have probably already guessed, the call to the show_mouse function in Listing 1 tells Allegro to display a mouse pointer on the graphics window. As you will see later, a call to the show_mouse function passing NULL as a parameter hides the mouse pointer.
The documentation for show_mouse contains some cautions, so you should review that documentation before calling this function.
The animation loop
The animation loop is shown in Listing 2, which contains a pair of nested while loops. The outer loop continues to iterate until the user presses the Esc key, at which time the program terminates.
Listing 2. The animation loop.
while(!key[KEY_ESC]){ while(mouseInfo(&xCoor,&yCoor,&color)){ //Draw while mouse button is down. draw(xCoor,yCoor,screenBuf,color); }//end while }//end while return 0; }//end main END_OF_MAIN(); |
The inner loop
During each iteration of the inner loop, the conditional clause calls the mouseInfo function. This function returns true if a left or right mouse button is pressed and returns false if no mouse buttons are pressed. (This program does not attempt to service the middle button, a mouse wheel, etc.)
If the mouseInfo function returns true, the body of the inner loop in Listing 2 is executed, calling the draw function to draw the filled circles shown in Figure 1.
Beginning of the mouseInfo function
The mouseInfo function receives three pointers of type int. As you can see from the call to the mouseInfo function in Listing 2, each of these parameters points to one of the local variables having the same name that was declared in Listing 1. During each execution of the function, the coordinates of the mouse pointer and sometimes a color value for red or green will be stored indirectly in those variables.
The mouseInfo function begins in Listing 3.
Listing 3. Beginning of the mouseInfo function.
bool mouseInfo(int *xCoor,int *yCoor,int *color){ //Get current mouse coordinates and send back via // pointer variables. *xCoor = mouse_x; *yCoor = mouse_y; |
The mouse_x and mouse_y variables
Apparently mouse_x and mouse_y are global variables that are made available to the program by the header file named allegro.h.
Although the documentation doesn't have a lot to say on the subject, accessing mouse_x and mouse_y in Listing 3 returns the horizontal and vertical coordinates of the mouse pointer relative to the upper-left corner of the black graphics window in Figure 1.
As mentioned above, Listing 3 uses the first two pointers received as parameters to store the coordinate values in the local variables in the main function declared in Listing 2.
Completion of the mouseInfo function
The mouse_b function that is called twice in Listing 4 returns 0 (false) if a mouse button is not pressed when the function is called.
Listing 4. Completion of the mouseInfo function.
//Test for a mouse button pressed. Set drawing color // based on left or right mouse button. if(mouse_b & 1){//left mouse button *color = makecol(255,0,0);//red return true;//signal the requirement to draw }else if(mouse_b & 2){//right button *color = makecol(0,255,0);//green return true; }else{//no button return false;//no drawing required }//end else }//end mouseInfo |
The return value when a button is pressed
If the left mouse button is pressed when the mouse_b function is called, it returns a 1. If the right mouse button is pressed when the function is called, it returns a 2. (In C++, a non-zero integer value is interpreted as true.)
Test for a pressed mouse button
Listing 4 tests to determine if either button is pressed when the mouseInfo function is called. If both calls to mouse_b return 0, Listing 4 returns false, causing the body of the inner loop in Listing 2 to be skipped during the current iteration.
Behavior when a mouse button is pressed
If either mouse button is pressed, the code in Listing 4 determines which button is pressed and takes the appropriate action based on that determination. If the left mouse button is pressed, Listing 4 stores the color value for red indirectly into the local variable named color in Listing 1. If the right mouse button is pressed (and the left mouse button is not pressed), Listing 4 stores the color value for green indirectly into the local variable named color in Listing 1. (If both mouse buttons are pressed, Listing 4 stores the color value for red indirectly into the local variable named color in Listing 1.)
If either button is pressed, the mouseInfo function returns true causing the draw function to be called once during the current iteration of the inner loop in Listing 2.
The draw function
As you can see in Listing 2, when the draw function is called, the coordinate and color values stored in the local variables in Listing 1 are passed as parameters. In addition, a pointer to the off-screen buffer is also passed to the draw function.
The draw function is shown in its entirety in Listing 5.
Listing 5. The draw function.
void draw(int xCoor,int yCoor,BITMAP* buf,int color){ show_mouse(NULL);//hide mouse pointer while drawing //Draw filled circle at mouse coor on off-screen buffer. circlefill(buf,xCoor,yCoor,5,color); //Copy the off-screen image to the screen. blit(buf,screen,0,0,0,0,440,500); show_mouse(screen);//show mouse when drawing finished }//end draw |
Hide the mouse pointer and draw a filled circle
Listing 5 begins by hiding the mouse pointer in order to satisfy one of the cautions mentioned earlier.
Once the mouse pointer is turned off, Listing 5 uses the values of the incoming parameters to draw a filled circle of the specified color at the specified location in the off-screen buffer. Then Listing 5 copies the contents of the off-screen buffer to the screen. I have explained code similar to this in numerous previous lessons (see Resources) so I won't repeat that explanation here.
Finally, Listing 5 makes the mouse pointer visible again before returning control to the main function.
You learned how to service the mouse in this lesson. In particular, you learned how to write code that will respond when the user presses either the left or right mouse button while pointing to an Allegro graphics window.
Listing 6. Source code for the program named Mouse01.
/*Project Mouse01 Illustrates how to handle mouse presses and mouse drags. The program displays a black 440x500 graphics window. Pointing to the black area and pressing the left mouse button causes the mouse pointer to disappear and a red filled circle to be drawn at the location of the mouse pointer. Point to the black area and pressing the right mouse button causes the mouse pointer to disappear and a green filled circle to be drawn at the location of the mouse pointer. Dragging slowly with the right or left mouse button pressed produces a wide red or green line (depending on which button is pressed) that traces out the path of the mouse pointer. Dragging rapidly with a mouse button pressed may produce a non-uniform sequence of red or green filled circles that trace out the path of the mouse pointer. Releasing the mouse button causes the mouse pointer to reappear. Pressing the Esc key causes the program to terminate. ********************************************************/ #include <allegro.h> //LOOK! NO GLOBAL VARIABLES bool mouseInfo(int *xCoor,int *yCoor,int *color){ //Get current mouse coordinates and send back via // pointer variables. *xCoor = mouse_x; *yCoor = mouse_y; //Test for a mouse button pressed. Set drawing color // based on left or right mouse button. if(mouse_b & 1){//left mouse button *color = makecol(255,0,0);//red return true;//signal the requirement to draw }else if(mouse_b & 2){//right button *color = makecol(0,255,0);//green return true; }else{//no button return false;//no drawing required }//end else }//end mouseInfo //------------------------------------------------------// void draw(int xCoor,int yCoor,BITMAP* buf,int color){ show_mouse(NULL);//hide mouse pointer while drawing //Draw filled circle at mouse coor on off-screen buffer. circlefill(buf,xCoor,yCoor,5,color); //Copy the off-screen image to the screen. blit(buf,screen,0,0,0,0,440,500); show_mouse(screen);//show mouse when drawing finished }//end draw //------------------------------------------------------// int main(){ //NOTE THE USE OF LOCAL VARIABLES IN PLACE OF GLOBALS BITMAP* screenBuf = NULL; int xCoor = 0; int yCoor = 0; int color = 0; allegro_init(); install_mouse(); install_keyboard(); set_color_depth(32); set_gfx_mode( GFX_AUTODETECT_WINDOWED,440,500,0,0); screenBuf = create_bitmap(440,500); show_mouse(screen); while(!key[KEY_ESC]){ while(mouseInfo(&xCoor,&yCoor,&color)){ //Draw while mouse button is down. draw(xCoor,yCoor,screenBuf,color); }//end while }//end while return 0; }//end main END_OF_MAIN(); |
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.
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.
-end-