/** * @authors Sebastian Gaida * @file src/vkcv/Window.cpp * @brief Window class to handle a basic rendering surface and input */ #include <vector> #include <GLFW/glfw3.h> #include "vkcv/Window.hpp" namespace vkcv { static std::vector<GLFWwindow*> s_Windows; Window::Window(GLFWwindow *window) : m_window(window), e_mouseButton(true), e_mouseMove(true), e_mouseScroll(true), e_resize(true), e_key(true), e_char(true), e_gamepad(true) { glfwSetWindowUserPointer(m_window, this); // combine Callbacks with Events glfwSetMouseButtonCallback(m_window, Window::onMouseButtonEvent); glfwSetCursorPosCallback(m_window, Window::onMouseMoveEvent); glfwSetWindowSizeCallback(m_window, Window::onResize); glfwSetKeyCallback(m_window, Window::onKeyEvent); glfwSetScrollCallback(m_window, Window::onMouseScrollEvent); glfwSetCharCallback(m_window, Window::onCharEvent); } Window::~Window() { Window::e_mouseButton.unlock(); Window::e_mouseMove.unlock(); Window::e_mouseScroll.unlock(); Window::e_resize.unlock(); Window::e_key.unlock(); Window::e_char.unlock(); Window::e_gamepad.unlock(); s_Windows.erase(std::find(s_Windows.begin(), s_Windows.end(), m_window)); glfwDestroyWindow(m_window); if(s_Windows.empty()) { glfwTerminate(); } } Window Window::create( const char *windowTitle, int width, int height, bool resizable) { if(s_Windows.empty()) { glfwInit(); } width = std::max(width, 1); height = std::max(height, 1); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, resizable ? GLFW_TRUE : GLFW_FALSE); GLFWwindow *window = glfwCreateWindow(width, height, windowTitle, nullptr, nullptr); s_Windows.push_back(window); return Window(window); } void Window::pollEvents() { for (auto glfwWindow : s_Windows) { auto window = static_cast<Window *>(glfwGetWindowUserPointer(glfwWindow)); window->e_mouseButton.unlock(); window->e_mouseMove.unlock(); window->e_mouseScroll.unlock(); window->e_resize.unlock(); window->e_key.unlock(); window->e_char.unlock(); window->e_gamepad.unlock(); } glfwPollEvents(); for (int gamepadIndex = GLFW_JOYSTICK_1; gamepadIndex <= GLFW_JOYSTICK_LAST; gamepadIndex++) { if (glfwJoystickPresent(gamepadIndex)) { onGamepadEvent(gamepadIndex); } } for (auto glfwWindow : s_Windows) { auto window = static_cast<Window *>(glfwGetWindowUserPointer(glfwWindow)); window->e_mouseButton.lock(); window->e_mouseMove.lock(); window->e_mouseScroll.lock(); window->e_resize.lock(); window->e_key.lock(); window->e_char.lock(); window->e_gamepad.lock(); } } void Window::onMouseButtonEvent(GLFWwindow *callbackWindow, int button, int action, int mods) { auto window = static_cast<Window *>(glfwGetWindowUserPointer(callbackWindow)); if (window != nullptr) { window->e_mouseButton(button, action, mods); } } void Window::onMouseMoveEvent(GLFWwindow *callbackWindow, double x, double y) { auto window = static_cast<Window *>(glfwGetWindowUserPointer(callbackWindow)); if (window != nullptr) { window->e_mouseMove(x, y); } } void Window::onMouseScrollEvent(GLFWwindow *callbackWindow, double xoffset, double yoffset) { auto window = static_cast<Window *>(glfwGetWindowUserPointer(callbackWindow)); if (window != nullptr) { window->e_mouseScroll(xoffset, yoffset); } } void Window::onResize(GLFWwindow *callbackWindow, int width, int height) { auto window = static_cast<Window *>(glfwGetWindowUserPointer(callbackWindow)); if (window != nullptr) { window->e_resize(width, height); } } void Window::onKeyEvent(GLFWwindow *callbackWindow, int key, int scancode, int action, int mods) { auto window = static_cast<Window *>(glfwGetWindowUserPointer(callbackWindow)); if (window != nullptr) { window->e_key(key, scancode, action, mods); } } void Window::onCharEvent(GLFWwindow *callbackWindow, unsigned int c) { auto window = static_cast<Window *>(glfwGetWindowUserPointer(callbackWindow)); if (window != nullptr) { window->e_char(c); } } void Window::onGamepadEvent(int gamepadIndex) { size_t activeWindowIndex = std::find_if( s_Windows.begin(), s_Windows.end(), [](GLFWwindow* window){return glfwGetWindowAttrib(window, GLFW_FOCUSED);} ) - s_Windows.begin(); // fixes index getting out of bounds (e.g. if there is no focused window) activeWindowIndex *= (activeWindowIndex < s_Windows.size()); auto window = static_cast<Window *>(glfwGetWindowUserPointer(s_Windows[activeWindowIndex])); if (window != nullptr) { window->e_gamepad(gamepadIndex); } } bool Window::isWindowOpen() const { return !glfwWindowShouldClose(m_window); } int Window::getWidth() const { int width; glfwGetWindowSize(m_window, &width, nullptr); return width; } int Window::getHeight() const { int height; glfwGetWindowSize(m_window, nullptr, &height); return height; } GLFWwindow *Window::getWindow() const { return m_window; } void Window::getFramebufferSize(int &width, int &height) const { glfwGetFramebufferSize(m_window, &width, &height); } }