diff --git a/config/Sources.cmake b/config/Sources.cmake index 0d0a37876813861c605466566eced727a70f6488..9d2c7b1f2595beb17212a6daf1b5331d8926d76d 100644 --- a/config/Sources.cmake +++ b/config/Sources.cmake @@ -51,4 +51,6 @@ set(vkcv_sources ${vkcv_source}/vkcv/Framebuffer.hpp ${vkcv_source}/vkcv/Framebuffer.cpp + + ${vkcv_include}/vkcv/Event.hpp ) diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index 45e555151584e60f4edd29058e5a59e076f9fafc..065c21d225810f465f0909cb8c1479c1031aba8f 100644 --- a/include/vkcv/Core.hpp +++ b/include/vkcv/Core.hpp @@ -33,7 +33,7 @@ namespace vkcv * * @param context encapsulates various Vulkan objects */ - Core(Context &&context, const Window &window, SwapChain swapChain, std::vector<vk::ImageView> imageViews, + Core(Context &&context, Window &window, SwapChain swapChain, std::vector<vk::ImageView> imageViews, const CommandResources& commandResources, const SyncResources& syncResources) noexcept; // explicit destruction of default constructor Core() = delete; @@ -53,6 +53,14 @@ namespace vkcv SyncResources m_SyncResources; uint32_t m_currentSwapchainImageIndex; std::vector<vk::Framebuffer> m_TemporaryFramebuffers; + + /** + * recreates the swapchain + * @param[in] width new window width + * @param[in] height new window hight + */ + static void recreateSwapchain(int width, int height); + public: /** * Destructor of #Core destroys the Vulkan objects contained in the core's context. @@ -107,7 +115,7 @@ namespace vkcv * @param[in] deviceExtensions (optional) Requested device extensions * @return New instance of #Context */ - static Core create(const Window &window, + static Core create(Window &window, const char *applicationName, uint32_t applicationVersion, std::vector<vk::QueueFlagBits> queueFlags = {}, diff --git a/include/vkcv/Event.hpp b/include/vkcv/Event.hpp new file mode 100644 index 0000000000000000000000000000000000000000..092f271c025e63be80b994b6b3921795c3e99671 --- /dev/null +++ b/include/vkcv/Event.hpp @@ -0,0 +1,64 @@ +#pragma once + +#include <functional> + +namespace vkcv { + + template<typename... T> + struct event_function { + typedef std::function<void(T...)> type; + }; + + /** + * template for event handling + * @tparam T parameter list + */ + template<typename... T> + struct event { + private: + std::vector<typename event_function<T...>::type> m_handles; + + public: + + /** + * calls all function handles with the given arguments + * @param arguments of the given function + */ + void operator()(T... arguments) { + for (auto &handle : this->m_handles) { + handle(arguments...); + } + } + + /** + * adds a function handle to the event to be called + * @param handle of the function + */ + void add(typename event_function<T...>::type handle) { + this->m_handles.push_back(handle); + } + + /** + * removes a function handle of the event + * @param handle of the function + */ + void remove(typename event_function<T...>::type handle) { + this->m_handles.erase( + remove(this->m_handles.begin(), this->m_handles.end(), handle), + this->m_handles.end() + ); + } + + event() = default; + + event(const event &other) = delete; + + event(event &&other) = delete; + + ~event() = default; + + event &operator=(const event &other) = delete; + + event &operator=(event &&other) = delete; + }; +} diff --git a/include/vkcv/Window.hpp b/include/vkcv/Window.hpp index 87c98a9281e6081c98487c7fd314d960b818190f..bb8081c166360e97595ff6994971390e53d6aa32 100644 --- a/include/vkcv/Window.hpp +++ b/include/vkcv/Window.hpp @@ -7,6 +7,7 @@ #define NOMINMAX #include <algorithm> +#include "Event.hpp" struct GLFWwindow; @@ -23,6 +24,32 @@ namespace vkcv { */ explicit Window(GLFWwindow *window); + /** + * mouse callback for moving the mouse on the screen + * @param[in] window The window that received the event. + * @param[in] xpos The new cursor x-coordinate, relative to the left edge of the content area. + * @param[in] ypos The new cursor y-coordinate, relative to the top edge of the content area. + */ + static void onMouseMoveEvent(GLFWwindow *window, double x, double y); + + /** + * resize callback for the resize option of the window + * @param[in] window The window that was resized. + * @param[in] width The new width, in screen coordinates, of the window. + * @param[in] height The new height, in screen coordinates, of the window. + */ + static void onResize(GLFWwindow *callbackWindow, int width, int height); + + /** + * key callback for the pressed key + * @param[in] window The window that received the event. + * @param[in] key The [keyboard key](@ref keys) that was pressed or released. + * @param[in] scancode The system-specific scancode of the key. + * @param[in] action `GLFW_PRESS`, `GLFW_RELEASE` or `GLFW_REPEAT`. + * @param[in] mods Bit field describing which [modifier keys](@ref mods) were held down. + */ + static void onKeyEvent(GLFWwindow *callbackWindow, int key, int scancode, int action, int mods); + public: /** * creates a GLFWwindow with the parameters in the function @@ -41,11 +68,23 @@ namespace vkcv { [[nodiscard]] bool isWindowOpen() const; + /** + * binds windowEvents to lambda events + */ + void initEvents(); + /** * polls all events on the GLFWwindow */ static void pollEvents(); + /** + * basic events of the window + */ + event< double, double > e_mouseMove; + event< int, int > e_resize; + event< int, int, int, int > e_key; + /** * returns the current window * @return window handle diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp index 3c3f91de9ac1c4490859559db2bca5bdd089ecfa..d718da0989251b7a992d020324c2bf2131dbf19e 100644 --- a/projects/first_triangle/src/main.cpp +++ b/projects/first_triangle/src/main.cpp @@ -2,6 +2,7 @@ #include <vkcv/Core.hpp> #include <vkcv/Window.hpp> #include <vkcv/ShaderProgram.hpp> +#include <GLFW/glfw3.h> int main(int argc, const char** argv) { const char* applicationName = "First Triangle"; @@ -15,6 +16,32 @@ int main(int argc, const char** argv) { false ); + // showing basic usage lambda events of window + window.e_mouseMove.add([&](double x, double y){ + std::cout << "movement: " << x << " , " << y << std::endl; + }); + + window.e_key.add([&](int key, int scancode, int action, int mods){ + switch (key) { + case GLFW_KEY_W: + std::cout << "Move forward" << std::endl; + break; + case GLFW_KEY_A: + std::cout << "Move left" << std::endl; + break; + case GLFW_KEY_S: + std::cout << "Move backward" << std::endl; + break; + case GLFW_KEY_D: + std::cout << "Move right" << std::endl; + break; + default: + std::cout << "this key is not supported yet: " << std::endl; + } + }); + + window.initEvents(); + vkcv::Core core = vkcv::Core::create( window, applicationName, @@ -102,8 +129,6 @@ int main(int argc, const char** argv) { core.beginFrame(); core.renderTriangle(trianglePass, trianglePipeline, windowWidth, windowHeight); core.endFrame(); - - window.pollEvents(); } return 0; } diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index 41c2ac6f821a4dbd122b65fd06c3585d1fccd79d..488715116cbb3b978dfab79e1e0e3d8e05c0f4dc 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -16,7 +16,7 @@ namespace vkcv { - Core Core::create(const Window &window, + Core Core::create(Window &window, const char *applicationName, uint32_t applicationVersion, std::vector<vk::QueueFlagBits> queueFlags, @@ -70,6 +70,10 @@ namespace vkcv const auto defaultCommandResources = createDefaultCommandResources(context.getDevice(), graphicQueueFamilyIndex); const auto defaultSyncResources = createDefaultSyncResources(context.getDevice()); + window.e_resize.add([&](int width, int height){ + recreateSwapchain(width,height); + }); + return Core(std::move(context) , window, swapChain, imageViews, defaultCommandResources, defaultSyncResources); } @@ -78,7 +82,7 @@ namespace vkcv return m_Context; } - Core::Core(Context &&context, const Window &window , SwapChain swapChain, std::vector<vk::ImageView> imageViews, + Core::Core(Context &&context, Window &window , SwapChain swapChain, std::vector<vk::ImageView> imageViews, const CommandResources& commandResources, const SyncResources& syncResources) noexcept : m_Context(std::move(context)), m_window(window), @@ -154,7 +158,7 @@ namespace vkcv if (acquireSwapchainImage() != Result::SUCCESS) { return; } - + m_window.pollEvents(); m_Context.getDevice().waitIdle(); // FIMXE: this is a sin against graphics programming, but its getting late - Alex destroyTemporaryFramebuffers(); const vk::CommandBufferUsageFlags beginFlags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit; @@ -213,4 +217,9 @@ namespace vkcv vk::Format Core::getSwapchainImageFormat() { return m_swapchain.getSurfaceFormat().format; } + + void Core::recreateSwapchain(int width, int height) { + /* boilerplate for #34 */ + std::cout << "Resized to : " << width << " , " << height << std::endl; + } } diff --git a/src/vkcv/Window.cpp b/src/vkcv/Window.cpp index 376f363a95c1e873c435825ba97e155205851347..87f302c146f79f82a9b5334fd6a651fa00a92616 100644 --- a/src/vkcv/Window.cpp +++ b/src/vkcv/Window.cpp @@ -42,14 +42,52 @@ namespace vkcv { return Window(window); } - bool Window::isWindowOpen() const { - return !glfwWindowShouldClose(m_window); + void Window::initEvents() { + glfwSetWindowUserPointer(m_window, this); + + // combine Callbacks with Events + glfwSetCursorPosCallback(m_window, Window::onMouseMoveEvent); + + glfwSetWindowSizeCallback(m_window, Window::onResize); + + glfwSetKeyCallback(m_window, Window::onKeyEvent); } void Window::pollEvents() { glfwPollEvents(); } + 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::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); + } + } + + bool Window::isWindowOpen() const { + return !glfwWindowShouldClose(m_window); + } + int Window::getWidth() const { int width; glfwGetWindowSize(m_window, &width, nullptr);