Open GL Super Bible

Previous Table of Contents Next


We established this volume with a call to glOrtho(), much as we did for others in the previous chapters. Listing 6-1 shows the code for our ChangeSize() function that gets called when the window is sized (including when it is first created). This code looks a little different from that in previous chapters, and you’ll notice some unfamiliar functions (glMatrixMode, glLoadIdentity). We’ll spend more time on these in Chapter 7, exploring their operation in more detail.

Listing 6-1 Code to establish the viewing volume in Figure 6-1

// Change viewing volume and viewport.  Called when window is resized
void ChangeSize(GLsizei w, GLsizei h)
        {
        GLfloat nRange = 100.0f;

        // Prevent a divide by zero
        if(h == 0)
                h = 1;

        // Set Viewport to window dimensions
        glViewport(0, 0, w, h);

        // Reset projection matrix stack
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();

        // Establish clipping volume (left, right, bottom, top, near, far)
       if (w <= h)
                 glOrtho (-nRange, nRange, -nRange*h/w, nRange*h/w,
                           -nRange,nRange);
else
                 glOrtho (-nRange*w/h, nRange*w/h, -nRange, nRange,
                           -nRange,nRange);

        // Reset Model view matrix stack
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
       }


Why the Cart Before the Horse
Look at any of the source code of this chapter, and you’ll notice some new functions in the RenderScene() functions: glRotate(), glPushMatrix(), and glPopMatrix(). Though they’re covered in more detail in Chapter 7, we’re introducing them now. That’s because they implement some important features that we wanted you to have as soon as possible. These functions let you plot and draw in 3D, and help you easily visualize your drawing from different angles. All of this chapter’s sample programs employ the arrow keys for rotating the drawing around the x- and y-axes. Look at any 3D drawing dead-on (straight down the z-axis) and it may still look two-dimensional. But when you can spin the drawings around in space, it’s much easier to see the effects of what you’re drawing.

There is a lot to learn about drawing in 3D, and in this chapter we want you to focus on that. By changing only the drawing code for any of the examples that follow, you can start experimenting right away with 3D drawing and still get interesting results. Later, you’ll learn how to manipulate drawings using the other functions.


A 3D Point: The Vertex

To specify a drawing point in this 3D “palette,” we use the OpenGL function glVertex—without a doubt the most used function in all of the OpenGL API. This is the “lowest common denominator” of all the OpenGL primitives: a single point in space. The glVertex function can take from two to four parameters of any numerical type, from bytes to doubles, subject to the naming conventions discussed in Chapter 3.

The following single line of code specifies a point in our coordinate system located 50 units along the x-axis, 50 units along the y-axis, and 0 units out the z-axis:

glVertex3f(50.0f, 50.0f, 0.0f);

This point is illustrated in Figure 6-2. Here we chose to represent the coordinates as floating point values, as we shall do for the remainder of the book. Also, the form of glVertex() that we have used takes three arguments for the x, y, and z coordinate values, respectively.


Figure 6-2  The point (50,50,0) as specified by glVertex3f(50.0f, 50.0f, 0.0f)

Two other forms of glVertex take two and four arguments, respectively. We could represent the same point in Figure 6-2 with this code:

glVertex2f(50.0f, 50.0f);

This form of glVertex takes only two arguments that specify the x and y values, and assumes the z coordinate to be 0.0 always. The form of glVertex taking four arguments, glVertex4, uses a fourth coordinate value w, which is used for scaling purposes. You will learn more about this in Chapter 7 when we spend more time exploring coordinate transformations.

Draw Something!

Now we have a way of specifying a point in space to OpenGL. What can we make of it, and how do we tell OpenGL what to do with it? Is this vertex a point that should just be plotted? Is it the endpoint of a line, or the corner of a cube? The geometric definition of a vertex is not just a point in space, but rather the point at which an intersection of two lines or curves occurs. This is the essence of primitives.

A primitive is simply the interpretation of a set or list of vertices into some shape drawn on the screen. There are ten primitives in OpenGL, from a simple point drawn in space to a closed polygon of any number of sides. You use the glBegin command to tell OpenGL to begin interpreting a list of vertices as a particular primitive. You then end the list of vertices for that primitive with the glEnd command. Kind of intuitive, don’t you think?

Drawing Points

Let’s begin with the first and simplest of primitives: points. Look at the following code:

glBegin(GL_POINTS);                      // Select points as the primitive
        glVertex3f(0.0f, 0.0f, 0.0f);    // Specify a point
        glVertex3f(50.0f, 50.0f, 50.0f); // Specify another point
glEnd();                                 // Done drawing points

The argument to glBegin, GL_POINTS, tells OpenGL that the following vertices are to be interpreted and drawn as points. Two vertices are listed here, which translates to two specific points, both of which would be drawn.

This brings up an important point about glBegin and glEnd: You can list multiple primitives between calls as long as they are for the same primitive type. In this way, with a single glBegin/glEnd sequence you can include as many primitives as you like.

This next code segment is very wasteful and will execute more slowly than the preceding code:

glBegin(GL_POINTS);             // Specify point drawing
        glVertex3f(0.0f, 0.0f, 0.0f);
glEnd();

glBegin(GL_POINTS);            // Specify another point
        glVertex3f(50.0f, 50.0f, 50.0f);
glEnd();


Indenting Your Code
In the foregoing examples, did you notice the indenting style used for the calls to glVertex()? This convention is used by most OpenGL programmers to make the code easier to read. It is not required, but it does make it easier to find where primitives start and stop.


Previous Table of Contents Next