Chapter 7. Vertex Processing Extensions

This chapter describes how to use the following OpenGL vertex processing extensions:

The following groups of obsolete (legacy) vertex processing extensions are also briefly described:

The legacy extensions are supported for compatibility and are not fully documented in this guide.

ARB_vertex_buffer_object—The Vertex Buffer Object Extension

The ARB_vertex_buffer_object extension allows applications to store buffers containing application-defined data in graphics memory and to draw vertex arrays using data contained in those buffers, instead of the usual vertex array usage where array data is taken from application memory.

Why Use Buffer Objects?

When drawing vertex arrays using unextended OpenGL 1.3, all data in the arrays must be transferred from application memory to the graphics processor. In Onyx4 and Silicon Graphics Prism systems (as well as all other modern graphics systems), the bandwidth between application memory and the graphics processor (typically over an interface like PCI-X or AGP) is substantially lower than the bandwidth between the graphics processor and its own local graphics memory. Therefore, when drawing vertex array data repeatedly with no changes or only small changes relative to the size of the arrays, substantial performance increases can be realized by storing vertex arrays in graphics memory. It is impossible to reach the maximum vertex transformation rates supported by the graphics processor unless vertex data is being supplied from graphics memory.

This extension provides an explicit mechanism for creating and managing data buffers in graphics memory by defining portions of those buffers as vertex arrays and drawing vertices using those arrays.

Alternatives to Buffer Objects

In the past, optimization advice often included the use of OpenGL display lists to encapsulate drawing commands. Display lists can also be stored in graphics memory and provide similar performance benefits. However, display lists cannot be modified once they are created; even the simplest change to a list requires destroying and re-creating its entire contents. Also, it is considerably more difficult for the graphics library to recognize and optimize display lists, because they can contain arbitrary sequences of OpenGL commands, not just array data.

While Onyx4 and Silicon Graphics Prism systems do perform display list optimizations, new applications should use buffer objects if possible. Buffer objects are more easily optimized, and individual elements of a buffer object can be modified without needing to re-create the entire buffer in graphics memory.

Another approach to high-performance drawing operations used in the past is for the application to hint to the graphics library that its vertex arrays will not be modified for some period of time by locking portions of the currently bound vertex arrays (see section “EXT_compiled_vertex_array—The Compiled Vertex Array Extension”). Locking allows the graphics library to copy vertex array data into graphics memory for the duration of the lock. However, any changes to vertex array data requires the expensive operations of unlocking, changing, and re-locking the array. Also, only a single set of vertex arrays can be locked at a time; therefore, if multiple arrays are used for drawing, the performance benefits of locking are lost.

While Onyx4 and Silicon Graphics Prism systems do support locking vertex arrays, new applications should use buffer objects if possible. Multiple buffer objects can be defined and switched without swapping buffer data out of graphics memory and, as just described, individual elements of buffer objects can easily be modified.

Disadvantages of Buffer Objects

While buffer objects are the easiest and most reliable way to achieve maximum geometry throughput, graphics memory is usually a much more limited resource than application memory. Typically graphics processors have only 256–512 MB of graphics memory, and that memory must be shared among the framebuffer, texture, display lists, and buffer object storage.

If an application's use of graphics memory exceeds the amount physically present in the system, data may be automatically swapped out when not in use. This can result in greatly reduced performance and, in extreme cases, may result in applications terminating due to excessive graphics memory use. Examples where such situations are likely to arise include applications using many 2D image textures, using large 3D textures for volume rendering, or using large vertex arrays for drawing high-complexity models. In such cases, applications can achieve better performance by managing the swapping of texture and buffer data into graphics memory manually instead of relying on the automatic algorithms supported within the graphics library. However, such buffer management can be difficult to tune. A recommended alternative is to use higher-level scene graph APIs built on OpenGL, like OpenGL Performer and OpenGL Volumizer. These software layers are optimized to achieve maximum performance on Silicon Graphics systems while still supporting very large datasets.

Using Buffer Objects

As shown in the following code lines, buffer objects are represented by object names (of type GLuint) which are managed in exactly the same fashion as texture and display list names with routines for allocating unused buffer object names, deleting named buffer objects, and testing if a name refers to a valid buffer object:

void glGenBuffersARB(GLsizei n, GLuint *buffers);
void glDeleteBuffersARB(GLsizei n, const GLuint *buffers);
GLboolean glIsBufferARB(GLuint buffer);

 Note that when deleting a buffer object with glDeleteBuffersARB(), all data in graphics memory associated with that buffer object will be freed as well. Because graphics memory is usually a scarce resource compared to application memory, it is important to delete buffer objects if they are no longer needed or to reuse the memory associated with buffer objects.

Defining Buffer Objects

Once a buffer object name has been obtained from glGenBuffers(), the corresponding buffer object can be created by making the following call:

void glBindBufferARB(GLenum target, GLuint buffer);

The argument buffer is the buffer object name, and target is either GL_ARRAY_BUFFER_ARB (for vertex array data) or GL_ELEMENT_ARRAY_BUFFER_ARB (for array index data). The newly created buffer object is initially defined with a size of zero.

You can also use glBindBufferARB() to bind an existing buffer object. If the bind is successful, no change is made to the state of the newly bound buffer object and any previous binding to target is broken.

While a buffer object is bound, operations on the target to which it is bound affect that object, and queries of the target return information about that object.

Initially, the reserved buffer object name 0 is bound to each of GL_ARRAY_BUFFER_ARB and GL_ELEMENT_ARRAY_BUFFER_ARB. However, there is no buffer object corresponding to the name 0, and any attempt to operate on or query the GL_ARRAY_BUFFER_ARB or GL_ELEMENT_ARRAY_BUFFER_ARB target when it is bound to zero will generate errors. This is because binding to zero is used to indicate that normal vertex array behavior should apply, as described further later in section “Using Buffer Objects as Vertex Array Sources”.

Defining and Editing Buffer Object Contents

Buffer objects contain the same data that a normal OpenGL vertex array would contain, and the data is laid out in the same fashion. However, instead of simply providing a pointer to vertex array data in application memory, the contents of buffer objects must be explicitly defined.

Once a valid buffer object has been bound, define its contents by making the following call:

void glBufferDataARB(GLenum target, GLsizeiptrARB size, const void *data,
                     GLenum usage);

target 

If the buffer contents are to be used for vertex array data (for example, vertices, normals, texture coordinates, etc.), then target must be GL_ARRAY_BUFFER_ARB. If the contents are to be used for vertex index data (for example, indices into vertex array data), then target must be GL_ELEMENT_ARRAY_BUFFER_ARB. This target is described further later in the section “Using Buffer Objects as Vertex Array Sources”.

data 

A pointer to the buffer data in application memory. The argument data may be NULL, in which case the buffer object size is set as specified, but its contents remain undefined.

size 

The length of data in basic machine units (bytes). The type of size is the new C type GLsizeiptrARB. This type is an unsigned integer type guaranteed to be large enough to represent the largest possible object in application memory.

usage 

Provides a hint as to the expected usage pattern of the buffer being defined. The following are the valid usage hints:

GL_STREAM_DRAW_ARB 

Buffer contents will be specified once by the application and used at most a few times as the source of a drawing command.

GL_STREAM_READ_ARB  

Buffer contents will be specified once by reading data from OpenGL and queried at most a few times by the application.

GL_STREAM_COPY_ARB 

Buffer contents will be specified once by reading data from OpenGL and used at most a few times as the source of a drawing command.

GL_STATIC_DRAW_ARB  

Buffer contents will be specified once by the application and used many times as the source for drawing commands.

GL_STATIC_READ_ARB 

Buffer contents will be specified once by reading data from OpenGL and queried many times by the application.

GL_STATIC_COPY_ARB  

Buffer contents will be specified once by reading data from OpenGL and used many times as the source for drawing commands.

GL_DYNAMIC_DRAW_ARB 

Buffer contents will be respecified repeatedly by the application and used many times as the source for drawing commands.

GL_DYNAMIC_READ_ARB  

Buffer contents will be respecified repeatedly by reading data from OpenGL and queried many times by the application.

GL_DYNAMIC_COPY_ARB 

Buffer contents will be respecified repeatedly by reading data from OpenGL and used many times as the source for drawing commands.

The most common usage patterns for buffer objects being used as vertex array or element sources are the following:

GL_STATIC_DRAW_ARB  

Used for unchanging objects. This usage is similar to creating display lists that will be called many times.

GL_DYNAMIC_DRAW_ARB 

Used for objects whose contents may be edited repeatedly.

Many of the usage patterns are only expected to be relevant for future extensions built on ARB_vertex_buffer_object that use the same buffer object mechanism for other purposes, such as pixel or video data.

To edit (update) the contents of an existing buffer object by changing only part of the buffer contents, make the following call:

void glBufferSubDataARB(GLenum target, GLintptrARB offset, GLsizeiptrARB
                        size, const void *data);

The arguments target, data, and size specify the buffer object target to be affected, a pointer to the updated data block in application memory, and the length of the data block to replace in the buffer in the same fashion as the corresponding parameters of glBufferDataARB().

The argument offset specifies the start of the range of data to replace in the buffer object in basic machine units relative to the beginning of the buffer being modified. The type of offset is the new C type GLintptrARB. This type is an integer type guaranteed to be large enough to represent the largest possible offset to an element of a buffer in application memory.

Elements offset through (offset + size – 1) in the buffer object bound to target are replaced by the corresponding elements in application memory starting at data. An error is generated if offset is less than zero, or if (offset + size) is greater than the size of the buffer object.

Mapping Buffer Objects to Application Memory

An alternate method for editing buffer objects is to map them into application memory by making the following call:

void *glMapBufferARB(GLenum target, GLenum access);

If the buffer object bound to target can be successfully mapped, a pointer to the buffer contents is returned; otherwise, a GL_OUT_OF_MEMORY error will be generated.

The argument access must be one of GL_READ_ONLY_ARB, GL_WRITE_ONLY_ARB, or GL_READ_WRITE_ARB. It specifies which operations may be performed on the buffer while it is mapped. The most common access pattern for buffer objects being used as vertex array sources is GL_WRITE_ONLY_ARB. It indicates that small parts of the buffer may be updated, but nothing will be read from the buffer.

While a buffer object is mapped, no OpenGL operations may refer to the mapped data either by issuing drawing commands that would refer to data in the mapped buffer object or by passing pointers within the mapped region to other OpenGL commands. Also, glBufferSubData() may not be called while the corresponding buffer object is mapped.

After modifying mapped buffer object contents and before using that buffer object as a source or sink for OpenGL, unmap the buffer object by making the following call:

GLboolean glUnmapBufferARB(GLenum target);

If glUnmapBufferARB() returns GL_FALSE, it indicates that values in the buffer object's data have become corrupted (usually as the result of a screen resolution change or another event that affects graphics memory). In this case, the buffer object contents are undefined.


Note: Mapping buffer objects into application memory may be a very inefficient way to modify their contents especially when performing indirect rendering, and such mapping has several possible failure modes caused by external events such as resolution changes. If possible, use glBufferSubData() to update buffer contents instead.


Using Buffer Objects as Vertex Array Sources

Once you create a buffer object and define its contents, you can use it as a source for array drawing operations. When any of the commands defining an array pointer (including those in the following list) is called while a buffer object is bound, the interpretation of the pointer argument to that command is changed:

  • glColorPointer()

  • glEdgeFlagPointer()

  • glIndexPointer()

  • glNormalPointer()

  • glTexCoordPointer()

  • glVertexPointer()

  • glFogCoordPointerEXT(), if the EXT_fog_coord extension is supported

  • glSecondaryColorPointerEXT(), if the EXT_secondary_color extension is supported

  • glVertexAttribPointerARB(), if the ARB_vertex_program extension is supported

  • glWeightPointerARB(), if the ARB_vertex_blend extension is supported

Instead of being interpreted as a pointer to data in application memory, the pointer is interpreted as an offset within the currently bound buffer object.

After defining a particular array pointer in this fashion and when the corresponding array is enabled, all vertex array drawing operations (for example, those in the following list) will read data from the corresponding buffer object instead of from application memory:

  • glArrayElement()

  • glDrawArrays()

  • glDrawElements()

  • glDrawRangeElements()

  • glMultiDrawArrays()

  • glMultiDrawElementsEXT()

Once an array pointer is defined as an offset within a buffer object, the buffer object may be unbound, but the array pointer will continue to refer to that buffer object until it is redefined. This allows different array pointers to refer to different buffer objects, as well as to application memory. However, for maximum performance, all enabled array pointers should refer to buffer objects, both because any access to application memory while drawing is likely to limit performance due to bandwidth constraints and the complexity of mixing arrays from application and buffer object memory may throw the OpenGL implementation onto a slower and more complex code path.

When specifying array pointers as offsets within buffer objects, the application must convert an integer offset, expressed in basic machine units into a pointer argument. For this purpose, it is useful to define a macro like the following:

#define BUFFER_OFFSET(offset) ((char *)NULL + (offset))

For example, suppose that the bound buffer object contains an array of packed 3-component, floating point normal data and you wish to set the normal pointer to the 64th element of this array. In this case, the offset in basic machine units would be 64 * 3 * sizeof(GLfloat). Therefore, you would make the following call:

glNormalPointer(3, GL_FLOAT, 0,
                BUFFER_OFFSET(64 * 3 * sizeof(GLfloat)));

Using Buffer Objects as Array Indices

In addition to storing vertex array data in buffer objects, array indices may also be stored. These indices are normally specified as pointer arguments to the array drawing commands glDrawElements(), glDrawRangeElements(), and (if the EXT_multi_draw_arrays extension is supported) glMultiDrawElementsEXT(). By storing both array data and array indices in buffer objects, indexed drawing operations do not need to refer to application memory ever once they are set up. This enables maximum performance.

Array indices in buffer objects are defined using the same calls as for array data—for example, glBindBufferARB(), glBufferDataARB(), etc. However, the target GL_ELEMENT_ARRAY_BUFFER_ARB must be used for indices instead of GL_ARRAY_BUFFER_ARB.

In the same fashion as the array pointer calls, if glDrawElements() or glDrawRangeElements() is called while a buffer object is bound to GL_ELEMENT_ARRAY_BUFFER_ARB, the indices argument to these calls is interpreted as an offset into the buffer object, rather than a pointer to index data in application memory. If glMultiDrawElementsEXT() is called, the indices argument is still interpreted as a pointer into application memory; however, the contents of the memory located at that pointer are then interpreted as an array of offsets into the buffer object, rather than an array of pointers into application memory.

Querying Data in Buffer Objects

To query part or all of the contents of a buffer object, make the following call:

void glGetBufferSubDataARB(GLenum target, GLintptrARB offset,
                           GLsizeiptrARB size, void *data);

The argumemts target, offset, and size have the same meaning as the corresponding arguments of glBufferSubDataARB(); they specify the target to be queried and the range of data within the buffer object bound to that target to return. The returned data is copied to the region of application memory referenced by data.

Buffer object contents may not be queried while an object is mapped; calls to glGetBufferSubDataARB() will generate a GL_INVALID_OPERATION error in this case.

Sample Code

The following code fragment defines two buffer objects, fills them with data interpreted respectively as vertex coordinates and vertex colors, and draws a triangle using the data contained in the buffer objects.

#define BUFFER_OFFSET(offset) ((char *)NULL + (offset))

/* Vertex coordinate and color data to place in buffer objects */
GLfloat vertexData[] = { -1.0,  1.0,  0.0,
                         -1.0, -1.0,  0.0,
                          1.0, -1.0,  0.0 };
GLfloat colorData[] = {  0.0,  0.0,  0.0,
                         1.0,  0.0,  0.0,
                         1.0,  1.0,  0.0 };

/* Names of the vertex and color buffer objects */
GLuint vertexBuffer, colorBuffer;

/* Generate two unused buffer object names */
glGenBuffersARB(1, &vertexBuffer);
glGenBuffersARB(1, &colorBuffer);

/* Bind the first buffer object and fill it with vertex data */
glBindBufferARB(GL_ARRAY_BUFFER, vertexBuffer);
glBufferDataARB(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);

/* Bind the second buffer object and fill it with color data */
glBindBufferARB(GL_ARRAY_BUFFER, colorBuffer);
glBufferDataARB(GL_ARRAY_BUFFER, sizeof(colorData), colorData, GL_STATIC_DRAW);

/* Enable vertex and color arrays for drawing */
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);

/* Set the vertex array pointer to the start of the vertex buffer object */
glBindBufferARB(GL_ARRAY_BUFFER, vertexBuffer);
glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0));

/* Set the color array pointer to the start of the color buffer object */
glBindBufferARB(GL_ARRAY_BUFFER, colorBuffer);
glColorPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0));

/* Unbind the array buffer target, since all enabled array
 * pointers have now been set.
 */
glBindBufferARB(GL_ARRAY_BUFFER, 0);

/*
 * Everything up to this point is initialization. Now the application
 * can enter its drawing loop.
 */

while (!drawingLoopDone()) {
    /* Perform input and per-loop processing, if required */
    doLoopProcessing();

    /* Draw the triangle defined by the vertex and color buffer objects */
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
}

/*
 * When the drawing loop is complete, buffer objects should be deleted.
 */

/* Disable the vertex and color arrays */
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);

/* Free data contained in the buffer objects, and delete the objects */
glDeleteBuffersARB(1, vertexBuffer);
glDeleteBuffersARB(1, colorBuffer);

New Functions

The ARB_vertex_buffer_object extension introduces the following functions:

  • glBindBufferARB()

  • glBufferDataARB()

  • glBufferSubDataARB()

  • glDeleteBuffersARB()

  • glGenBuffersARB()

  • glGetBufferSubDataARB()

  • glIsBufferARB()

  • glMapBufferARB()

  • glUnmapBufferARB()

ARB_window_pos—The Window-Space Raster Position Extension

The ARB_window_pos extension provides a set of functions to directly set the raster position in window coordinates. This extension bypasses the model-view and projection matrices and the viewport-to-window mapping.

Why Use the Window-Space Raster Position Extension?

When drawing two-dimensional geometry, applications often want to have pixel-precise control of where pixels are drawn on the screen. Normally when specifying the current raster position, the raster position specified by the application is treated in the same fashion as a vertex: it is transformed by the model-view and projection matrices and then sent through the viewport-to-window mapping to arrive at a window-space raster position.

While it is possible to set the raster position to a specific window-space location using the conventional mechanism, doing so requires careful setup of the transformation matrices and viewport mapping. Also, if the projected window-space raster position is outside the window bounds, it may be marked invalid so that nothing will be drawn by glDrawPixels(), even though this effect may be desirable (for drawing pixel images that are partially outside the window but whose visible regions are still drawn).

This extension introduces a mechanism for directly setting the raster position in window-space coordinates and ensuring that the resulting raster position will always be valid even if it is outside the window.

Using the Window-Space Raster Position Extenstion

The current raster position may be defined in window space with any of the following calls:

void 
glWindowPos2sARB(GLshort x, GLshort y);
void 
glWindowPos2iARB(GLint x, GLint y);
void 
glWindowPos2fARB(GLfloat x, GLfloat y);
void 
glWindowPos2dARB(GLdouble x, GLdouble y);
void 
glWindowPos3sARB(GLshort x, GLshort y, GLshort z);
void 
glWindowPos3iARB(GLint x, GLint y, GLint z);
void 
glWindowPos3fARB(GLfloat x, GLfloat y, GLfloat z);
void 
glWindowPos3dARB(GLdouble x, GLdouble y, GLdouble z);

In the glWindowPos2*() forms of this call, only the x and y raster position coordinates are specified, and raster position z is always set to zero. In the glWindowPos3*() forms, x, y, and z are all specified.

The following are the vector forms of these calls;

void 
glWindowPos2svARB(const GLshort *pos);
void 
glWindowPos2ivARB(const GLint *pos);
void 
glWindowPos2fvARB(const GLfloat *pos);
void 
glWindowPos2dvARB(const GLdouble *pos);
void 
glWindowPos3svARB(const GLshort *pos);
void 
glWindowPos3ivARB(const GLint *pos);
void 
glWindowPos3fvARB(const GLfloat *pos);
void 
glWindowPos3dvARB(const GLdouble *pos);

In the glWindowPos2*vARB() forms of this call, the argument is a pointer to a two-element vector specifying x and y, and the raster position z is always set to zero. In the glWindowPos3*vARB() forms, the argument is a pointer to a three-element vector specifying x, y, and z.

For all forms of glWindowPos*(), associated data (raster color, texture coordinates, etc.) for the current raster position is taken from the current state values in the same fashion as for glRasterPos*(). However, lighting, texture coordinate generation, and clipping are not performed by glWindowPos*().

New Functions

The ARB_window_pos extesnion introduces the 16 functions listed in preceding section.

EXT_clip_volume_hint—The Clip Volume Hint Extension

The EXT_clip_volume_hint extension provides a mechanism for applications to indicate that they do not require clip volume clipping for primitives. It allows applications to maximize performance in situations where they know that clipping is unnecessary.

Why Use Clip Volume Hints?

Clipping geometry to the clip volume can decrease performance, and is not always needed. In many situations, applications can determine that part or all of the geometry being rendered lies entirely inside the clip volume; in other words, that such geometry will never be clipped. This is typically done by testing bounding boxes around application geometry against the clip volume. While such tests might in principle be done using OpenGL features such as the NV_occlusion_query extension, it is usually best to simply compare bounding boxes against the plane equations defining the clip volume entirely in the application code.

Using Clip Volume Hints

To hint that clip volume clipping does not need to be performed, call glHint() with a target of CLIP_VOLUME_CLIPPING_HINT_EXT and a mode of GL_FASTEST. To hint that clip volume clipping must be performed, use a mode of GL_NICEST instead.

As with all hints, the clip volume hint is only an indication and the OpenGL implementation may not respect the hint when set to GL_FASTEST. However, if large amounts of geometry can easily be tested to confirm that they need not be clipped, then there may be performance gains in using the hint particularly when using multiple user-defined clipping planes.

EXT_compiled_vertex_array—The Compiled Vertex Array Extension

The EXT_compiled_vertex_array extension defines an interface which allows static (unchanging) vertex arrays in application memory to be cached, pre-transformed, or pre-compiled.

Why Use Compiled Vertex Arrays?

Compiled vertex arrays may be used to cache the transformed results of array data for reuse by several glDrawArrays(), glArrayElement(), or glDrawElements() commands. For example, you might get better performance when drawing a large mesh of quadrilaterals one strip at a time, where each successive strip shares half its vertices with the previous strip. It also allows transferring array data to faster memory for more efficient processing.

Using compiled vertex arrays is an optimization technique that should be used only when porting old code that already uses client-side vertex arrays for drawing. Whenever possible in new applications, use buffer objects instead (see “ARB_vertex_buffer_object—The Vertex Buffer Object Extension”).

Compiled vertex arrays should be used only when executing multiple vertex array drawing commands that collectively refer multiple times to most of the elements in the locked range. The performance benefits of using compiled vertex arrays with very small vertex arrays (consequently, not reusing many elements) are unlikely to be worthwhile.

Using Compiled Vertex Arrays

To use compiled vertex arrays, follow these steps:

  1. Identify the range of elements of the currently bound vertex arrays that may be reused in subsequent drawing operations

  2. Make the following call:

    void glLockArraysEXT(GLint first, GLsizei count);
    

    The argument first specifies a starting element index and count specifies the number of elements to lock. Elements first through ( first + count – 1) of all enabled vertex arrays will be locked.

  3. Render geometry using glDrawArrays(), glDrawElements(), or other vertex array drawing commands.

    While vertex arrays are locked, changes made to array contents by an application may not be reflected in any vertex array drawing commands. Furthermore, vertex array drawing commands that refer to array elements outside the locked range have undefined results.

  4. When finished drawing data in the locked ranges, make the following call:

    void glUnlockArraysEXT(void);
    

    This unlocks all arrays; subsequent changes to vertex arrays are properly reflected by drawing commands, and the restriction of drawing only elements within the locked range is lifted.

New Functions

The EXT_compiled_vertex_array extension introduces the following functions:

  • glLockArraysEXT()

  • glUnlockArraysEXT()

EXT_fog_coord—The Fog Coordinate Extension

The EXT_fog_coord extension introduces the fog coordinate, a new per-vertex attribute, which may be used in fog computation in place of the fragment's eye distance.

Why Use Fog Coordinates?

Normally, when fog is enabled, the fog factor computed for each fragment is based on the distance from the camera to the fragment. This distance is fed into one of three parameterized fog models (linear, exponential, or exponential-squared), as selected by parameters to glFog*().

Fog models based only on fragment distance do not provide a level of control sufficient for effects such as patchy fog. By specifying arbitrary per-vertex values as input to the fog model rather than fragment distance, applications can produce more sophisticated and realistic fog models.

Using Fog Coordinates

To select use of either the fog coordinate or the fragment eye distance when computing fog, specify the fog coordinate source by making the following call:

glFogi(GL_FOG_COORDINATE_SOURCE_EXT, param);

If param is GL_FOG_COORDINATE_EXT, the fog coordinate is used in fog computations. If param is GL_FRAGMENT_DEPTH_EXT, the fragment eye distance is used. Initially fragment eye distance is used.

Fog coordinates are interpolated over primitives in the same fashion as colors, texture coordinates, and other vertex attributes. When drawing immediate-mode geometry, the current fog coordinate is specified by calling one of the following functions:

void glFogCoordfEXT(GLfloat coord);
void glFogCoorddEXT(GLdouble coord);
void glFogCoordfvEXT(GLfloat *coord);
void glFogCoorddvEXT(GLdouble *coord);

The fog coordinate may also be specified when drawing using vertex arrays. An array of per-vertex fog coordinates is defined by making the following call:

void glFogCoordPointerEXT(GLenum type, GLsizei stride, const GLvoid *ptr);

The argument type specifies the type of data in the array and must be either GL_FLOAT or GL_DOUBLE. The argument stride specifies the offset in basic machine units from one fog coordinate to the next in the array starting at ptr. As with other vertex array specification calls, a stride of zero indicates that fog coordinates are tightly packed in the array.

To enable or disable fog coordinates when drawing vertex arrays, call glEnableClientState() or glDisableClientState() with parameter GL_FOG_COORDINATE_ARRAY_EXT.

Querying the Fog Coordinate State

The current fog coordinate can be queried by calling glGetFloatv() with parameter name GL_CURRENT_FOG_COORDINATE_EXT. Parameters of the fog coordinate vertex array pointer can be queried by calling glGetIntegerv() with parameter name GL_FOG_COORDINATE_ARRAY_TYPE_EXT or GL_FOG_COORDINATE_ARRAY_STRIDE_EXT and calling glGetPointerv() with parameter name GL_FOG_COORDINATE_ARRAY_POINTER_EXT.

New Functions

The EXT_fog_coord extension introduces the following functions:

  • glFogCoordfEXT()

  • glFogCoorddEXT()

  • glFogCoordfvEXT()

  • glFogCoorddvEXT()

  • glFogCoordPointerEXT()

EXT_multi_draw_arrays—The Multiple Draw Arrays Extension

The EXT_multi_draw_arrays extension defines two functions that allow multiple groups of primitives to be rendered from the same vertex arrays.

Why Use Multiple Draw Arrays?

When drawing many small, disjoint geometric primitives from a single set of vertex arrays, a separate call to glDrawArrays() or glDrawElements() is required for each primitive. This can be inefficient due to the setup required for each call. Using this extension, multiple disjoint ranges of vertex arrays can be drawn in a single call. This reduces the setup overhead and code complexity.

Using Multiple Draw Arrays

When drawing more than one range of data from a set of vertex arrays, where each such range is a contiguous group of elements in the arrays, make the following call:

void glMultiDrawArraysEXT(GLenum mode, const GLint *first,
                          const GLsizei *count, GLsizei primcount);

This is equivalent to the following multiple calls to glDrawArrays():

for (int i = 0; i < primcount; i++) {
    if (count[i]) > 0)
        glDrawArrays(mode, first[i], count[i]);
}

When drawing more than one range of data, where each range is defined by a contiguous range of indices, make the following call:

void glMultiDrawElementsEXT(GLenum mode, const GLsizei *count,
                   GLenum type, const GLvoid **indices, GLsizei primcount);

 This is equivalent to the following multiple calls to glDrawElements();

for (int i = 0; i < primcount; i++) {
    if (count[i]) > 0)
        glDrawElements(mode, count[i], type, indices[i]);
}

The ith element of the count array is the number of array indices to draw, and the ith element of the index array is a pointer to the array indices. All indices must be of the same specified type.

New Functions

The EXT_multi_draw_arrays extension introduces the following functions:

  • glMultiDrawArraysEXT()

  • glMultiDrawElementsEXT()

EXT_secondary_color—The Secondary Color Extension

The EXT_secondary_color extension introduces the secondary color, a new per-vertex attribute. When lighting is disabled, the secondary color may be added to the color resulting from texturing. In unextended OpenGL 1.3, this color sum computation is only possible when lighting is enabled, and the secondary color used in this situation is based on the specular term of lighting equations rather than being explicitly defined by the application.

Why Use Secondary Color?

Many rendering algorithms use texture-based lighting computations rather than the builtin vertex lighting of OpenGL. While texture-based lighting is more difficult to specify, it supports arbitrary lighting models. In unextended OpenGL 1.3, the color sum hardware is not available to texture-based lighting. By introducting an explicit secondary color attribute, lighting effects such as non-textured specular highlights can easily be produced even when using texture-based lighting.

Using Secondary Color

To control the use of secondary color and color sum when OpenGL lighting is disabled, call glEnable() or glDisable() with parameter GL_COLOR_SUM_EXT.

Only the red, green, and blue components of the secondary color can be controlled; the alpha component is unused in the color sum and is assumed to be zero. Initially, the secondary color is (0,0,0).

Secondary color is interpolated over primitives in the same fashion as color. When drawing immediate-mode geometry, the current secondary color is specified by calling one of the following functions:

void 
glColor3bEXT(GLbyte red, GLbyte green, GLbyte blue);
void 
glColor3ubEXT(GLubyte red, GLubyte green, GLubyte blue);
void 
glColor3sEXT(GLshort red, GLshort green, GLshort blue);
void 
glColor3usEXT(GLushort red, GLushort green, GLushort blue);
void 
glColor3iEXT(GLint red, GLint green, GLint blue);
void 
glColor3uiEXT(GLuint red, GLuint green, GLuint blue);
void 
glColor3fEXT(GLfloat red, GLfloat green, GLfloat blue);
void 
glColor3dEXT(GLdouble red, GLdouble green, GLdouble blue);
void 
glColor3bvEXT(GLbyte *coords);
void 
glColor3ubvEXT(GLubyte *coords);
void 
glColor3svEXT(GLshort *coords);
void 
glColor3usvEXT(GLushort *coords);
void 
glColor3ivEXT(GLint *coords);
void 
glColor3uivEXT(GLuint *coords);
void 
glColor3fvEXT(GLfloat *coords);
void 
glColor3dvEXT(GLdouble *coords);

In the vector forms of these calls, coords is a three-element array containing red, green, and blue secondary color components in order. The data formats supported and interpretation of parameter values as color components are identical to the three-component glColor*() commands.

Secondary color may also be specified when drawing using vertex arrays. An array of per-vertex secondary colors is defined by making the following call:

void glSecondaryColorPointerEXT(GLint size, GLenum type, GLsizei stride,
                                const GLvoid *ptr);

 The arguments are defined as follows:

size 

Specifies the number of components per color value and must always be 3.

type 

Specifies the type of data in the array and must be one of GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_INT, GL_UNSIGNED_INT, GL_FLOAT, or GL_DOUBLE.

stride 

Specifies the offset in basic machine units from one secondary color to the next in the array starting at ptr. As with other vertex array specification calls, a stride of zero indicates that secondary colors are tightly packed in the array.

To enable or disable secondary colors when drawing vertex arrays, call glEnableClientState() or glDisableClientState() with parameter GL_SECONDARY_COLOR_ARRAY_EXT.

Querying the Secondary Color State

The current secondary color can be queried by calling glGetFloatv() with parameter name GL_CURRENT_SECONDARY_COLOR_EXT. Parameters of the secondary color vertex array pointer can be queried by calling glGetIntegerv() with one of the following parameter names and calling glGetPointerv() with parameter name GL_SECONDARY_COLOR_ARRAY_POINTER_EXT:

  • GL_SECONDARY_COLOR_ARRAY_SIZE_EXT

  • GL_SECONDARY_COLOR_ARRAY_TYPE_EXT

  • GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT

New Functions

The EXT_secondary_color extension introduces the list of functions defined in section “Using Secondary Color”.

The Vertex Array Object Extensions (Legacy)

In addition to the ARB_vertex_buffer_object extension, Onyx4 and Silicon Graphics Prism systems also support the following set of ATI vendor extensions that were developed prior to ARB_vertex_buffer_object and were the basis on which ARB_vertex_buffer_object was specified:

  • ATI_element_array

  • ATI_map_object_buffer

  • ATI_vertex_array_object

  • ATI_vertex_attrib_array_object


    Note: These four extensions are included only for support of legacy applications being ported from other platforms. They supply no functionality beyond that of ARB_vertex_buffer_object and are not as widely used. Whenever writing new code using buffer objects, always use the ARB extension.


Since these are legacy extensions, they are not documented in detail in this guide. The following table briefly describes each extension in terms of how it maps onto ARB_vertex_buffer_object:

ATI_vertex_array_object 

Defines the base functionality for creating array objects: defining usage modes and contents of array objects and defining specific vertex arrays as portions of array objects.

ATI_vertex_attrib_array_object 

Defines additional APIs for creating array objects that can contain vertex attribute data for use with the ARB_vertex_program and ARB_fragment_program extensions.

ATI_element_array 

Allows drawing array objects using arrays of indices also in array objects, analogous to the ELEMENT_ARRAY_BUFFER_ARB target supported by ARB_vertex_buffer_object.

ATI_map_object_buffer 

Allows mapping array objects into application memory, analogous to the glMapBufferARB() functionality of ARB_vertex_buffer_object.

New Functions

The legacy vertex array objects extensions introduce the following functions:

  • glArrayObjectATI()

  • glDrawElementArrayATI()

  • glDrawRangeElementArrayATI()

  • glElementPointerATI()

  • glFreeObjectBufferATI()

  • glGetArrayObjectfvATI()

  • glGetArrayObjectivATI()

  • glGetObjectBufferfvATI()

  • glGetObjectBufferivATI()

  • glGetVariantArrayObjectfvATI()

  • glGetVariantArrayObjectivATI()

  • glGetVertexAttribArrayObjectfvATI()

  • glGetVertexAttribArrayObjectivATI()

  • glIsObjectBufferATI()

  • glMapObjectBufferATI()

  • glNewObjectBufferATI()

  • glUnmapObjectBufferATI()

  • glUpdateObjectBufferATI()

  • glVariantArrayObjectATI()

  • glVertexAttribArrayObjectATI()

The Texture Coordinate Generation Extensions (Legacy)

There are two legacy texture coordinate generation extensions:

  • EXT_texgen_reflection

  • NV_texgen_reflection

The EXT_texgen_reflection extension provides two new texture coordinate generation modes that are useful in texture-based lighting and environment mapping. Differing only in the token names used, the NV_texgen_reflection provides identical functionality.


Note: The functionality defined by these extensions was later promoted into a standard part of OpenGL 1.3, and these extensions are included only for support of legacy applications being ported from other platforms. Whenever writing new code, always use the OpenGL 1.3 interface.

Since these are legacy extensions, they are not documented in detail here; only the mapping from the extension tokens to the OpenGL 1.3 tokens is defined.

EXT_texgen_reflection defines the following two new texture generation modes, according to the value of param to glTexGeni() when its pname argument is GL_TEXTURE_GEN_MODE:

  • GL_NORMAL_MAP_EXT

  • GL_REFLECTION_MAP_EXT

NV_texgen_reflection uses the following token names to define the same modes, respectively:

  • GL_NORMAL_MAP_NV

  • GL_REFLECTION_MAP_NV

In OpenGL 1.3, the mode defined by GL_NORMAL_MAP_EXT and GL_NORMAL_MAP_NV may instead be defined by GL_NORMAL_MAP. Likewise, the the mode defined by GL_REFLECTION_MAP_EXT and GL_REFLECTION_MAP_NV may instead be defined by GL_REFLECTION_MAP.