Allegro can set up several virtual timer functions, all going at different
speeds.
Under DOS it will constantly reprogram the clock to make sure they are all
called at the correct times. Because they alter the low level timer chip
settings, these routines should not be used together with other DOS timer
functions like the djgpp uclock() routine.
Under other platforms, they are usually implemented using threads, which run
parallel to the main thread. Therefore timer callbacks on such platforms
will not block the main thread when called, so you may need to use
appropriate synchronisation devices (eg. mutexes, semaphores, etc.) when
accessing data that is shared by a callback and the main thread. (Currently
Allegro does not provide such devices.)
Installs the Allegro timer interrupt handler. You must do this before
installing any user timer routines, and also before displaying a mouse
pointer, playing FLI animations or MIDI music, and using any of the GUI
routines. Returns zero on success, or a negative number on failure (but
you may decide not to check the return value as this function is very
unlikely to fail).
See also:
remove_timer,
install_int.
Removes the Allegro timer handler (and, under DOS, passes control of the
clock back to the operating system). You don't normally need to bother
calling this, because allegro_exit() will do it for you.
See also:
install_timer,
allegro_exit.
Installs a user timer handler, with the speed given as the number of
milliseconds between ticks. This is the same thing as
install_int_ex(proc, MSEC_TO_TIMER(speed)). If you call this routine
without having first installed the timer module, install_timer() will be
called automatically. If there is no room to add a new user timer,
install_int() will return a negative number, otherwise it returns zero.
See also:
install_timer,
remove_int,
install_int_ex,
install_param_int.
Adds a function to the list of user timer handlers or, if it is already
installed, retroactively adjusts its speed (i.e makes as though the speed
change occured precisely at the last tick). The speed is given in hardware
clock ticks, of which there are 1193181 a second. You can convert from
other time formats to hardware clock ticks with the macros:
SECS_TO_TIMER(secs) - give the number of seconds between
each tick
MSEC_TO_TIMER(msec) - give the number of milliseconds
between ticks
BPS_TO_TIMER(bps) - give the number of ticks each second
BPM_TO_TIMER(bpm) - give the number of ticks per minute
If there is no room to add a new user timer, install_int_ex() will return
a negative number, otherwise it returns zero. There can only be sixteen
timers in use at a time, and some other parts of Allegro (the GUI code,
the mouse pointer display routines, rest(), the FLI player, and the MIDI
player) need to install handlers of their own, so you should avoid using
too many at the same time. If you call this routine without having first
installed the timer module, install_timer() will be called automatically.
Your function will be called by the Allegro interrupt handler and not
directly by the processor, so it can be a normal C function and does not
need a special wrapper. You should be aware, however, that it will be
called in an interrupt context, which imposes a lot of restrictions on
what you can do in it. It should not use large amounts of stack, it must
not make any calls to the operating system, use C library functions, or
contain any floating point code, and it must execute very quickly. Don't
try to do lots of complicated code in a timer handler: as a general rule
you should just set some flags and respond to these later in your main
control loop.
In a DOS protected mode environment like djgpp, memory is virtualised and
can be swapped to disk. Due to the non-reentrancy of DOS, if a disk swap
occurs inside an interrupt handler the system will die a painful death,
so you need to make sure you lock all the memory (both code and data)
that is touched inside timer routines. Allegro will lock everything it
uses, but you are responsible for locking your handler functions. The
macros LOCK_VARIABLE (variable), END_OF_FUNCTION (function_name),
END_OF_STATIC_FUNCTION (function_name), and LOCK_FUNCTION (function_name)
can be used to simplify this task. For example, if you want an interrupt
handler that increments a counter variable, you should write:
volatile int counter;
void my_timer_handler()
{
counter++;
}
END_OF_FUNCTION(my_timer_handler);
and in your initialisation code you should lock the memory:
LOCK_VARIABLE(counter);
LOCK_FUNCTION(my_timer_handler);
Obviously this can get awkward if you use complicated data structures and
call other functions from within your handler, so you should try to keep
your interrupt routines as simple as possible.
See also:
install_timer,
remove_int,
install_int,
install_param_int_ex.
Removes a function from the list of user interrupt routines. At program
termination, allegro_exit() does this automatically.
See also:
install_int,
install_int_ex,
remove_param_int.
Like install_int(), but the callback routine will be passed a copy of the
specified void pointer parameter. To disable the handler, use
remove_param_int() instead of remove_int().
See also:
install_timer,
remove_param_int,
install_param_int_ex,
install_int.
Like install_int_ex(), but the callback routine will be passed a copy of
the specified void pointer parameter. To disable the handler, use
remove_param_int() instead of remove_int().
See also:
install_timer,
remove_param_int,
install_param_int,
install_int_ex.
Like remove_int(), but for use with timer callbacks that have parameter
values. If there is more than one copy of the same callback active at a
time, it identifies which one to remove by checking the parameter value
(so you can't have more than one copy of a handler using an identical
parameter).
See also:
install_param_int,
install_param_int_ex,
remove_int.
Checks whether it is possible to sync the timer module with the monitor
retrace, given the current platform and environment (at the moment this
is only possible when running in clean DOS mode in a VGA or mode-X
resolution). Returns non-zero if simulation is possible.
See also:
timer_simulate_retrace,
timer_is_using_retrace.
The DOS timer handler can be used to simulate vertical retrace
interrupts. A retrace interrupt can be extremely useful for implementing
smooth animation, but unfortunately the VGA hardware doesn't support it.
The EGA did, and some SVGA chipsets do, but not enough, and not in a
sufficiently standardised way, for it to be useful. Allegro works around
this by programming the timer to generate an interrupt when it thinks a
retrace is next likely to occur, and polling the VGA inside the interrupt
handler to make sure it stays in sync with the monitor refresh. This
works quite well in some situations, but there are a lot of caveats:
-
You can't use the retrace simulator in SVGA modes. It will work with
some chipsets, but not others, and it conflicts with most VESA
implementations. Retrace simulation is only reliable in VGA mode 13h
and mode-X.
-
Retrace simulation doesn't work under win95, because win95 returns
garbage when I try to read the elapsed time from the PIT. If anyone
knows how I can make this work, please tell me!
-
Retrace simulation involves a lot of waiting around in the timer
handler with interrupts disabled. This will significantly slow down
your entire system, and may also cause static when playing samples on
SB 1.0 cards (because they don't support auto-initialised DMA: SB 2.0
and above will be fine).
Bearing all those problems in mind, I'd strongly advise against relying
on the retrace simulator. If you are coding in mode-X, and don't care
about your program working under win95, it is great, but it would be a
good idea to give the user an option to disable it.
Retrace simulation must be enabled before you use the triple buffering
functions in a mode-X resolution. It can also be useful for simple
retrace detection, because the polling vsync() function can occasionally
miss retraces if a soundcard or timer interrupt occurs at exactly the
same time as the retrace. When retrace interrupt simulation is enabled,
vsync() will check the retrace_count variable rather than polling the
VGA, so it won't miss retraces even if they are masked by other
interrupts.
See also:
install_timer,
retrace_count,
retrace_proc,
request_scroll,
vsync,
timer_can_simulate_retrace,
timer_is_using_retrace,
enable_triple_buffer.
Checks whether the timer module is currently synced with the monitor
retrace or not. Returns non-zero if it is.
See also:
timer_simulate_retrace,
timer_can_simulate_retrace.
If the retrace simulator is installed, this count is incremented on each
vertical retrace; otherwise, if the refresh rate is known, the count is
incremented at the same rate (ignoring retraces); otherwise, it is
incremented 70 times a second. This provides a useful way of controlling
the speed of your program without the hassle of installing user timer
functions.
The speed of retraces varies depending on the graphics mode. In mode 13h
and 200/400 line mode-X resolutions there are 70 retraces a second, and
in 240/480 line modes there are 60. It can be as low as 50 (in 376x282
mode) or as high as 92 (in 400x300 mode).
See also:
timer_simulate_retrace,
timer_is_using_retrace,
retrace_proc.
If the retrace simulator is installed, this function is called during
every vertical retrace; otherwise, if the refresh rate is known, the
function is called at the same rate (ignoring retraces); otherwise it is
called 70 times a second. Set it to NULL to disable the callback. The
function must obey the same rules as regular timer handlers (ie. it must
be locked, and mustn't call OS or libc functions) but even more so: it
must execute very quickly, or it will mess up the timer synchronisation.
The only use I can see for this function is for palette manipulations,
because triple buffering can be done with the request_scroll() function,
and the retrace_count variable can be used for timing your code. If you
want to alter the palette in the retrace_proc you should use the inline
_set_color() function rather than the regular set_color() or
set_palette(), and you shouldn't try to alter more than two or three
palette entries in a single retrace.
See also:
timer_simulate_retrace,
timer_is_using_retrace,
retrace_count,
_set_color.
Once Allegro has taken over the timer the standard delay() function will
no longer work, so you should use this routine instead. The time is given
in milliseconds.
See also:
install_timer,
rest_callback.
Like rest(), but continually calls the specified function while it is
waiting for the required time to elapse.
See also:
install_timer,
rest.
Back to contents