Josh,
I finally got around to implement the "correct" solution for your problem. I'm attaching a version which should work well with the base Croquet version (if not, then check the iVars in GLX which is the only problematic place). To use it, check out class GLExtManager and in particular its *CLASS* side, for reasons following.
GLExtManager classComment<printIt>
GLExtManager handles OpenGL extension functions for GLX. Since extensions are specific for particular renderer/drivers all extensions must be looked up dynamically. I provide the technical means to handle extensions transparently for any number of contexts.
Declaring Extensions: ======================== Extension functions (and constants) have to be specifically declared. To declare functions and constants for an extension you need to do the following:
#1: Go to the CLASS side of GLExtManager and add a category that has the same name as listed in glGet(GL_EXTENSIONS). For example, to use the ARB imaging extension this category must be named GL_ARB_imaging (even though the extension is referred to as 'ARB imaging' glGet will tell us that the name GL_ARB_imaging so that is what you need to use). WARNING: The name must match EXACTLY, no extra spaces, watch for small and capital letters etc.
#2: Add a method which initializes the constants in this extension. The method itself MUST follow the convention to begin with 'initialize' and should then use the extension name. E.g., for initializing the constants in the ARB_imaging it should be called 'initializeArbImaging'.
The constants itself can be initialized by just copying them from the spec describing them and use the provided utility methods for initialization (just look over a few existing extensions). I am trying to make it easy for you to just copy those constants.
Note that all constants appear ONLY in the GLExtConstants - OpenGLConstants is exclusively used for standard OpenGL constants.
#3: Add the functions the extension defines. Generally, these should just be plain ffi call methods but there are three important issues: a) NEVER provide a 'module' for these functions. Since they are looked up by opengl specific means other ways are used and you MUST NOT provide a module. The extension this particular function is contained in is defined by the category and not by the module (this is to prevent confusion about 'I have no GL_ARB_imaging.dll' or even worse the possibility that on some system any such thing even exists (!)). b) NEVER do anything but just the plain FFI call (optionally followed by a plain return or call to #externalCallFailed). The method you are writing will actually be run in an entirely different place - you are only providing a template for the sake of your convenience (and speed). If you need more sophisticated error handling do this in the place where you call the method or provide a helper in GLX or something similar, but NEVER EVER DO THIS HERE. c) The calling convention is effectively ignored. Since it is platform specific it will in fact be replaced by the appropriate OS calling convention when used.
#4: Evaluate 'GLExtManager initialize' which will add the constants to GLExtConstants.
Using Extensions: ==================== Once you declared the extension, using it is simple. Since the constants defined by the extension are accessible through the GLExtConstants pool, you can just refer to them by name.
To invoke an extension method you need to query for the GLX' extension manager called 'glExt'. The extension manager is the guy who can understand the extension functions you declared. To give an example, in order to invoke the 'glUnlockArraysEXT' function you would use something like: glx glExt glUnlockArraysEXT etc.
IMPORTANT: You must NEVER, EVER keep a reference to the extension manager. All invokations have to be done transparently through glx.
In case you wonder why you cannot use glx directly, read the implementation details (the short answer is that there are Good Reasons (tm) not to do it).
Implementation details: =========================== In order to implement the dynamic lookup mechanism in the most convenient way, the GLExtManager is always created as a 'unique subclass' of GLExtManager. That is when you ask for a new extension manager using 'GLExtManager new' you actually get a subclass of GLExtManager which is denoted by an asterisk in front of it so it looks as *GLExtManager.
The *GLExtManager does not understand any of the function you have provided. When it runs into a message which it doesn't understand it performs the following functions: 1: First it looks if that method is in fact an extension method you defined. 2: If it is, it looks if the extension this method belongs to is present in the renderer it is bound to (e.g., the GLExtManager's glx inst var) 3: If the extension is present it looks at the functions you declared for this extension, and for each function - it copies the template method - it looks up calling convention / address of the function - it installs a new ffi call spec for that method - it adds this method to *GLExtManager 4: Once all the function for the extension have been loaded it reinvokes the message which failed.
Preloading extensions: ========================= As you can see from the implementation details, there is a certain overhead involved in handling extensions. In particular, there can be a noticable speed impact when an extension is loaded 'on demand' (e.g., when a message is not understood). To compensate for this, extensions can be loaded explicitly, by using, e.g., glx glExt loadExtension: #'GL_ARB_imaging'.
BTW, if anyone needs particular extensions it would be nice if you'd add them "to the pool" so that we can all easily use them (I hate typing all this stuff).
Cheers, - Andreas