/* timeloop.h

   This module contains a universal timing loop function. "Universal" means
   that this timing loop is designed to handle any situation where one
   function (the 'update' function) must be called at a specific rate and
   another function (the 'draw' function) should be called as often as
   possible, though not more often than 'update'.

   Before any such loop can be used safely, the interrupt handler and any
   variables it accesses must be locked. Call initialise_timeloop() once at
   the beginning of the program to take care of this.

   initialise_timeloop() will call initialise_control() in control.h, thus
   locking the necessary functions and variables in control.h. Note:
   Allegro's key[] array is already locked, so there is no need to lock it
   here. NOT TRUE!!! initialise_control() IS CALLED FROM THE MAIN MODULE!!!

   To run such a timing loop, use timeloop(). 'speed' is specified as for
   install_int_ex(). Use BPS_TO_TIMER(x) for a rate of x Hz.

   draw() is always called once before any calls to update().

   update() will be called at the rate specified on average. It will not
   necessarily be called at even intervals, so you should not use the key[]
   or joy[] variables here. To detect keys other than the players' controls,
   use keypressed() and readkey(). (Do not use readkey() without
   keypressed()!)

   If possible, draw() will be called every time update() is called. However,
   if it executes too slowly for this to happen, draw() will be called less
   frequently in order that update() can be called at the desired rate. If
   update() is called a maximum of 'max_skip' times successively, then draw()
   will be called anyway and the loop will slow down. It is compulsory to
   specify a value for max_skip.

   Since update() will not be called at even intervals, the control.h module
   provides methods for sampling the keyboard and joystick at exact times.
   To use this functionality, i.e. for the game, pass nonzero for the
   'use_control' parameter. Otherwise, i.e. for the menus, pass zero.

   If use_control is nonzero, the timer handler will call update_control()

   but the 'control' parameter will represent
   the player's controls sampled at accurately measured intervals. For this
   to work accurately with the joystick driver, poll_joystick() must be
   called frequently by the 'draw' function. TODO: is this a good idea, or
   could poll_joystick() be slow? Bob'll know...
*/


/*

NOTES:

true_game_time is incremented by timeloop_handler().

game_time represents the current logic frame being processed.

When reading real-life stuff such as the keyboard and joystick, use
true_game_time.

When reading virtual stuff such as the level or the AI (which reads the
level), use game_time.

*/


#ifndef INCLUDED_TIMELOOP_H
#define INCLUDED_TIMELOOP_H

extern int game_time;

extern volatile int true_game_time;

void timeloop_handler(void);

void timeloop(int speed,
              int max_skip,
              void *data,
              int (*update)(void *data),
              void (*draw)(void *data));

void stop_timeloop();
void restart_timeloop();

void initialise_timeloop();

#endif /* INCLUDED_TIMELOOP_H */
