LablGLES: OpenGL ES from OCaml
Posted by Jeffrey
OpenGL ES is a reduced version of the OpenGL graphics standard, suitable for use on small devices like mobile phones. My OCaml interface is provided as a set of patches to LablGL, an OCaml OpenGL interface by Jacques Garrigue and others.
You can use LablGLES to build OpenGL applications in OCaml for the iPhone and other iOS devices using OCamlXARM, a cross compiler for iOS. Starting with LablGLES 1.1.9, you can also use LablGLES to build OpenGL applications for the iOS Simulator using OcamlXSim.
As of LablGLES 1.1.4, there is also support for compiling and linking under Android. (Android patches were contributed by Paul Snively, psnively@mac.com.)
The current version of LablGLES is 1.1.9, which is based on LablGL version 1.04. It supports OpenGL ES Version 1.1, including a few extensions necessary for iOS. If you want to use it to build iOS apps, you need an installation of Xcode, Apple’s development environment. See Apple’s developer website for details. The build shown on this page was tested with Xcode 4.0.2, but will work with any recent version of Xcode (version 3.2.5 or later, say).
The LablGLES library has been used in production on iOS. In fact the Psellos Cassino app currently available in the iTunes store is a LablGLES app.
Overview
The LablGL release contains three interfaces: to OpenGL, to Tcl/Tk, and to GLUT. Only OpenGL is readily applicable in an embedded environment; I do not build the other parts (and they are not affected by any of the patches).
To a fairly good approximation, OpenGL ES is a subset of OpenGL. Roughly speaking, then, the patches just remove the parts of LablGL that aren’t in OpenGL ES. In addition, I added support for framebuffer objects, an extension required for OpenGL ES applications on iOS devices. I also added support for PVRTC compressed textures, which again are very useful on iOS devices.
Note that a few of the command lines of the following discussion are too long to fit on a single line of a typical browser window. In a lot of cases there is no good place to split them into smaller lines, usually because of a long filename or URL. Take care that you enter them as a single line if you are typing them in by hand.
Get LablGL Sources and Patches
Choose a place to work (an empty directory would be good).
$ cd <good place to work>
Download the sources for the LablGL 1.04 release:
$ curl -O -s http://wwwfun.kurims.kyoto-u.ac.jp/soft/olabl/dist/lablgl-1.04.tar.gz
$ ls -l lablgl-1.04.tar.gz
-rw-r--r-- 1 psellos staff 410525 Aug 16 15:41 lablgl-1.04.tar.gz
Download LablGLES patches from Psellos:
$ curl -O -s http://psellos.com/pub/lablgles/lablgles-1.1.9.diff
$ ls -l lablgles-1.1.9.diff
-rw-r--r-- 1 psellos staff 145726 Aug 16 15:42 lablgles-1.1.9.diff
To save typing, you can access these two links directly from your browser:
Unpack and Apply Patches
Unpack the LablGL sources.
$ tar --strip-components=1 -xzf lablgl-1.04.tar.gz
Apply the LablGLES patch.
$ patch -p0 -E < lablgles-1.1.9.diff
patching file Makefile.config.iossim
patching file ESVERSION
patching file src/glMap.mli
patching file src/gluQuadric.mli
patching file src/gluMisc.mli
patching file src/glu_tags.var
patching file src/gluTess.ml
patching file src/ml_glu.c
patching file src/ml_glu.h
patching file src/gluQuadric.ml
. . .
patching file Makefile.config.ex
patching file Makefile.config.android
patching file Makefile.config.mingw
patching file Makefile.common
patching file Makefile.config.ios
patching file Makefile
The patch command lists 59 patched files. Because OpenGLES is a subset of OpenGL, around 20 of the LablGL source files are not applicable to LablGLES. The patch causes all their content to disappear, and the -E option asks for these empty files to be deleted.
Build the Library
Specific details for building LablGLES will depend a great deal on your host and target systems. Here I show how to build for iOS (iPhone and iPad) and for the iOS Simulator, using Apple’s Xcode and the two previously mentioned OCaml cross compilers, OCamlXARM and OCamlXSim.
If you’re using OCamlXARM or OCamlXSim, please make sure you have a
recent version. The LablGLES compilation requires the camlp4
preprocessor, which didn’t work in earlier versions of the cross
compilers. For OCamlXARM you want ocaml-3.10.2+xarm12
or later. For
OCamlXSim you want ocaml-3.12.1+xsim1
or later. If you built the
compilers yourself from source, you should have built OCamlXARM from
patches with version 1.0.12 or later. You should have built OCamlXSim
from the directions posted on July 15, 2011 or later.
The build of LablGL (and thus LablGLES) is controlled by a main
Makefile
that is the same for all environments. Details for a
particular environment are defined in a file named Makefile.config
,
which is included by the main Makefile
. The LablGL release includes
several examples for different environments, named Makefile.config.ex
,
Makefile.config.osx
, and so on. The LablGLES patches create three new
files for different OpenGLES environments:
Makefile.config.ios | for iPhone and iPad |
Makefile.config.iossim | for iOS Simulator |
Makefile.config.android | for Android |
The first step in building LablGLES, then, is to create a
Makefile.config
file that defines the details of your environment.
Here I will show how to use use the Makefile.config.ios
and
Makefile.config.iossim
that come with LablGLES.
You will generally need to modify the Makefile to fit your local
development layout. If you are working with iOS or the iOS Simulator,
you may need to specify the location of your cross compiler or adjust
the iOS SDK version. The lines in Makefile.config.ios
looks as
follows:
OCAMLBINDIR=/usr/local/ocamlxarm/bin
SDK=/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk
The lines in Makefile.config.iossim
looks as follows:
OCAMLBINDIR=/usr/local/ocamlxsim/bin
SDK=/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.3.sdk
Make sure the lines specify the location of your OCaml cross compiler
(and other utilities), and the base SDK you want to use. You probably
want to set SDK
to the most recent SDK version you have installed on
your system.
Once you have your configuration file, copy it into place and compile the library. For iOS, this looks as follows:
$ cp Makefile.config.ios Makefile.config
$ make lib libopt
cd src && make all LIBDIR="`ocamlc -where`"
/usr/local/ocamlxarm/bin/ocamlc -pp /usr/local/ocamlxarm/bin/camlp4o var2def.ml -o var2def
/usr/local/ocamlxarm/bin/ocamlc -pp /usr/local/ocamlxarm/bin/camlp4o var2switch.ml -o var2switch
/usr/local/ocamlxarm/bin/ocamlrun ../src/var2def < gl_tags.var > gl_tags.h
/usr/local/ocamlxarm/bin/ocamlrun ../src/var2switch -table GL_ < gl_tags.var > gl_tags.c
/usr/local/ocamlxarm/bin/ocamlc -c -w s -ccopt "-c -O -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.2.sdk" ml_gl.c
. . .
/usr/local/ocamlxarm/bin/ocamlc -c -w s -I +labltk raw.mli
/usr/local/ocamlxarm/bin/ocamlc -c -w s -I +labltk raw.ml
/usr/local/ocamlxarm/bin/ocamlc -c -w s -I +labltk gl.mli
/usr/local/ocamlxarm/bin/ocamlc -c -w s -I +labltk gl.ml
. . .
/usr/local/ocamlxarm/bin/ocamlopt -c -ccopt -isysroot -ccopt /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk -cclib -Wl,-syslibroot,/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk -I +labltk glFramebuffer.ml
/usr/local/ocamlxarm/bin/ocamlmklib -ldopt -Wl,-syslibroot,/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk -o lablgles ml_gl.o ml_raw.o ml_glarray.o ml_glframe.o raw.cmx gl.cmx glLight.cmx glMat.cmx glMisc.cmx glPix.cmx glClear.cmx glTex.cmx glDraw.cmx glFunc.cmx glArray.cmx glFramebuffer.cmx -framework OpenGLES
For the iOS Simulator it looks as follows:
$ cp Makefile.config.iossim Makefile.config
$ make lib libopt
cd src && make all LIBDIR="`ocamlc -where`"
/usr/local/ocamlxsim/bin/ocamlc -pp /usr/local/ocamlxsim/bin/camlp4o var2def.ml -o var2def
. . .
/usr/local/ocamlxsim/bin/ocamlmklib -ldopt -Wl,-syslibroot,/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.3.sdk -o lablgles ml_gl.o ml_raw.o ml_glarray.o ml_glframe.o raw.cmx gl.cmx glLight.cmx glMat.cmx glMisc.cmx glPix.cmx glClear.cmx glTex.cmx glDraw.cmx glFunc.cmx glArray.cmx glFramebuffer.cmx -framework OpenGLES
The compilation produces around 50 lines of output, some of them quite long.
The supplied Makefile.config.ios
and Makefile.config.iossim
specify
that LablGLES should be installed in a subdirectory named release
. To
create this local installation, type make install
:
$ make install
cd src && make install
. . .
The installation process produces around 15 lines of output. The
contents of the release
directory should look something like this:
$ ls -l release
total 712
-rw-r--r-- 1 psellos staff 4492 Aug 16 15:47 build.ml
-rwxr-xr-x 1 psellos staff 33028 Aug 16 15:47 dlllablgles.so
-rw-r--r-- 1 psellos staff 3065 Aug 16 15:47 gl.cmi
-rw-r--r-- 1 psellos staff 707 Aug 16 15:47 gl.cmx
-rw-r--r-- 1 psellos staff 2719 Aug 16 15:47 gl.ml
-rw-r--r-- 1 psellos staff 1874 Aug 16 15:47 gl.mli
. . .
-rw-r--r-- 1 psellos staff 53872 Aug 16 15:47 lablgles.a
-rw-r--r-- 1 psellos staff 18325 Aug 16 15:47 lablgles.cma
-rw-r--r-- 1 psellos staff 2564 Aug 16 15:47 lablgles.cmxa
-rw-r--r-- 1 psellos staff 36384 Aug 16 15:47 liblablgles.a
-rw-r--r-- 1 psellos staff 6258 Aug 16 15:47 raw.cmi
-rw-r--r-- 1 psellos staff 1313 Aug 16 15:47 raw.cmx
-rw-r--r-- 1 psellos staff 3179 Aug 16 15:47 raw.ml
-rw-r--r-- 1 psellos staff 3716 Aug 16 15:47 raw.mli
Test
To verify that the library works, try compiling and linking a small test program, such as the following:
$ cat glestest.ml
let main () =
begin
GlPix.store (`unpack_alignment 1);
GlFunc.blend_func `one `one_minus_src_alpha;
Gl.enable `blend;
GlTex.env (`mode `modulate);
GlDraw.viewport ~x: 0 ~y: 0 ~w: 320 ~h: 460;
GlMat.mode `projection;
GlMat.load_identity ();
GlMat.ortho ~x: (0.0, 320.0) ~y: (0.0, 460.0)
~z: (-100.0, 100.0);
GlClear.color ~alpha: 1.0 (0.8, 0.333, 0.0);
GlClear.clear [`color];
end
let () = main ()
Now compile and link with the cross compiler. This example is for
compilation to iOS (with OCamlXARM). To test compilation to the iOS
Simulator, replace ocamlxarm
with ocamlxsim
.
$ /usr/local/ocamlxarm/bin/ocamlopt -I release -o glestest lablgles.cmxa glestest.ml
$ file glestest
glestest: Mach-O executable arm
If the compiler produces an executable, LablGLES very likely has been built correctly.
You may, instead, see an error like one of the following:
$ /usr/local/ocamlxarm/bin/ocamlopt -I release -o glestest lablgles.cmxa glestest.ml
ld: library not found for -lcrt1.o
collect2: ld returned 1 exit status
Error during linking
or
$ /usr/local/ocamlxsim/bin/ocamlopt -I release -o glestest lablgles.cmxa glestest.ml
ld: framework not found OpenGLES
collect2: ld returned 1 exit status
File "caml_startup", line 1, characters 0-1:
Error: Error during linking
This means that your version of OCamlXARM or OCamlXSim has been built with an earlier version of the iOS SDK. As described on the OCamlXARM page, this is hard to avoid due to Apple’s steady release of new versions of iOS and SDKs for them.
You could rebuild OCamlXARM and OCamlXSim for the latest SDK, but the
easiest solution is to specify explicit options to ocamlopt
telling it
which SDK version to use. To use the iOS 4.3 SDK with OCamlXARM:
$ PLAT=/Developer/Platforms/iPhoneOS.platform
$ PLATBIN=$PLAT/Developer/usr/bin
$ SDK=$PLAT/Developer/SDKs/iPhoneOS4.3.sdk
$ OCCC="$PLATBIN/gcc-4.2 -arch armv6"
$ OCOPTS="-ccopt -isysroot -ccopt $SDK -cclib -Wl,-syslibroot,$SDK"
$ /usr/local/ocamlxarm/bin/ocamlopt -cc "$OCCC" $OCOPTS -I release -o glestest lablgles.cmxa glestest.ml
$ file glestest
glestest: Mach-O executable arm
To use the iOS 4.3 SDK with OCamlXSim:
$ PLAT=/Developer/Platforms/iPhoneSimulator.platform
$ SDK=$PLAT/Developer/SDKs/iPhoneSimulator4.3.sdk
$ OCOPTS="-ccopt -isysroot -ccopt $SDK -cclib -Wl,-syslibroot,$SDK"
$ /usr/local/ocamlxarm/bin/ocamlopt $OCOPTS -I release -o glestest lablgles.cmxa glestest.ml
$ file glestest
glestest: Mach-O executable i386
Although the extra options are painful to specify, you’re generally not going to be typing them in by hand. You just need to set up your build system (Makefile, Xcode, etc.) once, and it will take care of it.
Note: These compiles of
glestest.ml
only test that the LablGLES library has been created
correctly. A program that actually displays graphical content requires
a little more setup. For a working example of a LablGLES app, see the
accompanying note OCaml OpenGL ES iPhone App: IcosaBlue.
Further Information
As I said above, I’ve put together an example LablGLES app named IcosaBlue. The app itself is quite simple, but it demonstrates the extra Cocoa Touch classes and setup required to embed OpenGL ES graphics in an iPhone app. To make it as useful as possible, I packaged it both for the iPhone Simulator and for the iPhone device. See the IcosaBlue page for a description of how to build it and how it works.
I’m happy to get any comments, corrections, or questions at jeffsco@psellos.com.