Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
46 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:

Using Extensions

Finally, it's time to learn what you need to do to use an extension. In general, there are only a couple of steps you need to take:

  • determine whether or not the extension is supported
  • obtain the entry point for the any of the extension's functions that you want to use
  • define any enumerants you're going to use.

Let's look at each of these steps in greater detail.

Caution: Before checking for extension availability and obtaining pointers to functions, you MUST have a current rendering context. In addition, the entry points are specific to each rendering context, so if you're using more than one, you'll have to obtain a separate entry point for each.

Querying the Name String

In order to find out whether or not a specific extension is available, first get the list of all the name strings supported by the OpenGL implementation. To do this, you just need to call glGetString() using GL_EXTENSIONS, like so:

char* extensionsList = (char*) glGetString(GL_EXTENSIONS);

After this executes, extensionsList points to a null-terminated buffer containing the name strings of all the extensions available to you. These name strings are separated by spaces, including a space after the last name string.

I'm casting the value returned by glGetString() because the function actually returns an array of unsigned chars. Since most of the string manipulation functions I'll be using require signed chars, I do the cast once now instead of doing it many times later.

To find out whether or not the extension you're looking for is supported, you'll need to search this buffer to see if it includes the extension's name string. I'm not going to go into great detail about how to parse the buffer, since there are many ways to do so, and it's something that at this stage in your programming career, you should be able to do without much effort. One thing you need to watch out for, though, is accidentally matching a substring. For example, if you're trying to use the EXT_texture_env extension, and the implementation doesn't support it, but it does support EXT_texture_env_dot3, then calling something like:

strstr("GL_EXT_texture_env", extensionsList);

is going to give you positive results, making you think that the EXT_texture_env extension is supported, when it's really not. The CheckExtension() function in the demo program included with this article shows one way to avoid this problem.

Obtaining the Function's Entry Point

Because of the way Microsoft handles its OpenGL implementation, calling a new function provided by an extension requires that you request a function pointer to the entry point from the ICD. This isn't as bad as it sounds.

First of all, you need to declare a function pointer. If you've worked with function pointers before, you know that they can be pretty ugly. If not, here's an example:

void (APIENTRY * pglCopyTexSubImage3DEXT) (GLenum, GLint, GLint,
    GLint, GLint, GLint, GLint, GLsizei, GLsizei) = NULL;
Update 4/24/03: For the book, and initially here, I used the function name (i.e. glCopyTexSubImage3DEXT) as the pointer name. A reader pointed out to me that on a number of operating systems (e.g. Linux) this can cause serious problems, so it should be avoided. Thanks, Ian!

Now that we have the function pointer, we can attempt to assign an entry point to it. This is done using the function wglGetProcAddress():

PROC wglGetProcAddress( LPCSTR  lpszProcName );

The only parameter is the name of the function you want to get the address of. The return value is the entry point of the function if it exists, or NULL otherwise. Since the value returned is essentially a generic pointer, you need to cast it to the appropriate function pointer type.

Let's look at an example, using the function pointer we declared above:

pglCopyTexSubImage3DEXT  =
    (void (APIENTRY *) (GLenum, GLint, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei))
    wglGetProcAddress("glCopyTexSubImage3DEXT");

And you thought the function pointer declaration was ugly.

You can make life easier on yourself by using typedefs. In fact, you can obtain a header called "glext.h" which contains typedefs for most of the extensions out there. This header can usually be obtained from your favorite hardware vendor (for example, NVIDIA includes it in their OpenGL SDK), or from SGI at the following URL:

http://oss.sgi.com/projects/ogl-sample/ABI/glext.h

Using this header, the code above becomes:

PFNGLCOPYTEXSUBIMAGE3DEXTPROC pglCopyTexSubImage3DEXT = NULL;
pglCopyTexSubImage3DEXT = (PFNGLCOPYTEXSUBIMAGE3DEXTPROC) wglGetProcAddress("glCopyTexSubImage3DEXT");

Isn't that a lot better?

As long as wglGetProcAddress() doesn't return NULL, you can then freely use the function pointer as if it were a normal OpenGL function.

Declaring Enumerants

To use new enumerants defined by an extension, all you have to do is define the enumerant to be the appropriate integer value. You can find this value in the extension specification. For example, the specification for the EXT_texture_lod_bias says that GL_TEXTURE_LOD_BIAS_EXT should have a value of 0x8501, so somewhere, probably in a header (or possibly even in gl.h), you'd have the following:

#define GL_TEXTURE_LOD_BIAS_EXT    0x8501

Rather than defining all these values yourself, you can use the glext.h header, mentioned in the last section, since it contains all of them for you. Most OpenGL programmers I know use this header, so don't hesitate to use it yourself and save some typing time.

Win32 Specifics

In addition to the standard extensions that have been covered so far, there are some extensions that are specific to the Windows system. These extensions provide additions that are very specific to the windowing system and the way it interacts with OpenGL, such as additional options related to pixel formats. These extensions are easily identified by their use of "WGL" instead of "GL" in their names. The name strings for these extensions normally aren't included in the buffer returned by glGetString(GL_EXTENSIONS), although a few are. To get all of the Windows-specific extensions, you'll have to use another function, wglGetExtensionsStringARB(). As the ARB suffix indicates, it's an extension itself (ARB_extensions_string), so you'll have to get the address of it yourself using wglGetProcAddress(). Note that for some reason, some ICDs identify this as wglGetExtensionsStringEXT() instead, so if you fail to get a pointer to one, try the other. The format of this function is as follows:

const char* wglGetExtensionsStringARB(HDC hdc);
Caution: Normally, it's good practice to check for an extension by examining the buffer returned by glGetString() before trying to obtain function entry points. However, it's not strictly necessary to do so. If you try to get the entry point for a non-existant function, wglGetProcAddress() will return NULL, and you can simply test for that. The reason I'm mentioning this is because to use wglGetExtensionsStringARB(), that's exactly what you have to do. It appears that with most ICDs, the name string for this extension, WGL_ARB_extensions_string, doesn't appear in the buffer returned by glGetString(). Instead, it is included in the buffer returned by wglGetExtensionsStringARB()! Go figure.

Its sole parameter is the handle to your rendering context. The function returns a buffer similar to that returned by glGetString(GL_EXTENSIONS), with the only difference being that it only contains the names of WGL extensions.

Some WGL extension string names included in the buffer returned by wglGetExtensionsStringARB() may also appear in the buffer returned by glGetString(). This is due to the fact that those extensions existed before the creation of the ARB_extensions_string extension, and so their name strings appear in both places to avoid breaking existing software.

Just as there is a glext.h header for core OpenGL extensions, so is there a wglext.h for WGL extensions. You can find it at the following link:

http://oss.sgi.com/projects/ogl-sample/ABI/wglext.h



OpenGL 1.2 and 1.3

Contents
  Introduction
  OpenGL Extensions
  Using Extensions
  OpenGL 1.2 and 1.3
  Writing Well-Behaved Programs
  Demo & Conclusion

  Source code
  Printable version
  Discuss this article