feat: Introduce TimingManager for Accurate Frame Timing
- Added TimingManager class to provide precise timing for animations and frame pacing, addressing issues with ImGui::GetIO().DeltaTime. - Updated event handling in the window management to use SDL_PollEvent for improved responsiveness. - Integrated TimingManager into EditorManager, BackgroundRenderer, and WelcomeScreen for consistent delta time usage across the application. - Enhanced animation updates to utilize accurate frame timing, improving visual performance and user experience.
This commit is contained in:
119
src/app/core/timing.h
Normal file
119
src/app/core/timing.h
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
#ifndef YAZE_APP_CORE_TIMING_H
|
||||||
|
#define YAZE_APP_CORE_TIMING_H
|
||||||
|
|
||||||
|
#include <SDL.h>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace yaze {
|
||||||
|
namespace core {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class TimingManager
|
||||||
|
* @brief Provides accurate timing for animations and frame pacing
|
||||||
|
*
|
||||||
|
* This class solves the issue where ImGui::GetIO().DeltaTime only updates
|
||||||
|
* when events are processed (mouse movement, etc). It uses SDL's performance
|
||||||
|
* counter to provide accurate timing regardless of input events.
|
||||||
|
*/
|
||||||
|
class TimingManager {
|
||||||
|
public:
|
||||||
|
static TimingManager& Get() {
|
||||||
|
static TimingManager instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Update the timing manager (call once per frame)
|
||||||
|
* @return The delta time since last update in seconds
|
||||||
|
*/
|
||||||
|
float Update() {
|
||||||
|
uint64_t current_time = SDL_GetPerformanceCounter();
|
||||||
|
float delta_time = 0.0f;
|
||||||
|
|
||||||
|
if (last_time_ > 0) {
|
||||||
|
delta_time = (current_time - last_time_) / static_cast<float>(frequency_);
|
||||||
|
|
||||||
|
// Clamp delta time to prevent huge jumps (e.g., when debugging)
|
||||||
|
if (delta_time > 0.1f) {
|
||||||
|
delta_time = 0.1f;
|
||||||
|
}
|
||||||
|
|
||||||
|
accumulated_time_ += delta_time;
|
||||||
|
frame_count_++;
|
||||||
|
|
||||||
|
// Update FPS counter once per second
|
||||||
|
if (accumulated_time_ >= 1.0f) {
|
||||||
|
fps_ = static_cast<float>(frame_count_) / accumulated_time_;
|
||||||
|
frame_count_ = 0;
|
||||||
|
accumulated_time_ = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
last_time_ = current_time;
|
||||||
|
last_delta_time_ = delta_time;
|
||||||
|
return delta_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the last frame's delta time in seconds
|
||||||
|
*/
|
||||||
|
float GetDeltaTime() const {
|
||||||
|
return last_delta_time_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get current FPS
|
||||||
|
*/
|
||||||
|
float GetFPS() const {
|
||||||
|
return fps_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get total elapsed time since first update
|
||||||
|
*/
|
||||||
|
float GetElapsedTime() const {
|
||||||
|
if (last_time_ == 0) return 0.0f;
|
||||||
|
uint64_t current_time = SDL_GetPerformanceCounter();
|
||||||
|
return (current_time - first_time_) / static_cast<float>(frequency_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reset the timing state
|
||||||
|
*/
|
||||||
|
void Reset() {
|
||||||
|
last_time_ = 0;
|
||||||
|
first_time_ = SDL_GetPerformanceCounter();
|
||||||
|
accumulated_time_ = 0.0f;
|
||||||
|
frame_count_ = 0;
|
||||||
|
fps_ = 0.0f;
|
||||||
|
last_delta_time_ = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TimingManager() {
|
||||||
|
frequency_ = SDL_GetPerformanceFrequency();
|
||||||
|
first_time_ = SDL_GetPerformanceCounter();
|
||||||
|
last_time_ = 0;
|
||||||
|
accumulated_time_ = 0.0f;
|
||||||
|
frame_count_ = 0;
|
||||||
|
fps_ = 0.0f;
|
||||||
|
last_delta_time_ = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t frequency_;
|
||||||
|
uint64_t first_time_;
|
||||||
|
uint64_t last_time_;
|
||||||
|
float accumulated_time_;
|
||||||
|
uint32_t frame_count_;
|
||||||
|
float fps_;
|
||||||
|
float last_delta_time_;
|
||||||
|
|
||||||
|
TimingManager(const TimingManager&) = delete;
|
||||||
|
TimingManager& operator=(const TimingManager&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace core
|
||||||
|
} // namespace yaze
|
||||||
|
|
||||||
|
#endif // YAZE_APP_CORE_TIMING_H
|
||||||
|
|
||||||
@@ -120,28 +120,29 @@ absl::Status ShutdownWindow(Window& window) {
|
|||||||
absl::Status HandleEvents(Window& window) {
|
absl::Status HandleEvents(Window& window) {
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
SDL_WaitEvent(&event);
|
while (SDL_PollEvent(&event)) {
|
||||||
ImGui_ImplSDL2_ProcessEvent(&event);
|
ImGui_ImplSDL2_ProcessEvent(&event);
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case SDL_KEYDOWN:
|
case SDL_KEYDOWN:
|
||||||
case SDL_KEYUP: {
|
case SDL_KEYUP: {
|
||||||
io.KeyShift = ((SDL_GetModState() & KMOD_SHIFT) != 0);
|
io.KeyShift = ((SDL_GetModState() & KMOD_SHIFT) != 0);
|
||||||
io.KeyCtrl = ((SDL_GetModState() & KMOD_CTRL) != 0);
|
io.KeyCtrl = ((SDL_GetModState() & KMOD_CTRL) != 0);
|
||||||
io.KeyAlt = ((SDL_GetModState() & KMOD_ALT) != 0);
|
io.KeyAlt = ((SDL_GetModState() & KMOD_ALT) != 0);
|
||||||
io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0);
|
io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0);
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case SDL_WINDOWEVENT:
|
|
||||||
switch (event.window.event) {
|
|
||||||
case SDL_WINDOWEVENT_CLOSE:
|
|
||||||
window.active_ = false;
|
|
||||||
break;
|
|
||||||
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
|
||||||
io.DisplaySize.x = static_cast<float>(event.window.data1);
|
|
||||||
io.DisplaySize.y = static_cast<float>(event.window.data2);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
break;
|
case SDL_WINDOWEVENT:
|
||||||
|
switch (event.window.event) {
|
||||||
|
case SDL_WINDOWEVENT_CLOSE:
|
||||||
|
window.active_ = false;
|
||||||
|
break;
|
||||||
|
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
||||||
|
io.DisplaySize.x = static_cast<float>(event.window.data1);
|
||||||
|
io.DisplaySize.y = static_cast<float>(event.window.data2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
int mouseX;
|
int mouseX;
|
||||||
int mouseY;
|
int mouseY;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "absl/strings/match.h"
|
#include "absl/strings/match.h"
|
||||||
#include "absl/strings/str_cat.h"
|
#include "absl/strings/str_cat.h"
|
||||||
#include "app/core/features.h"
|
#include "app/core/features.h"
|
||||||
|
#include "app/core/timing.h"
|
||||||
#include "util/file_util.h"
|
#include "util/file_util.h"
|
||||||
#include "app/core/project.h"
|
#include "app/core/project.h"
|
||||||
#include "app/editor/code/assembly_editor.h"
|
#include "app/editor/code/assembly_editor.h"
|
||||||
@@ -636,6 +637,10 @@ void EditorManager::Initialize(const std::string& filename) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
absl::Status EditorManager::Update() {
|
absl::Status EditorManager::Update() {
|
||||||
|
// Update timing manager for accurate delta time across the application
|
||||||
|
// This fixes animation timing issues that occur when mouse isn't moving
|
||||||
|
core::TimingManager::Get().Update();
|
||||||
|
|
||||||
popup_manager_->DrawPopups();
|
popup_manager_->DrawPopups();
|
||||||
ExecuteShortcuts(context_.shortcut_manager);
|
ExecuteShortcuts(context_.shortcut_manager);
|
||||||
toast_manager_.Draw();
|
toast_manager_.Draw();
|
||||||
@@ -1475,7 +1480,7 @@ void EditorManager::DrawMenuBar() {
|
|||||||
|
|
||||||
if (show_emulator_) {
|
if (show_emulator_) {
|
||||||
Begin("Emulator", &show_emulator_, ImGuiWindowFlags_MenuBar);
|
Begin("Emulator", &show_emulator_, ImGuiWindowFlags_MenuBar);
|
||||||
emulator_.Run();
|
emulator_.Run(current_rom_);
|
||||||
End();
|
End();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
#include "app/core/timing.h"
|
||||||
#include "app/gui/theme_manager.h"
|
#include "app/gui/theme_manager.h"
|
||||||
#include "imgui/imgui.h"
|
#include "imgui/imgui.h"
|
||||||
|
|
||||||
@@ -23,7 +24,7 @@ void BackgroundRenderer::RenderDockingBackground(ImDrawList* draw_list, const Im
|
|||||||
const ImVec2& window_size, const Color& theme_color) {
|
const ImVec2& window_size, const Color& theme_color) {
|
||||||
if (!draw_list) return;
|
if (!draw_list) return;
|
||||||
|
|
||||||
UpdateAnimation(ImGui::GetIO().DeltaTime);
|
UpdateAnimation(core::TimingManager::Get().GetDeltaTime());
|
||||||
|
|
||||||
// Get current theme colors
|
// Get current theme colors
|
||||||
auto& theme_manager = ThemeManager::Get();
|
auto& theme_manager = ThemeManager::Get();
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "absl/time/clock.h"
|
#include "absl/time/clock.h"
|
||||||
#include "absl/time/time.h"
|
#include "absl/time/time.h"
|
||||||
#include "app/core/project.h"
|
#include "app/core/project.h"
|
||||||
|
#include "app/core/timing.h"
|
||||||
#include "app/gui/icons.h"
|
#include "app/gui/icons.h"
|
||||||
#include "app/gui/theme_manager.h"
|
#include "app/gui/theme_manager.h"
|
||||||
#include "imgui/imgui.h"
|
#include "imgui/imgui.h"
|
||||||
@@ -244,7 +245,8 @@ bool WelcomeScreen::Show(bool* p_open) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Smooth interpolation to target position (faster response)
|
// Smooth interpolation to target position (faster response)
|
||||||
float lerp_speed = 8.0f * ImGui::GetIO().DeltaTime;
|
// Use TimingManager for accurate delta time
|
||||||
|
float lerp_speed = 8.0f * yaze::core::TimingManager::Get().GetDeltaTime();
|
||||||
triforce_positions_[i].x += (target_pos.x - triforce_positions_[i].x) * lerp_speed;
|
triforce_positions_[i].x += (target_pos.x - triforce_positions_[i].x) * lerp_speed;
|
||||||
triforce_positions_[i].y += (target_pos.y - triforce_positions_[i].y) * lerp_speed;
|
triforce_positions_[i].y += (target_pos.y - triforce_positions_[i].y) * lerp_speed;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user