PyOpenGL uses the wrapper generator SWIG to convert wrapper descriptions (interfaces) into Python extension modules. In order to add to PyOpenGL you need SWIG 1.3a5 which available at the SWIG homepage. If you haven't used SWIG before then you might consider playing with it a bit before you contemplate trying to contribute to PyOpenGL.
PyOpenGL makes extensive use of the SWIG typemap feature. Chances are that you won't have to write any complex typemaps yourself as most these have probably already been created to support the GL module, etc. You may have to write some simple scalar typemaps.
You probably won't have to modify the build system to add a module unless the module needs some external library or such. To add a module just put the interface file (.i extension) in the interface directory. For example, GL.ARB.multitexture goes into interface/GL/ARB/multitexture.i.
Here are some lines common to every interface file (using the GLUT module as an example)
/* # BUILD api_versions [1, 2, 5, 7, 9, 11, 13] # BUILD macro_template 'GLUT_XLIB_IMPLEMENTATION >= %(api_version)d' # BUILD headers ['GL/glut.h'] # BUILD libs ['GLUT'] */ %module GLUT #define __version__ "$Revision: 1.23 $" #define __api_version__ API_VERSION #define __doc__ "http:\057\057reality.sgi.com/mjk/glut3/glut3.html" %include util.inc
First off notice that the __doc__ define uses "\057\057" and not "//". This is because the preprocessor of SWIG is a bit buggy and sometimes won't handle double slashes.
Second, notice the inclusion of the util.inc file. It defines a lot of the typemaps and such needed by PyOpenGL modules, chances are you'll need it.
PyOpenGL has the ability to support multiple versions of an API. This is accomplished by this line
# BUILD api_versions [1, 2, 5, 7, 9, 11, 13]
For each number listed in this list the build system will run SWIG with the macro API_VERSION defined to be the API version to be generated. So suppose that I want to put in a feature that is only supported in version 11 of the API. Then the function prototype in the interface would look like this:
#if API_VERSION >= 11 void foo(int bar); #endif
Note that the SWIG preprocessor also doesn't like comparisons between hexadecimal numbers so don't use this
#ifdef API_VERSION >= 0xb
When the generated C code for the interface is compiled it needs to pick out the right code for API version that is supported. Usually the API version is defined by some macro in the header file which defines the API. For instance, GLUT has the macro GLUT_XLIB_IMPLEMENTATION. In order to test this macro first the build system needs to know what header the macro is located in. This is accomplished by the
# BUILD headers ['GL/glut.h']
line. The build system also needs to know how to make a comparison on the macro. This is accomplished by the
# BUILD macro_template 'GLUT_XLIB_IMPLEMENTATION >= %(api_version)d'
line. The string defined by the macro template line should be a Python format string. The substitution names allowed are api_version_underscore which splits the API_VERSION into high word and low word separated by an underscore, and api_version which is just API_VERSION as an integer. api_version_underscore is useful for macros like GL_VERSION_1_1.
If the API that you are wrapping defines structures or classes which need to be exposed than you need to use the "shadow" feature of SWIG. I won't go into all the details of how this feature works here. To see an example of its use look at the WGL module. To turn on shadowing use this line:
# BUILD shadow 1
There are other "BUILD" headers allowed by PyOpenGL. Here are some examples:
To only build the module on GLX platforms:
# BUILD gl_platforms ['GLX']
To specify what libraries the module needs:
# BUILD libs = ['GLUT']
Note that the names in the in the libs header are platform independent names. The setup script transforms these into a platform specific name or names. For example on Win32, GLUT = glut32.
One nice feature of Python is the docstring feature. SWIG does not support this natively, but PyOpenGL has a workaround to enable their use. To add a docstring to a function call "foo" just include in the interface the line:
DOC(foo, "foo() -> bar")
PyOpenGL doesn't expose the glGetError function, instead it throws a GL.GLerror exception. To turn on the GL exception handler you need a line like this:
GL_EXCEPTION_HANDLER()
Some GL commands are designed to run between a glBegin and a glEnd. For these it is not possible to call glGetError, so before these functions you need this:
EXCEPTION_HANDLER()
To restore the ordinary exception handler just call GL_EXCEPTION_HANDLER again.
WGL, AGL, etc. need their own OS specific exception handler, so you'll need use the SWIG %except command. Look at the WGL module for an example.