I have added an Allegro5 back-end to my game engine, paintown, and here is my experience doing the port.
Originally Paintown was written using Allegro4. Eventually I wanted to have better support for OSX and the ability to resize windows so I ported the game to SDL (while keeping the Allegro4 back-end). Recently I have implemented most of the Allegro5 back-end well enough to play the game sans a few features.
Porting Allegro4 to SDL was not that hard. Mostly I had to assemble various extra SDL libraries that together give the same functionality as Allegro4. Allegro4 and SDL share mostly the same philosophy about 2d graphics: create memory bitmaps at will and blit them to the screen at some point. I already had a wrapper class around Allegro4 so none of my game logic had to change to support the SDL back-end.
Implementing Allegro5 was much harder. The single most major issue I repeatedly ran into was the split between video and memory bitmaps. The main thread is the only one that should be creating video bitmaps (assuming a single display for the application) and is the only thread that should be blitting said bitmaps. All other threads should deal with memory bitmaps.
The main thread also should only be blitting/drawing video bitmaps to the backbuffer rather than drawing on those video bitmaps and then blitting them like in Allegro4/SDL. I had a few places where I would create a bitmap, draw some rectangles and circles on it, and then blit it to the screen. Instead its better to create sub-bitmaps of the backbuffer and draw the rectangles and circles directly to the backbuffer. This resulted in fewer resources being used for all backends because I didn't need to create an extra memory bitmap in Allegro4/SDL nor did I need an FBO in Allegro5. I did run into the dreaded "so I add 0.5 to all coordinates?" issue but I seemed to have gotten past that.
Paintown is set up to show a loading screen while various resources are being loaded and this is where I learned about the difference between memory and video bitmaps. After initially sort of getting things to work the game ran but extremely slowly (~3fps). The reason is that the loading threads were creating memory bitmaps by default because there was no 'current_display' set in the tls structure. When a new thread is created the tls structure is initialized mostly with 0's for every field. I still use this setup, where loading threads create memory bitmaps, but now I convert them to video bitmaps before they are used in the main thread (more on this later).
I was experiencing many segfaults during development that were very hard to debug until I finally ran valgrind. It turned out that the problem was in the way I was using the ttf addon. The loading threads were calling al_get_font_width and al_get_font_height but those methods try to actually draw the text and measure the size of the pixels that come out. Before the loading thread was created I had already used the fonts in the main thread to draw the menu and so the ttf drew the glyphs using its cache of video bitmaps that were created in the main thread. When the loading thread tried to use these same fonts a segfault occurred because the video bitmaps from the main thread could not be used in a thread where there was no display set up.
The solution to the ttf problem was to keep two versions of a font, one that just used video bitmaps and one that used memory bitmaps. As long as the current target bitmap is NULL the fonts will use memory bitmaps. My code looks basically like this:
I talked with Elias about this on IRC who would like to find some solution
within the ttf addon itself.
A somewhat related problem to the fonts (or at least one that manifested itself while the fonts were being used) was reseting the target bitmap. I do draw onto bitmaps occasionally and the bitmap wrapper class supports this so it calls al_set_target_bitmap(my_bitmap) before any draw operation. Of course the bitmap class also destroys the ALLEGRO_BITMAP* in the destructor which could end up with the situation that a destroyed bitmap was still set as the target bitmap. The solution was to set the target bitmap to NULL if the current target is the same as the bitmap about to be destroyed.
Finally I dealt with the issue of converting memory bitmaps to video bitmaps by checking if the bitmap is memory immediately before it was drawn to a video bitmap. If that is the case then I clone the bitmap as a video bitmap and destroy the old memory bitmap.
This works ok except it breaks the sharing properties I was using in my game. Objects that share Bitmap objects share the underlying ALLEGRO_BITMAP* pointer but when one object creates its own ALLEGRO_BITMAP* then it becomes the sole owner thus the bitmap could be duplicated amongst several objects. I could make my engine smarter about this but at this point it would be a pain to fix.
Instead Elias suggested a new flag for bitmaps that would automatically convert memory bitmaps to video if the same scenario existed as above. Something like ALLEGRO_UPLOAD_AS_SOON_AS_POSSIBLE. I took a very quick stab at hacking it into Allegro5 but it didn't work, Elias says he will try to implement it later in the week or something.
Blending confused the heck out of me for a while. Basically I randomly changed the arguments to al_set_blender until it worked and I think I understand things now but they are definitely not intuitive to someone coming from Allegro4/SDL.
To emulate draw_trans_sprite from Allegro4 in Allegro5 this is what I used (credit to
Trent for the suggestion)
is equal to
I have yet to implement a handful of features like dealing with the 8-bit stuff that MUGEN mode wants and resizing windows but things are looking up. Allegro5 is pretty cool once you get used to it so thanks to everyone who continually works on it.
If you want to try Paintown in Allegro5 mode build it like so:
$ svn co https://paintown.svn.sourceforge.net/svnroot/paintown/trunk
$ export ALLEGRO5=1
The only dependency is scons. There is a cmake build but it doesn't support Allegro5 yet (but it will eventually). Also I only tested on linux so far but if it works on other os's I would be glad to know!