Contributing
Prev | Chapter 4. Internals | Next

## Contributing

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.

### The Build System

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`.

### Interface Files

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.

#### Docstrings

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")

#### Exception Handlers

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.

Prev | Home | Next
Porting | Up | Appendix A. Changes