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