For saving memory or improving performance, many display cards also support various other color modes.
In the area of performance improvement, some cards support a 32-bit color mode sometimes called true color mode. Actually, the 32-bit color mode cannot display any more colors than the 24-bit mode, but it improves performance by aligning the data for each pixel on a 32-bit address boundary. Unfortunately, this results in a wasted 8-bits (1 byte) per pixel. On today’s 32-bit Intel PCs, a memory address evenly divisible by 32 results in much faster memory access.
Two other popular display modes are sometimes supported to use memory more efficiently. The first is 15-bit color mode, which uses 5 bits each for storing red, green, and blue components. Each pixel can display any of 32,768 different colors. And in 16-bit mode, an additional bit is added for one of the color components (usually green), allowing one of 65,536 possible colors for each pixel. This last mode, especially, is practically as effective as 24-bit for photographic image reproduction. It is difficult to tell the difference between 16-bit and 24-bit color modes for most photographic images, although some banding may be observed on smoothly shaded surfaces with only 16 bits of color.
Programmatically, a color in the 15- or 16-bit color mode is set in the same way as for the 24-bit color modes—that is, as a set of three 8-bit intensities. The hardware or device driver takes this 24-bit color value and scales it to the nearest matching 15- or 16-bit color value before setting the pixel color.
You now know that OpenGL specifies an exact color as separate intensities of red, green, and blue components. You also know that Windows-supported PC hardware may be able to display nearly all of these combinations, or only a very few. How, then, do we specify a desired color in terms of these red, green, and blue components? And how will Windows fulfill this request using the colors it has available?
Since a color is specified by three positive color values, we can model the available colors as a volume that we shall call the RGB color space. Figure 8-6 shows what this color space looks like at the origin with red, green, and blue as the axes. The red, green, and blue coordinates are specified just like x, y, and z coordinates. At the origin (0,0,0), the relative intensities of all the components is zero, and the resulting color is black. The maximum available on the PC for storage information is 24 bits, so with 8 bits for each component, let’s say that a value of 255 along the axis would represent full saturation of that component. We would then end up with a cube measuring 255 on each side. The corner directly opposite black, where the concentrations are (0,0,0), is white with relative concentrations of (255,255,255). At full saturation (255) from the origin along each axis would lie the pure colors of red, green, and blue, respectively.
This “color cube” (Figure 8-7) then contains all the possible colors, either on the surface of the cube or within the interior of the cube. For example, all possible shades of gray between black and white lie internally on the diagonal line between the corner (0,0,0) and (255,255,255).
Figure 8-8 is a screenshot of the smoothly shaded color cube produced by a sample program from this chapter, CCUBE. The surface of this cube shows the color variations from black on one corner to white on the opposite corner. Red, green, and blue are present on their corners 255 units from black. Additionally, the colors yellow, cyan, and magenta have corners showing the combination of the other three primary colors. This program will do an adequate job of rendering the color cube, even in a 16-color Windows display mode, and you’ll learn how this is done later in this chapter. You can also spin the color cube around to examine all of its sides, by pressing the arrow keys.
Let’s briefly review the glColor() function. It is prototyped as follows:
void glColor<x><t>(red, green, blue, alpha);
In the function name, the <x> represents the number of arguments; it may be 3 for three arguments of red, green, and blue, or 4 for four arguments to include the alpha component. (The alpha component specifies the translucency of the color and will be covered in more detail in (Chapter 15.) For the time being, just use a three-argument version of the function.
The <t> in the function name specifies the argument’s data type and can be b, d, f, i, s, ub, ui, us, for byte, double, float, integer, short, unsigned byte, unsigned integer, and unsigned short data types, respectively. Another version of the function has a v appended to the end; this version takes an array that contains the arguments (the v stands for vectored). In the Reference Section you will find an entry with more details on the glColor() function.
Most OpenGL programs that you’ll see will use glColor3f and will specify the intensity of each component as 0.0 for none or 1.0 for full intensity. However, it may be easier, if you have Windows programming experience, to use the glColor3ub version of the function. This version takes three unsigned bytes, from 0 to 255, to specify the intensities of red, green, and blue. Using this version of the function is like using the Windows RGB macro to specify a color:
glColor3ub(0,255,128) = RGB(0,255,128)
In fact, this may make it easier for you to match your OpenGL colors to existing RGB colors used by your program for other non-OpenGL drawing tasks.
Remember that the RGB macro specifies a color to Windows but does not itself set the current drawing color, as glColor does. To do this, you’d use the RGB macro in conjunction with the creation of a GDI pen or brush.