Posted on 19.02.08
A little later than expected, I’ve put out GLCaml release 20080215. The first tar packages contained a GL constant overflow bug on 32-bit systems (which crept in despite testing on a 32-bit system before uploading to Sourceforge from a 64-bit system). My apologies for any users bitten by it. A bug fix release has been put up.
What does it contain? The API has been revamped. In particular, the use of Bigarrays was not very popular: Bigarrays do not coexist effortlessly with native OCaml array types. The problem with using native Ocaml int, float and bool arrays is twofold. First, on 32-bit systems, arrays are limited in length to 4 million elements. Secondly, native Ocaml types (floats excepted) do not match on the bit-level with the native C types used in OpenGL implementations. So conversion between the different types is necessary, and adds an extra layer of inefficiency. In addition, a number of parameters to OpenGL functions are read-write, meaning that for a function call two conversion layers must take place: Ocaml to C, then the function call, and then from C back to Ocaml.
A (not exhaustive) examination of the uses of arrays in OpenGL functions demonstrate three basic uses:
- As array-based alternatives for vertex functions, in which case the typical number of elements is between 2 and 4
- As a fudge to emulate variable parameter passing with variable length arrays, in which another parameter directly or indirectly determines the array length. Typical numbers of elements are between 1 and 4
- As textures or bitmaps
In the first two cases there will be some performance hits translating between types, but this is not significant except in the cases that large amounts of vertex data are being processed. Fortunately float arrays are passed directly to OpenGL, so vertex data passed to functions taking double precision floating point array arguments do not have to carry out any conversions. For case 1 and 2 I decided that the performance hit for conversion to and from Ocaml types was acceptable. (Luckily, I get to define what the definition of “acceptable” is).
For textures and bitmaps, typically void pointers are passed, and another argument informs OpenGL of the nature of the void pointer. A kind of poor man’s run-time type determination, as it were. Textures are large, and copying back and forth would be prohibitive. So there must be some way to pass a texture directly to an OpenGL function without copying it to a Bigarray first. The question is, in what form are textures stored in the first place? Normally, textures are packed arrays of unsigned bytes representing RGB or RGBA values (or RGB[A] values packed into 16-bit words). Other texture formats are possible, such as the representation of a texture as an array of single-precision floating point numbers. In all cases, they do not correspond to arrays of standard Ocaml types (31-bit ints or double precision floats). Additionally, bitmaps are generated and stored by other programs in almost all occasions as packed byte arrays.
The native Ocaml type coming closest to a packed byte array is a string. Strings have a 16 million byte length limitation on 32 bit systems, but can be used to hold texture-maps. In SDLCaml, I have written a pure-Ocaml function to load a TGA bitmap into a string. So I think that OpenGL functions taking void pointers should accept strings.
Also important: bindings to external libraries, such as SDL, generally return pointers to packed byte arrays. SDL.surface_pixels returns such a pointer. So these should be accepted as well.
Solution: void pointers become polymorphic types, and the GLCaml FFI binding looks at the tag of the variable passed in and does a conversion from string or Bigarray accordingly. The downside of this is the possibility of segfaults if something other than a string, a bigarray, or a pointer from an external FFI is passed. But then, I wouldn’t want to deny Ocaml users the dangers associated with void pointers in C.
The second major change is that Glenums (or the glenum type in GLCaml) have been changed to ints. In theory Glenums are enumerated types, in practice OpenGL uses them as both enumerated types and integer arguments. I provided functions to convert between glenums and ints in earlier versions of GLcaml, but converting back and forth between ints and glenums quickly becomes a pain. So the glenums are gone. Everything is an int.
The third change is that silent fails are no longer possible. Every time an OpenGL call fails because the call is not available an exception is raised and has to be handled (or not) by the caller. This is because functions with in/out parameters can leave their parameters in an undefined state. (Ocaml allows string creation with garbage in it, for instance).
There’s some new stuff as well. The Win module, that integrates OpenGL with Ocaml graphics windows on Unix and Windows, has been included. This precludes the necessity for GLUT, SDL or some other library in order to display OpenGL graphics. There have been some bug fixes as well in SDLCaml.
And shaders work. That was the whole reason for revising GLCaml in the first placeComments Off
Posted on 29.12.07
In between the social duties usual during this time of the year I’ve been trying to work on and off on GLCaml. I’ve had some feedback from the (not very large) user base over the past few months and it’s clear that some changes are needed.
For instance, the use of enumerations is a pain, because OpenGL mixes enumerations and integers willy-nilly, and having to convert back-and-forth in Ocaml is just not worth the hassle. Also, although the use of Bigarrays is in my opinion mostly unavoidable, I’m trying to minimize usage where it is not strictly necessary.
A couple of weeks ago, Jon Harrop mailed that he had gotten GL shaders to work, albeit with some difficulty and hand tweaking. I’m taking the opportunity to test shaders and related bindings more thoroughly, but this will take some time.
I think the next release of GLCaml will have some fairly major changes; some cosmetic, some fundamental. Basically GL constants (glenums in GLcaml) will become ints, and as a result GL_ALL_CAPS notation will have to become gl_lower_case notation. But before I release it I’d like to test it reasonably well. Revise and revamp the documentation, examples and website as well. This might take a month or so, depending on free time.
What does all this have to do with Zlib’s inflate algorithm? Nothing. But about a month ago I implemented an Ocaml-only implementation of Zlib’s inflate algorithm (RFC 1951). It’s not the first one: Extlib has one, but using it requires pulling in a lot of other stuff as well. I was writing a pure-Ocaml PNG decoder (mostly done but very buggy, will finish it when I have the time), and needed a simple zlib decoder.
So I wrote one. The source code is available (under the BSD licence). It’s pretty compact: about 250 lines of code, including comments. Usage is very simple: pass a string containing data compressed with the zlib deflate algorithm, and a string large enough to contain the decompressed data, and it returns the same string with the decompressed data.
uncompress -> string -> string -> string. I added a small, simple example to uncompress gzipped files.
The code is based more or less on the specs, with a peek every now and then at Andrew Church’s tinflate.c when I got stuck on some ambiguity or other. It’s pretty compact - 200 lines of code - and pretty slow: gunzip beats it by a factor of 10 to 100. Maybe if I have time I’ll try and optimize it. First I have to find the time to finish the PNG decoder. And GLCaml, of course.Comments Off
Posted on 12.02.07
I’ve always thought it would be nice if it were possible to use OpenGL calls in a window created with the Ocaml Graphics module. This would prevent the need to require external toolkits such as SDL or GLUT.
The Ocaml Graphics module is quite limited compared to SDL or GLUT, and also fills a slightly different niche, but it does come with a number of useful functions for drawing text, various graphics primitives, and for polling mouse and keyboard events. Simple standalone programs or demos can be created and distributed without requiring that the SDL or GLUT shared library be present on those systems.
To get an Ocaml window working with OpenGL I wrote a stub file in C and a few lines of ML code. When the test program is compiled and linked (download a gzipped tar file containing all necessary files here) it results in a program that runs as seen in the screenshot below.
The file win_stub.c and the few lines of ML code in the prologue of win_test.ml is all that is needed to use OpenGL within an Ocaml application. For the actual OpenGL bindings either GLCaml or lablgl will suffice.
For the provided examples, extract the files contained in glgraphics.tar.gz, and run make. Edit the makefile if necessary, to ensure that the line
CLIB=GL is uncommented on Linux, and the line
CLIB=opengl32 gdi32 is uncommented if compiling on Windows with MinGW.
You need the file win_stub.c and the ML code contained in this section, specifically the function init_opengl () and the external functions init_gl’(), find_window() and swap_buffers (). Link the resultant executable with libGL.a on X11, opengl32.lib and gdi32.lib on Windows.
- First set up your caml window with Graphics.open_graph ()
- Next, call the function init_gl ()
- After this you can (re)set the window title (if you set it previously it will be empty)
- Feel free to call any OpenGL calls you wish. lablgl, glcaml and camlgl may all be used.
- You may mix the Ocaml graphics functions with OpenGL.
- Call swap_buffers () any time you need to flip the contents of your back buffer to the screen.
How does it work?
The method used is similar, but not identical, on both Windows and X11. Ocaml does not expose the internals of the window (understandably, because they are highly platform-specific), so they have to be obtained via other means. On both X11 and Win32 you can obtain pointers to internal rendering surfaces of windows provided you can identify them by name. After opening the window with Graphics.open_graph (), the function init_opengl () has to be called. This function gives the current window a (hopefully) unique title Then C code is called which searches through all available windows for a window with that particular name, gets pointers to its internal structure (both Win32 and Xlib allow this) and sets it up for use as an OpenGL surface. This method works on Windows and X11; it may work on OS-X (with a little tweaking in the #defines) but I have not tested that.
Posted on 26.01.07
The GLCaml and SDLCaml bindings proved to be more popular than I had thought they would be, averaging a frenzied 2 downloads per day. (Really, people, restrain yourselves). Still, that’s been around 350 downloads since I first put it up in June ‘06.
So I’ve moved the project to glcaml.sourceforge.net. It’s now got its own website and project page. I’ve updated GLCaml to include support for OpenGL 2.1, which came out in August ‘06. The generated code has been cleaned up, and a minor bug fixed.
Why GLCaml instead of lablgl? Well, GLCaml consists of only three files (two, if you want to forego the .mli file), without any dependencies whatsoever, so you can drop them into whatever project you’re working on, and you’re ready to go. It supports OpenGL up to the latest version (2.1 at the moment), whereas lablgl only supports OpenGL 1.2. It’s a very thin wrapper, so it’s fast. The nomenclature is exactly the same as the native ‘C’ OpenGL API, so you can copy and paste code from books, tutorials and C/C++ projects without trouble.
Why not GLCaml? Well lablgl is elegant, typesafe, it’s been written by smarter people than I (you might want to take that into account before rushing to ship 50K copies of your GLCaml-powered 3D shooter), and it’s been around longer - thus better tested.
GLCaml had a companion library, SDLCaml, which was a similar compact binding to SDL (and in fact somewhat pre-dates GLCaml, since I’d worked on it on-and-off since April ‘06). I’ve decided not to make a separate project page for SDLCaml, but to leave it as a supported, optional library within the GLCaml project. I will continue to maintain and update it, but it won’t be as visible as GLCaml: I do think it’s incredibly handy, but the OCaml landscape is littered with good SDL bindings (like OcamlSDL and Jean-Christophe Filliatre’s ocamlsdl) and mine doesn’t add extremely much value, aside from being very compact.No comments
Posted on 30.06.06
UPDATE: This project has moved to glcaml.sourceforge.net.
The (automatically generated) OpenGL bindings cover OpenGL 1.1, 1.2, 1.3, 1.4, 1.5, 2.0 and most current non-platform-specific extensions. There are no dependencies whatsoever: the system opengl shared library is loaded dynamically, and the functions are called dynamically, so there is no need to link against import libraries.
The SDL bindings are fairly but not wholly complete; they are hand-written and functions are bound on an as-needed-by me basis. They are only dependent on the SDL main library and not on the mixer, ttf or image libraries. Because I wanted to have basic sound capabilities, the SDL_Audio modules are implemented, along with extra functions for panning and pitch shifting audio buffers.
- The source code, in a tar gzipped file, along with around 20 examples
- The documentation, fairly complete for SDL
This has been tested and works on Windows 2000, Windows XP, and Ubuntu Linux running on AMD64.
On Windows I use the mingw Ocaml compiler suite along with the msys shell; the source tarball contains makefiles that work as-is on the Windows mingw/msys port and under Linux. It will probably work as-is for the cygwin port of Ocaml, and will definitely need some tweaking to work under the Visual-C port.
Posted on 07.03.05
Posted on 04.03.05