Section 1.5. A Simple Example


1.5. A Simple Example

The OpenGL code shown in Listing 1-1, although very simple, should serve as a good introduction. This program, called SimpleExample, is available from the book's Web site. It draws a white triangle on a black background, as shown in Figure 1-3.

Listing 1-1. SimpleExample program

 #include <GL/glut.h> #include <GL/glu.h> #include <GL/gl.h> #include <string> #include <sstream> #include <assert.h> // Define an ID for the "Quit" menu item. static const int QUIT_VALUE( 99 ); // Global variable to hold display list ID GLuint listID; // // GLUT display callback. Called by GLUT when the window // needs redrawing. static void display() {     glClear( GL_COLOR_BUFFER_BIT );     // Modeling transform, move geometry 4 units back in Z.     glLoadIdentity();     glTranslatef( 0.f, 0.f, -4.f );     // Draw the geometry     glCallList( listID );     // Swap buffers (display the rendered image).     glutSwapBuffers();     assert( glGetError() == GL_NO_ERROR ); } // // GLUT resize callback, called when window size changes. static void reshape( int w, int h ) {     // Update the viewport to draw to the full window     glViewport( 0, 0, w, h );     // Update the projection matrix / aspect ratio     glMatrixMode( GL_PROJECTION );     glLoadIdentity();     gluPerspective( 50., (double)w/(double)h, 1., 10. );     // Leave us in model-view mode for our display routine     glMatrixMode( GL_MODELVIEW );     assert( glGetError() == GL_NO_ERROR ); } // // GLUT menu callback, called when user selects a menu item. static void mainMenuCB( int value ) {     if (value == QUIT_VALUE)         exit( 0 ); } static void init() {     // Dither is on by default but not needed, disable it.     glDisable( GL_DITHER );     // Determine whether or not vertex arrays are available.     // In other words, check for OpenGL v1.1...     std::string ver((const char*) glGetString( GL_VERSION ));     assert( !ver.empty() );     std::istringstream verStream( ver );     int major, minor;     char dummySep;     verStream >> major >> dummySep >> minor;     const bool useVertexArrays = ( (major >= 1) && (minor >= 1) );     const GLfloat data[] = {         -1.f, -1.f, 0.f,         1.f, -1.f, 0.f,         0.f, 1.f, 0.f };     if (useVertexArrays)     {         // Set up for using vertex arrays.         glEnableClientState( GL_VERTEX_ARRAY );         glVertexPointer( 3, GL_FLOAT, 0, data );     }     // Create a new display list.     listID = glGenLists( 1 );     glNewList( listID, GL_COMPILE );     if (useVertexArrays)         // Vertex arrays are available in OpenGL 1.1, use them.         glDrawArrays( GL_TRIANGLES, 0, 3 );     else     {         // Use OpenGL 1.0 Begin/End interface.         glBegin( GL_TRIANGLES );         glVertex3fv( &data[0] );         glVertex3fv( &data[3] );         glVertex3fv( &data[6] );         glEnd();     }     glEndList();     assert( glGetError() == GL_NO_ERROR );     // Register our display and resize callbacks with GLUT.     glutDisplayFunc( display );     glutReshapeFunc( reshape );     // Create a right-mouse menu to allow users to exit.     int mainMenu = glutCreateMenu( mainMenuCB );     glutAddMenuEntry( "Quit", QUIT_VALUE );     glutAttachMenu( GLUT_RIGHT_BUTTON ); } int main( int argc, char** argv ) {     glutInit( &argc, argv );     // Create a single GLUT window, 300x300 pixels, RGB mode,     // and double-buffered. Call it "Simple Example".     glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );     glutInitWindowSize( 300, 300 );     glutCreateWindow( "Simple Example" );     init();     // Loop for events.     glutMainLoop();     return 0; } 

Figure 1-3. Output from the SimpleExample program.


The first three header files<GL/glut.h>, <GL/glu.h>, and <GL/gl.h> contain definitions for GLUT, GLU, and OpenGL, respectively. They're followed by some standard C/C++ header files.

This code uses the C preprocessor to define a value that identifies the Quit menu option. When the user opens the menu and selects the Quit option, GLUT passes this identifier to the menu callback function.

Modern programming style avoids use of global variables, but they are still useful and acceptable for small demos such as this. In this case, the code defines an OpenGL display list identifier as a global. The application initializes it in the init() function and references it in the display() callback. OpenGL display lists can store many types of OpenGL commands, but this list holds only drawing commands. For more information on display lists, see Chapter 2, "Drawing Primitives."

GLUT calls the display() callback function when necessary to refresh the window. In this example, this function includes OpenGL calls to clear the window, load a transformation matrix, call the display list that contains the commands to draw the triangle, and check for errors. It also contains a GLUT call to swap buffers.

The next function, reshape(), also a GLUT callback, is executed when the user resizes the window. The function issues OpenGL commands to draw to the full window and maintain the correct aspect ratio and projection. It, too, checks for errors.

GLUT calls the mainMenuCB() function when the user selects an item from the pop-up menu. This function checks only to see whether the item selected is the Quit item, and if so, it causes the application to exit.

The init() function configures OpenGL and creates the display list.

There are many ways to draw primitives in OpenGL. To keep this example simple, it demonstrates only two methods: the glBegin()/glEnd() method and vertex arrays. Because the vertex arrays feature isn't available in OpenGL version 1.0, the code queries OpenGL for its version. If the version is 1.1 or later, the code uses a vertex array rendering command to draw the triangle; otherwise, it uses glBegin()/glEnd(). It's common for OpenGL applications to choose which features to use based on the OpenGL version.

Regardless of the method, the application stores the drawing commands in a display list. Note that display lists store only OpenGL commands. The conditional to check the version gets executed only when the display list is constructed, to determine its contents. When the display() function executes (or calls) the list, only the stored OpenGL commands are executedeither the vertex array call or the glBegin()/glEnd() calls, but not the conditional. Display lists are an effective way to both reduce the number of function calls, as well as eliminate conditionals that are constant at runtime.

Finally, the init() function registers the callback functions and creates the GLUT pop-up menu.

The main() routine performs GLUT initialization to create a window and rendering context. After creating the window, main() calls init() to perform further initialization. Finally, it calls glutMainLoop(), which waits for events and messages, and calls back to the application when necessary.




OpenGL Distilled
OpenGL Distilled
ISBN: 0321336798
EAN: 2147483647
Year: 2007
Pages: 123
Authors: Paul Martz

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net