#include "Window.hpp" #include #include #include #include #include #include "../core/utils/logger.hpp" /// Default floating window width constexpr auto DEFAULT_WIDTH = 1280; /// Default floating window height constexpr auto DEFAULT_HEIGHT = 720; constexpr auto MIN_WIDTH = 854; constexpr auto MIN_HEIGHT = 480; constexpr auto APP_NAME = "Univerxel"; Window::Window() : ptr(nullptr), targetFPS(60) { if (!glfwInit()) { FATAL("Failed to initialize GLFW"); } } Window::~Window() { glfwTerminate(); } bool Window::create(const CreateInfo &opt) { if(isReady()) { LOG_W("Previous window in use"); return false; } glfwWindowHint(GLFW_SAMPLES, opt.samples); switch (opt.client.type) { case CreateInfo::Client::Type::GL: glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, opt.client.major); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, opt.client.minor); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); break; case CreateInfo::Client::Type::VK: LOG_W("WIP client type"); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); break; default: FATAL("Unsupported client type"); break; } #if FIXED_WINDOW glfwWindowHint(GLFW_RESIZABLE, false); //Note: Dev-only: Force floating on i3 #endif ptr = glfwCreateWindow(DEFAULT_WIDTH, DEFAULT_HEIGHT, APP_NAME, NULL, NULL); if (ptr == NULL) { LOG_E("Failed to open GLFW window"); return false; } glfwMakeContextCurrent(ptr); // Ensure we can capture the escape key being pressed below glfwSetInputMode(ptr, GLFW_STICKY_KEYS, GL_TRUE); // Hide the mouse and enable unlimited mouvement glfwSetInputMode(ptr, GLFW_CURSOR, GLFW_CURSOR_DISABLED); // Set the mouse at the center of the screen // TODO: move to input manager glfwPollEvents(); glfwSetCursorPos(ptr, DEFAULT_WIDTH / 2, DEFAULT_HEIGHT / 2); // Force aspect ratio glfwSetWindowSizeLimits(ptr, MIN_WIDTH, MIN_HEIGHT, GLFW_DONT_CARE, GLFW_DONT_CARE); glfwSetWindowAspectRatio(ptr, RATIO_WIDTH, RATIO_HEIGHT); glfwSetFramebufferSizeCallback(ptr, opt.pfnResize); glfwSetWindowTitle(ptr, APP_NAME); glfwSetWindowAttrib(ptr, GLFW_RESIZABLE, true); return true; } bool Window::isReady() const { return ptr != nullptr; } void Window::setTargetFPS(int val) { targetFPS = val; glfwSwapInterval(static_cast(val < MIN_FPS)); } double Window::getTime() const { return glfwGetTime(); } void Window::startFrame() { frameStart = getTime(); } void Window::wait(int microseconds) { std::this_thread::sleep_for(std::chrono::microseconds(microseconds)); } void Window::waitTargetFPS() { if (targetFPS >= MIN_FPS && targetFPS <= MAX_FPS) { while (glfwGetTime() < frameStart + 1.0 / targetFPS) { wait(); } } } void Window::destroy() { glfwDestroyWindow(ptr); ptr = nullptr; } bool Window::shouldClose() { return glfwWindowShouldClose(ptr); } void Window::setFullscreen(bool val) { // MAYBE: real fullscreen if(fullscreen != val) { fullscreen = val; if (val) { GLFWmonitor *monitor = glfwGetPrimaryMonitor(); const GLFWvidmode *mode = glfwGetVideoMode(monitor); glfwSetWindowMonitor(ptr, monitor, 0, 0, mode->width, mode->height, mode->refreshRate); } else { glfwSetWindowMonitor(ptr, nullptr, 0, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT, GLFW_DONT_CARE); } } }