1 module pixelperfectengine.system.timer; 2 /* 3 * Copyright (C) 2015-2021, by Laszlo Szeremi under the Boost license. 4 * 5 * Pixel Perfect Engine, system.timer module 6 */ 7 import collections.sortedlist; 8 public import core.time; 9 10 static CoarseTimer timer; 11 12 static this() { 13 timer = new CoarseTimer(); 14 } 15 /** 16 * Implements a coarse timer, that checks the time periodically (e.g. on VSYNC), then calls the delegate if the time 17 * assigned to it has been lapsed. 18 * Is fast and can effectively test for multiple elements, but is inaccurate which can even fluctuate if tests are done 19 * on VSYNC intervals. This will make the duration longer in every case (up to 16.7ms on 60Hz displays), but this 20 * still should be accurate enough for many cases. 21 * Delegates must take no arguments and nothrow to avoid issues from that. 22 */ 23 public class CoarseTimer { 24 alias TimerReceiver = nothrow void delegate(); 25 /** 26 * A timer entry. 27 */ 28 protected struct Entry { 29 TimerReceiver onLapse; ///The delegate to be called. 30 MonoTime when; ///When the delegate must be called, in system time. 31 int opCmp(const Entry other) const @nogc @trusted pure nothrow { 32 return when.opCmp(other.when); 33 } 34 bool opEquals(const Entry other) const @nogc @trusted pure nothrow { 35 return when == other.when; 36 } 37 size_t toHash() const @nogc @safe pure nothrow { 38 return cast(size_t)when.ticks; 39 } 40 } 41 protected SortedList!Entry timerList; ///The list of timer entries. 42 protected Entry[] timerRegs; ///Secondary timer list 43 protected uint status; ///1 if during testing, 0 otherwise 44 ///CTOR 45 public this() @safe pure nothrow { 46 47 } 48 /** 49 * Registers an entry for the timer. 50 * Delta sets the amount of time into the future. 51 */ 52 public void register(TimerReceiver dg, Duration delta) @safe nothrow { 53 if (!status) 54 timerList.put(Entry(dg, MonoTime.currTime + delta)); 55 else 56 timerRegs ~= Entry(dg, MonoTime.currTime + delta); 57 } 58 /** 59 * Tests the entries. 60 * If enough time has passed, then those entries will be called and deleted. 61 */ 62 public void test() nothrow { 63 status = 1; 64 while (timerList.length) { 65 if (MonoTime.currTime >= timerList[0].when) { 66 timerList[0].onLapse(); 67 timerList.remove(0); 68 } else { 69 break; 70 } 71 } 72 foreach (e ; timerRegs) 73 timerList.put(e); 74 timerRegs.length = 0; 75 status = 0; 76 } 77 }