Home Index Search Links About Us
[LinuxFocus Image]
[Navegation Bar]
  News   Archives   Companies   Tips  

GLUT Programming: Windows and Animations

by


Introduction

Initializations

Event Processing

Animation Example



GLUT Homepage
GLUT Author
GLUT-3.6 sources

Introduction

For design reasons the OpenGL specification was isolated from any window system dependencies. The resulting interface is a portable, streamlined and efficient 2D and 3D rendering library. It is up to the native window system to open and render windows. The OpenGL library communicates with the native system through additional auxiliary libraries. For example, the GLX auxiliary library describes the interaction between OpenGL and the X window System. 

The OpenGL Utility Toolkit (GLUT) is a programming interface with ANSI C and FORTRAN bindings for writing window system independent OpenGL programs. It was written by Mark J. Kilgard and covers a great hole left by the OpenGL specification. Thanks to GLUT developers we can use a common window system interface independently of the target platform. OpenGL applications using GLUT can be easily ported between platforms without having to introduce numerous changes to the source code. GLUT definitely simplifies the production of OpenGL code and it complements the OpenGL library. 

GLUT is relatively small and easy to learn. It is well designed and in fact, its author has already written wonderful documentation for it. Therefore starting a series of articles here in LinuxFocus seems redundant. We encourage any serious developer to read Mark's documentation. Our purpose for writing this regular GLUT column is to introduce the GLUT library and its usage step by step with examples as a companion reading with the OpenGL series of this magazine. We hope this will  make a useful contribution and motivate more programmers to join the OpenGL-linux wagon.  In any case, get your own copy of Mark's documentation as a good reference. 

The GLUT API is a state machine like OpenGL. This means that GLUT has a number of state variables that live during the execution of the application. The initial states of the GLUT machine has been reasonably chosen to fit most applications. The program can modify the values of the state variables as it sees fit. Whenever a GLUT function is invoked its action is modified according to the values of the state variables. GLUT functions are simple, they take few parameters. No pointers are returned and the only pointers passed to GLUT functions are pointers to character strings and opaque font handles. 

GLUT functions can be classified into several sub-APIs according to their functionality: 

  • Initialization 
  • Beginning Event Processing 
  • Window Management 
  • Overlay Management 
  • Menu Management 
  • Callback registration 
  • Color Index Colormap Management 
  • State Retrieval 
  • Font Rendering 
  • Geometric Shape Rendering 
In this article we will explore some of the initialization, event processing and window management functions necessary to start a simple OpenGL program. 

Initializations

Every OpenGL program using GLUT must begin by initializing the GLUT state machine. The glut initialization functions are prefixed by glutInit-. The main initialization routine is glutInit
Usage 
  glutInit(int **argcp, char **argv); 
  argcp is a pointer to the program's unmodified argc variable from main. Upon return, the value pointed to by argcp is updated because glutInit extracts any command line options relevant for the GLUT library, for example: under the X Window System environment, any options relevant for the X window associated to the GLUT window
  argv is the program's unmodified argv variable for main.  

glutInit takes care of initializing the GLUT state variables and negotiating a session with the window system. There are a few routines that could appear before glutInit; only routines prefixed by glutInit-. These routines can be used to set the default window initialization state.  For example: 
Usage 
  glutInitWindowPosition(int x, int **y); 
  glutInitWindowSize(int width, int **height); 
  x,y  = screen position in pixels of the window (upper left corner) 
  width,height  in pixels of the window. 

There is another initialization routine omni-present in every OpenGL application, glutInitDisplayMode()
Usage 
  glutInitDisplayMode(unsigned int mode); 
  mode is the Display mode, a bitwise OR-ing of GLUT display mode bit masks. The possible bitmask values are: 

GLUT_RGBA  Select an RGBA mode window. This is the default if neither GLUT_RGBA nor GLUT_INDEX are specified. 
GLUT_RGB  same as GLUT_RGBA. 
GLUT_INDEX  Select color index window mode. This overrides GLUT_RGBA. 
GLUT_SINGLE  Select a single buffered window. This is the default. 
GLUT_DOUBLE  Select a double buffered window. This overrides GLUT_SINGLE. 
GLUT_ACCUM  Select a window with an accumulation buffer. 
GLUT_ALPHA  Select a window with an alpha component to the color buffer(s). 
GLUT_DEPTH  Select a window with a depth buffer. 
GLUT_STENCIL  Select a window with a stencil buffer. 
GLUT_MULTISAMPLE  Select a window with multismapling support. 
GLUT_STEREO Select a stereo window. 
GLUT_LUMINANCE Select a stereo window with a "luminance" color model. 
If some of these features are not familiar to you, don't worry., sooner or later we will write about them. Let us examine a couple of examples.  First a simple initialization for one shot rendering application: 

#include <GL/glut.h> 

void main(int argcp, char **argv){ 

/* Set window size and location */ 
glutInitWindowSize(640, 480); 
glutInitWindowPosition(0, 0); 

/* Select type of Display mode:  
   Single buffer & RGBA color */ 
glutInitDisplayMode(GLUT_RGBA | GLUT_SINGLE); 

/* Initialize GLUT state */ 
glutInit(&argcp, argv);  

.....more code 

}; 

Second an example of an animation program: 

#include <GL/glut.h> 

void main(int argcp, char **argv){ 

/* Set window size and location */ 
glutInitWindowSize(640, 480); 
glutInitWindowPosition(0, 0); 

/* Select type of Display mode: 
   Double buffer & RGBA color */ 
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); 

/* Initialize GLUT state */ 
glutInit(&argcp, argv);  

.....more code 

}; 

We will come back to these two examples as we continue to learn more about GLUT. The main difference is that in the second case the display is initialized in a double buffer mode, ideal for animations because it eliminates flickering effects while changing frames in the animation sequence. 

Event Processing

As mentioned before, GLUT is a state machine. Now we will learn it is also designed as an event driven engine. This means that there is a "timer" or continuous loop that gets started after the proper initializations and that processes, one by one, all the events declared to GLUT during initialization. Events are: a mouse being clicked, a window closed, a window reshape, a cursor moved, keyboard keys pressed, and even more curiously the "idle" event, i.e. nothing happens!  Each one of the possible events must be registered in one of the GLUT state variables for the "timer" or event processing loop of GLUT to periodically check whether that event has been triggered by the user. 
 
For example, we could register "click mouse button" as an event for GLUT to watch out for. Events are registered through callback registration routines. All have the syntax glut[someEvent]Func, in the case of the mouse clicking it would be glutMouseFunc. A callback registration tells the GLUT engine which user-defined function is to be called if the corresponding event is triggered. So, if I write my own routine MyMouse which specifies what to do if the left mouse button is clicked, (or the right, etc.) then I can register my callback function after the glutInit() in main() using the statement "glutMouseFunc(MyMouse);" . 

Let us leave for later which callback functions and events are permitted in GLUT. The important thing now is that after all the important events in our application have been registered we must invoke the event processing routine of GLUT, namely glutMainLoop(). The function never comes back, our program basically enters an infinite loop. It will call as necessary any callbacks that have been previously registered. Every main() for an OpenGL application must then end in a glutMainLoop() statement. So in the case of our animation template: 

#include <GL/glut.h> 

void main(int argcp, char **argv){ 

/* Initialize GLUT state */ 
glutInit(&argcp, argv);  
glutInitWindowSize(640, 480); 
glutInitWindowPosition(0, 0); 

/* Open a window */ 
glutCreateWindow("My OpenGL Application"); 

/* Select type of Display mode:  
   Double buffer & RGBA color */ 
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); 
 

/* Register Callback Functions */ 
..... 

/* Start Event Processing Engine */ 
glutMainLoop(); 
}; 

Notice I have added some extra code we never mentioned before. It is one of GLUT's window management routines, glutCreateWindow(char **name). This is what I like so much about OpenGL & GLUT design philosophy, it is pretty clear what the routine does by just looking at the name!. It also takes care of actually passing the order to the underlying window system to open a window for our OpenGL application. The window will have the name "name" passed as a character string. In the X Window Environment this name is written on the upper left corner of the window. The window management section of GLUT has many other functions that we will eventually have a look at. For now, this one is sufficient. I have also rearranged the initialization routines to show that they can be placed after glutInit(). 

Back to events... I want now to introduce two callback registration functions that are very fundamental in any animation program. The glutDisplayFunc which sets the display function for the current window and the glutIdleFunc which sets the idle callback. Both registration routines expect a function of type void *(void). Say we write two additional callback functions to our animation template, void MyDisplay(void) which takes care of invoking the OpenGL instructions that actually draw our scene onto the window, and void MyIdle(void) which is a function that gets called whenever there is no other user input, that is, each time the event processing machine of GLUT goes once around the infinite loop (glutMainLoop()) and does not find any new event triggered, it processes MyIdle. Why do I need to register an Idle callback function in an animation program? Because if we wish to modify each one of the images (frames) shown during the animation independently of any user input, there has to be a function (the idle callback function) that gets called every so often during the life of  the OpenGL program and changes the frames before they get drawn by Mydisplay()

Animation Example

Finally here is a simple template for an animation program: 
#include <GL/glut.h> 

void MyIdle(void){ 
/* Some code to modify the variables defining next frame */ 
.... 
}; 

void MyDisplay(void){ 
/* Some OpenGL code that draws a frame */ 
.... 
/* After drawing the frame we swap the buffers */ 
glutSwapBuffers(); 
}; 

void main(int argcp, char **argv){ 

/* Initialize GLUT state */ 
glutInit(&argcp, argv);  
glutInitWindowSize(640, 480); 
glutInitWindowPosition(0, 0); 

/* Open a window */ 
glutCreateWindow("My OpenGL Application"); 

/* Select type of Display mode:  
   Double buffer & RGBA color */ 
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); 

/* Register Callback Functions */ 
glutDisplayFunc(MyDisplay) 
glutIdleFunc(MyIdle) 

/* Start Event Processing Engine */ 
glutMainLoop(); 
}; 

Notice that at the end of MyDisplay I have added a new GLUT routine, glutSwapBuffers(). This is very useful in animations. We are using a window in DOUBLE buffer mode, one shown and one hidden. The drawing OpenGL instructions in this case always render into the hidden buffer. The glutSwapBuffers call, exchanges the buffers, showing in the window at once what was drawn. This technique is common in computer animations because it prevents the human eye from seeing the frame being constructed line by line. 

There is already enough material to start writing OpenGL applications.  The only things missing are the OpenGL instructions in MyDisplay that actually do the drawing...but that is another story ;-). 

In the next article on GLUT programming we will explore in more depth the functionality available to us in the Window Management section of GLUT, and how to open multiple scenes inside the same window.  We will also learn about using menus, including the pros and cons for their portability. 


For more information: