#pragma once #include namespace Core { class Timer { public: static const uint32_t DefaultFps = 30; explicit Timer(uint32_t target_fps = DefaultFps) : target_fps_(normalize_fps(target_fps)), tick_remainder_(0), frame_start_ms_(0), fixed_delta_ms_(0) { } void begin_frame(uint32_t now_ms) { frame_start_ms_ = now_ms; fixed_delta_ms_ = next_tick_ms(); } uint32_t target_fps() const { return target_fps_; } uint32_t fixed_delta_ms() const { return fixed_delta_ms_; } uint32_t frame_start_ms() const { return frame_start_ms_; } uint32_t remaining_frame_ms(uint32_t now_ms) const { const uint32_t elapsed_ms = now_ms - frame_start_ms_; return elapsed_ms < fixed_delta_ms_ ? fixed_delta_ms_ - elapsed_ms : 0u; } static bool is_supported_fps(uint32_t fps) { return fps == 30u || fps == 45u || fps == 60u; } static uint32_t normalize_fps(uint32_t fps) { return is_supported_fps(fps) ? fps : DefaultFps; } private: uint32_t next_tick_ms() { tick_remainder_ += 1000u; const uint32_t tick_ms = tick_remainder_ / target_fps_; tick_remainder_ %= target_fps_; return tick_ms; } uint32_t target_fps_; uint32_t tick_remainder_; uint32_t frame_start_ms_; uint32_t fixed_delta_ms_; }; }