From b5c3b78d57ee6e85bf3deefdab5533e1e4111655 Mon Sep 17 00:00:00 2001 From: Cristian Luis Duarte Date: Thu, 1 Mar 2018 17:58:23 -0300 Subject: [PATCH] Android - Virtual Pad - Limit joystick inside base circle. --- .../TouchscreenVirtualPadDevice.cpp | 98 ++++++++++++++----- .../TouchscreenVirtualPadDevice.h | 5 + 2 files changed, 80 insertions(+), 23 deletions(-) diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp index 90a78b3231..1774bbb4d3 100644 --- a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp +++ b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp @@ -50,6 +50,7 @@ void TouchscreenVirtualPadDevice::init() { _screenDPI = eventScreen->physicalDotsPerInch(); _fixedRadius = _screenDPI * 256 / 534; + _fixedRadiusForCalc = _fixedRadius - _screenDPI * 105 / 534; // 105 is the radius of the stick circle } auto& virtualPadManager = VirtualPad::Manager::instance(); @@ -79,6 +80,79 @@ float clip(float n, float lower, float upper) { return std::max(lower, std::min(n, upper)); } +glm::vec2 TouchscreenVirtualPadDevice::clippedPointInCircle(float radius, glm::vec2 origin, glm::vec2 touchPoint) { + float deltaX = touchPoint.x-origin.x; + float deltaY = touchPoint.y-origin.y; + + float distance = sqrt(pow(deltaX,2)+pow(deltaY,2)); + + // First case, inside the boundaires, just use the distance + if (distance <= radius) { + return touchPoint; + } + + // Second case, purely vertical (avoid division by zero) + if (deltaX == 0.0f) { + return vec2(touchPoint.x, clip(touchPoint.y, origin.y-radius, origin.y+radius) ); + } + + // Third case, calculate point in circumference + // line formula + float m = deltaY/deltaX; + float b = touchPoint.y - m * touchPoint.x; + + // quadtratic coefs of circumference and line intersection + float qa = pow(m,2)+1; + float qb = 2 * ( m * b - origin.x - origin.y * m ); + float qc = pow(origin.x, 2) - pow(radius,2) + b * b - 2 * b * origin.y + pow(origin.y, 2); + + float discr = qb * qb - 4 * qa * qc; + float discrSign = deltaX>0?1.0:-1.0; + + float finalX = (- qb + discrSign * sqrt(discr)) / (2 * qa); + float finalY = m * finalX + b; + + return vec2(finalX, finalY); +} + +void TouchscreenVirtualPadDevice::processInputUseCircleMethod(VirtualPad::Manager& virtualPadManager) { + vec2 clippedPoint = clippedPointInCircle(_fixedRadiusForCalc, _firstTouchLeftPoint, _currentTouchLeftPoint); + + _inputDevice->_axisStateMap[controller::LX] = (clippedPoint.x - _firstTouchLeftPoint.x) / _fixedRadiusForCalc; + _inputDevice->_axisStateMap[controller::LY] = (clippedPoint.y - _firstTouchLeftPoint.y) / _fixedRadiusForCalc; + + virtualPadManager.getLeftVirtualPad()->setFirstTouch(_firstTouchLeftPoint); + virtualPadManager.getLeftVirtualPad()->setCurrentTouch(clippedPoint); + virtualPadManager.getLeftVirtualPad()->setBeingTouched(true); + virtualPadManager.getLeftVirtualPad()->setShown(true); // If touched, show in any mode (fixed joystick position or non-fixed) +} + +void TouchscreenVirtualPadDevice::processInputUseSquareMethod(VirtualPad::Manager& virtualPadManager) { + float leftDistanceScaleX, leftDistanceScaleY; + leftDistanceScaleX = (_currentTouchLeftPoint.x - _firstTouchLeftPoint.x) / _screenDPIScale.x; + leftDistanceScaleY = (_currentTouchLeftPoint.y - _firstTouchLeftPoint.y) / _screenDPIScale.y; + + leftDistanceScaleX = clip(leftDistanceScaleX, -STICK_RADIUS_INCHES, STICK_RADIUS_INCHES); + leftDistanceScaleY = clip(leftDistanceScaleY, -STICK_RADIUS_INCHES, STICK_RADIUS_INCHES); + + // NOW BETWEEN -1 1 + leftDistanceScaleX /= STICK_RADIUS_INCHES; + leftDistanceScaleY /= STICK_RADIUS_INCHES; + + _inputDevice->_axisStateMap[controller::LX] = leftDistanceScaleX; + _inputDevice->_axisStateMap[controller::LY] = leftDistanceScaleY; + + /* Shared variables for stick rendering (clipped to the stick radius)*/ + // Prevent this for being done when not in first person view + virtualPadManager.getLeftVirtualPad()->setFirstTouch(_firstTouchLeftPoint); + virtualPadManager.getLeftVirtualPad()->setCurrentTouch( + glm::vec2(clip(_currentTouchLeftPoint.x, -STICK_RADIUS_INCHES * _screenDPIScale.x + _firstTouchLeftPoint.x, STICK_RADIUS_INCHES * _screenDPIScale.x + _firstTouchLeftPoint.x), + clip(_currentTouchLeftPoint.y, -STICK_RADIUS_INCHES * _screenDPIScale.y + _firstTouchLeftPoint.y, STICK_RADIUS_INCHES * _screenDPIScale.y + _firstTouchLeftPoint.y)) + ); + virtualPadManager.getLeftVirtualPad()->setBeingTouched(true); + virtualPadManager.getLeftVirtualPad()->setShown(true); // If touched, show in any mode (fixed joystick position or non-fixed) +} + void TouchscreenVirtualPadDevice::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) { auto userInputMapper = DependencyManager::get(); userInputMapper->withLock([&, this]() { @@ -89,29 +163,7 @@ void TouchscreenVirtualPadDevice::pluginUpdate(float deltaTime, const controller setupFixedCenter(virtualPadManager); if (_validTouchLeft) { - float leftDistanceScaleX, leftDistanceScaleY; - leftDistanceScaleX = (_currentTouchLeftPoint.x - _firstTouchLeftPoint.x) / _screenDPIScale.x; - leftDistanceScaleY = (_currentTouchLeftPoint.y - _firstTouchLeftPoint.y) / _screenDPIScale.y; - - leftDistanceScaleX = clip(leftDistanceScaleX, -STICK_RADIUS_INCHES, STICK_RADIUS_INCHES); - leftDistanceScaleY = clip(leftDistanceScaleY, -STICK_RADIUS_INCHES, STICK_RADIUS_INCHES); - - // NOW BETWEEN -1 1 - leftDistanceScaleX /= STICK_RADIUS_INCHES; - leftDistanceScaleY /= STICK_RADIUS_INCHES; - - _inputDevice->_axisStateMap[controller::LX] = leftDistanceScaleX; - _inputDevice->_axisStateMap[controller::LY] = leftDistanceScaleY; - - /* Shared variables for stick rendering (clipped to the stick radius)*/ - // Prevent this for being done when not in first person view - virtualPadManager.getLeftVirtualPad()->setFirstTouch(_firstTouchLeftPoint); - virtualPadManager.getLeftVirtualPad()->setCurrentTouch( - glm::vec2(clip(_currentTouchLeftPoint.x, -STICK_RADIUS_INCHES * _screenDPIScale.x + _firstTouchLeftPoint.x, STICK_RADIUS_INCHES * _screenDPIScale.x + _firstTouchLeftPoint.x), - clip(_currentTouchLeftPoint.y, -STICK_RADIUS_INCHES * _screenDPIScale.y + _firstTouchLeftPoint.y, STICK_RADIUS_INCHES * _screenDPIScale.y + _firstTouchLeftPoint.y)) - ); - virtualPadManager.getLeftVirtualPad()->setBeingTouched(true); - virtualPadManager.getLeftVirtualPad()->setShown(true); // If touched, show in any mode (fixed joystick position or non-fixed) + processInputUseCircleMethod(virtualPadManager); } else { virtualPadManager.getLeftVirtualPad()->setBeingTouched(false); if (_fixedPosition) { diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h index 6e65ef7ab2..f71490b0e3 100644 --- a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h +++ b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h @@ -79,6 +79,7 @@ protected: bool _fixedPosition; glm::vec2 _fixedCenterPosition; qreal _fixedRadius; + qreal _fixedRadiusForCalc; int _extraBottomMargin {0}; void touchLeftBegin(glm::vec2 touchPoint); @@ -89,6 +90,10 @@ protected: void touchRightUpdate(glm::vec2 touchPoint); void touchRightEnd(); void setupFixedCenter(VirtualPad::Manager& virtualPadManager, bool force = false); + + void processInputUseCircleMethod(VirtualPad::Manager& virtualPadManager); + void processInputUseSquareMethod(VirtualPad::Manager& virtualPadManager); + glm::vec2 clippedPointInCircle(float radius, glm::vec2 origin, glm::vec2 touchPoint); // just for debug private: void debugPoints(const QTouchEvent* event, QString who);