NeHe Productions: OpenGL Lesson #12Date de publication : 31/03/2006 , Date de mise à jour : 31/03/2006
Par
Jeff Molofee ( NeHe ) (Autres articles)
Lesson: 12 In this tutorial I'll teach you how to use Display Lists. Not only do display lists speed up
your code, they also cut down on the number of lines of code you need to write when creating a
simple GL scene.
For example. Lets say you're making the game asteroids. Each level starts off with at least 2
asteroids. So you sit down with your graph paper (grin), and figure out how to make a 3D
asteroid. Once you have everything figured out, you build the asteroid in OpenGL using Polygons
or Quads. Lets say the asteroid is octagonal (8 sides). If you're smart you'll create a loop,
and draw the asteroid once inside the loop. You'll end up with roughly 18 lines or more of code
to make the asteroid. Creating the asteroid each time it's drawn to the screen is hard on your
system. Once you get into more complex objects you'll see what I mean.
So what's the solution? Display Lists!!! By using a display list, you create the object just
once. You can texture map it, color it, whatever you want to do. You give the display list a
name. Because it's an asteroid we'll call the display list 'asteroid'. Now any time I want to
draw the textured / colored asteroid on the screen, all I have to do is call glCallList(asteroid).
the premade asteroid will instantly appear on the screen. Because the asteroid has already built
in the display list, OpenGL doesn't have to figure out how to build it. It's prebuilt in memory.
This takes alot of strain off your processor and allows your programs to run alot faster!
So are you ready to learn? :) We'll call this the Q-Bert Display List demo. What you'll end
up with is a Q-Bert type screen made up of 15 cubes. Each cube is made up of a TOP, and a BOX.
The top will be a seperate display list so that we can color it a darker shade. The box is a
cube without the top :)
This code is based around lesson 6. I'll rewrite most of the program so it's easier to see where
I've made changes. The follow lines of code are standard code used in just about all the lessons.
Now we set up our variables. First we set up storage for one texture. Then we create two new
variables for our 2 display lists. These variable will act as pointers to where the display
list is stored in ram. They're called box and top.
After that we have 2 variables called xloop and yloop which are used to position the cubes on
the screen and 2 variables called xrot and yrot that are used to rotate the cubes on the x axis
and y axis.
Next we create two color arrays. The first one boxcol stores the color values for Bright Red, Orange, Yellow, Green
and Blue. Each value inside the {}'s represent a red, green and blue value. Each group of {}'s is a specific color.
The second color array we create is for Dark Red, Dark Orange, Dark Yellow, Dark Green and Dark Blue. The
dark colors will be used to draw the top of the boxes. We want the lid to be darker than the rest of the box.
Now we build the actual Display List. If you notice, all the code to build the box is in the
first list, and all the code to build the top is in the other list. I'll try to explain this
section in alot of detail.
We start off by telling OpenGL we want to build 2 lists. glGenLists(2) creates room for the
two lists, and returns a pointer to the first list. 'box' will hold the location of the first
list. Whenever we call box the first list will be drawn.
Now we're going to build the first list. We've already freed up room for two lists, and we
know that box points to the area we're going to store the first list. So now all we have to do
is tell OpenGL where the list should go, and what type of list to make.
We use the command glNewList() to do the job. You'll notice box is the first parameter. This
tells OpenGL to store the list in the memory location that box points to. The second parameter
GL_COMPILE tells OpenGL we want to prebuild the list in memory so that OpenGL doesn't have to
figure out how to create the object ever time we draw it.
GL_COMPILE is similar to programming. If you write a program, and load it into your compiler,
you have to compile it every time you want to run it. If it's already compiled into an .EXE
file, all you have to do is click on the .exe to run it. No compiling needed. Once GL has
compiled the display list, it's ready to go, no more compiling required. This is where we get
the speed boost from using display lists.
The next section of code draws the box without the top. It wont appear on the screen. It
will be stored in the display list.
You can put just about any command you want between glNewList() and glEndList(). You can set
colors, you can change textures, etc. The only type of code you CAN'T add is code that would
change the display list on the fly. Once the display list is built, you CAN'T change it.
If you added the line glColor3ub(rand()%255,rand()%255,rand()%255) into the code below, you
might think that each time you draw the object to the screen it will be a different color. But
because the list is only CREATED once, the color will not change each time you draw it to the
screen. Whatever color the object was when it was first made is the color it will remain.
If you want to change the color of the display list, you have to change it BEFORE you draw the
display list to the screen. I'll explain more on this later.
We tell OpenGL we're done making our list with the command glEndList(). Anything between
glNewList() and glEndList is part of the Display List, anything before glNewList() or after
glEndList() is not part of the current display list.
Now we'll make our second display list. To find out where the second display list is stored
in memory, we take the value of the old display list (box) and add one to it. The code below
will make 'top' equal the location of the second display list.
Now that we know where to store the second display list, we can build it. We do this the same
way we built the first display list, but this time we tell OpenGL to store the list at 'top'
instead of 'box'.
The following section of code just draws the top of the box. It's a simple quad drawn on the Z
plane.
Again we tell OpenGL we're done building our second list with the command glEndList(). That's it.
We've successfully created 2 display lists.
The bitmap/texture building code is the same code we used in previous tutorials to load and build a texture. We want
a texture that we can map onto all 6 sides of each cube. I've decided to use mipmapping to make the texture look real
smooth. I hate seeing pixels :) The name of the texture to load is called 'cube.bmp'. It's stored in a directory
called data. Find LoadBMP and change that line to look like the line below.
Resizing code is exactly the same as the code in Lesson 6.
The init code only has a few changes. I've added the line
BuildList(). This will jump to the section of code that builds the
display lists.
Notice that BuildList() is after LoadGLTextures(). It's important to
know the order things should go in. First we build the textures, so
when we
create our display lists, there's a texture already created that we can
map onto the cube.
The next three lines of code enable quick and dirty lighting. Light0 is predefined on most
video cards, so it saves us the hassle of setting up lights. After we enable light0 we enable
lighting. If light0 isn't working on your video card (you see blackness), just disable lighting.
The last line GL_COLOR_MATERIAL lets us add color to texture maps. If we don't enable material
coloring, the textures will always be their original color. glColor3f(r,g,b) will have no affect
on the coloring. So it's important to enable this.
Finally we set the perspective correction to look nice, and we return TRUE letting our program know that
initialization went OK.
Now for the drawing code. As usual, I got a little crazy with the math. No SIN, and COS, but
it's still a little strange :) We start off as usual by clearing the screen and depth buffer.
Then we bind a texture to the cube. I could have added this line inside the display list code,
but by leaving it outside the display list, I can change the texture whenever I want. If I
added the line glBindTexture(GL_TEXTURE_2D, texture[0]) inside the display list code, the display
list would be built with whatever texture I selected permanently mapped onto it.
Now for the fun stuff. We have a loop called yloop. This loop is used to position the cubes
on the Y axis (up and down). We want 5 rows of cubes up and down, so we make a loop from 1 to
less than 6 (which is 5).
We have another loop called xloop. It's used to position the cubes on the X axis (left to right).
The number of cubes drawn left to right depends on what row we're on. If we're on the top row,
xloop will only go from 0 to 1 (drawing one cube). The next row xloop will go from 0 to 2
(drawing 2 cubes), etc.
We reset our view with glLoadIdentity().
The next line translates to a specific spot on the screen. It looks confussing, but it's
actually not. On the X axis, the following happens:
We move to the right 1.4 units so that the pyramid is in the center of the screen. Then we
multiply xloop by 2.8 and add the 1.4 to it. (we multiply by 2.8 so that the cubes are
not on top of eachother (2.8 is roughly the width of the cubes when they're rotated 45 degrees).
Finally we subtract yloop*1.4. This moves the cubes left depending on what row we're on. If
we didn't move to the left, the pyramid would line up on the left side (wouldn't really look a
pyramid would it).
On the Y axis we subtract yloop from 6 otherwise the pyramid would be built upside down. Then
we multiply the result by 2.4. Otherwise the cubes would be on top of eachother on the y
axis (2.4 is roughly the height of each cube). Then we subtract 7 so that the pyramid starts at
the bottom of the screen and is built upwards.
Finally, on the Z axis we move into the screen 20 units. That way the pyramid fits nicely on
the screen.
Now we rotate on the x axis. We'll tilt the cube towards the view by 45 degrees minus 2 multiplied
by yloop. Perspective mode tilts the cubes automatically, so I subtract to compensate for the tilt.
Not the best way to do it, but it works :)
Finally we add xrot. This gives us keyboard control over the angle. (fun to play around with).
After we've rotated on the x axis, we rotate 45 degrees on the y axis, and add yrot so we have
keyboard control on the y axis.
Next we select a box color (bright) before we actually draw the box portion of the cube. Notice
we're using glColor3fv(). What this does is loads all three values (red, green, blue) from
inside the {}'s at once and sets the color. 3fv stands for 3 values, floating point, v is a
pointer to an array. The color we select is yloop-1 which gives us a different color for each
row of the cubes. If we used xloop-1 we'd get a different color for each column.
Now that the color is set, all we have to do is draw our box. Instead of writing out all the
code to draw a box, all we do is call our display list. We do this with the command
glCallList(box). box tells OpenGL to select the box display list. The box display list is
the cube without its top.
The box will be drawn using the color we selected with glColor3fv(), at the position we
translated to.
Now we select a top color (darker) before we draw the top of the box. If you actually wanted
to make Q-Bert, you'd change this color whenever Q-Bert jumped on the box. The color depends
on the row (yloop-1).
Finally, the only thing left to do is draw the top display list. This will add a darker colored
lid to the box. That's it. Very easy!
The remaining changes have all been made in WinMain(). The code has been added right after our SwapBuffers(hDC) line.
It check to see if we are pressing left, right, up or down, and moves the cubes accordingly.
Like all the previous tutorials, make sure the title at the top of the window is correct.
By the end of this tutorial you should have a good understanding of how display lists work, how to create them, and
how to display them on the screen. Display lists are great. Not only do they simplify coding complex projects,
they also give you that little bit of extra speed required to maintain high framerates.
I hope you've enjoy the tutorial. If you have any questions or feel somethings not clear,
please email me and let me know.
Jeff Molofee ( NeHe )
|
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2006 Nehe Gamedev.net. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.