Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » A5 : timer issue

This thread is locked; no one can reply to it. rss feed Print
A5 : timer issue
William Labbett
Member #4,486
March 2004
avatar

Hi, I've been trying to get to grips with the timer events and timers because I'm trying to work on the speed of animations.

I wrote this code :

#SelectExpand
1#include <allegro5/allegro.h> 2#include <allegro5/allegro_primitives.h> 3#include <allegro5/allegro_image.h> 4#include <allegro5/allegro_font.h> 5#include <stdio.h> 6#include <stdlib.h> 7 8 9 10 11 12int main() 13{ 14 ALLEGRO_DISPLAY *display = NULL; 15 ALLEGRO_FONT *font = NULL; 16 17 ALLEGRO_EVENT event; 18 19 int loop_count = 0; 20 bool got_loop_count = false; 21 bool counting_loops = false; 22 int timer_count_before = 0; 23 int timer_count_after = 0; 24 int time_counting = 0; 25 26 al_init(); 27 al_set_new_display_flags(ALLEGRO_WINDOWED); 28 29 ALLEGRO_EVENT_QUEUE *queue = al_create_event_queue(); 30 ALLEGRO_TIMER *timer = al_create_timer(1.0f/120.0f); 31 32 display = al_create_display(1600, 900); 33 if(display == NULL) 34 { 35 printf("Couldn't create display."); 36 } 37 38 if( al_init_primitives_addon() == false) 39 { 40 printf("Couldn't initialise image addon."); 41 } 42 43 al_init_image_addon(); 44 al_init_font_addon(); 45 46 al_install_keyboard(); 47 48 al_init_primitives_addon(); 49 50 font = al_load_font("fixed_font.tga", 24, 0); 51 52 53 54 al_register_event_source(queue, al_get_keyboard_event_source()); 55 al_register_event_source(queue, al_get_timer_event_source(timer)); 56 al_register_event_source(queue, al_get_display_event_source(display)); 57 al_start_timer(timer); 58 59 al_set_target_backbuffer(display); 60 61 al_clear_to_color(al_map_rgb(0, 0, 0)); 62 63 al_flip_display(); 64 65 while(1) 66 { 67 al_wait_for_event(queue, &event); 68 69 switch(event.type) 70 { 71 case ALLEGRO_EVENT_KEY_DOWN: 72 if(event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) 73 { 74 return 0; 75 } 76 else if(event.keyboard.keycode == ALLEGRO_KEY_F1) 77 { 78 al_destroy_display(display); 79 printf("Program finished.\n\n"); 80 system("PAUSE"); 81 return 0; 82 } 83 break; 84 case ALLEGRO_EVENT_TIMER: 85 86 if(got_loop_count == false) 87 { 88 printf("Got timer event.\n"); 89 } 90 91 if(counting_loops == true) 92 { 93 timer_count_after = al_get_timer_count(timer); 94 printf("timer count (second time) is %d.\n", timer_count_after); 95 96 97 time_counting = timer_count_after - timer_count_before; 98 got_loop_count = true; 99 counting_loops = false; 100 } 101 102 if(counting_loops == false && got_loop_count == false) 103 { 104 counting_loops = true; 105 timer_count_before = al_get_timer_count(timer); 106 printf("timer count (first time) is %d.\n", timer_count_before); 107 } 108 109 //al_flush_event_queue(queue); 110 111 break; 112 case ALLEGRO_EVENT_DISPLAY_CLOSE: 113 return 0; 114 break; 115 default: 116 break; 117 118 } 119 120 121 //al_clear_to_color(al_map_rgb(0, 0, 0)); 122 //al_draw_filled_circle(125, 384, 52.0f, al_map_rgb(255, 0, 0)); 123 124 if(got_loop_count == true) 125 { 126 al_draw_textf(font, al_map_rgb(255, 255, 255), 30, 10, 0, "Clock ticks = %d. Number of full loops : %d.", time_counting, loop_count); 127 al_draw_textf(font, al_map_rgb(255, 255, 255), 30, 25, 0, "Clock ticks before = %d. Clock ticks after = %d.", timer_count_before, timer_count_after); 128 } 129 130 al_flip_display(); 131 132 if(counting_loops == true) 133 { 134 printf("Incrementing loop_count.\n"); 135 ++loop_count; 136 } 137 138 } 139 140 return 0; 141 142}

I get this output :

Got timer event.
timer count (first time) is 4.
Incrementing loop_count.
Got timer event.
timer count (second time) is 4.

If someone would take the trouble to take a look at the code you might notice that despite the output confirming that a timer event and the ++loop_count; line have both occured imbetween the two points where al_get_timer_count is called the two calls to al_get_timer_count() both return 4. This doesn't make any sense to me. Does someone know why it's happening?

DanielH
Member #934
January 2001
avatar

Trying to wrap my head around what you have

#SelectExpand
1 // a 2 if(got_loop_count == false) 3 { 4 printf("Got timer event.\n"); 5 } 6 7 // b 8 if(counting_loops == true) 9 { 10 timer_count_after = al_get_timer_count(timer); 11 printf("timer count (second time) is %d.\n", timer_count_after); 12 13 14 time_counting = timer_count_after - timer_count_before; 15 got_loop_count = true; 16 counting_loops = false; 17 } 18 19 // c 20 if(counting_loops == false && got_loop_count == false) 21 { 22 counting_loops = true; 23 timer_count_before = al_get_timer_count(timer); 24 printf("timer count (first time) is %d.\n", timer_count_before); 25 }

start: glc = false, cl = false;

1st iteration: a printed, b ignored, c processed
cl = true, glc = false, tcb is set

cl is true so loop_count increments once

2nd iteration: a printed, b processed, c ignored
cl = false, glc = true, tca is set, tc is calculated (tca-tcb)

cl is false and will always be false after this point
loop_count not incremented.

3rd iteration: a ignored, b ignored, c ignored

Nothing happens after that because cl is false and glc is true

What is it supposed to do?

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Your code doesn't really make sense. Keep it simple. Allegro has everything you need in the timer event itself.

do {
   ALLEGRO_EVENT ev;
   al_wait_for_event(queue , &ev);
   if (ev.type == ALLEGRO_EVENT_TIMER) {
      old_ticks = tick_count;
      tick_count = ev.timer.count;/** forgive I can't remember if this is right*/
      do_stuff_with_ticks(tick_count - old_ticks);
   }
   else {...}
   
} while (!al_is_event_queue_empty(queue);

William Labbett
Member #4,486
March 2004
avatar

No, the code isn't familiar but it makes perfect sense. It does exactly what Daniel described. Thenks Daniel for working it out.

What it's meant to do is simple :

It calculates how many clock ticks it takes to run the code after the event loop.
I need to know this because I need to how frequently my drawing code gets executed. (I simplified the program and left out the drawing code).

So it makes a record of the timer count. Then it does one run of the code after
the event loop. Then when the code gets back to the event loop it waits for the next timer event and records the count.

What doesn't make sense it that according to the event queue there's a new timer tick but the timer count hasn't changed. The manual does say that once al_wait_for_event get's an event it copies the event into the ALLEGRO_EVENT * provided and removes it from the queue so the next ALLEGRO_EVENT_TIMER should be a new clock tick meaning the number returned from al_get_timer_count should be larger.

BTW If I call al_flush_event_queue which shouldn't be necessary the code works as expected.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

torhu
Member #2,727
September 2002
avatar

I need to know this because I need to how frequently my drawing code gets executed. (I simplified the program and left out the drawing code).

How frequently compared to your logic timer? Or do you want an FPS counter?

Normally you would just draw once per logic update. And maybe skip the drawing when the event queue is not empty after the logic is done to avoid getting behind.

William Labbett
Member #4,486
March 2004
avatar

Thanks very much to both of you.

torhu said:

How frequently compared to your logic timer?

It's got to be only as frequent or less frequent right? If it can't be more frequent I'd have to decrease the ticks_per_second passed to al_create_timer() EDIT : if I wanted to slow down the graphics updating ?.

I did also want an FPS counter and I figured that was sort of what I was doing in a not so normal way.

DanielH
Member #934
January 2001
avatar

al_wait_for_event will limit your frame counter to events. If you want to calculate FPS then draw every loop iteration and only process an event if there is an event.

Check out my Tic Tac Toe game. I don't wait for events.

#SelectExpand
1void App::processInput() 2{ 3 static ALLEGRO_EVENT event; 4 5 while (!al_event_queue_is_empty(this->m_queue)) 6 { 7 al_get_next_event(this->m_queue, &event); 8 9 switch (event.type) 10 { 11 case ALLEGRO_EVENT_TIMER: 12 { 13 ++this->m_counter; 14 } break; 15// ... 16} 17 18 19int32_t App::loop() 20{ 21 while (!this->m_kill) 22 { 23 this->processInput(); 24 25 while (this->m_counter > 0) 26 { 27 this->doLogic(); 28 --this->m_counter; 29 } 30 31 if (this->m_dirty) 32 { 33 this->draw(); 34 this->m_dirty = false; 35 } 36 37 al_rest(0.01); 38 } 39 40 return 0; 41}

You could remove the 'dirty' check and add a couple vars (frames and seconds). At each draw, increment a frame counter. At each timer increment a seconds counter. FPS = frames/second;

Go to: