diff --git a/include/vkcv/Window.hpp b/include/vkcv/Window.hpp index f71671c935a0a5e17bb517c726d75ffff2973532..59a8826e62cf77b661e1ba7e1a84ee367c3fb48a 100644 --- a/include/vkcv/Window.hpp +++ b/include/vkcv/Window.hpp @@ -39,6 +39,12 @@ namespace vkcv { */ static void onMouseButtonEvent(GLFWwindow *callbackWindow, int button, int action, int mods); + /** + * @brief A callback function for handling mouse scrolling events. + * @param[in] callbackWindow The window that received the event. + * @param[in] xoffset The extent of horizontal scrolling. + * @param[in] yoffset The extent of vertical scrolling. + */ static void onMouseScrollEvent(GLFWwindow *callbackWindow, double xoffset, double yoffset); /** @@ -59,6 +65,11 @@ namespace vkcv { */ static void onKeyEvent(GLFWwindow *callbackWindow, int key, int scancode, int action, int mods); + /** + * @brief TODO + */ + static void onGamepadEvent(int gamepadIndex, Window *window); + public: /** * creates a GLFWwindow with the parameters in the function @@ -85,7 +96,7 @@ namespace vkcv { /** * polls all events on the GLFWwindow */ - static void pollEvents(); + void pollEvents(); /** * basic events of the window @@ -95,6 +106,7 @@ namespace vkcv { event< double, double > e_mouseScroll; event< int, int > e_resize; event< int, int, int, int > e_key; + event< int > e_gamepad; /** * returns the current window diff --git a/modules/camera/include/vkcv/camera/CameraController.hpp b/modules/camera/include/vkcv/camera/CameraController.hpp index 5fe7aba586068beff15525617d8e4817662746b7..5a534f9167d170795913c6710182a03373716e64 100644 --- a/modules/camera/include/vkcv/camera/CameraController.hpp +++ b/modules/camera/include/vkcv/camera/CameraController.hpp @@ -59,6 +59,12 @@ namespace vkcv::camera { * @param[in] camera The camera object. */ virtual void mouseButtonCallback(int button, int action, int mods, Camera &camera) = 0; + + /** + * @brief todo + * @param gamepadIndex + */ + virtual void gamepadCallback(int gamepadIndex, Camera &camera) = 0; }; } \ No newline at end of file diff --git a/modules/camera/include/vkcv/camera/CameraManager.hpp b/modules/camera/include/vkcv/camera/CameraManager.hpp index 69c4b311a561b9f3ce27e3d9906d68f21e2334ac..bb7e3df2eba47e5dad8e9b548e3c7ba2dad7883a 100644 --- a/modules/camera/include/vkcv/camera/CameraManager.hpp +++ b/modules/camera/include/vkcv/camera/CameraManager.hpp @@ -30,6 +30,7 @@ namespace vkcv::camera { std::function<void(double, double)> m_mouseScrollHandle; std::function<void(int, int, int)> m_mouseButtonHandle; std::function<void(int, int)> m_resizeHandle; + std::function<void(int)> m_gamepadHandle; Window& m_window; std::vector<Camera> m_cameras; @@ -42,6 +43,8 @@ namespace vkcv::camera { double m_lastX; double m_lastY; + double m_inputDelayTimer; + /** * @brief Binds the camera object to the window event handles. */ @@ -86,6 +89,11 @@ namespace vkcv::camera { * @param[in] height The new height of the window. */ void resizeCallback(int width, int height); + + /** + * @brief TODO + */ + void gamepadCallback(int gamepadIndex); /** * @brief Gets a camera controller object of specified @p controllerType. diff --git a/modules/camera/include/vkcv/camera/PilotCameraController.hpp b/modules/camera/include/vkcv/camera/PilotCameraController.hpp index c6a9f7c7ffa9a3be77f12c29e456291fb8f6b845..349544d28b825289d80a71d677e84a0ed205ed99 100644 --- a/modules/camera/include/vkcv/camera/PilotCameraController.hpp +++ b/modules/camera/include/vkcv/camera/PilotCameraController.hpp @@ -17,6 +17,10 @@ namespace vkcv::camera { bool m_left; bool m_right; + float m_gamepadX; + float m_gamepadY; + float m_gamepadZ; + bool m_rotationActive; float m_cameraSpeed; @@ -133,6 +137,12 @@ namespace vkcv::camera { * @param[in] camera The camera object. */ void mouseButtonCallback(int button, int action, int mods, Camera &camera); + + /** + * @brief todo + * @param gamepadIndex + */ + void gamepadCallback(int gamepadIndex, Camera &camera); }; } \ No newline at end of file diff --git a/modules/camera/include/vkcv/camera/TrackballCameraController.hpp b/modules/camera/include/vkcv/camera/TrackballCameraController.hpp index 0211043a9c6b862df8e500af190ad1f75a3c78aa..58b78dca5cd35f85149f0e571cd74d0a49851003 100644 --- a/modules/camera/include/vkcv/camera/TrackballCameraController.hpp +++ b/modules/camera/include/vkcv/camera/TrackballCameraController.hpp @@ -95,6 +95,11 @@ namespace vkcv::camera { */ void mouseButtonCallback(int button, int action, int mods, Camera &camera); + /** + * @brief todo + * @param gamepadIndex + */ + void gamepadCallback(int gamepadIndex, Camera &camera); }; } \ No newline at end of file diff --git a/modules/camera/src/vkcv/camera/CameraManager.cpp b/modules/camera/src/vkcv/camera/CameraManager.cpp index 977c61d03dac51598281262acf9609540063a9e4..567abf5500ff4dcd5abaec7afd1f6d6f5ab8cebb 100644 --- a/modules/camera/src/vkcv/camera/CameraManager.cpp +++ b/modules/camera/src/vkcv/camera/CameraManager.cpp @@ -1,6 +1,5 @@ #include "vkcv/camera/CameraManager.hpp" - #include <vkcv/Logger.hpp> namespace vkcv::camera { @@ -12,6 +11,7 @@ namespace vkcv::camera { m_activeCameraIndex = 0; m_lastX = static_cast<float>(window.getWidth()) / 2.0f; m_lastY = static_cast<float>(window.getHeight()) / 2.0f; + m_inputDelayTimer = glfwGetTime() + 0.2; } CameraManager::~CameraManager() {} @@ -22,6 +22,7 @@ namespace vkcv::camera { m_mouseScrollHandle = m_window.e_mouseScroll.add([&](double offsetX, double offsetY) {this->scrollCallback( offsetX, offsetY);} ); m_mouseButtonHandle = m_window.e_mouseButton.add([&] (int button, int action, int mods) {this->mouseButtonCallback( button, action, mods);}); m_resizeHandle = m_window.e_resize.add([&](int width, int height) {this->resizeCallback(width, height);}); + m_gamepadHandle = m_window.e_gamepad.add([&](int gamepadIndex) {this->gamepadCallback(gamepadIndex);}); } void CameraManager::resizeCallback(int width, int height) { @@ -75,7 +76,29 @@ namespace vkcv::camera { break; } } - + + // todo: fix event catch speed + void CameraManager::gamepadCallback(int gamepadIndex) { + // handle camera switching + GLFWgamepadstate gamepadState; + glfwGetGamepadState(gamepadIndex, &gamepadState); + + double time = glfwGetTime(); + if (time - m_inputDelayTimer > 0.2) { + int switchDirection = gamepadState.buttons[GLFW_GAMEPAD_BUTTON_DPAD_RIGHT] - gamepadState.buttons[GLFW_GAMEPAD_BUTTON_DPAD_LEFT]; + m_activeCameraIndex += switchDirection; + if (std::greater<int>{}(m_activeCameraIndex, m_cameras.size() - 1)) { + m_activeCameraIndex = 0; + } + else if (std::less<int>{}(m_activeCameraIndex, 0)) { + m_activeCameraIndex = m_cameras.size() - 1; + } + m_inputDelayTimer = time; + } + + getActiveController().gamepadCallback(gamepadIndex, getActiveCamera()); // handle camera rotation, translation + } + CameraController& CameraManager::getActiveController() { const ControllerType type = getControllerType(getActiveCameraIndex()); return getControllerByType(type); diff --git a/modules/camera/src/vkcv/camera/PilotCameraController.cpp b/modules/camera/src/vkcv/camera/PilotCameraController.cpp index 1a50a0efa4b4e75adb81ce869d6b927bd0046758..13ae0b2bbba270e1ba46ba5f788d9cd7ee80922b 100644 --- a/modules/camera/src/vkcv/camera/PilotCameraController.cpp +++ b/modules/camera/src/vkcv/camera/PilotCameraController.cpp @@ -1,5 +1,4 @@ #include "vkcv/camera/PilotCameraController.hpp" - #include <GLFW/glfw3.h> namespace vkcv::camera { @@ -12,9 +11,13 @@ namespace vkcv::camera { m_left = false; m_right = false; + m_gamepadX = 0.0f; + m_gamepadY = 0.0f; + m_gamepadZ = 0.0f; + m_rotationActive = false; - m_cameraSpeed = 2.0f; + m_cameraSpeed = 2.5f; m_fov_nsteps = 100; m_fov_min = 10; @@ -70,9 +73,9 @@ namespace vkcv::camera { const float distance = m_cameraSpeed * static_cast<float>(deltaTime); - position += distance * getDirectionFactor(m_forward, m_backward) * front; - position += distance * getDirectionFactor(m_left, m_right) * left; - position += distance * getDirectionFactor(m_upward, m_downward) * up; + position += distance * (getDirectionFactor(m_forward, m_backward) + m_gamepadZ) * front; + position += distance * (getDirectionFactor(m_left, m_right) + m_gamepadX) * left; + position += distance * (getDirectionFactor(m_upward, m_downward) + m_gamepadY) * up; camera.lookAt(position, position + front, up); } @@ -127,6 +130,45 @@ namespace vkcv::camera { } } + void PilotCameraController::gamepadCallback(int gamepadIndex, Camera &camera) { + GLFWgamepadstate gamepadState; + glfwGetGamepadState(gamepadIndex, &gamepadState); + + float sensitivity = 0.05f; + double threshold = 0.03; // todo: needs further investigation! + + // handle rotations + double stickRightX = static_cast<double>(gamepadState.axes[GLFW_GAMEPAD_AXIS_RIGHT_X]); + double stickRightY = static_cast<double>(gamepadState.axes[GLFW_GAMEPAD_AXIS_RIGHT_Y]); + if ((std::less<double>{}(stickRightX, -threshold) || std::greater<double>{}(stickRightX, threshold)) + && (std::less<double>{}(stickRightY, -threshold) || std::greater<double>{}(stickRightY, threshold))) { + panView(stickRightX * sensitivity, stickRightY * sensitivity, camera); + } + + // handle zooming + double zoom = static_cast<double>((gamepadState.axes[GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER] + - gamepadState.axes[GLFW_GAMEPAD_AXIS_LEFT_TRIGGER]) + * sensitivity * 0.5); + changeFov(zoom, camera); + + // handle translation + m_gamepadY = gamepadState.buttons[GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER] - gamepadState.buttons[GLFW_GAMEPAD_BUTTON_LEFT_BUMPER]; + float stickLeftX = gamepadState.axes[GLFW_GAMEPAD_AXIS_LEFT_X]; + float stickLeftY = gamepadState.axes[GLFW_GAMEPAD_AXIS_LEFT_Y]; + if (std::less<float>{}(stickLeftY, -threshold) || std::greater<float>{}(stickLeftY, threshold)) { + m_gamepadZ = -stickLeftY; + } + else { + m_gamepadZ = 0.0f; + } + if (std::less<float>{}(stickLeftX, -threshold) || std::greater<float>{}(stickLeftX, threshold)) { + m_gamepadX = -stickLeftX; + } + else { + m_gamepadX = 0.0f; + } + } + void PilotCameraController::moveForward(int action){ m_forward = static_cast<bool>(action); diff --git a/modules/camera/src/vkcv/camera/TrackballCameraController.cpp b/modules/camera/src/vkcv/camera/TrackballCameraController.cpp index 201c6ecdc1c703dbcd53b7dc4b179c86576f2312..71ab484d6ac93719cd6436644239d42bd0fdd1d7 100644 --- a/modules/camera/src/vkcv/camera/TrackballCameraController.cpp +++ b/modules/camera/src/vkcv/camera/TrackballCameraController.cpp @@ -1,5 +1,4 @@ #include "vkcv/camera/TrackballCameraController.hpp" - #include <GLFW/glfw3.h> namespace vkcv::camera { @@ -82,7 +81,7 @@ namespace vkcv::camera { return; } - float sensitivity = 0.05f; + float sensitivity = 0.025f; xoffset *= sensitivity; yoffset *= sensitivity; @@ -97,4 +96,26 @@ namespace vkcv::camera { m_rotationActive = false; } } + + void TrackballCameraController::gamepadCallback(int gamepadIndex, Camera &camera) { + GLFWgamepadstate gamepadState; + glfwGetGamepadState(gamepadIndex, &gamepadState); + + float sensitivity = 0.025f; + double threshold = 0.03; // todo: needs further investigation! + + // handle rotations + double stickRightX = static_cast<double>(gamepadState.axes[GLFW_GAMEPAD_AXIS_RIGHT_X]); + double stickRightY = static_cast<double>(gamepadState.axes[GLFW_GAMEPAD_AXIS_RIGHT_Y]); + if ((std::less<double>{}(stickRightX, -threshold) || std::greater<double>{}(stickRightX, threshold)) + && (std::less<double>{}(stickRightY, -threshold) || std::greater<double>{}(stickRightY, threshold))) { + panView(stickRightX * sensitivity, stickRightY * sensitivity, camera); + } + + // handle translation + double stickLeftY = static_cast<double>(gamepadState.axes[GLFW_GAMEPAD_AXIS_LEFT_Y]); + if (std::less<double>{}(stickLeftY, -threshold) || std::greater<double>{}(stickLeftY, threshold)) { + updateRadius(-stickLeftY * sensitivity, camera); + } + } } \ No newline at end of file diff --git a/projects/cmd_sync_test/src/main.cpp b/projects/cmd_sync_test/src/main.cpp index a02c4542c7608e520e5ed33e746b5a9c836fc09f..ce2e0fbfaf06469030a99a7b248cb596c1c56fbf 100644 --- a/projects/cmd_sync_test/src/main.cpp +++ b/projects/cmd_sync_test/src/main.cpp @@ -223,7 +223,7 @@ int main(int argc, const char** argv) { auto start = std::chrono::system_clock::now(); const auto appStartTime = start; while (window.isWindowOpen()) { - vkcv::Window::pollEvents(); + window.pollEvents(); uint32_t swapchainWidth, swapchainHeight; if (!core.beginFrame(swapchainWidth, swapchainHeight)) { diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp index 42b1f595dc9f36f8cfb9816a1508980aefb52a83..b33e514a3503f7ba748bea23843e29e3887e32d7 100644 --- a/projects/first_mesh/src/main.cpp +++ b/projects/first_mesh/src/main.cpp @@ -155,7 +155,7 @@ int main(int argc, const char** argv) { auto start = std::chrono::system_clock::now(); while (window.isWindowOpen()) { - vkcv::Window::pollEvents(); + window.pollEvents(); if(window.getHeight() == 0 || window.getWidth() == 0) continue; diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp index 8ecea2b69906b017b321e3ca6002761fb8ffdd7d..4775afdcf89778d363e298996fa1ae1e92e944fa 100644 --- a/projects/first_triangle/src/main.cpp +++ b/projects/first_triangle/src/main.cpp @@ -160,15 +160,17 @@ int main(int argc, const char** argv) { const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); vkcv::camera::CameraManager cameraManager(window, windowWidth, windowHeight); - uint32_t camIndex = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT); - uint32_t camIndex2 = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL); + uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT); + uint32_t camIndex1 = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL); - cameraManager.getCamera(camIndex).setPosition(glm::vec3(0, 0, -2)); + cameraManager.getCamera(camIndex0).setPosition(glm::vec3(0, 0, -2)); + cameraManager.getCamera(camIndex1).setPosition(glm::vec3(0.0f, 0.0f, 0.0f)); + cameraManager.getCamera(camIndex1).setCenter(glm::vec3(0.0f, 0.0f, -1.0f)); while (window.isWindowOpen()) { window.pollEvents(); - + uint32_t swapchainWidth, swapchainHeight; // No resizing = No problem if (!core.beginFrame(swapchainWidth, swapchainHeight)) { continue; diff --git a/src/vkcv/Window.cpp b/src/vkcv/Window.cpp index c21271b78f7501721d5c0496d0344dd68e2e7e52..70cfb153833c528be39c5d2c292e0b5da0d04083 100644 --- a/src/vkcv/Window.cpp +++ b/src/vkcv/Window.cpp @@ -5,7 +5,6 @@ */ #include <GLFW/glfw3.h> - #include "vkcv/Window.hpp" namespace vkcv { @@ -55,14 +54,16 @@ namespace vkcv { glfwSetKeyCallback(m_window, Window::onKeyEvent); glfwSetScrollCallback(m_window, Window::onMouseScrollEvent); + + glfwSetJoystickUserPointer(GLFW_JOYSTICK_1, this); } void Window::pollEvents() { + onGamepadEvent(GLFW_JOYSTICK_1, this); glfwPollEvents(); } void Window::onMouseButtonEvent(GLFWwindow *callbackWindow, int button, int action, int mods) { - auto window = static_cast<Window *>(glfwGetWindowUserPointer(callbackWindow)); if (window != nullptr) { @@ -71,7 +72,6 @@ namespace vkcv { } void Window::onMouseMoveEvent(GLFWwindow *callbackWindow, double x, double y) { - auto window = static_cast<Window *>(glfwGetWindowUserPointer(callbackWindow)); if (window != nullptr) { @@ -88,7 +88,6 @@ namespace vkcv { } void Window::onResize(GLFWwindow *callbackWindow, int width, int height) { - auto window = static_cast<Window *>(glfwGetWindowUserPointer(callbackWindow)); if (window != nullptr) { @@ -97,7 +96,6 @@ namespace vkcv { } void Window::onKeyEvent(GLFWwindow *callbackWindow, int key, int scancode, int action, int mods) { - auto window = static_cast<Window *>(glfwGetWindowUserPointer(callbackWindow)); if (window != nullptr) { @@ -105,6 +103,12 @@ namespace vkcv { } } + void Window::onGamepadEvent(int gamepadIndex, Window *window) { + if (glfwJoystickPresent(gamepadIndex)) { + window->e_gamepad(gamepadIndex); + } + } + bool Window::isWindowOpen() const { return !glfwWindowShouldClose(m_window); }