diff --git a/Projects/Android/AndroidManifest.xml b/Projects/Android/AndroidManifest.xml index c3928e9..e34a460 100644 --- a/Projects/Android/AndroidManifest.xml +++ b/Projects/Android/AndroidManifest.xml @@ -24,9 +24,14 @@ > + + + + + SessionActive = (result == XR_SUCCESS); // Set session state once we have entered VR mode and have a valid session object. - if (app->SessionActive) { + if (app->SessionActive) + { XrPerfSettingsLevelEXT cpuPerfLevel = XR_PERF_SETTINGS_LEVEL_BOOST_EXT; XrPerfSettingsLevelEXT gpuPerfLevel = XR_PERF_SETTINGS_LEVEL_BOOST_EXT; @@ -980,23 +1045,25 @@ void ovrApp_HandleSessionStateChanges(ovrApp* app, XrSessionState state) { OXR(xrGetInstanceProcAddr( app->Instance, "xrPerfSettingsSetPerformanceLevelEXT", - (PFN_xrVoidFunction*)(&pfnPerfSettingsSetPerformanceLevelEXT))); + (PFN_xrVoidFunction * )(&pfnPerfSettingsSetPerformanceLevelEXT))); OXR(pfnPerfSettingsSetPerformanceLevelEXT( app->Session, XR_PERF_SETTINGS_DOMAIN_CPU_EXT, cpuPerfLevel)); OXR(pfnPerfSettingsSetPerformanceLevelEXT( app->Session, XR_PERF_SETTINGS_DOMAIN_GPU_EXT, gpuPerfLevel)); +#ifdef META_QUEST PFN_xrSetAndroidApplicationThreadKHR pfnSetAndroidApplicationThreadKHR = NULL; OXR(xrGetInstanceProcAddr( app->Instance, "xrSetAndroidApplicationThreadKHR", - (PFN_xrVoidFunction*)(&pfnSetAndroidApplicationThreadKHR))); + (PFN_xrVoidFunction * )(&pfnSetAndroidApplicationThreadKHR))); OXR(pfnSetAndroidApplicationThreadKHR( app->Session, XR_ANDROID_THREAD_TYPE_APPLICATION_MAIN_KHR, app->MainThreadTid)); OXR(pfnSetAndroidApplicationThreadKHR( app->Session, XR_ANDROID_THREAD_TYPE_RENDERER_MAIN_KHR, app->RenderThreadTid)); +#endif } } else if (state == XR_SESSION_STATE_STOPPING) { assert(app->SessionActive); @@ -1045,6 +1112,7 @@ GLboolean ovrApp_HandleXrEvents(ovrApp* app) { perf_settings_event->fromLevel, perf_settings_event->toLevel); } break; +#ifdef META_QUEST case XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB: { const XrEventDataDisplayRefreshRateChangedFB* refresh_rate_changed_event = (XrEventDataDisplayRefreshRateChangedFB*)(baseEventHeader); @@ -1053,6 +1121,7 @@ GLboolean ovrApp_HandleXrEvents(ovrApp* app) { refresh_rate_changed_event->fromDisplayRefreshRate, refresh_rate_changed_event->toDisplayRefreshRate); } break; +#endif case XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING: { XrEventDataReferenceSpaceChangePending* ref_space_change_event = (XrEventDataReferenceSpaceChangePending*)(baseEventHeader); @@ -1606,7 +1675,7 @@ void VR_InitRenderer( ) { gAppState.Instance, gAppState.SystemId, XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, &gAppState.ViewportConfig)); - +#ifdef META_QUEST XrSystemColorSpacePropertiesFB colorSpacePropertiesFB = {}; colorSpacePropertiesFB.type = XR_TYPE_SYSTEM_COLOR_SPACE_PROPERTIES_FB; @@ -1688,6 +1757,7 @@ void VR_InitRenderer( ) { OXR(gAppState.pfnRequestDisplayRefreshRate(gAppState.Session, 0.0f)); ALOGV("Requesting system default display refresh rate"); } +#endif uint32_t numOutputSpaces = 0; OXR(xrEnumerateReferenceSpaces(gAppState.Session, 0, &numOutputSpaces, NULL)); @@ -1717,6 +1787,16 @@ void VR_InitRenderer( ) { gAppState.Projections[eye].type = XR_TYPE_VIEW; } +#ifdef PICO_XR + xrGetInstanceProcAddr(gAppState.Instance,"xrSetConfigPICO", (PFN_xrVoidFunction*)(&pfnXrSetConfigPICO)); + xrGetInstanceProcAddr(gAppState.Instance,"xrGetConfigPICO", (PFN_xrVoidFunction*)(&pfnXrGetConfigPICO)); + + pfnXrSetConfigPICO(gAppState.Session,TRACKING_ORIGIN,"0"); + pfnXrSetConfigPICO(gAppState.Session,TRACKING_ORIGIN,"1"); + + pfnXrGetConfigPICO(gAppState.Session, GET_DISPLAY_RATE, &gAppState.currentDisplayRefreshRate); +#endif + ovrRenderer_Create( gAppState.Session, &gAppState.Renderer, @@ -1740,7 +1820,7 @@ void * AppThreadFunction(void * parm ) { jclass cls = java.Env->GetObjectClass(java.ActivityObject); // Note that AttachCurrentThread will reset the thread name. - prctl(PR_SET_NAME, (long) "OVR::Main", 0, 0, 0); + prctl(PR_SET_NAME, (long) "AppThreadFunction", 0, 0, 0); openjk_initialised = false; vr_screen_dist = NULL; @@ -1748,6 +1828,8 @@ void * AppThreadFunction(void * parm ) { ovrApp_Clear(&gAppState); gAppState.Java = java; + ovrEgl_CreateContext(&gAppState.Egl, NULL); + EglInitExtensions(); PFN_xrInitializeLoaderKHR xrInitializeLoaderKHR; xrGetInstanceProcAddr( @@ -1765,16 +1847,25 @@ void * AppThreadFunction(void * parm ) { // Create the OpenXR instance. XrApplicationInfo appInfo; memset(&appInfo, 0, sizeof(appInfo)); - strcpy(appInfo.applicationName, "JKQUest"); + strcpy(appInfo.applicationName, "JKXR"); appInfo.applicationVersion = 0; - strcpy(appInfo.engineName, "JKQuest"); + strcpy(appInfo.engineName, "JKXR"); appInfo.engineVersion = 0; appInfo.apiVersion = XR_CURRENT_API_VERSION; XrInstanceCreateInfo instanceCreateInfo; memset(&instanceCreateInfo, 0, sizeof(instanceCreateInfo)); instanceCreateInfo.type = XR_TYPE_INSTANCE_CREATE_INFO; +#ifdef META_QUEST instanceCreateInfo.next = NULL; +#endif +#ifdef PICO_XR + XrInstanceCreateInfoAndroidKHR instanceCreateInfoAndroid = {XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR}; + instanceCreateInfoAndroid.applicationVM = java.Vm; + instanceCreateInfoAndroid.applicationActivity = java.ActivityObject; + + instanceCreateInfo.next = (XrBaseInStructure*)&instanceCreateInfoAndroid; +#endif instanceCreateInfo.createFlags = 0; instanceCreateInfo.applicationInfo = appInfo; instanceCreateInfo.enabledApiLayerCount = 0; @@ -1823,6 +1914,7 @@ void * AppThreadFunction(void * parm ) { graphicsRequirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR; OXR(pfnGetOpenGLESGraphicsRequirementsKHR(gAppState.Instance, gAppState.SystemId, &graphicsRequirements)); +#ifdef META_QUEST XrSystemColorSpacePropertiesFB colorSpacePropertiesFB = {}; colorSpacePropertiesFB.type = XR_TYPE_SYSTEM_COLOR_SPACE_PROPERTIES_FB; @@ -1832,7 +1924,7 @@ void * AppThreadFunction(void * parm ) { OXR(xrGetSystemProperties(gAppState.Instance, gAppState.SystemId, &systemProperties)); ALOGV("System Color Space Properties: colorspace=%d", colorSpacePropertiesFB.colorSpace); - +#endif //Set device defaults if (SS_MULTIPLIER == 0.0f) @@ -1851,9 +1943,6 @@ void * AppThreadFunction(void * parm ) { gAppState.GpuLevel = GPU_LEVEL; gAppState.MainThreadTid = gettid(); - ovrEgl_CreateContext(&gAppState.Egl, NULL); - - EglInitExtensions(); VR_EnterVR(); VR_InitRenderer(); @@ -1949,6 +2038,11 @@ void VR_UpdateStageBounds() { //All the stuff we want to do each frame void JKVR_FrameSetup() { + if (gAppState.FrameSetup) + { + return; + } + GLboolean stageBoundsDirty = GL_TRUE; if (ovrApp_HandleXrEvents(&gAppState)) { VR_Recenter(); @@ -1998,6 +2092,8 @@ void JKVR_FrameSetup() JKVR_getTrackedRemotesOrientation(); JKVR_processHaptics(); + + gAppState.FrameSetup = true; } int GetRefresh() @@ -2021,6 +2117,8 @@ void VR_ClearFrameBuffer( int width, int height) glScissor( 0, 0, 0, 0 ); glDisable( GL_SCISSOR_TEST ); + //This is a bit of a hack, but we need to do this to correct for the fact that the engine uses linear RGB colorspace + //but openxr uses SRGB (or something, must admit I don't really understand, but adding this works to make it look good again) glDisable( GL_FRAMEBUFFER_SRGB ); } @@ -2167,101 +2265,6 @@ void JKVR_HapticEvent(const char* event, int position, int flags, int intensity, } } -void JKVR_SyncActions( void ) -{ - // Attach to session - XrSessionActionSetsAttachInfo attachInfo = {}; - attachInfo.type = XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO; - attachInfo.next = NULL; - attachInfo.countActionSets = 1; - attachInfo.actionSets = &runningActionSet; - OXR(xrAttachSessionActionSets(gAppState.Session, &attachInfo)); - - // sync action data - XrActiveActionSet activeActionSet = {}; - activeActionSet.actionSet = runningActionSet; - activeActionSet.subactionPath = XR_NULL_PATH; - - XrActionsSyncInfo syncInfo = {}; - syncInfo.type = XR_TYPE_ACTIONS_SYNC_INFO; - syncInfo.next = NULL; - syncInfo.countActiveActionSets = 1; - syncInfo.activeActionSets = &activeActionSet; - OXR(xrSyncActions(gAppState.Session, &syncInfo)); - - // query input action states - XrActionStateGetInfo getInfo = {}; - getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO; - getInfo.next = NULL; - getInfo.subactionPath = XR_NULL_PATH; -} - -void JKVR_UpdateControllers( ) -{ - JKVR_SyncActions(); - - //get controller poses - XrAction controller[] = {handPoseLeftAction, handPoseRightAction}; - XrPath subactionPath[] = {leftHandPath, rightHandPath}; - XrSpace controllerSpace[] = {leftControllerAimSpace, rightControllerAimSpace}; - for (int i = 0; i < 2; i++) { - if (ActionPoseIsActive(controller[i], subactionPath[i])) { - XrSpaceVelocity vel = {}; - vel.type = XR_TYPE_SPACE_VELOCITY; - XrSpaceLocation loc = {}; - loc.type = XR_TYPE_SPACE_LOCATION; - loc.next = &vel; - OXR(xrLocateSpace(controllerSpace[i], gAppState.CurrentSpace, gAppState.PredictedDisplayTime, &loc)); - - gAppState.TrackedController[i].Active = (loc.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) != 0; - gAppState.TrackedController[i].Pose = loc.pose; - gAppState.TrackedController[i].Velocity = vel; - - // apply velocity -// float dt = (in_vrEventTime - lastframetime) * 0.001f; -// for (int j = 0; j < 3; j++) { -// (&gAppState.TrackedController[i].Pose.position.x)[j] += (&vel.linearVelocity.x)[j] * dt; -// } - } else { - ovrTrackedController_Clear(&gAppState.TrackedController[i]); - } - } - - leftRemoteTracking_new = gAppState.TrackedController[0]; - rightRemoteTracking_new = gAppState.TrackedController[1]; - - - memset(&leftTrackedRemoteState_new, 0, sizeof leftTrackedRemoteState_new); - memset(&rightTrackedRemoteState_new, 0, sizeof rightTrackedRemoteState_new); - - //button mapping - if (GetActionStateBoolean(menuAction).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_Enter; - if (GetActionStateBoolean(buttonXAction).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_X; - if (GetActionStateBoolean(buttonYAction).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_Y; - leftTrackedRemoteState_new.GripTrigger = GetActionStateFloat(gripLeftAction).currentState; - if (leftTrackedRemoteState_new.GripTrigger > 0.5f) leftTrackedRemoteState_new.Buttons |= xrButton_GripTrigger; - if (GetActionStateBoolean(thumbstickLeftClickAction).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_LThumb; - - if (GetActionStateBoolean(buttonAAction).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_A; - if (GetActionStateBoolean(buttonBAction).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_B; - rightTrackedRemoteState_new.GripTrigger = GetActionStateFloat(gripRightAction).currentState; - if (rightTrackedRemoteState_new.GripTrigger > 0.5f) rightTrackedRemoteState_new.Buttons |= xrButton_GripTrigger; - if (GetActionStateBoolean(thumbstickRightClickAction).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_RThumb; - - //index finger click - if (GetActionStateBoolean(indexLeftAction).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_Trigger; - if (GetActionStateBoolean(indexRightAction).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_Trigger; - - //thumbstick - XrActionStateVector2f moveJoystickState; - moveJoystickState = GetActionStateVector2(moveOnLeftJoystickAction); - leftTrackedRemoteState_new.Joystick.x = moveJoystickState.currentState.x; - leftTrackedRemoteState_new.Joystick.y = moveJoystickState.currentState.y; - - moveJoystickState = GetActionStateVector2(moveOnRightJoystickAction); - rightTrackedRemoteState_new.Joystick.x = moveJoystickState.currentState.x; - rightTrackedRemoteState_new.Joystick.y = moveJoystickState.currentState.y; -} void JKVR_getHMDOrientation() {//Get orientation @@ -2318,16 +2321,15 @@ void JKVR_getTrackedRemotesOrientation() {//Get info for tracked remotes &rightTrackedRemoteState_new, &rightTrackedRemoteState_old, &rightRemoteTracking_new, xrButton_X, xrButton_Y, xrButton_A, xrButton_B); break; -/* case WEAPON_ALIGN: + case WEAPON_ALIGN: HandleInput_WeaponAlign(&rightTrackedRemoteState_new, &rightTrackedRemoteState_old, &rightRemoteTracking_new, &leftTrackedRemoteState_new, &leftTrackedRemoteState_old, &leftRemoteTracking_new, xrButton_A, xrButton_B, xrButton_X, xrButton_Y); break; - */ } } -void JKVR_submitFrame() +void JKVR_updateProjections() { XrViewLocateInfo projectionInfo = {}; projectionInfo.type = XR_TYPE_VIEW_LOCATE_INFO; @@ -2347,6 +2349,15 @@ void JKVR_submitFrame() projectionCapacityInput, &projectionCountOutput, gAppState.Projections)); +} + +void JKVR_submitFrame() +{ + if (gAppState.SessionActive == GL_FALSE) { + return; + } + + JKVR_updateProjections(); XrFovf fov = {}; XrPosef viewTransform[2]; @@ -2390,7 +2401,7 @@ void JKVR_submitFrame() memset(&projection_layer_elements[eye], 0, sizeof(XrCompositionLayerProjectionView)); projection_layer_elements[eye].type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW; - projection_layer_elements[eye].pose = XrPosef_Inverse(viewTransform[eye]); + projection_layer_elements[eye].pose = gAppState.xfStageFromHead; projection_layer_elements[eye].fov = fov; memset(&projection_layer_elements[eye].subImage, 0, sizeof(XrSwapchainSubImage)); projection_layer_elements[eye].subImage.swapchain = @@ -2451,6 +2462,8 @@ void JKVR_submitFrame() endFrameInfo.layers = layers; OXR(xrEndFrame(gAppState.Session, &endFrameInfo)); + + gAppState.FrameSetup = false; } static void ovrAppThread_Create( ovrAppThread * appThread, JNIEnv * env, jobject activityObject, jclass activityClass ) diff --git a/Projects/Android/jni/JKVR/OpenXrInput_MetaQuest.cpp b/Projects/Android/jni/JKVR/OpenXrInput_MetaQuest.cpp new file mode 100644 index 0000000..3608393 --- /dev/null +++ b/Projects/Android/jni/JKVR/OpenXrInput_MetaQuest.cpp @@ -0,0 +1,502 @@ +#include "VrInput.h" +#include "VrCvars.h" + +extern ovrApp gAppState; + +#ifdef META_QUEST + +XrSpace CreateActionSpace(XrAction poseAction, XrPath subactionPath) { + XrActionSpaceCreateInfo asci = {}; + asci.type = XR_TYPE_ACTION_SPACE_CREATE_INFO; + asci.action = poseAction; + asci.poseInActionSpace.orientation.w = 1.0f; + asci.subactionPath = subactionPath; + XrSpace actionSpace = XR_NULL_HANDLE; + OXR(xrCreateActionSpace(gAppState.Session, &asci, &actionSpace)); + return actionSpace; +} + +XrActionSuggestedBinding ActionSuggestedBinding(XrAction action, const char* bindingString) { + XrActionSuggestedBinding asb; + asb.action = action; + XrPath bindingPath; + OXR(xrStringToPath(gAppState.Instance, bindingString, &bindingPath)); + asb.binding = bindingPath; + return asb; +} + +XrActionSet CreateActionSet(int priority, const char* name, const char* localizedName) { + XrActionSetCreateInfo asci = {}; + asci.type = XR_TYPE_ACTION_SET_CREATE_INFO; + asci.next = NULL; + asci.priority = priority; + strcpy(asci.actionSetName, name); + strcpy(asci.localizedActionSetName, localizedName); + XrActionSet actionSet = XR_NULL_HANDLE; + OXR(xrCreateActionSet(gAppState.Instance, &asci, &actionSet)); + return actionSet; +} + +XrAction CreateAction( + XrActionSet actionSet, + XrActionType type, + const char* actionName, + const char* localizedName, + int countSubactionPaths, + XrPath* subactionPaths) { + ALOGV("CreateAction %s, %" PRIi32, actionName, countSubactionPaths); + + XrActionCreateInfo aci = {}; + aci.type = XR_TYPE_ACTION_CREATE_INFO; + aci.next = NULL; + aci.actionType = type; + if (countSubactionPaths > 0) { + aci.countSubactionPaths = countSubactionPaths; + aci.subactionPaths = subactionPaths; + } + strcpy(aci.actionName, actionName); + strcpy(aci.localizedActionName, localizedName ? localizedName : actionName); + XrAction action = XR_NULL_HANDLE; + OXR(xrCreateAction(actionSet, &aci, &action)); + return action; +} + +bool ActionPoseIsActive(XrAction action, XrPath subactionPath) { + XrActionStateGetInfo getInfo = {}; + getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO; + getInfo.action = action; + getInfo.subactionPath = subactionPath; + + XrActionStatePose state = {}; + state.type = XR_TYPE_ACTION_STATE_POSE; + OXR(xrGetActionStatePose(gAppState.Session, &getInfo, &state)); + return state.isActive != XR_FALSE; +} + +XrActionStateFloat GetActionStateFloat(XrAction action) { + XrActionStateGetInfo getInfo = {}; + getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO; + getInfo.action = action; + + XrActionStateFloat state = {}; + state.type = XR_TYPE_ACTION_STATE_FLOAT; + + OXR(xrGetActionStateFloat(gAppState.Session, &getInfo, &state)); + return state; +} + +XrActionStateBoolean GetActionStateBoolean(XrAction action) { + XrActionStateGetInfo getInfo = {}; + getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO; + getInfo.action = action; + + XrActionStateBoolean state = {}; + state.type = XR_TYPE_ACTION_STATE_BOOLEAN; + + OXR(xrGetActionStateBoolean(gAppState.Session, &getInfo, &state)); + return state; +} + +XrActionStateVector2f GetActionStateVector2(XrAction action) { + XrActionStateGetInfo getInfo = {}; + getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO; + getInfo.action = action; + + XrActionStateVector2f state = {}; + state.type = XR_TYPE_ACTION_STATE_VECTOR2F; + + OXR(xrGetActionStateVector2f(gAppState.Session, &getInfo, &state)); + return state; +} + + +//OpenXR +XrPath leftHandPath; +XrPath rightHandPath; +XrAction handPoseLeftAction; +XrAction handPoseRightAction; +XrAction indexLeftAction; +XrAction indexRightAction; +XrAction menuAction; +XrAction buttonAAction; +XrAction buttonBAction; +XrAction buttonXAction; +XrAction buttonYAction; +XrAction gripLeftAction; +XrAction gripRightAction; +XrAction moveOnLeftJoystickAction; +XrAction moveOnRightJoystickAction; +XrAction thumbstickLeftClickAction; +XrAction thumbstickRightClickAction; +XrAction vibrateLeftFeedback; +XrAction vibrateRightFeedback; +XrActionSet runningActionSet; +XrSpace leftControllerAimSpace = XR_NULL_HANDLE; +XrSpace rightControllerAimSpace = XR_NULL_HANDLE; +qboolean inputInitialized = qfalse; +qboolean useSimpleProfile = qfalse; + + +//0 = left, 1 = right +float vibration_channel_duration[2] = {0.0f, 0.0f}; +float vibration_channel_intensity[2] = {0.0f, 0.0f}; + +void JKVR_InitActions( void ) +{ + // Actions + 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); + indexRightAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "index_right", "Index right", 0, NULL); + menuAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "menu_action", "Menu", 0, NULL); + buttonAAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "button_a", "Button A", 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); + moveOnRightJoystickAction = CreateAction(runningActionSet, XR_ACTION_TYPE_VECTOR2F_INPUT, "move_on_right_joy", "Move on right Joy", 0, NULL); + thumbstickLeftClickAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "thumbstick_left", "Thumbstick left", 0, NULL); + thumbstickRightClickAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "thumbstick_right", "Thumbstick right", 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); + + OXR(xrStringToPath(gAppState.Instance, "/user/hand/left", &leftHandPath)); + OXR(xrStringToPath(gAppState.Instance, "/user/hand/right", &rightHandPath)); + handPoseLeftAction = CreateAction(runningActionSet, XR_ACTION_TYPE_POSE_INPUT, "hand_pose_left", NULL, 1, &leftHandPath); + handPoseRightAction = CreateAction(runningActionSet, XR_ACTION_TYPE_POSE_INPUT, "hand_pose_right", NULL, 1, &rightHandPath); + + if (leftControllerAimSpace == XR_NULL_HANDLE) { + leftControllerAimSpace = CreateActionSpace(handPoseLeftAction, leftHandPath); + } + if (rightControllerAimSpace == XR_NULL_HANDLE) { + rightControllerAimSpace = CreateActionSpace(handPoseRightAction, rightHandPath); + } + + XrPath interactionProfilePath = XR_NULL_PATH; + XrPath interactionProfilePathTouch = XR_NULL_PATH; + XrPath interactionProfilePathKHRSimple = XR_NULL_PATH; + + OXR(xrStringToPath(gAppState.Instance, "/interaction_profiles/oculus/touch_controller", &interactionProfilePathTouch)); + OXR(xrStringToPath(gAppState.Instance, "/interaction_profiles/khr/simple_controller", &interactionProfilePathKHRSimple)); + + // Toggle this to force simple as a first choice, otherwise use it as a last resort + if (useSimpleProfile) { + ALOGV("xrSuggestInteractionProfileBindings found bindings for Khronos SIMPLE controller"); + interactionProfilePath = interactionProfilePathKHRSimple; + } else { + // Query Set + XrActionSet queryActionSet = CreateActionSet(1, "query_action_set", "Action Set used to query device caps"); + XrAction dummyAction = CreateAction(queryActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "dummy_action", "Dummy Action", 0, NULL); + + // Map bindings + XrActionSuggestedBinding bindings[1]; + int currBinding = 0; + bindings[currBinding++] = ActionSuggestedBinding(dummyAction, "/user/hand/right/input/system/click"); + + XrInteractionProfileSuggestedBinding suggestedBindings = {}; + suggestedBindings.type = XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING; + suggestedBindings.next = NULL; + suggestedBindings.suggestedBindings = bindings; + suggestedBindings.countSuggestedBindings = currBinding; + + // Try all + suggestedBindings.interactionProfile = interactionProfilePathTouch; + XrResult suggestTouchResult = xrSuggestInteractionProfileBindings(gAppState.Instance, &suggestedBindings); + OXR(suggestTouchResult); + + if (XR_SUCCESS == suggestTouchResult) { + ALOGV("xrSuggestInteractionProfileBindings found bindings for QUEST controller"); + interactionProfilePath = interactionProfilePathTouch; + } + + if (interactionProfilePath == XR_NULL_PATH) { + // Simple as a fallback + bindings[0] = ActionSuggestedBinding(dummyAction, "/user/hand/right/input/select/click"); + suggestedBindings.interactionProfile = interactionProfilePathKHRSimple; + XrResult suggestKHRSimpleResult = xrSuggestInteractionProfileBindings(gAppState.Instance, &suggestedBindings); + OXR(suggestKHRSimpleResult); + if (XR_SUCCESS == suggestKHRSimpleResult) { + ALOGV("xrSuggestInteractionProfileBindings found bindings for Khronos SIMPLE controller"); + interactionProfilePath = interactionProfilePathKHRSimple; + } else { + ALOGE("xrSuggestInteractionProfileBindings did NOT find any bindings."); + assert(qfalse); + } + } + } + + // Action creation + { + // Map bindings + XrActionSuggestedBinding bindings[32]; // large enough for all profiles + int currBinding = 0; + + { + if (interactionProfilePath == interactionProfilePathTouch) { + bindings[currBinding++] = ActionSuggestedBinding(indexLeftAction, "/user/hand/left/input/trigger"); + bindings[currBinding++] = ActionSuggestedBinding(indexRightAction, "/user/hand/right/input/trigger"); + bindings[currBinding++] = ActionSuggestedBinding(menuAction, "/user/hand/left/input/menu/click"); + bindings[currBinding++] = ActionSuggestedBinding(buttonXAction, "/user/hand/left/input/x/click"); + bindings[currBinding++] = ActionSuggestedBinding(buttonYAction, "/user/hand/left/input/y/click"); + bindings[currBinding++] = ActionSuggestedBinding(buttonAAction, "/user/hand/right/input/a/click"); + bindings[currBinding++] = ActionSuggestedBinding(buttonBAction, "/user/hand/right/input/b/click"); + 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(moveOnRightJoystickAction, "/user/hand/right/input/thumbstick"); + bindings[currBinding++] = ActionSuggestedBinding(thumbstickLeftClickAction, "/user/hand/left/input/thumbstick/click"); + bindings[currBinding++] = ActionSuggestedBinding(thumbstickRightClickAction, "/user/hand/right/input/thumbstick/click"); + bindings[currBinding++] = ActionSuggestedBinding(vibrateLeftFeedback, "/user/hand/left/output/haptic"); + bindings[currBinding++] = ActionSuggestedBinding(vibrateRightFeedback, "/user/hand/right/output/haptic"); + bindings[currBinding++] = ActionSuggestedBinding(handPoseLeftAction, "/user/hand/left/input/aim/pose"); + bindings[currBinding++] = ActionSuggestedBinding(handPoseRightAction, "/user/hand/right/input/aim/pose"); + } + + if (interactionProfilePath == interactionProfilePathKHRSimple) { + bindings[currBinding++] = ActionSuggestedBinding(indexLeftAction, "/user/hand/left/input/select/click"); + bindings[currBinding++] = ActionSuggestedBinding(indexRightAction, "/user/hand/right/input/select/click"); + bindings[currBinding++] = ActionSuggestedBinding(buttonAAction, "/user/hand/left/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(vibrateRightFeedback, "/user/hand/right/output/haptic"); + bindings[currBinding++] = ActionSuggestedBinding(handPoseLeftAction, "/user/hand/left/input/aim/pose"); + bindings[currBinding++] = ActionSuggestedBinding(handPoseRightAction, "/user/hand/right/input/aim/pose"); + } + } + + XrInteractionProfileSuggestedBinding suggestedBindings = {}; + suggestedBindings.type = XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING; + suggestedBindings.next = NULL; + suggestedBindings.interactionProfile = interactionProfilePath; + suggestedBindings.suggestedBindings = bindings; + suggestedBindings.countSuggestedBindings = currBinding; + OXR(xrSuggestInteractionProfileBindings(gAppState.Instance, &suggestedBindings)); + + // Enumerate actions + XrPath actionPathsBuffer[32]; + char stringBuffer[256]; + XrAction actionsToEnumerate[] = { + indexLeftAction, + indexRightAction, + menuAction, + buttonAAction, + buttonBAction, + buttonXAction, + buttonYAction, + gripLeftAction, + gripRightAction, + moveOnLeftJoystickAction, + moveOnRightJoystickAction, + thumbstickLeftClickAction, + thumbstickRightClickAction, + vibrateLeftFeedback, + vibrateRightFeedback, + handPoseLeftAction, + handPoseRightAction + }; + for (size_t i = 0; i < sizeof(actionsToEnumerate) / sizeof(actionsToEnumerate[0]); ++i) { + XrBoundSourcesForActionEnumerateInfo enumerateInfo = {}; + enumerateInfo.type = XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO; + enumerateInfo.next = NULL; + enumerateInfo.action = actionsToEnumerate[i]; + + // Get Count + uint32_t countOutput = 0; + OXR(xrEnumerateBoundSourcesForAction( + gAppState.Session, &enumerateInfo, 0 /* request size */, &countOutput, NULL)); + ALOGV( + "xrEnumerateBoundSourcesForAction action=%lld count=%u", + (long long)enumerateInfo.action, + countOutput); + + if (countOutput < 32) { + OXR(xrEnumerateBoundSourcesForAction( + gAppState.Session, &enumerateInfo, 32, &countOutput, actionPathsBuffer)); + for (uint32_t a = 0; a < countOutput; ++a) { + XrInputSourceLocalizedNameGetInfo nameGetInfo = {}; + nameGetInfo.type = XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO; + nameGetInfo.next = NULL; + nameGetInfo.sourcePath = actionPathsBuffer[a]; + nameGetInfo.whichComponents = XR_INPUT_SOURCE_LOCALIZED_NAME_USER_PATH_BIT | + XR_INPUT_SOURCE_LOCALIZED_NAME_INTERACTION_PROFILE_BIT | + XR_INPUT_SOURCE_LOCALIZED_NAME_COMPONENT_BIT; + + uint32_t stringCount = 0u; + OXR(xrGetInputSourceLocalizedName( + gAppState.Session, &nameGetInfo, 0, &stringCount, NULL)); + if (stringCount < 256) { + OXR(xrGetInputSourceLocalizedName( + gAppState.Session, &nameGetInfo, 256, &stringCount, stringBuffer)); + char pathStr[256]; + uint32_t strLen = 0; + OXR(xrPathToString( + gAppState.Instance, + actionPathsBuffer[a], + (uint32_t)sizeof(pathStr), + &strLen, + pathStr)); + ALOGV( + " -> path = %lld `%s` -> `%s`", + (long long)actionPathsBuffer[a], + pathStr, + stringBuffer); + } + } + } + } + } + inputInitialized = qtrue; +} + +void JKVR_SyncActions( void ) +{ + // Attach to session + XrSessionActionSetsAttachInfo attachInfo = {}; + attachInfo.type = XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO; + attachInfo.next = NULL; + attachInfo.countActionSets = 1; + attachInfo.actionSets = &runningActionSet; + OXR(xrAttachSessionActionSets(gAppState.Session, &attachInfo)); + + // sync action data + XrActiveActionSet activeActionSet = {}; + activeActionSet.actionSet = runningActionSet; + activeActionSet.subactionPath = XR_NULL_PATH; + + XrActionsSyncInfo syncInfo = {}; + syncInfo.type = XR_TYPE_ACTIONS_SYNC_INFO; + syncInfo.next = NULL; + syncInfo.countActiveActionSets = 1; + syncInfo.activeActionSets = &activeActionSet; + OXR(xrSyncActions(gAppState.Session, &syncInfo)); + + // query input action states + XrActionStateGetInfo getInfo = {}; + getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO; + getInfo.next = NULL; + getInfo.subactionPath = XR_NULL_PATH; +} + +void JKVR_UpdateControllers( ) +{ + JKVR_SyncActions(); + + //get controller poses + XrAction controller[] = {handPoseLeftAction, handPoseRightAction}; + XrPath subactionPath[] = {leftHandPath, rightHandPath}; + XrSpace controllerSpace[] = {leftControllerAimSpace, rightControllerAimSpace}; + for (int i = 0; i < 2; i++) { + if (ActionPoseIsActive(controller[i], subactionPath[i])) { + XrSpaceVelocity vel = {}; + vel.type = XR_TYPE_SPACE_VELOCITY; + XrSpaceLocation loc = {}; + loc.type = XR_TYPE_SPACE_LOCATION; + loc.next = &vel; + OXR(xrLocateSpace(controllerSpace[i], gAppState.CurrentSpace, gAppState.PredictedDisplayTime, &loc)); + + gAppState.TrackedController[i].Active = (loc.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) != 0; + gAppState.TrackedController[i].Pose = loc.pose; + gAppState.TrackedController[i].Velocity = vel; + } else { + ovrTrackedController_Clear(&gAppState.TrackedController[i]); + } + } + + leftRemoteTracking_new = gAppState.TrackedController[0]; + rightRemoteTracking_new = gAppState.TrackedController[1]; + + + memset(&leftTrackedRemoteState_new, 0, sizeof leftTrackedRemoteState_new); + memset(&rightTrackedRemoteState_new, 0, sizeof rightTrackedRemoteState_new); + + //button mapping + if (GetActionStateBoolean(menuAction).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_Enter; + if (GetActionStateBoolean(buttonXAction).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_X; + if (GetActionStateBoolean(buttonYAction).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_Y; + leftTrackedRemoteState_new.GripTrigger = GetActionStateFloat(gripLeftAction).currentState; + if (leftTrackedRemoteState_new.GripTrigger > 0.5f) leftTrackedRemoteState_new.Buttons |= xrButton_GripTrigger; + if (GetActionStateBoolean(thumbstickLeftClickAction).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_LThumb; + + if (GetActionStateBoolean(buttonAAction).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_A; + if (GetActionStateBoolean(buttonBAction).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_B; + rightTrackedRemoteState_new.GripTrigger = GetActionStateFloat(gripRightAction).currentState; + if (rightTrackedRemoteState_new.GripTrigger > 0.5f) rightTrackedRemoteState_new.Buttons |= xrButton_GripTrigger; + if (GetActionStateBoolean(thumbstickRightClickAction).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_RThumb; + + //index finger click + if (GetActionStateBoolean(indexLeftAction).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_Trigger; + if (GetActionStateBoolean(indexRightAction).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_Trigger; + + //thumbstick + XrActionStateVector2f moveJoystickState; + moveJoystickState = GetActionStateVector2(moveOnLeftJoystickAction); + leftTrackedRemoteState_new.Joystick.x = moveJoystickState.currentState.x; + leftTrackedRemoteState_new.Joystick.y = moveJoystickState.currentState.y; + + moveJoystickState = GetActionStateVector2(moveOnRightJoystickAction); + rightTrackedRemoteState_new.Joystick.x = moveJoystickState.currentState.x; + rightTrackedRemoteState_new.Joystick.y = moveJoystickState.currentState.y; +} + +void JKVR_Vibrate( int duration, int chan, float intensity ) +{ + for (int i = 0; i < 2; ++i) + { + int channel = (i + 1) & chan; + if (channel) + { + if (vibration_channel_duration[i] > 0.0f) + return; + + if (vibration_channel_duration[i] == -1.0f && duration != 0.0f) + return; + + vibration_channel_duration[i] = duration; + vibration_channel_intensity[i] = intensity * vr_haptic_intensity->value; + } + } +} + +void JKVR_processHaptics() { + static float lastFrameTime = 0.0f; + float timestamp = (float)(Sys_Milliseconds( )); + float frametime = timestamp - lastFrameTime; + lastFrameTime = timestamp; + + for (int i = 0; i < 2; ++i) { + if (vibration_channel_duration[i] > 0.0f || + vibration_channel_duration[i] == -1.0f) { + + // fire haptics using output action + XrHapticVibration vibration = {}; + vibration.type = XR_TYPE_HAPTIC_VIBRATION; + vibration.next = NULL; + vibration.amplitude = vibration_channel_intensity[i]; + vibration.duration = ToXrTime(vibration_channel_duration[i]); + vibration.frequency = 3000; + XrHapticActionInfo hapticActionInfo = {}; + hapticActionInfo.type = XR_TYPE_HAPTIC_ACTION_INFO; + hapticActionInfo.next = NULL; + hapticActionInfo.action = i == 0 ? vibrateLeftFeedback : vibrateRightFeedback; + OXR(xrApplyHapticFeedback(gAppState.Session, &hapticActionInfo, (const XrHapticBaseHeader*)&vibration)); + + if (vibration_channel_duration[i] != -1.0f) { + vibration_channel_duration[i] -= frametime; + + if (vibration_channel_duration[i] < 0.0f) { + vibration_channel_duration[i] = 0.0f; + vibration_channel_intensity[i] = 0.0f; + } + } + } else { + // Stop haptics + XrHapticActionInfo hapticActionInfo = {}; + hapticActionInfo.type = XR_TYPE_HAPTIC_ACTION_INFO; + hapticActionInfo.next = NULL; + hapticActionInfo.action = i == 0 ? vibrateLeftFeedback : vibrateRightFeedback; + OXR(xrStopHapticFeedback(gAppState.Session, &hapticActionInfo)); + } + } +} +#endif diff --git a/Projects/Android/jni/JKVR/OpenXrInput_PicoXR.cpp b/Projects/Android/jni/JKVR/OpenXrInput_PicoXR.cpp new file mode 100644 index 0000000..e6ab62a --- /dev/null +++ b/Projects/Android/jni/JKVR/OpenXrInput_PicoXR.cpp @@ -0,0 +1,641 @@ +#include "VrInput.h" +#include "VrCvars.h" + +extern ovrApp gAppState; + +//#ifdef PICO_XR + +XrResult CheckXrResult(XrResult res, const char* originator) { + if (XR_FAILED(res)) { + Com_Printf("error: %s", originator); + } + return res; +} + +#define CHECK_XRCMD(cmd) CheckXrResult(cmd, #cmd); + +#define SIDE_LEFT 0 +#define SIDE_RIGHT 1 +#define SIDE_COUNT 2 + + +XrActionSet actionSet; +XrAction grabAction; +XrAction poseAction; +XrAction vibrateAction; +XrAction quitAction; +/*************************pico******************/ +XrAction touchpadAction; +XrAction AXAction; +XrAction homeAction; +XrAction BYAction; +XrAction backAction; +XrAction sideAction; +XrAction triggerAction; +XrAction joystickAction; +XrAction batteryAction; +//---add new---------- +XrAction AXTouchAction; +XrAction BYTouchAction; +XrAction RockerTouchAction; +XrAction TriggerTouchAction; +XrAction ThumbrestTouchAction; +XrAction GripAction; +//---add new----------zgt +XrAction AAction; +XrAction BAction; +XrAction XAction; +XrAction YAction; +XrAction ATouchAction; +XrAction BTouchAction; +XrAction XTouchAction; +XrAction YTouchAction; +XrAction aimAction; +/*************************pico******************/ +XrSpace aimSpace[SIDE_COUNT]; +XrPath handSubactionPath[SIDE_COUNT]; +XrSpace handSpace[SIDE_COUNT]; + + + +XrActionSuggestedBinding ActionSuggestedBinding(XrAction action, XrPath path) { + XrActionSuggestedBinding asb; + asb.action = action; + asb.binding = path; + return asb; +} + +XrActionStateBoolean GetActionStateBoolean(XrAction action, int hand) { + XrActionStateGetInfo getInfo = {}; + getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO; + getInfo.action = action; + if (hand >= 0) + getInfo.subactionPath = handSubactionPath[hand]; + + XrActionStateBoolean state = {}; + state.type = XR_TYPE_ACTION_STATE_BOOLEAN; + CHECK_XRCMD(xrGetActionStateBoolean(gAppState.Session, &getInfo, &state)); + return state; +} + +XrActionStateFloat GetActionStateFloat(XrAction action, int hand) { + XrActionStateGetInfo getInfo = {}; + getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO; + getInfo.action = action; + if (hand >= 0) + getInfo.subactionPath = handSubactionPath[hand]; + + XrActionStateFloat state = {}; + state.type = XR_TYPE_ACTION_STATE_FLOAT; + CHECK_XRCMD(xrGetActionStateFloat(gAppState.Session, &getInfo, &state)); + return state; +} + +XrActionStateVector2f GetActionStateVector2(XrAction action, int hand) { + XrActionStateGetInfo getInfo = {}; + getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO; + getInfo.action = action; + if (hand >= 0) + getInfo.subactionPath = handSubactionPath[hand]; + + XrActionStateVector2f state = {}; + state.type = XR_TYPE_ACTION_STATE_VECTOR2F; + CHECK_XRCMD(xrGetActionStateVector2f(gAppState.Session, &getInfo, &state)); + return state; +} + +void JKVR_InitActions( void ) +{ + // Create an action set. + { + XrActionSetCreateInfo actionSetInfo = {}; + actionSetInfo.type = XR_TYPE_ACTION_SET_CREATE_INFO; + strcpy(actionSetInfo.actionSetName, "gameplay"); + strcpy(actionSetInfo.localizedActionSetName, "Gameplay"); + actionSetInfo.priority = 0; + CHECK_XRCMD(xrCreateActionSet(gAppState.Instance, &actionSetInfo, &actionSet)); + } + + // Get the XrPath for the left and right hands - we will use them as subaction paths. + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left", &handSubactionPath[SIDE_LEFT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right", &handSubactionPath[SIDE_RIGHT])); + + // Create actions. + { + // Create an input action for grabbing objects with the left and right hands. + XrActionCreateInfo actionInfo = {}; + actionInfo.type = XR_TYPE_ACTION_CREATE_INFO; + actionInfo.actionType = XR_ACTION_TYPE_FLOAT_INPUT; + strcpy(actionInfo.actionName, "grab_object"); + strcpy(actionInfo.localizedActionName, "Grab Object"); + actionInfo.countSubactionPaths = SIDE_COUNT; + actionInfo.subactionPaths = handSubactionPath; + CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &grabAction)); + + // Create an input action getting the left and right hand poses. + actionInfo.actionType = XR_ACTION_TYPE_POSE_INPUT; + strcpy(actionInfo.actionName, "hand_pose"); + strcpy(actionInfo.localizedActionName, "Hand Pose"); + actionInfo.countSubactionPaths = SIDE_COUNT; + actionInfo.subactionPaths = handSubactionPath; + CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &poseAction)); + + actionInfo.actionType = XR_ACTION_TYPE_POSE_INPUT; + strcpy(actionInfo.actionName, "aim_pose"); + strcpy(actionInfo.localizedActionName, "Aim Pose"); + actionInfo.countSubactionPaths = SIDE_COUNT; + actionInfo.subactionPaths = handSubactionPath; + CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &aimAction)); + + // Create output actions for vibrating the left and right controller. + actionInfo.actionType = XR_ACTION_TYPE_VIBRATION_OUTPUT; + strcpy(actionInfo.actionName, "vibrate_hand"); + strcpy(actionInfo.localizedActionName, "Vibrate Hand"); + actionInfo.countSubactionPaths = SIDE_COUNT; + actionInfo.subactionPaths = handSubactionPath; + CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &vibrateAction)); + + // Create input actions for quitting the session using the left and right controller. + // Since it doesn't matter which hand did this, we do not specify subaction paths for it. + // We will just suggest bindings for both hands, where possible. + actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT; + strcpy(actionInfo.actionName, "quit_session"); + strcpy(actionInfo.localizedActionName, "Quit Session"); + actionInfo.countSubactionPaths = SIDE_COUNT; + actionInfo.subactionPaths = handSubactionPath; + CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &quitAction)); + /**********************************pico***************************************/ + // Create input actions for toucpad key using the left and right controller. + actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT; + strcpy(actionInfo.actionName, "touchpad"); + strcpy(actionInfo.localizedActionName, "Touchpad"); + actionInfo.countSubactionPaths = SIDE_COUNT; + actionInfo.subactionPaths = handSubactionPath; + CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &touchpadAction)); + + actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT; + strcpy(actionInfo.actionName, "axkey"); + strcpy(actionInfo.localizedActionName, "AXkey"); + actionInfo.countSubactionPaths = SIDE_COUNT; + actionInfo.subactionPaths = handSubactionPath; + CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &AXAction)); + + + actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT; + strcpy(actionInfo.actionName, "homekey"); + strcpy(actionInfo.localizedActionName, "Homekey"); + actionInfo.countSubactionPaths = SIDE_COUNT; + actionInfo.subactionPaths = handSubactionPath; + CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &homeAction)); + + actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT; + strcpy(actionInfo.actionName, "bykey"); + strcpy(actionInfo.localizedActionName, "BYkey"); + actionInfo.countSubactionPaths = SIDE_COUNT; + actionInfo.subactionPaths = handSubactionPath; + CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &BYAction)); + + actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT; + strcpy(actionInfo.actionName, "backkey"); + strcpy(actionInfo.localizedActionName, "Backkey"); + actionInfo.countSubactionPaths = SIDE_COUNT; + actionInfo.subactionPaths = handSubactionPath; + CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &backAction)); + + actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT; + strcpy(actionInfo.actionName, "sidekey"); + strcpy(actionInfo.localizedActionName, "Sidekey"); + actionInfo.countSubactionPaths = SIDE_COUNT; + actionInfo.subactionPaths = handSubactionPath; + CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &sideAction)); + + actionInfo.actionType = XR_ACTION_TYPE_FLOAT_INPUT; + strcpy(actionInfo.actionName, "trigger"); + strcpy(actionInfo.localizedActionName, "Trigger"); + actionInfo.countSubactionPaths = SIDE_COUNT; + actionInfo.subactionPaths = handSubactionPath; + CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &triggerAction)); + + actionInfo.actionType = XR_ACTION_TYPE_VECTOR2F_INPUT; + strcpy(actionInfo.actionName, "joystick"); + strcpy(actionInfo.localizedActionName, "Joystick"); + actionInfo.countSubactionPaths = SIDE_COUNT; + actionInfo.subactionPaths = handSubactionPath; + CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &joystickAction)); + + actionInfo.actionType = XR_ACTION_TYPE_FLOAT_INPUT; + strcpy(actionInfo.actionName, "battery"); + strcpy(actionInfo.localizedActionName, "battery"); + actionInfo.countSubactionPaths = SIDE_COUNT; + actionInfo.subactionPaths = handSubactionPath; + CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &batteryAction)); + //------------------------add new--------------------------------- + actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT; + strcpy(actionInfo.actionName, "axtouch"); + strcpy(actionInfo.localizedActionName, "AXtouch"); + actionInfo.countSubactionPaths = SIDE_COUNT; + actionInfo.subactionPaths = handSubactionPath; + CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &AXTouchAction)); + + actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT; + strcpy(actionInfo.actionName, "bytouch"); + strcpy(actionInfo.localizedActionName, "BYtouch"); + actionInfo.countSubactionPaths = SIDE_COUNT; + actionInfo.subactionPaths = handSubactionPath; + CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &BYTouchAction)); + + actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT; + strcpy(actionInfo.actionName, "rockertouch"); + strcpy(actionInfo.localizedActionName, "Rockertouch"); + actionInfo.countSubactionPaths = SIDE_COUNT; + actionInfo.subactionPaths = handSubactionPath; + CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &RockerTouchAction)); + + actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT; + strcpy(actionInfo.actionName, "triggertouch"); + strcpy(actionInfo.localizedActionName, "Triggertouch"); + actionInfo.countSubactionPaths = SIDE_COUNT; + actionInfo.subactionPaths = handSubactionPath; + CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &TriggerTouchAction)); + + actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT; + strcpy(actionInfo.actionName, "thumbresttouch"); + strcpy(actionInfo.localizedActionName, "Thumbresttouch"); + actionInfo.countSubactionPaths = SIDE_COUNT; + actionInfo.subactionPaths = handSubactionPath; + CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &ThumbrestTouchAction)); + + actionInfo.actionType = XR_ACTION_TYPE_FLOAT_INPUT; + strcpy(actionInfo.actionName, "gripvalue"); + strcpy(actionInfo.localizedActionName, "GripValue"); + actionInfo.countSubactionPaths = SIDE_COUNT; + actionInfo.subactionPaths = handSubactionPath; + CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &GripAction)); + + //--------------add new----------zgt + actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT; + strcpy(actionInfo.actionName, "akey"); + strcpy(actionInfo.localizedActionName, "Akey"); + actionInfo.countSubactionPaths = SIDE_COUNT; + actionInfo.subactionPaths = handSubactionPath; + CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &AAction)); + + actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT; + strcpy(actionInfo.actionName, "bkey"); + strcpy(actionInfo.localizedActionName, "Bkey"); + actionInfo.countSubactionPaths = SIDE_COUNT; + actionInfo.subactionPaths = handSubactionPath; + CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &BAction)); + + actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT; + strcpy(actionInfo.actionName, "xkey"); + strcpy(actionInfo.localizedActionName, "Xkey"); + actionInfo.countSubactionPaths = SIDE_COUNT; + actionInfo.subactionPaths = handSubactionPath; + CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &XAction)); + + actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT; + strcpy(actionInfo.actionName, "ykey"); + strcpy(actionInfo.localizedActionName, "Ykey"); + actionInfo.countSubactionPaths = SIDE_COUNT; + actionInfo.subactionPaths = handSubactionPath; + CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &YAction)); + + actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT; + strcpy(actionInfo.actionName, "atouch"); + strcpy(actionInfo.localizedActionName, "Atouch"); + actionInfo.countSubactionPaths = SIDE_COUNT; + actionInfo.subactionPaths = handSubactionPath; + CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &ATouchAction)); + + actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT; + strcpy(actionInfo.actionName, "btouch"); + strcpy(actionInfo.localizedActionName, "Btouch"); + actionInfo.countSubactionPaths = SIDE_COUNT; + actionInfo.subactionPaths = handSubactionPath; + CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &BTouchAction)); + + actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT; + strcpy(actionInfo.actionName, "xtouch"); + strcpy(actionInfo.localizedActionName, "Xtouch"); + actionInfo.countSubactionPaths = SIDE_COUNT; + actionInfo.subactionPaths = handSubactionPath; + CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &XTouchAction)); + + actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT; + strcpy(actionInfo.actionName, "ytouch"); + strcpy(actionInfo.localizedActionName, "Ytouch"); + actionInfo.countSubactionPaths = SIDE_COUNT; + actionInfo.subactionPaths = handSubactionPath; + CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &YTouchAction)); + /**********************************pico***************************************/ + + + } + + XrPath selectPath[SIDE_COUNT]; + XrPath squeezeValuePath[SIDE_COUNT]; + XrPath squeezeClickPath[SIDE_COUNT]; + XrPath posePath[SIDE_COUNT]; + XrPath hapticPath[SIDE_COUNT]; + XrPath menuClickPath[SIDE_COUNT]; + XrPath systemPath[SIDE_COUNT]; + XrPath thumbrestPath[SIDE_COUNT]; + XrPath triggerTouchPath[SIDE_COUNT]; + XrPath triggerValuePath[SIDE_COUNT]; + XrPath thumbstickClickPath[SIDE_COUNT]; + XrPath thumbstickTouchPath[SIDE_COUNT]; + XrPath thumbstickPosPath[SIDE_COUNT]; + XrPath aimPath[SIDE_COUNT]; + + /**************************pico************************************/ + XrPath touchpadPath[SIDE_COUNT]; + XrPath AXValuePath[SIDE_COUNT]; + XrPath homeClickPath[SIDE_COUNT]; + XrPath BYValuePath[SIDE_COUNT]; + XrPath backPath[SIDE_COUNT]; + XrPath sideClickPath[SIDE_COUNT]; + XrPath triggerPath[SIDE_COUNT]; + XrPath joystickPath[SIDE_COUNT]; + XrPath batteryPath[SIDE_COUNT]; + //--------------add new---------- + XrPath GripPath[SIDE_COUNT]; + XrPath AXTouchPath[SIDE_COUNT]; + XrPath BYTouchPath[SIDE_COUNT]; + XrPath RockerTouchPath[SIDE_COUNT]; + XrPath TriggerTouchPath[SIDE_COUNT]; + XrPath ThumbresetTouchPath[SIDE_COUNT]; + //--------------add new----------zgt + XrPath AValuePath[SIDE_COUNT]; + XrPath BValuePath[SIDE_COUNT]; + XrPath XValuePath[SIDE_COUNT]; + XrPath YValuePath[SIDE_COUNT]; + XrPath ATouchPath[SIDE_COUNT]; + XrPath BTouchPath[SIDE_COUNT]; + XrPath XTouchPath[SIDE_COUNT]; + XrPath YTouchPath[SIDE_COUNT]; + /**************************pico************************************/ + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/select/click", &selectPath[SIDE_LEFT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/select/click", &selectPath[SIDE_RIGHT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/menu/click", &menuClickPath[SIDE_LEFT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/menu/click", &menuClickPath[SIDE_RIGHT])); + + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/squeeze/value", &squeezeValuePath[SIDE_LEFT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/squeeze/value", &squeezeValuePath[SIDE_RIGHT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/squeeze/click", &squeezeClickPath[SIDE_LEFT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/squeeze/click", &squeezeClickPath[SIDE_RIGHT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/grip/pose", &posePath[SIDE_LEFT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/grip/pose", &posePath[SIDE_RIGHT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/aim/pose", &aimPath[SIDE_LEFT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/aim/pose", &aimPath[SIDE_RIGHT])); + + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/output/haptic", &hapticPath[SIDE_LEFT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/output/haptic", &hapticPath[SIDE_RIGHT])); + + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/trigger/touch", &triggerTouchPath[SIDE_LEFT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/trigger/touch", &triggerTouchPath[SIDE_RIGHT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/trigger/value", &triggerValuePath[SIDE_LEFT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/trigger/value", &triggerValuePath[SIDE_RIGHT])); + + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/thumbstick/click", &thumbstickClickPath[SIDE_LEFT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/thumbstick/click", &thumbstickClickPath[SIDE_RIGHT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/thumbstick/touch", &thumbstickTouchPath[SIDE_LEFT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/thumbstick/touch", &thumbstickTouchPath[SIDE_RIGHT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/thumbstick", &thumbstickPosPath[SIDE_LEFT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/thumbstick", &thumbstickPosPath[SIDE_RIGHT])); + + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/system/click", &systemPath[SIDE_LEFT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/system/click", &systemPath[SIDE_RIGHT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/thumbrest/touch", &thumbrestPath[SIDE_LEFT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/thumbrest/touch", &thumbrestPath[SIDE_RIGHT])); + + /**************************pico************************************/ + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/back/click", &backPath[SIDE_LEFT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/back/click", &backPath[SIDE_RIGHT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/battery/value", &batteryPath[SIDE_LEFT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/battery/value", &batteryPath[SIDE_RIGHT])); + + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/x/click", &XValuePath[SIDE_LEFT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/y/click", &YValuePath[SIDE_LEFT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/a/click", &AValuePath[SIDE_RIGHT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/b/click", &BValuePath[SIDE_RIGHT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/x/touch", &XTouchPath[SIDE_LEFT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/y/touch", &YTouchPath[SIDE_LEFT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/a/touch", &ATouchPath[SIDE_RIGHT])); + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/b/touch", &BTouchPath[SIDE_RIGHT])); + /**************************pico************************************/ + XrActionSuggestedBinding bindings[128]; + int currBinding = 0; + + // Suggest bindings for the Pico Neo 3 controller + { + XrPath picoMixedRealityInteractionProfilePath; + CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/interaction_profiles/pico/neo3_controller", + &picoMixedRealityInteractionProfilePath)); + + bindings[currBinding++] = ActionSuggestedBinding(touchpadAction, thumbstickClickPath[SIDE_LEFT]); + bindings[currBinding++] = ActionSuggestedBinding(touchpadAction, thumbstickClickPath[SIDE_RIGHT]); + bindings[currBinding++] = ActionSuggestedBinding(joystickAction, thumbstickPosPath[SIDE_LEFT]); + bindings[currBinding++] = ActionSuggestedBinding(joystickAction, thumbstickPosPath[SIDE_RIGHT]); + bindings[currBinding++] = ActionSuggestedBinding(RockerTouchAction, thumbstickTouchPath[SIDE_LEFT]); + bindings[currBinding++] = ActionSuggestedBinding(RockerTouchAction, thumbstickTouchPath[SIDE_RIGHT]); + + bindings[currBinding++] = ActionSuggestedBinding(triggerAction, triggerValuePath[SIDE_LEFT]); + bindings[currBinding++] = ActionSuggestedBinding(triggerAction, triggerValuePath[SIDE_RIGHT]); + bindings[currBinding++] = ActionSuggestedBinding(TriggerTouchAction, triggerTouchPath[SIDE_LEFT]); + bindings[currBinding++] = ActionSuggestedBinding(TriggerTouchAction, triggerTouchPath[SIDE_RIGHT]); + + bindings[currBinding++] = ActionSuggestedBinding(sideAction, squeezeClickPath[SIDE_LEFT]); + bindings[currBinding++] = ActionSuggestedBinding(sideAction, squeezeClickPath[SIDE_RIGHT]); + bindings[currBinding++] = ActionSuggestedBinding(GripAction, squeezeValuePath[SIDE_LEFT]); + bindings[currBinding++] = ActionSuggestedBinding(GripAction, squeezeValuePath[SIDE_RIGHT]); + bindings[currBinding++] = ActionSuggestedBinding(poseAction, posePath[SIDE_LEFT]); + bindings[currBinding++] = ActionSuggestedBinding(poseAction, posePath[SIDE_RIGHT]); + + bindings[currBinding++] = ActionSuggestedBinding(homeAction, systemPath[SIDE_LEFT]); + bindings[currBinding++] = ActionSuggestedBinding(homeAction, systemPath[SIDE_RIGHT]); + bindings[currBinding++] = ActionSuggestedBinding(backAction, backPath[SIDE_LEFT]); + bindings[currBinding++] = ActionSuggestedBinding(backAction, backPath[SIDE_RIGHT]); + bindings[currBinding++] = ActionSuggestedBinding(batteryAction, batteryPath[SIDE_LEFT]); + bindings[currBinding++] = ActionSuggestedBinding(batteryAction, batteryPath[SIDE_RIGHT]); + + bindings[currBinding++] = ActionSuggestedBinding(ThumbrestTouchAction, thumbrestPath[SIDE_LEFT]); + bindings[currBinding++] = ActionSuggestedBinding(ThumbrestTouchAction, thumbrestPath[SIDE_RIGHT]); + bindings[currBinding++] = ActionSuggestedBinding(vibrateAction, hapticPath[SIDE_LEFT]); + bindings[currBinding++] = ActionSuggestedBinding(vibrateAction, hapticPath[SIDE_RIGHT]); + + bindings[currBinding++] = ActionSuggestedBinding(XTouchAction, XTouchPath[SIDE_LEFT]); + bindings[currBinding++] = ActionSuggestedBinding(YTouchAction, YTouchPath[SIDE_LEFT]); + bindings[currBinding++] = ActionSuggestedBinding(ATouchAction, ATouchPath[SIDE_RIGHT]); + bindings[currBinding++] = ActionSuggestedBinding(BTouchAction, BTouchPath[SIDE_RIGHT]); + bindings[currBinding++] = ActionSuggestedBinding(XAction, XValuePath[SIDE_LEFT]); + bindings[currBinding++] = ActionSuggestedBinding(YAction, YValuePath[SIDE_LEFT]); + bindings[currBinding++] = ActionSuggestedBinding(AAction, AValuePath[SIDE_RIGHT]); + bindings[currBinding++] = ActionSuggestedBinding(BAction, BValuePath[SIDE_RIGHT]); + bindings[currBinding++] = ActionSuggestedBinding(aimAction, aimPath[SIDE_LEFT]); + bindings[currBinding++] = ActionSuggestedBinding(aimAction, aimPath[SIDE_RIGHT]); + + XrInteractionProfileSuggestedBinding suggestedBindings = {}; + suggestedBindings.type = XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING; + suggestedBindings.interactionProfile = picoMixedRealityInteractionProfilePath; + suggestedBindings.suggestedBindings = bindings; + suggestedBindings.countSuggestedBindings = currBinding; + CHECK_XRCMD(xrSuggestInteractionProfileBindings(gAppState.Instance, &suggestedBindings)); + } + + XrActionSpaceCreateInfo actionSpaceInfo = {}; + actionSpaceInfo.type = XR_TYPE_ACTION_SPACE_CREATE_INFO; + actionSpaceInfo.action = poseAction; + actionSpaceInfo.poseInActionSpace.orientation.w = 1.f; + actionSpaceInfo.subactionPath = handSubactionPath[SIDE_LEFT]; + CHECK_XRCMD(xrCreateActionSpace(gAppState.Session, &actionSpaceInfo, &handSpace[SIDE_LEFT])); + actionSpaceInfo.subactionPath = handSubactionPath[SIDE_RIGHT]; + CHECK_XRCMD(xrCreateActionSpace(gAppState.Session, &actionSpaceInfo, &handSpace[SIDE_RIGHT])); + actionSpaceInfo.action = aimAction; + actionSpaceInfo.poseInActionSpace.orientation.w = 1.f; + actionSpaceInfo.subactionPath = handSubactionPath[SIDE_LEFT]; + CHECK_XRCMD(xrCreateActionSpace(gAppState.Session, &actionSpaceInfo, &aimSpace[SIDE_LEFT])); + actionSpaceInfo.subactionPath = handSubactionPath[SIDE_RIGHT]; + CHECK_XRCMD(xrCreateActionSpace(gAppState.Session, &actionSpaceInfo, &aimSpace[SIDE_RIGHT])); + + XrSessionActionSetsAttachInfo attachInfo = {}; + attachInfo.type = XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO; + attachInfo.countActionSets = 1; + attachInfo.actionSets = &actionSet; + CHECK_XRCMD(xrAttachSessionActionSets(gAppState.Session, &attachInfo)); +} + +void JKVR_SyncActions( void ) +{ + XrActiveActionSet activeActionSet = {}; + activeActionSet.actionSet = actionSet; + activeActionSet.subactionPath = XR_NULL_PATH; + XrActionsSyncInfo syncInfo; + syncInfo.type = XR_TYPE_ACTIONS_SYNC_INFO; + syncInfo.countActiveActionSets = 1; + syncInfo.activeActionSets = &activeActionSet; + CHECK_XRCMD(xrSyncActions(gAppState.Session, &syncInfo)); +} + +void JKVR_UpdateControllers( ) +{ + JKVR_SyncActions(); + + //get controller poses + for (int i = 0; i < 2; i++) { + XrSpaceVelocity vel = {}; + vel.type = XR_TYPE_SPACE_VELOCITY; + XrSpaceLocation loc = {}; + loc.type = XR_TYPE_SPACE_LOCATION; + loc.next = &vel; + XrResult res = xrLocateSpace(aimSpace[i], gAppState.CurrentSpace, gAppState.PredictedDisplayTime, &loc); + if (res != XR_SUCCESS) { + Com_Printf("xrLocateSpace error: %d", (int)res); + } + + gAppState.TrackedController[i].Active = (loc.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) != 0; + gAppState.TrackedController[i].Pose = loc.pose; + gAppState.TrackedController[i].Velocity = vel; + } + + leftRemoteTracking_new = gAppState.TrackedController[0]; + rightRemoteTracking_new = gAppState.TrackedController[1]; + + + + //button mapping + leftTrackedRemoteState_new.Buttons = 0; + if (GetActionStateBoolean(backAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_Enter; + if (GetActionStateBoolean(XAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_X; + if (GetActionStateBoolean(YAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_Y; + if (GetActionStateBoolean(sideAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_GripTrigger; + if (GetActionStateBoolean(touchpadAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_LThumb; + if (GetActionStateFloat(triggerAction, SIDE_LEFT).currentState > 0.5f) leftTrackedRemoteState_new.Buttons |= xrButton_Trigger; + + rightTrackedRemoteState_new.Buttons = 0; + if (GetActionStateBoolean(backAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_Enter; + if (GetActionStateBoolean(AAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_A; + if (GetActionStateBoolean(BAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_B; + if (GetActionStateBoolean(sideAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_GripTrigger; + if (GetActionStateBoolean(touchpadAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_RThumb; + if (GetActionStateFloat(triggerAction, SIDE_RIGHT).currentState > 0.5f) rightTrackedRemoteState_new.Buttons |= xrButton_Trigger; + + //thumbstick + XrActionStateVector2f moveJoystickState; + moveJoystickState = GetActionStateVector2(joystickAction, SIDE_LEFT); + leftTrackedRemoteState_new.Joystick.x = moveJoystickState.currentState.x; + leftTrackedRemoteState_new.Joystick.y = moveJoystickState.currentState.y; + + moveJoystickState = GetActionStateVector2(joystickAction, SIDE_RIGHT); + rightTrackedRemoteState_new.Joystick.x = moveJoystickState.currentState.x; + rightTrackedRemoteState_new.Joystick.y = moveJoystickState.currentState.y; +} + + +//0 = left, 1 = right +float vibration_channel_duration[2] = {0.0f, 0.0f}; +float vibration_channel_intensity[2] = {0.0f, 0.0f}; + +void JKVR_Vibrate( int duration, int chan, float intensity ) +{ + for (int i = 0; i < 2; ++i) + { + int channel = (i + 1) & chan; + if (channel) + { + if (vibration_channel_duration[i] > 0.0f) + return; + + if (vibration_channel_duration[i] == -1.0f && duration != 0.0f) + return; + + vibration_channel_duration[i] = duration; + vibration_channel_intensity[i] = intensity * vr_haptic_intensity->value; + } + } +} + +void JKVR_processHaptics() { + static float lastFrameTime = 0.0f; + float timestamp = (float)(Sys_Milliseconds( )); + float frametime = timestamp - lastFrameTime; + lastFrameTime = timestamp; + + for (int i = 0; i < 2; ++i) { + if (vibration_channel_duration[i] > 0.0f || + vibration_channel_duration[i] == -1.0f) { + + // fire haptics using output action + XrHapticVibration vibration = {}; + vibration.type = XR_TYPE_HAPTIC_VIBRATION; + vibration.next = NULL; + vibration.amplitude = vibration_channel_intensity[i]; + vibration.duration = ToXrTime(vibration_channel_duration[i]); + vibration.frequency = 3000; + XrHapticActionInfo hapticActionInfo = {}; + hapticActionInfo.type = XR_TYPE_HAPTIC_ACTION_INFO; + hapticActionInfo.next = NULL; + hapticActionInfo.action = vibrateAction; + hapticActionInfo.subactionPath = handSubactionPath[i]; + OXR(xrApplyHapticFeedback(gAppState.Session, &hapticActionInfo, (const XrHapticBaseHeader*)&vibration)); + + if (vibration_channel_duration[i] != -1.0f) { + vibration_channel_duration[i] -= frametime; + + if (vibration_channel_duration[i] < 0.0f) { + vibration_channel_duration[i] = 0.0f; + vibration_channel_intensity[i] = 0.0f; + } + } + } else { + // Stop haptics + XrHapticActionInfo hapticActionInfo = {}; + hapticActionInfo.type = XR_TYPE_HAPTIC_ACTION_INFO; + hapticActionInfo.next = NULL; + hapticActionInfo.action = vibrateAction; + hapticActionInfo.subactionPath = handSubactionPath[i]; + OXR(xrStopHapticFeedback(gAppState.Session, &hapticActionInfo)); + } + } +} +//#endif diff --git a/Projects/Android/jni/JKVR/VrCommon.h b/Projects/Android/jni/JKVR/VrCommon.h index a3ec196..f4a6dbf 100644 --- a/Projects/Android/jni/JKVR/VrCommon.h +++ b/Projects/Android/jni/JKVR/VrCommon.h @@ -11,7 +11,6 @@ #include #include #include -#include #include #include @@ -36,31 +35,6 @@ #define ALOGV(...) #endif -extern XrPath leftHandPath; -extern XrPath rightHandPath; -extern XrAction handPoseLeftAction; -extern XrAction handPoseRightAction; -extern XrAction indexLeftAction; -extern XrAction indexRightAction; -extern XrAction menuAction; -extern XrAction buttonAAction; -extern XrAction buttonBAction; -extern XrAction buttonXAction; -extern XrAction buttonYAction; -extern XrAction gripLeftAction; -extern XrAction gripRightAction; -extern XrAction moveOnLeftJoystickAction; -extern XrAction moveOnRightJoystickAction; -extern XrAction thumbstickLeftClickAction; -extern XrAction thumbstickRightClickAction; -extern XrAction vibrateLeftFeedback; -extern XrAction vibrateRightFeedback; -extern XrActionSet runningActionSet; -extern XrSpace leftControllerAimSpace; -extern XrSpace rightControllerAimSpace; -extern qboolean inputInitialized; -extern qboolean useSimpleProfile; - enum { ovrMaxLayerCount = 1 }; enum { ovrMaxNumEyes = 2 }; @@ -206,6 +180,7 @@ typedef struct ANativeWindow* NativeWindow; bool Resumed; bool Focused; + bool FrameSetup; XrInstance Instance; XrSession Session; @@ -274,13 +249,6 @@ void handleTrackedControllerButton(ovrInputStateTrackedRemote * trackedRemoteSta void interactWithTouchScreen(bool reset, ovrInputStateTrackedRemote *newState, ovrInputStateTrackedRemote *oldState); int GetRefresh(); -//XrAction stuff -bool ActionPoseIsActive(XrAction action, XrPath subactionPath); -XrActionStateBoolean GetActionStateBoolean(XrAction action); -XrActionStateFloat GetActionStateFloat(XrAction action); -XrActionStateVector2f GetActionStateVector2(XrAction action); - - void VR_Recenter(); //Called from engine code @@ -297,17 +265,15 @@ void JKVR_HapticEnable(); void JKVR_HapticDisable(); void JKVR_processMessageQueue(); void JKVR_FrameSetup(); -void JKVR_setUseScreenLayer(bool use); void JKVR_processHaptics(); void JKVR_getHMDOrientation( ); void JKVR_getTrackedRemotesOrientation(); +void JKVR_updateProjections(); +void JKVR_UpdateControllers( ); bool JKVR_useScreenLayer(); void JKVR_prepareEyeBuffer(int eye ); void JKVR_finishEyeBuffer(int eye ); void JKVR_submitFrame(); -void GPUDropSync(); -void GPUWaitSync(); - #endif //vrcommon_h \ No newline at end of file diff --git a/Projects/Android/jni/JKVR/VrInputCommon.cpp b/Projects/Android/jni/JKVR/VrInputCommon.cpp index 84082ff..8f59aa6 100644 --- a/Projects/Android/jni/JKVR/VrInputCommon.cpp +++ b/Projects/Android/jni/JKVR/VrInputCommon.cpp @@ -1,6 +1,5 @@ /************************************************************************************ -Filename : VrInputRight.c Content : Handles common controller input functionality Created : September 2019 Authors : Simon Brown @@ -56,411 +55,6 @@ vr_client_info_t vr; extern ovrApp gAppState; -//OpenXR -XrPath leftHandPath; -XrPath rightHandPath; -XrAction handPoseLeftAction; -XrAction handPoseRightAction; -XrAction indexLeftAction; -XrAction indexRightAction; -XrAction menuAction; -XrAction buttonAAction; -XrAction buttonBAction; -XrAction buttonXAction; -XrAction buttonYAction; -XrAction gripLeftAction; -XrAction gripRightAction; -XrAction moveOnLeftJoystickAction; -XrAction moveOnRightJoystickAction; -XrAction thumbstickLeftClickAction; -XrAction thumbstickRightClickAction; -XrAction vibrateLeftFeedback; -XrAction vibrateRightFeedback; -XrActionSet runningActionSet; -XrSpace leftControllerAimSpace = XR_NULL_HANDLE; -XrSpace rightControllerAimSpace = XR_NULL_HANDLE; -qboolean inputInitialized = qfalse; -qboolean useSimpleProfile = qfalse; - - - -XrSpace CreateActionSpace(XrAction poseAction, XrPath subactionPath) { - XrActionSpaceCreateInfo asci = {}; - asci.type = XR_TYPE_ACTION_SPACE_CREATE_INFO; - asci.action = poseAction; - asci.poseInActionSpace.orientation.w = 1.0f; - asci.subactionPath = subactionPath; - XrSpace actionSpace = XR_NULL_HANDLE; - OXR(xrCreateActionSpace(gAppState.Session, &asci, &actionSpace)); - return actionSpace; -} - -XrActionSuggestedBinding ActionSuggestedBinding(XrAction action, const char* bindingString) { - XrActionSuggestedBinding asb; - asb.action = action; - XrPath bindingPath; - OXR(xrStringToPath(gAppState.Instance, bindingString, &bindingPath)); - asb.binding = bindingPath; - return asb; -} - -XrActionSet CreateActionSet(int priority, const char* name, const char* localizedName) { - XrActionSetCreateInfo asci = {}; - asci.type = XR_TYPE_ACTION_SET_CREATE_INFO; - asci.next = NULL; - asci.priority = priority; - strcpy(asci.actionSetName, name); - strcpy(asci.localizedActionSetName, localizedName); - XrActionSet actionSet = XR_NULL_HANDLE; - OXR(xrCreateActionSet(gAppState.Instance, &asci, &actionSet)); - return actionSet; -} - -XrAction CreateAction( - XrActionSet actionSet, - XrActionType type, - const char* actionName, - const char* localizedName, - int countSubactionPaths, - XrPath* subactionPaths) { - ALOGV("CreateAction %s, %" PRIi32, actionName, countSubactionPaths); - - XrActionCreateInfo aci = {}; - aci.type = XR_TYPE_ACTION_CREATE_INFO; - aci.next = NULL; - aci.actionType = type; - if (countSubactionPaths > 0) { - aci.countSubactionPaths = countSubactionPaths; - aci.subactionPaths = subactionPaths; - } - strcpy(aci.actionName, actionName); - strcpy(aci.localizedActionName, localizedName ? localizedName : actionName); - XrAction action = XR_NULL_HANDLE; - OXR(xrCreateAction(actionSet, &aci, &action)); - return action; -} - -bool ActionPoseIsActive(XrAction action, XrPath subactionPath) { - XrActionStateGetInfo getInfo = {}; - getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO; - getInfo.action = action; - getInfo.subactionPath = subactionPath; - - XrActionStatePose state = {}; - state.type = XR_TYPE_ACTION_STATE_POSE; - OXR(xrGetActionStatePose(gAppState.Session, &getInfo, &state)); - return state.isActive != XR_FALSE; -} - -XrActionStateFloat GetActionStateFloat(XrAction action) { - XrActionStateGetInfo getInfo = {}; - getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO; - getInfo.action = action; - - XrActionStateFloat state = {}; - state.type = XR_TYPE_ACTION_STATE_FLOAT; - - OXR(xrGetActionStateFloat(gAppState.Session, &getInfo, &state)); - return state; -} - -XrActionStateBoolean GetActionStateBoolean(XrAction action) { - XrActionStateGetInfo getInfo = {}; - getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO; - getInfo.action = action; - - XrActionStateBoolean state = {}; - state.type = XR_TYPE_ACTION_STATE_BOOLEAN; - - OXR(xrGetActionStateBoolean(gAppState.Session, &getInfo, &state)); - return state; -} - -XrActionStateVector2f GetActionStateVector2(XrAction action) { - XrActionStateGetInfo getInfo = {}; - getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO; - getInfo.action = action; - - XrActionStateVector2f state = {}; - state.type = XR_TYPE_ACTION_STATE_VECTOR2F; - - OXR(xrGetActionStateVector2f(gAppState.Session, &getInfo, &state)); - return state; -} - -void JKVR_InitActions( void ) -{ - // Actions - 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); - indexRightAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "index_right", "Index right", 0, NULL); - menuAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "menu_action", "Menu", 0, NULL); - buttonAAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "button_a", "Button A", 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); - moveOnRightJoystickAction = CreateAction(runningActionSet, XR_ACTION_TYPE_VECTOR2F_INPUT, "move_on_right_joy", "Move on right Joy", 0, NULL); - thumbstickLeftClickAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "thumbstick_left", "Thumbstick left", 0, NULL); - thumbstickRightClickAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "thumbstick_right", "Thumbstick right", 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); - - OXR(xrStringToPath(gAppState.Instance, "/user/hand/left", &leftHandPath)); - OXR(xrStringToPath(gAppState.Instance, "/user/hand/right", &rightHandPath)); - handPoseLeftAction = CreateAction(runningActionSet, XR_ACTION_TYPE_POSE_INPUT, "hand_pose_left", NULL, 1, &leftHandPath); - handPoseRightAction = CreateAction(runningActionSet, XR_ACTION_TYPE_POSE_INPUT, "hand_pose_right", NULL, 1, &rightHandPath); - - if (leftControllerAimSpace == XR_NULL_HANDLE) { - leftControllerAimSpace = CreateActionSpace(handPoseLeftAction, leftHandPath); - } - if (rightControllerAimSpace == XR_NULL_HANDLE) { - rightControllerAimSpace = CreateActionSpace(handPoseRightAction, rightHandPath); - } - - XrPath interactionProfilePath = XR_NULL_PATH; - XrPath interactionProfilePathTouch = XR_NULL_PATH; - XrPath interactionProfilePathKHRSimple = XR_NULL_PATH; - - OXR(xrStringToPath(gAppState.Instance, "/interaction_profiles/oculus/touch_controller", &interactionProfilePathTouch)); - OXR(xrStringToPath(gAppState.Instance, "/interaction_profiles/khr/simple_controller", &interactionProfilePathKHRSimple)); - - // Toggle this to force simple as a first choice, otherwise use it as a last resort - if (useSimpleProfile) { - ALOGV("xrSuggestInteractionProfileBindings found bindings for Khronos SIMPLE controller"); - interactionProfilePath = interactionProfilePathKHRSimple; - } else { - // Query Set - XrActionSet queryActionSet = CreateActionSet(1, "query_action_set", "Action Set used to query device caps"); - XrAction dummyAction = CreateAction(queryActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "dummy_action", "Dummy Action", 0, NULL); - - // Map bindings - XrActionSuggestedBinding bindings[1]; - int currBinding = 0; - bindings[currBinding++] = ActionSuggestedBinding(dummyAction, "/user/hand/right/input/system/click"); - - XrInteractionProfileSuggestedBinding suggestedBindings = {}; - suggestedBindings.type = XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING; - suggestedBindings.next = NULL; - suggestedBindings.suggestedBindings = bindings; - suggestedBindings.countSuggestedBindings = currBinding; - - // Try all - suggestedBindings.interactionProfile = interactionProfilePathTouch; - XrResult suggestTouchResult = xrSuggestInteractionProfileBindings(gAppState.Instance, &suggestedBindings); - OXR(suggestTouchResult); - - if (XR_SUCCESS == suggestTouchResult) { - ALOGV("xrSuggestInteractionProfileBindings found bindings for QUEST controller"); - interactionProfilePath = interactionProfilePathTouch; - } - - if (interactionProfilePath == XR_NULL_PATH) { - // Simple as a fallback - bindings[0] = ActionSuggestedBinding(dummyAction, "/user/hand/right/input/select/click"); - suggestedBindings.interactionProfile = interactionProfilePathKHRSimple; - XrResult suggestKHRSimpleResult = xrSuggestInteractionProfileBindings(gAppState.Instance, &suggestedBindings); - OXR(suggestKHRSimpleResult); - if (XR_SUCCESS == suggestKHRSimpleResult) { - ALOGV("xrSuggestInteractionProfileBindings found bindings for Khronos SIMPLE controller"); - interactionProfilePath = interactionProfilePathKHRSimple; - } else { - ALOGE("xrSuggestInteractionProfileBindings did NOT find any bindings."); - assert(qfalse); - } - } - } - - // Action creation - { - // Map bindings - XrActionSuggestedBinding bindings[32]; // large enough for all profiles - int currBinding = 0; - - { - if (interactionProfilePath == interactionProfilePathTouch) { - bindings[currBinding++] = ActionSuggestedBinding(indexLeftAction, "/user/hand/left/input/trigger"); - bindings[currBinding++] = ActionSuggestedBinding(indexRightAction, "/user/hand/right/input/trigger"); - bindings[currBinding++] = ActionSuggestedBinding(menuAction, "/user/hand/left/input/menu/click"); - bindings[currBinding++] = ActionSuggestedBinding(buttonXAction, "/user/hand/left/input/x/click"); - bindings[currBinding++] = ActionSuggestedBinding(buttonYAction, "/user/hand/left/input/y/click"); - bindings[currBinding++] = ActionSuggestedBinding(buttonAAction, "/user/hand/right/input/a/click"); - bindings[currBinding++] = ActionSuggestedBinding(buttonBAction, "/user/hand/right/input/b/click"); - 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(moveOnRightJoystickAction, "/user/hand/right/input/thumbstick"); - bindings[currBinding++] = ActionSuggestedBinding(thumbstickLeftClickAction, "/user/hand/left/input/thumbstick/click"); - bindings[currBinding++] = ActionSuggestedBinding(thumbstickRightClickAction, "/user/hand/right/input/thumbstick/click"); - bindings[currBinding++] = ActionSuggestedBinding(vibrateLeftFeedback, "/user/hand/left/output/haptic"); - bindings[currBinding++] = ActionSuggestedBinding(vibrateRightFeedback, "/user/hand/right/output/haptic"); - bindings[currBinding++] = ActionSuggestedBinding(handPoseLeftAction, "/user/hand/left/input/aim/pose"); - bindings[currBinding++] = ActionSuggestedBinding(handPoseRightAction, "/user/hand/right/input/aim/pose"); - } - - if (interactionProfilePath == interactionProfilePathKHRSimple) { - bindings[currBinding++] = ActionSuggestedBinding(indexLeftAction, "/user/hand/left/input/select/click"); - bindings[currBinding++] = ActionSuggestedBinding(indexRightAction, "/user/hand/right/input/select/click"); - bindings[currBinding++] = ActionSuggestedBinding(buttonAAction, "/user/hand/left/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(vibrateRightFeedback, "/user/hand/right/output/haptic"); - bindings[currBinding++] = ActionSuggestedBinding(handPoseLeftAction, "/user/hand/left/input/aim/pose"); - bindings[currBinding++] = ActionSuggestedBinding(handPoseRightAction, "/user/hand/right/input/aim/pose"); - } - } - - XrInteractionProfileSuggestedBinding suggestedBindings = {}; - suggestedBindings.type = XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING; - suggestedBindings.next = NULL; - suggestedBindings.interactionProfile = interactionProfilePath; - suggestedBindings.suggestedBindings = bindings; - suggestedBindings.countSuggestedBindings = currBinding; - OXR(xrSuggestInteractionProfileBindings(gAppState.Instance, &suggestedBindings)); - - // Enumerate actions - XrPath actionPathsBuffer[32]; - char stringBuffer[256]; - XrAction actionsToEnumerate[] = { - indexLeftAction, - indexRightAction, - menuAction, - buttonAAction, - buttonBAction, - buttonXAction, - buttonYAction, - gripLeftAction, - gripRightAction, - moveOnLeftJoystickAction, - moveOnRightJoystickAction, - thumbstickLeftClickAction, - thumbstickRightClickAction, - vibrateLeftFeedback, - vibrateRightFeedback, - handPoseLeftAction, - handPoseRightAction - }; - for (size_t i = 0; i < sizeof(actionsToEnumerate) / sizeof(actionsToEnumerate[0]); ++i) { - XrBoundSourcesForActionEnumerateInfo enumerateInfo = {}; - enumerateInfo.type = XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO; - enumerateInfo.next = NULL; - enumerateInfo.action = actionsToEnumerate[i]; - - // Get Count - uint32_t countOutput = 0; - OXR(xrEnumerateBoundSourcesForAction( - gAppState.Session, &enumerateInfo, 0 /* request size */, &countOutput, NULL)); - ALOGV( - "xrEnumerateBoundSourcesForAction action=%lld count=%u", - (long long)enumerateInfo.action, - countOutput); - - if (countOutput < 32) { - OXR(xrEnumerateBoundSourcesForAction( - gAppState.Session, &enumerateInfo, 32, &countOutput, actionPathsBuffer)); - for (uint32_t a = 0; a < countOutput; ++a) { - XrInputSourceLocalizedNameGetInfo nameGetInfo = {}; - nameGetInfo.type = XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO; - nameGetInfo.next = NULL; - nameGetInfo.sourcePath = actionPathsBuffer[a]; - nameGetInfo.whichComponents = XR_INPUT_SOURCE_LOCALIZED_NAME_USER_PATH_BIT | - XR_INPUT_SOURCE_LOCALIZED_NAME_INTERACTION_PROFILE_BIT | - XR_INPUT_SOURCE_LOCALIZED_NAME_COMPONENT_BIT; - - uint32_t stringCount = 0u; - OXR(xrGetInputSourceLocalizedName( - gAppState.Session, &nameGetInfo, 0, &stringCount, NULL)); - if (stringCount < 256) { - OXR(xrGetInputSourceLocalizedName( - gAppState.Session, &nameGetInfo, 256, &stringCount, stringBuffer)); - char pathStr[256]; - uint32_t strLen = 0; - OXR(xrPathToString( - gAppState.Instance, - actionPathsBuffer[a], - (uint32_t)sizeof(pathStr), - &strLen, - pathStr)); - ALOGV( - " -> path = %lld `%s` -> `%s`", - (long long)actionPathsBuffer[a], - pathStr, - stringBuffer); - } - } - } - } - } - inputInitialized = qtrue; -} - - -//0 = left, 1 = right -float vibration_channel_duration[2] = {0.0f, 0.0f}; -float vibration_channel_intensity[2] = {0.0f, 0.0f}; - -void JKVR_Vibrate( int duration, int chan, float intensity ) -{ - for (int i = 0; i < 2; ++i) - { - int channel = (i + 1) & chan; - if (channel) - { - if (vibration_channel_duration[channel] > 0.0f) - return; - - if (vibration_channel_duration[channel] == -1.0f && duration != 0.0f) - return; - - vibration_channel_duration[channel] = duration; - vibration_channel_intensity[channel] = intensity * vr_haptic_intensity->value; - } - } -} - -void JKVR_processHaptics() { - static float lastFrameTime = 0.0f; - float timestamp = (float)(Sys_Milliseconds( )); - float frametime = timestamp - lastFrameTime; - lastFrameTime = timestamp; - - for (int i = 0; i < 2; ++i) { - if (vibration_channel_duration[i] > 0.0f || - vibration_channel_duration[i] == -1.0f) { - - // fire haptics using output action - XrHapticVibration vibration = {}; - vibration.type = XR_TYPE_HAPTIC_VIBRATION; - vibration.next = NULL; - vibration.amplitude = vibration_channel_intensity[i]; - vibration.duration = ToXrTime(vibration_channel_duration[i]); - vibration.frequency = 3000; - XrHapticActionInfo hapticActionInfo = {}; - hapticActionInfo.type = XR_TYPE_HAPTIC_ACTION_INFO; - hapticActionInfo.next = NULL; - hapticActionInfo.action = i == 0 ? vibrateLeftFeedback : vibrateRightFeedback; - OXR(xrApplyHapticFeedback(gAppState.Session, &hapticActionInfo, (const XrHapticBaseHeader*)&vibration)); - - if (vibration_channel_duration[i] != -1.0f) { - vibration_channel_duration[i] -= frametime; - - if (vibration_channel_duration[i] < 0.0f) { - vibration_channel_duration[i] = 0.0f; - vibration_channel_intensity[i] = 0.0f; - } - } - } else { - // Stop haptics - XrHapticActionInfo hapticActionInfo = {}; - hapticActionInfo.type = XR_TYPE_HAPTIC_ACTION_INFO; - hapticActionInfo.next = NULL; - hapticActionInfo.action = i == 0 ? vibrateLeftFeedback : vibrateRightFeedback; - OXR(xrStopHapticFeedback(gAppState.Session, &hapticActionInfo)); - } - } -} //keys.h void Sys_QueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr ); diff --git a/Projects/Android/jni/JKVR/VrInputDefault.cpp b/Projects/Android/jni/JKVR/VrInputDefault.cpp index 587d213..626f960 100644 --- a/Projects/Android/jni/JKVR/VrInputDefault.cpp +++ b/Projects/Android/jni/JKVR/VrInputDefault.cpp @@ -214,17 +214,18 @@ void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew, if (vr.item_selector) { static bool itemSwitched = false; if (between(-0.2f, pPrimaryJoystick->y, 0.2f) && - (between(0.8f, primaryJoystickX, 1.0f) || - between(-1.0f, primaryJoystickX, -0.8f))) { + (primaryJoystickX > 0.8f || primaryJoystickX < -0.8f)) { + if (!itemSwitched) { - if (between(0.8f, primaryJoystickX, 1.0f)) { + if (primaryJoystickX > 0.8f) { sendButtonActionSimple("itemselectornext"); - } else { + itemSwitched = true; + } else if (primaryJoystickX < -0.8f) { sendButtonActionSimple("itemselectorprev"); + itemSwitched = true; } - itemSwitched = true; } - } else { + } else if (between(-0.4f, primaryJoystickX, 0.4f)) { itemSwitched = false; } } @@ -249,12 +250,12 @@ void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew, if (between(-0.2f, primaryJoystickX, 0.2f)) { if (cl.frame.ps.weapon == WP_DISRUPTOR) { - sendButtonAction("+altattack", between(0.8f, pPrimaryJoystick->y, 1.0f)); + sendButtonAction("+altattack", pPrimaryJoystick->y > 0.8f); } else { - sendButtonAction("+attack", between(0.8f, pPrimaryJoystick->y, 1.0f)); - sendButtonAction("+altattack", between(-1.0f, pPrimaryJoystick->y, -0.8f)); + sendButtonAction("+attack", pPrimaryJoystick->y > 0.8f); + sendButtonAction("+altattack", pPrimaryJoystick->y < -0.8f); } } } diff --git a/Projects/Android/jni/JKVR/VrInputWeaponAlign.cpp b/Projects/Android/jni/JKVR/VrInputWeaponAlign.cpp index c83dd67..dab17bc 100644 --- a/Projects/Android/jni/JKVR/VrInputWeaponAlign.cpp +++ b/Projects/Android/jni/JKVR/VrInputWeaponAlign.cpp @@ -7,11 +7,6 @@ Authors : Simon Brown *************************************************************************************/ -#include -#include -#include -#include -#include #include #include "VrInput.h" diff --git a/Projects/Android/jni/OpenJK/Android.mk b/Projects/Android/jni/OpenJK/Android.mk index 63d4fef..a8ccc2a 100644 --- a/Projects/Android/jni/OpenJK/Android.mk +++ b/Projects/Android/jni/OpenJK/Android.mk @@ -1,7 +1,11 @@ LOCAL_PATH := $(call my-dir) -JK3_BASE_CFLAGS = -DHAVE_GLES -DFINAL_BUILD -fexceptions -Wall -Wno-write-strings -Wno-comment -fno-caller-saves -fno-tree-vectorize -Wno-unused-but-set-variable -fvisibility=hidden +# Uncomment for the correct headset - slight changes required in OpenXR implementation +#OPENXR_HMD = -DMETA_QUEST +OPENXR_HMD = -DPICO_XR + +JK3_BASE_CFLAGS = $(OPENXR_HMD) -DHAVE_GLES -DFINAL_BUILD -fexceptions -Wall -Wno-write-strings -Wno-comment -fno-caller-saves -fno-tree-vectorize -Wno-unused-but-set-variable -fvisibility=hidden JK3_BASE_CPPFLAGS = -fvisibility-inlines-hidden -Wno-invalid-offsetof -fvisibility=hidden JK3_BASE_LDLIBS = @@ -11,7 +15,6 @@ JK3_BASE_LDLIBS = JK3_BASE_LDLIBS += -Wl JK3_BASE_C_INCLUDES := $(OPENJK_PATH)/lib $(JK3_CODE_PATH)/client $(JK3_CODE_PATH)/server $(JK3_CODE_PATH)/libs/freetype2/include $(JK3_CODE_PATH)/common $(JK3_CODE_PATH)/gl -JK3_BASE_C_INCLUDES += $(LOCAL_PATH)/../../../../../../OpenXR/Include JK3_BASE_C_INCLUDES += $(LOCAL_PATH)/../../../../../../3rdParty/khronos/openxr/OpenXR-SDK/include JK3_BASE_C_INCLUDES += $(JK3_CODE_PATH)/ $(OPENJK_PATH)/code/ $(OPENJK_PATH)/shared/ $(JK3_CODE_PATH)/ui $(OPENJK_PATH)/lib/gsl-lite/include diff --git a/Projects/Android/jni/OpenJK/Android_client_ja.mk b/Projects/Android/jni/OpenJK/Android_client_ja.mk index 3a8ad59..9eace92 100644 --- a/Projects/Android/jni/OpenJK/Android_client_ja.mk +++ b/Projects/Android/jni/OpenJK/Android_client_ja.mk @@ -124,11 +124,12 @@ JK3_SRC = \ JKVR_SRC_FILES := ${TOP_DIR}/JKVR/JKVR_SurfaceView.cpp \ - ${TOP_DIR}/JKVR/VrInputCommon.cpp \ - ${TOP_DIR}/JKVR/VrInputDefault.cpp \ - ${TOP_DIR}/JKVR/argtable3.c -# ${TOP_DIR}/JKVR/VrCompositor.cpp \ -# ${TOP_DIR}/JKVR/VrInputWeaponAlign.cpp \ + ${TOP_DIR}/JKVR/VrInputCommon.cpp \ + ${TOP_DIR}/JKVR/VrInputDefault.cpp \ + ${TOP_DIR}/JKVR/VrInputWeaponAlign.cpp \ + ${TOP_DIR}/JKVR/argtable3.c \ + ${TOP_DIR}/JKVR/OpenXRInput_MetaQuest.cpp \ + ${TOP_DIR}/JKVR/OpenXRInput_PicoXR.cpp LOCAL_SRC_FILES += $(JK3_SRC) $(JKVR_SRC_FILES) diff --git a/Projects/Android/jni/OpenJK/Android_client_jo.mk b/Projects/Android/jni/OpenJK/Android_client_jo.mk index cc3aae5..f5215cf 100644 --- a/Projects/Android/jni/OpenJK/Android_client_jo.mk +++ b/Projects/Android/jni/OpenJK/Android_client_jo.mk @@ -126,9 +126,10 @@ JK3_SRC = \ JKVR_SRC_FILES := ${TOP_DIR}/JKVR/JKVR_SurfaceView.cpp \ ${TOP_DIR}/JKVR/VrInputCommon.cpp \ ${TOP_DIR}/JKVR/VrInputDefault.cpp \ - ${TOP_DIR}/JKVR/argtable3.c -# ${TOP_DIR}/JKVR/VrCompositor.cpp \ -# ${TOP_DIR}/JKVR/VrInputWeaponAlign.cpp \ + ${TOP_DIR}/JKVR/VrInputWeaponAlign.cpp \ + ${TOP_DIR}/JKVR/argtable3.c \ + ${TOP_DIR}/JKVR/OpenXRInput_MetaQuest.cpp \ + ${TOP_DIR}/JKVR/OpenXRInput_PicoXR.cpp LOCAL_SRC_FILES += $(JK3_SRC) $(JKVR_SRC_FILES) diff --git a/Projects/Android/jni/OpenJK/code/client/cl_scrn.cpp b/Projects/Android/jni/OpenJK/code/client/cl_scrn.cpp index 7e9f61a..0ffb4dc 100644 --- a/Projects/Android/jni/OpenJK/code/client/cl_scrn.cpp +++ b/Projects/Android/jni/OpenJK/code/client/cl_scrn.cpp @@ -507,6 +507,7 @@ void SCR_UpdateScreen( void ) { // that case. if ( cls.uiStarted ) { + //Try again here in case we've not done it yet JKVR_FrameSetup(); for (int eye = 0; eye < 2; ++eye) diff --git a/Projects/Android/jni/OpenJK/code/qcommon/common.cpp b/Projects/Android/jni/OpenJK/code/qcommon/common.cpp index 0b7d230..7200f4e 100644 --- a/Projects/Android/jni/OpenJK/code/qcommon/common.cpp +++ b/Projects/Android/jni/OpenJK/code/qcommon/common.cpp @@ -24,6 +24,7 @@ along with this program; if not, see . // common.c -- misc functions used in client and server +#include #include "q_shared.h" #include "qcommon.h" #include "qcommon/q_version.h" @@ -1363,6 +1364,8 @@ void Com_Frame( void ) { int timeVal; static int lastTime = 0, bias = 0; + JKVR_FrameSetup(); + // write config file if anything changed Com_WriteConfiguration(); diff --git a/java/com/drbeef/jkquest/GLES3JNIActivity.java b/java/com/drbeef/jkquest/GLES3JNIActivity.java index 1454fd7..22594d3 100644 --- a/java/com/drbeef/jkquest/GLES3JNIActivity.java +++ b/java/com/drbeef/jkquest/GLES3JNIActivity.java @@ -65,6 +65,7 @@ import java.util.Vector; e.printStackTrace(); } + System.loadLibrary("openxr_loader"); System.loadLibrary( "openjk_" + game ); }