Sure looks like Greek to me!
Hey, it's not that bad. We just need to break down the program in small pieces to figure out what's going on. But in order to keep this introduction brief, certain concepts such as viewports, won't be discussed.
First off is the include command which lets C++ know that this program will be using OpenGL and GLUT. The GLUT include is the only include that's needed for this example since it contains includes to the standard Windows (windows.h) and OpenGL libraries (gl.h and glu.h).
RenderScene - glClear()
The next series of statements are part of a user named subroutine, or function, called RenderScene. This subroutine contains OpenGL commands, or commands that begin with gl as opposed to glu or glut.
OpenGL contains a variety of buffers (color, depth, stencil, and accumulation) which are areas in memory used to save data. Prior to rendering a scene, it's a good idea to clear, or initilaize, the appropriate buffers. In our example, the color buffer is cleared since it's the buffer normally used to draw with.
Clearing a color buffer can be a relatively expensive operation as close to two million pixel addresses require initialization at a resolution of 1600x1200. In some cases, multiple buffers can be initialized simultaneously through hardware. Game engines such as Quake will only clear the depth buffer, since there's no point in clearing the color buffer as every pixel in each frame will always be used.
RenderScene - glColor3f()
The primary method of generating color on a monitor in OpenGL is with the RGB, or RBGA mode, which is set using the glutInitDisplayMode() command. Each pixel, which is the smallest visible element the display hardware can put on the screen, can emit different amounts of red, green, and blue light. These colors are referred to as the R, G, and B values. A forth value, which is used for blending colors, is called the alpha value.
RGB Color Mode
The R, G, and B values are floating point numbers which range from 0.0 (none) to 1.0 (full intensity). For example, when R = 0.0, G = 0.0, and B = 1.0 the brightest possible blue is displayed. If R, G, and B are all 0.0, the pixel is black and if all are 1.0, the pixel is drawn in the brightest possible white.
In theory, OpenGL can support an infinite range of colors and is limited by the capability of the display hardware (which is normally 16,777,216 colors, or 256 red x 256 green x 256 blue).
The glColor3f() function uses floating point values to determine the color and defaults to an alpha value of 1.0. If an alpha value other than 1.0 is required, then a call to glColor4f() is necessary.
RenderScene - glRectf()
Models, or objects, in OpenGL are constructed with geometric primitives which consist of points, line segments, and polygons. The process of generating the images corresponding to these models is referred to as rendering.
OpenGL Geometric Primitives
Models are defined using vertex data which represents a single point that marks the endpoint of a line or the corner of a polygon. By definition, a vertex is where two edges meet.
Since rectangles are frequently used in OpenGL, a command to easily generate them has been furnished as part of the OpenGL library. The next step in the sample program calls for a rectangle to be generated based on the x and y coordinates that have been furnished to the glRectf() function:
glRectf(50.0f, 150.0f, 150.0f, 50.0f);
The first two coordinates (x1, y1) specify one vertex of the rectangle (upper-left corner) and the second two (x2, y2) specify the opposite vertex of the rectangle (lower-right corner). In this example, the depth, or z-value, of the rectangle defaults to 0.0.
X, Y, Z Coordinate System
The same rectangle could also have been created using the polygon geometric primitive based on the follow vertex commands:
glVertex2f(50.0f, 150.0f); // x1, y1 - top-left corner
glVertex2f(150.0f, 150.0f); // x2, y1 - top-right corner
glVertex2f(150.0f, 50.0f); // x2, y2 - bottom-right corner
glVertex2f(50.0f, 50.0f); // x1, y2 - bottom-left corner
An important concept to remember is that a point is a location in space, and is described by a coordinate in a coordinate system. We typically use the Cartesian coordinate system to describe points in three dimensions by measuring positively or negatively along the X, Y, and Z axes. The point located at (0,0,0) is called the origin of the coordinate system.
RenderScene - glFlush()
The last command in the RenderScene subroutine is a call to glFlush(). This will ensure that the drawing commands are actually executed as opposed to being stored in a buffer awaiting additional OpenGL commands.
I will be discussing the commands that appear in this subroutine in a follow-up article. For now just remember that this subroutine is called when a window initially appears, is moved, or resized, courtesy of the glutReshapeFunc() command.
Initialize - glClearColor()
The Initialize subroutine specifies the red, green, blue, and alpha values used to clear the color buffer. In our example, the color buffer is set to black. The color buffer remains black until it's changed via a subsequent call to glClearColor() is made.
The main part of the program is contained in the routine named main. The order of events takes place as follows:
- Initialize the color buffer (OpenGL)
- Select a display mode (GLUT)
- Open a window (GLUT)
- Render a rectangle (OpenGL)
You may have noticed that initializing the color buffer, via the call to the Initialize subroutine, was executed first although the command appears towards the end of the program. This is due to the fact that GLUT commands are not executed until the glutMainLoop() command appears.
Although we've selected a single buffer via the GLUT_SINGLE parameter in the glutInitDisplayMode() function, the majority of OpenGL applications use double buffering.
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
When double buffering is enabled, one buffer is displayed while the second buffer is being drawn. When the drawing of a frame is complete, the two buffers are swapped, so the one that was being viewed is now used for drawing, and vice versa. Double buffering is useful in providing smooth animation between frames.
Like I said before this program may not be impressive, but you've got to crawl before you can walk right? The following screen shot shows the results of the program which is the window with the black background containing a green rectangle. I left the Visual C++ user interface up in case you're interested in taking a peak at it.
If you think of the enhancements that can be made to this program, such as transformation (rotation, movement) or adding a texture or light source, there's certainly much more information to learn.
Which brings me to the methodology I used before ever laying down the first C++ code. I spent a great deal of time gathering information from multiple sources on the commands that would be used in the program. I read and re-read information until I thouroughly understood the purpose of each OpenGL command being used. By doing so, I developed an understanding of what took place during program execution.
The executable for this example can be downloaded here (17K). It also requires version 3.7.3 of glut32.dll (219K) which may already be in your windows/system directory.