Proposal for an OpenGL FORTRAN Binding
September 16, 1994
Proposal for an OpenGL FORTRAN Binding
Allen Akin
September 16, 1994
If you're most interested in the FORTRAN binding as viewed by an
application developer, then read the sections titled "Overview" and
"Binding". If you're considering implementing the binding, then you
should read the "Summary of Issues" section carefully.
Note that the implementation of the binding is highly
system-dependent. It's likely that SGI won't be able to supply a
sample version of anything other than the ".h" files which define
manifest constants. If you want to supply an OpenGL library to your
FORTRAN customers, you'll probably have to implement the wrapper
routines from scratch.
Overview
1. Scope.
This proposal covers FORTRAN bindings for the core of OpenGL and
for the GLU (OpenGL Utilities).
It does not cover the GLX API, because we're told there is no
consensus on a FORTRAN binding for the Xlib routines and data
structures needed by GLX. It also does not cover the analogous
support routines for Microsoft Windows, because Microsoft has not
yet published a C binding to serve as a model.
2. Compatibility with FORTRAN standards.
The FORTRAN binding is intended to work with standard Fortran 90
implementations, as well as standard FORTRAN 77 implementations
with some extensions that we believe are universally available.
3. Identifiers in C and FORTRAN bindings.
The identifiers in the FORTRAN binding are the same as those in the
C binding, with the exception that the "gl" prefix is changed to
"fgl" and the "GL" prefix is changed to "FGL". External symbols
must use "fgl" rather than "gl" to avoid name-space clashes in some
systems that implement the OpenGL FORTRAN binding as a wrapper
around the OpenGL C binding. We changed the other names for
consistency and to prepare for potential problems with long
identifiers.
4. Parameter lists and return types in C and FORTRAN bindings.
In general the parameter lists and return types of routines in the
FORTRAN binding are identical to those of the corresponding
routines in the C binding (subject to the data type substitutions
described next).
5. Data types in C and FORTRAN bindings.
Types in the OpenGL C binding will be translated to FORTRAN types
as follows:
GLbyte INTEGER*1
GLshort INTEGER*2
GLint, GLsizei INTEGER*4
GLfloat, GLclampf REAL*4
GLdouble, GLclampd REAL*8
GLubyte INTEGER*1
GLboolean LOGICAL*1
GLushort INTEGER*2
GLuint, GLenum, GLbitfield INTEGER*4
GLvoid no equivalent needed
pointers (see below) CHARACTER*8
6. Letter case in code and documentation.
Letter case is not significant in the FORTRAN binding. This is
required by the relevant FORTRAN standards. For the sake of
consistency with the documentation describing the C binding,
identifiers in the FORTRAN binding will be documented in mixed
case. This is not the usual FORTRAN practice, but it seems to be
the best compromise for OpenGL.
7. Packaging.
Manifest constants and declarations of external subprograms will be
packaged in include files named "fgl.h" (for the OpenGL core) and
"fglu.h" (for the OpenGL Utilities) which will reside in the same
directory as "gl.h" and "glu.h" used by the C binding.
Since nearly all systems will implement the FORTRAN binding as a
set of wrappers that invoke routines in the C binding, I think it
will be most convenient if the wrappers are included in the same
libraries as the corresponding C routines. This eliminates the
need to link with multiple libraries, and may simplify library
construction, distribution, and documentation.
Summary of Issues
Implementors should read this section carefully, because it describes a
number of potential problems that might be encountered when building a
FORTRAN binding.
In the following paragraphs, the term "respondents" refers to the
Usenet readers who replied to a query posted in the newsgroups
comp.graphics.opengl and comp.lang.fortran.
1. Case Sensitivity.
All respondents agreed that case must not be significant. (That
is, the OpenGL binding should not include identifiers that differ
only in case.) This is not a problem for OpenGL.
Apparently all current FORTRAN compilers accept mixed-case input.
However, respondents disagreed about the desirability of mixed-case
identifiers.
2. Use of Underscores.
Fortran 90 specifically allows underscores in identifiers, provided
that the underscores do not appear as the first or last character.
This is not a problem for OpenGL.
All respondents indicated that underscores are supported in their
current workstation development environments.
3. Identifier Length Limits.
Fortran 90 requires that identifiers be distinguishable in their
first 31 characters. The C binding for OpenGL meets this
requirement.
The C binding includes identifiers that are longer than 31
characters (GL_CURRENT_RASTER_TEXTURE_COORDS and
GL_CURRENT_RASTER_POSITION_VALID). We do not know whether some
FORTRAN compilers will object to identifiers of this length.
There seems to be no consensus about the maximum length for
external identifiers (those that are visible to the linker). The
longest such identifiers in the C binding appear to be
glGetTexLevelParameteriv and glGetTexLevelParameterfv, at 24
characters. 23 characters must be significant to distinguish the
two names. Several respondents indicated that they would not
expect linkers to be able to handle such lengths. However, none
identified a system that they knew would fail. FORTRAN
environments are probably not any more restrictive than C
environments, so if 24-character externals are acceptable in C on a
given system then they are likely to be acceptable in FORTRAN.
4. External Namespace Clashes.
Some environments (e.g. Microsoft FORTRAN) have a general
cross-language calling capability that allows FORTRAN applications
to call the routines in the OpenGL C binding directly.
Unfortunately, most systems lack this feature. Therefore, I expect
most vendors will implement the OpenGL FORTRAN bindings as a set of
"wrapper" routines that call corresponding C routines.
The issue is whether one can write a wrapper that allows a FORTRAN
program to call a C routine, and guarantee that the wrapper can be
invoked from FORTRAN using the name of the C routine. If this is
so, then the same routine names can be used in the FORTRAN and C
bindings. If this is not so, the FORTRAN binding must use distinct
names.
Apparently the usual way to solve this problem in UNIX environments
is to have FORTRAN append an underscore to the names of external
identifiers. For example, a FORTRAN program would call
"GLBEGIN(GL_POLYGON)" and the call would actually invoke an
external routine named "GLBEGIN_". This routine could be a wrapper
which executes "glBegin(GL_POLYGON)" and thus invokes the regular
OpenGL C routine.
According to the respondents, VMS FORTRAN and UNICOS (Cray) FORTRAN
environments do not handle external FORTRAN names in this way. IBM
(XLF) and HP do not handle external FORTRAN names in this way
unless a compiler option is used. Many respondents stated that
they cannot use this option in all cases.
Several respondents noted that *all* the external names in the C
binding are mixed-case, whereas *all* external references from
FORTRAN applications are in a single case (because compilers map
the names to one case to enforce case-insensitivity). This might
allow the same names to be used for both bindings; all that is
necessary is to ensure that the FORTRAN wrappers have appropriate
single-case names.
According to Burkhard Burow, author of CFORTRAN (a C <-> FORTRAN
interfacing package), this technique works on all systems he's
tried *except* VMS. He says the VMS linker is case-insensitive
for FORTRAN modules, so the external names will conflict.
Therefore it appears that we must use distinct names for the same
OpenGL routine in the C and FORTRAN bindings. This is why we
changed the "gl" prefix in the C binding to "fgl" in the FORTRAN
binding.
5. Data Type Incompatibilities.
Some data types in C may not be available in FORTRAN, or
vice-versa. The example cited most-often is the lack of "short" on
Cray systems. It appears that this is not a serious problem for
the OpenGL binding, though it may be a problem for portability of
applications that use such types.
FORTRAN lacks support for unsigned arithmetic, so C unsigned
integer types must be translated to FORTRAN signed integer types.
This should not be a major problem.
Pointer types are more awkward. See below.
6. Data Value Incompatibilities.
Examples are the values of the FORTRAN LOGICAL type. The FORTRAN
values for .TRUE. and .FALSE. do not necessarily correspond to the
C conventions of nonzero and zero. At the moment, it appears that
Microsoft FORTRAN is the only environment for which this may be a
problem. (MS FORTRAN uses only the least-significant byte to hold
the LOGICAL value; the other bytes may contain arbitrary data.) For
such systems, the wrapper routines must perform an appropriate
conversion.
7. Data Layout Incompatibilities.
FORTRAN stores multidimensional arrays in column-major order, while
C stores them in row-major order. It appears that this is not a
problem, since there are no multidimensional arrays in the C
binding for OpenGL.
There are no structs in the C binding, so handling structure layout
is not an issue.
8. Pointers.
Pointer types are not generally available in FORTRAN 77.
Use of pointers in parameter lists is not a problem; the wrapper
routines can convert between FORTRAN and C calling conventions as
needed. No special pointer type is required.
One core OpenGL routine (glGetString) and one GLU routine
(gluErrorString) return pointers to character strings. There is no
simple way to support these routines in FORTRAN 77, where there are
no means to dereference pointers or allocate memory dynamically.
No matter how large a fixed-size buffer is used for the return
value, it might be too small. (Especially for glGetString, which
can return an arbitrarily-long list of extension names.) Even if a
return value is provided to indicate that the supplied buffer is
too small, there is no portable way to allocate a larger one and
try again.
For now, we will simply declare these routines to return a
CHARACTER*256 value. (Some implementations of FORTRAN 77 limit the
maximum length of a character string to 256.) If developers are
concerned about this, we can ask them to work around the problem by
adding some assembly code to call the C versions of the routines,
or we can write a small utility to deliver the strings one buffer
at a time.
Three GLU routines (gluNewNurbsRenderer, gluNewQuadric, and
gluNewTess) return pointer values. These routines are problematic,
because their return values are compared to NULL, stored, and
re-used by the application program.
Some machines now support 64-bit pointers, so if these routines are
to return actual pointers, they must return a FORTRAN object of at
least that size. CHARACTER*8 variables are an option, though they
have an awkward representation for NULL. REAL*8 variables are
another option, though on some machines floating-point load and
store operations may corrupt the value of the pointer or generate
an exception. INTEGER*8 variables are not available on all FORTRAN
implementations.
I think the right compromise is to represent pointers as variables
of type CHARACTER*8. This allows source code portability, makes
implementation easy on both 32- and 64-bit machines, and makes the
FORTRAN binding as similar to the C binding as possible. The value
of NULL is slightly awkward to construct on some FORTRAN 77
implementations, but is easy to use once constructed:
character*8 tessobj, NULL
NULL = char(0) // char(0) ... // char(0)
tessobj = fgluNewTess()
if (tessobj .eq. NULL) ...
9. GL -> OpenGL Converter.
One respondent requested a tool for converting GL-based FORTRAN
programs to OpenGL. At the moment there are no plans for such a
tool.
10. Standards Committee Involvement.
Many of the respondents raised this topic. There appear to be
three distinct issues.
First, X3J3 and WG5 will *strongly* encourage the use of Fortran 90
as a basis for new bindings. Fortran 90 implementations are not
yet widely available, so this approach has the disadvantage that it
may not play well with existing development environments.
Second, some existing FORTRAN standards set requirements for
FORTRAN bindings. The two that were cited are POSIX.9 (for rules
about FORTRAN name spaces), and Fortran 90 ("Guidelines for
Language Bindings.")
Third, more than one respondent stated that X3J3 and WG5 will be
annoyed if FORTRAN bindings are proposed without consulting them
(or at least providing documentation for them to review). This may
be an issue for some licensees who are actively involved in
standards work.
Jose Oglesby, the Microsoft representative to X3J3, volunteered to
act as liaison to the ARB if the OpenGL community decides to
address these issues.
Binding
The full FORTRAN binding is many thousands of lines long, so we've
chosen to omit it from this proposal. However, this section will
illustrate selected parts of the binding.
The definitions of manifest constants in the C binding translate to
INTEGER and PARAMETER statements in the FORTRAN binding. For example:
#define GL_ACCUM 0x0100
becomes
integer*4 FGL_ACCUM
parameter ( FGL_ACCUM = 256 )
Types are converted according to the table in the Overview section.
We assume that assembly-language wrapper routines will handle the
conversion from FORTRAN calling conventions to C calling conventions.
This allows the FORTRAN calls can be inferred from the C calls with
very little effort:
void glVertex3fv (const GLfloat *v);
subroutine fglVertex3fv (v)
real*4 v(3)
void glColor3ub (GLubyte red, GLubyte green, GLubyte blue);
subroutine fglColor3ub (red, green, blue)
integer*1 red, green, blue
The C routines involving pointers are translated as follows:
const GLubyte * glGetString (GLenum name);
character*256 fglGetString (name)
integer*4 name
const GLubyte* gluErrorString (GLenum errorCode);
character*256 fgluErrorString (errorCode)
integer*4 errorCode
GLUnurbsObj* gluNewNurbsRenderer (void);
character*8 fgluNewNurbsRenderer()
GLUtriangulatorObj* gluNewTess (void);
character*8 fgluNewTess()
GLUquadricObj* gluNewQuadric (void);
character*8 fgluNewQuadric()
The types GLUnurbsObj*, GLUtriangulatorObj*, and GLUquadricObj* are all
translated to CHARACTER*8. Variables of this type can be copied, passed
to other GLU routines, etc. They can also be tested against a NULL
pointer value in exactly the same manner as C pointers. We will define
the NULL value as char(0)//char(0)//...//char(0) (8 occurrences of
char(0)). Note that a single char(0) is not sufficient, because FORTRAN
strings are blank-padded.
[end]