Hacky setup for adjusting position of upper and lower panels from menu (partial, toggle doesn't work)

This commit is contained in:
amwatson 2024-03-20 23:05:50 -05:00
parent e9eb4a30fd
commit 9f57f8530e
6 changed files with 159 additions and 105 deletions

View file

@ -436,6 +436,30 @@ void GameSurfaceLayer::SetTopPanelFromController(const XrVector3f& controllerPos
mTopPanel.mPanelFromWorld = XrPosef{windowRotation, windowPosition}; mTopPanel.mPanelFromWorld = XrPosef{windowRotation, windowPosition};
} }
void GameSurfaceLayer::SetTopPanelFromThumbstick(const float thumbstickY) {
static constexpr float kDepthSpeed = 0.05f;
static constexpr float kMaxDepth = -10.0f;
mTopPanel.mPanelFromWorld.position.z -= (thumbstickY * kDepthSpeed);
mTopPanel.mPanelFromWorld.position.z =
std::min(mTopPanel.mPanelFromWorld.position.z, mLowerPanel.mPanelFromWorld.position.z);
mTopPanel.mPanelFromWorld.position.z =
std::max(mTopPanel.mPanelFromWorld.position.z, kMaxDepth);
}
XrPosef GameSurfaceLayer::SetLowerPanelFromThumbstick(const float thumbstickY) {
static constexpr float kDepthSpeed = 0.05f;
static constexpr float kMaxDepth = -10.0f;
mLowerPanel.mPanelFromWorld.position.y += (thumbstickY * kDepthSpeed);
mLowerPanel.mPanelFromWorld.position.y =
std::min(mLowerPanel.mPanelFromWorld.position.y, mTopPanel.mPanelFromWorld.position.y);
mLowerPanel.mPanelFromWorld.position.y =
std::max(mLowerPanel.mPanelFromWorld.position.y, kMaxDepth);
return mLowerPanel.mPanelFromWorld;
}
XrPosef GameSurfaceLayer::GetTopPanelFromHeadPose(uint32_t eye, const XrPosef& headPose) { XrPosef GameSurfaceLayer::GetTopPanelFromHeadPose(uint32_t eye, const XrPosef& headPose) {
XrVector3f panelPosition = headPose.position; XrVector3f panelPosition = headPose.position;
@ -460,17 +484,6 @@ XrPosef GameSurfaceLayer::GetTopPanelFromHeadPose(uint32_t eye, const XrPosef& h
} }
// based on thumbstick, modify the depth of the top panel // based on thumbstick, modify the depth of the top panel
void GameSurfaceLayer::SetTopPanelFromThumbstick(const float thumbstickY) {
static constexpr float kDepthSpeed = 0.05f;
static constexpr float kMaxDepth = -10.0f;
mTopPanel.mPanelFromWorld.position.z -= (thumbstickY * kDepthSpeed);
mTopPanel.mPanelFromWorld.position.z =
std::min(mTopPanel.mPanelFromWorld.position.z, mLowerPanel.mPanelFromWorld.position.z);
mTopPanel.mPanelFromWorld.position.z =
std::max(mTopPanel.mPanelFromWorld.position.z, kMaxDepth);
}
// Next error code: -2 // Next error code: -2
int32_t GameSurfaceLayer::Init(const XrSession& session, const jobject activityObject) { int32_t GameSurfaceLayer::Init(const XrSession& session, const jobject activityObject) {
if (mImmersiveMode > 0) { if (mImmersiveMode > 0) {

View file

@ -167,9 +167,10 @@ public:
XrVector2f& result2d, XrVector2f& result2d,
XrPosef& result3d) const; XrPosef& result3d) const;
void SetTopPanelFromController(const XrVector3f& controllerPosition); void SetTopPanelFromController(const XrVector3f& controllerPosition);
XrPosef GetTopPanelFromHeadPose(uint32_t eye, const XrPosef& headPose);
void SetTopPanelFromThumbstick(const float thumbstickY); void SetTopPanelFromThumbstick(const float thumbstickY);
XrPosef SetLowerPanelFromThumbstick(const float thumbstickY);
XrPosef GetTopPanelFromHeadPose(uint32_t eye, const XrPosef& headPose);
private: private:
int Init(const XrSession& session, const jobject activityObject); int Init(const XrSession& session, const jobject activityObject);

View file

@ -325,3 +325,5 @@ int UILayer::CreateSwapchain() {
void UILayer::SendClickToUI(const XrVector2f& pos2d, const int type) { void UILayer::SendClickToUI(const XrVector2f& pos2d, const int type) {
mEnv->CallIntMethod(mVrUILayerObject, mSendClickToUIMethodID, pos2d.x, pos2d.y, type); mEnv->CallIntMethod(mVrUILayerObject, mSendClickToUIMethodID, pos2d.x, pos2d.y, type);
} }
void UILayer::SetPanelWithPose(const XrPosef& pose) { mPanelFromWorld = pose; }

View file

@ -123,6 +123,8 @@ public:
*/ */
void SendClickToUI(const XrVector2f& pos2d, const int type); void SendClickToUI(const XrVector2f& pos2d, const int type);
void SetPanelWithPose(const XrPosef& pose);
private: private:
int Init(const std::string& className, const jobject activityObject, const XrVector3f& position, int Init(const std::string& className, const jobject activityObject, const XrVector3f& position,
const XrSession& session); const XrSession& session);

View file

@ -650,7 +650,7 @@ private:
XrPosef cursorPose3d = XrMath::Posef::Identity(); XrPosef cursorPose3d = XrMath::Posef::Identity();
XrVector2f cursorPos2d = {0, 0}; XrVector2f cursorPos2d = {0, 0};
float scaleFactor = 0.01f; float scaleFactor = 0.01f;
CursorLayer::CursorType cursorType = 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 = [[maybe_unused]] const auto nonPreferredController =
mInputStateFrame.mPreferredHand == InputStateFrame::LEFT_CONTROLLER mInputStateFrame.mPreferredHand == InputStateFrame::LEFT_CONTROLLER
@ -685,16 +685,18 @@ private:
if (triggerState.changedSinceLastSync) { if (triggerState.changedSinceLastSync) {
mErrorMessageLayer->SendClickToUI(cursorPos2d, triggerState.currentState); mErrorMessageLayer->SendClickToUI(cursorPos2d, triggerState.currentState);
} }
} else { // Don't test for cursor intersection if error message is shown }
if (appState.mIsKeyboardActive) { // Don't test for cursor intersection if error message is shown
if (!shouldRenderCursor && appState.mIsKeyboardActive) {
shouldRenderCursor = mKeyboardLayer->GetRayIntersectionWithPanel( shouldRenderCursor = mKeyboardLayer->GetRayIntersectionWithPanel(
start, end, cursorPos2d, cursorPose3d); start, end, cursorPos2d, cursorPose3d);
if (triggerState.changedSinceLastSync) { if (triggerState.changedSinceLastSync) {
mKeyboardLayer->SendClickToUI(cursorPos2d, triggerState.currentState); mKeyboardLayer->SendClickToUI(cursorPos2d, triggerState.currentState);
} }
} else { }
// No dialogs/popups that should impede normal cursor interaction with // No dialogs/popups that should impede normal cursor interaction with
// applicable panels // applicable panels
if (!shouldRenderCursor && appState.ShouldShowLowerPanel()) {
shouldRenderCursor = mGameSurfaceLayer->GetRayIntersectionWithPanel( shouldRenderCursor = mGameSurfaceLayer->GetRayIntersectionWithPanel(
start, end, cursorPos2d, cursorPose3d); start, end, cursorPos2d, cursorPose3d);
if (triggerState.currentState == 0 && triggerState.changedSinceLastSync) { if (triggerState.currentState == 0 && triggerState.changedSinceLastSync) {
@ -710,12 +712,29 @@ private:
jni->CallVoidMethod(mActivityObject, mSendClickToWindowMethodID, jni->CallVoidMethod(mActivityObject, mSendClickToWindowMethodID,
cursorPos2d.x, cursorPos2d.y, 2); cursorPos2d.x, cursorPos2d.y, 2);
} }
}
if (!shouldRenderCursor) { if (!shouldRenderCursor) {
shouldRenderCursor = mRibbonLayer->GetRayIntersectionWithPanel( shouldRenderCursor = mRibbonLayer->GetRayIntersectionWithPanel(
start, end, cursorPos2d, cursorPose3d); start, end, cursorPos2d, cursorPose3d);
if (triggerState.changedSinceLastSync) { if (shouldRenderCursor && triggerState.changedSinceLastSync) {
mRibbonLayer->SendClickToUI(cursorPos2d, triggerState.currentState); mRibbonLayer->SendClickToUI(cursorPos2d, triggerState.currentState);
} }
if (shouldRenderCursor &&
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 (!shouldRenderCursor) { if (!shouldRenderCursor) {
@ -726,19 +745,17 @@ private:
// a problem for any games. // a problem for any games.
ForwardButtonStateIfNeeded( ForwardButtonStateIfNeeded(
jni, mActivityObject, mForwardVRInputMethodID, 104 /* BUTTON_L2 */, jni, mActivityObject, mForwardVRInputMethodID, 104 /* BUTTON_L2 */,
mInputStateFrame mInputStateFrame.mIndexTriggerState[InputStateFrame::LEFT_CONTROLLER],
.mIndexTriggerState[InputStateFrame::LEFT_CONTROLLER],
"l2"); "l2");
ForwardButtonStateIfNeeded( ForwardButtonStateIfNeeded(
jni, mActivityObject, mForwardVRInputMethodID, 105 /* BUTTON_R2 */, jni, mActivityObject, mForwardVRInputMethodID, 105 /* BUTTON_R2 */,
mInputStateFrame mInputStateFrame.mIndexTriggerState[InputStateFrame::RIGHT_CONTROLLER],
.mIndexTriggerState[InputStateFrame::RIGHT_CONTROLLER],
"r2"); "r2");
} }
}
// Hit test the top panel // Hit test the top panel if positional menu is active.
if (!shouldRenderCursor) { if (!shouldRenderCursor &&
appState.mLowerMenuType == LowerMenuType::POSITIONAL_MENU) {
shouldRenderCursor = mGameSurfaceLayer->GetRayIntersectionWithPanelTopPanel( shouldRenderCursor = mGameSurfaceLayer->GetRayIntersectionWithPanelTopPanel(
start, end, cursorPos2d, cursorPose3d); start, end, cursorPos2d, cursorPose3d);
// If top panel is hit, trigger controls the // If top panel is hit, trigger controls the
@ -760,11 +777,8 @@ private:
thumbstickState.currentState.y); thumbstickState.currentState.y);
} }
} }
if (shouldRenderCursor) {
cursorType = CursorLayer::CursorType::CURSOR_TYPE_TOP_PANEL;
}
}
} }
// Add a scale factor so the cursor doesn't scale as // Add a scale factor so the cursor doesn't scale as
// quickly as the panel(s) with distance. This may be // quickly as the panel(s) with distance. This may be
// mildly unsettling, but it helps to ensure the cursor // mildly unsettling, but it helps to ensure the cursor
@ -1065,9 +1079,7 @@ private:
class AppState { class AppState {
public: public:
bool ShouldShowLowerPanel() const { bool ShouldShowLowerPanel() const { return mLowerMenuType == LowerMenuType::MAIN_MENU; }
return mLowerMenuType == LowerMenuType::MAIN_MENU;
}
LowerMenuType mLowerMenuType = LowerMenuType::MAIN_MENU; LowerMenuType mLowerMenuType = LowerMenuType::MAIN_MENU;

View file

@ -2,15 +2,39 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/position_panel" android:id="@+id/position_panel"
android:layout_width="wrap_content" android:gravity="center"
android:layout_height="wrap_content"> android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout <LinearLayout
android:id="@+id/linearLayout"
android:layout_width="1000dp" android:layout_width="1000dp"
android:layout_height="0dp" android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textview.MaterialTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Press and hold trigger on panel to move it"
android:textAlignment="center"
android:textColor="@color/citra_onBackground" />
<androidx.appcompat.widget.AppCompatToggleButton
android:id="@+id/toggle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Lock Horizontal Axis"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>