I love OpenGL. Whenever I want to do some real-time 3D stuff, OpenGL is the API of my choice because of its simplyness and platform-independence. But honestly, OpenGL can also be a bitch sometimes. For example, there is no portable way of using textures with non-power-of-two dimensions. Another major annoyance is the way »modern« extensions are handled. To use recent technology like shaders, you need C header files that contain all definitions of the new functions, constants and so on. Annoyingly, these aren’t available in some development environments: Out-of-the-box OpenGL support ends at version 1.1 in both MSVC and my favourite dev system, lcc-win32. So you have to get the headers from somewhere else – OpenGL.org‘s only comment to this is »get it from you graphics hardware vendor«. Maybe you could really get it there if you are brave enough and download the ATI or nVidia SDKs, which are 350 MB each. But the headers aren’t enough for actually getting started: You can’t just call those fancy functions like
glCompileShaderARB, because there are no library bindings for them. Instead, you have to politely ask your OpenGL implementation for pointers to each used function via
There is actually an »instant solution« for this: It’s called GLEW, the OpenGL Extensions Wrangler Library. You just call
glewInit on initialization, and off you go. This is fine if you are going to write a full-fledged OpenGL-powered application. But what I am going to do is write 4k or 64k intros, and a shared library like GLEW just isn’t feasible under these conditions. So I devised some kind of a minimalistic alternative to GLEW, which is not quite as comfortable, but allows for much smaller code.
Generating the header file
While looking around in GLEW’s source code distribution, I noticed that the header file is actually automatically generated from a bunch of »extension specifications« that contain all constants and function prototypes for a specific extension. Some scripts in GLEW then transform these specs into a header file that almost, but not completely, fits my needs. So I wrote another header file generator:
glext.py generates a nice
glext.h that contains a nice feature missing in GLEW’s and SGI’s extension header file: Function declarations. This means that not only a type declaration (like
PFNGLCOMPILESHADERARBPROC) matching the function’s signature is generated, but also a cocrete declaration like
extern PFNGLCOMPILESHADERARBPROC glCompileShaderARB;.
Loading the function pointers
The header file is enough to satisfy the compiler – a call to
glCompileShaderARB will be translated into a lookup of an externally declared function pointer of that name. But of course, the linker will whine about an unresolved reference. Consequently, a function pointer instance is required for every used function.
This task is accomplished by another script,
extfuncs.py. It takes a list of all required functions and generates a C source code file containing declarations for all needed functions. Furthermore, a C function named
glextInit will be generated that actually performs the
GetProcAddress calls to fill in the variables. This function has to be called from the executing program once after OpenGL initialization.
The list of required functions mentioned above can be derived in either of two ways:
extfuncs.py can scan an arbitrary set of files for OpenGL function calls. For example, »
python extfuncs.py *.c« will generate an
extfuncs.c that works for all function references found in the source files of the current directory. If no parameter is specified,
extfuncs.py only scans a single file:
extfuncs.lst. This file may contain any text, only the OpenGL function names found therein are important. Thus, putting the linker error messages (»undefined reference to …«) into this file will work :)
I put together a quick example, mainly made of older code from me, with shader stuff from a very nice tutorial I found on the net. And what can I say – it works as expected :)
- glext.zip (119k) – the toolchain and example program decribed above (lcc-win32 required)