#pragma once #include #include struct GLFWwindow; namespace hd2d { // GLFW window + OpenGL 4.5 core context with simple polled input. class Window { public: // Non-resizable windows float on tiling WMs, keeping an exact size. // `visible = false` creates a hidden, never-focused window that only // provides the GL context (headless captures: render into an // OffscreenTarget, see Screenshot.h). Hidden windows ignore vsync, // swapBuffers() is a no-op (unmapped Wayland surfaces never get frame // callbacks, so a real swap could block forever) and every input query // reports nothing, so the user's keyboard/mouse cannot affect them. bool create(int width, int height, const std::string& title, bool vsync = true, bool resizable = true, bool visible = true); void destroy(); // Polls events and refreshes per-frame input state. Returns false once the // window should close. bool pollEvents(); void swapBuffers(); bool visible() const { return visible_; } bool keyDown(int glfwKey) const; bool keyPressed(int glfwKey) const; // went down this frame bool mouseDown(int glfwButton) const; glm::vec2 mouseDelta() const { return visible_ ? mouseDelta_ : glm::vec2(0.0f); } float scrollDelta() const { return visible_ ? scrollDelta_ : 0.0f; } int width() const { return width_; } int height() const { return height_; } bool resized() const { return resized_; } GLFWwindow* handle() const { return window_; } void setTitle(const std::string& title); void requestClose(); private: static void onFramebufferSize(GLFWwindow* w, int width, int height); static void onScroll(GLFWwindow* w, double dx, double dy); GLFWwindow* window_ = nullptr; int width_ = 0, height_ = 0; bool resized_ = false; bool visible_ = true; bool keys_[512] = {}; bool prevKeys_[512] = {}; glm::vec2 lastMouse_{0.0f}; glm::vec2 mouseDelta_{0.0f}; float scrollAccum_ = 0.0f; float scrollDelta_ = 0.0f; }; } // namespace hd2d