libtcod
Loading...
Searching...
No Matches
timer.hpp
Go to the documentation of this file.
1/* BSD 3-Clause License
2 *
3 * Copyright © 2008-2025, Jice and the libtcod contributors.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 *
16 * 3. Neither the name of the copyright holder nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
34#pragma once
35#ifndef LIBTCOD_TIMER_HPP_
36#define LIBTCOD_TIMER_HPP_
37#ifndef NO_SDL
38#include <SDL3/SDL_timer.h>
39
40#include <algorithm>
41#include <cstddef>
42#include <cstdint>
43#include <deque>
44#include <numeric>
45#include <stdexcept>
46#include <vector>
47
48#include "config.h"
49
50namespace tcod {
51
70class [[nodiscard]] Timer {
71 public:
72
75 Timer() : last_time_{SDL_GetPerformanceCounter()} {}
76
86 float sync(int desired_fps = 0) {
87 const uint64_t frequency = SDL_GetPerformanceFrequency();
88 uint64_t current_time = SDL_GetPerformanceCounter(); // The precise current time.
89 int64_t delta_time = static_cast<int64_t>(current_time - last_time_); // The precise delta time.
90 if (desired_fps > 0) {
91 const int64_t desired_delta_time = frequency / desired_fps; // Desired precise delta time.
92 const int64_t time_until_next_frame_ms =
93 (desired_delta_time - delta_time) * 1000 / static_cast<int64_t>(frequency);
94 if (time_until_next_frame_ms > 2) {
95 // Sleep until 1 millisecond before the target time.
96 SDL_Delay(static_cast<uint32_t>(time_until_next_frame_ms) - 1);
97 }
98 while (delta_time < desired_delta_time) { // Spin for the remaining time.
99 current_time = SDL_GetPerformanceCounter();
100 delta_time = static_cast<int64_t>(current_time - last_time_);
101 }
102 }
103 last_time_ = current_time;
104 const float delta_time_s = std::max(0.0f, static_cast<float>(delta_time) / frequency); // Delta time in seconds.
105 // Drop samples as they hit the total time and count limits.
106 double total_time = std::accumulate(samples_.begin(), samples_.end(), 0.0); // Total time of all samples.
107 while (!samples_.empty() && (total_time > MAX_SAMPLES_TIME || samples_.size() >= MAX_SAMPLES_COUNT)) {
108 total_time -= samples_.front();
109 samples_.pop_front();
110 }
111 samples_.push_back(delta_time_s);
112 return delta_time_s;
113 }
114
117 [[nodiscard]] float get_mean_fps() const noexcept {
118 if (samples_.empty()) return 0;
119 const double total_time = std::accumulate(samples_.begin(), samples_.end(), 0.0);
120 if (total_time == 0) return 0;
121 return 1.0f / static_cast<float>(total_time / static_cast<double>(samples_.size()));
122 }
123
126 [[nodiscard]] float get_last_fps() const noexcept {
127 if (samples_.empty()) return 0;
128 if (samples_.back() == 0) return 0;
129 return 1.0f / samples_.back();
130 }
131
134 [[nodiscard]] float get_min_fps() const noexcept {
135 if (samples_.empty()) return 0;
136 const float sample = *std::max_element(samples_.begin(), samples_.end());
137 if (sample == 0) return 0;
138 return 1.0f / sample;
139 }
140
143 [[nodiscard]] float get_max_fps() const noexcept {
144 if (samples_.empty()) return 0;
145 const float sample = *std::min_element(samples_.begin(), samples_.end());
146 if (sample == 0) return 0;
147 return 1.0f / sample;
148 }
149
152 [[nodiscard]] float get_median_fps() const noexcept {
153 if (samples_.empty()) return 0;
154 std::vector<float> samples(samples_.begin(), samples_.end());
155 std::sort(samples.begin(), samples.end());
156 float median_sample = samples[samples.size() / 2];
157 if (samples.size() % 2 == 0 && samples.size() > 2) {
158 median_sample = (median_sample + samples[samples.size() / 2 + 1]) / 2.0f;
159 }
160 if (median_sample == 0) return 0;
161 return 1.0f / median_sample;
162 }
163
164 private:
165 static constexpr size_t MAX_SAMPLES_COUNT = 1024; // Hard limit on the number of samples held.
166 static constexpr double MAX_SAMPLES_TIME = 1.0; // Hard limit on the total time of samples held.
167
168 uint64_t last_time_; // The last precise time sampled.
169 std::deque<float> samples_; // The most recent delta time samples in seconds.
170};
171} // namespace tcod
172#endif // NO_SDL
173#endif // LIBTCOD_TIMER_HPP_
float get_last_fps() const noexcept
Return the framerate of the last call to sync().
Definition timer.hpp:126
float sync(int desired_fps=0)
Sync the time to a given framerate (if provided) and return the delta time compared to the previous c...
Definition timer.hpp:86
Timer()
Construct a new Timer object.
Definition timer.hpp:75
float get_median_fps() const noexcept
Return the median framerate.
Definition timer.hpp:152
float get_min_fps() const noexcept
Return the lowest framerate recently sampled.
Definition timer.hpp:134
float get_max_fps() const noexcept
Return the highest framerate recently sampled.
Definition timer.hpp:143
float get_mean_fps() const noexcept
Return the mean framerate.
Definition timer.hpp:117
Libtcod config header.
The libtcod namespace.
Definition bresenham.hpp:157