diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index b892908c..4cd7a316 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -255,8 +255,8 @@ void Engine::updateFrontend() { gui->postAct(); } -void Engine::nextFrame() { - windowControl->nextFrame(); +void Engine::nextFrame(bool waitForRefresh) { + windowControl->nextFrame(waitForRefresh); } void Engine::startPauseLoop() { @@ -275,7 +275,7 @@ void Engine::startPauseLoop() { if (isHeadless()) { platform::sleep(1.0 / params.tps * 1000); } else { - nextFrame(); + nextFrame(false); } } if (initialCursorLocked) { diff --git a/src/engine/Engine.hpp b/src/engine/Engine.hpp index 58a79f95..6b09b2ca 100644 --- a/src/engine/Engine.hpp +++ b/src/engine/Engine.hpp @@ -99,7 +99,7 @@ public: void applicationTick(); void updateFrontend(); void renderFrame(); - void nextFrame(); + void nextFrame(bool waitForRefresh); void startPauseLoop(); /// @brief Set screen (scene). diff --git a/src/engine/Mainloop.cpp b/src/engine/Mainloop.cpp index 5435e983..e87bc7d9 100644 --- a/src/engine/Mainloop.cpp +++ b/src/engine/Mainloop.cpp @@ -45,7 +45,9 @@ void Mainloop::run() { engine.renderFrame(); } engine.postUpdate(); - engine.nextFrame(); + engine.nextFrame( + dynamic_cast(engine.getScreen().get()) != nullptr + ); } logger.info() << "main loop stopped"; } diff --git a/src/engine/WindowControl.cpp b/src/engine/WindowControl.cpp index 0dabd009..637f4899 100644 --- a/src/engine/WindowControl.cpp +++ b/src/engine/WindowControl.cpp @@ -8,6 +8,7 @@ #include "window/input.hpp" #include "debug/Logger.hpp" #include "graphics/core/ImageData.hpp" +#include "util/platform.hpp" static debug::Logger logger("window-control"); @@ -78,15 +79,19 @@ void WindowControl::toggleFullscreen() { } } -void WindowControl::nextFrame() { +void WindowControl::nextFrame(bool waitForRefresh) { const auto& settings = engine.getSettings(); auto& window = engine.getWindow(); auto& input = engine.getInput(); - window.setFramerate( - window.isIconified() && settings.display.limitFpsIconified.get() - ? 20 - : settings.display.framerate.get() - ); + if (waitForRefresh) { + window.setFramerate(Window::FPS_UNLIMITED); + } else { + window.setFramerate( + window.isIconified() && settings.display.limitFpsIconified.get() + ? 20 + : settings.display.framerate.get() + ); + } window.swapBuffers(); - input.pollEvents(); + input.pollEvents(waitForRefresh); } diff --git a/src/engine/WindowControl.hpp b/src/engine/WindowControl.hpp index f3b7c8bc..2bea138e 100644 --- a/src/engine/WindowControl.hpp +++ b/src/engine/WindowControl.hpp @@ -16,7 +16,7 @@ public: Result initialize(); - void nextFrame(); + void nextFrame(bool waitForRefresh); void saveScreenshot(); diff --git a/src/window/Window.hpp b/src/window/Window.hpp index 135e4f7d..71004470 100644 --- a/src/window/Window.hpp +++ b/src/window/Window.hpp @@ -18,6 +18,8 @@ enum class WindowMode { class Window { public: + static inline constexpr int FPS_UNLIMITED = 0; + Window(glm::ivec2 size) : size(std::move(size)) {} virtual ~Window() = default; @@ -40,6 +42,9 @@ public: virtual void popScissor() = 0; virtual void resetScissor() = 0; + virtual void setShouldRefresh() = 0; + virtual bool checkShouldRefresh() = 0; + virtual double time() = 0; virtual void setFramerate(int framerate) = 0; diff --git a/src/window/detail/GLFWWindow.cpp b/src/window/detail/GLFWWindow.cpp index 27f56d3c..a80c10e0 100644 --- a/src/window/detail/GLFWWindow.cpp +++ b/src/window/detail/GLFWWindow.cpp @@ -180,14 +180,18 @@ public: : window(window) { } - void pollEvents() override { + void pollEvents(bool waitForRefresh) override { delta.x = 0.0f; delta.y = 0.0f; scroll = 0; currentFrame++; codepoints.clear(); pressedKeys.clear(); - glfwPollEvents(); + if (waitForRefresh) { + glfwWaitEvents(); + } else { + glfwPollEvents(); + } for (auto& [_, binding] : bindings.getAll()) { if (!binding.enabled) { @@ -377,6 +381,18 @@ public: prevSwap = time(); } + void setShouldRefresh() override { + shouldRefresh = true; + } + + bool checkShouldRefresh() override { + if (shouldRefresh) { + shouldRefresh = false; + return true; + } + return false; + } + bool isMaximized() const override { return glfwGetWindowAttrib(window, GLFW_MAXIMIZED); } @@ -557,12 +573,14 @@ private: double prevSwap = 0.0; int posX = 0; int posY = 0; + bool shouldRefresh = true; }; static_assert(!std::is_abstract()); static void mouse_button_callback(GLFWwindow* window, int button, int action, int) { auto handler = static_cast(glfwGetWindowUserPointer(window)); handler->input.onMouseCallback(button, action == GLFW_PRESS); + handler->setShouldRefresh(); } static void character_callback(GLFWwindow* window, unsigned int codepoint) { @@ -574,6 +592,8 @@ static void key_callback( GLFWwindow* window, int key, int /*scancode*/, int action, int /*mode*/ ) { auto handler = static_cast(glfwGetWindowUserPointer(window)); + handler->setShouldRefresh(); + auto& input = handler->input; if (key == GLFW_KEY_UNKNOWN) { return; @@ -599,11 +619,13 @@ static void window_size_callback(GLFWwindow* window, int width, int height) { static void scroll_callback(GLFWwindow* window, double, double yoffset) { auto handler = static_cast(glfwGetWindowUserPointer(window)); handler->input.scroll += yoffset; + handler->setShouldRefresh(); } static void cursor_pos_callback(GLFWwindow* window, double xpos, double ypos) { auto handler = static_cast(glfwGetWindowUserPointer(window)); handler->input.setCursorPosition(xpos, ypos); + handler->setShouldRefresh(); } static void iconify_callback(GLFWwindow* window, int iconified) { @@ -629,6 +651,11 @@ static void create_standard_cursors() { } } +static void refresh_callback(GLFWwindow* window) { + auto handler = static_cast(glfwGetWindowUserPointer(window)); + handler->setShouldRefresh(); +} + static void setup_callbacks(GLFWwindow* window) { glfwSetKeyCallback(window, key_callback); glfwSetMouseButtonCallback(window, mouse_button_callback); @@ -637,6 +664,7 @@ static void setup_callbacks(GLFWwindow* window) { glfwSetCharCallback(window, character_callback); glfwSetScrollCallback(window, scroll_callback); glfwSetWindowIconifyCallback(window, iconify_callback); + glfwSetWindowRefreshCallback(window, refresh_callback); } std::tuple< diff --git a/src/window/input.hpp b/src/window/input.hpp index 2edfe4c7..84c12040 100644 --- a/src/window/input.hpp +++ b/src/window/input.hpp @@ -261,7 +261,7 @@ class Input { public: virtual ~Input() = default; - virtual void pollEvents() = 0; + virtual void pollEvents(bool waitForRefresh) = 0; virtual const char* getClipboardText() const = 0; virtual void setClipboardText(const char* str) = 0;