Mercurial > projects > mde
view mde/scheduler/runTime.d @ 26:611f7b9063c6
Changed the licensing and removed a few dead files.
Changed licensing to "GPL version 2 or later" to avoid future compatibility issues.
Also a unittest fix to the previous commit.
committer: Diggory Hardy <diggory.hardy@gmail.com>
author | Diggory Hardy <diggory.hardy@gmail.com> |
---|---|
date | Thu, 03 Apr 2008 18:15:02 +0100 |
parents | 47478557428d |
children |
line wrap: on
line source
/* LICENSE BLOCK Part of mde: a Modular D game-oriented Engine Copyright © 2007-2008 Diggory Hardy This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ /** Scheduler */ module mde.scheduler.runTime; import tango.time.Time; debug { import tango.util.log.Log : Log, Logger; private Logger logger; } static this() { debug logger = Log.getLogger ("mde.scheduler.runTime"); } /** Some enums used by per request functions. */ enum RF_KEYS : uint { DRAW }; // 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]. // NOTE: support delegates or not? /// This class can run scheduled functions per frame or every t seconds (sim-time). abstract 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 ~= new TimeFct (fct, n); } /** Add a function to be called per requested update. * * A bool parameter is stored locally describing whether or not the function needs recalling, * and is set true upon creation and when requestUpdate is called with the same key. The * function is then called by scheduler's run() whenever this bool variable is true. */ static void perRequest (uint key, void function() fct) in { debug if ((key in requestFcts) is null) logger.warn ("perRequest: replacing existing function with same key!"); } body { requestFcts[key] = fct; requestFctsUpdate[key] = true; } /** Request an update to request function key. */ static void requestUpdate (uint key) { // Note: check the value for this key actually exists bool* p = key in requestFctsUpdate; if (p) *p = true; else debug logger.warn ("requestUpdate called with invalid key"); } /** 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 } // Call all per-request functions: foreach (key, fct; requestFcts) { if (requestFctsUpdate[key]) { fct(); requestFctsUpdate[key] = false; } } } /* Holds details for functions called per time interval. * Needs to be a reference type, and using a class is easiest for this. */ private static class 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); this (scheduleFct f, TimeSpan t) { fct = f; interval = t; } } private static Time lastTime = Time (0L); private static scheduleFct[] frameFcts; private static TimeFct[] timeFcts; private static void function()[uint] requestFcts; private static bool[uint] requestFctsUpdate; // associated with requestFcts }