diff --git a/src/android/app/src/main/jni/vr/layers/CursorLayer.h b/src/android/app/src/main/jni/vr/layers/CursorLayer.h index 2f48b3655..b8d75e985 100644 --- a/src/android/app/src/main/jni/vr/layers/CursorLayer.h +++ b/src/android/app/src/main/jni/vr/layers/CursorLayer.h @@ -37,7 +37,7 @@ public: /** The type of cursor to render. * Determines the color of the cursor. **/ - enum class CursorType { CURSOR_TYPE_NORMAL, CURSOR_TYPE_TOP_PANEL, NUM_CURSOR_TYPES }; + enum class CursorType { CURSOR_TYPE_NORMAL, CURSOR_TYPE_POSITIONAL_MENU, NUM_CURSOR_TYPES }; /** * @param session a valid XR Session */ 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 ae0aa3aff..719477cfe 100644 --- a/src/android/app/src/main/jni/vr/layers/GameSurfaceLayer.cpp +++ b/src/android/app/src/main/jni/vr/layers/GameSurfaceLayer.cpp @@ -31,7 +31,6 @@ License : Licensed under GPLv3 or any later version. namespace { constexpr float kSuperImmersiveRadius = 0.5f; -constexpr float kDistanceBetweenPanelsInMeters = 0.75f; constexpr float kInitialLowerPanelPitchInRadians = -MATH_FLOAT_PI / 4.0f; // -45 degrees in radians //----------------------------------------------------------------------------- @@ -485,7 +484,7 @@ void GameSurfaceLayer::SetLowerPanelFromController(const XrVector3f& controllerP // Construct a quaternion for the pitch adjustment const XrQuaternionf pitchAdjustmentQuat = - XrMath::FromAxisAngle({1.0f, 0.0f, 0.0f}, newPitchRadians / 2.0f); + XrMath::Quatf::FromAxisAngle({1.0f, 0.0f, 0.0f}, newPitchRadians / 2.0f); // Combine the base rotation with the pitch adjustment mLowerPanel.mPanelFromWorld = {baseRotation * pitchAdjustmentQuat, windowPosition}; @@ -503,19 +502,6 @@ void GameSurfaceLayer::SetTopPanelFromThumbstick(const float thumbstickY) { std::max(mTopPanel.mPanelFromWorld.position.z, kMaxDepth); } -XrPosef GameSurfaceLayer::SetLowerPanelFromThumbstick(const float thumbstickY) { - static constexpr float kMinY = -3.0f; - - mLowerPanel.mPanelFromWorld.position.y += (thumbstickY * kThumbstickSpeed); - mLowerPanel.mPanelFromWorld.position.y = - std::min(mLowerPanel.mPanelFromWorld.position.y, - mTopPanel.mPanelFromWorld.position.y - kDistanceBetweenPanelsInMeters); - mLowerPanel.mPanelFromWorld.position.y = - std::max(mLowerPanel.mPanelFromWorld.position.y, kMinY); - - return mLowerPanel.mPanelFromWorld; -} - XrPosef GameSurfaceLayer::GetTopPanelFromHeadPose(uint32_t eye, const XrPosef& headPose) { XrVector3f panelPosition = headPose.position; 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 e6d0b970a..c177a3b2c 100644 --- a/src/android/app/src/main/jni/vr/vr_main.cpp +++ b/src/android/app/src/main/jni/vr/vr_main.cpp @@ -98,6 +98,22 @@ void ForwardButtonStateIfNeeded(JNIEnv* jni, jobject activityObject, } } +void SendTriggerStateToWindow(JNIEnv* jni, jobject activityObject, + jmethodID sendClickToWindowMethodID, + const XrActionStateBoolean& triggerState, + const XrVector2f& cursorPos2d) { + if (triggerState.currentState == 0 && triggerState.changedSinceLastSync) { + jni->CallVoidMethod(activityObject, sendClickToWindowMethodID, cursorPos2d.x, cursorPos2d.y, + 0); + } else if (triggerState.changedSinceLastSync && triggerState.currentState == 1) { + jni->CallVoidMethod(activityObject, sendClickToWindowMethodID, cursorPos2d.x, cursorPos2d.y, + 1); + } else if (triggerState.currentState == 1 && !triggerState.changedSinceLastSync) { + jni->CallVoidMethod(activityObject, sendClickToWindowMethodID, cursorPos2d.x, cursorPos2d.y, + 2); + } +} + [[maybe_unused]] const char* XrSessionStateToString(const XrSessionState state) { switch (state) { case XR_SESSION_STATE_UNKNOWN: @@ -652,7 +668,7 @@ private: float scaleFactor = 0.01f; CursorLayer::CursorType cursorType = appState.mLowerMenuType == LowerMenuType::POSITIONAL_MENU - ? CursorLayer::CursorType::CURSOR_TYPE_TOP_PANEL + ? CursorLayer::CursorType::CURSOR_TYPE_POSITIONAL_MENU : CursorLayer::CursorType::CURSOR_TYPE_NORMAL; [[maybe_unused]] const auto nonPreferredController = @@ -690,6 +706,7 @@ private: // Hit-test panels in order of priority (and known depth) + // 1. Error message layer if (appState.mShouldShowErrorMessage) { shouldRenderCursor = mErrorMessageLayer->GetRayIntersectionWithPanel( start, end, cursorPos2d, cursorPose3d); @@ -697,7 +714,8 @@ private: mErrorMessageLayer->SendClickToUI(cursorPos2d, triggerState.currentState); } } - // Don't test for cursor intersection if error message is shown + + // 2. Keyboard layer if (!shouldRenderCursor && appState.mIsKeyboardActive) { shouldRenderCursor = mKeyboardLayer->GetRayIntersectionWithPanel( start, end, cursorPos2d, cursorPose3d); @@ -715,6 +733,7 @@ private: mRibbonLayer->SetPanelWithPose(mGameSurfaceLayer->GetLowerPanelPose()); } + // 3. Lower panel if (!shouldRenderCursor) { shouldRenderCursor = mGameSurfaceLayer->GetRayIntersectionWithPanel( start, end, cursorPos2d, cursorPose3d); @@ -726,50 +745,21 @@ private: sIsLowerPanelBeingPositioned = true; } else if (appState.mLowerMenuType == LowerMenuType::MAIN_MENU) { - if (triggerState.currentState == 0 && triggerState.changedSinceLastSync) { - jni->CallVoidMethod(mActivityObject, mSendClickToWindowMethodID, - cursorPos2d.x, cursorPos2d.y, 0); - } else if (triggerState.changedSinceLastSync && - triggerState.currentState == 1) { - jni->CallVoidMethod(mActivityObject, mSendClickToWindowMethodID, - cursorPos2d.x, cursorPos2d.y, 1); - } else if (triggerState.currentState == 1 && - !triggerState.changedSinceLastSync) { - - jni->CallVoidMethod(mActivityObject, mSendClickToWindowMethodID, - cursorPos2d.x, cursorPos2d.y, 2); - } + SendTriggerStateToWindow(jni, mActivityObject, mSendClickToWindowMethodID, + triggerState, cursorPos2d); } } + // 4. Ribbon layer if (!shouldRenderCursor) { shouldRenderCursor = mRibbonLayer->GetRayIntersectionWithPanel( start, end, cursorPos2d, cursorPose3d); if (shouldRenderCursor && triggerState.changedSinceLastSync) { mRibbonLayer->SendClickToUI(cursorPos2d, triggerState.currentState); } - if ((shouldRenderCursor || sIsLowerPanelBeingPositioned) && - appState.mLowerMenuType == LowerMenuType::POSITIONAL_MENU && - triggerState.currentState) { - - static constexpr float kThumbStickDirectionThreshold = 0.5f; - // If trigger is pressed, thumbstick controls - // the depth - const XrActionStateVector2f& thumbstickState = - mInputStateFrame.mThumbStickState[mInputStateFrame.mPreferredHand]; - - if (std::abs(thumbstickState.currentState.y) > - kThumbStickDirectionThreshold) { - const XrPosef lowerPanelPose = - mGameSurfaceLayer->SetLowerPanelFromThumbstick( - thumbstickState.currentState.y); - mRibbonLayer->SetPanelWithPose(lowerPanelPose); - } - } } - if (sIsLowerPanelBeingPositioned) { shouldRenderCursor = true; } - // Hit test the top panel if positional menu is active. + // 5. Hit test the top panel if positional menu is active. if (!shouldRenderCursor && appState.mLowerMenuType == LowerMenuType::POSITIONAL_MENU) { shouldRenderCursor = mGameSurfaceLayer->GetRayIntersectionWithPanelTopPanel( @@ -822,6 +812,7 @@ private: scaleFactor = 0.01f + 0.003f * distance; } } + if (sIsLowerPanelBeingPositioned) { shouldRenderCursor = true; } } if (shouldRenderCursor) { diff --git a/src/android/app/src/main/res/layout/vr_ribbon.xml b/src/android/app/src/main/res/layout/vr_ribbon.xml index f53f788c9..8f71064b9 100644 --- a/src/android/app/src/main/res/layout/vr_ribbon.xml +++ b/src/android/app/src/main/res/layout/vr_ribbon.xml @@ -72,7 +72,7 @@ android:layout_weight="1" android:minHeight="0dp" android:padding="0dp" - android:paddingVertical="12dp" + android:paddingVertical="20dp" android:text="<" />