#include "display.hpp" #include #include namespace rog::ui { GLFWwindow *display::create_window(glm::uvec2 extent, std::string_view title, void *user_data) { glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); const auto window = glfwCreateWindow(extent.x, extent.y, title.data(), nullptr, nullptr); if (window == nullptr) { auto description = static_cast(nullptr); glfwGetError(&description); throw std::runtime_error(description); } glfwSetWindowUserPointer(window, user_data); return window; } display::display(user_input *input, glm::uvec2 extent, std::string_view title) : handle(create_window(extent, title, this)), title(title), input(input) { glfwSetWindowSizeCallback( handle, [](GLFWwindow *window, int width, int height) { auto self = static_cast(glfwGetWindowUserPointer(window)); for (const auto &cb : self->resize_callbacks) { cb(glm::uvec2(width, height)); } }); glfwSetKeyCallback(handle, [](GLFWwindow *window, int key, [[maybe_unused]] int scancode, int action, [[maybe_unused]] int mods) { auto self = static_cast(glfwGetWindowUserPointer(window)); if (action == GLFW_RELEASE) { self->input->set_key_state(static_cast(key), key_state::released); } else if (action == GLFW_REPEAT) { self->input->set_key_state(static_cast(key), key_state::repeat); } else if (action == GLFW_PRESS) { self->input->set_key_state(static_cast(key), key_state::pressed); } }); glfwSetCursorPosCallback(handle, [](GLFWwindow *window, double x, double y) { static_cast(glfwGetWindowUserPointer(window)) ->input->set_mouse_pos(glm::vec2{x, y}); }); glfwSetMouseButtonCallback( handle, [](GLFWwindow *window, int button, int action, int mods) { auto self = static_cast(glfwGetWindowUserPointer(window)); auto mouse_button = ui::mouse_button::left; switch (button) { case GLFW_MOUSE_BUTTON_LEFT: mouse_button = ui::mouse_button::left; break; case GLFW_MOUSE_BUTTON_RIGHT: mouse_button = ui::mouse_button::right; break; case GLFW_MOUSE_BUTTON_MIDDLE: mouse_button = ui::mouse_button::middle; break; default:; } auto mouse_action = ui::button_state::down; switch (action) { case GLFW_PRESS: mouse_action = ui::button_state::down; break; case GLFW_RELEASE: mouse_action = ui::button_state::up; break; default:; } self->input->set_mouse_button(mouse_button, mouse_action); }); } display::~display() { glfwDestroyWindow(handle); } display::display(const display &rhs) : handle(create_window(rhs.extent(), rhs.title, this)), title(rhs.title) { glfwSetWindowSizeCallback( handle, [](GLFWwindow *window, int width, int height) { auto self = static_cast(glfwGetWindowUserPointer(window)); for (const auto &cb : self->resize_callbacks) { cb(glm::uvec2(width, height)); } }); } display::display(display &&rhs) noexcept : handle(std::exchange(rhs.handle, nullptr)), title(rhs.title) {} display &display::operator=(const display &rhs) { return *this = display(rhs); } display &display::operator=(display &&rhs) noexcept { std::swap(handle, rhs.handle); std::swap(title, rhs.title); return *this; } bool display::should_close() const noexcept { return glfwWindowShouldClose(handle); } glm::uvec2 display::extent() const noexcept { auto extent = glm::ivec2(); glfwGetFramebufferSize(handle, &extent.x, &extent.y); return extent; } void display::poll_events() { glfwPollEvents(); } vk::raii::SurfaceKHR display::create_surface(const vk::raii::Instance &instance) { auto c_surface = VkSurfaceKHR(); glfwCreateWindowSurface(*instance, handle, nullptr, &c_surface); return vk::raii::SurfaceKHR(instance, c_surface); } void display::resize_callback(std::function callback) { resize_callbacks.push_back(callback); } GLFWwindow *display::raw() const noexcept { return handle; } void display::request_close() noexcept { glfwSetWindowShouldClose(handle, true); } } // namespace rog::ui