feat: refresh on demand in menu (adaptive framerate)

This commit is contained in:
MihailRis 2025-11-09 22:22:24 +03:00
parent ba0977a6f0
commit 7fc3703ad2
8 changed files with 56 additions and 16 deletions

View File

@ -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) {

View File

@ -99,7 +99,7 @@ public:
void applicationTick();
void updateFrontend();
void renderFrame();
void nextFrame();
void nextFrame(bool waitForRefresh);
void startPauseLoop();
/// @brief Set screen (scene).

View File

@ -45,7 +45,9 @@ void Mainloop::run() {
engine.renderFrame();
}
engine.postUpdate();
engine.nextFrame();
engine.nextFrame(
dynamic_cast<const MenuScreen*>(engine.getScreen().get()) != nullptr
);
}
logger.info() << "main loop stopped";
}

View File

@ -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);
}

View File

@ -16,7 +16,7 @@ public:
Result initialize();
void nextFrame();
void nextFrame(bool waitForRefresh);
void saveScreenshot();

View File

@ -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;

View File

@ -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<GLFWWindow>());
static void mouse_button_callback(GLFWwindow* window, int button, int action, int) {
auto handler = static_cast<GLFWWindow*>(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<GLFWWindow*>(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<GLFWWindow*>(glfwGetWindowUserPointer(window));
handler->input.scroll += yoffset;
handler->setShouldRefresh();
}
static void cursor_pos_callback(GLFWwindow* window, double xpos, double ypos) {
auto handler = static_cast<GLFWWindow*>(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<GLFWWindow*>(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<

View File

@ -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;