1 /**
2 Copyright: Copyright (c) 2013-2018 Andrey Penechko.
3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
4 Authors: Andrey Penechko.
5 */
6 
7 module voxelman.utils.fpshelper;
8 
9 import core.thread;
10 import voxelman.utils.signal;
11 
12 /++
13  + Helper for measuring frames per second and setting static FPS.
14  + Usually needs to be located as field of game class.
15  +/
16 struct FpsHelper
17 {
18 	Signal!(FpsHelper*) fpsUpdated;
19 
20 	/// fps will be updated each updateInterval seconds
21 	double updateInterval = 0.5;
22 
23 	/// Stores actual FPS value
24 	double fps = 0;
25 
26 	/// Stores update time passed trough update every updateInterval
27 	double updateTime = 0;
28 
29 	/// Stores last delta time passed into update()
30 	double deltaTime = 0;
31 
32 	/// Stores amount of updates between
33 	size_t fpsTicks;
34 
35 	/// Accumulates time before reaching update interval
36 	double secondsAccumulator = 0;
37 
38 	bool limitFps = true;
39 
40 	uint maxFps = 60;
41 
42 	/// Delta time value will clamped to meet interval [0;timeLimit].
43 	/// This can prevent from value lags when entering hibernation or resizing the window.
44 	double timeLimit = 1;
45 
46 	void update(double dt, double updateTime)
47 	{
48 		if (dt > timeLimit)
49 		{
50 			dt = timeLimit;
51 		}
52 		deltaTime = dt;
53 
54 		++fpsTicks;
55 		secondsAccumulator += dt;
56 
57 		if (secondsAccumulator >= updateInterval)
58 		{
59 			fps = fpsTicks/secondsAccumulator;
60 			this.updateTime = updateTime;
61 			secondsAccumulator -= updateInterval;
62 			fpsTicks = 0;
63 			fpsUpdated.emit(&this);
64 		}
65 	}
66 
67 	void sleepAfterFrame(double frameTime)
68 	{
69 		if (limitFps)
70 		{
71 			uint msecs = cast(uint)((1/cast(double)maxFps - frameTime)*1000);
72 			if (msecs > 0)
73 				Thread.sleep(dur!"msecs"(msecs));
74 		}
75 	}
76 }
77