Posted on 09.09.09
A recent reddit thread on the joy of programming contains a lot of comments to the effect that working on green-field code is pleasurable and rewarding, while working on bug-ridden legacy balls of mud represents soul-destroying drudgery.
The past five years or so I’ve been working on very large code bases, in an industrial/high tech setting. The flagship product suite at Almos Systems (wide-area meteorological real-time data collection and analysis) was about a million lines of C++. At ASML it takes 25 - 30 million lines of code to run the latest lithography scanners. And though I would not have believed it 5 years ago, I find working on these immense projects (all with code dating back to the mid ’90’s) the most rewarding work I have done in my career to date.
When faced with an immediate problem, like finding and fixing the root cause of a bug, or adding new features or functionality, the pre-existing mountain of legacy code certainly adds often severe constraints to any potential solution. The lack of freedom that exists compared to starting with a fresh slate can be quite daunting. I can readily imagine that the very prospect sucks the joy out of programming for many people.
On the other hand, programming is about problem solving. Working with large code bases, with legacy code, with reams of undocumented code and the original authors long gone, is in and of itself a challenge. It is generally not an intractable challenge. It isn’t easy, but it is solvable. And this is what I did not know 5 years ago. To be asked to do the impossible, is soul-destroying. To be asked to do the difficult, can be very rewarding.
It requires the the right tools. Testing - adding unit tests, functional tests, integration testing. Refactoring, decoupling, cleaning up interfaces, eliminating dead code, rationalization of API’s. It’s hard and invariably tedious work, but if planned reasonably carefully, and executed methodically, it produces positive results. As I once remarked to a colleague when faced with the seemingly endless prospect of interface normalization, if you have to clean out the Aegean stables and all you have is a small shovel, the only thing you can do is close your eyes and start shovelling. It will seem interminable, but there will come a time that you can reopen your eyes and discover that the manure has all been shovelled away, and the stables are - well, maybe not shiny and new, but certainly a lot cleaner and more tractable than when you started out. And then you can stand back, lean on your shovel, and survey your work with satisfaction.
It also requires teamwork. Programming is by-and-large a solitary activity: even in large projects individual developers prefer to work on a piece of code alone. Maintaining a large code base, used by hundreds to thousands of developers, requires continuous and methodical planning and coordination. Existing functionality must not break, migrations and maintenance efforts must be scheduled and delivered on time, and without hindering the reality of delivering new functionality and following the demands of the market closely. This requires a gregariousness that, while not necessarily atypical of developers, is for many certainly not second nature. The level of communication involved is to some extent at odds with the need of the individual developer to program in peace and quiet, in the “zone". Juggling the conflicting requirements of frequent and precise coordination between developers and development teams, and the need to allow developers to get in the flow and finish their tasks, is work that I find surprisingly enjoyable. I recognise, however, that this is not necessarily the case for everyone. Still, to a large degree, work is what you make of it, and it is certainly possible to derive satisfaction from working on large, hairy projects … maybe even more so than on spanking new problems.Comments Off
Posted on 09.08.09
I’ve used OpenSolaris 2009-06 as my primary desktop at home for a month now in order to get a better feel for how usable it is for me as a desktop OS.
At home I surf the web, read email, work on the occasional website (personal websites or websites I build and maintain for charitable or voluntary purposes), listen to music, and indulge every now and then in a little hobby programming, preferably in an exotic programming language. (Although lately I seem to be programming almost exclusively in Ocaml at home - it has slowly replaced C++ as my personal language of choice, and I now also use it for situations in which I am not merely dabbling).
For these purposes OpenSolaris works just fine. It’s actually a fairly lightweight system. I’m running it on a fairly old system, an AMD64 Sempron with 1GB RAM, purchased in 2005, which was not up to the task of running Ubuntu 8.10 smoothly. (Firefox tabs with multiple embedded Youtube videos, for instance, slow noticeably). OpenSolaris runs smoother and more responsively on the whole than later versions of Ubuntu.
Hardware support is still suboptimal. I was able to get my network card working after some difficulty, but USB devices are rather sketchily supported. USB memory sticks and external hard drives can be mounted and read without problems, but I cannot mount or read photos or films from any of my cameras directly. This alone prevents me from setting up a Solaris monoculture here at home.
From a programmer’s perspective, there are a couple of unsatisfactory issues. First is that the GNU toolchain is not particularly well supported. Solaris ships with gcc 3.4.3, and while there’s nothing wrong with the sun compiler suite, lots of open source packages do not compile with it without some degree of tweaking, especially if they compile from makefiles written without making use of autotools.
Secondly, and quite surprisingly, the Solaris X terminal does not support colours. This means that syntax highlighting does not work for terminal-mode vim or emacs, for instance. This annoys me more than I would have thought it would, since I prefer to use vim in combination with terminator.
OpenSolaris for the desktop looks and feels rather like a lightweight Ubuntu. The desktop is Gnome, the package manager is similar to apt, the toolkit is gtk2. There is very little resemblance to the Common Desktop Environment // Motif look and feel of classic Solaris. In fact, OpenSolaris does not even come with Motif installed, so personal favourites such as nedit are not available.
So why run OpenSolaris as a desktop OS? There are not many compelling reasons to choose it above Linux distributions such as Ubuntu. Based on a single data point I think it is less demanding on hardware than the newest versions of Ubuntu, while offering reasonably recent features - the latest Nvidia drivers, USB and networking support (better than Ubuntu’s: if my router hiccups or needs to be rebooted, OpenSolaris detects quickly and reliably when it is up and running again and retrieves a new IP if needed, while Ubuntu is tardy and unreliable in this respect). The file system is fast and reliable, and can be repartitioned on the fly, but this is not a killer feature for a desktop.
Will I keep it? Yes, I think so: it works, it’s stable, it’s given my Sempron a new lease of life. Would I recommend it as a desktop OS for other users? Probably not: there’s no compelling reason to use it in preference to a modern Linux distribution. What would it take for me to migrate all my desktops to OpenSolaris? Better hardware support, in particular for network cards and cameras, and more software packages in the Sun repositories. Given the remarkable progress OpenSolaris has made the past year, this is an unlikely but not unthinkable scenario.Comments Off
Posted on 06.06.09
Last month I tried installing OpenSolaris 2008-11, but did not succeed in getting networking working. Today I noticed that OpenSolaris 2009-06 was just released. I really would like to use Solaris at home. I use it at work and have gotten attached to its quirks. So I downloaded the iso and burned an install CD.
Installation was quicker and smoother on my machine than with 2008-11 (specs: AMD64 Sempron, VIA VT6xxx motherboard with onboard VT6102 Rhine II NIC, NVidia GeForce 6200 with 256 MB memory, a 160 GB hard disk, and 1 GB of RAM).
However - yet again - the installer did not install the correct driver for my VT6102 network card. Fortunately, the install CD - which doubled as a live CD - had a handy little widget which reported the state of all hardware and informed me that the drivers for my card were not available. This was information I did not have when I encountered the same problem with 2008-11.
Googling (on another machine with a working connection) brought me to this very useful page with unofficial drivers for various Solaris versions. This is what I did:
- Downloaded the file vfe-2.6.4.tar.gz, and copied it using a usb stick to my Solaris machine.
- Unpacked the file in a temporary directory
elliott@horza:~$ cd vfe-2.6.4
elliott@horza:~$ mv Makefile Makefile.old
elliott@horza:~$ cp Makefile.amd64_gcc Makefile
elliott@horza:~$ make install
elliott@horza:~$ vim /etc/hostsHere I added the line xxx.xxx.xxx.xxx vfe, where the x’s weere a rough guess as to the IP my DHCP server would supply once the network interface was up and running. My internal network does not use static IP’s, the main router assigns dynamic IP’s which overrides the value in this file anyway.
elliott@horza:~$ devfsadm -i vfeThis command failed with the message “Failed to attach vfe driver”
elliott@horza:~$ touch /etc/hostname.vfe0
elliott@horza:~$ touch /etc/dhcp.vfe0
I then rebooted the workstation. After rebooting the network notifier widget notified me that network interface vfe0 was up and running, and I was able to access the internet.
Next step: installing Flash. From http://get.adobe.com/flashplayer/?promoid=BUIGP I downloaded the player, unzipped and untarred it, and copied (as root) the file
/usr/lib/firefox/plugins/. After restarting firefox, Flash worked fine. A visit to Youtube verified that both sound and video were working fine.
The installer had set the size of my swap partition at 512 MB, in my opinion far too little especially in combination with Firefox usage. A little googling turned up http://www.crypticide.com/dropsafe/article/2649, which had a solution that worked for me:
zfs set volsize=3G rpool/swap, followed by a reboot.
OpenSolaris has a package manager very similar to Ubuntu’s synaptic package manager, with a reasonable number of rather developer-centric packages available. I got the packages I’m used to on most systems (gcc, ocaml, wxwindows etc), and am now a fairly happy puppy.Comments Off
Posted on 16.05.09
My ASUS eee PC netbook is one of my favourite toys, if a little underpowered (512 MB memory, 4 GB flash disk space). I have a couple of better-specced PCs and would like to run programs on their CPUs, while displaying the output on my netbook.
My main box is a quad-core Phenom with 8GB memory, running Ubuntu 9.04. I carried out the following steps:
- Make sure the main box has a ssh server installed and running:
# sudo apt-get install openssh-server openssh-client
- run sudo gdmsetup, and enable X11 forwarding. The file /etc/gdm/gdm.conf should contain
- X11Forwarding yes
- X11DisplayOffset 10
- In the .bashhrc of the account I want to log in with, I add the following lines
- export DISPLAY=localhost:0.0
- xhost +
- Restart the nome Display Manager on the box
- From the netbook, login with ssh user@ip_of_box -X
And now firefox, gvim etc can be run on the host machine with visual output on the netbook. Despite the difference in screen resolution, Gnome actually does a pretty good job of accomodating window sizes to the netbook’s tiny display. I’m typing this post on my netbook via an instance of epiphany runing on my quad-core box. It looks and feels almost like the real thing.Comments Off
Posted on 02.05.09
I’ve been using Solaris 5.10 on a daily basis at work for a couple of years now (on rather underpowered, overpriced sparc v9 Ultras and the occasional Blade). Despite its quirks I’ve gotten used to it - even fond of it, so I decided to download and install Open Solaris 2008-10 on a spare workstation at home.
I chose to install it as the sole operating system on a 64-bit Sempron with 1 GB of RAM. The installer, while pretty, chose to allocate a mere 512 MB for the swap partition (why so little, I have no idea). I couldn’t figure out how to change it (although I didn’t try very hard either). On the plus side, my nVidia video card was detected and configured automatically, and the correct proprietary drivers installed (always a hassle with standard Linux distros). On the negative side - and this was the ultimate showstopper - I couldn’t get networking to work. While it apparently recognized my network card (an on-board VT6102 Rhine II NIC every other distro recognizes effortlessly) , I couldn’t get it to do anything. It didn’t see my router-slash-DHCP server, didn’t pick up an IP address, did nothing with the DNS and gateway settings I fed it, and couldn’t ping any other servers on my home network. Some googling trawled up forum postings where an unsettling number of convoluted steps were taken to resolve similar sounding problems. Had the rest of the OpenSolaris experience been worth it I might have made the effort, but I wound up never resolving this issue.
Open Solaris booted very sluggishly on my Sempron (it took literally minutes), and took even longer to shut down (more than 5 minutes - the first time it took so long I thought the computer had hung and shut it down via the power-off switch.) It boots into a standard Gnome environment, which is a great deal prettier than the Common Desktop Environment I’m used to at work. However, from my viewpoint as a casual end-user (email, surfing, programming in C\C++\Ocaml\Haskell, creating the odd website, listening to music and watching the odd DVD), it offers no tangible benefits over Ubuntu or OpenSuse. Sun hardware, while expensive and underpowered, is rock-stable, but the same cannot be said of OpenSolaris’s x86 stock PC support. The lack of networking was a killer, which the other features could not compensate for.
So I uninstalled it, and now that desktop is running OpenSUSE 11.1.Comments Off
Posted on 25.12.08
Over the years I’ve grown attached to the Minimalist GNU for Windows package for C & C++ development on Windows, which I use together with MSYS. I’ve also grown fond of the OCaml compiler, so when version 3.11 was released earlier this month I decided to install it on the Unix systems I work with regularly. I normally build from source, and version 3.11 was as easy to build and install as previous versions.
Yesterday I decided to upgrade the compiler on my Vista laptop from 3.10.2 to 3.11, so I downloaded the self installer for the MinGW toolchain, installed it without fuss, and tried to compile the project I was working on.
To my displeasure, a warning message about missing flexlink.exe was barfed out when I tried running ocamlopt. A brief google session later turned up Alain Frisch’s flexdll site, which had downloads containing the binary flexlink.exe, and this fa.caml thread, which contained instructions of how to make flexlink.exe work nicely with MSYS.
- Download and install the self installer for the MinGW toolchain
- Download the flexdll binary release, and unzip it somewhere temporary.
- copy flexlink.exe and flexdll_mingw.o to the bin directory of your OCaml distribution
- Open an MSYS shell, and edit your profile (
cd /etc; vim profile)
- Add the following line:
export FLEXLINKFLAGS="-nocygpath -L C:\MinGW\lib", where
C:\MinGW\libshould point to the actual lib directory of your MinGW installation
And voíla! ocamlopt works again. Personally I feel that flexlink.exe should be in the binary installer, and it should look for flexdll_mingw.o in ../lib, not in the directory where it’s located (bin).Comments Off
Posted on 01.09.08
I bought the Asus Eee PC 701 (7″ screen, 512 MB memory, 4GB SD card of which 2.5 GB was already taken up by the operating system), primarily for travelling purposes.
After this ocaml was installed and ready for use.No comments
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 13.12.07
A finite state machine consists of a finite number of states, and a transition function which, given a state and an input, results in another state and an output.
An example of a simple FSM is a door, such as can be found in an elevator. Such a door requires a push on a button to open it. It opens, remains open for a short period of time, and then automatically closes again.
Normally, such a door would be modelled with two states, Open and Closed, and two transitions: from Closed to Open after a push on the button, and from Open to Close after a time out.
However, I would like to implement such a door as simply as possible. If I were to represent a door as a collection of states, there has to be a state available at any given time. So I use four states: Open, Closing, Closed, and Opening. At any given time the door is in one of these four states. A transition from one state to another is instantaneous. The states themselves, however, have duration. For instance, it takes some time for the door to open or close; once open the door will close after some time, and once closed it remains that way until someone presses a button.
A simple implementation in 20 lines of Ocaml can be found here. The demo takes up another 27 lines of code. (Excluding comments). Compile with
ocamlc graphics.cma unix.cma test.ml -o test and run; press a mouse button to open the door. The doors take 3 seconds to open or close, and an open door will start closing again after 5 seconds.
Screenshot, demonstrating the subtleties of Programmer’s ArtComments Off
Posted on 29.11.07
Ocaml’s floating point numbers are double precision i.e. 64 bytes. There is currently no way to read in 32-bit single precision numbers from a binary stream using the Ocaml standard library. Of course, a small stub function in C to read in a float and return it is always possible. But I find it irritating. So, being ill at home today with the flu and having nothing better to do, I looked up the definition of an IEEE 754 32-bit single precision float on Wikipedia and implemented a pure Ocaml function to read a 32-bit float from a binary stream.
let n = read_float32 ic
where ic is a standard input channel
Update: Jon Harrop points out that there is an Int32.float_of_bits function that achieves the same task. This is like kind of charging a closed door only to find it unlockedComments Off
Posted on 08.08.07
Collision detection is an important part of any physical simulation. The basis is formed by the intersection of primitives, and the triangle-triangle intersection test is one of the most commonly used tests.
As described in the CGA FAQ:
Let the two triangles be and . If lies strictly to one side of the plane containing , or lies strictly to one side of the plane containing , the triangles do not intersect. Otherwise, compute the line of intersection between the planes. Let , for and , denote the interval of intersections between the triangles and the line. Either interval may be empty. and intersect if and only if and overlap.
The Ocaml implementation of this test can be viewed online. Compiling with the command
ocamlopt graphics.cmxa unix.cmxa collision.ml -o collision produces the following program:
A quick comparison with the canonical implementation by Thomas Moeller shows that my straightforward Ocaml implementation runs roughly 5 times as slowly as Moeller’s implementation in C.
My implementation currently handles coplanar triangles rather erratically, so I will either have to add a special function to check and handle coplanar triangles, or possibly check triangle normals for parallelism and perturb one of the triangles slightly to bring it out of plane before applying the normal test.No comments
Posted on 29.07.07
Previously, I had written a simple 1d spring demo.. The next logical step was extension to three dimensions (wholly trivial) and the addition of constraints.
To start with, I begin with the canonical problem: a bead on a round frictionless wire hoop. (This is also equivalent to modeling the bob of a simple rigid pendulum). This is a path constraint. Movement is free along the path, but prohibited in any other direction. This can be represented by a constraint vector and a path. The constraint vector is the local radius of curvature and is perpendicular to the free path. The path represents all the positions in space a particle under that constraint may occupy.
For a bead on a hoop, the constraint vector is simply the radius of curvature, and for a hoop this is a vector of constant magnitude pointing towards the center of the hoop.
Any force acting on the bead produces an acceleration and over a period of time dt a displacement dx. This displacement causes the particle to travel in a straight line to x0, and (often) deviate from the path. So a vector can be constructed starting at the (deviated) position x0 along the constraint vector. This vector will intersect the path at a point x1. At this position a new velocity vector can be constructed tangent to the path (i.e. perpendicular to the constraint vector), with the same magnitude as the velocity vector at x0 (with, however, a different direction).
Source code can be viewed online. Compile with
ocamlopt unix.cmxa graphics.cmxa physics.ml -o physics or
ocamlc unix.cma graphics.cma physics.ml -o physics
Posted on 21.07.07
While playing around with a number of simple integrators I wrote a quick 1 dimensional spring demo. Four point spring unit masses are animated using various methods of evaluation (simple Euler, Newton-Stormer-Verlet, 4th order Runge-Kutta and a simple explicit Verlet integrator.
All four methods have the tendency to explode over time, although the Euler integrator does that the easiest. Somewhat to my surprise both Verlet integrators are more stable than the 4th order Runge Kutta integrator.
Source code can be viewed online. Compile with
ocamlopt unix.cmxa graphics.cmxa physics.ml -o physics or
ocamlc unix.cma graphics.cma physics.ml -o physics
This piece of Ocaml code leaks memory:
let rec main () =
let _ = Graphics.auto_synchronize false in
let _ = Graphics.auto_synchronize true in
let () = Graphics.open_graph ” 800x600″; main ()
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 09.02.07
In 1900 the Ladies Home Journal made 29 predictions about the year 2000. Sample:
There will be air-ships, but they will not successfully compete with surface cars and water vessels for passenger or freight traffic. They will be maintained as deadly war-vessels by all military nations. Some will transport men and goods. Others will be used by scientists making observations at great heights above the earth.
These prophecies reveal as much about the nature of science fiction as about the nature of science. They’re often utopian, or naive extrapolations of existing knowledge. And change is accelerating. I’m sure the world of 2100 is literally unimaginable to us today. It’s not even worth trying.
I clicked the link and had a look at the predictions. I found them surprisingly prescient, certainly considering that the year in which they were made (1900), preceded the airplane, motorized vehicles, widespread use of electricity and telecommunications.
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 20.01.07
The Gecko rendering engine on x64 Linux crashes often and easily. Firefox, Epiphany and the Mozilla Web browser all crash on me, sometimes multiple times a day. This wasn’t always the case. Something rotten crept in during an Ubuntu auto-update half a year ago, and since then surfing has become a much more …. Win95 experience again. Bah.No comments
Posted on 16.01.07
I just read that last Sunday was Jordy’s birthday (of Dur dur d’être bébé fame). This song featured a toddler burbling “Dur dur d’être bébé” to the accompaniment of upbeat house music. It was an enormous hit in the summer of ‘92.
Jordy’s now 19 years old. 19! Daaaaamn!!!! Where’d the time go?
Couple of months back, I saw one of the Kriss Kross kids on MTV. Dude is almost 30!!! Last time I saw him he was a pre-teen hopping around energetically with his clothes on bass-ackwards, shouting “Jump! Jump!".
When the f*ck did I get this old and how the f*ck did that happen?No comments