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 solutionwithin 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 toTrent for the suggestion)

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.

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!

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.

This particular issue has been discussed before. While I personally wouldn't be opposed to such an opt-in feature, I still think it would be better to explicitly declare when such conversion takes place.

My suggestion is according the current behavior of video bitmaps silently being treated as memory bitmaps if there is no display. So only those memory bitmaps that are supposed to be video bitmaps would be uploaded.

If you don't want them uploaded, then why mark them as video bitmaps? It seems like people would always set ALLEGRO_UPLOAD_AS_SOON_AS_POSSIBLE with video bitmaps, so it seems extraneous to me.

To me, the important thing is to be able to say when and which display you want to use. But of course, the proposed flag could still be used along with an explicit function as I suggest. They aren't mutually exclusive. (But again, I don't think the flag is very useful.)

If you want to pick and choose with more precision than just globally uploading all bitmaps that are supposed to be video bitmaps, then an explicit function to convert a single bitmap could be used.

When I tried hacking this feature into A5 the ttf stuff had problems. Basically it was trying to auto-convert the memory ttf bitmaps to video bitmaps which is exactly what I don't want. But maybe I screwed something else up.

<edit> Ok I think a function that set a flag on a bitmap to convert to a video bitmap as soon as possible would be better than setting the global bitmap flags.

Basically it was trying to auto-convert the memory ttf bitmaps to video bitmaps which is exactly what I don't want.

With my suggestion you would just mark them as memory bitmaps when loading the TTF font, and the upload function would never try to convert them because they weren't originally loaded with the video bitmap flag set.

I assume that would work, but I don't know much about the TTF add-on.

Quote:

Ok I think a function that set a flag on a bitmap to convert to a video bitmap as soon as possible would be better than setting the global bitmap flags.

Is the proposed flag in your original post meant to be a display or bitmap one?

Anyway, I'm curious on the use cases. To me it seems like the ALLEGRO_VIDEO_BITMAPis the flag. And all we need is a function to claim those "video" bitmaps that are currently stored as memory bitmaps.

That is, if you set ALLEGRO_MEMORY_BITMAP, then those bitmaps would never be uploaded by the explicit claim-all function. You would have to convert those ones yourself by a function that operated on a single bitmap.

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.

I'm not sure that's necessarily true, I think you can blit to the display from a background thread (at least you could at one point), but you have to set things up to do that. Even then, this is probably not a very good idea and should be avoided, as you say (blitting to other displays should be fine though).

Anyway, nice post! I'm sure it'll be a great help to many people.

EDIT:

Quote:

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.

Forgot to say, a cleaner approach here may be to store/restore the target bitmap state. May not be worth it, but I thought I'd mention it in case you didn't know about the save/restore state functions.

I like it. al_upload_memory_video_bitmaps() should make loading bitmaps in another thread much easier. And from what I see it will also work for fonts (which currently can't be loaded in another thread at all since we have no al_clone_font() function).

(Doesn't really solve the issue we discussed last time... if you forget to create a video bitmap after al_create_display() you likely also forget to call al_upload_memory_video_bitmaps() )

if you forget to create a video bitmap after al_create_display() you likely also forget to call al_upload_memory_video_bitmaps()

I agree, but at least the solution is simple. I don't consider this functionality as a way to help the forgetful; it's meant to allow people who understand what they are doing have a bit more control over how to load images.

My architecture works best with on-demand uploading so as long as I can do that with whatever functions get added I'm fine.

Another issue I found last night is stretching bitmaps works differently in A4 and A5. In A4 if I stretch a bitmap with starting coordinates off the screen the bitmap will get stretched first and clipped second. In A5 its the reverse. So to emulate the A4 behavior I added a translate transformation before the scaling transformation and always draw to 0, 0.

Here is what it should look like in A4/SDL (note the position of Akuma):{"name":"a4.png","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/7\/0\/701e345b804ad5354e8a1f3945d9b2a8.png","w":646,"h":510,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/7\/0\/701e345b804ad5354e8a1f3945d9b2a8"}

Could we do that by actually making ALLEGRO_BITMAP a union of the current struct and the ALLEGRO_BITMAP_OGL/ALLEGRO_BITMAP_D3D structs? That's similar to how it's done with the event system.Not very different, but a bit less messy than allocating enough space for the largest of those structs by hand...

Hi guys, sorry for interrupt your deep conversation, but, I was studying one of Peter's examples (OGRE) and it says:

Quote:

Ogre 1.7 (and, optionally, earlier versions) uses the FreeImage library tohandle image loading. FreeImage bundles its own copies of common librarieslike libjpeg and libpng, which can conflict with the system copies of thoselibraries that allegro_image uses. That means we can't use allegro_imagesafely, nor any of the addons which depend on it.

One solution would be to write a codec for Ogre that avoids FreeImage, orwrite allegro_image handlers using FreeImage. The latter would probably beeasier and useful for other reasons.

Now that you're talking about bitmaps and so, implementing FreeImage would be too difficult? this has something to do with what you're talking about?.

Because I really think making Allegro compatible with OGRE would be a strong step, don't you think?