| 411 | }; |
| 412 | |
| 413 | struct FramerateWindow : Window { |
| 414 | int num_active = 0; |
| 415 | int num_displayed = 0; |
| 416 | |
| 417 | struct CachedDecimal { |
| 418 | StringID strid; |
| 419 | uint32_t value; |
| 420 | |
| 421 | inline void SetRate(double value, double target) |
| 422 | { |
| 423 | const double threshold_good = target * 0.95; |
| 424 | const double threshold_bad = target * 2 / 3; |
| 425 | this->value = (uint32_t)(value * 100); |
| 426 | this->strid = (value > threshold_good) ? STR_FRAMERATE_FPS_GOOD : (value < threshold_bad) ? STR_FRAMERATE_FPS_BAD : STR_FRAMERATE_FPS_WARN; |
| 427 | } |
| 428 | |
| 429 | inline void SetTime(double value, double target) |
| 430 | { |
| 431 | const double threshold_good = target / 3; |
| 432 | const double threshold_bad = target; |
| 433 | this->value = (uint32_t)(value * 100); |
| 434 | this->strid = (value < threshold_good) ? STR_FRAMERATE_MS_GOOD : (value > threshold_bad) ? STR_FRAMERATE_MS_BAD : STR_FRAMERATE_MS_WARN; |
| 435 | } |
| 436 | |
| 437 | inline uint32_t GetValue() const { return this->value; } |
| 438 | inline uint32_t GetDecimals() const { return 2; } |
| 439 | }; |
| 440 | |
| 441 | CachedDecimal rate_gameloop{}; ///< cached game loop tick rate |
| 442 | CachedDecimal rate_drawing{}; ///< cached drawing frame rate |
| 443 | CachedDecimal speed_gameloop{}; ///< cached game loop speed factor |
| 444 | std::array<CachedDecimal, PFE_MAX> times_shortterm{}; ///< cached short term average times |
| 445 | std::array<CachedDecimal, PFE_MAX> times_longterm{}; ///< cached long term average times |
| 446 | |
| 447 | static constexpr int MIN_ELEMENTS = 5; ///< smallest number of elements to display |
| 448 | |
| 449 | FramerateWindow(WindowDesc &desc, WindowNumber number) : Window(desc) |
| 450 | { |
| 451 | this->InitNested(number); |
| 452 | this->UpdateData(); |
| 453 | this->num_displayed = this->num_active; |
| 454 | |
| 455 | /* Window is always initialised to MIN_ELEMENTS height, resize to contain num_displayed */ |
| 456 | ResizeWindow(this, 0, (std::max(MIN_ELEMENTS, this->num_displayed) - MIN_ELEMENTS) * GetCharacterHeight(FS_NORMAL)); |
| 457 | } |
| 458 | |
| 459 | /** Update the window on a regular interval. */ |
| 460 | const IntervalTimer<TimerWindow> update_interval = {std::chrono::milliseconds(100), [this](auto) { |
| 461 | this->UpdateData(); |
| 462 | this->SetDirty(); |
| 463 | }}; |
| 464 | |
| 465 | void UpdateData() |
| 466 | { |
| 467 | double gl_rate = _pf_data[PFE_GAMELOOP].GetRate(); |
| 468 | this->rate_gameloop.SetRate(gl_rate, _pf_data[PFE_GAMELOOP].expected_rate); |
| 469 | this->speed_gameloop.SetRate(gl_rate / _pf_data[PFE_GAMELOOP].expected_rate, 1.0); |
| 470 | if (this->IsShaded()) return; // in small mode, this is everything needed |
nothing calls this directly
no test coverage detected