OpenGL is a 2D/3D graphics library. It is based on IRIS GL, developed at Silicon Graphics for their high-end workstations, but is . You can find more information about the OpenGL standard at www.opengl.org. This document is not a tutorial, but introduces some of the basic concepts of OpenGL that will be used in our projects, and provides pointers into the documentation.The best book for learning OpenGL is the

OpenGL Programming Guide, Second Edition, from the OpenGL Architecture Review Board. Copies of this book will be available in the lab in Sieg 228.You can use the GLTemplate application to experiment with the features of OpenGL.

## OpenGL Conventions

All the functions in the OpenGL library have names beginning with "gl". Defined constants have names beginning with "GL_".It common for there to be a family of functions for performing the same operation, differing only in the number and/or types of arguments accepted by each. The names of these functions have tags at the end to indicate the type of argument. The whole family will be referred to with a star syntax. For instance,

glColor*()refers to any of the 32 functions available within OpenGL for setting the current color, including:

glColor3f( GLfloat, GLfloat, GLfloat )glColor4d( GLdouble, GLdouble, GLdouble, GLdouble )glColor3ubv( GLubyte* )There is also a library of utility functions whose names all begin with "glu". These are simply convenience functions for doing some common tasks that take a few OpenGL commands to perform.

## OpenGL as a State Machine

OpenGL keeps a large amount of state. It has many modes which can be switched on and off with theglEnableandglDisablecommands. You should think of each function call as manipulating this state, rather than performing a specific drawing operation. To enable high performance, implementations of OpenGL are allowed to buffer commands almost arbitrarily. When you have sent some commands to OpenGL and want to be sure that the results actually appear on screen, callglFlushto force OpenGL to complete.The OpenGL state is kept in a data structure called a

rendering context. We will typically create one rendering context for each OpenGL window. This keeps state changes for drawing in one window from interfering with drawing in the other windows. Switching to another context is done by callingwglCurrentContex.## Drawing Primitives

Drawing in OpenGL consists of callingglBeginto tell OpenGL what you want to draw, then a series of calls toglVertex*to specify the geometry, then a call theglEndto finish up. The single argument toglBegintells it how to interpret the series of vertices you are going to throw at it. Here are some of the valid things to send toglBegin:

GL_POINTSdraws each vertex as a point GL_LINESdraws a segment connecting the vertices 1 and 2, a segment connecting vertices 3 and 4, 5 and 6, and so on GL_TRIANGLESdraws the first three vertices as a triangle, the second group of three as another triangle, and so on GL_POLYGONtakes the vertices as a single, simple, convex polygon There are several other options, see the manual for more explanation. Note that whenever you tell OpenGL to draw a polygon, it must be flat and convex. Triangles are easy, because they are always flat and convex, but with higher-order polygons you must be careful or your results will look wrong. Each polygon has a front side and a back side, which can be rendered differently if you choose. The front side is defined (by default) as the side from which the vertices appear in counterclockwise order.

The vertices you specify are coordinates in 3D space. They are transformed by the current modelview matrix, then by the current projection matrix to determine where they map to on the screen.

NOTE:Many OpenGL operations are not allowed between aglBeginand aglEnd, including all those listed underMatrix Stacksbelow. Used inappropriately an OpenGL function will likely fail silently. For basic 2D programs such as ImpressionistglVertex*andglColor*will probably be the only two gl* functions used between aglBeginand aglEnd. You can use as much non-OpenGL code as you like, though.## Matrix Stacks

Contained in the OpenGL state are two matrices which affect how geometry appears on the screen. Theprojectionmatrix determines the position and orientation of the camera. Themodelviewmatrix is used to transform geometry before rendering it. In our projects, the projection matrix will typically be set up by the skeleton code. You will change the modelview matrix to affect how primitives are drawn on the screen.The state maintains a stack for each matrix, with the top matrix being the one that is in force. You can thus make temporary changes by pushing a copy, altering the matrix, using it, then throwing it away with a pop. Since a full stack is maintained, you can nest these temporary changes to (almost) arbitrary depth. The useful commands for manipulating these stacks are:

glMatrixModeSelects which matrix stack is being manipulated, GL_PROJECTION or GL_MODELVIEW. (Actually, there is a third one for controlling texture mapping, but you can read about that in the manual.) The remaining commands all affect the currently selected matrix stack. glLoadIdentityReplaces the top element of the stack with an identity matrix. glPushMatrixDuplicates the top element of the matrix stack. glPopMatrixPops and discards the top element of the stack. glTranslate*

glRotate*

glScale*Composes the top element of the stack with a transformation.

## Manipulating the Frame Buffer

Frequently you will want to copy around blocks of pixels, rather than drawing individual primitives like lines and polygons. You could do this by drawing individualGL_POINTobjects, but that would be horrendously slow and inefficient. Instead, there is a set of OpenGL functions for copying blocks of pixels to and from the framebuffer.

glReadPixels, glDrawPixelsread/write a block of pixels from/to the frame buffer glReadBuffer, glDrawBufferselect which buffer is read/written glPixelStore*specify how pixels read/written are arranged glRasterPos*set the starting point for pixel write operations Keep in mind that we will frequently be using a double-buffered framebuffer to provide smooth animation. With double-buffering, objects are typically drawn into the "back" buffer, which is then swapped with the front buffer (with the

SwapBuffersfunction) to provide the illusion of instantaneous redrawing. It is important to understand which buffer you are reading or writing when doing block pixel operations.

problems or comments to dougz@cs.washington.edu | Tuesday, 13-Oct-1998 02:48:54 PDT |