Allegro puede establecer varias funciones virtuales de temporización, todas funcionando a diferentes velocidades.
Bajo DOS reprogramará el reloj contínuamente para asegurarse de que todas se llaman en el momento adecuado. Dado que estas rutinas alteran el chip de temporización de bajo nivel, estas rutinas no deben usarse con otras rutinas de temporización del DOS, como la rutina uclock() del djgpp.
En otras plataformas están implementados usando hilos, que corren de forma paralela al hilo principal. Por lo tanto las rutinas de llamada instaladas con temporizadores no bloquearán al hilo principal cuando sean llamadas, por lo que podría necesitar dispositivos de sincronización apropiados (ej: semáforos, mutexes, etc) cuando acceda a datos compartidos por el hilo principal y su rutina de temporización. (Por ahora Allegro no provee este tipo de dispositivos de sincronización.)
int install_timer();
Instala el controlador de temporización de Allegro. Debe hacer esto antes
de instalar cualquier rutina de temporización propia, e incluso antes de
visualizar el puntero del ratón, reproducir una animación FLI, reproducir
música MIDI y usar cualquiera de las rutinas GUI. Devuelve cero con éxito,
o un número negativo si hubo problemas (pero puede decidir si quiere
verificar el valor de retorno de esta función, dado que es muy poco
probable que pueda fallar).
void remove_timer();
Quita el controlador de temporización de Allegro (y, bajo DOS, devuelve el
control del reloj al sistema operativo). Normalmente no hace falta llamar
esta función, porque allegro_exit() lo hará por usted.
int install_int(void (*proc)(), int speed);
Instala un temporizador con el tiempo dado en número de milisegundos
entre cada tick. Esto es lo mismo que hacer install_int_ex(proc,
MSEC_TO_TIMER(speed)). Si llama esta rutina sin haber instalado primero
el módulo de temporización, install_timer() será llamado automáticamente.
Si no hay más espacio para añadir otro temporizador de usuario,
install_int() devolverá un número negativo, en otro caso devolverá cero.
int install_int_ex(void (*proc)(), int speed);
Añade una función a la lista de temporizadores del usuario, o si ya está
instalada, ajusta su velocidad retroactivamente (es decir, hace como si
el cambio de velocidad hubiese ocurrido precisamente en el último tick).
El valor se da en ticks de reloj, que son 1193181 por segundo. Puede
convertir la velocidad a partir de otros formatos de tiempo con las
siguientes macros:
SECS_TO_TIMER(secs) - pase el número de segundos entre cada tick MSEC_TO_TIMER(msec) - pase el número de milisegundos entre cada tick BPS_TO_TIMER(bps) - pase el número de ticks por segundo BPM_TO_TIMER(bpm) - pase el número de ticks por minutoSi no queda espacio para un temporizador nuevo, install_int_ex() devolverá un número negativo, o cero de otro modo. Sólo puede haber 16 temporizadores a la vez, y algunas partes de Allegro (código GUI, rutinas para visualizar el puntero del ratón, rest(), el reproductor de ficheros FLI o MIDI) necesitan instalar sus propios temporizadores, por lo que debería evitar usar muchos a la vez.
Su función será llamada por el controlador de interrupciones de Allegro y no directamente por el procesador, por lo que puede ser una función normal en C, y no necesita ninguna función de envoltura. Sin embargo tenga en cuenta que será llamada en contexto de interrupción, lo que impone muchas restricciones sobre lo que puede hacer en ella. No debería usar grandes cantidades de pila, no puede hacer llamadas al sistema operativo o usar funciones de la biblioteca de C, o contener código con operaciones en coma flotante, y debe ejecutarse rápidamente. No intente hacer cosas complicadas con su temporizador: como regla general debería ajustar un par de valores y actuar en consecuencia de éstos dentro de su bucle de control principal.
En un entorno DOS en modo protegido como djgpp, la memoria es virtualizada y puede ser paginada a disco. Debido a la no-reentrancia del DOS, si una paginación al disco ocurre dentro de su función de temporización, el sistema morirá de forma dolorosa, por lo que debe asegurarse de bloquear (lock) toda la memoria (de código y datos) que sea modificada dentro de su rutina de temporización. Allegro bloqueará todo lo que use, pero usted es responsable de bloquear su rutina de temporización. Las macros LOCK_VARIABLE(variable), END_OF_FUNCTION(nombre_de_funcion), y LOCK_FUNCTION(nombre_de_funcion) pueden ser usadas para simplificar esta tarea. Por ejemplo, si quiere que su temporizador incremente una variable de contador, debería escribir:
volatile int contador;y en su código de inicio debería bloquear la memoria de esta manera:void mi_temporizador() { contador++; }
END_OF_FUNCTION(mi_temporizador);
LOCK_VARIABLE(contador); LOCK_FUNCTION(mi_temporizador);Obviamente esto puede ser extraño si usa estructuras de datos complicadas y llama otras funciones desde su temporizador, por lo que debería crear sus temporizadores tan simples como pueda.
void remove_int(void (*proc)());
Quita una función de la lista de temporizadores de usuario. Al finalizar
su programa, allegro_exit() hará esto automáticamente.
int install_param_int(void (*proc)(void *), void *param, int speed);
Como install_int(), pero a la rutina callback se le pasará una copia del
puntero void especificado. Para desactivar este temporizador, use
remove_param_int() en vez de remove_int().
int install_param_int_ex(void (*proc)(void *), void *param, int speed);
Como install_int_ex(), pero a la rutina callback se le pasará una copia
del puntero void especificado. Para desactivar este temporizador, use
remove_param_int() en vez de remove_int().
void remove_param_int(void (*proc)(void *), void *param);
Como remove_int(), pero se usa con las rutinas de temporización que tienen
parámetros. Si hay más de una copia de la misma rutina activa a la vez,
elegirá la rutina a desactivar comprobando el valor del parámetro (por lo
que no puede tener más de una copia de un mismo temporizador usando un
parámetro idéntico).
int timer_can_simulate_retrace()
Comprueba si es posible sincronizar el módulo de temporización con el
retrazo del monitor, dependiendo del entorno y plataforma actual (por el
momento esto sólo es posible ejecutándo un el programa en modo DOS puro y
en una resolución VGA o modo-X). Devuelve distinto de cero si la
simulación es posible.
void timer_simulate_retrace(int enable);
El controlador DOS de temporización puede ser usado para simular
interrupciones de retrazo vertical. Una interrupción de retrazo puede ser
extremadamente útil para implementar una animacion suave, pero
desafortunadamente el hardware de la VGA no puede hacerlo. La Ega lo podía
hacer, y algunas SVGA pueden pero no completamente, y de forma no
suficientemente estandarizada para que sea útil. Allegro soluciona esto
programando el reloj para que genere una unterrupción cuando crea que va
a ocurrir, y leyendo la VGA dentro del controlador de interrupción para
asegurarse de que está sincronizado con el refresco del monitor. Esto
funciona bastante bien en algunas situaciones, pero hay muchos problemas:
- Nunca use el simulador de retrazo en modos SVGA. Funcionará con algunas tarjetas, pero no en otras, y tiene conflictos con la mayoría de las implementaciones VESA. La simulación de retrazo sólo es fiable en el modo 13 de la VGA y en el modo-X.
- La simulación de retrazo no funciona bajo win95, porque win95 devuelve basura cuando intento leer el tiempo transcurrido del PIT. Si alguien sabe cómo solucionar esto, íque por favor me mande un email!
- La simulación de retrazo conlleva mucha espera del controlador de temporización con las interrupciones desactivadas. Esto reducirá la velocidad del sistema de forma significante, y podría causar estática el reproducir sonidos con tarjetas SB 1.0 (ya que no soportan la auto-inicialización DMA: las SB 2.0 y superiores funcionarán bien).
Considerando todos estos problemas, se aconsejaría no depender del simulador de retrazo vertical. Si está trabajando en modo-X, y no le importa que su programa funcione bajo win95, está bien, pero sería buena idea dejar al usuario la posibilidad de desactivarlo.
La simulación de retrazo debe ser activada antes de usar las funciones de triple buffer en resoluciones del modo-X. Esto puede ser útil también como una simple detección de retrazo, ya que leer vsync() puede hacer que ignore algún retrazo de vez en cuando si justo una interrupción de sonido o temporización ocurre a la vez. Cuando la simulación de retrazo está activada, vsync() comprobará la variable retrace_count en vez de leer los registros de la VGA, para que no pierda ningún retrazo incluso si está siendo enmascarado por otras interrupciones.
int timer_is_using_retrace()
Comprueba si el modulo de temporización está, en ese momento, sincronizado
con el monitor o no. Devuelve distinto de cero si lo está.
extern volatile int retrace_count;
Si el simulador de retrazo está instalado, esto es incrementado con cada
retrazo vertical, de otro modo es incrementado 70 veces por segundo
(ignorando los retrazos). Esto le permite controlar la velocidad de su
programa sin tener que instalar funciones de temporización propias.
La velocidad del retrazo depende del modo gráfico. En el modo 13h y resoluciones en modo-X de 200/400 líneas hay 70 retrazos por segundo, y en modos-X de 240/480 líneas hay 60. Puede ser tan bajo como 50 (en modo 376x282) o tan alto como 92 (en modo 400x300).
extern void (*retrace_proc)();
Si el simulador de retrazo está instalado, esta función será llamada
durante cada retrazo, de otro modo es llamada 70 veces por segundo
(ignorando los retrazos). Póngala a NULL para desactivar las llamadas.
Esta función obedece las mismas reglas que los temporizadores normales (es
decir: debe estar bloqueada (locked), y no puede llamar al DOS o funciones
de libc) pero incluso más: debe ejecutarse _muy_ rápido, o fastidiará la
sincronización del reloj. El único uso que veo para esta función es para
hacer manipulaciones de paleta, ya que el triple buffering puede hacerse
con la función request_scroll(), y la variable retrace_count puede ser
usada para temporizar su código. Si quiere alterar la paleta dentro de
retrace_proc, debe usar la función inline _set_color() en vez de la
corriente set_color() o set_palette(), y no debería intentar alterar más
de dos o tres colores de la paleta en un mismo retrazo.
void rest(long time);
Una vez que Allegro reprograma el reloj, la función estándar delay() no
funcionará, por lo que tendrá que usar ésta. El tiempo time se pasa en
milisegundos.
void rest_callback(long time, void (*callback)())
Como rest(), pero llama continuamente la función específica mientras está
esperando que pase el tiempo requerido.