Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Timers and high speed animation - need advice!

This thread is locked; no one can reply to it. rss feed Print
Timers and high speed animation - need advice!
James Bunting
Member #30
April 2000
avatar

I am trying to understand the Allegro timer/interrupt code in a little more detail as I need a high precision timer system for high speed animations. I need to animate loads of things at all kinds of speeds but using just one interrupt.

In a nutshell to get the full range of intervals I need (in this case to animate stuff with a range from 1 to 60 times per sec) I need to install a timer that fires every 120 hunds/sec. I figure this because it allows me to move things at >30 intervals (say 55 or 49 etc). To not double the timer range to 120 (as in run it at 60 ticks) means that there is no difference between moving 31 and 59 times per sec as the move interval will not divide into the ticks.

Anyway putting all that stuff aside (which can clearly be a real head bender) my questions are...

1. Am I missing the point totally and looking at things the wrong way? Is there another way of getting stuff to animate at anything from 1 to 59 or even say 47 times per sec?

2. If my game slows down to < 120 FPS (very likely at times) would the timer interrupt not fire on time. So it it seperate from the game code like a "proper hardware" interrupt under DOS?

3. Is 120 ticks per sec considered too fast for an Allegro interrupt? Not the norm surely?

Michael Jensen
Member #2,870
October 2002
avatar

I think the highest you can really depend on is about 100 ticks a second -- the timers arn't much more accurate than 10ms... (I don't think even the Windows OS timers are for that matter)...

At any rate, if you're going to max out at 60 animations per second, then the most you'll ever need to call your timer is 60 times a second...

Basically, in each of your objects have a constant variable that says how many ticks to skip per frame of animation, and another variable to count. (For instance if you want to animate an object at 60 fps, you would never skip any frames and the constant would be 1, if you wanted 30 fps for another object, you would set it to 2, 45 fps would be 1.33, 15 fps would be 4 -- I think the formula is something like constant_skip_var = (1/(fps/60) )

every tick you would add one to the counter, and every time the counter was equal to or greater than the constant you would call your animate (usually just incrase the frame counter) and subtract the constant value from the counter value.

--- that method has some obvious flaws though.

Audric
Member #907
January 2001

Quote:

1. Am I missing the point totally and looking at things the wrong way? Is there another way of getting stuff to animate at anything from 1 to 59 or even say 47 times per sec?

You should be able to do everything with a single-speed timer, for example 100Hz.

Animate means either or all of the following:
a) take a "logical step" in the unit's AI: examine the situation and make decisions accordingly.
b) modify the coordinates : this is the movement.
c) modifiy the appearance. sprite, color, blinking effect on/off, angle (heading)

For b), you can use coordinates and speed with a precision higher than pixel "integers". So you can precisely map any speed and position: A constant +0.35 speed will result in a movement of 35 pixels per second.

a) and c) usually can be taken as discrete steps, so they don't need sub-step precision.

ImLeftFooted
Member #3,935
October 2003
avatar

1#ifndef TIMER_H
2#define TIMER_H
3 
4#ifndef WIN32
5#include <sys/time.h>
6#endif
7 
8extern class Timer {
9public:
10
11 typedef unsigned int time_t;
12
13private:
14
15#ifdef WIN32
16 unsigned long long startTime;
17 unsigned long long currentTime;
18#else
19 timeval startTime;
20 timeval currentTime;
21#endif
22
23public:
24
25 Timer();
26
27 time_t usecs();
28 time_t msecs();
29 time_t secs();
30
31}timer;
32 
33#endif

1#include "timer.h"
2#include "log.h"
3 
4#ifdef WIN32
5#include <windows.h>
6#else
7#include <sys/time.h>
8#endif
9 
10Timer timer;
11 
12Timer::Timer()
13{
14#ifdef WIN32
15 startTime = GetTickCount();
16#else
17 gettimeofday(&startTime, 0);
18#endif
19}
20 
21Timer::time_t Timer::usecs()
22{
23#ifdef WIN32
24 static bool onetime = 0;
25 static unsigned long long freq = 0;
26
27 if(!onetime) {
28
29 onetime = true;
30 QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
31 }
32
33 QueryPerformanceCounter((LARGE_INTEGER*)&currentTime);
34
35 currentTime *= 1000000;
36 currentTime /= freq;
37
38 return currentTime - startTime * 1000;
39#else
40 gettimeofday(&currentTime, 0);
41
42 return (unsigned long)((currentTime.tv_sec - startTime.tv_sec) / 1000)
43 + (unsigned long)((currentTime.tv_usec - startTime.tv_usec));
44#endif
45}
46 
47Timer::time_t Timer::msecs()
48{
49#ifdef WIN32
50 currentTime = GetTickCount();
51
52 return currentTime - startTime;
53#else
54 gettimeofday(&currentTime, 0);
55
56 return (unsigned long)((currentTime.tv_sec - startTime.tv_sec) * 1000)
57 + (unsigned long)((currentTime.tv_usec - startTime.tv_usec) / 1000);
58#endif
59}
60 
61Timer::time_t Timer::secs()
62{
63#ifdef WIN32
64 currentTime = GetTickCount();
65
66 return (currentTime - startTime) / 1000;
67#else
68 gettimeofday(&currentTime, 0);
69
70 return (unsigned long)(currentTime.tv_sec - startTime.tv_sec);
71#endif
72}
73#endif

There are 1000 milliseconds(msecs) in a second, and 1000 usecs in a millisecond.

Tested on windows and linux and usec precision appears to be pretty consistent.

[edit]
Heres some usage:

...
Timer::time_t t = timer.usecs();

...

cout << timer.usecs() - t << " Microseconds have passed.\n";

Wilson Saunders
Member #5,872
May 2005
avatar

If some of your animations are running too fast you should have a frame display for multiple updates.
So if your code looks like this:

1void Update(){
2 anim ++;
3 if( anim >= 3) anim = 0;
4}
5 
6void draw(){
7 switch(anim){
8 case 0:
9 draw_frame0();
10 break;
11 case 1:
12 draw_frame1();
13 break;
14 case 2:
15 draw_frame2();
16 break;
17}

You can make it run at half speed by changing it to look like this:

1void Update(){
2 anim ++;
3 if( anim >= 6) anim = 0;
4}
5 
6void draw(){
7 switch(anim){
8 case 0:
9 case 1:
10 draw_frame0();
11 break;
12 case 2:
13 case 3:
14 draw_frame1();
15 break;
16 case 4:
17 case 5:
18 draw_frame2();
19 break;
20}

________________________________________________
Play my games at http://monkeydev.com

BAF
Member #2,981
December 2002
avatar

Just some simple math is needed. Here is my (probably flawed somehow) code from a TINS a few years ago:

anim.h:

#SelectExpand
1// baf 2005 2 3// anim.h 4// animation stuff 5 6#ifndef ANIM_H 7#define ANIM_H 8 9#include "main.h" 10#include "timers.h" 11 12typedef struct ABITMAP 13{ 14 int num_frames, fps, w, h, masked; 15 BITMAP **frames; 16} ABITMAP; 17 18typedef struct ABITMAP_INSTANCE 19{ 20 ABITMAP *parent; 21 int curframe; 22} ABITMAP_INSTANCE; 23 24ABITMAP *load_abitmap(const char *filename); 25int save_abitmap(const char *filename, ABITMAP *bmp); 26ABITMAP_INSTANCE *grab_abitmap_instance(ABITMAP *bmp); 27 28void destroy_abitmap(ABITMAP *bmp); 29void destroy_abitmap_instance(ABITMAP_INSTANCE *bmp); 30 31void update_animation(ABITMAP_INSTANCE *bmp); 32void ablit(ABITMAP_INSTANCE *source, BITMAP *dest, int dest_x, int dest_y); 33void ablit_r(ABITMAP_INSTANCE *source, BITMAP *dest, int dest_x, int dest_y, fixed angle); 34 35#endif

anim.c:

#SelectExpand
1// baf 2005 2 3// anim.c 4// animation stuff 5 6#include "anim.h" 7 8int lac = 0; 9 10ABITMAP *load_abitmap(const char *filename) 11{ 12 PACKFILE *abmp; 13 ABITMAP *ret; 14 int i, x, y; 15 abmp = pack_fopen(filename, "r"); 16 if(!abmp) 17 return NULL; 18 ret = (ABITMAP *)malloc(sizeof(ABITMAP)); 19 ret->num_frames = pack_igetl(abmp); 20 ret->fps = pack_igetl(abmp); 21 ret->w = pack_igetl(abmp); 22 ret->h = pack_igetl(abmp); 23 ret->masked = pack_igetl(abmp); 24 ret->frames = (BITMAP **)malloc(sizeof(BITMAP *) * ret->num_frames); 25 for(i = 0; i < ret->num_frames; ++i) 26 { 27 abmp = pack_fopen_chunk(abmp, 1); 28 ret->frames<i> = create_bitmap(ret->w, ret->h); 29 for(y = 0; y < ret->h; ++y) 30 for(x = 0; x < ret->w; ++x) 31 putpixel(ret->frames<i>, x, y, makecol(pack_igetl(abmp), pack_igetl(abmp), pack_igetl(abmp))); 32 abmp = pack_fclose_chunk(abmp); 33 } 34 pack_fclose(abmp); 35 return ret; 36} 37 38int save_abitmap(const char *filename, ABITMAP *bmp) 39{ 40 PACKFILE *abmp; 41 int i, x, y, col; 42 abmp = pack_fopen(filename, "w"); 43 if(!abmp) 44 return -1; 45 pack_iputl(bmp->num_frames, abmp); 46 pack_iputl(bmp->fps, abmp); 47 pack_iputl(bmp->w, abmp); 48 pack_iputl(bmp->h, abmp); 49 pack_iputl(bmp->masked, abmp); 50 for(i = 0; i < bmp->num_frames; ++i) 51 { 52 abmp = pack_fopen_chunk(abmp, 1); 53 for(y = 0; y < bmp->h; ++y) 54 { 55 for(x = 0; x < bmp->w; ++x) 56 { 57 col = getpixel(bmp->frames<i>, x, y); 58 pack_iputl(getr(col), abmp); 59 pack_iputl(getg(col), abmp); 60 pack_iputl(getb(col), abmp); 61 } 62 } 63 abmp = pack_fclose_chunk(abmp); 64 } 65 pack_fclose(abmp); 66} 67 68ABITMAP_INSTANCE *grab_abitmap_instance(ABITMAP *bmp) 69{ 70 ABITMAP_INSTANCE *ret; 71 ret = (ABITMAP_INSTANCE *)malloc(sizeof(ABITMAP_INSTANCE)); 72 ret->parent = bmp; 73 ret->curframe = 0; 74 return ret; 75} 76 77 78void destroy_abitmap(ABITMAP *bmp) 79{ 80 int i; 81 for(i = 0; i < bmp->num_frames; ++i) 82 destroy_bitmap(bmp->frames<i>); 83 free(bmp->frames); 84 free(bmp); 85} 86 87void destroy_abitmap_instance(ABITMAP_INSTANCE *bmp) 88{ 89 free(bmp); 90} 91 92 93void update_animation(ABITMAP_INSTANCE *bmp) 94{ 95 BASSERT(bmp); 96 97 /* if(anim_counter == lac) 98 return; 99 lac = anim_counter;*/ 100 101 // anim_counter goes up by 60 each second... we gotta calculate this with frames per second. 102 // update. the curframe. 103 if(anim_counter % (60 / bmp->parent->fps) == 0) 104 ++bmp->curframe; 105 106 // we dont want segfaults ;) 107 if(bmp->curframe >= bmp->parent->num_frames) 108 bmp->curframe %= bmp->parent->num_frames; 109 110 // keep it from overflowing 111 if(anim_counter >= 60) 112 anim_counter -= 60; 113} 114 115void ablit(ABITMAP_INSTANCE *source, BITMAP *dest, int dest_x, int dest_y) 116{ 117 BASSERT(source); 118 BASSERT(source->parent); 119 BASSERT(source->parent->frames); 120 //printf("%d ", source->curframe); 121 if(source->parent->masked) 122 masked_blit(source->parent->frames[source->curframe], dest, 0, 0, dest_x, dest_y, source->parent->w, source->parent->h); 123 else 124 blit(source->parent->frames[source->curframe], dest, 0, 0, dest_x, dest_y, source->parent->w, source->parent->h); 125} 126 127void ablit_r(ABITMAP_INSTANCE *source, BITMAP *dest, int dest_x, int dest_y, fixed angle) 128{ 129 rotate_sprite(dest, source->parent->frames[source->curframe], dest_x, dest_y, angle); 130}

And here is the abitmap utility:

#SelectExpand
1// baf 2005 2 3// abitmap_util.c 4// utility to spew out abitmaps :) 5 6#include "main.h" 7#include "timers.h" 8#include "anim.h" 9 10FILE *logfile; 11BITMAP *buffer; 12 13int main() 14{ 15 char c = ' ', filename[512]; 16 int i; 17 ABITMAP *cur; 18 ABITMAP_INSTANCE *cur_i; 19 BITMAP *tmp; FILE *hmm; 20 logfile = fopen("./abitmap_util.log", "w"); 21 printf("Hey. This is ABITMAP Utility coming at you live from stdout!\n"); 22 printf("Please choose:\n L) Load and view an abitmap\n C) Create an abitmap\n E) Edit an abitmap\n"); 23 while(tolower(c) != 'l' && tolower(c) != 'c' && tolower(c) != 'e') 24 { 25 printf("->"); 26 scanf("%c", &c); 27 printf("\n"); 28 } 29 if(tolower(c) == 'l') 30 { 31 printf("Enter filename to view -> "); 32 scanf("%s", filename); 33 printf("\n"); 34 //if(file_exists(filename, FA_RDONLY, NULL) == 0) 35 /*if((hmm = fopen(filename, "r")) == NULL) 36 { 37 printf("File doesnt exist! Bye bye\n"); 38 return -1; 39 } 40 fclose(hmm);*/ 41 allegro_init(); 42 set_color_depth(32); 43 cur = load_abitmap(filename); 44 if(!cur) 45 { 46 printf("File doesn't exist! Bye bye\n"); 47 return -1; 48 } 49 cur_i = grab_abitmap_instance(cur); 50 BASSERT(cur != NULL); 51 BASSERT(cur_i != NULL); 52 install_keyboard(); 53 install_timer(); 54 install_timers(); 55 set_gfx_mode(GFX_AUTODETECT, 800, 600, 0, 0); 56 buffer = create_bitmap(SCREEN_W, SCREEN_H); 57 i = 0; 58 while(!key[KEY_ESC]) 59 { 60 if(i != anim_counter) 61 update_animation(cur_i); 62 i = anim_counter; 63 vsync(); 64 clear_bitmap(buffer); 65 ablit(cur_i, buffer, 0, 0); 66 textprintf_right_ex(buffer, font, SCREEN_W, 0, makecol(255,255,255), makecol(0,0,0), "Frame: %d | ABM FPS: %d", cur_i->curframe, cur->fps); 67 textprintf_right_ex(buffer, font, SCREEN_W, 10, makecol(255,255,255), makecol(0,0,0), "%d", anim_counter % (60 / cur->fps)); 68 textprintf_right_ex(buffer, font, SCREEN_W, 20, makecol(255,255,255), makecol(0,0,0), "DEBUG - cur frame count: %d", anim_counter); 69 blit(buffer, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H); 70 //sleep(60 / cur->fps + 10); 71 } 72 } 73 else if(tolower(c) == 'e') 74 { 75 int done = 0; 76 printf("Enter filename to edit -> "); 77 scanf("%s", filename); 78 printf("\n"); 79 install_allegro(SYSTEM_NONE, &errno, atexit); 80 set_color_depth(32); 81 cur = load_abitmap(filename); 82 if(!cur) return -1; 83 printf("Loaded %s\n", filename); 84 printf("Settings:\n\tFPS: %d\n\tMasked: %d\n", cur->fps, cur->masked); 85 printf("New FPS -> "); 86 scanf("%d", &cur->fps); 87 printf("New Masked -> "); 88 scanf("%d", &cur->masked); 89 save_abitmap(filename, cur); 90 printf("Modified"); 91 } 92 else 93 { 94 install_allegro(SYSTEM_NONE, &errno, atexit); 95 set_color_depth(32); 96 cur = (ABITMAP *)malloc(sizeof(ABITMAP)); 97 printf("How many frames? "); 98 scanf("%d", &cur->num_frames); 99 printf("How many FPS? "); 100 scanf("%d", &cur->fps); 101 printf("Width "); 102 scanf("%d", &cur->w); 103 printf("Height "); 104 scanf("%d", &cur->h); 105 printf("Masked "); 106 scanf("%d", &cur->masked); 107 cur->frames = (BITMAP **)malloc(sizeof(BITMAP *) * cur->num_frames); 108 for(i = 0; i < cur->num_frames; ++i) 109 { 110 printf("Enter filename for frame %d (bmp). -> ", i + 1); 111 scanf("%s", filename); 112 tmp = load_bitmap(filename, NULL); 113 cur->frames<i> = create_bitmap(cur->w, cur->h); 114 blit(tmp, cur->frames<i>, 0, 0, 0, 0, cur->w, cur->h); 115 } 116 printf("Enter output filename -> "); 117 scanf("%s", filename); 118 save_abitmap(filename, cur); 119 printf("Yay! We didnt crash!"); 120 } 121} 122END_OF_MAIN()

Go to: