mirror of
https://github.com/amwatson/CitraVR.git
synced 2024-09-19 19:01:38 +02:00
Hacky setup for adjusting position of upper and lower panels from menu (partial, toggle doesn't work)
This commit is contained in:
parent
e9eb4a30fd
commit
9f57f8530e
6 changed files with 159 additions and 105 deletions
|
@ -436,6 +436,30 @@ void GameSurfaceLayer::SetTopPanelFromController(const XrVector3f& controllerPos
|
|||
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) {
|
||||
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
|
||||
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
|
||||
int32_t GameSurfaceLayer::Init(const XrSession& session, const jobject activityObject) {
|
||||
if (mImmersiveMode > 0) {
|
||||
|
|
|
@ -158,18 +158,19 @@ public:
|
|||
*
|
||||
* Note: assumes viewer is looking down the -Z axis.
|
||||
*/
|
||||
bool GetRayIntersectionWithPanel(const XrVector3f& start,
|
||||
const XrVector3f& end,
|
||||
XrVector2f& result2d,
|
||||
XrPosef& result3d) const;
|
||||
bool GetRayIntersectionWithPanelTopPanel(const XrVector3f& start,
|
||||
const XrVector3f& end,
|
||||
XrVector2f& result2d,
|
||||
XrPosef& result3d) const;
|
||||
void SetTopPanelFromController(const XrVector3f& controllerPosition);
|
||||
XrPosef GetTopPanelFromHeadPose(uint32_t eye, const XrPosef& headPose);
|
||||
|
||||
bool GetRayIntersectionWithPanel(const XrVector3f& start,
|
||||
const XrVector3f& end,
|
||||
XrVector2f& result2d,
|
||||
XrPosef& result3d) const;
|
||||
bool GetRayIntersectionWithPanelTopPanel(const XrVector3f& start,
|
||||
const XrVector3f& end,
|
||||
XrVector2f& result2d,
|
||||
XrPosef& result3d) const;
|
||||
void SetTopPanelFromController(const XrVector3f& controllerPosition);
|
||||
void SetTopPanelFromThumbstick(const float thumbstickY);
|
||||
XrPosef SetLowerPanelFromThumbstick(const float thumbstickY);
|
||||
|
||||
XrPosef GetTopPanelFromHeadPose(uint32_t eye, const XrPosef& headPose);
|
||||
|
||||
private:
|
||||
int Init(const XrSession& session, const jobject activityObject);
|
||||
|
|
|
@ -325,3 +325,5 @@ int UILayer::CreateSwapchain() {
|
|||
void UILayer::SendClickToUI(const XrVector2f& pos2d, const int type) {
|
||||
mEnv->CallIntMethod(mVrUILayerObject, mSendClickToUIMethodID, pos2d.x, pos2d.y, type);
|
||||
}
|
||||
|
||||
void UILayer::SetPanelWithPose(const XrPosef& pose) { mPanelFromWorld = pose; }
|
||||
|
|
|
@ -123,6 +123,8 @@ public:
|
|||
*/
|
||||
void SendClickToUI(const XrVector2f& pos2d, const int type);
|
||||
|
||||
void SetPanelWithPose(const XrPosef& pose);
|
||||
|
||||
private:
|
||||
int Init(const std::string& className, const jobject activityObject, const XrVector3f& position,
|
||||
const XrSession& session);
|
||||
|
|
|
@ -650,7 +650,7 @@ private:
|
|||
XrPosef cursorPose3d = XrMath::Posef::Identity();
|
||||
XrVector2f cursorPos2d = {0, 0};
|
||||
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 =
|
||||
mInputStateFrame.mPreferredHand == InputStateFrame::LEFT_CONTROLLER
|
||||
|
@ -685,86 +685,100 @@ private:
|
|||
if (triggerState.changedSinceLastSync) {
|
||||
mErrorMessageLayer->SendClickToUI(cursorPos2d, triggerState.currentState);
|
||||
}
|
||||
} else { // Don't test for cursor intersection if error message is shown
|
||||
if (appState.mIsKeyboardActive) {
|
||||
shouldRenderCursor = mKeyboardLayer->GetRayIntersectionWithPanel(
|
||||
start, end, cursorPos2d, cursorPose3d);
|
||||
if (triggerState.changedSinceLastSync) {
|
||||
mKeyboardLayer->SendClickToUI(cursorPos2d, triggerState.currentState);
|
||||
}
|
||||
} else {
|
||||
// No dialogs/popups that should impede normal cursor interaction with
|
||||
// applicable panels
|
||||
shouldRenderCursor = mGameSurfaceLayer->GetRayIntersectionWithPanel(
|
||||
start, end, cursorPos2d, cursorPose3d);
|
||||
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);
|
||||
}
|
||||
if (!shouldRenderCursor) {
|
||||
shouldRenderCursor = mRibbonLayer->GetRayIntersectionWithPanel(
|
||||
start, end, cursorPos2d, cursorPose3d);
|
||||
if (triggerState.changedSinceLastSync) {
|
||||
mRibbonLayer->SendClickToUI(cursorPos2d, triggerState.currentState);
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
// Don't test for cursor intersection if error message is shown
|
||||
if (!shouldRenderCursor && appState.mIsKeyboardActive) {
|
||||
shouldRenderCursor = mKeyboardLayer->GetRayIntersectionWithPanel(
|
||||
start, end, cursorPos2d, cursorPose3d);
|
||||
if (triggerState.changedSinceLastSync) {
|
||||
mKeyboardLayer->SendClickToUI(cursorPos2d, triggerState.currentState);
|
||||
}
|
||||
}
|
||||
// No dialogs/popups that should impede normal cursor interaction with
|
||||
// applicable panels
|
||||
if (!shouldRenderCursor && appState.ShouldShowLowerPanel()) {
|
||||
shouldRenderCursor = mGameSurfaceLayer->GetRayIntersectionWithPanel(
|
||||
start, end, cursorPos2d, cursorPose3d);
|
||||
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) {
|
||||
|
||||
// Hit test the top panel
|
||||
if (!shouldRenderCursor) {
|
||||
shouldRenderCursor = mGameSurfaceLayer->GetRayIntersectionWithPanelTopPanel(
|
||||
start, end, cursorPos2d, cursorPose3d);
|
||||
// If top panel is hit, trigger controls the
|
||||
// position/rotation
|
||||
if (shouldRenderCursor && triggerState.currentState) {
|
||||
// null out X component -- screen should stay
|
||||
// center
|
||||
mGameSurfaceLayer->SetTopPanelFromController(
|
||||
XrVector3f{0, cursorPose3d.position.y, cursorPose3d.position.z});
|
||||
// If trigger is pressed, thumbstick controls
|
||||
// the depth
|
||||
const XrActionStateVector2f& thumbstickState =
|
||||
mInputStateFrame.mThumbStickState[mInputStateFrame.mPreferredHand];
|
||||
jni->CallVoidMethod(mActivityObject, mSendClickToWindowMethodID,
|
||||
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 &&
|
||||
appState.mLowerMenuType == LowerMenuType::POSITIONAL_MENU &&
|
||||
triggerState.currentState) {
|
||||
|
||||
static constexpr float kThumbStickDirectionThreshold = 0.5f;
|
||||
if (std::abs(thumbstickState.currentState.y) >
|
||||
kThumbStickDirectionThreshold) {
|
||||
mGameSurfaceLayer->SetTopPanelFromThumbstick(
|
||||
thumbstickState.currentState.y);
|
||||
}
|
||||
}
|
||||
if (shouldRenderCursor) {
|
||||
cursorType = CursorLayer::CursorType::CURSOR_TYPE_TOP_PANEL;
|
||||
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) {
|
||||
// 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");
|
||||
}
|
||||
|
||||
// Hit test the top panel if positional menu is active.
|
||||
if (!shouldRenderCursor &&
|
||||
appState.mLowerMenuType == LowerMenuType::POSITIONAL_MENU) {
|
||||
shouldRenderCursor = mGameSurfaceLayer->GetRayIntersectionWithPanelTopPanel(
|
||||
start, end, cursorPos2d, cursorPose3d);
|
||||
// If top panel is hit, trigger controls the
|
||||
// position/rotation
|
||||
if (shouldRenderCursor && triggerState.currentState) {
|
||||
// null out X component -- screen should stay
|
||||
// center
|
||||
mGameSurfaceLayer->SetTopPanelFromController(
|
||||
XrVector3f{0, cursorPose3d.position.y, cursorPose3d.position.z});
|
||||
// If trigger is pressed, thumbstick controls
|
||||
// the depth
|
||||
const XrActionStateVector2f& thumbstickState =
|
||||
mInputStateFrame.mThumbStickState[mInputStateFrame.mPreferredHand];
|
||||
|
||||
static constexpr float kThumbStickDirectionThreshold = 0.5f;
|
||||
if (std::abs(thumbstickState.currentState.y) >
|
||||
kThumbStickDirectionThreshold) {
|
||||
mGameSurfaceLayer->SetTopPanelFromThumbstick(
|
||||
thumbstickState.currentState.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
|
@ -1065,9 +1079,7 @@ private:
|
|||
|
||||
class AppState {
|
||||
public:
|
||||
bool ShouldShowLowerPanel() const {
|
||||
return mLowerMenuType == LowerMenuType::MAIN_MENU;
|
||||
}
|
||||
bool ShouldShowLowerPanel() const { return mLowerMenuType == LowerMenuType::MAIN_MENU; }
|
||||
|
||||
LowerMenuType mLowerMenuType = LowerMenuType::MAIN_MENU;
|
||||
|
||||
|
|
|
@ -2,15 +2,39 @@
|
|||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/position_panel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
android:gravity="center"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<FrameLayout
|
||||
<LinearLayout
|
||||
android:id="@+id/linearLayout"
|
||||
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" />
|
||||
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_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
Loading…
Reference in a new issue