Выбрать главу

Now, lets continue with the application:

glutDisplayFunc(display);

glutMainLoop();

The first function sets the function that GLUT will use whenever it needs to update the view. We then call glutMainLoop() which actually runs the program. From this point on our work is done; GLUT will handle the details of managing the window and calling our painting function to display it.

Here is the display function again:

void display(void) {

 glClear(GL_COLOR_BUFFER_BIT);

 glRectf(-5.0, 5.0, 5.0, –5.0);

 glutSwapBuffers();

}

The first thing we do is call glClear with GL_COLOR_BUFFER_BIT parameter. This will clear the window with the color we specified earlier using glClearColor. Next, we actually draw our rectangle, using the glRectf function.

Now's the time I should bring up something about OpenGL function calls – they often come in different forms. For example, take glColor, which sets the current foreground color. This function has several prototypes, for example:

glColor3f(float, float, float);

glColor4f(float, float, float, float);

glColor3d(double, double, double);

glColor3i(int, int, int);

etc, etc, etc.

As you can see, OpenGL functions are usually formatted like this:

gl Color 3 f

However, even though most OpenGL functions can accept any type, it's usually best to pass floats. OpenGL uses floating point values for all its internal calculations, so passing any other type is a waste of time since OGL will just convert it back to floating point anyway.

The next function, glutSwapBuffers(), swaps the back buffer to the screen buffer. In double-buffered mode, the drawing commands do not draw to the screen. Rather, they draw to an offscreen buffer. Once you are done drawing, you copy the entire back buffer to the screen at once, thus producing smooth animation. Of course, in this simple example there is no animation, but without a double buffer even moving the window around the screen will cause the rectangle to flicker. Besides, it's good to get into the habit of producing smooth graphics!

OK, now feel free to copy this program into an editor, compile it, and run it. Note you will have to link with whatever libs your version of OpenGL has provided, as well as the GLUT library. Under linux you will also probably have to link the X Window libraries such as libX11.a.

Congratulations! You are now an OpenGL Programmer! But I know what you're

saying…"Where are the 3D graphics? You think I'm reading this junk to learn

how to draw a stupid square?" Well, since you're so impatient, lets move on to creating 3D worlds with OpenGL…

II. Points, Lines, and Polygons

Before we start drawing 3D objects, lets quickly go over some fundamentals.  You will find drawing to a 3D canvas is in fact very similar to plain old 2D applications.  This is because OpenGL uses a coodinate system called the Cartesian plane.  The difference here is that instead of having two axis which stretch horizontally and vertically, we add a third axis, the z (or depth) axis.  You can think of this as a line which runs through the origin (0,0 on a Cartesian coordinate system), going in the direction from away from you to straight towards you (in OpenGL, the positive z-axis always points towards you, while the negative points away).  Using this system, we can represent a point in 3D space, called a "vertex", with three coordinites, representing x, y, and z.  For example:

(0,0,0) ← The origin, the center of our defined space.

(2,0,4) ← 2 units to the right, 4 units towards us, on the center of the y-axis.

(3,-4,-2) ← 3 units to the right, 4 units down, and 2 units away from us.

Got the hang of it? Then lets plot some points with OpenGL. We can use the function glVertex to specifiy vertices, flanked by calls to glBegin and glEnd:

glBegin(GL_POINTS); /* We want to draw points */

glVertex3f(2.0, 0.0, 4.0); /* Specify a couple of vertices */

glVertex3f(3.0, –4.0, –2.0);

glEnd(); /* End points */

As you can see, glBegin tells OpenGL we want to start drawing (as well as WHAT we want to start drawing), and glEnd tells it to stop. The great thing about OGL's method of 3D drawing is it's flexibility – lets say we want to draw some lines:

glBegin(GL_LINES); /* lets do some lines now */

glVertex3f(6.0, 4.0, 2.0); /* here's one */

glVertex3f(2.0, –4.0, 3.3);

glVertex3f(5.0, 8.0, 8.0); /* here's another */

glVertex3f(-4.7, 5.0, –3.0);

glVertex3f(0.0, 0.0, 0.0); /* and another! */

glVertex3f(6.0, –1.0, –7.0);

glEnd();

Note that we now have one line for every two vertices. If you specify an odd number, the last vertex is ignored.

Now lets do some shapes. OpenGL specifies 6 different polygon primitives: GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_QUADS, GL_QUAD_STRIP, and GL_POLYGON. Triangle and quad strips are shortcuts for building polygons next to each other, and likewise a triangle fan is a group of triangles that share a center point. GL_POLYGON can specify a general polygon with any number of vertices. The one you should use most often is GL_TRIANGLES, since most graphic accelerators are optimized for triangle operations. Here's an example of a generic triangle:

glBegin(GL_TRIANGLES);

glVertex3f(-3.0, –3.0, 2.0);

glVertex3f(3.0, –3.0, –1.0);

glVertex3f(0.0, 3.0, 4.0);

glEnd();

See? Nothing to it!

Now, lets take what we've learned so far and draw some 3D using OpenGL. As you can see, the following program bears more than a passing resemblence to the previous one (GLUT is so nice that way), with some changes to the display() function. One thing you will notice is that I change the current color with glColor before specifiying some of the vertices. When OpenGL sees a polygon with vertices that have different colors, it draws the figure by smoothly shading from one color to the next. In this example I've created an abstract shape made out of one square surrounded by four triangles. One point of the triangles is red, while the other two are blue. This creates a smoothing purple effect across the face of the triangle.

I'm also using this example to demonstrate some of the UI routines that GLUT uses. In this case we are going to be using the function glutKeyboardFunc(). This function defines a callback handler that will be called whenever a key is pressed while our window has focus.

/**********************************************************************/

/******************************************/

/* Example 2: Drawing in 3D */

/******************************************/

#include <windows.h>

#include <gl\gl.h>

#include <gl\glut.h>

void init(void);

void display(void);

void keyboard(unsigned char, int, int);

int main (int argc, char **argv) {

 glutInit(&argc, argv);

 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);

 glutInitWindowSize(600, 600);

 glutInitWindowPosition(50, 50);

 glutCreateWindow("A 3D Object");

 init();

 glutDisplayFunc(display);