* events may be the source of inaccuracy, it doesn't tell a lot.
*/
#include <allegro5/allegro.h>
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_primitives.h>
#include <stdio.h>
#include <stdarg.h>
#include <math.h>
#include "common.c"
struct Example
{
ALLEGRO_FONT *myfont;
ALLEGRO_EVENT_QUEUE *queue;
double FPS;
int x[4];
bool first_tick;
double this_time, prev_time, accum_time;
double min_diff, max_diff, second_spread;
double second;
double timer_events;
double timer_error;
double timestamp;
} ex;
static void init(void)
{
ex.FPS = 50;
ex.first_tick = true;
ex.myfont = al_create_builtin_font();
if (!ex.myfont) {
abort_example("Error creating builtin font\n");
}
}
static void cleanup(void)
{
al_destroy_font(ex.myfont);
ex.myfont = NULL;
}
static void print(int x, int y, char const *format, ...)
{
va_list list;
char message[1024];
va_start(list, format);
vsnprintf(message, sizeof message, format, list);
va_end(list);
al_draw_text(ex.myfont, al_map_rgb_f(0, 0, 0), x, y, 0, message);
}
static void draw(void)
{
int h, y, i;
double cur_time, event_overhead, total_error;
cur_time = al_get_time();
event_overhead = cur_time - ex.timestamp;
total_error = event_overhead + ex.timer_error;
h = al_get_font_line_height(ex.myfont);
al_clear_to_color(al_map_rgb_f(1, 1, 1));
print(0, 0, "%.9f target for %.0f Hz Timer", 1.0 / ex.FPS, ex.FPS);
print(0, h, "%.9f now", ex.this_time - ex.prev_time);
print(0, 2 * h, "%.9f accum over one second",
ex.accum_time / ex.timer_events);
print(0, 3 * h, "%.9f min", ex.min_diff);
print(0, 4 * h, "%.9f max", ex.max_diff);
print(300, 3.5 * h, "%.9f (max - min)", ex.second_spread);
print(300, 4.5 * h, "%.9f (timer error)", ex.timer_error);
print(300, 5.5 * h ,"%.9f (event overhead)", event_overhead);
print(300, 6.5 * h, "%.9f (total error)" , total_error);
y = 240;
for (i = 0; i < 4; i++) {
al_draw_filled_rectangle(ex.x[i], y + i * 60, ex.x[i] + (1 << i),
y + i * 60 + 60, al_map_rgb(1, 0, 0));
}
}
static void tick(ALLEGRO_TIMER_EVENT* timer_event)
{
int i;
ex.this_time = al_get_time();
if (ex.first_tick) {
ex.first_tick = false;
}
else {
double duration;
if (ex.this_time - ex.second >= 1) {
ex.second = ex.this_time;
ex.accum_time = 0;
ex.timer_events = 0;
ex.second_spread = ex.max_diff - ex.min_diff;
ex.max_diff = 0;
ex.min_diff = 1;
}
duration = ex.this_time - ex.prev_time;
if (duration < ex.min_diff)
ex.min_diff = duration;
if (duration > ex.max_diff)
ex.max_diff = duration;
ex.accum_time += duration;
ex.timer_events++;
ex.timer_error = timer_event->error;
ex.timestamp = timer_event->timestamp;
}
draw();
al_flip_display();
for (i = 0; i < 4; i++) {
ex.x[i] += 1 << i;
ex.x[i] %= 640;
}
ex.prev_time = ex.this_time;
}
static void run(void)
{
ALLEGRO_EVENT event;
while (1) {
al_wait_for_event(ex.queue, &event);
switch (event.type) {
case ALLEGRO_EVENT_DISPLAY_CLOSE:
return;
case ALLEGRO_EVENT_KEY_DOWN:
if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
return;
break;
case ALLEGRO_EVENT_TIMER:
tick(&event.timer);
break;
}
}
}
int main(int argc, char **argv)
{
ALLEGRO_DISPLAY *display;
ALLEGRO_TIMER *timer;
(void)argc;
(void)argv;
if (!al_init()) {
abort_example("Could not init Allegro.\n");
}
al_init_primitives_addon();
al_install_keyboard();
al_install_mouse();
al_init_font_addon();
display = al_create_display(640, 480);
if (!display) {
abort_example("Could not create display.\n");
}
init();
timer = al_create_timer(1.000 / ex.FPS);
ex.queue = al_create_event_queue();
al_register_event_source(ex.queue, al_get_keyboard_event_source());
al_register_event_source(ex.queue, al_get_mouse_event_source());
al_register_event_source(ex.queue, al_get_display_event_source(display));
al_register_event_source(ex.queue, al_get_timer_event_source(timer));
al_start_timer(timer);
run();
al_destroy_event_queue(ex.queue);
cleanup();
return 0;
}