CS 381 Fall 2011  >  Lecture Notes for Thursday, September 8, 2011

CS 381 Fall 2011
Lecture Notes for Thursday, September 8, 2011

OpenGL Primitives

Primitives in General

All rendering operations are composed of primitives.

OpenGL primitives are of two kinds:

The Ten glBegin-Style Primitives

We now consider the second category. There are ten glBegin-style primitives.

Below are illustrations of these primitives. The colored regions illustrate what is drawn. Small circles represent vertices; the numbers show the order in which the glVertex* calls are made.

Primitive GL_POINTS draws a point for each specified vertex.
Image not displayed: GL_POINTS primitive

Primitive GL_LINES takes an even number of vertices, drawing a line segment between vertices 1-2, then 3-4, then 5-6, etc.
Image not displayed: GL_LINES primitive

Primitive GL_LINE_STRIP draws a line segment between each consecutive pair of vertices: 1-2, then 2-3, then 3-4, etc.
Image not displayed: GL_LINE_STRIP primitive

Primitive GL_LINE_LOOP is just like GL_LINE_STRIP, except that it also draws a line segment between the first and last vertices.
Image not displayed: GL_LINE_LOOP primitive

Primitive GL_TRIANGLES is similar to GL_LINES. It makes triangles out of triples of vertices: 1-2-3, then 4-5-6, then 7-8-9, etc.
Image not displayed: GL_TRIANGLES primitive

Primitive GL_TRIANGLE_STRIP is similar to GL_LINE_STRIP. It make a triangle out of each consecutive triple of vertices: 1-2-3, then 2-3-4, then 3-4-5, etc.
Image not displayed: GL_TRIANGLE_STRIP primitive

Primitive GL_TRIANGLE_FAN makes triangles using the first vertex and each consective pair in the remaining vertices: 1-2-3, then 1-3-4, then 1-4-5, etc.
Image not displayed: GL_TRIANGLE_FAN primitive

Primitive GL_QUADS is similar to GL_TRIANGLES. It makes quadrilaterals out of quadruples of vertices: 1-2-3-4, then 5-6-7-8, etc.
Image not displayed: GL_QUADS primitive

Primitive GL_QUAD_STRIP is almost exactly like GL_TRIANGLE_STRIP. It makes quadrilaterals, rather than triangles, but since a quadrilateral is two triangles stuck together, there might be no difference at all. (Note that the order of the vertices around a quadrilateral is different from that for GL_QUADS: 1-2-4-3 vs. 1-2-3-4.)
Image not displayed: GL_QUAD_STRIP primitive

Primitive GL_POLYGON draws a single polygon using all given vertices. The result is very similar to the output of GL_TRIANGLE_FAN (and might be exactly the same).
Image not displayed: GL_POLYGON primitive

Know these ten primitives, including the associated vertex orderings!

Quadrilaterals and general polygons (last 3 primitives above) must be:

Primitives in Code

Typical code:

glBegin(GL_TRIANGLES);
    glVertex2d(0., 0.);
    glVertex2d(1., 0.);
    glVertex2d(1., 1.);
glEnd();

Only a very limited set of GL commands can be executed between glBegin and glEnd, where “between” does not refer to the structure of your code, but only the order in which OpenGL commands are executed. Of the commands we have seen, only glVertex* and glColor* are legal.

The glVertex* command does two things:

Note that this means that attributes of a vertex (its color, for example) must be set before the glVertex* command.

Note: The glBegin-glVertex*-glEnd method is very flexible, but it can have high overhead, due to the large number of function calls. There are more efficient mechanisms for getting vertex data to the pipeline. You may wish to look into vertex arrays and vertex buffer objects. However, while these can improve speed in some cases, they do not add any new capabilities.

Quickie Text

OpenGL has facilities for drawing bitmaps, and GLUT can use these to make text in the graphics window. (GLUT text is rather low-quality by today’s standards; we will not spend much time on it.)

To make a character, set the raster position using glRasterPos*, and than call glutBitmapCharacter with 2 parameters: the character set (I prefer GLUT_BITMAP_9_BY_15) and the character (a char). This advances the raster position, so that successive calls to glutBitmapCharacter will place characters in a line, as usual.

I have written a class to make GLUT text convenient. See textkbd.cpp.

Unit Overview—Animation & Interaction

This concludes our unit on The Basics of Computer Graphics. Now we begin the second unit: Animation & Interaction.

Major Topics:

Events

GUIs & Events

Programs that have a graphical user interface (GUI—say “gooey”) are almost always event-driven. An event is something that happens, often originating with the user, that the program can respond to.

Some examples of events (these can vary from system to system):

A typical GUI program does its initialization, makes a window, and then enters its event loop. In this loop, it waits for an event, responds, when it gets one, by executing the appropriate handler, and then goes back to waiting.

A response to an event will often require a change in the contents of a window; the window must be redrawn. However, event handlers (other than those that handle window redisplay events) should generally not do any drawing. Instead, they:

Later, when the redisplay event is processed, the window contents will be redrawn, using the above-mentioned data.

Events in GLUT Programs

In a GLUT program, you do not write the event loop. Instead you call glutMainLoop, which does not return. Event handlers should be registered with GLUT before calling glutMainLoop.

For example, GLUT generates a reshape event when the size of a window is set, that is, when the window is created or resized. Such events are handled by a reshape function, which takes two parameters (ints giving the new width and height of the drawing area of the window, in pixels) and returns nothing.

void myReshape(int w, int h);

To register a reshape function, call glutReshapeFunc with a pointer to the function.

glutReshapeFunc(myReshape);

See textkbd.cpp for an example of a simple reshape function.

Drawing is done when GLUT signals a display event. Register a display function with glutDisplayFunc.

glutDisplayFunc(myDisplay);

You can also post your own display events. To do this, call glutPostRedisplay, which takes no parameters.

glutPostRedisplay();

You cannot add parameters to GLUT callbacks. In particular, the display function has none. Thus, the data describing the window contents must be stored in global variables. Thus, here is how we make an event update the window contents, in a GLUT program.

As a memory aid, note that the intials above spell “DICE”.

The Keyboard in GLUT

In a GLUT program, the keyboard function handles ASCII keypresses. Register this with glutKeyboardFunc. The keyboard function takes 3 parameters: the key pressed, and the x and y coordinates of the mouse at the time of the keypress, (in pixels, from the upper-left-hand corner of the drawing area of the window). It returns nothing.

void myKeyboard(unsigned char key, int x, int y)
{
    switch (key)
    {
    case 'a':
    case 'A':
        // handle A-key press here
        glutPostRedisplay();
        break;
    ...

In a GLUT program, the special function handles non-ASCII keypresses (e.g., arrow keys). Register this with glutSpecialFunc. The signature of the special function is identical to that of the keyboard function, except that the first parameter is an int. This int should be one of a number of special values defined in glut.h.

void mySpecial(int key, int x, int y)
{
    switch (key)
    {
    case GLUT_KEY_RIGHT:  // right arrow key
        // handle right-arrow-key press here
        glutPostRedisplay();
        break;
    ...

We added keyboard handling to textkbd.cpp (which see).


CS 381 Fall 2011: Lecture Notes for Thursday, September 8, 2011 / Updated: 11 Nov 2011 / Glenn G. Chappell / ggchappell@alaska.edu