From 2e101fdd1e82ed67e08af7a2076d0bec7962c69d Mon Sep 17 00:00:00 2001 From: saschawillems Date: Mon, 20 Jun 2016 22:08:50 +0200 Subject: [PATCH] First person gamepad camera for Android (move with LT, look around with RT) --- base/camera.hpp | 65 +++++++++++++++++++++++++++++++++++++- base/vulkanexamplebase.cpp | 65 ++++++++++++++++++++++---------------- base/vulkanexamplebase.h | 10 ++---- 3 files changed, 104 insertions(+), 36 deletions(-) diff --git a/base/camera.hpp b/base/camera.hpp index 7c55fe87..fb457ea2 100644 --- a/base/camera.hpp +++ b/base/camera.hpp @@ -6,7 +6,6 @@ * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) */ - #define GLM_FORCE_RADIANS #define GLM_FORCE_DEPTH_ZERO_TO_ONE #include @@ -133,4 +132,68 @@ public: } }; + // Update camera passing separate axis data (gamepad) + // Returns true if view or position has been changed + bool updatePad(glm::vec2 axisLeft, glm::vec2 axisRight, float deltaTime) + { + bool retVal = false; + + if (type == CameraType::firstperson) + { + // Use the common console thumbstick layout + // Left = view, right = move + + const float deadZone = 0.0015f; + const float range = 1.0f - deadZone; + + glm::vec3 camFront; + camFront.x = -cos(glm::radians(rotation.x)) * sin(glm::radians(rotation.y)); + camFront.y = sin(glm::radians(rotation.x)); + camFront.z = cos(glm::radians(rotation.x)) * cos(glm::radians(rotation.y)); + camFront = glm::normalize(camFront); + + float moveSpeed = deltaTime * movementSpeed * 2.0f; + float rotSpeed = deltaTime * 50.0f; + + // Move + if (fabsf(axisLeft.y) > deadZone) + { + float pos = (fabsf(axisLeft.y) - deadZone) / range; + position -= camFront * pos * ((axisLeft.y < 0.0f) ? -1.0f : 1.0f) * moveSpeed; + retVal = true; + } + if (fabsf(axisLeft.x) > deadZone) + { + float pos = (fabsf(axisLeft.x) - deadZone) / range; + position += glm::normalize(glm::cross(camFront, glm::vec3(0.0f, 1.0f, 0.0f))) * pos * ((axisLeft.x < 0.0f) ? -1.0f : 1.0f) * moveSpeed; + retVal = true; + } + + // Rotate + if (fabsf(axisRight.x) > deadZone) + { + float pos = (fabsf(axisRight.x) - deadZone) / range; + rotation.y += pos * ((axisRight.x < 0.0f) ? -1.0f : 1.0f) * rotSpeed; + retVal = true; + } + if (fabsf(axisRight.y) > deadZone) + { + float pos = (fabsf(axisRight.y) - deadZone) / range; + rotation.x -= pos * ((axisRight.y < 0.0f) ? -1.0f : 1.0f) * rotSpeed; + retVal = true; + } + } + else + { + // todo: move code from example base class for look-at + } + + if (retVal) + { + updateViewMatrix(); + } + + return retVal; + } + }; \ No newline at end of file diff --git a/base/vulkanexamplebase.cpp b/base/vulkanexamplebase.cpp index 3b67faeb..4212eaee 100644 --- a/base/vulkanexamplebase.cpp +++ b/base/vulkanexamplebase.cpp @@ -517,31 +517,40 @@ void VulkanExampleBase::renderLoop() // todo : check if gamepad is present // todo : time based and relative axis positions bool updateView = false; - // Rotate - if (std::abs(gamePadState.axes.x) > deadZone) + if (camera.type != Camera::CameraType::firstperson) { - rotation.y += gamePadState.axes.x * 0.5f * rotationSpeed; - camera.rotate(glm::vec3(0.0f, gamePadState.axes.x * 0.5f, 0.0f)); - updateView = true; + // Rotate + if (std::abs(gamePadState.axisLeft.x) > deadZone) + { + rotation.y += gamePadState.axisLeft.x * 0.5f * rotationSpeed; + camera.rotate(glm::vec3(0.0f, gamePadState.axisLeft.x * 0.5f, 0.0f)); + updateView = true; + } + if (std::abs(gamePadState.axisLeft.y) > deadZone) + { + rotation.x -= gamePadState.axisLeft.y * 0.5f * rotationSpeed; + camera.rotate(glm::vec3(gamePadState.axisLeft.y * 0.5f, 0.0f, 0.0f)); + updateView = true; + } + // Zoom + if (std::abs(gamePadState.axisRight.y) > deadZone) + { + zoom -= gamePadState.axisRight.y * 0.01f * zoomSpeed; + updateView = true; + } + if (updateView) + { + viewChanged(); + } } - if (std::abs(gamePadState.axes.y) > deadZone) + else { - rotation.x -= gamePadState.axes.y * 0.5f * rotationSpeed; - camera.rotate(glm::vec3(gamePadState.axes.y * 0.5f, 0.0f, 0.0f)); - updateView = true; + updateView = camera.updatePad(gamePadState.axisLeft, gamePadState.axisRight, frameTimer); + if (updateView) + { + viewChanged(); + } } - // Zoom - if (std::abs(gamePadState.axes.rz) > deadZone) - { - zoom -= gamePadState.axes.rz * 0.01f * zoomSpeed; - updateView = true; - } - if (updateView) - { - viewChanged(); - } - - } } #elif defined(__linux__) @@ -1128,7 +1137,7 @@ void VulkanExampleBase::handleMessages(HWND hWnd, UINT uMsg, WPARAM wParam, LPAR break; } - if (camera.firtsperson) + if (camera.firstperson) { switch (wParam) { @@ -1150,7 +1159,7 @@ void VulkanExampleBase::handleMessages(HWND hWnd, UINT uMsg, WPARAM wParam, LPAR keyPressed((uint32_t)wParam); break; case WM_KEYUP: - if (camera.firtsperson) + if (camera.firstperson) { switch (wParam) { @@ -1242,10 +1251,12 @@ int32_t VulkanExampleBase::handleAppInput(struct android_app* app, AInputEvent* { if (AInputEvent_getSource(event) == AINPUT_SOURCE_JOYSTICK) { - vulkanExample->gamePadState.axes.x = AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_X, 0); - vulkanExample->gamePadState.axes.y = AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_Y, 0); - vulkanExample->gamePadState.axes.z = AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_Z, 0); - vulkanExample->gamePadState.axes.rz = AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_RZ, 0); + // Left thumbstick + vulkanExample->gamePadState.axisLeft.x = AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_X, 0); + vulkanExample->gamePadState.axisLeft.y = AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_Y, 0); + // Right thumbstick + vulkanExample->gamePadState.axisRight.x = AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_Z, 0); + vulkanExample->gamePadState.axisRight.y = AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_RZ, 0); } else { diff --git a/base/vulkanexamplebase.h b/base/vulkanexamplebase.h index 52a337c5..deec7533 100644 --- a/base/vulkanexamplebase.h +++ b/base/vulkanexamplebase.h @@ -180,16 +180,10 @@ public: } depthStencil; // Gamepad state (only one pad supported) - struct { - struct - { - float x = 0.0f; - float y = 0.0f; - float z = 0.0f; - float rz = 0.0f; - } axes; + glm::vec2 axisLeft = glm::vec2(0.0f); + glm::vec2 axisRight = glm::vec2(0.0f); } gamePadState; // OS specific