Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Porting from Allegro 4.4 to 5.0

This thread is locked; no one can reply to it. rss feed Print
Porting from Allegro 4.4 to 5.0
Francis Langlais
Member #15,985
June 2015

I'm student and I just finished my 2nd year in computer engineering and I'm working for my teacher for the summer and one of the task he gave me was to port a game from Allegro 4.4 to Allegro 5.0. He don't know anything about Allegro and the person who code the game (let's call him John) left so I have no reference at all. The game is 4 automated robot fighting with lasers and missiles and the student have to code their behaviour using C. As of now I think I did everything right using Allegro 4.4 and Allegro 5.0 User guide but there is some question I have that I can't seem to find any answer so I'll ask them here.

First : timers

In Allegro 4.4 John use LOCK_VARIABLE and LOCK_FUNCTION which from what I understand are needed in Allegro 4.4 for timers and are not used in Allegro 5.0 anymore. He also use install_int_ex function.

My question is : Do install_int_ex do the same thing as al_create_timer(timerName)? What does the LOCK function did in Allegro 4.4?

Here is the code:

#SelectExpand
1volatile int calcCounter = 0; 2volatile int calcsCompleted = 0, cps = 0; 3volatile int frameCounter = 0, fps = 0; 4 5void FPSTimer(void) { 6 fps = frameCounter; 7 frameCounter = 0; 8 cps = calcsCompleted; 9 calcsCompleted = 0; 10} 11 12void AddCalc(void) { 13 calcCounter++; 14} 15 LOCK_VARIABLE(calcCounter); 16 LOCK_VARIABLE(calcsCompleted); 17 LOCK_VARIABLE(cps); 18 LOCK_VARIABLE(frameCounter); 19 LOCK_FUNCTION(fps); 20 LOCK_FUNCTION(AddCalc); 21 22 if (install_int_ex(AddCalc, BPS_TO_TIMER(CALCS_PER_SEC)) != 0) 23 AbortOnError( 24 "Fight() failed to create calcs timer.\nProgram will exit."); 25 26 if (install_int_ex(FPSTimer, SECS_TO_TIMER(1)) != 0) 27 AbortOnError("Fight() failed to create FPS timer.\nProgram will exit.");

Second : floodfill

Floodfill was a function in Allegro 4.4 that did the same thing the fill bucket do in MSpaint.
floodfill(BITMAP targetBitmap, int x, int y, int color);
I did find a solution on the forum but the person told that it use alot of memory to draw pixel by pixel on a BITMAP.

My question : Is there any way to implement this function without using too much memory?

Third and last : do_line

This one is trickier. This function calculate all the point on a line and do a function along this line. In the game this is use to check if there is a something along a line sensor. If so the line stop at the first pixel it encounter that is not the background color.
void do_line(BITMAP *bmp, int x1, y1, x2, y2, int d, void (*proc)(BITMAP *bmp, int x, int y, int d));

My question : Is there a way to do this? If not how should I do it using a minimum of memory.

*Sorry for my English.

Edgar Reynaldo
Member #8,592
May 2007
avatar

First : timers

In Allegro 4.4 John use LOCK_VARIABLE and LOCK_FUNCTION which from what I understand are needed in Allegro 4.4 for timers and are not used in Allegro 5.0 anymore. He also use install_int_ex function.

My question is : Do install_int_ex do the same thing as al_create_timer(timerName)? What does the LOCK function did in Allegro 4.4?

You don't need to worry about locking any functions or data with Allegro 5, unless you're working with bitmap data directly, but there are functions for that.

install_int_ex doesn't do the same thing as al_create_timer. It installs a call back function that gets called every time the timer ticks. You can do the same thing in allegro 5 by doing this :

al_register_event_queue(queue , al_get_timer_event_source(timer);
//...
ALLEGRO_EVENT ev;
al_wait_for_event(queue , &ev);
if (ev.type == ALLEGRO_EVENT_TIMER) {
   /// Put the code from install_int_ex inside here for the same effect
   /// Eg...
   /// ++count;
}

Quote:

Third and last : do_line

This one is harder but can still be done using al_draw_soft_line. I can't give you the exact details though.

Francis Langlais
Member #15,985
June 2015

Thank you! That help a lot for the timer.

Chris Katko
Member #1,881
January 2002
avatar

Check out these for some differences between the two library versions:

https://wiki.allegro.cc/index.php?title=Porting_from_A4_to_A5

https://www.allegro.cc/forums/thread/610896/964091

http://stackoverflow.com/questions/6418757/porting-allegro-4-to-allegro-5

I'm not sure if this is helpful, or rambling and confusing, so if the latter, feel free to disregard:

Basically, in Allegro 4, everything was double buffered (draw everything to a memory bitmap, and then when you're entirely done, blit that to the screen at the right time with vsync so it doesn't flicker) or page flipped. (Rare, everything is in video memory and VRAM-to-VRAM copied to a off-screen page of VRAM. Then when ready, change the videocard's "screen" to point to that new page. It uses two pages, and they are flipped between each other.)

I believe Allegro 5 is page flipped because modern Direct3D and OpenGL do that. Allegro is a thin layer over those. Whereas Allegro 4 had to "re-invent the wheel" with specific routines for everything because in general, there were no frameworks for that.

There are two ways to do things:

The old way, you either used double buffering (everyhthing was kept locally in RAM), or page flipping (everything in VRAM so it's hardware accelerated 2-D if the card supports it.).

The new way goes through OpenGL/DirectX, which then go through the native graphics driver. So instead of fiddling with registers, you're calling API's which call driver API's which say "draw this please." Everything is in a texture, and Allegro bitmaps are tied to textures with some additional helper information around them.

[This paragraph can be skipped:]
The new way also has the "Fixed/Classic Pipeline" (~1995-2005) vs "Modern Pipeline" (~2005 onward). Classic pipeline used to be faster because it was set-in-stone. Shaders were for special things, and the fixed pipeline did everything else like vertex transformation. The modern pipeline let you (and forced you!) to use shaders for everything. Without a shader, you don't get anything on the screen. These days, the fixed pipeline forces the card into compatibility mode. It's slower, but still 1000's of times faster than your traditional old videocards. IIRC, Allegro normally runs in fixed mode, and that's fine for 2-D games. But if you go on, you'll want to look into the details of this.

They already mentioned that A4 used timers, A5 uses event queues.

Allegro 5 uses event queues for everything. They're not too hard, but they're different, so read up on them. You're just running an event handler that checks if any events are on the event queue, and if so, it deals with them. That's it. But if you're careful, you can still structure a game like Allegro 4 without an event handler, so it should be relatively easy to port an A4 game to A5 without ripping out the core logic.

[edit]

My question : Is there a way to do this? If not how should I do it using a minimum of memory.

I don't recall the solution to your problem off-the-top of my head, but don't worry about using "minimum amounts of memory." Memory is cheap. Super cheap. Use whatever solution makes sense. It's unlikely you'll be wasting too much memory.

Quote:

*Sorry for my English.

Don't worry about it. I definitely had far worse English when I started here.

-----sig:
“Programs should be written for people to read, and only incidentally for machines to execute.” - Structure and Interpretation of Computer Programs

Francis Langlais
Member #15,985
June 2015

For an event source of a timer, do I have to clear the event queue after a tick or is every tick a new event?

I just don't understand when to clear my event queue or not.

Also, I don't want the whole game to wait for that timer (I guess, still not sure about that). Is there a way to store the present event into ALLEGRO_EVENT ev; without stopping the program and wait for it?

Edgar Reynaldo
Member #8,592
May 2007
avatar

For an event source of a timer, do I have to clear the event queue after a tick or is every tick a new event?

No, when you call al_wait_for_event or you call al_get_next_event and it returns true, then the event is taken off the queue. So every tick is a new event, and it ticks at the rate you set with al_create_timer.

Quote:

Also, I don't want the whole game to wait for that timer (I guess, still not sure about that). Is there a way to store the present event into ALLEGRO_EVENT ev; without stopping the program and wait for it?

Yes, see al_get_next_event or al_wait_for_event_timed or al_wait_for_event_until.

Typically the input loop looks like this :

#SelectExpand
1ALLEGRO_EVENT_QUEUE* queue = al_create_event_queue(); 2if (!queue) {return 1;} 3al_register_event_source(queue , al_get_keyboard_event_source()); 4al_register_event_source(queue , al_get_mouse_event_source()); 5al_register_event_source(queue , al_get_display_event_source(display)); 6al_register_event_source(queue , al_get_timer_event_source(timer)); 7 8// Input loop 9while (!quit) { 10 if (redraw) { 11 // redraw 12 al_flip_display(); 13 redraw = false; 14 } 15 16 do { 17 ALLEGRO_EVENT ev; 18 al_wait_for_event(queue , &ev); 19 if (ev.type == ALLEGRO_EVENT_TIMER) { 20 // do some timed action 21 redraw = true; 22 } 23 if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { 24 quit = true; 25 break; 26 } 27 } while (!al_is_event_queue_empty(queue)); 28}

Francis Langlais
Member #15,985
June 2015

Ok so I think I understand.

In the example Edgar mentioned with the input loop, you have the if(redraw) loop that redraw the whole scene every time the while start. Does that make it the FPS of my program?

Because as I say earlier, that was code using Allegro 4.4 and I think all the structure of the program is now wrong because of it. So should I try to match the example or should I just keep it as it is?

#SelectExpand
1int main(int argc, char *argv[]) { 2 ROBOTCOLORS colours[4] = { ROBOT_RED, ROBOT_GREEN, ROBOT_YELLOW, 3 ROBOT_PURPLE }; 4 int cnt; 5 6 ProcessCommandLine(argc, argv); 7 InitCompetition(); 8 9 for (cnt = 0; cnt < numInCompetition; cnt++) { 10 (*fpREG[registeredRobots[cnt]])(colours[cnt]); 11 } 12 13 Fight(); 14 EndCompetition(); 15 16 return EXIT_SUCCESS; 17}

This is my main and the action is in the Fight(); function.
At the moment I have an event queue for my graphic when I draw everything and I have another one where I use the timer and my keyboard input.

Edgar Reynaldo
Member #8,592
May 2007
avatar

Francis Langlais
Member #15,985
June 2015

#SelectExpand
1void Fight() { 2 int calcsUntilOrders = 0; 3 char systemMessage[255] = ""; 4 ROBOT *robot; 5 6 ALLEGRO_EVENT_QUEUE *event_queue = NULL; 7 ALLEGRO_EVENT event; 8 ALLEGRO_TIMER *FramePerSecondTimer; 9 ALLEGRO_TIMER *AddCalcTimer; 10 11 AddCalcTimer = al_create_timer(1 / 60); 12 FramePerSecondTimer = al_create_timer(1); 13 event_queue = al_create_event_queue(); 14 al_register_event_source(event_queue, al_get_keyboard_event_source()); 15 al_register_event_source(event_queue, 16 al_get_timer_event_source(FramePerSecondTimer)); 17 al_register_event_source(event_queue, 18 al_get_timer_event_source(AddCalcTimer)); 19 20 al_get_next_event(event_queue, &event); 21 if (event.timer.source == AddCalcTimer) { 22 AddCalc(); 23 } 24 25 if (event.timer.source == FramePerSecondTimer) { 26 FPSTimer(); 27 } 28 29 while (event.keyboard.keycode != ALLEGRO_KEY_SPACE) 30 ; //Wait for screen to initialize before starting. 31 32 theGame.state = GS_FIGHTING; 33 34 while (event.keyboard.keycode != ALLEGRO_KEY_ESCAPE) { 35 36 if (event.type == ALLEGRO_EVENT_KEY_DOWN) //Check for relevant keys. 37 { 38 if (event.keyboard.keycode == 'r' || event.keyboard.keycode == 'R') //User wants re-randomized loc's. 39 ForeachLL_M(robotList, robot) 40 { 41 ChooseRandomLocation(robot); 42 robot->heading = GetRandomNumber(360); 43 } 44 } 45 46 while (calcCounter) { 47 calcCounter--; 48 calcsUntilOrders++; 49 50 UpdateEnergySystems(robotList); //Do first so we know what 51 //systems are powered. 52 MoveRobots(robotList); 53 DrawRobotBitmaps(robotList); 54 CheckRobotCollisions(&theGame, robotList); 55 56 MoveWeapons(weaponList); 57 CheckWeaponCollisions(&theGame, robotList, weaponList); 58 59 //Now that collisions are 60 ApplyDamage(&theGame, robotList, deadRobotList); //done and weapons have 61 //hit, we apply damage. 62 63 DrawSensorBitmaps(robotList); //Need to draw BEFORE data is 64 //updated because bimaps are 65 //used in collision detection. 66 UpdateSensorData(robotList); 67 68 UpdateParticles(); 69 70 calcsCompleted++; 71 72 if (calcsUntilOrders == ORDER_FREQ) { 73 calcsUntilOrders = 0; 74 ForeachLL_M(robotList, curRobot) 75 curRobot->ActionsFunction(TURN_TIME); 76 } 77 78 if (theGame.useSounds) 79 PlaySounds(&theGame); 80 81 } 82 83 sprintf(systemMessage, "FPS: %d CPS: %d", fps, cps); 84 RenderScene(robotList, deadRobotList, weaponList, systemMessage); 85 frameCounter++; 86 } 87}

That's the whole Fight function. It's where everything happens except for initializing/de-initializing everything.

The main difference I see with your example is that I draw everything at the end of my loop inside Fight().

Edgar Reynaldo
Member #8,592
May 2007
avatar

Allegro 5 is event based. You need to check for events inside a loop, because they will keep coming. You can't just check for an event once, and then expect it to change.

Also, you need to make sure the event type matches the data you are trying to get out of it.

Ie.

// This loop will check for all current events
while (al_get_next_event(queue , &ev) {
   if (ev.type == ALLEGRO_EVENT_KEY_DOWN) {
      // Now it's okay to access the keyboard member, because we know it's a keyboard event
      if (ev.keyboard.keycode == ALLEGRO_KEY_R) {
         // do stuff
      }
   }
}

Thomas Fjellstrom
Member #476
June 2000
avatar

That will also spin the loop needlessly.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Edgar Reynaldo
Member #8,592
May 2007
avatar

I realize that. ;) I'm just trying to explain the basics of using a loop to process all the events. If you look at my earlier example it uses al_wait_for_event. He didn't seem to fully grasp that model yet so I tried to use a simpler version to explain things. That's all. ;)

Go to: