< Previous PageNext Page > Hide TOC

Setting Up Function Pointers to OpenGL Routines

Function pointers to OpenGL routines allow you to deploy your application across multiple versions of Mac OS X regardless of whether the entry point is supported at link time or runtime. This practice also provides support for code that needs to run cross-platform—in both Mac OS X and Windows.

Note: If you are deploying your application only in Mac OS X v10.4 or later, you do not need to read this chapter. Instead, consider the alternative, which is to set the gcc attribute that allows weak linking of symbols. Keep in mind, however, that weak linking may impact your application's performance. For more information, see Frameworks and Weak Linking.

This appendix discusses the tasks needed to set up and use function pointers as entry points to OpenGL routines:

In this section:

Obtaining a Function Pointer to an Arbitrary OpenGL Entry Point
Initializing Entry Points


Obtaining a Function Pointer to an Arbitrary OpenGL Entry Point

Getting a pointer to an OpenGL entry point function is fairly straightforward from either Cocoa or Carbon. In either framework in Mac OS X, you can use the Dynamic Loader function NSLookupAndBindSymbol to get the address of an OpenGL entry point. The Dynamic Loader is part of the system framework, not part of Cocoa, which is why NSLookupAndBindSymbol (declared in /usr/include/mach-o/dyld.h) works in Mach-O Carbon applications as well as Cocoa ones. Carbon applications also have the option of using the AGL API, although this approach involves a bit more code. You'll see how to use both approaches in this section.

Keep in mind that getting a valid function pointer means that the entry point is exported by the OpenGL framework; it does not guarantee that a particular routine is supported and valid to call from within your application. You still need to check for OpenGL functionality on a per-renderer basis as described in “Detecting Functionality.”

Listing B-1 shows how to use NSLookupAndBindSymbol from within the function MyNSGLGetProcAddress. When provided a symbol name, this application-defined function returns the appropriate function pointer from the global symbol table. A detailed explanation for each numbered line of code appears following the listing.

Listing B-1  Using NSLookupAndBindSymbol to obtain a symbol for a symbol name

#import <mach-o/dyld.h>
#import <stdlib.h
#import <string.h>
void * MyNSGLGetProcAddress (const char *name)
{
    NSSymbol symbol;
    char *symbolName;
    symbolName = malloc (strlen (name) + 2); // 1
    strcpy(symbolName + 1, name); // 2
    symbolName[0] = '_'; // 3
    symbol = NULL;
    if (NSIsSymbolNameDefined (symbolName)) // 4
        symbol = NSLookupAndBindSymbol (symbolName);
    free (symbolName); // 5
    return symbol ? NSAddressOfSymbol (symbol) : NULL; // 6
}

Here's what the code does:

  1. Allocates storage for the symbol name plus an underscore character ('_'). The underscore character is part of the UNIX C symbol-mangling convention, so make sure that you provide storage for it.

  2. Copies the symbol name into the string variable, starting at the second character, to leave room for prefixing the underscore character.

  3. Copies the underscore character into the first character of the symbol name string.

  4. Checks to make sure that the symbol name is defined, and if it is, looks up the symbol.

  5. Frees the symbol name string because it is no longer needed.

  6. Returns the appropriate pointer if successful, or NULL if not successful. Before using this pointer, you should make sure that is it valid.

Using the AGL API to obtain a function pointer for an OpenGL entry point requires that you get a Core Foundation bundle reference. As a result, you need to perform a bit of set up work before you make the critical call to the Core Foundation function CFBundleGetFunctionPointerForName, as you'll see by looking at the code in Listing B-2. This code requires Carbon and is designed for use with Mach-O and CFM Carbon applications. You would use this approach only if you need to support older versions of your application. If your application runs only in Mac OS X, it should be a Mach-O application. A detailed explanation for each numbered line of code appears following the listing.

Listing B-2  Using AGL to get a function pointer for an entry in the OpenGL framework

 #include <Carbon/Carbon.h>
CFBundleRef gBundleRefOpenGL = NULL;
 
OSStatus MyAGLInitEntryPoints (void)
{
    OSStatus err = noErr;
    const Str255 frameworkName = "\pOpenGL.framework"; // 1
    FSRefParam fileRefParam;
    FSRef fileRef;
    CFURLRef bundleURLOpenGL;
 
    memset (&fileRefParam, 0, sizeof(fileRefParam)); // 2
    memset (&fileRef, 0, sizeof(fileRef));
    fileRefParam.ioNamePtr  = frameworkName; // 3
    fileRefParam.newRef = &fileRef;
    err = FindFolder (kSystemDomain, kFrameworksFolderType, false,
                            &fileRefParam.ioVRefNum,  &fileRefParam.ioDirID);// 4
    if (noErr != err) {
        DebugStr ("\pCould not find frameworks folder");
        return err;
    }
    err = PBMakeFSRefSync (&fileRefParam); // 5
    if (noErr != err) {
        DebugStr ("\pCould make FSRef to frameworks folder");
        return err;
    }
   bundleURLOpenGL = CFURLCreateFromFSRef (kCFAllocatorDefault,&fileRef); // 6
    if (!bundleURLOpenGL) {
        DebugStr ("\pCould not create OpenGL Framework bundle URL");
        return paramErr;
    }
    gBundleRefOpenGL = CFBundleCreate(kCFAllocatorDefault, bundleURLOpenGL); // 7
    if (!gBundleRefOpenGL) {
        DebugStr ("\pCould not create OpenGL Framework bundle");
        return paramErr;
    }
    CFRelease (bundleURLOpenGL); // 8
    if (!CFBundleLoadExecutable (gBundleRefOpenGL)) { // 9
        DebugStr ("\pCould not load Mach-O executable");
        return paramErr;
    }
    return err;
}
 
void MyAGLDeAllocEntryPoints (void) // 10
{
    if (gBundleRefOpenGL != NULL) {
        CFBundleUnloadExecutable (gBundleRefOpenGL);
        CFRelease (gBundleRefOpenGL);
        gBundleRefOpenGL = NULL;
    }
}
 
void * MyAGLGetProcAddress (char * pszProc) // 11
{
    return CFBundleGetFunctionPointerForName (gBundleRefOpenGL,
                CFStringCreateWithCStringNoCopy (NULL,
                         pszProc, CFStringGetSystemEncoding (), NULL) );
}

Here's what the code does:

  1. Declares a string for the framework name (OpenGL.framework), which is where you need to search for OpenGL function.

  2. Sets up a buffer for the framework name. The next line does the same for the file reference.

  3. Assigns the framework and then the file reference.

  4. Finds the OpenGL framework directory; handles the error condition if the folder isn't found.

  5. Creates an FSRef data structure for the OpenGL framework directory and handles an error condition should one occur.

  6. Creates a Core Foundation URL from the FSRef data structure and handles an error condition should one occur.

  7. Creates a Core Foundation bundle reference to the OpenGL framework and handles an error condition should one occur.

  8. Releases the Core Foundation URL because it is no longer needed.

  9. Loads the bundle.

  10. Performs necessary clean up work.

  11. Gets a function pointer for an OpenGL entry point.

Initializing Entry Points

Listing B-3 shows how to use the MyNSGLGetProcAddress function from Listing B-1 to obtain a few OpenGL entry points. A detailed explanation for each numbered line of code appears following the listing.

Listing B-3  Using NSGLGetProcAddress to obtain an OpenGL entry point

#import "MyNSGLGetProcAddress.h" // 1
static void InitEntryPoints (void);
static void DeallocEntryPoints (void);
 
// Function pointer type definitions
typedef void (*glBlendColorProcPtr)(GLclampf red,GLclampf green,
                        GLclampf blue,GLclampf alpha);
typedef void (*glBlendEquationProcPtr)(GLenum mode);
 typedef void (*glDrawRangeElementsProcPtr)(GLenum mode, GLuint start,
                GLuint end,GLsizei count,GLenum type,const GLvoid *indices);
 
glBlendColorProcPtr pfglBlendColor = NULL; // 2
glBlendEquationProcPtr pfglBlendEquation = NULL;
glDrawRangeElementsProcPtr pfglDrawRangeElements = NULL;
 
static void InitEntryPoints (void) // 3
{
    pfglBlendColor = (glBlendColorProcPtr) MyNSGLGetProcAddress
                                    ("glBlendColor");
    pfglBlendEquation = (glBlendEquationProcPtr)MyNSGLGetProcAddress
                                ("glBlendEquation");
    pfglDrawRangeElements = (glDrawRangeElementsProcPtr)MyNSGLGetProcAddress
                                ("glDrawRangeElements");
}
// -------------------------
static void DeallocEntryPoints (void) // 4
{
    pfglBlendColor = NULL;
    pfglBlendEquation = NULL;
    pfglDrawRangeElements = NULL;;
}

Here's what the code does:

  1. Imports the header file that contains the MyNSGLProcAddress function from Listing B-1.

  2. Declares function pointers for the functions of interest. Note that each function pointer uses the prefix pf to distinguish it from the function it points to. Although using this prefix is not a requirement, it's best to avoid using the exact function names.

  3. Initializes the entry points. This function repeatedly calls the MyNSGLProcAddress function to obtain function pointers for each of the functions of interest—glBlendColor, glBlendEquation, and glDrawRangeElements.

  4. Sets each of the function pointers to NULL when they are no longer needed.

Listing B-4 demonstrates how to use the function aglGetProcAddress to obtain a few OpenGL entry points. Note that the approach used by this code is similar to that used in Listing B-3. A detailed explanation for each numbered line of code appears following the listing.

Listing B-4  Using AGL to obtain an OpenGL entry point

#include "MyAGLGetProcAddress.h" // 1
 
static OSStatus InitEntryPoints (void);
static void DeallocEntryPoints (void);
 
typedef void (*glBlendColorProcPtr)(GLclampf red,GLclampf green,
                        GLclampf blue,GLclampf alpha); // 2
typedef void (*glBlendEquationProcPtr)(GLenum mode);
typedef void (*glDrawRangeElementsProcPtr)(GLenum mode,GLuint start,
                        GLuint end,GLsizei count,GLenum type,
                        const GLvoid *indices);
 
glBlendColorProcPtr pfglBlendColor = NULL; // 3
glBlendEquationProcPtr pfglBlendEquation = NULL;
glDrawRangeElementsProcPtr pfglDrawRangeElements  = NULL;
 
static OSStatus InitEntryPoints (void)
{
    OSStatus err = MyAGLInitEntryPoints(); // 4
    if (noErr == err) { // 5
        pfglBlendColor = (glBlendColorProcPtr)
                    MyAGLGetProcAddress ("glBlendColor");
        pfglBlendEquation = (glBlendEquationProcPtr)
                    MyAGLGetProcAddress ("glBlendEquation");
        pfglDrawRangeElements = (glDrawRangeElementsProcPtr)
               MyAGLGetProcAddress("glDrawRangeElements");
    }
    return err;
}
 
static void DeallocEntryPoints (void)
{
    pfglBlendColor = NULL; // 6
    pfglBlendEquation = NULL;
    pfglDrawRangeElements = NULL;
    MyAGLDellocEntryPoints (); // 7
}

Here's what the code does:

  1. Imports the header file that contains the MyAGLGetProcAdress function from Listing B-2.

  2. Declares function pointers for the functions of interest.

  3. Initializes each function pointer to NULL.

  4. Calls the initialization function defined in Listing B-2.

  5. After checking for an error condition, obtains the function pointers for the functions of interest by calling the MyAGLGetProcAddress function defined in Listing B-2.

  6. Sets each of the function pointers to NULL when they are no longer needed.

  7. Deallocates the function pointers when they are no longer needed by calling the deallocation function defined in Listing B-2.



< Previous PageNext Page > Hide TOC


© 2004, 2008 Apple Inc. All Rights Reserved. (Last updated: 2008-06-09)


Did this document help you?
Yes: Tell us what works for you.
It’s good, but: Report typos, inaccuracies, and so forth.
It wasn’t helpful: Tell us what would have helped.