04 Rutinas de temporización

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).

Relacionado con: remove_timer, install_int.
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.
Relacionado con: install_timer, allegro_exit.
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.
Relacionado con: install_timer, remove_int, install_int_ex.
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 minuto
Si 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;

      void mi_temporizador()
      {
         contador++;
      }

      END_OF_FUNCTION(mi_temporizador);
y en su código de inicio debería bloquear la memoria de esta manera:
      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.
Relacionado con: install_timer, remove_int, install_int.
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.
Relacionado con: install_int, install_int_ex.
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().
Relacionado con: install_timer, remove_param_int, install_param_int_ex, install_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().
Relacionado con: install_timer, remove_param_int, install_param_int, install_int_ex.
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).
Relacionado con: install_param_int, install_param_int_ex, remove_int.
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.
Relacionado con: timer_simulate_retrace, timer_is_using_retrace.
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.

Relacionado con: enable_triple_buffer, install_timer, retrace_count, retrace_proc, request_scroll, vsync, timer_can_simulate_retrace, timer_is_using_retrace.
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á.
Relacionado con: timer_simulate_retrace, timer_can_simulate_retrace.
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).

Relacionado con: timer_simulate_retrace, retrace_proc.
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.
Relacionado con: _set_color, timer_simulate_retrace, timer_is_using_retrace, retrace_count.
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.
Relacionado con: install_timer, rest_callback.
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.
Relacionado con: install_timer, rest.

Volver al Indice