OpenXR touch controllers completely implemented

This commit is contained in:
Lubos 2022-04-23 21:06:35 +02:00
parent 0bf485664c
commit b11122e368
3 changed files with 112 additions and 89 deletions

View file

@ -25,14 +25,17 @@ XrAction aimPoseAction;
XrAction gripPoseAction; XrAction gripPoseAction;
XrAction indexLeftAction; XrAction indexLeftAction;
XrAction indexRightAction; XrAction indexRightAction;
XrAction toggleAction; XrAction menuAction;
XrAction moveOnXAction; XrAction buttonAAction;
XrAction moveOnYAction; XrAction buttonBAction;
XrAction buttonXAction;
XrAction buttonYAction;
XrAction gripLeftAction;
XrAction gripRightAction;
XrAction moveOnLeftJoystickAction; XrAction moveOnLeftJoystickAction;
XrAction moveOnRightJoystickAction; XrAction moveOnRightJoystickAction;
XrAction thumbstickClickAction; XrAction thumbstickLeftClickAction;
XrAction vibrateLeftToggle; XrAction thumbstickRightClickAction;
XrAction vibrateRightToggle;
XrAction vibrateLeftFeedback; XrAction vibrateLeftFeedback;
XrAction vibrateRightFeedback; XrAction vibrateRightFeedback;
XrActionSet runningActionSet; XrActionSet runningActionSet;
@ -643,14 +646,17 @@ void IN_VRInit( void )
runningActionSet = CreateActionSet(1, "running_action_set", "Action Set used on main loop"); runningActionSet = CreateActionSet(1, "running_action_set", "Action Set used on main loop");
indexLeftAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "index_left", "Index left", 0, NULL); indexLeftAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "index_left", "Index left", 0, NULL);
indexRightAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "index_right", "Index right", 0, NULL); indexRightAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "index_right", "Index right", 0, NULL);
toggleAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "toggle", "Toggle", 0, NULL); menuAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "menu_action", "Menu", 0, NULL);
moveOnXAction = CreateAction(runningActionSet, XR_ACTION_TYPE_FLOAT_INPUT, "move_on_x", "Move on X", 0, NULL); buttonAAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "button_a", "Button A", 0, NULL);
moveOnYAction = CreateAction(runningActionSet, XR_ACTION_TYPE_FLOAT_INPUT, "move_on_y", "Move on Y", 0, NULL); buttonBAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "button_b", "Button B", 0, NULL);
buttonXAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "button_x", "Button X", 0, NULL);
buttonYAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "button_y", "Button Y", 0, NULL);
gripLeftAction = CreateAction(runningActionSet, XR_ACTION_TYPE_FLOAT_INPUT, "grip_left", "Grip left", 0, NULL);
gripRightAction = CreateAction(runningActionSet, XR_ACTION_TYPE_FLOAT_INPUT, "grip_right", "Grip right", 0, NULL);
moveOnLeftJoystickAction = CreateAction(runningActionSet, XR_ACTION_TYPE_VECTOR2F_INPUT, "move_on_left_joy", "Move on left Joy", 0, NULL); moveOnLeftJoystickAction = CreateAction(runningActionSet, XR_ACTION_TYPE_VECTOR2F_INPUT, "move_on_left_joy", "Move on left Joy", 0, NULL);
moveOnRightJoystickAction = CreateAction(runningActionSet, XR_ACTION_TYPE_VECTOR2F_INPUT, "move_on_right_joy", "Move on right Joy", 0, NULL); moveOnRightJoystickAction = CreateAction(runningActionSet, XR_ACTION_TYPE_VECTOR2F_INPUT, "move_on_right_joy", "Move on right Joy", 0, NULL);
thumbstickClickAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "thumbstick_click", "Thumbstick Click", 0, NULL); thumbstickLeftClickAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "thumbstick_left", "Thumbstick left", 0, NULL);
vibrateLeftToggle = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "vibrate_left", "Vibrate Left Controller", 0, NULL); thumbstickRightClickAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "thumbstick_right", "Thumbstick right", 0, NULL);
vibrateRightToggle = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "vibrate_right", "Vibrate Right Controller", 0, NULL);
vibrateLeftFeedback = CreateAction(runningActionSet, XR_ACTION_TYPE_VIBRATION_OUTPUT, "vibrate_left_feedback", "Vibrate Left Controller Feedback", 0, NULL); vibrateLeftFeedback = CreateAction(runningActionSet, XR_ACTION_TYPE_VIBRATION_OUTPUT, "vibrate_left_feedback", "Vibrate Left Controller Feedback", 0, NULL);
vibrateRightFeedback = CreateAction(runningActionSet, XR_ACTION_TYPE_VIBRATION_OUTPUT, "vibrate_right_feedback", "Vibrate Right Controller Feedback", 0, NULL); vibrateRightFeedback = CreateAction(runningActionSet, XR_ACTION_TYPE_VIBRATION_OUTPUT, "vibrate_right_feedback", "Vibrate Right Controller Feedback", 0, NULL);
@ -716,25 +722,24 @@ void IN_VRInit( void )
// Action creation // Action creation
{ {
// Map bindings // Map bindings
XrActionSuggestedBinding bindings[22]; // large enough for all profiles XrActionSuggestedBinding bindings[32]; // large enough for all profiles
int currBinding = 0; int currBinding = 0;
{ {
if (interactionProfilePath == interactionProfilePathTouch) { if (interactionProfilePath == interactionProfilePathTouch) {
bindings[currBinding++] = ActionSuggestedBinding(indexLeftAction, "/user/hand/left/input/trigger"); bindings[currBinding++] = ActionSuggestedBinding(indexLeftAction, "/user/hand/left/input/trigger");
bindings[currBinding++] = ActionSuggestedBinding(indexRightAction, "/user/hand/right/input/trigger"); bindings[currBinding++] = ActionSuggestedBinding(indexRightAction, "/user/hand/right/input/trigger");
bindings[currBinding++] = ActionSuggestedBinding(toggleAction, "/user/hand/left/input/x/click"); bindings[currBinding++] = ActionSuggestedBinding(menuAction, "/user/hand/left/input/menu/click");
bindings[currBinding++] = ActionSuggestedBinding(toggleAction, "/user/hand/right/input/a/click"); bindings[currBinding++] = ActionSuggestedBinding(buttonXAction, "/user/hand/left/input/x/click");
bindings[currBinding++] = ActionSuggestedBinding(moveOnXAction, "/user/hand/left/input/squeeze/value"); bindings[currBinding++] = ActionSuggestedBinding(buttonYAction, "/user/hand/left/input/y/click");
bindings[currBinding++] = ActionSuggestedBinding(moveOnXAction, "/user/hand/right/input/squeeze/value"); bindings[currBinding++] = ActionSuggestedBinding(buttonAAction, "/user/hand/right/input/a/click");
bindings[currBinding++] = ActionSuggestedBinding(moveOnYAction, "/user/hand/left/input/trigger/value"); bindings[currBinding++] = ActionSuggestedBinding(buttonBAction, "/user/hand/right/input/b/click");
bindings[currBinding++] = ActionSuggestedBinding(moveOnYAction, "/user/hand/right/input/trigger/value"); bindings[currBinding++] = ActionSuggestedBinding(gripLeftAction, "/user/hand/left/input/squeeze/value");
bindings[currBinding++] = ActionSuggestedBinding(gripRightAction, "/user/hand/right/input/squeeze/value");
bindings[currBinding++] = ActionSuggestedBinding(moveOnLeftJoystickAction, "/user/hand/left/input/thumbstick"); bindings[currBinding++] = ActionSuggestedBinding(moveOnLeftJoystickAction, "/user/hand/left/input/thumbstick");
bindings[currBinding++] = ActionSuggestedBinding(moveOnRightJoystickAction, "/user/hand/right/input/thumbstick"); bindings[currBinding++] = ActionSuggestedBinding(moveOnRightJoystickAction, "/user/hand/right/input/thumbstick");
bindings[currBinding++] = ActionSuggestedBinding(thumbstickClickAction, "/user/hand/left/input/thumbstick/click"); bindings[currBinding++] = ActionSuggestedBinding(thumbstickLeftClickAction, "/user/hand/left/input/thumbstick/click");
bindings[currBinding++] = ActionSuggestedBinding(thumbstickClickAction, "/user/hand/right/input/thumbstick/click"); bindings[currBinding++] = ActionSuggestedBinding(thumbstickRightClickAction, "/user/hand/right/input/thumbstick/click");
bindings[currBinding++] = ActionSuggestedBinding(vibrateLeftToggle, "/user/hand/left/input/y/click");
bindings[currBinding++] = ActionSuggestedBinding(vibrateRightToggle, "/user/hand/right/input/b/click");
bindings[currBinding++] = ActionSuggestedBinding(vibrateLeftFeedback, "/user/hand/left/output/haptic"); bindings[currBinding++] = ActionSuggestedBinding(vibrateLeftFeedback, "/user/hand/left/output/haptic");
bindings[currBinding++] = ActionSuggestedBinding(vibrateRightFeedback, "/user/hand/right/output/haptic"); bindings[currBinding++] = ActionSuggestedBinding(vibrateRightFeedback, "/user/hand/right/output/haptic");
bindings[currBinding++] = ActionSuggestedBinding(aimPoseAction, "/user/hand/left/input/aim/pose"); bindings[currBinding++] = ActionSuggestedBinding(aimPoseAction, "/user/hand/left/input/aim/pose");
@ -746,8 +751,8 @@ void IN_VRInit( void )
if (interactionProfilePath == interactionProfilePathKHRSimple) { if (interactionProfilePath == interactionProfilePathKHRSimple) {
bindings[currBinding++] = ActionSuggestedBinding(indexLeftAction, "/user/hand/left/input/select/click"); bindings[currBinding++] = ActionSuggestedBinding(indexLeftAction, "/user/hand/left/input/select/click");
bindings[currBinding++] = ActionSuggestedBinding(indexRightAction, "/user/hand/right/input/select/click"); bindings[currBinding++] = ActionSuggestedBinding(indexRightAction, "/user/hand/right/input/select/click");
bindings[currBinding++] = ActionSuggestedBinding(vibrateLeftToggle, "/user/hand/left/input/menu/click"); bindings[currBinding++] = ActionSuggestedBinding(buttonAAction, "/user/hand/left/input/menu/click");
bindings[currBinding++] = ActionSuggestedBinding(vibrateRightToggle, "/user/hand/right/input/menu/click"); bindings[currBinding++] = ActionSuggestedBinding(buttonXAction, "/user/hand/right/input/menu/click");
bindings[currBinding++] = ActionSuggestedBinding(vibrateLeftFeedback, "/user/hand/left/output/haptic"); bindings[currBinding++] = ActionSuggestedBinding(vibrateLeftFeedback, "/user/hand/left/output/haptic");
bindings[currBinding++] = ActionSuggestedBinding(vibrateRightFeedback, "/user/hand/right/output/haptic"); bindings[currBinding++] = ActionSuggestedBinding(vibrateRightFeedback, "/user/hand/right/output/haptic");
bindings[currBinding++] = ActionSuggestedBinding(aimPoseAction, "/user/hand/left/input/aim/pose"); bindings[currBinding++] = ActionSuggestedBinding(aimPoseAction, "/user/hand/left/input/aim/pose");
@ -766,19 +771,22 @@ void IN_VRInit( void )
OXR(xrSuggestInteractionProfileBindings(engine->appState.Instance, &suggestedBindings)); OXR(xrSuggestInteractionProfileBindings(engine->appState.Instance, &suggestedBindings));
// Enumerate actions // Enumerate actions
XrPath actionPathsBuffer[16]; XrPath actionPathsBuffer[32];
char stringBuffer[256]; char stringBuffer[256];
XrAction actionsToEnumerate[] = { XrAction actionsToEnumerate[] = {
indexLeftAction, indexLeftAction,
indexRightAction, indexRightAction,
toggleAction, menuAction,
moveOnXAction, buttonAAction,
moveOnYAction, buttonBAction,
buttonXAction,
buttonYAction,
gripLeftAction,
gripRightAction,
moveOnLeftJoystickAction, moveOnLeftJoystickAction,
moveOnRightJoystickAction, moveOnRightJoystickAction,
thumbstickClickAction, thumbstickLeftClickAction,
vibrateLeftToggle, thumbstickRightClickAction,
vibrateRightToggle,
vibrateLeftFeedback, vibrateLeftFeedback,
vibrateRightFeedback, vibrateRightFeedback,
aimPoseAction, aimPoseAction,
@ -799,9 +807,9 @@ void IN_VRInit( void )
(long long)enumerateInfo.action, (long long)enumerateInfo.action,
countOutput); countOutput);
if (countOutput < 16) { if (countOutput < 32) {
OXR(xrEnumerateBoundSourcesForAction( OXR(xrEnumerateBoundSourcesForAction(
engine->appState.Session, &enumerateInfo, 16, &countOutput, actionPathsBuffer)); engine->appState.Session, &enumerateInfo, 32, &countOutput, actionPathsBuffer));
for (uint32_t a = 0; a < countOutput; ++a) { for (uint32_t a = 0; a < countOutput; ++a) {
XrInputSourceLocalizedNameGetInfo nameGetInfo = {}; XrInputSourceLocalizedNameGetInfo nameGetInfo = {};
nameGetInfo.type = XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO; nameGetInfo.type = XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO;
@ -841,8 +849,9 @@ static void IN_VRController( qboolean isRightController, XrPosef pose )
{ {
//Set gun angles - We need to calculate all those we might need (including adjustments) for the client to then take its pick //Set gun angles - We need to calculate all those we might need (including adjustments) for the client to then take its pick
vec3_t rotation = {0}; vec3_t rotation = {0};
if (isRightController != (vr_righthanded->integer != 0)) if (isRightController == (vr_righthanded->integer != 0))
QuatToYawPitchRoll(pose.orientation, rotation, vr.offhandangles2); // used for off-hand direction mode {
//Set gun angles - We need to calculate all those we might need (including adjustments) for the client to then take its pick
rotation[PITCH] = vr_weaponPitch->value; rotation[PITCH] = vr_weaponPitch->value;
QuatToYawPitchRoll(pose.orientation, rotation, vr.weaponangles); QuatToYawPitchRoll(pose.orientation, rotation, vr.weaponangles);
@ -857,6 +866,20 @@ static void IN_VRController( qboolean isRightController, XrPosef pose )
VectorCopy(vr.weaponoffset_last[1], vr.weaponoffset_last[0]); VectorCopy(vr.weaponoffset_last[1], vr.weaponoffset_last[0]);
VectorCopy(vr.weaponoffset, vr.weaponoffset_last[1]); VectorCopy(vr.weaponoffset, vr.weaponoffset_last[1]);
VectorSubtract(vr.weaponposition, vr.hmdposition, vr.weaponoffset); VectorSubtract(vr.weaponposition, vr.hmdposition, vr.weaponoffset);
} else {
QuatToYawPitchRoll(pose.orientation, rotation, vr.offhandangles2); // used for off-hand direction mode
rotation[PITCH] = vr_weaponPitch->value;
QuatToYawPitchRoll(pose.orientation, rotation, vr.offhandangles);
///location relative to view
vr.weaponposition[0] = pose.position.x;
vr.weaponposition[1] = pose.position.y + vr_heightAdjust->value;
vr.weaponposition[2] = pose.position.z;
VectorCopy(vr.offhandoffset_last[1], vr.offhandoffset_last[0]);
VectorCopy(vr.offhandoffset, vr.offhandoffset_last[1]);
VectorSubtract(vr.offhandposition, vr.hmdposition, vr.offhandoffset);
}
if (vr.virtual_screen || cl.snap.ps.pm_type == PM_INTERMISSION) if (vr.virtual_screen || cl.snap.ps.pm_type == PM_INTERMISSION)
{ {
@ -1183,9 +1206,6 @@ static void IN_VRButtons( qboolean isRightController, uint32_t buttons )
{ {
vrController_t* controller = isRightController == qtrue ? &rightController : &leftController; vrController_t* controller = isRightController == qtrue ? &rightController : &leftController;
//TODO:
/*
{
// Menu button // Menu button
if ((buttons & ovrButton_Enter) && !IN_InputActivated(&controller->buttons, ovrButton_Enter)) { if ((buttons & ovrButton_Enter) && !IN_InputActivated(&controller->buttons, ovrButton_Enter)) {
IN_ActivateInput(&controller->buttons, ovrButton_Enter); IN_ActivateInput(&controller->buttons, ovrButton_Enter);
@ -1278,7 +1298,6 @@ static void IN_VRButtons( qboolean isRightController, uint32_t buttons )
} else { } else {
IN_HandleInactiveInput(&controller->buttons, ovrButton_Y, "Y", 0, qfalse); IN_HandleInactiveInput(&controller->buttons, ovrButton_Y, "Y", 0, qfalse);
} }
*/
} }
void IN_VRInputFrame( void ) void IN_VRInputFrame( void )
@ -1400,44 +1419,22 @@ void IN_VRInputFrame( void )
getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO; getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO;
getInfo.next = NULL; getInfo.next = NULL;
getInfo.subactionPath = XR_NULL_PATH; getInfo.subactionPath = XR_NULL_PATH;
XrActionStateBoolean toggleState = GetActionStateBoolean(toggleAction);
XrActionStateBoolean vibrateLeftState = GetActionStateBoolean(vibrateLeftToggle);
XrActionStateBoolean vibrateRightState = GetActionStateBoolean(vibrateRightToggle);
XrActionStateBoolean thumbstickClickState = GetActionStateBoolean(thumbstickClickAction);
} }
//TODO: //button mapping
/*ovrInputCapabilityHeader capsHeader; uint32_t lButtons = 0;
uint32_t index = 0; if (GetActionStateBoolean(menuAction).currentState) lButtons |= ovrButton_Enter;
for (;;) { if (GetActionStateBoolean(buttonXAction).currentState) lButtons |= ovrButton_X;
ovrResult enumResult = vrapi_EnumerateInputDevices(ovr, index, &capsHeader); if (GetActionStateBoolean(buttonYAction).currentState) lButtons |= ovrButton_Y;
if (enumResult < 0) { if (GetActionStateFloat(gripLeftAction).currentState > 0.5f) lButtons |= ovrButton_GripTrigger;
break; if (GetActionStateBoolean(thumbstickLeftClickAction).currentState) lButtons |= ovrButton_LThumb;
} IN_VRButtons(qfalse, lButtons);
++index; uint32_t rButtons = 0;
if (GetActionStateBoolean(buttonAAction).currentState) rButtons |= ovrButton_A;
if (capsHeader.Type != ovrControllerType_TrackedRemote) { if (GetActionStateBoolean(buttonBAction).currentState) rButtons |= ovrButton_B;
continue; if (GetActionStateFloat(gripRightAction).currentState > 0.5f) rButtons |= ovrButton_GripTrigger;
} if (GetActionStateBoolean(thumbstickRightClickAction).currentState) rButtons |= ovrButton_RThumb;
IN_VRButtons(qtrue, rButtons);
qboolean isRight;
vrController_t* controller;
if (caps.ControllerCapabilities & ovrControllerCaps_LeftHand) {
isRight = qfalse;
controller = &leftController;
controllerIDs[0] = capsHeader.DeviceID;
} else if (caps.ControllerCapabilities & ovrControllerCaps_RightHand) {
isRight = qtrue;
controller = &rightController;
controllerIDs[1] = capsHeader.DeviceID;
}
else {
continue;
}
IN_VRButtons(isRight, state.Buttons);
}*/
//index finger click //index finger click
XrActionStateBoolean indexState; XrActionStateBoolean indexState;

View file

@ -464,11 +464,11 @@ void VR_DrawFrame( engine_t* engine ) {
cylinder_layer.subImage.imageRect.extent.height = engine->appState.Renderer.FrameBuffer[0].ColorSwapChain.Height; cylinder_layer.subImage.imageRect.extent.height = engine->appState.Renderer.FrameBuffer[0].ColorSwapChain.Height;
cylinder_layer.subImage.imageArrayIndex = 0; cylinder_layer.subImage.imageArrayIndex = 0;
const XrVector3f axis = {0.0f, 1.0f, 0.0f}; const XrVector3f axis = {0.0f, 1.0f, 0.0f};
const XrVector3f pos = {xfStageFromHead.position.x, 0.0f, xfStageFromHead.position.z - 1.0f}; const XrVector3f pos = {xfStageFromHead.position.x, -0.25f, xfStageFromHead.position.z - 1.0f};
cylinder_layer.pose.orientation = XrQuaternionf_CreateFromVectorAngle(axis, 0); cylinder_layer.pose.orientation = XrQuaternionf_CreateFromVectorAngle(axis, 0);
cylinder_layer.pose.position = pos; cylinder_layer.pose.position = pos;
cylinder_layer.radius = 1.0f; cylinder_layer.radius = 1.0f;
cylinder_layer.centralAngle = MATH_PI * 0.75f; cylinder_layer.centralAngle = MATH_PI * 0.5f;
cylinder_layer.aspectRatio = 1.0f; cylinder_layer.aspectRatio = 1.0f;
engine->appState.Layers[engine->appState.LayerCount++].Cylinder = cylinder_layer; engine->appState.Layers[engine->appState.LayerCount++].Cylinder = cylinder_layer;

View file

@ -126,6 +126,32 @@ typedef struct {
float M[4][4]; float M[4][4];
} ovrMatrix4f; } ovrMatrix4f;
typedef enum ovrButton_ {
ovrButton_A = 0x00000001, // Set for trigger pulled on the Gear VR and Go Controllers
ovrButton_B = 0x00000002,
ovrButton_RThumb = 0x00000004,
ovrButton_RShoulder = 0x00000008,
ovrButton_X = 0x00000100,
ovrButton_Y = 0x00000200,
ovrButton_LThumb = 0x00000400,
ovrButton_LShoulder = 0x00000800,
ovrButton_Up = 0x00010000,
ovrButton_Down = 0x00020000,
ovrButton_Left = 0x00040000,
ovrButton_Right = 0x00080000,
ovrButton_Enter = 0x00100000, //< Set for touchpad click on the Go Controller, menu
// button on Left Quest Controller
ovrButton_Back = 0x00200000, //< Back button on the Go Controller (only set when
// a short press comes up)
ovrButton_GripTrigger = 0x04000000, //< grip trigger engaged
ovrButton_Trigger = 0x20000000, //< Index Trigger engaged
ovrButton_Joystick = 0x80000000, //< Click of the Joystick
ovrButton_EnumSize = 0x7fffffff
} ovrButton;
typedef struct { typedef struct {
uint64_t frameIndex; uint64_t frameIndex;
ovrApp appState; ovrApp appState;