The last requirement of our ChangeSize() function is to redefine the clipping volume so that the aspect ratio remains square. The aspect ratio is the ratio of the number of pixels along a unit of length in the vertical direction to the number of pixels along the same unit of length in the horizontal direction. An aspect ratio of 1.0 would define a square aspect ratio. An aspect ratio of 0.5 would specify that for every two pixels in the horizontal direction for a unit of length, there is one pixel in the vertical direction for the same unit of length.
If a viewport is specified that is not square and it is mapped to a square clipping volume, that will cause images to be distorted. For example, a viewport matching the window size and dimensions but mapped to a square clipping volume would cause images to appear tall and thin in tall and thin windows, and wide and short in wide and short windows. In this case, our square would only appear square when the window was sized to be a square.
In our example, an orthographic projection is used for the clipping volume (see Chapter 2). The OpenGL command to create this projection is glOrtho():
void glOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far );
In 3D Cartesian space, the left and right values specify the minimum and maximum coordinate value displayed along the x-axis; bottom and top are for the y-axis. The near and far parameters are for the z-axis, generally with negative values extending away from the viewer (see Figure 3-9).
Just before the code using glOrtho(), you’ll notice a single call to glLoadIdentity(). This is needed because glOrtho() doesn’t really establish the clipping volume, but rather modifies the existing clipping volume. It multiplies the matrix that describes the current clipping volume by the matrix that describes the clipping volume described in its arguments. The discussion of matrix manipulations and coordinate transformations is in Chapter 7. For now, you just need to know that glLoadIdentity() serves to “reset” the coordinate system to unity before any matrix manipulations are performed. Without this “reset” every time glOrtho() is called, each successive call to glOrtho() could result in a further corruption of our intended clipping volume, which may not even display our rectangle.
The following code does the actual work of keeping our “square” square.
if (w <= h) glOrtho (0, 250, 0, 250*h/w, 1.0, -1.0); else glOrtho (0, 250*w/h, 0, 250, 1.0, -1.0);
Our clipping volume (visible coordinate space) is modified so that the left-hand side is always at x = 0. The right-hand side extends to 250 unless the window is wider than it is tall. In that case, the right-hand side is extended by the aspect ratio of the window. The bottom is always at y = 0, and extends upward to 250 unless the window is taller than it is wide. In that case the upper coordinate is extended by the aspect ratio. This serves to keep a square coordinate region 250 x 250 available regardless of the shape of the window. Figure 3-10 shows how this works.
Thus far, we’ve discussed the basics of using the AUX library for creating a window and using OpenGL commands for the actual drawing. You will often want to move or rotate your images and scenes, creating an animated effect. Let’s take the previous example, which draws a square, and make the square bounce off the sides of the window. You could create a loop that continually changes your object’s coordinates before calling the RenderScene() function. This would cause the square to appear to move around within the window.
The AUX library provides a function that makes it much easier to set up a simple animated sequence. This function, auxIdleFunc(), takes the name of a function to call continually while your program sits idle. The function to perform your idle processing is prototyped like this:
void CALLBACK IdleFunction(void);
This function is then called repeatedly by the AUX library unless the window is being moved or resized.
If we change the hard-coded values for the location of our rectangle to variables, and then constantly modify those variables in the IdleFunction(), the rectangle will appear to move across the window. Let’s look at an example of this kind of animation. In Listing 3-4, we’ll modify Listing 3-3 to bounce the square around off the inside borders of the window. We’ll need to keep track of the position and size of the rectangle as we go along, and account for any changes in window size.