next up previous contents
Next: 21. List of Demo Up: 20. Using OpenGL Extensions Previous: 20.4 Portably Using OpenGL

20.5 Win32's Scheme for Getting Extension Function Pointers

Most OpenGL implementations support extension commands just like core commands. Assuming your OpenGL header file provides the function prototypes and enumerants for the extension you want to use, you simply compile your executable assuming the extension routines exist. The assumption then is that before calling any extension routines, your program will first check the GL_EXTENSIONS string value to verify that the OpenGL extension is supported. If the extension is supported, you can then safely call the extension's routines and use its enumerants. If not supported, your program must avoid usting the extension.

In the case of using an extension's new routines, this works because most operating systems today support flexible shared libraries. A shared library delays the binding of a routine name to its executable function until the routine is first called when your program runs. This is known as a run-time link instead of a compile-time link. A problem occurs if you call an OpenGL extension routine that is not supported by your OpenGL run-time library. The result is a run-time link error that is generally a fatal program error. This is why it is so important to check the GL_EXTENSIONS string before using any extension. If you have first verified the extension is supported, then your program can safely call the extension's routines in full expectation that the system's run-time linker will invoke the extension routine correctly.

Unfortunately, the world's most popular operating system does not work so nicely. Win32 operating systems require special care to invoke OpenGL extension routines. Win32 programs using OpenGL link with a Microsoft-supplied shared library called OPENGL32.DLL. Because the library is supplied by Microsoft, OpenGL hardware vendors are not at liberty to change it to add extensions. Instead, OpenGL hardware vendors implement another hidden shared library known as an ICD or Installable Client Driver. When an ICD is installed the OPENGL32.DLL library passes most OpenGL calls directly to the driver. Unfortunately, because extension routines are not present in the OPENGL32.DLL shared library that OpenGL programs actually link with, is no way for the Win32 run-time linker to call the driver's extension routine automatically. The bottom line is that this makes using extensions more difficult in the Win32 environment.

The EXT_bgra example above showing how to safely detect and use the extension at run-time and compile-time is straightforward because the EXT_bgra simply adds two new enumerants (GL_BGRA_EXT and GL_BGR_EXT) and does not require any new routines.

Using an extension that includes new function call entry-points is harder in Win32 because you must first explicitly request the function pointer from the OpenGL ICD before you can call the OpenGL function.

The EXT_point_parameters extension provides eye-distance attenuation of OpenGL's point primitive. Section 17.9.2 discusses the extension as a means to render particle systems. Indeed, the extension is used by Id Software in Quake 2 for rendering particle systems. With the extension, firing weapon and explosions are rendered as huge clusters of OpenGL point primitives with OpenGL automatically adjusting the point size based on the distance of the particles from the viewer. Closer particles appear bigger; particles in the distance appear smaller. A particle whose size would be smaller than a pixel is automatically faded based on its sub-pixel size. Anyone that wants to see the improvement this extension brings to a 3D game should play Quake 2 on a PC with an OpenGL driver supporting the EXT_point_parameters extension. Start a gun battle and check out the particles!

The EXT_point_parameters extension adds two new OpenGL entry points called glPointParameterfEXT() and glPointParameterfvEXT(). These routines allow the application to specify the attenuation equation parameters and fade threshold. As explained, because of the way Microsoft chose to support OpenGL extension functions, an OpenGL application cannot simply link with these functions. The application must first use the wglGetProcAddress routine to query the function address and then call through the returned address to call the extension function.

First, declare function prototype typedefs that match the extension's entry points. For example:

#ifdef _WIN32
               (GLenum pname, GLfloat param);
               (GLenum pname, const GLfloat *params);

Your <GL/gl.h> header file may already have these typedefs declared if your <GL/gl.h> defines the GL_EXT_point_parameters macro. Now declare global variables of the type of these function prototype typedefs like this:

#ifdef _WIN32

The names above exactly match the extension's function names. Once we use wglGetProcAddress to assign these function variables the address of the OpenGL driver's extension functions, we can call glPointParameterfEXT() and glPointParameterfvEXT() as if they were normal functions. You pass wglGetProcAddress the name of the routine as an ASCII string. Verify that the extension is supported and, if so, initialize the function variables like this:

  int hasPointParams = isExtensionSupported("GL_EXT_point_parameters");
#ifdef _WIN32
  if (hasPointParams) {
Note that before the code above is called, you should have a current OpenGL rendering context.

With the function variables properly initialized to the extension entry-points, you can use the extension like this:

  if (hasPointParams) {
    static GLfloat quadratic[3] = { 0.25, 0.0, 1/60.0 };
    glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, quadratic);
    glPointParameterfEXT(GL_POINT_FADE_THRESHOLD_SIZE_EXT, 1.0);

Be careful because the function returned by wglGetProcAddress is only guaranteed to work for the pixel format type of the OpenGL rendering context that was current when wglGetProcAddress was called. If you have multiple contexts created for different pixel formats, then keeping a single function addresses in a global variable as shown above may create problems. You may need to maintain distinct function addresses on a per-pixel format basis. Specifically, the Microsoft documentation for wglGetProcAddress warns:

The [Microsoft] OpenGL library supports multiple implementations of its functions. Extension functions supported in one rendering context are not necessarily available in a separate rendering context. Thus, for a given rendering context in an application, use the function addresses returned by the wglGetProcAddress function only.

The spelling and the case of the extension function pointed to by string must be identical to that of a function supported and implemented by OpenGL. Because extension functions are not exported by OpenGL, you must use wglGetProcAddress to get the addresses of vendor-specific extension functions.

The extension function addresses are unique for each pixel format. All rendering contexts of a given pixel format share the same extension function addresses.

Win32's requirement that you use wglGetProcAddress is a real drag, but if you do everything right, using OpenGL extensions works and gives you access to amazing new OpenGL features. And let's be honest; wglGetProcAddress is hardly the only annoying and awkward thing about programming with the Win32 API. Still, by using the C preprocessor and coding carefully, you actually can write OpenGL programs that use OpenGL extensions and compile from the same source code for both UNIX and Win32 environments.

next up previous contents
Next: 21. List of Demo Up: 20. Using OpenGL Extensions Previous: 20.4 Portably Using OpenGL
David Blythe