diff --git a/Projects/Android/jni/src/Lambda1VR/L1VR_SurfaceView.c b/Projects/Android/jni/src/Lambda1VR/L1VR_SurfaceView.c index d1edee7..0573db9 100644 --- a/Projects/Android/jni/src/Lambda1VR/L1VR_SurfaceView.c +++ b/Projects/Android/jni/src/Lambda1VR/L1VR_SurfaceView.c @@ -346,6 +346,8 @@ convar_t *vr_highlight_actionables; convar_t *vr_headtorch; convar_t *vr_quick_crouchjump; convar_t *vr_stereo_side; +convar_t *vr_gesture_triggered_use; +convar_t *vr_use_gesture_boundary; void initialize_gl4es(); @@ -400,6 +402,8 @@ void VR_Init() vr_highlight_actionables = Cvar_Get( "vr_highlight_actionables", "1", CVAR_ARCHIVE, "Set to 0 to disable highlighting of actionable objects/entities" ); vr_headtorch = Cvar_Get( "vr_headtorch", "0", CVAR_ARCHIVE, "Set to 1 to enable head-torch flashlight mode" ); vr_quick_crouchjump = Cvar_Get( "vr_quick_crouchjump", "1", CVAR_ARCHIVE, "Set to 0 to disable quick crouch-jump mode (double clicking jump button triggers duck)" ); + vr_gesture_triggered_use = Cvar_Get( "vr_gesture_triggered_use", "0", CVAR_ARCHIVE, "Set to 0 to disable use gesture, 1 to enable" ); + vr_use_gesture_boundary = Cvar_Get( "vr_use_gesture_boundary", "0.35", CVAR_ARCHIVE, "Use gesture boundary" ); //Not to be changed by users, as it will be overwritten anyway vr_stereo_side = Cvar_Get( "vr_stereo_side", "0", CVAR_READ_ONLY, "Eye being drawn" ); diff --git a/Projects/Android/jni/src/Lambda1VR/VrCommon.h b/Projects/Android/jni/src/Lambda1VR/VrCommon.h index 2c84960..5a8b6ea 100644 --- a/Projects/Android/jni/src/Lambda1VR/VrCommon.h +++ b/Projects/Android/jni/src/Lambda1VR/VrCommon.h @@ -63,6 +63,7 @@ extern vec3_t flashlightoffset; extern int ducked; extern bool player_moving; +extern int use_gesture_state; bool isMultiplayer(); bool isScopeEngaged(); diff --git a/Projects/Android/jni/src/Lambda1VR/VrCvars.h b/Projects/Android/jni/src/Lambda1VR/VrCvars.h index 991d24a..1fdfcfc 100644 --- a/Projects/Android/jni/src/Lambda1VR/VrCvars.h +++ b/Projects/Android/jni/src/Lambda1VR/VrCvars.h @@ -27,6 +27,8 @@ extern convar_t *vr_controller_tracking_haptic; extern convar_t *vr_highlight_actionables; extern convar_t *vr_headtorch; extern convar_t *vr_quick_crouchjump; +extern convar_t *vr_gesture_triggered_use; +extern convar_t *vr_use_gesture_boundary; //Used and updated continuously during rendering extern convar_t *vr_stereo_side; \ No newline at end of file diff --git a/Projects/Android/jni/src/Lambda1VR/VrInputAlt.c b/Projects/Android/jni/src/Lambda1VR/VrInputAlt.c index fdd0e71..e955540 100644 --- a/Projects/Android/jni/src/Lambda1VR/VrInputAlt.c +++ b/Projects/Android/jni/src/Lambda1VR/VrInputAlt.c @@ -194,7 +194,50 @@ void HandleInput_Alt( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew, ovr weaponangles[MELEE][YAW] += (cl.refdef.cl_viewangles[YAW] - hmdorientation[YAW]); weaponangles[MELEE][PITCH] *= -1.0f; - //Use (Action) + // Use (Action gesture) + if (vr_gesture_triggered_use->integer) { + bool gestureUseAllowed = !vr_weapon_stabilised->value; + // Off-hand gesture + float xOffset = hmdPosition[0] - pOffTracking->HeadPose.Pose.Position.x; + float zOffset = hmdPosition[2] - pOffTracking->HeadPose.Pose.Position.z; + float distanceToBody = sqrtf((xOffset * xOffset) + (zOffset * zOffset)); + if (gestureUseAllowed && (distanceToBody > vr_use_gesture_boundary->value)) { + if (!(use_gesture_state & VR_USE_GESTURE_OFF_HAND)) { + sendButtonAction("+use2", true); + } + use_gesture_state |= VR_USE_GESTURE_OFF_HAND; + } else { + if (use_gesture_state & VR_USE_GESTURE_OFF_HAND) { + sendButtonAction("+use2", false); + } + use_gesture_state &= ~VR_USE_GESTURE_OFF_HAND; + } + // Weapon-hand gesture + xOffset = hmdPosition[0] - pDominantTracking->HeadPose.Pose.Position.x; + zOffset = hmdPosition[2] - pDominantTracking->HeadPose.Pose.Position.z; + distanceToBody = sqrtf((xOffset * xOffset) + (zOffset * zOffset)); + if (gestureUseAllowed && (distanceToBody > vr_use_gesture_boundary->value)) { + if (!(use_gesture_state & VR_USE_GESTURE_WEAPON_HAND)) { + sendButtonAction("+use", true); + } + use_gesture_state |= VR_USE_GESTURE_WEAPON_HAND; + } else { + if (use_gesture_state & VR_USE_GESTURE_WEAPON_HAND) { + sendButtonAction("+use", false); + } + use_gesture_state &= ~VR_USE_GESTURE_WEAPON_HAND; + } + } else { + if (use_gesture_state & VR_USE_GESTURE_OFF_HAND) { + sendButtonAction("+use2", false); + } + if (use_gesture_state & VR_USE_GESTURE_WEAPON_HAND) { + sendButtonAction("+use", false); + } + use_gesture_state = 0; + } + + // Use (Action button) if ((pDominantTrackedRemoteNew->Buttons & xrButton_Joystick) != (pDominantTrackedRemoteOld->Buttons & xrButton_Joystick)) { diff --git a/Projects/Android/jni/src/Lambda1VR/VrInputAlt2.c b/Projects/Android/jni/src/Lambda1VR/VrInputAlt2.c index 3f6fc36..8bd5439 100644 --- a/Projects/Android/jni/src/Lambda1VR/VrInputAlt2.c +++ b/Projects/Android/jni/src/Lambda1VR/VrInputAlt2.c @@ -206,7 +206,50 @@ void HandleInput_Alt2( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew, ov weaponangles[MELEE][YAW] += (cl.refdef.cl_viewangles[YAW] - hmdorientation[YAW]); weaponangles[MELEE][PITCH] *= -1.0f; - //Use (Action) + // Use (Action gesture) + if (vr_gesture_triggered_use->integer) { + bool gestureUseAllowed = !vr_weapon_stabilised->value; + // Off-hand gesture + float xOffset = hmdPosition[0] - pOffTracking->HeadPose.Pose.Position.x; + float zOffset = hmdPosition[2] - pOffTracking->HeadPose.Pose.Position.z; + float distanceToBody = sqrtf((xOffset * xOffset) + (zOffset * zOffset)); + if (gestureUseAllowed && (distanceToBody > vr_use_gesture_boundary->value)) { + if (!(use_gesture_state & VR_USE_GESTURE_OFF_HAND)) { + sendButtonAction("+use2", true); + } + use_gesture_state |= VR_USE_GESTURE_OFF_HAND; + } else { + if (use_gesture_state & VR_USE_GESTURE_OFF_HAND) { + sendButtonAction("+use2", false); + } + use_gesture_state &= ~VR_USE_GESTURE_OFF_HAND; + } + // Weapon-hand gesture + xOffset = hmdPosition[0] - pDominantTracking->HeadPose.Pose.Position.x; + zOffset = hmdPosition[2] - pDominantTracking->HeadPose.Pose.Position.z; + distanceToBody = sqrtf((xOffset * xOffset) + (zOffset * zOffset)); + if (gestureUseAllowed && (distanceToBody > vr_use_gesture_boundary->value)) { + if (!(use_gesture_state & VR_USE_GESTURE_WEAPON_HAND)) { + sendButtonAction("+use", true); + } + use_gesture_state |= VR_USE_GESTURE_WEAPON_HAND; + } else { + if (use_gesture_state & VR_USE_GESTURE_WEAPON_HAND) { + sendButtonAction("+use", false); + } + use_gesture_state &= ~VR_USE_GESTURE_WEAPON_HAND; + } + } else { + if (use_gesture_state & VR_USE_GESTURE_OFF_HAND) { + sendButtonAction("+use2", false); + } + if (use_gesture_state & VR_USE_GESTURE_WEAPON_HAND) { + sendButtonAction("+use", false); + } + use_gesture_state = 0; + } + + // Use (Action button) if ((pDominantTrackedRemoteNew->Buttons & xrButton_Joystick) != (pDominantTrackedRemoteOld->Buttons & xrButton_Joystick)) { diff --git a/Projects/Android/jni/src/Lambda1VR/VrInputCommon.c b/Projects/Android/jni/src/Lambda1VR/VrInputCommon.c index 7e6f714..a34d6b3 100644 --- a/Projects/Android/jni/src/Lambda1VR/VrInputCommon.c +++ b/Projects/Android/jni/src/Lambda1VR/VrInputCommon.c @@ -42,6 +42,7 @@ vec3_t flashlightoffset; int ducked; bool player_moving; +int use_gesture_state; bool stabiliseScope; char * g_pszBackpackWeapon; diff --git a/Projects/Android/jni/src/Lambda1VR/VrInputDefault.c b/Projects/Android/jni/src/Lambda1VR/VrInputDefault.c index 8e54c14..37a2dce 100644 --- a/Projects/Android/jni/src/Lambda1VR/VrInputDefault.c +++ b/Projects/Android/jni/src/Lambda1VR/VrInputDefault.c @@ -207,7 +207,50 @@ void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew, weaponangles[MELEE][YAW] += (cl.refdef.cl_viewangles[YAW] - hmdorientation[YAW]); weaponangles[MELEE][PITCH] *= -1.0f; - //Use (Action) + // Use (Action gesture) + if (vr_gesture_triggered_use->integer) { + bool gestureUseAllowed = !vr_weapon_stabilised->value; + // Off-hand gesture + float xOffset = hmdPosition[0] - pOffTracking->HeadPose.Pose.Position.x; + float zOffset = hmdPosition[2] - pOffTracking->HeadPose.Pose.Position.z; + float distanceToBody = sqrtf((xOffset * xOffset) + (zOffset * zOffset)); + if (gestureUseAllowed && (distanceToBody > vr_use_gesture_boundary->value)) { + if (!(use_gesture_state & VR_USE_GESTURE_OFF_HAND)) { + sendButtonAction("+use2", true); + } + use_gesture_state |= VR_USE_GESTURE_OFF_HAND; + } else { + if (use_gesture_state & VR_USE_GESTURE_OFF_HAND) { + sendButtonAction("+use2", false); + } + use_gesture_state &= ~VR_USE_GESTURE_OFF_HAND; + } + // Weapon-hand gesture + xOffset = hmdPosition[0] - pDominantTracking->HeadPose.Pose.Position.x; + zOffset = hmdPosition[2] - pDominantTracking->HeadPose.Pose.Position.z; + distanceToBody = sqrtf((xOffset * xOffset) + (zOffset * zOffset)); + if (gestureUseAllowed && (distanceToBody > vr_use_gesture_boundary->value)) { + if (!(use_gesture_state & VR_USE_GESTURE_WEAPON_HAND)) { + sendButtonAction("+use", true); + } + use_gesture_state |= VR_USE_GESTURE_WEAPON_HAND; + } else { + if (use_gesture_state & VR_USE_GESTURE_WEAPON_HAND) { + sendButtonAction("+use", false); + } + use_gesture_state &= ~VR_USE_GESTURE_WEAPON_HAND; + } + } else { + if (use_gesture_state & VR_USE_GESTURE_OFF_HAND) { + sendButtonAction("+use2", false); + } + if (use_gesture_state & VR_USE_GESTURE_WEAPON_HAND) { + sendButtonAction("+use", false); + } + use_gesture_state = 0; + } + + // Use (Action button) if ((pDominantTrackedRemoteNew->Buttons & xrButton_Joystick) != (pDominantTrackedRemoteOld->Buttons & xrButton_Joystick)) { diff --git a/Projects/Android/jni/src/Lambda1VR/VrInputOne.c b/Projects/Android/jni/src/Lambda1VR/VrInputOne.c index c1b66b8..daa7984 100644 --- a/Projects/Android/jni/src/Lambda1VR/VrInputOne.c +++ b/Projects/Android/jni/src/Lambda1VR/VrInputOne.c @@ -425,6 +425,49 @@ void HandleInput_OneController( ovrInputStateTrackedRemote *pDominantTrackedRemo } } + // Use (Action gesture) + if (vr_gesture_triggered_use->integer) { + bool gestureUseAllowed = !vr_weapon_stabilised->value; + // Off-hand gesture + float xOffset = hmdPosition[0] - pOffTracking->HeadPose.Pose.Position.x; + float zOffset = hmdPosition[2] - pOffTracking->HeadPose.Pose.Position.z; + float distanceToBody = sqrtf((xOffset * xOffset) + (zOffset * zOffset)); + if (gestureUseAllowed && (distanceToBody > vr_use_gesture_boundary->value)) { + if (!(use_gesture_state & VR_USE_GESTURE_OFF_HAND)) { + sendButtonAction("+use2", true); + } + use_gesture_state |= VR_USE_GESTURE_OFF_HAND; + } else { + if (use_gesture_state & VR_USE_GESTURE_OFF_HAND) { + sendButtonAction("+use2", false); + } + use_gesture_state &= ~VR_USE_GESTURE_OFF_HAND; + } + // Weapon-hand gesture + xOffset = hmdPosition[0] - pDominantTracking->HeadPose.Pose.Position.x; + zOffset = hmdPosition[2] - pDominantTracking->HeadPose.Pose.Position.z; + distanceToBody = sqrtf((xOffset * xOffset) + (zOffset * zOffset)); + if (gestureUseAllowed && (distanceToBody > vr_use_gesture_boundary->value)) { + if (!(use_gesture_state & VR_USE_GESTURE_WEAPON_HAND)) { + sendButtonAction("+use", true); + } + use_gesture_state |= VR_USE_GESTURE_WEAPON_HAND; + } else { + if (use_gesture_state & VR_USE_GESTURE_WEAPON_HAND) { + sendButtonAction("+use", false); + } + use_gesture_state &= ~VR_USE_GESTURE_WEAPON_HAND; + } + } else { + if (use_gesture_state & VR_USE_GESTURE_OFF_HAND) { + sendButtonAction("+use2", false); + } + if (use_gesture_state & VR_USE_GESTURE_WEAPON_HAND) { + sendButtonAction("+use", false); + } + use_gesture_state = 0; + } + sendButtonAction("+speed", running ? 1 : 0); } } diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/const.h b/Projects/Android/jni/src/Xash3D/xash3d/common/const.h index ec18de9..b24975c 100644 --- a/Projects/Android/jni/src/Xash3D/xash3d/common/const.h +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/const.h @@ -676,6 +676,7 @@ #define IN_RELOAD (1U << 13) #define IN_ALT1 (1U << 14) #define IN_SCORE (1U << 15) // Used by client.dll for when scoreboard is held down +#define IN_USE2 (1U << 16) // Break Model Defines #define BREAK_TYPEMASK 0x4F @@ -703,6 +704,10 @@ #define TE_BOUNCE_SHELL 1 #define TE_BOUNCE_SHOTSHELL 2 +// VR use gesture flags +#define VR_USE_GESTURE_OFF_HAND 1 +#define VR_USE_GESTURE_WEAPON_HAND 2 + // Rendering constants enum { diff --git a/Projects/Android/jni/src/Xash3D/xash3d/common/usercmd.h b/Projects/Android/jni/src/Xash3D/xash3d/common/usercmd.h index 96e3c91..55d0d3a 100644 --- a/Projects/Android/jni/src/Xash3D/xash3d/common/usercmd.h +++ b/Projects/Android/jni/src/Xash3D/xash3d/common/usercmd.h @@ -27,7 +27,7 @@ typedef struct usercmd_s float sidemove; // Sideways velocity float upmove; // Upward velocity byte lightlevel; // Light level at spot where we are standing. - unsigned short buttons; // Attack and move buttons + int buttons; // Attack and move buttons byte impulse; // Impulse command issued byte weaponselect; // Current weapon id diff --git a/Projects/Android/jni/src/Xash3D/xash3d/engine/common/net_encode.c b/Projects/Android/jni/src/Xash3D/xash3d/engine/common/net_encode.c index 8df8cb0..040a4ba 100644 --- a/Projects/Android/jni/src/Xash3D/xash3d/engine/common/net_encode.c +++ b/Projects/Android/jni/src/Xash3D/xash3d/engine/common/net_encode.c @@ -677,6 +677,14 @@ qboolean Delta_ParseField( char **delta_script, const delta_field_t *pInfo, delt *delta_script = COM_ParseFile( *delta_script, token ); if( token[0] != ',' ) *delta_script = oldpos; // not a ',' + // Ugly hack, but we need bigger size of buttons fields to be able to pass additional "use2" command state. + // Based on tests should not cause problems with multiplayer, but allow this to be disabled just in case. + int forceCompatibility = Cvar_Get("vr_force_network_compatibility", "0", CVAR_LATCH, "")->integer; + if (!forceCompatibility && !Q_strcmp( pField->name, "buttons" )) { + pField->flags = 8; // DT_INTEGER + pField->bits = 17; + } + return true; } diff --git a/Projects/Android/jni/src/Xash3D/xash3d/mainui/menus/Controls.cpp b/Projects/Android/jni/src/Xash3D/xash3d/mainui/menus/Controls.cpp index 507d79b..776b83c 100644 --- a/Projects/Android/jni/src/Xash3D/xash3d/mainui/menus/Controls.cpp +++ b/Projects/Android/jni/src/Xash3D/xash3d/mainui/menus/Controls.cpp @@ -68,7 +68,9 @@ private: CMenuCheckBox headTorch; CMenuCheckBox handModels; CMenuCheckBox quickCrouchJump; + CMenuCheckBox useGesture; CMenuSlider snapTurnAngle; + CMenuSlider useGestureBoundary; CMenuTable controllerList; CMenuControllerModesModel controllerListModel; @@ -117,6 +119,10 @@ void CMenuControls::_Init( void ) headTorch.SetCoord( 320, 570 ); headTorch.LinkCvar( "vr_headtorch" ); + useGesture.SetNameAndStatus( "Gesture Triggered Use", "Toggles triggering of use action by gesture" ); + useGesture.SetCoord( 720, 570 ); + useGesture.LinkCvar( "vr_gesture_triggered_use" ); + snapTurnAngle.SetNameAndStatus( "Snap/Smooth Turn: %.1f degrees", "Controller turn angle, < 10 is smooth turning per frame" ); snapTurnAngle.Setup( 0.0, 90.0, 1.0f ); snapTurnAngle.onChanged = CMenuEditable::WriteCvarCb; @@ -125,6 +131,14 @@ void CMenuControls::_Init( void ) snapTurnAngle.SetDrawValue(true); snapTurnAngle.LinkCvar("vr_snapturn_angle"); + useGestureBoundary.SetNameAndStatus( "Use Gesture Boundary", "Configures how far you need to reach to activate use gesture" ); + useGestureBoundary.Setup( 0.2, 0.5, 0.01f ); + useGestureBoundary.onChanged = CMenuEditable::WriteCvarCb; + useGestureBoundary.SetCoord( 320, 750 ); + useGestureBoundary.SetSize( 520, 40 ); + useGestureBoundary.SetDrawValue(true); + useGestureBoundary.LinkCvar("vr_use_gesture_boundary"); + AddItem( controllerList ); AddItem( hmdWalkDirection ); AddItem( quickCrouchJump ); @@ -132,6 +146,8 @@ void CMenuControls::_Init( void ) AddItem( headTorch ); AddItem( handModels ); AddItem( snapTurnAngle ); + AddItem( useGesture ); + AddItem( useGestureBoundary ); } @@ -162,6 +178,8 @@ void CMenuControls::SetConfig( ) headTorch.WriteCvar(); handModels.WriteCvar(); snapTurnAngle.WriteCvar(); + useGesture.WriteCvar(); + useGestureBoundary.WriteCvar(); // We're done now, just close Hide();