Top

Generating Source Codes for F03GL

Handling of GLUT Callbacks

Using F03GL

Character string arguments

Incompatibilities with NISTIR 6134

Compiler Notes

 

Belorussian translation

Fortran 2003 Interface to OpenGL

The F03GL library

The F03GL library provides a Fortran 2003 interface to the OpenGL library, along with the GLU and GLUT toolkits. It has been developed by Anthony Stone and Aleksandar Donev. We have already received useful feedback from several users of this library, and we are grateful for their suggestions. There is still room for improvement, and we would be glad to receive further comments and bug reports.

All the source codes associated with the F03GL library can be downloaded as a zip archive f03gl.zip or a gzipped tarfile f03gl.tgz. There is a README file which gives basic instructions for unpacking and compiling the files and running the tests. The package is distributed under the terms of the GNU General Public Licence, version 3.

F03GL uses the C Interoperability features of Fortran 2003 and binds to the C interface for OpenGL. Therefore, any system that has an OpenGL library and headers and a Fortran compiler that supports C Interoperability should be able to use this interface easily. In this sense, F03GL is different from the f90gl library by William F. Mitchell, found at http://math.nist.gov/f90gl. That library implements the official Fortran 90 OpenGL interface (as adopted by OpenGL Architecture Review Board), described in NISTIR 6134.  It uses compiler-specific wrappers in order to implement the Fortran bindings, and does not use Fortran 2003 features. The F03GL library was meant to be a very light interface to the C library, with minimal use of wrappers, and as little use of non-standard or processor-dependent features as possible. The differences between F03GL and NISTIR 6134 are described at the end of this page. The conversion of codes using the Fortran 90 interface should involve minimal effort. We have converted several of the examples from the f90gl distribution to use F03GL, and we acknowledge with thanks Dr Mitchell's permission to do so. Many additional examples of the use of OpenGL routines with Fortran and the F03GL package may be found at the dolfyn website.

Generating Source Codes for F03GL

The Fortran source codes containing modules with PARAMETER declarations, INTERFACE blocks, and some minimal wrappers are generated automatically using Perl scripts. One of our goals is to develop tools that can easily automate the conversion of C header files to Fortran MODULEs, and for this purpose we are doing work with Craig Rasmussen at LANL to develop XML stylesheets to be used for this purpose (visit the CHASM toolkit webpage). The Perl scripts themselves are not very sophisticated and contain many hacks so that they work for the OpenGL interfaces, and they can probably easily be adopted to other applications.

For the generation of the GL and GLU interfaces, instead of using the C header files GL.h and GLU.h (these are somewhat cut-back versions of relatively standard Linux gl.h and glu.h), we decided to use the authentic SGI specification of the interfaces in the files gl.spec, enum.spec, glu.spec and enumglu.spec, found at http://oss.sgi.com/projects/ogl-sample/registry. (Files mentioned here in this red sanserif font are included in the f03gl package.)

Only a couple of minor fixes were made to these files. The spec files provide more information than the C headers: for example, they give INTENT info and bounds info for array arguments, and they also document things like the OpenGL library retaining pointers for internal use. We tried to use all of this information to produce better Fortran interfaces. The Fortran codes are produced with

   spec_interfaces.pl --bozinit --PUBLIC -p . -d -m OpenGL -gl
   spec_interfaces.pl --bozinit --PRIVATE -p . -d -m OpenGL -glu

Executing spec_interfaces.pl without arguments will give a brief documentation of the main options. The most important one is the “-m” or “--module” option which decides what the prefix of the Fortran MODULE names is. If you want to replace f90gl in your codes (as we do in adopting some of its examples), the module names should be OpenGL_GL, OpenGL_GLU and OpenGL_GLUT. If you want to keep the f90gl modules and try the new F03GL library, then “-m F03GL” would be a good option. If your Fortran compiler does not support BOZ constants (hexadecimal constants of the form z"0B04") in PARAMETER statements, regenerate the interfaces without the “--bozinit” option. Otherwise, you can just use the files OpenGL_gl.f90 and OpenGL_glu.f90 in the f03gl package.

For the GLUT library, there are no spec files, and we used C header files to generate the interfaces. There are also different GLUT-like toolkit libraries and corresponding headers, namely, the original GLUT.h (again, a cut-back version of glut.h from GLUT 3.8) by Mark J. Kilgard (SGI), which is not public-domain but is free, as well as several open-source replacements, such as the FreeGLUT.h from FreeGLUT or OpenGLUT.h from OpenGLUT. We have tested the Perl script h_interfaces.pl with all of these libraries and generated the source codes OpenGL_glut.f90, OpenGL_freeglut.f90 and OpenGL_openglut.f90, using something like

   h_interfaces.pl -q --bozinit --scalar -m OpenGL -i GLUT.h

The GLUT pre-defined fonts, which are void C pointer values, cannot be handled directly in Fortran, where TYPE(C_PTR) is an opaque type that cannot be given explicit values. Also, different GLUT implementations seem to handle the fonts differently. We therefore decided to add GLUT_fonts.c and use non-constants of TYPE(C_PTR) and pre-defined fonts. This makes no visible difference to the user. The PROTECTED attribute is used to make them more constant-like, but if your compiler does not yet support that attribute simply delete it in the Perl script. Note that glutInit has been overloaded with a generic interface that allows one to omit command arguments, since these are not commonly used in Fortran codes.

Handling of GLUT Callbacks

The biggest complication is the treatment of GLUT callbacks, and in particular, turning them off. There are two ways to pass procedures (as arguments) to C in Fortran 2003: as dummy procedures, which can be given full interfaces, or as procedure pointers [i.e., TYPE(C_FUNPTR) arguments, which are generic procedure pointers]. We prefer the former since giving full interfaces helps (good) compilers verify that the user-supplied callbacks have the expected interfaces. However, it then becomes difficult to turn off the callback, which in GLUT is done by passing a NULL function pointer. In Fortran, this is best done by making the dummy procedure OPTIONAL, but this requires using wrappers since OPTIONAL arguments cannot be interoperable (yet). The user simply omits the callback argument in order to turn it off. In NISTIR 6134, and in closer conformance to the C interface, one supplies an actual argument GLUT_NULL_FUNC. The script h_interfaces.glutnullfunc.pl generates an interface which uses some non-conforming tricks to make this work while still preserving the checking of callback interfaces. Some may prefer to make the callbacks TYPE(C_FUNPTR) and call the GLUT C functions directly without the wrappers (the interfaces for these are already generated by the Perl scripts), but we do not encourage this since it requires changing the calling sequence (one has to put C_FUNLOC in the actual argument list instead of simply passing the callback procedure as an actual), and will lead to incompatibilites among the codes of different users of F03GL.

Character string arguments

In F03GL, the string arguments are passed as character arrays [CHARACTER(C_CHAR), DIMENSION(*)], in agreement with the F03 standard, rather than as character strings [CHARACTER(KIND=C_CHAR, LEN=*)]. The F03 standard has special hacks that allow for strings to be passed as actual arguments, but a null character (C_CHAR_NULL) is not appended automatically but rather needs to be manually appended. We provide, in OpenGL_gl.f90, a helper routine CString that converts a string to a null-terminated character array. User codes need to change strings such as "text" in actual argument lists with CString("text")

Using F03GL

If the Fortran sources with the OpenGL modules compile successfully, the next step is testing them. The program
RandomSphere_OpenGLUT.f90 provides a tutorial-style test program. This program uses some of the most useful new Free/OpenGLUT features, which are emulated with classical GLUT in RandomSphere_GLUT.f90. We have also adapted some of the test examples from f90gl to work with f03gl. Execute the script Script.sh in the f03gl directory, first setting the COMPILER environment variable to the appropriate compiler command. The examples have been tested with nagfor, gfortran and ifort. For compiler-dependent details see the compiler notes. Further examples may be found at the dolfyn website.

Incompatibilities with NISTIR 6134

Here is a list of incompatibilities with NISTIR 6134.

  1. The names of the modules may be OpenGL_XXX if the user wants to replace f90gl, but otherwise they should be F03GL_XXX.
  2. F03GL does not deal with processors lacking short types. It merely defines, for example, GLshort=C_SHORT, where C_SHORT is a kind parameter defined in the F2003 intrinsic ISO_C_BINDING module. It may be -1 if the processor does not support the kind in question, which means that programs using this kind parameter simply will not compile. This is probably less of a problem today since almost all relevant processors support the C set of standard integer types.
  3. GLboolean are INTEGER(GLboolean)=INTEGER(C_SIGNED_CHAR) rather than LOGICAL, according to the F2003 standard. LOGICAL(C_BOOL) interoperates only with C99’s _Bool. For other “logicals” in C (quotes because they are really integer types anyway), one should use INTEGER.
  4. char becomes CHARACTER(KIND=C_CHAR), following F2003. On almost all, if not all, processors, this is the same as default CHARACTER. char* becomes a character array ["CHARACTER(C_CHAR), DIMENSION(*)"]. not a character string.
  5. Functions that return pointers, and in particular char*, have a return of TYPE(C_PTR), a “generic” C pointer. They can be converted to an array pointer of type CHARACTER(KIND=C_CHAR) using the F2003 procedure C_F_POINTER. We do not provide a function inside F2003 for this but it is easy to write. Converting them to POINTERs of type CHARACTER(KIND=C_CHAR,LEN=:) is not legal according to F2003 since the length must be 1 to be interoperable.
  6. TYPE(GLCPTR) becomes TYPE(C_PTR), and GLNULLPTR becomes C_NULL_PTR from F2003. Sadly, there is no TYPEALIAS in F2003 so these cannot be aliased.
  7. F2003 does not define any user-defined types such as gluQuadricObj or TK_RGTImageRec. If these types are manipulated via a pointer (handle), a TYPE(C_PTR) argument is used. It is possible to define derived types if really needed, but this is not necessary for the base libraries since there only handles appear and the components of the structures are never needed. Again, TYPEALIAS would have been useful...
  8. Void arguments become TYPE(C_PTR)---no generic interface is provided since this does not conform to the F2003 standard. Only TYPE(C_PTR) interoperates with “void*”.
  9. The procedures are not generic, but rather merely interfaces to the specific C routines (which are assumed to have external linkeage). At present the only exception is glutInit, which has been overloaded so that it can be called without arguments.
  10. No truncation to 31 characters has been done. This might be done by the Fortran processor itself, namely, it might ignore all characters 32 and higher.
  11. GLUTNULLFUNC has been deleted (see above discussion of GLUT callbacks---we do provide a version of the GLUT interfaces where GLUTNULLFUNC can be used). Instead, simply call the GLUT procedure without supplying an actual argument for the callback to turn it off. Note that this may require use of keywords if the optional callback argument is not the last one in the argument list.
  12. In the cases where GL retains a pointer to an actual argument, as in glFeedbackBuffer (section 4.2 in NISTIR), F03GL uses a TYPE(C_PTR) dummy instead of putting a TARGET attribute on the dummy, which may fail. The only cases where the Fortran 2003 standard actually guarantees no-copy is when the dummy is assumed-shape and TARGET---and assumed-shape complicates interoperability (in fact it will only be supported in the upcoming F2008).
  13. GLUT callbacks need to have arguments with the VALUE attribute and have a BIND(C) label, so that they can be called directly from C. Note that BIND(C,NAME="") may be used to suppress the binding label for subroutines that are only needed as callbacks. This avoids polluting the global symbol namespace with callbacks.

Valid XHTML 1.0 Transitional