Lesson 17: Display ListsDisplay lists are used in OpenGL as stored versions of a series of OpenGL calls. These lists are then accessed with a display list handle. TheoryOkay... great. Access them with a handle. So... why use display lists anyways? Actually, there is absolutely no reason to. Display lists are useless. No, not really. I was just pulling your leg. First of all, display lists are more convenient to use - you get to replace all those OpenGL rendering calls with a single glCallList(). But, even better - when display lists are stored, lots of extra calculations that are normally done each time you call, say glVertex3f() or glTexCoord2f(), are done once and then stored. So, by avoiding the unnecessary calculations, the use of display lists can speed up your rendering code. Basically, all you have to do is find an unused handle, then reference it and tell OpenGL to start collecting commands to put into the display list. When you're done, tell OpenGL that you're done compiling, and then all you have to do is call it with glCallList(). It's pretty simple! ImplementationRemember the Cube class? Well, now it's time to go to the next step: Spheres!!! The Sphere class constructs a geodisic sphere and stores it in a display list. Listing 17-1: sphere.h
As you can see, the Sphere class is quite extensive and has many parameters that affect how it works. The member dl_handle is, as you might have guessed, the display list handle. This is what is used to reference the display list once it has been compiled. stacks and slices are, respectively, the number of subdivisions along the Y axis and the number of divisions around the Y axis. These are similar to lines of longitude and latitude on a globe. shade is the "colour" of the sphere(level of gray), rad is the radius, and the other variables represent the position, orientation, and speeds of the sphere. Now, for the implementation of the Sphere class: Listing 17-2: sphere.cpp
The constructor and destructor should be easy enough to follow, so I'll jump right in to Sphere::ConstructDisplayList(). After any old lists which may exist are deleted, we get a display list handle by calling glGenLists() with the number of display lists we want to generate(in this case, 1). We then make sure that the handle actually "points" to a real display list by checking it with glIsList(). GLuint glGenLists(int range)
Generates a range of contiguous display list handles. Returns the integer that represents the first display list; if this is zero, then there was an error in trying to allocate enough display lists. Otherwise, you can start using display lists with the handles return value through return value + range - 1. int glIsList(GLuint list)
Returns 1 if the specified display list handle points to a valid display list; otherwise, returns 0. After the display list handle is allocated, we can compile it. This is done by using the function glNewList() and glEndList to border the OpenGL calls that we want to be stored in the display list. All the OpenGL function calls that are made between these two functions are recorded to the display list supplied to glNewList(). void glNewList(GLuint list, int mode)
Starts the compilation of the display list with the handle list in mode mode. If mode is GL_COMPILE, the display list is merely compiled and not executed. If mode is GL_COMPILE_AND_EXECUTE, the OpenGL commands that you call are executed as they are stored in the display list. Any OpenGL calls can be made between glNewList() and glEndList(), with the following special rules(these are taken from the OpenGL 1.1 Reference):
void glEndList(void)
Finishes the compilation of a display list which was started with a call to glNewList(). In between glNewList() and glEndList() is the sphere generating code, which uses some nifty trigonometry to make a sphere. The sphere is made up of a series of quad strips running from the top of the sphere to the bottom, following the "lines of latitude", as it were. Just ignore the calls to glNormal() in the display list compilation code - those will be used in the next lesson, and I didn't want to have to re-write the sphere class just to add those function calls :) Sphere::DeleteDisplayList() uses glDeleteLists() to get rid of the display list used by the class. void glDeleteLists(GLuint list, int range)
Frees resources for range lists starting at list. In Sphere::Update(), the position and rotations of the sphere are updated based on the positional and angular velocities of the sphere. Then, in Sphere::Render(), the needed transformations are applied to the modelview matrix, and then glCallList() is used to execute the display list. (Finally!) void glCallList(GLuint list)
Executes the display list named list. Commands in the display list are executed in the same order in which they were compiled. There is another way to execute display lists, using glCallLists(). An explanation of it can be found here. And now, we finally get to use the class in a nice little example program! Listing 17-3: agl17.cpp
Compile this program along with sphere.cpp and you will see five nice spinning single-coloured spheres on a black background. The Guts of agl17.cppAfter writing this long lesson, I don't feel like explaining much more, and luckily, I don't have to! :) There is pretty much nothing new at all in this example program, except for the use of the Sphere class. Now, how about an exercise for the reader? I can hear the anxious cheering now! ;) The example I wrote was okay, but it generated five separate display lists when really you could have gotten away with only one display list, shared between all the spheres. Maybe one could generate a sphere with a radius of one, then add a call to glScale() in Sphere::Update() to scale the sphere by its radius? Hint, hint. In the Next Lesson...Yes, this article is almost over! Don't fret, though, the next lesson is complicated and difficult to understand! That's right, it's about lighting! Yay!
|