Dynamically changing the frequency of the Allegro timers mid-game.
Andrei Ellman

Hi,

I am currently implementing a facility in my game where the speed of everything can be speeded up or slowed down (eg. by rotating the mousewheel).

In order to implement this, I have to change the rate at which my timer-function is called. Does anyone know if it is a good idea to do the following in my code...

remove_int(my_int_callback); /* Stop the tick-timer */
install_int_ex(my_int_callback, BPS_TO_TIMER(new_ticks_per_second)); /* Start the tick-timer at the new speed */

Is the call to remove_int needed? This would mean the code to change the tick-speed would just be

install_int_ex(my_int_callback, BPS_TO_TIMER(new_ticks_per_second)); /* Tell the tick-timer to tick at the new speed */

While reading the changelog from Allegro 1.2 to Allegro 2.0, I noticed this snippet:

Quote:

The timer routines now have better than millisecond accuracy, and it is possible to alter the speed of a user timer callback in realtime (by reinstalling it with a different speed value).

Is this still true now that Allegro has not only transitioned from 2.0 to 4.2, but also gone from being a DOS-only library to a multi-platform library? If it is still true, that would mean I would not need to call remove_int. I've heard that the Windows version of Allegro uses a separate thread for timers, so changing the timer-value might be problematic - especially if I have a second timer running (although I only need one timer unless I want to measuer the FPS as well).

Also, if I alter the speed of a timer-callback in realtime (be it by re-installing it, or un-installing it and then installing it), would the timer go at the new speed immediately, or would it wait until the next tick, and then adjust itself? Also, does it set off the new tick immediately, or wait until the first tick-interval is complete and then do a tick?

When changing, I would like the gap between ticks to be no slower than the slower of the two tick-speeds. This is because if it was, then the player could cheat and slow down the game by constantly changing it's speed. Ideally, the gap between the two ticks should be as long as the length of time as either one of them (or somewhere in between), although it would be OK for the gap to be any length shorter than than the slowest tick-speed, but if the gap becomes too small, then the game will speed up if constantly changing speed.

Just in case calling install_int_ex() creates a tick that is longer than either of the two tick-speeds, is it reccommended that instead of calling install_int_ex() in the logic-loop, the logic-loop sets a flag, and the if the flag is set, the interrupt-callback calls install_int_ex(), or is calling install_int_ex() inside it's own callback just asking for trouble?

Also, I've heard that the accuracy of the Allegro timers is not very accurate past 100 ticks per second. Is that just an upper-bound limit, or does that mean that once the timer goes above 100, the ticks start to become irregular but over the long-term, the average tick-speed is more or less correct. Does this also mean that 100 ticks per second is the last 'island of stability' in the linear 'ticks-space', or are tick-speeds of 99, 98, 97, 96 etc. accurate as well? Also, is it better to change the tick-speed to a discrete number of ticks-per-second, or is it better to set it to something like (K/n)*m where n and m are integers and K is a standard ticks-per-second rate such as 60 or 100. Another way of saying this is is it more accurate to specify the time in ticks-per-second, or is it better to specify it as an interval between two ticks in milliseconds?

And finally, if I wanted to create a timer that ticked in time to the monitor's refresh (obiously, this will be a fixed speed timer), is it enough to call install_int_ex() immediately after a vsync()?

AE.

PS. My game does everything in discrete steps, so please don't tell me to use a delta-time based logic-updating mechanism instead.

Thomas Fjellstrom

I'm pretty sure you've always been able to change the frequency of a timer without removing it first.

Also, all installed timers are run from the same timer thread.

Neil Walker

Why not just multiply everything by a delta value?

Sirocco
Quote:

I am currently implementing a facility in my game where the speed of everything can be speeded up or slowed down (eg. by rotating the mousewheel).

That's pretty darn cool. You can call install_int_ex() and it will adjust the existing timer's frequency if it is already installed. There's no need to uninstall it first.

Quote:

Also, I've heard that the accuracy of the Allegro timers is not very accurate past 100 ticks per second.

It's a limitation of the Windows timing setup, which at best gives you around 100 or so updates per second within your Allegro timers. If you call it more often it just doubles up on some of the updates. So a 200Hz timer would end up being updated twice 100 times per second. The accuracy provided is imperfect, but more than enough for most 2D apps, but I'd rely on delta time or something similar if you need to go 3D.

Quote:

And finally, if I wanted to create a timer that ticked in time to the monitor's refresh (obiously, this will be a fixed speed timer), is it enough to call install_int_ex() immediately after a vsync()?

I've tried this in the past, and I didn't perceive any noticeable improvement.

Andrei Ellman

OK. I've tried calling install_int_ex() from within my game-loop, and everything works just like I'd expect it to work - even if I break the 100 ticks-per-second barier. There are no noticable slowdowns when I rotate the mousewheel. So everything appears to be working fine (I've only tested this on Windows 2000 (both Windowed and Fullscreen), should I expect it to work OK on other Osses?).

Quote:

Why not just multiply everything by a delta value?

My game is a 2D sprite-based game where all movement and commands are done in discrete steps (the movement follows pre-defined path-points). Even keeping track of a 'movement-remainder' would add extra overhead. Of course, a 3D game (or any 2D game based on vectors) would be better off with delta-time.

Quote:

Quote:

And finally, if I wanted to create a timer that ticked in time to the monitor's refresh (obiously, this will be a fixed speed timer), is it enough to call install_int_ex() immediately after a vsync()?

I've tried this in the past, and I didn't perceive any noticeable improvement.

Just out of interest, would Allegro's retrace simulator be of any use instead of a started-at-vsync() tick-timer? In a different app that does the logic on a delta-time basis, I once tried using the retrace simulator. However, Although I could get it to work with Allegro 4.0, I couldn't get it to work with Allegro 4.1.x (where x is some number around 13 or so) and have not tried it since. I've heard that some in the Allegro development community want to get rid of the retrace simulator. Having a tick-timer that matches the monitor's refresh-rate seems like a useful thing to have, so I don't see why anyone is trying to get rid of it.

AE.

Todd Cope

Allegro's timers aren't accurate enough for you to sync them to the monitor refresh. Also, from what I remember, the retrace simulator doesn't work in Windows at all as it relies on accurate timers.

Trent Gamblin

You've all given me a good idea. I just made my cut scenes run twice as fast when a button is held down. Thanks! :)

Steve++

That reminds me of an old C64 game called street surfer. As your skateboard speeds up, so does the music. It's a wicked game!

Andrei Ellman

Just one more question. install_int_ex() can sometimes fail (return a nonzero value). Can it only fail when adding a new interupt, or is it also capable of failing when adjusting the speed of an existing interrupt? And if it does, does the interrupt stop or just continue at it's old speed?

As for the retrace simulator, although it works fine with DOS, it does not seem to work very well under Windows 2000. I think I may only use it in the DOS version, and the Windows version just uses a timer that ticks at the monitor's current refresh-rate (if it can be obtained).

<rant>
Speaking of which, how come a modern platform like the PC does not fire off an interrupt whenever the vertical retrace begins? I think that nowardays, most graphics cards offer this facility (although I think this is optional), but AFAIK, there does not seem to be a way of finding out when this happened. It appears that as I've been upgrading my hardwere, the retrace-interrupt ability of the hardware has been going down. On the Atari ST (a 16 bit computer), vertical-blank interrupts (vertical retrace interrupts) were always available, and on the Atari 8-bit, I not only had vertical retrace interrupts, but horizontal retrace interrupts. How's that for backward progress? Now, give me pixel-blank-iterrupts, and I'll be a happy camper.
</rant>

Steve++ said:

As your skateboard speeds up, so does the music.

That's something I hope to do in my game ... but I don't have any music for it yet. Another thing I plan to do with the music is that when the time limit is within it's last 10 seconds, the music will gradually start to play out of tune to give the player that feeling of urgency.

AE.

Steve++
Quote:

Steve++ said:

As your skateboard speeds up, so does the music.

That's something I hope to do in my game ... but I don't have any music for it yet. Another thing I plan to do with the music is that when the time limit is within it's last 10 seconds, the music will gradually start to play out of tune to give the player that feeling of urgency.

Don't rely on Allegro MIDI for that, because the timing is based on the Allegro timer rather than OS-provided MIDI services. While easy to program, the result will be choppy and subject to the OS scheduler. Best to use some kind of MOD format. If that doesn't support interactive music to a satisfactory level, use Allegro's audio stream system.

Sirocco
Quote:

Allegro's timers aren't accurate enough for you to sync them to the monitor refresh. Also, from what I remember, the retrace simulator doesn't work in Windows at all as it relies on accurate timers.

Actually, it can if your refresh rate isn't too high. For example, you can set up a mode 13h display (that's 320x200x8 under DOS) which is locked at 70Hz, and use a 70Hz timer plus vsync for smooth scrolling. The problem is that under windows you have variable refresh rates, among other things.

Andrei Ellman
Sirocco said:

The problem is that under windows you have variable refresh rates, among other things.

Does that mean the actual refresh rate of the montor is variable? I would have thought that all modes had fixed refresh rates. What good would a variable monitor-refresh rate be?

AE.

Sirocco
Quote:

Does that mean the actual refresh rate of the montor is variable? I would have thought that all modes had fixed refresh rates.

Sure. For example, with my CRT and video card under windows I can select an extremely wide range of resolutions and refresh rates from 60 - 120Hz for each of them (with certain exceptions). Under DOS you didn't have a large choice regarding your refresh rates because... well... you just didn't ;) If you ran mode 13H you got a 320x200 display at 70Hz, and if you picked a Mode-X mode you were locked in at 60Hz.

Quote:

What good would a variable monitor-refresh rate be?

I dunno. I'm wondering about that right now. I normally handle things like camera operation with an interrupt/timer set to a frequency, and when it's close to a multiple of the refresh rate things look good... at other times it can look nasty.

Andrei Ellman

So, does that mean the refresh rate varies on it's own accord, or only if the user varies it using the dispaly-properties applet or your gfx-card manufacturer's applet while your program is running?

Also, I think that some GFX cards actually fire an interrupt when the vertical retrace begins, but AFAIK, this is not standard accross all cards. Does Allegro's vsync() make use of this interrupt, and if so, would it be possible to do something else such as increase a timer when this occurs?

AE.

Sirocco
Quote:

So, does that mean the refresh rate varies on it's own accord, or only if the user varies it using the dispaly-properties applet or your gfx-card manufacturer's applet while your program is running?

You're limited to what your monitor is capable of, and what your video card can push. I'm going to go out on a limb and surmise that under Windows if you don't manually set your refresh rate(s) it will be whatever the default setting is (probably 60Hz) for all modes 640x480 and above. Some drivers let you set individual refresh rates for each video mode, and others just offer a global setting.

Quote:

Also, I think that some GFX cards actually fire an interrupt when the vertical retrace begins, but AFAIK, this is not standard accross all cards.

IIRC, there is a flag that is set when vsync occurs, which is what vsync is waiting for when you call it; this isn't 100% reliable. I'm not aware of any cards firing an interrupt upon vsync, and can't even see where this would be useful, but my knowledge in that particular area isn't quite expansive.

Andrei Ellman
Quote:

IIRC, there is a flag that is set when vsync occurs, which is what vsync is waiting for when you call it;

Question: Does Allegro's vsync() yield the CPU to other processes while it's waiting, or does it just busy-wait until the flag is set?

Quote:

I'm not aware of any cards firing an interrupt upon vsync, and can't even see where this would be useful

It would be useful for setting up triple-buffering code that automatically flips the screen when a vsync occurs, or when using normal page-flipping and you want to implement a version of vsync() that yields the CPU to other processes. Other uses include changing the palette at each vertical blank so you can create a smooth fade synchronised to the refresh rate without risking changing the palette mid-screen, and changing the screen address to obtain smooth scrolling. On the Amiga, you also had horizontal-blank-interrupts and that enabled you to do things like change the palette every scanline to be able to display more colours onscreen than there were in the palette, and change the screen address mid-screen in order to implement a scrolling area and a fixed area (eg. the status-display).

AE.

Steve++

Sadly, those days are gone. You either need to put up with jittery 2D or use 3D with delta timing.

Andrei Ellman

OK. I've got all the info I need, and I can now change the speed of my game smoothly. Thanks.

AE.

Richard Phipps

Welcome to the world of personal computers, where the OS / monitor / gfx card ensure no game can run 100% smoothly on every machine.

I miss the Amiga. :(

Sirocco
Quote:

I miss the Amiga. :(

This was not a problem under DOS either ^.^

Neil Roy

First off, I miss my Amiga too. But I have an WinUAE. :)

As for variable refresh rates, this is something you can manually adjust depending on your monitor. Check your display properties, click on advanced then monitor. You can raise the refresh rate up for any resolution you choose to the maximum your monitor will handle. I like this fact, my refresh rate is always set to the best I can as I notice the difference. The screen seems more... "solid" at a higher rate, sometimes "shimmers" at a low rate. This can also mean more FPS on a game while still having smooth video.

In one of my games (Deluxe Pacman) I do the following:

1float speed = 1.0; // initial game speed (slow = 1.2, fast = 0.8)
2volatile float game_time;
3 
4void game_timer(void)
5{
6 game_time++;
7} END_OF_FUNCTION(game_timer);
8 
9install_int(game_timer, 5);
10 
11while (game_time > 0) {
12 poll_keyboard();
13 input_check();
14 move_players();
15 move_ghosts();
16 check_collision();
17 game_time-=speed;
18}

I simply change the speed variable depending on how fast I want the game to run. The interupt never gets touched.

Thread #587270. Printed from Allegro.cc