GL

OpenGL Library; API versions 1.0 and 1.1

Selection and Feedback buffers

Normally in OpenGL to use a selection buffer one would do the following:

GLuint buffer[SIZE];
glSelectBuffer(SIZE, buffer);
glRenderMode(GL_SELECT);
/* draw some stuff */
GLint count = glRenderMode(GL_RENDER);
/* parse the selection buffer */

In Python this accomplished like this:

glSelectBuffer(SIZE) # allocate a selection buffer of SIZE elements
glRenderMode(GL_SELECT)
# draw some stuff
buffer = glRenderMode(GL_RENDER)
for hit_record in buffer:
    min_depth, max_depth, names = hit_record
    # do something with the record

Feedback buffers are used in the same way except that each item in the buffer is tuple (token, value), where value is either a passthrough token or a list of vertices. Note that if glRenderMode returns a buffer than it also resets OpenGL's pointer for the corresponding buffer. This means that the buffer returned by glRenderMode is independent of future calls to glRenderMode, i.e. it will not be overwritten by any such future calls. This makes the returned buffer somewhat thread-safe. It also means that every call to glRenderMode(GL_SELECT | GL_FEEDBACK) needs to preceded by a call to glSelectBuffer or glFeedbackBuffer first, i.e. the following code will not work

glSelectBuffer(SIZE) # allocate a selection buffer of SIZE elements
glRenderMode(GL_SELECT)
# draw some stuff
buffer = glRenderMode(GL_RENDER)
# do another selection
glRenderMode(GL_SELECT)
# draw some stuff
buffer = glRenderMode(GL_RENDER)

Instead one must

glSelectBuffer(SIZE) # allocate a selection buffer of SIZE elements
glRenderMode(GL_SELECT)
# draw some stuff
buffer = glRenderMode(GL_RENDER)
# do another selection
glSelectBuffer(SIZE) allocate a new selection buffer
glRenderMode(GL_SELECT)
# draw some stuff
buffer = glRenderMode(GL_RENDER)

In previous versions of PyOpenGL in order to perform selection one would use the glSelectWithCallback function. This function is still available, but the only thing that it does in addition to the method described above is setup the projection matrix using gluPickMatrix.

Array Routines

Each call which sets an array pointer, such as glVertexPointer, will have many variants. First there will a function which is identical that of the specification. For the pointer argument one should pass a string. Also note that the stride values are used.

Next there will a set of functions named

glXPointer{ub|b|us|s|ui|i|f|d}

These will usually take as a single argument a multidimensional array of values. The type argument is controlled by the suffix of the function (ub is unsigned byte, etc.) All other arguments are derived from the dimensions of the array.

So for glColorPointer we have:

glColorPointer(size, type, stride, pointer) -> None
glColorPointerub(pointer[][]) -> None
glColorPointerb(pointer[][]) -> None
glColorPointerus(pointer[][]) -> None
glColorPointers(pointer[][]) -> None
glColorPointerui(pointer[][]) -> None
glColorPointeri(pointer[][]) -> None
glColorPointerf(pointer[][]) -> None
glColorPointerd(pointer[][]) -> None

This same decoration strategy is used for other array functions besides glXPointer. For instance, glDrawElements has the Python binding:

glDrawElements(mode, count, type, indices) -> None

where indices is expected to be a string. There are also the decorated bindings

glDrawElementsub(mode, indices[]) -> None
glDrawElementsus(mode, indices[]) -> None
glDrawElementsui(mode, indices[]) -> None

where "indices" is now a single dimensional array.

When calling a glColorPointer, glVertexPointer, etc. Python needs to allocate memory to store the values that OpenGL needs. This memory is reference counted and takes into account function calls like glPushClientAttrib and glPopClientAttrib. To force this memory to be released one just need to make a call glColorPointerub(None).

Currently glPushClientAttrib will always set the GL_CLIENT_VERTEX_ARRAY_BIT flag as glPopClientAttrib has no way of knowing that flag was set and the state of the flag is needed to know whether or not to decrement the pointer locks on the allocated memory. This may change in the future. That said, surrounding array use glPushClientAttrib/glPopClientAttrib is a good way to force the release of any allocated memory, but make sure that all calls to glXPointer, etc. are within the ClientAttrib block if you chose to use this scheme.

Note

Since all the memory allocation is automatic there is no need for glGetPointerv function, so it is excluded.

Note

The function glInterleavedArrays is also present, but it does not have the variants that the others do (i.e., no glInterleavedArraysf)

Warning

If you write an extension module which makes calls to the pointer functions and expects to interact with PyOpenGL safely it should push the client state (from within the extension) before and after array use.

Image Routines

glDrawPixels and the other image/texturing functions have much the same decoration scheme as the array functions. For glDrawPixels there is the standard function which expects a string as the pixel data:

glDrawPixels(width, height, format, type, pixels) -> None

This function will respect the parameters set by glPixelStore{i|f}. There is also a collection of variants which take a multidimensional array as the data source and set glPixelStore{i|f} automatically. For example:

glDrawPixelsub(format, pixels) -> None

Notice that width and height are inferred from the pixel data and the type is GLubyte.

Error Handling

In OpenGL the current error status is retrieved with the function glGetError. This function returns an error code and clears the current error status at the same time. On some distributed systems multiple errors may be generated at a time. In that case it is necessary to call glGetError multiple times.

PyOpenGL does not expose the glGetError. Instead it automatically checks the error status and throws an instance of GL.GLerror on an error. This is a more "Pythonic" approach. GL.GLerror is a subclass of EnvironmentError and has a errno and msg like EnvironmentError. In the case of multiple errors the errno attribute will be set to a tuple of error numbers and msg will be a concatenation of the error messages for each error.