#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"; static void glfw_error_callback(int error, const char* description) { LOG_E("[GLFW] " << error << ": " << description); } Window::Window() : ptr(nullptr), targetFPS(60) { glfwSetErrorCallback(glfw_error_callback); 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: 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; } if (opt.client.type == CreateInfo::Client::Type::GL) glfwMakeContextCurrent(ptr); // 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); setTargetFPS(opt.fps); setFullscreen(opt.fullscreen); return true; } bool Window::isReady() const { return ptr != nullptr; } void Window::setTargetFPS(int val) { targetFPS = val; } 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); } } }