1 /**
2  * Defines the static Time class, which manages all game time related things.
3  */
4 module dash.utility.time;
5 import dash.utility;
6 
7 import std.datetime;
8 
9 /**
10  * Converts a duration to a float of seconds.
11  * 
12  * Params:
13  *  dur =           The duration to convert.
14  *
15  * Returns: The duration in seconds.
16  */
17 float toSeconds( Duration dur )
18 {
19     return cast(float)dur.total!"hnsecs" / cast(float)1.convert!( "seconds", "hnsecs" );
20 }
21 
22 TimeManager Time;
23 
24 static this()
25 {
26     Time = new TimeManager;
27 }
28 
29 /**
30  * Manages time and delta time.
31  */
32 final class TimeManager
33 {
34 private:
35     Duration delta;
36     Duration total;
37     
38 public:
39     /**
40      * Time since last frame in seconds.
41      */
42     @property float deltaTime() { return delta.toSeconds; }
43     /**
44      * Total time spent running in seconds.
45      */
46     @property float totalTime() { return total.toSeconds; }
47 
48     /**
49      * Update the times. Only call once per frame!
50      */
51     void update()
52     {
53         assert( onMainThread, "Must call Time.update from main thread." );
54 
55         updateTime();
56 
57         import dash.core.dgame: DGame;
58         DGame.instance.editor.send( "dash:perf:frametime", deltaTime );
59     }
60 
61 private:
62     this()
63     {
64         delta = total = Duration.zero;
65     }
66 }
67 
68 private:
69 StopWatch sw;
70 TickDuration cur;
71 TickDuration prev;
72 Duration delta;
73 Duration total;
74 Duration second;
75 int frameCount;
76 
77 /**
78  * Initialize the time controller with initial values.
79  */
80 static this()
81 {
82     cur = prev = TickDuration.min;
83     total = delta = second = Duration.zero;
84     frameCount = 0;
85 }
86 
87 /**
88  * Thread local time update.
89  */
90 void updateTime()
91 {
92     if( !sw.running )
93     {
94         sw.start();
95         cur = prev = sw.peek();
96     }
97 
98     delta = cast(Duration)( cur - prev );
99 
100     prev = cur;
101     cur = sw.peek();
102 
103     // Pass to values
104     Time.total = cast(Duration)cur;
105     Time.delta = delta;
106 
107     // Update framerate
108     ++frameCount;
109     second += delta;
110     if( second >= 1.seconds )
111     {
112         tracef( "Framerate: %d", frameCount );
113         second = Duration.zero;
114         frameCount = 0;
115     }
116 }