Open GL Super Bible

Previous Table of Contents Next


Improving Performance

You may have spotted a glaring performance problem with the WM_PAINT technique, however. Each time the bolt is drawn, a large number of calculations must be performed to redraw the thread, the shaft, and the bolt head. Among these calculations are some pretty expensive calls to sin() and cos().

What we need is a way of storing all these vertices and normals as they are calculated, so we can reuse them rather than go back through all that trigonometry to calculate spiral paths and such. OpenGL has just what we need: display lists. With a display list, you can record OpenGL function calls (and their results) and play them back at a later time. Display lists are faster than just reexecuting the same OpenGL functions singly. Further, non-OpenGL calls such as our trigonometry and normal calculations are not stored, but their results, which are passed to the OpenGL functions, are. You should be getting an inkling of why display lists are such a good idea.


Human Beings and Computer Performance
A good rule of thumb in any type of software engineering is to work first on improvements that yield at least a 20% increase in performance. It is universally accepted that human beings, for the most part, have difficulty “detecting” an increase in software performance that is less than 20%. For OpenGL, this 20% value can often be attained quickly by using display lists when the number of polygons is high. It’s a good idea to get in the habit of using them.

Creating a Display List

Creating a display list is a very straightforward process. Just as you delimit an OpenGL primitive with glBegin/glEnd, you delimit a display list with glNewList/glEndList. A display list, however, is named with an integer value that you supply. The following code represents a typical example of display list creation:

glNewList(1,GL_COMPILE);
         …
         …
        // Some OpenGL Code
         …
         …
glEndList();

As the second parameter to glNewList, you can specify GL_COMPILE or GL_COMPILE_AND_EXECUTE. This tells OpenGL whether to compile and store the OpenGL commands, or to compile, store, and execute the commands as they occur. Later, when you need to execute the display list, simply call

glCallList(1);

The identifier you supply is the same as that supplied in the corresponding call to glNewList.

Listing 10-10 is the code for our new example, SLSTBOLT, which makes use of display lists to produce the spinning bolt. Notice that you can nest calls to display lists. The maximum number of nested calls is 64 to prevent infinite recursion. In this code, we create a display list for each part of the bolt, and then one display list that does all the coordinate transformations and calls the lists to create the completed bolt.

Listing 10-10 New spinning bolt code using display lists

#define HEAD_LIST       1
#define SHAFT_LIST      2
#define THREAD_LIST     3
#define BOLT_LIST       4
 …
 …
// This function does any needed initialization on the rendering
// context.  Here it sets up and initializes the lighting for
// the scene, and creates display lists used later
void SetupRC()
        {
        …
        …
        …
        // Create display list for Bolt head
        glNewList(HEAD_LIST,GL_COMPILE);
                RenderHead();
        glEndList();

        // Create display list for shaft
        glNewList(SHAFT_LIST,GL_COMPILE);
                RenderShaft();
        glEndList();

        // Create display list for thread
        glNewList(THREAD_LIST,GL_COMPILE);
                RenderThread();
        glEndList();

        // Create nested display list for entire bolt
        glNewList(BOLT_LIST,GL_COMPILE);

                // Clear the window with current clearing color
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

                // Make sure we have the correct matrix mode
                glMatrixMode(GL_MODELVIEW);

                // Rotate and translate the coordinate system
                // Note this will be cumulative
                glRotatef(5.0f, 0.0f, 1.0f, 0.0f);

                // Translate and render the head
                glTranslatef(0.0f, 0.0f, 55.0f);
                glCallList(HEAD_LIST);

                // Translate back some and render the shaft and thread
                together
                glTranslatef(0.0f, 0.0f, -15.0f);
                glCallList(SHAFT_LIST);
                glCallList(THREAD_LIST);

                // Translate back again for next pass
                glTranslatef(0.0f, 0.0f, -40.0f);

        // End Bolt list
        glEndList();
        }
// Called to draw the entire bolt
void RenderScene(void)
        {
        glCallList(BOLT_LIST);

        // Flush drawing commands
        glFlush();
        }

You’ll see that we defined some macros to identify the display lists more easily. These macros simply map to the numeric value that identifies the display list. Figure 10-10 shows the output from this new and improved spinning bolt program. The elapsed time for the example using display lists was just over 13 seconds, about a 2-second improvement. This may not seem like much, but wait a few chapters and come back and try it again with special effects such as texture mapping or NURBS surfaces. As mentioned earlier, 1,700 triangles is really a very small portion of what some larger and more complex scenes will consist of.


Figure 10-10  Output from SLSTBOLT using display lists


The Tank Simulator
Try the tank simulator as it stood after the last chapter, and compare it to the one for this chapter. This version, which makes heavy use of display lists, consists of many thousands of triangles, and you won’t need any benchmarking program or stopwatch to know that the performance has been enhanced!

Summary

We used this chapter to slow down somewhat and just talk about how to build a three-dimensional object, starting with using the OpenGL primitives to create simple 3D pieces, and then assembling them into a larger and more complex object. Learning the API is the easy part, but your level of experience in assembling 3D objects and scenes will be what differentiates you from your peers. Once an object or scene is broken down into small and potentially reusable components, you can save building time by using display lists. You’ll find many more functions for utilizing and managing display lists in the Reference Section. You also learned a simple way to benchmark your OpenGL programs so you can get firsthand experience of the effects of optimizing your code.


Previous Table of Contents Next