I am currently working in a project that I have written out in OCaml, and I need to do some graphics. This project is a small emulator for the space invaders arcade machine (following emulator101.com).
Current state of affairs
The emulator is almost working now, but one thing is left though: I need to be able to interract with the game, as of right now, the game will launch and the cut scenes will play, but I haven’t been able write the interaction part. Up to this point, I was using the Graphics library to manage printing and that was working OK, it was very convenient to use for a specific reason: I am using a ROM dump of the game which, during the emulation encodes the entire screen to display as a bit-map as a location in the memory. Glossing a bit over the details, what I was doing until now was to read this bit map and convert it into a variable bitmap : color array array
, and then simply call draw_image (make_image bitmap) 0 0
every time I wanted to refresh my screen.
One minor problem with this solution is that apparently the function make_image
is a bit slow, and while profiling the app, I found out that 20% of the computing time is dedicated to it.
Adding the controls
I now want to add the controls, but I am running into a bigger problem here: the events management of the Graphics library is extremely limited, and in particular there is no way of telling if two keys are pressed at the same time, and there is no way to poll for key releases. That’s problematic, firstly for the space invaders machine because I don’t want the ship to need to stop for shooting, and also because I made all project modular enough to hopefully accomodate other machines working on the same processor fairly easily, and in which being able to detect simultaneous key presses may be more crucial. So after some googling I found two ways of interacting with SDL using OCaml: The OcamlSdl library and the Tsdl library. So I decided to try and leverage all the power of the SDL library, to get finer events managements and maybe also solve the efficiency problem I was having. For some reason the OcamlSdl library was causing trouble at the compilation, so I decided to settle for the Tsdl.
Messing around with SDL
Ok, so now I am back at trying to get the graphics done, I should now say that I have no previous experience with SDL, so I had to spend quite some time trying to understand how things work, and this is what I now understand (I am stating these facts here because I am not so confident about it, so a confirmation of this would be most welcome): There are two versions of SDL: SDL1.2 and SDL2. As far as I understand in SDL1.2, one use to define and print Surfaces, which are basically a huge block of pixels, with their color, this way of doing things is now considered deprecated, since SDL2. In SDL2, the canonical way of doing things is to use textures, as they allow to manipulate the graphical objects separately and move all the computations over to the GPU instead of relying on the CPU to compute on surfaces. So it is my understanding that given the nature of my project, I really should use the old way, even though it is deprecated, as I am emulating a program that does compute a bitmap at 60 hertz using the CPU. I have absolutely no interest in manipulating textures for this project, as nothing will ever change on the CPU.
Printing a bitmap using Surfaces with the Tsdl library
Here is where I am getting confused now, using the Tsdl library, I want to use the function Sdl.create_rgb_surface_from
which seems to me to correspond to the make_image
of the Graphics library. The issue is that once I call this function (and pattern-match to handle the error case separately), I get an object new_surface:Sdl.surface
, which I don’t know how to set to my window. I know that I can also get the surface associated to my window by calling Sdl.get_surface(window)
. It seems that in standard SDL (in C) these two functions give pointers (of type SDL_Surface *
), so if I was in C, I would just have to do SDL_GetSurface(window) = new_surface
, but of course that’s not how OCaml works.
So maybe there is a very easy trick that I am not seeing to account for the fact that the OCaml types really are pointers, but this all looks very confusing to me. I can see that the surface type in OCaml behaves like a pointer, as I can call Sdl.fill_rect surface rectangle color
which will fill a given rectangle of a given color in the surface. I feel like I am missing a function that takes a surface and sets in to another surface. It is my understanding that I could use Sdl.blit_surface
for this purpose, but that would mean unnecessarily copying the content of the first surface into the second instead of simply modifying the value of a pointer.
Questions
I have two questions related to what I have said:
- Am I using the right technology for this project? I am very happy to have written the CPU emulator in OCaml, I think that I could save a significant amount of work with the powerful design choices it offers and I am very satisfied on how it turned out. So I really want to stick with OCaml, but I have no clue if the libraries I am using for graphics and events are well suited to my purposes.
- Assuming that Tsdl is a reasonnable choice to perform what I do, how do I do the equivalent of
draw_image (make_image bitmap) 0 0
of the Graphics library?