1 module gfm.sdl2.framecounter;
2 
3 import std.string;
4 
5 import derelict.sdl2.sdl;
6 
7 import gfm.core.queue,
8        gfm.sdl2.sdl;
9 
10 
11 /// Utility class which gives time delta between frames, and 
12 /// logs some framerate statistics.
13 /// Useful for a variable timestep application.
14 final class FrameCounter
15 {
16     public
17     {
18         /// Creates a FrameCounter, SDL must be initialized.
19         this(SDL2 sdl)
20         {
21             _sdl = sdl;
22             _firstFrame = true;
23             _elapsedTime = 0;
24             _frameTimes = new RingBuffer!ulong(10);
25         }
26 
27         /// Marks the beginning of a new frame.
28         /// Returns: Current time difference since last frame, in milliseconds.
29         ulong tickMs()
30         {
31             if (_firstFrame)
32             {
33                 _lastTime = SDL_GetTicks();
34                 _firstFrame = false;
35                 _frameTimes.pushBack(0);
36                 return 0; // no advance for first frame
37             }
38             else
39             {
40                 uint now = SDL_GetTicks();
41                 uint delta = now - _lastTime;
42                 _elapsedTime += delta;
43                 _lastTime = now;
44                 _frameTimes.pushBack(delta);
45                 return delta;
46             }
47         }
48 
49         /// Marks the beginning of a new frame.
50         /// Returns: Current time difference since last frame, in seconds.
51         deprecated alias tick = tickSecs;
52         double tickSecs()
53         {
54             return tickMs() * 0.001;
55         }
56 
57         /// Returns: Elapsed time since creation, in milliseconds.
58         ulong elapsedTimeMs() const
59         {
60             return _elapsedTime;
61         }
62 
63         /// Returns: Elapsed time since creation, in seconds.
64         double elapsedTime() const
65         {
66             return _elapsedTime * 0.001;
67         }
68 
69         /// Returns: Displayable framerate statistics.
70         string getFPSString()
71         {
72             double sum = 0;
73             double min = double.infinity;
74             double max = -double.infinity;
75             foreach(ulong frameTime; _frameTimes[])
76             {
77                 if (frameTime < min)
78                     min = frameTime;
79                 if (frameTime > max)
80                     max = frameTime;
81                 sum += frameTime;
82             }
83 
84             double avg = sum / cast(double)(_frameTimes[].length);
85             int avgFPS = cast(int)(0.5 + ( avg != 0 ? 1000 / avg : 0 ) );
86             int avgdt = cast(int)(0.5 + avg);
87 
88             return format("FPS: %s dt: avg %sms min %sms max %sms", avgFPS, avgdt, min, max);
89         }
90     }
91 
92     private
93     {
94         SDL2 _sdl;
95         RingBuffer!ulong _frameTimes;
96         bool _firstFrame;
97         uint _lastTime;
98         ulong _elapsedTime;
99     }
100 }
101