diff options
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/application.cpp | 62 | ||||
| -rw-r--r-- | src/core/application.h | 13 |
2 files changed, 71 insertions, 4 deletions
diff --git a/src/core/application.cpp b/src/core/application.cpp index 1541e34..3a21cac 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -10,6 +10,8 @@ #include <imgui.h> #include <glm/glm.hpp> #include <algorithm> +#include <thread> +#include <chrono> namespace Donut { @@ -85,6 +87,9 @@ namespace Donut g_prev_scroll = glfwSetScrollCallback((GLFWwindow*)m_window->get_native_window(), donut_scroll_callback); + m_device->set_vsync(SettingsManager::get_v_sync_enabled()); // apply the persisted preference + glfwGetWindowSize((GLFWwindow*)m_window->get_native_window(), &m_windowed_w, &m_windowed_h); + m_start_time = glfwGetTime(); DONUT_INFO("Application ready on {} backend", m_device->device_name()); } @@ -93,24 +98,75 @@ namespace Donut { while (m_running) { + double frame_start = glfwGetTime(); glfwPollEvents(); if (!m_minimized && m_device) render_frame(); + + // With vsync off, cap to the target FPS (vsync itself paces otherwise). + if (!SettingsManager::get_v_sync_enabled()) + { + int fps = SettingsManager::get_target_fps(); + if (fps > 0) + { + double budget = 1.0 / (double)fps; + double elapsed = glfwGetTime() - frame_start; + if (elapsed < budget) + std::this_thread::sleep_for(std::chrono::duration<double>(budget - elapsed)); + } + } + } + } + + auto Application::set_resolution(int w, int h) -> void + { + if (m_window && !is_fullscreen()) + glfwSetWindowSize((GLFWwindow*)m_window->get_native_window(), w, h); + } + + auto Application::set_fullscreen(bool on) -> void + { + if (!m_window) return; + GLFWwindow* win = (GLFWwindow*)m_window->get_native_window(); + if (on == is_fullscreen()) return; + if (on) + { + glfwGetWindowPos(win, &m_windowed_x, &m_windowed_y); + glfwGetWindowSize(win, &m_windowed_w, &m_windowed_h); + GLFWmonitor* mon = glfwGetPrimaryMonitor(); + const GLFWvidmode* mode = glfwGetVideoMode(mon); + glfwSetWindowMonitor(win, mon, 0, 0, mode->width, mode->height, mode->refreshRate); + } + else + { + glfwSetWindowMonitor(win, nullptr, m_windowed_x, m_windowed_y, m_windowed_w, m_windowed_h, 0); } } + auto Application::set_vsync(bool on) -> void { if (m_device) m_device->set_vsync(on); } + auto Application::set_ui_scale(float scale) -> void { ImGui::GetIO().FontGlobalScale = scale; } + auto Application::is_fullscreen() const -> bool + { return m_window && glfwGetWindowMonitor((GLFWwindow*)m_window->get_native_window()) != nullptr; } + auto Application::get_window_size(int& w, int& h) const -> void + { w = 0; h = 0; if (m_window) glfwGetWindowSize((GLFWwindow*)m_window->get_native_window(), &w, &h); } + auto Application::render_frame() -> void { RHI::CommandList* cmd = m_device->begin_frame(glm::vec4(0.05f, 0.06f, 0.10f, 1.0f)); if (!cmd) return; // frame skipped (e.g. swapchain recreation) m_device->imgui_new_frame(); - View view = m_ui->draw(UIContext{ *m_scene, m_device->device_name() }); - update_input(view); - m_render_path->sync_hdri(m_scene->hdri_path); + // Keep the scene camera's projection current before the UI builds, so the + // scene-tab gizmo and the render agree on the same matrices this frame. int w = 0, h = 0; glfwGetFramebufferSize((GLFWwindow*)m_window->get_native_window(), &w, &h); + m_scene->scene_camera.set_projection(45.0f, (float)w / (float)std::max(h, 1), 0.1f, 1000.0f); + + View view = m_ui->draw(UIContext{ *m_scene, m_device->device_name(), *this }); + update_input(view); + m_render_path->sync_hdri(m_scene->hdri_path); + float time = (float)(glfwGetTime() - m_start_time); m_render_path->render(*cmd, *m_scene, view, w, h, m_user_moving, time); diff --git a/src/core/application.h b/src/core/application.h index cbd741d..10a375f 100644 --- a/src/core/application.h +++ b/src/core/application.h @@ -19,7 +19,7 @@ namespace Donut // RenderPath (device-side rendering) and the UILayer (tabbed workspaces), and // runs the frame loop that wires them together. All the rendering lives in the // RHI + shared renderers; all the editing lives in the Scene + workspaces. - class Application + class Application : public AppActions { public: Application(const std::string& name = "Donut", @@ -32,6 +32,14 @@ namespace Donut auto get_window() -> Window& { return *m_window; } static auto get() -> Application& { return *s_instance; } + // AppActions — window/device changes requested by the Setup workspace. + auto set_resolution(int w, int h) -> void override; + auto set_fullscreen(bool on) -> void override; + auto set_vsync(bool on) -> void override; + auto set_ui_scale(float scale) -> void override; + auto get_window_size(int& w, int& h) const -> void override; + auto is_fullscreen() const -> bool override; + private: auto on_init() -> void; auto on_shutdown() -> void; @@ -54,6 +62,9 @@ namespace Donut double m_start_time = 0.0; bool m_user_moving = false; + // windowed-mode geometry saved across a fullscreen toggle + int m_windowed_x = 100, m_windowed_y = 100, m_windowed_w = 1280, m_windowed_h = 720; + bool m_running = true; bool m_minimized = false; |
