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:

The Demo

I've created a simple demo to show you some extensions in action. As you can see from Figure 1, the demo itself is fairly simple, nothing more than a light moving above a textured surface, casting a light on it using a lightmap. The demo isn't interactive at all. I kept it simple because I wanted to be able to focus on the extension mechanism.


Figure 1: Basic lightmapping (click to enlarge)

The demo uses seven different extensions. Some of them aren't strictly necessary, but I wanted to include enough to get the point across. Table 2 lists all of the extensions in use, and how they are used.

Table 2 - Extensions used in the demo
Extension    Usage
ARB_multitexture The floor in this demo is a single quad with two textures applied to it: one for the bricks, and the other for the lightmap, which is updated with the light's position. The textures are combined using modulation.
EXT_point_parameteters When used, this extension causes point primitives to change size depending on their distance from the eye. You can set attenuation factors to determine how much the size changes, as well as define maximum and minimum sizes, and even specify that the points become partially transparent if they go below a certain threshold. The yellow light in the demo takes advantage of this extension. The effect is subtle, but you should be able to notice it changing size.
EXT_swap_control Most OpenGL drivers allow the user to specify whether or not screen redraws should wait for the monitor's vertical refresh, or vertical sync. If this is enabled, your game's framerate will be limited to whatever the monitor refresh rate is set to. This extension allows you to programmatically disable vsync to get to avoid this limitation.
EXT_bgra Since the demo uses Targas for textures, using this extension allows it to use their data directly without having to swap the red and blue components before creating the textures.
ARB_texture_compression    Since the demo only uses two textures, it won't gain much by using texture compression, but since it's easy, so I used it anyway. I allow the drivers to compress the data for me, rather than doing so myself beforehand.
EXT_texture_edge_clamp Again, this extension wasn't strictly necessary, but the demo shows how easy it is to use.
SGIS_generate_mipmap GLU provides a function, gluBuild2DMipMaps, that allows you to specify just the base level of a mipmap chain and automatically generates the other levels for you. This extension performs essentially the same function, with a couple of exceptions. One, it is a little more efficient. Two, it will cause all of the mipmap levels to be regenerated automatically whenever you change the base level. This can be useful when using dynamic textures.

The full source code to the demo is included on the CD, but there are a couple of functions that I want to look at.

The first is InitializeExtensions(). This function is called at startup, right after the rendering context is created. It verifies that the extensions used are supported, and gets the function entry points that are needed.

bool InitializeExtensions()
{
  if (CheckExtension("GL_ARB_multitexture"))
  {
    glMultiTexCoord2f = (PFNGLMULTITEXCOORD2FARBPROC)
        wglGetProcAddress("glMultiTexCoord2fARB");
    glActiveTexture = (PFNGLCLIENTACTIVETEXTUREARBPROC)
        wglGetProcAddress("glActiveTextureARB");
    glClientActiveTexture = (PFNGLACTIVETEXTUREARBPROC)
        wglGetProcAddress("glClientActiveTextureARB");
  }
  else
  {
    MessageBox(g_hwnd, "This program requires multitexturing, which "
      "is not supported by your hardware", "ERROR", MB_OK);
    return false;
  }

  if (CheckExtension("GL_EXT_point_parameters"))
  {
    glPointParameterfvEXT = (PFNGLPOINTPARAMETERFVEXTPROC)
        wglGetProcAddress("glPointParameterfvEXT");
  }

  if (CheckExtension("WGL_EXT_swap_control"))
  {
    wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)
        wglGetProcAddress("wglSwapIntervalEXT");
  }

  if (!CheckExtension("GL_EXT_bgra"))
  {
    MessageBox(g_hwnd, "This program requires the BGRA pixel storage"
      "format which is not supported by your hardware", "ERROR", MB_OK);
    return false;
  }

  g_useTextureCompression =
      CheckExtension("GL_ARB_texture_compression");
  g_useEdgeClamp = CheckExtension("GL_EXT_texture_edge_clamp");
  g_useSGISMipmapGeneration =
      CheckExtension("GL_SGIS_generate_mipmap");

  return true;
}

As you can see, there are two extensions that the demo requires: multitexturing and BGRA pixel formats. Although I could have provided alternate ways to do both of these things, doing so would have unnecessarily complicated the program. The point parameter and swap control extensions aren't required, so I don't exit if they aren't present. Instead, where they are used, I check to see if the function pointer is invalid (i.e., set to NULL). If so, I simply don't use the extension. I use a similar approach with the texture compression, texture edge clamp, and generate mipmap extensions. Since all three of these extensions only introduce new enumrants, I set global flags to indicate whether or not they are supported. When they are used, I check the flag, and if they aren't supported, I use an alternate method. For texture compression, I just use the normal pixel format, for texture edge clamp, I use normal clamping instead, and if the generate mipmaps extension isn't supported, I use gluBuild2DMipmaps() instead.

The other function I want to look at is the CheckExtension() function, which is used repeatedly by InitializeExtensions().

bool CheckExtension(char* extensionName)
{
  // get the list of supported extensions
  char* extensionList = (char*) glGetString(GL_EXTENSIONS);

  if (!extensionName || !extensionList)
    return false;

  while (*extensionList)
  {
    // find the length of the first extension substring
    unsigned int firstExtensionLength = strcspn(extensionList, " ");


    if (strlen(extensionName) == firstExtensionLength &&
      strncmp(extensionName, extensionList, firstExtensionLength) == 0)
    {
      return true;
    }

    // move to the next substring
    extensionList += firstExtensionLength + 1;
  }

  return false;
}

This function gets the extensions string, and then parses each full extension name string from it, comparing each to the requested extension. Notice that I'm finding each string by looking for the next space to be sure that I don't accidentally match a substring.

Also, this function doesn't check for WGL extensions at all, although it could easily be modified to do so. The code in the demo is not intended to be optimal, nor is it intended to be the "best" way to use extensions. Some people like to make extension function pointers global, as I have done, so that they can be used just like core OpenGL functions anywhere in your program. Others like to put class wrappers around them. Use whatever means you prefer. The demo was intentionally kept as straightforward as possible so that you could easily understand it and take out the parts that interest you.

What You've Learned

You've now seen you how you can use OpenGL's extensions to use the latest features offered by modern video cards. You've learned what some of these features are, and how your game can benefit from them. You've also seen ways in which you can get the most out of extensions without unnecessarily limiting your target audience.

Where To Go Now

I've given you an overview of the features available in OpenGL 1.2, 1.3, and through extensions. I've only been able to cover a few of them in detail. Fortunately, the web is full of resources to help get you started with using these features. The developer sections of the NVIDIA and ATI websites in particular are full of whitepapers, presentations, and demos. In addition, I've found the following websites to be quite useful.

http://www.nutty.org
http://romka.demonews.com
http://www.delphi3d.net

And of course, the front page of OpenGL.org is a great resource for finding links to pages containing OpenGL tutorials and demos.

Conclusion

Now that you have a basic understanding of extensions, I encourage you to spend some time researching them and experimenting on your own. You may find that some of them enable you to significantly improve the efficiency and visual quality of your games.

Acknowledgements

I'd like to thank Alexander Heiner and Mark Shaxted for reviewing this article and correcting some minor inaccuracies, as well as suggesting ways to make it more complete. I'd also like to thank my wife Melissa for making me look like a better writer than I really am.

References

[1] Mark Kilgard, "All About Extensions", http://www.opengl.org/developers/code/features/OGLextensions/OGLextensions.html
[2] NVIDIA Corporation, NVIDIA Developer Relations, http://developer.nvidia.com/
[3] ATI Technologies, ATI Developer Relations, http://www.ati.com/na/pages/resource_centre/dev_rel/devrel.html
[4] OpenGL Architectural Review Board, OpenGL 1.3 Specification, http://www.opengl.org/developers/documentation/specs.html



Dave Astle is the Executive Producer and one of the cofounders of GameDev.net. He is the coauthor of OpenGL Game Programming, has contributed to several other books, and has spoken at game industry conferences such as the Game Developers Conference. He has several years of game industry experience, and is currently a senior engineer on the Graphics and Gaming team at QUALCOMM, Inc. in San Diego, CA.


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