1 /*
2  *******************************************************************************************
3  * Dgame (a D game framework) - Copyright (c) Randy Schütt
4  * 
5  * This software is provided 'as-is', without any express or implied warranty.
6  * In no event will the authors be held liable for any damages arising from
7  * the use of this software.
8  * 
9  * Permission is granted to anyone to use this software for any purpose,
10  * including commercial applications, and to alter it and redistribute it
11  * freely, subject to the following restrictions:
12  * 
13  * 1. The origin of this software must not be misrepresented; you must not claim
14  *    that you wrote the original software. If you use this software in a product,
15  *    an acknowledgment in the product documentation would be appreciated but is
16  *    not required.
17  * 
18  * 2. Altered source versions must be plainly marked as such, and must not be
19  *    misrepresented as being the original software.
20  * 
21  * 3. This notice may not be removed or altered from any source distribution.
22  *******************************************************************************************
23  */
24 module Dgame.System.Clock;
25 
26 private import derelict.sdl2.functions;
27 
28 /**
29  * To convert the Clock milliseconds to seconds
30  */
31 float asSeconds(uint n) pure nothrow {
32 	return n >= 1000 ? (n / 1000) : 0;
33 }
34 
35 /**
36  * To convert the Clock milliseconds to minutes
37  */
38 float asMinutes(uint n) pure nothrow {
39 	immutable float secs = asSeconds(n);
40 	
41 	return secs >= 60 ? (secs / 60) : 0;
42 }
43 
44 /**
45  * To convert the Clock milliseconds to hours
46  */
47 ushort asHours(uint n) pure nothrow {
48 	immutable float mins = asMinutes(n);
49 	
50 	return mins >= 60 ? cast(ushort)(mins / 60) : 0;
51 }
52 
53 /**
54  * The Time struct converts ticks to msecs, seconds, minutes and hours.
55  */
56 struct Time {
57 	/// Milliseconds = Ticks
58 	uint msecs;
59 	/// Seconds = Milliseconds / 1000
60 	float seconds;
61 	//// Minutes = Seconds / 60
62 	float minutes;
63 	/// Hours = Minutes / 60
64 	ushort hours;
65 
66 	/**
67 	 * CTor
68 	 */
69 	this(uint msecs) pure nothrow {
70 		this.msecs   = msecs;
71 		this.seconds = asSeconds(msecs);
72 		this.minutes = asMinutes(msecs);
73 		this.hours   = asHours(msecs);
74 	}
75 
76 	/**
77 	 * Calculate the <b>remaining</b> time.
78 	 */
79 	static Time remain(Time time) pure nothrow {
80 		import std.math : floor;
81 
82 		const float min = time.minutes;
83 		const float sec = time.seconds;
84 
85 		time.minutes -= floor(float(time.hours)) * 60;
86 		time.minutes = floor(time.minutes);
87 		time.seconds -= floor(min) * 60;
88 		time.msecs -= floor(sec) * 1000;
89 
90 		return time;
91 	}
92 } unittest {
93 	Time time = Time(65_000);
94 
95 	assert(time.msecs == 65_000);
96 	assert(time.seconds == 65);
97 	assert(time.minutes >= 1.08f && time.minutes <= 1.09f);
98 
99 	time = Time.remain(time);
100 
101 	assert(time.msecs == 0f);
102 	assert(time.seconds == 5f);
103 	assert(time.minutes == 1f);
104 }
105 
106 /**
107  * This class handles timer functions and 
108  * the window class use these class to calculate the current fps.
109  *
110  * Author: rschuett
111  */
112 struct Clock {
113 private:
114 	uint _startTime;
115 	uint _numFrames;
116 	uint _currentFps;
117 	float _fpsTime;
118 	
119 public:
120 	/**
121 	 * Reset the clock time
122 	 */
123 	void reset() {
124 		this._startTime = SDL_GetTicks();
125 	}
126 	
127 	/**
128 	 * Returns the elapsed Time since the last reset.
129 	 */
130 	Time getElapsedTime() const {
131 		return Time(this.getElapsedTicks());
132 	}
133 	
134 	/**
135 	 * Returns only the milliseconds since the last reset.
136 	 */
137 	uint getElapsedTicks() const {
138 		return SDL_GetTicks() - this._startTime;
139 	}
140 	
141 	/**
142 	 * Returns the current framerate per seconds.
143 	 */
144 	uint getCurrentFps() {
145 		const uint elapsed_ticks = this.getElapsedTicks();
146 
147 		if (elapsed_ticks >= 1000) {
148 			this._currentFps = this._numFrames;
149 			this._fpsTime = (0f + elapsed_ticks) / this._numFrames;
150 			
151 			this._numFrames = 0;
152 			this.reset();
153 		}
154 		
155 		this._numFrames++;
156 		
157 		return this._currentFps;
158 	}
159 
160 	/**
161 	 * Returns the Time since the last Frame.
162 	 */
163 	float getFpsTime() const pure nothrow {
164 		return this._fpsTime;
165 	}
166 
167 	/**
168 	 * Returns the milliseconds since the application was started.
169 	 */
170 	static uint getTicks() {
171 		return SDL_GetTicks();
172 	}
173 	
174 	/**
175 	 * Returns the Time since the application was started.
176 	 */
177 	static Time getTime() {
178 		return Time(Clock.getTicks());
179 	}
180 	
181 	/**
182 	 * Wait for msecs milliseconds, which means that the application freeze for this time.
183 	 */
184 	static void wait(uint msecs) {
185 		SDL_Delay(msecs);
186 	}
187 	
188 	/**
189 	 * Use this function to get the 
190 	 * current value of the high resolution counter.
191 	 */
192 	static ulong getPerformanceCounter() {
193 		return SDL_GetPerformanceCounter();
194 	}
195 	
196 	/**
197 	 * Use this function to get the 
198 	 * count per second of the high resolution counter.
199 	 */
200 	static ulong getPerformanceFrequency() {
201 		return SDL_GetPerformanceFrequency();
202 	}
203 }