This is the fourth post in a series of OpenGL “tutorials” explaining how to get a triangle on your screen using as few lines of code, in as many languages, and on as many platforms as possible.

Sorry for the long wait, but I think I have something of a gem for you in this installment: Ocaml. There are actually two reasonable options out there for you to get OpenGL up and running in Ocaml. I used a somewhat old library called lablGL. It provides GLUT bindings as well (yay!) but only exposes OpenGL 1.2 (boo!) So writing shader programs could be a tad difficult. The other option out there is called GLCaml and it supports through OpenGL 2.1. However, it looks like the GLCaml interface was built by just automatically scraping some C files, which sounds a bit sketchy to me.

Here’s what you do to get set up. First, install Ocaml if you haven’t. Second, install lablGL. Both of these are very standard, straightforward makefile installs. Even if you’re not on a linux distro with apt-get (or macports/fink on mac), both installs are very easy to make directly from the source.

Once you’ve got yourself setup, the lablgl install should have put the lablglut command into your path. This command is just an alias for calling the ocaml interpreter (command ocaml) with the following argument:

-I $(ocamlc -where)/lablGL lablgl.cma lablglut.cma

Try running lablglut on the following program:

let _ =
    ignore (Glut.init Sys.argv);
    Glut.initDisplayMode ~alpha:true ~depth:true ~double_buffer:true ();
    Glut.initWindowSize ~w:500 ~h:500;
    Glut.initWindowPosition ~x:0 ~y:0;
    ignore (Glut.createWindow ~title:"Hello, GL!");

    Glut.displayFunc ~cb:
        begin fun () ->
            GlClear.clear [`color;`depth];

            GlDraw.color (1.0, 1.0, 1.0);
            GlDraw.begins `triangles;
                GlDraw.vertex3 (-0.5, -0.5, 1.0);
                GlDraw.vertex3 (0.5, -0.5, 1.0);
                GlDraw.vertex3 (-0.5, 0.5, 1.0);
            GlDraw.ends ();

            Glut.swapBuffers ()
        end;

    Glut.mainLoop ()

One more triangle down. Ok, what’s going on with this crazy syntax? Lots of tildes ~. Those tildes are used to provide named arguments to functions, allowing optional arguments and arbitrary reorderings. Next, that ignore function? We’re just telling ocaml that we don’t care about the return value of the ignored computation. In order to get ocaml to typecheck, we have to say this explicitly. Finally, the square brackets after clear are just syntax for a list. Needless to say there are many more details, but that should at least make the program readable.

One cool thing here is that we can write the draw function as an anonymous function inline.

Pros/Cons? I like a lot of things about Ocaml here. The best thing for a short program like this is that Ocaml is a lot more terse where it can be. Compared to C we don’t have to name main, and we don’t have to name draw. Another pleasant surprise is that the named arguments make the meaning of the program much more readable. On the downside, even though Ocaml compiles down to native code, the compiler does a lot of really stupid things.

My biggest pet peeve is that all of the floating point numbers are boxed. That is, they’re maintained by reference. So that means all of those floating point arguments to the vertex calls are allocated, and then references to those constants are passed to the function call. This is a really big performance penalty (space and time) for writing graphics code, where there are tons of fine-grained functions operating on a handful of floating point numbers (e.g. 3 dimensional vectors)

Advertisements