Porting from A4 to A5
From Allegro Wiki
Contents |
a4_aux.c
Versions of Allegro 4.9.19 and greater started shipping with a basic compatibility layer that translates Allegro 4 function calls (actually rewrites the functions) into Allegro 5 calls. The files are located in demos/speed and are named a4_aux.c and a4_aux.h. These could be helpful porting aids. The game "Speed" written by Shawn Hargreaves for Speedhack 1999 has been ported (as you may have already guessed) to Allegro 5 using this thin wrapper. Check out the source releases or svn for these files.
Documentation
Just like with A4, also in A5 the developers try to maintain a high quality and up-to-date reference manual - it always should be your first stop to look up how something is supposed to work: http://docs.liballeg.org
Mainloop and events
Your A4 mainloop likely looked like:
volatile int ticks; void timer(void) {ticks++;} ... install_int(timer, 1000.0 / FPS); ... while (1) { if (game_ticks < ticks) { poll_input(); handle_game_tick(); game_ticks++; need_redraw = true; } else if (need_redraw) { render_last_frame(); need_redraw = false; } rest(1); }
With various variations as how to handle frame skipping and other things. The main points are that input was polled, timing was done by installing a timer, and the loop was constructed so rest(1) would be executed whenever nothing else was to do.
With A5, everything is events based, so you would do something like:
al_install_timer(1.0 / FPS); ... while (1) { al_wait_for_event(queue, &event); /* handle input events */ if (event.type == ALLEGRO_EVENT_TIMER) { handle_game_tick(); need_redraw = true; } if (need_draw && al_event_queue_is_empty(queue)) { render_last_frame(); need_redraw = false; } }
Once you understand what is happening, this is a much cleaner solution. Whenever any input occurs, you get an event instantly. So you could have more fine-controlled input handling than in A4, or otherwise just collect input until the next game tick so it would work like A4. Similar, you get an event now at the exact time the timer ticks. There is no more need for something like rest(1), as your program will not even run as long as there are no events (al_wait_for_event will only return once there is a new event). There are again various ways to deal with frame skipping and other things - everything possible in A4 is still possible in A5.
Graphics
A5 uses floating point coordinates. While it needs some time to get used to, it often leads to clearer code, and is the only way to properly deal with sub-pixel accuracy (which was impossible with A4).
Filled shapes
For example if you draw a filled rectangle:
al_draw_filled_rectangle(2, 2, 7, 7, color)
It will fill a rectangle going from the coordinates 2.0/2.0 to 7.0/7.0, and usually fill it using something called the mid-point rule, that is, actually fill all pixels whose midpoint is inside the rectangle:
Note how the call
rectfill(screen, 2, 2, 7, 7, color)
in A4 would more correspond to this in A5:
al_draw_filled_rectangle(2.0, 2.0, 8.0, 8.0, color)
Because of the midpoint rule, it is best to avoid filled shapes which go through the center of a pixel. In such cases, it is up to the graphics drivers and graphics hardware whether to fill the pixel or not. In the case of filled rectangles, simply always draw from and to integer position and you will be fine. If you enable super-sampling, this is of course less important.
Hairlines
Things are slightly different for hair-lines. (Lines with a thickness of 1 are filled shapes, only thickness 0 means hairlines.) Here a pixel usually is lit when the hairline crosses it, like for example here:
It is drawn with:
al_draw_rectangle(screen, 2.5, 2.5, 6.5, 6.5, color, 0)
in A4 this would correspond more to:
rect(2, 2, 6, 6, color)
Here now the ambiguous case is when the shape touches the border between two pixels. Implementations again have no way of knowing which pixel to light - so if you want the exact same pixel-by-pixel result keep the shape in the middle of pixels. If you enable super-sampling, the lines will be drawn fully anti-aliased and this doesn't matter so much.
Thick lines
Often thick lines will have better results. For example
al_draw_rectangle(screen, 2.5, 2.5, 6.5, 6.5, color, 1)
will look the same as the hairline version, but this time actually is a filled shape with an outer outline from 2.0, 2.0 to 7.0, 7.0 and an inner outline from 3.0, 3.0 to 6.0, 6.0. This means the underlying rasterizer (e.g. OpenGL or DirectX) has less room to leave out or overdraw single pixels.
Sound
In A5 there is now an explicit distinction between a (hardware-)voice and a (software-)mixer so you can decide to stream sound directly to the hardware if you want or let Allegro do some mixing. Usually you likely don't care and just use the defaults, then play samples and stream music. For samples you still can get full control of how many are played, like with A4's voices. The simple API looks something like:
al_install_audio(ALLEGRO_AUDIO_DRIVER_AUTODETECT); al_reserve_samples(8); /* Load a sample. */ sample = al_load_sample("ding.ogg"); /* Play it. */ al_play_sample(sample, 1, 0, 1, ALLEGRO_PLAYMODE_ONCE, NULL);
Bold text


