view mde/scheduler.d @ 4:9a990644948c

Many changes: upgraded to tango 0.99.4, reorganised mde/input, large changes to mde/mergetag and mde/init, separated off test/MTTest.d and more. committer: Diggory Hardy <diggory.hardy@gmail.com>
author Diggory Hardy <diggory.hardy@gmail.com>
date Sun, 06 Jan 2008 17:38:51 +0000
parents
children 0047b364b6d9
line wrap: on
line source

/** Scheduler
*/
module mde.scheduler;

import tango.time.Time;

// NOTE: Currently has no support for removing functions. To fix, assign ID and store fct pointers
// in an associative array, returning the ID [on adding fct pointer].
// FIXME: support delegates or not?
/// This class can run scheduled functions per frame or every t seconds (sim-time).
class Scheduler
{
    /** The type of function pointer to be passed to the scheduler.
    *
    * The double $(I time) parameter gives the number of (sim) seconds since the function was last
    * called, or zero on the first run. */
    alias void function (double time) scheduleFct;
    
    /** Add a function to be called per frame. */
    static void perFrame (scheduleFct fct) {
        frameFcts ~= fct;
    }
    
    /** Add a function to be called per t secs or n 100-nano-sec intevals.
    *
    * Since the scheduler cannot guarantee a maximum time between calls, the interval at which
    * functions are called is always greater than or equal to the inverval specified here. Of
    * course, the actual inteval is given when the function is run.
    */
    static void perTime (double t, scheduleFct fct) {
        perTime (TimeSpan.interval(t), fct);
    }
    /** ditto */
    static void perTime (TimeSpan n, scheduleFct fct)
    in { assert (n > TimeSpan (0L)); }
    body {
        timeFcts ~= TimeFct (fct, n);
    }
    
    /** This function should get called by the main loop, once per frame.
    *
    * The parameter time should be the current sim-time, using the tango.core.Types.Time enum; all
    * time evaluations will use this.
    */
    static void run (Time time) {
        double interval;
        
        // Call all per-frame functions:
        if (lastTime == Time (0L)) interval = 0.0;		// 0 interval for first loop
        else interval = (time-lastTime).interval();
        
        foreach (fct; frameFcts) fct(interval);
        
        // Call all per-interval functions:
        foreach (fct; timeFcts) if (time >= fct.nextCall) {
            if (fct.nextCall == Time (0L)) interval = 0.0;	// 0 interval for first call
            else interval = (time - (fct.nextCall - fct.interval)).interval();
            fct.nextCall = time + fct.interval;		// when to call next
            
            fct.fct (interval);				// call
        }
    }
    
    /* Holds details for functions called per time interval. */
    private struct TimeFct {
        scheduleFct fct;			// function to call
        
        TimeSpan interval;			// interval to call at
        // Storing nextCall is more efficient than storing lastCall since only this number has to
        // be compared to time every frame where fct is not called:
        Time nextCall = Time (0L);
        
        static TimeFct opCall (scheduleFct f, TimeSpan t) {	// static CTOR
            TimeFct ret;
            ret.fct = f;
            ret.interval = t;
            return ret;
        }
    }
    
    private static Time lastTime = Time (0L);
    private static scheduleFct[] frameFcts;
    private static TimeFct[] timeFcts;
}