diff --git a/src/android/app/src/main/jni/vr/layers/GameSurfaceLayer.cpp b/src/android/app/src/main/jni/vr/layers/GameSurfaceLayer.cpp index e98cd7424..adc97754a 100644 --- a/src/android/app/src/main/jni/vr/layers/GameSurfaceLayer.cpp +++ b/src/android/app/src/main/jni/vr/layers/GameSurfaceLayer.cpp @@ -30,8 +30,8 @@ License : Licensed under GPLv3 or any later version. namespace { -constexpr float kSuperImmersiveRadius = 0.5f; - +constexpr float kSuperImmersiveRadius = 0.5f; +constexpr float kDistanceBetweenPanelsInMeters = 0.75f; //----------------------------------------------------------------------------- // Local sysprops @@ -124,7 +124,7 @@ Panel CreateTopPanel(const XrVector3f& position, const float surfaceWidth, Panel CreateLowerPanelFromTopPanel(const Panel& topPanel, const float resolutionFactor) { // Note: the fact that two constants are 0.75 is purely coincidental. constexpr float kDefaultLowerPanelScaleFactor = 0.75f * 0.75f; - constexpr float kLowerPanelYOffsetInMeters = -0.75f; + constexpr float kLowerPanelYOffsetInMeters = -kDistanceBetweenPanelsInMeters; constexpr float kLowerPanelZOffsetInMeters = -1.5f; // Pitch the lower panel away from the viewer 45 degrees constexpr float kLowerPanelPitchInRadians = -MATH_FLOAT_PI / 4.0f; @@ -420,8 +420,8 @@ bool GameSurfaceLayer::GetRayIntersectionWithPanel(const XrVector3f& start, void GameSurfaceLayer::SetTopPanelFromController(const XrVector3f& controllerPosition) { static constexpr XrVector3f viewerPosition{0, 0, 0}; // Set viewer position - const float sphereRadius = XrMath::Vector3f::Length( - mTopPanel.mPanelFromWorld.position - viewerPosition); // Set the initial distance of the + const float sphereRadius = XrMath::Vector3f::Length( + mTopPanel.mPanelFromWorld.position - viewerPosition); // Set the initial distance of the // window from the viewer static constexpr XrVector3f windowUpDirection{0, 1, 0}; // Y is up @@ -430,17 +430,21 @@ void GameSurfaceLayer::SetTopPanelFromController(const XrVector3f& controllerPos CalculatePanelPosition(viewerPosition, controllerPosition, sphereRadius); const XrQuaternionf windowRotation = CalculatePanelRotation(windowPosition, viewerPosition, windowUpDirection); - if (windowPosition.y < 0) { return; } + if (windowPosition.y < + (mLowerPanel.mPanelFromWorld.position.y + kDistanceBetweenPanelsInMeters)) { + return; + } if (XrMath::Quatf::GetYawInRadians(windowRotation) > MATH_FLOAT_PI / 3.0f) { return; } mTopPanel.mPanelFromWorld = XrPosef{windowRotation, windowPosition}; } -void GameSurfaceLayer::SetTopPanelFromThumbstick(const float thumbstickY) { - static constexpr float kDepthSpeed = 0.05f; - static constexpr float kMaxDepth = -10.0f; +static constexpr float kThumbstickSpeed = 0.05f; - mTopPanel.mPanelFromWorld.position.z -= (thumbstickY * kDepthSpeed); +void GameSurfaceLayer::SetTopPanelFromThumbstick(const float thumbstickY) { + static constexpr float kMaxDepth = -10.0f; + + mTopPanel.mPanelFromWorld.position.z -= (thumbstickY * kThumbstickSpeed); mTopPanel.mPanelFromWorld.position.z = std::min(mTopPanel.mPanelFromWorld.position.z, mLowerPanel.mPanelFromWorld.position.z); mTopPanel.mPanelFromWorld.position.z = @@ -448,14 +452,14 @@ void GameSurfaceLayer::SetTopPanelFromThumbstick(const float thumbstickY) { } XrPosef GameSurfaceLayer::SetLowerPanelFromThumbstick(const float thumbstickY) { - static constexpr float kDepthSpeed = 0.05f; - static constexpr float kMaxDepth = -10.0f; + static constexpr float kMinY = -3.0f; - mLowerPanel.mPanelFromWorld.position.y += (thumbstickY * kDepthSpeed); + mLowerPanel.mPanelFromWorld.position.y += (thumbstickY * kThumbstickSpeed); mLowerPanel.mPanelFromWorld.position.y = - std::min(mLowerPanel.mPanelFromWorld.position.y, mTopPanel.mPanelFromWorld.position.y); + std::min(mLowerPanel.mPanelFromWorld.position.y, + mTopPanel.mPanelFromWorld.position.y - kDistanceBetweenPanelsInMeters); mLowerPanel.mPanelFromWorld.position.y = - std::max(mLowerPanel.mPanelFromWorld.position.y, kMaxDepth); + std::max(mLowerPanel.mPanelFromWorld.position.y, kMinY); return mLowerPanel.mPanelFromWorld; } diff --git a/src/android/app/src/main/jni/vr/vr_main.cpp b/src/android/app/src/main/jni/vr/vr_main.cpp index 6890c9730..40dd5cfe7 100644 --- a/src/android/app/src/main/jni/vr/vr_main.cpp +++ b/src/android/app/src/main/jni/vr/vr_main.cpp @@ -650,7 +650,10 @@ private: XrPosef cursorPose3d = XrMath::Posef::Identity(); XrVector2f cursorPos2d = {0, 0}; float scaleFactor = 0.01f; - CursorLayer::CursorType cursorType = appState.mLowerMenuType == LowerMenuType::POSITIONAL_MENU ? CursorLayer::CursorType::CURSOR_TYPE_TOP_PANEL : CursorLayer::CursorType::CURSOR_TYPE_NORMAL; + CursorLayer::CursorType cursorType = + appState.mLowerMenuType == LowerMenuType::POSITIONAL_MENU + ? CursorLayer::CursorType::CURSOR_TYPE_TOP_PANEL + : CursorLayer::CursorType::CURSOR_TYPE_NORMAL; [[maybe_unused]] const auto nonPreferredController = mInputStateFrame.mPreferredHand == InputStateFrame::LEFT_CONTROLLER @@ -660,10 +663,15 @@ private: // unless neither controller is available. assert(mInputStateFrame.mIsHandActive[mInputStateFrame.mPreferredHand] || !mInputStateFrame.mIsHandActive[nonPreferredController]); - { const bool isPreferredControllerActive = mInputStateFrame.mIsHandActive[mInputStateFrame.mPreferredHand]; + + static bool sIsLowerPanelBeingPositioned = false; + + sIsLowerPanelBeingPositioned &= + appState.mLowerMenuType == LowerMenuType::POSITIONAL_MENU && + isPreferredControllerActive; if (isPreferredControllerActive) { const XrPosef pose = mInputStateFrame.mHandPositions[mInputStateFrame.mPreferredHand].pose; @@ -677,6 +685,8 @@ private: mInputStateFrame.mHandPositions[mInputStateFrame.mPreferredHand].pose, XrVector3f{0, 0, -3.5f}); + sIsLowerPanelBeingPositioned &= triggerState.currentState > 0; + // Hit-test panels in order of priority (and known depth) if (appState.mShouldShowErrorMessage) { @@ -696,6 +706,7 @@ private: } // No dialogs/popups that should impede normal cursor interaction with // applicable panels + if (!shouldRenderCursor && appState.ShouldShowLowerPanel()) { shouldRenderCursor = mGameSurfaceLayer->GetRayIntersectionWithPanel( start, end, cursorPos2d, cursorPose3d); @@ -713,13 +724,14 @@ private: cursorPos2d.x, cursorPos2d.y, 2); } } + if (!shouldRenderCursor) { shouldRenderCursor = mRibbonLayer->GetRayIntersectionWithPanel( start, end, cursorPos2d, cursorPose3d); if (shouldRenderCursor && triggerState.changedSinceLastSync) { mRibbonLayer->SendClickToUI(cursorPos2d, triggerState.currentState); } - if (shouldRenderCursor && + if ((shouldRenderCursor || sIsLowerPanelBeingPositioned) && appState.mLowerMenuType == LowerMenuType::POSITIONAL_MENU && triggerState.currentState) { @@ -730,28 +742,15 @@ private: mInputStateFrame.mThumbStickState[mInputStateFrame.mPreferredHand]; if (std::abs(thumbstickState.currentState.y) > kThumbStickDirectionThreshold) { - const XrPosef lowerPanelPose = mGameSurfaceLayer->SetLowerPanelFromThumbstick( - thumbstickState.currentState.y); + const XrPosef lowerPanelPose = + mGameSurfaceLayer->SetLowerPanelFromThumbstick( + thumbstickState.currentState.y); mRibbonLayer->SetPanelWithPose(lowerPanelPose); + sIsLowerPanelBeingPositioned = true; } } } - - if (!shouldRenderCursor) { - // Handling this here means L2/R2 are liable to - // be slightly out of sync with the other - // buttons (which are handled before - // WaitFrame()). We'll see if that ends up being - // a problem for any games. - ForwardButtonStateIfNeeded( - jni, mActivityObject, mForwardVRInputMethodID, 104 /* BUTTON_L2 */, - mInputStateFrame.mIndexTriggerState[InputStateFrame::LEFT_CONTROLLER], - "l2"); - ForwardButtonStateIfNeeded( - jni, mActivityObject, mForwardVRInputMethodID, 105 /* BUTTON_R2 */, - mInputStateFrame.mIndexTriggerState[InputStateFrame::RIGHT_CONTROLLER], - "r2"); - } + if (sIsLowerPanelBeingPositioned) { shouldRenderCursor = true; } // Hit test the top panel if positional menu is active. if (!shouldRenderCursor && @@ -779,6 +778,22 @@ private: } } + if (!shouldRenderCursor) { + // Handling this here means L2/R2 are liable to + // be slightly out of sync with the other + // buttons (which are handled before + // WaitFrame()). We'll see if that ends up being + // a problem for any games. + ForwardButtonStateIfNeeded( + jni, mActivityObject, mForwardVRInputMethodID, 104 /* BUTTON_L2 */, + mInputStateFrame.mIndexTriggerState[InputStateFrame::LEFT_CONTROLLER], + "l2"); + ForwardButtonStateIfNeeded( + jni, mActivityObject, mForwardVRInputMethodID, 105 /* BUTTON_R2 */, + mInputStateFrame.mIndexTriggerState[InputStateFrame::RIGHT_CONTROLLER], + "r2"); + } + // Add a scale factor so the cursor doesn't scale as // quickly as the panel(s) with distance. This may be // mildly unsettling, but it helps to ensure the cursor