03 Rutinas de temporización



El reloj estándar del PC cambia 18.2 veces por segundo, muy poco para juegos de acción rápida. Allegro puede sustituir la rutina de temporización del sistema con una propia, que reprograma el reloj a velocidades superiores y sigue llamando al controlador de la BIOS a la velocidad antigua. Puedes crear varios temporizadores virtuales propios, todos a velocidades diferentes, y Allegro reprogramará constantemente el reloj para asegurarse de que todos son llamados en el momento correcto. Ya que Allegro altera los ajustes de reloj del chip PIT, no debería ser usado junto con la función unlock() de la biblioteca libc de djgpp.

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.

void remove_timer();
Quita el controlador de temporización de Allegro y pasa el control del reloj a la BIOS. 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)).

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. 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 DOS o usar funciones de biblioteca que puedan llamar al DOS, 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 en su bucle de control principal.

En un entorno de 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 fijar (lock) toda la memoria (de código y datos) que sea modificada dentro de su rutina de temporización. Allegro fijará toda la que use, pero usted es responsable de fijar 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 fijar 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.

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.

extern int i_love_bill;
Si vale TRUE, activa el modo de especial de temporización 'para windows', el cual fija las interrupciones de reloj del hardware a una velocidad de 200 ticks por segundo en vez de reprogramarlo dinámicamente. Este modo reduce la precisión del reloj (por ejemplo, rest() redondeará el tiempo de espera a un múltiplo de 5 milisegundos), e impide que el simulador de retrazo vertical funcione (en este modo las llamadas a timer_simulate_retrace() son ignoradas). Por otro lado, esto hace que los programas funcionen bajo windows 3.1, y evita que win95 le obligue a ejecutar el programa en modo DOS. Este biestable debe ser ajustado antes de instalar el módulo de temporización y no debe ser cambiado mientras el módulo esté activo. Por defecto, allegro_init() activará este modo si detecta la presencia de Windows.

void timer_simulate_retrace(int enable);
El controlador de interrupciones puede ser usado para simular interrupciones de retrazo vertical. Una interrupción de retrazo puede ser extremadamente útil para implementar animaciones suaves, pero desafortunadamente el hardware de la VGA no puede hacerlo. La EGA lo podrí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 interrupción cuando piense que va a ocurrir un retrazo, 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 imlementaciones VESA. La simulación de retrazo sólo es de fiar en el modo 13h de la VGA y 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.

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). Llámela con NULL para desactivar el callback. Esta función obedece las mismas reglas que los temporizadores normales (es decir: debe estar fijada (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.




Volver al Indice