29#if !defined(XR_USE_PLATFORM_WIN32)
30# define strcpy_s(dest, source) strncpy((dest), (source), sizeof(dest))
34bool xr_result(XrInstance instance, XrResult result,
const char* format, ...)
36 if (XR_SUCCEEDED(result))
39 char resultString[XR_MAX_RESULT_STRING_SIZE];
41 if (instance != XR_NULL_HANDLE)
43 xrResultToString(instance, result, resultString);
45 size_t len1 = strlen(format);
46 size_t len2 = strlen(resultString) + 1;
47 char *formatRes =
new char[len1 + len2 + 15];
48 sprintf(formatRes,
"[OPENXR]: %s [%s]\n", format, resultString);
51 va_start(args, format);
52 MMechostr(MSKRUNTIME, formatRes, args);
59 size_t len1 = strlen(format);
60 char *formatRes =
new char[len1 + 12];
61 sprintf(formatRes,
"[OPENXR]: %s\n", format);
62 MMechostr(MSKRUNTIME, formatRes);
68void get_instance_properties(XrInstance instance)
71 XrInstanceProperties instance_props = { XR_TYPE_INSTANCE_PROPERTIES, XR_NULL_HANDLE };
72 std::stringstream buf;
74 result = xrGetInstanceProperties(instance, &instance_props);
75 if (!xr_result(XR_NULL_HANDLE, result,
"Failed to get instance info"))
78 buf <<
"[OPENXR]: Runtime Name: " << instance_props.runtimeName <<
"\n"
79 <<
"Runtime Version: " << XR_VERSION_MAJOR(instance_props.runtimeVersion) <<
"." << XR_VERSION_MINOR(instance_props.runtimeVersion) <<
"." << XR_VERSION_PATCH(instance_props.runtimeVersion) << std::endl;
80 MMechostr(MSKRUNTIME, buf.str().c_str());
83void print_system_properties(XrSystemProperties* system_properties,
bool hand_tracking_ext)
85 std::stringstream buf;
86 buf <<
"[OPENXR]: System properties for system " << system_properties->systemId <<
" \""
87 << system_properties->systemName <<
"\", vendor ID " << system_properties->vendorId <<
"\n"
88 <<
"\tMax layers : " << system_properties->graphicsProperties.maxLayerCount <<
"\n"
89 <<
"\tMax swapchain height: " << system_properties->graphicsProperties.maxSwapchainImageHeight <<
"\n"
90 <<
"\tMax swapchain width : " << system_properties->graphicsProperties.maxSwapchainImageWidth <<
"\n"
91 <<
"\tOrientation Tracking: " << system_properties->trackingProperties.orientationTracking <<
"\n"
92 <<
"\tPosition Tracking : " << system_properties->trackingProperties.positionTracking;
94 if (hand_tracking_ext)
97 buf <<
"\tHand Tracking : true";
100 MMechostr(MSKRUNTIME, buf.str().c_str());
104sOpenXr* sOpenXr::_singleton =
nullptr;
108 mRendererType = rsys;
109 mAppName =
"Scol OpenXR plugin";
110 mInstance = XR_NULL_HANDLE;
111 mSession = XR_NULL_HANDLE;
116 mPredictedDisplayTime = 0;
117 mScaleRatio = scaleRatio;
118 mSessionRunning =
false;
119 mRequestRestart =
false;
121 mViewType = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO;
122 mPassthroughEnable =
false;
123 mSkipNextFrame =
false;
124 mSystemId = XR_NULL_SYSTEM_ID;
125 mSession = XR_NULL_HANDLE;
126 mInstance = XR_NULL_HANDLE;
127 mLastControllerType = ControllerType::CLASSIC_CONTROLLER;
128 mExtensionsEnable = ExtensionType::EXTENSION_NONE;
130 for (
unsigned int i = 0; i < MAX_VR_CONTROLLERS; i++)
131 mControllerType[i] = ControllerType::CLASSIC_CONTROLLER;
133 for (
unsigned int i = 0; i < 2; i++)
136 mBlendMode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
137 mHandTracking.gestures =
false;
138 mHandTracking.supported =
false;
139 mHandTracking.system_supported =
false;
141 mPassthroughFB.supported =
false;
142 mPassthroughFB.available =
false;
143 mPassthroughFB.passthroughLayer = XR_NULL_HANDLE;
144 mPassthroughFB.pfnXrCreatePassthroughFBX = XR_NULL_HANDLE;
145 mPassthroughFB.pfnXrDestroyPassthroughFBX = XR_NULL_HANDLE;
146 mPassthroughFB.pfnXrPassthroughPauseFBX = XR_NULL_HANDLE;
147 mPassthroughFB.pfnXrPassthroughStartFBX = XR_NULL_HANDLE;
148 mPassthroughFB.pfnXrCreatePassthroughLayerFBX = XR_NULL_HANDLE;
149 mPassthroughFB.pfnXrDestroyPassthroughLayerFBX = XR_NULL_HANDLE;
150 mPassthroughFB.pfnXrPassthroughLayerPauseFBX = XR_NULL_HANDLE;
151 mPassthroughFB.pfnXrPassthroughLayerResumeFBX = XR_NULL_HANDLE;
152 mPassthroughFB.passthroughFeature = XR_NULL_HANDLE;
154 mPassthroughHTC.supported =
false;
155 mPassthroughHTC.passthroughFeature = XR_NULL_HANDLE;
156 mPassthroughHTC.pfnXrCreatePassthroughHTC = XR_NULL_HANDLE;
157 mPassthroughHTC.pfnXrDestroyPassthroughHTC = XR_NULL_HANDLE;
160 std::shared_ptr<PlatformData> data = std::make_shared<PlatformData>();
162#if defined(XR_USE_PLATFORM_WIN32)
163 mPlatform = CreatePlatform(data);
164#elif defined(XR_USE_PLATFORM_ANDROID)
165 struct android_app* androidApp = (
struct android_app*)SCgetExtra(
"this_inst");
168 androidApp->activity->vm->AttachCurrentThread(&Env,
nullptr);
170 data->applicationVM = androidApp->activity->vm;
171 data->applicationActivity = androidApp->activity->clazz;
173 mPlatform = CreatePlatform(data);
176 PFN_xrInitializeLoaderKHR initializeLoader = XR_NULL_HANDLE;
177 if (XR_SUCCEEDED(xrGetInstanceProcAddr(XR_NULL_HANDLE,
"xrInitializeLoaderKHR", (PFN_xrVoidFunction*)(&initializeLoader))))
179 XrLoaderInitInfoAndroidKHR loaderInitInfoAndroid;
180 memset(&loaderInitInfoAndroid, 0,
sizeof(loaderInitInfoAndroid));
181 loaderInitInfoAndroid.type = XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR;
182 loaderInitInfoAndroid.next = XR_NULL_HANDLE;
183 loaderInitInfoAndroid.applicationVM = androidApp->activity->vm;
184 loaderInitInfoAndroid.applicationContext = androidApp->activity->clazz;
185 initializeLoader((
const XrLoaderInitInfoBaseHeaderKHR*)&loaderInitInfoAndroid);
190 mRenderer = CreateRenderer(mRendererType);
197#if defined(XR_USE_PLATFORM_ANDROID)
198 struct android_app* androidApp = (
struct android_app*)SCgetExtra(
"this_inst");
199 androidApp->activity->vm->DetachCurrentThread();
203void sOpenXr::SetRenderer(RenderSystem renderer)
205 if (mRendererType != renderer)
207 mRendererType = renderer;
211 mRenderer = CreateRenderer(renderer);
216 mRenderer = CreateRenderer(renderer);
221void sOpenXr::SetExtensions(
int extensions)
223 if (extensions != mExtensionsEnable)
225 mExtensionsEnable = extensions;
236void sOpenXr::SetAppName(std::string name)
246bool sOpenXr::SetSceneBlendMode(XrEnvironmentBlendMode mode)
249 xrEnumerateEnvironmentBlendModes(mInstance, mSystemId, mViewType, 0, &blendCount,
nullptr);
253 std::vector<XrEnvironmentBlendMode> blendModes(blendCount);
254 xrEnumerateEnvironmentBlendModes(mInstance, mSystemId, mViewType, blendCount, &blendCount, blendModes.data());
256 for (
const auto& blendMode : blendModes)
258 if (blendMode == mode)
260 mBlendMode = blendMode;
268int sOpenXr::GetExtensions()
270 return mExtensionsEnable;
273bool sOpenXr::initialize()
276 mRequestRestart =
false;
278 if (!mRenderer->Setup())
285 uint32_t ext_count = 0;
286 result = xrEnumerateInstanceExtensionProperties(XR_NULL_HANDLE, 0, &ext_count, XR_NULL_HANDLE);
288 if (!xr_result(XR_NULL_HANDLE, result,
"Failed to enumerate number of extension properties"))
291 MMechostr(MSKRUNTIME,
"[OPENXR]: Runtime supports %d extensions\n", ext_count);
293 std::vector<XrExtensionProperties> extensionProperties(ext_count, { XR_TYPE_EXTENSION_PROPERTIES, XR_NULL_HANDLE });
294 result = xrEnumerateInstanceExtensionProperties(XR_NULL_HANDLE, ext_count, &ext_count, extensionProperties.data());
295 if (!xr_result(XR_NULL_HANDLE, result,
"Failed to enumerate extension properties"))
299 bool rendererSupport =
false;
300 mHandTracking.supported =
false;
301 mHandTracking.gestures =
false;
302 mPassthroughFB.supported =
false;
303 mPassthroughHTC.supported =
false;
304 mPicoController.supported =
false;
306 for (uint32_t i = 0; i < ext_count; i++)
308 MMechostr(MSKRUNTIME,
"\t%s v%d\n", extensionProperties[i].extensionName, extensionProperties[i].extensionVersion);
310 if (strcmp(mRenderer->GetExtension(), extensionProperties[i].extensionName) == 0)
311 rendererSupport =
true;
313 if ((strcmp(XR_EXT_HAND_TRACKING_EXTENSION_NAME, extensionProperties[i].extensionName) == 0) && (mExtensionsEnable & EXTENSION_HAND_TRACKING))
315 mHandTracking.supported =
true;
316 mHandTracking.trackers[VrController::Left] = 0;
317 mHandTracking.trackers[VrController::Right] = 0;
320 if ((strcmp(XR_FB_HAND_TRACKING_AIM_EXTENSION_NAME, extensionProperties[i].extensionName) == 0) && (mExtensionsEnable & EXTENSION_HAND_TRACKING))
321 mHandTracking.gestures =
true;
323 if ((strcmp(XR_FB_PASSTHROUGH_EXTENSION_NAME, extensionProperties[i].extensionName) == 0) && (mExtensionsEnable & EXTENSION_PASSTHROUGH))
324 mPassthroughFB.supported =
true;
326 if ((strcmp(XR_HTC_PASSTHROUGH_EXTENSION_NAME, extensionProperties[i].extensionName) == 0) && (mExtensionsEnable & EXTENSION_PASSTHROUGH))
327 mPassthroughHTC.supported =
true;
329 if (strcmp(XR_BD_CONTROLLER_INTERACTION_EXTENSION_NAME, extensionProperties[i].extensionName) == 0)
330 mPicoController.supported =
true;
334 if (!rendererSupport)
336 MMechostr(MSKRUNTIME,
"[OPENXR]: Runtime does not support Renderer API extension!\n");
341 std::vector<const char*> extensions;
343 MMechostr(MSKRUNTIME,
"[OPENXR]: Runtime supports extensions:\n");
344 MMechostr(MSKRUNTIME,
"\t%s\n", mRenderer->GetExtension());
345 extensions.push_back(mRenderer->GetExtension());
347 MMechostr(MSKRUNTIME,
"\t%s: %d\n", XR_EXT_HAND_TRACKING_EXTENSION_NAME, mHandTracking.supported);
348 MMechostr(MSKRUNTIME,
"\t%s: %d\n", XR_FB_HAND_TRACKING_AIM_EXTENSION_NAME, mHandTracking.gestures);
349 MMechostr(MSKRUNTIME,
"\t%s: %d\n", XR_FB_PASSTHROUGH_EXTENSION_NAME, mPassthroughFB.supported);
350 MMechostr(MSKRUNTIME,
"\t%s: %d\n", XR_HTC_PASSTHROUGH_EXTENSION_NAME, mPassthroughHTC.supported);
351 MMechostr(MSKRUNTIME,
"\t%s: %d\n", XR_BD_CONTROLLER_INTERACTION_EXTENSION_NAME, mPicoController.supported);
353 if (mHandTracking.supported)
354 extensions.push_back(XR_EXT_HAND_TRACKING_EXTENSION_NAME);
356 if (mHandTracking.gestures)
357 extensions.push_back(XR_FB_HAND_TRACKING_AIM_EXTENSION_NAME);
359 if (mPassthroughFB.supported)
360 extensions.push_back(XR_FB_PASSTHROUGH_EXTENSION_NAME);
362 if (mPassthroughHTC.supported)
363 extensions.push_back(XR_HTC_PASSTHROUGH_EXTENSION_NAME);
365 if (mPicoController.supported)
366 extensions.push_back(XR_BD_CONTROLLER_INTERACTION_EXTENSION_NAME);
369 const std::vector<std::string> platformExtensions = mPlatform->GetInstanceExtensions();
370 std::transform(platformExtensions.begin(), platformExtensions.end(), std::back_inserter(extensions),
371 [](
const std::string& ext) { return ext.c_str(); });
373 XrInstanceCreateInfo createInfo{ XR_TYPE_INSTANCE_CREATE_INFO };
374 createInfo.next = mPlatform->GetInstanceCreateExtension();
375 createInfo.enabledExtensionCount = (uint32_t)extensions.size();
376 createInfo.enabledExtensionNames = extensions.data();
378 strcpy_s(createInfo.applicationInfo.applicationName, mAppName.c_str());
379 createInfo.applicationInfo.apiVersion = XR_CURRENT_API_VERSION;
380 strcpy_s(createInfo.applicationInfo.engineName,
"OpenSpace3D - Scol Engine");
381 createInfo.applicationInfo.applicationVersion = 1;
383 result = xrCreateInstance(&createInfo, &mInstance);
384 if (!xr_result(XR_NULL_HANDLE, result,
"Failed to create XR instance."))
388 get_instance_properties(mInstance);
391 XrSystemGetInfo system_get_info = { XR_TYPE_SYSTEM_GET_INFO, XR_NULL_HANDLE, XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY };
393 result = xrGetSystem(mInstance, &system_get_info, &mSystemId);
394 if (!xr_result(mInstance, result,
"Failed to get system for HMD form factor.") || (mSystemId == XR_NULL_SYSTEM_ID))
396 xrDestroyInstance(mInstance);
400 MMechostr(MSKRUNTIME,
"[OPENXR]: Successfully got XrSystem with id %lu for HMD form factor\n", mSystemId);
404 XrSystemHandTrackingPropertiesEXT hand_tracking_props = { XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT };
405 XrSystemPassthroughProperties2FB passthrough_props{XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES_FB};
406 XrSystemProperties system_props = { XR_TYPE_SYSTEM_PROPERTIES };
408 if (mHandTracking.supported)
410 if (mPassthroughFB.supported)
411 hand_tracking_props.next = &passthrough_props;
413 system_props.next = &hand_tracking_props;
415 else if (mPassthroughFB.supported)
417 system_props.next = &passthrough_props;
420 result = xrGetSystemProperties(mInstance, mSystemId, &system_props);
421 if (!xr_result(mInstance, result,
"Failed to get System properties"))
423 xrDestroyInstance(mInstance);
427 mHandTracking.system_supported = mHandTracking.supported && hand_tracking_props.supportsHandTracking;
428 mHandTracking.gestures = mHandTracking.gestures && mHandTracking.system_supported;
431 mDeviceName = system_props.systemName;
432 print_system_properties(&system_props, mHandTracking.supported);
433 mIsPico = (mDeviceName ==
"SteamVR/OpenXR : pico") || (mDeviceName ==
"PICO 4") || (mDeviceName ==
"PICO 4 Pro") || (mDeviceName ==
"Pico Neo 3 Pro Eye");
435 printSupportedViewConfigs();
437 uint32_t view_count = 0;
438 result = xrEnumerateViewConfigurationViews(mInstance, mSystemId, mViewType, 0, &view_count, XR_NULL_HANDLE);
439 if (!xr_result(mInstance, result,
"Failed to get view configuration view count!"))
441 xrDestroyInstance(mInstance);
445 mViewconfigViews.resize(view_count, { XR_TYPE_VIEW_CONFIGURATION_VIEW, XR_NULL_HANDLE });
446 mViews.resize(view_count, { XR_TYPE_VIEW });
448 result = xrEnumerateViewConfigurationViews(mInstance, mSystemId, mViewType, view_count, &view_count, mViewconfigViews.data());
449 if (!xr_result(mInstance, result,
"Failed to enumerate view configuration views!"))
451 xrDestroyInstance(mInstance);
455 printViewconfigViewInfo();
457 if (!mRenderer->Check(mSystemId, mInstance))
459 xrDestroyInstance(mInstance);
464 mState = XR_SESSION_STATE_UNKNOWN;
465 XrSessionCreateInfo session_create_info = { XR_TYPE_SESSION_CREATE_INFO, mRenderer->GetBindings(), 0, mSystemId };
467 result = xrCreateSession(mInstance, &session_create_info, &mSession);
468 if (!xr_result(mInstance, result,
"Failed to create session"))
470 xrDestroyInstance(mInstance);
474 MMechostr(MSKRUNTIME,
"[OPENXR]: Successfully created a session!\n");
476 if (mHandTracking.system_supported)
478 result = xrGetInstanceProcAddr(mInstance,
"xrLocateHandJointsEXT",
reinterpret_cast<PFN_xrVoidFunction *
>(&mHandTracking.pfnLocateHandJointsEXT));
479 xr_result(mInstance, result,
"Failed to get xrLocateHandJointsEXT function!");
481 PFN_xrCreateHandTrackerEXT pfnCreateHandTrackerEXT = XR_NULL_HANDLE;
482 result = xrGetInstanceProcAddr(mInstance,
"xrCreateHandTrackerEXT",
reinterpret_cast<PFN_xrVoidFunction *
>(&pfnCreateHandTrackerEXT));
484 if (!xr_result(mInstance, result,
"Failed to get xrCreateHandTrackerEXT function!"))
485 mHandTracking.system_supported =
false;
487 XrHandTrackerCreateInfoEXT hand_tracker_create_info_l = { XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT, XR_NULL_HANDLE, XR_HAND_LEFT_EXT, XR_HAND_JOINT_SET_DEFAULT_EXT };
488 result = pfnCreateHandTrackerEXT(mSession, &hand_tracker_create_info_l, &mHandTracking.trackers[VrController::Left]);
489 if (!xr_result(mInstance, result,
"Failed to create left hand tracker"))
490 mHandTracking.system_supported =
false;
492 MMechostr(MSKRUNTIME,
"[OPENXR]: Created hand tracker for left hand\n");
494 XrHandTrackerCreateInfoEXT hand_tracker_create_info_r = { XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT, XR_NULL_HANDLE, XR_HAND_RIGHT_EXT, XR_HAND_JOINT_SET_DEFAULT_EXT };
495 result = pfnCreateHandTrackerEXT(mSession, &hand_tracker_create_info_r, &mHandTracking.trackers[VrController::Right]);
496 if (!xr_result(mInstance, result,
"Failed to create right hand tracker"))
497 mHandTracking.system_supported =
false;
499 MMechostr(MSKRUNTIME,
"[OPENXR]: Created hand tracker for right hand\n");
502 if (mPassthroughFB.supported)
504 if (!xr_result(mInstance, xrGetInstanceProcAddr(mInstance,
"xrCreatePassthroughFB",
505 reinterpret_cast<PFN_xrVoidFunction *
>(&mPassthroughFB.pfnXrCreatePassthroughFBX)),
506 "Failed to obtain the function pointer for xrCreatePassthroughFB") ||
508 !xr_result(mInstance, xrGetInstanceProcAddr(mInstance,
"xrDestroyPassthroughFB",
509 reinterpret_cast<PFN_xrVoidFunction *
>(&mPassthroughFB.pfnXrDestroyPassthroughFBX)),
510 "Failed to obtain the function pointer for xrDestroyPassthroughFB") ||
512 !xr_result(mInstance, xrGetInstanceProcAddr(mInstance,
"xrCreatePassthroughLayerFB",
513 reinterpret_cast<PFN_xrVoidFunction *
>(&mPassthroughFB.pfnXrCreatePassthroughLayerFBX)),
514 "Failed to obtain the function pointer for xrCreatePassthroughLayerFBX") ||
516 !xr_result(mInstance, xrGetInstanceProcAddr(mInstance,
"xrPassthroughStartFB",
517 reinterpret_cast<PFN_xrVoidFunction *
>(&mPassthroughFB.pfnXrPassthroughStartFBX)),
518 "Failed to obtain the function pointer for xrPassthroughStartFB") ||
520 !xr_result(mInstance, xrGetInstanceProcAddr(mInstance,
"xrPassthroughPauseFB",
521 reinterpret_cast<PFN_xrVoidFunction *
>(&mPassthroughFB.pfnXrPassthroughPauseFBX)),
522 "Failed to obtain the function pointer for xrPassthroughPauseFB") ||
524 !xr_result(mInstance, xrGetInstanceProcAddr(mInstance,
"xrPassthroughLayerResumeFB",
525 reinterpret_cast<PFN_xrVoidFunction *
>(&mPassthroughFB.pfnXrPassthroughLayerResumeFBX)),
526 "Failed to obtain the function pointer for xrPassthroughLayerResumeFB") ||
528 !xr_result(mInstance, xrGetInstanceProcAddr(mInstance,
"xrPassthroughLayerPauseFB",
529 reinterpret_cast<PFN_xrVoidFunction *
>(&mPassthroughFB.pfnXrPassthroughLayerPauseFBX)),
530 "Failed to obtain the function pointer for xrPassthroughLayerPauseFB") ||
532 !xr_result(mInstance, xrGetInstanceProcAddr(mInstance,
"xrDestroyPassthroughLayerFB",
533 reinterpret_cast<PFN_xrVoidFunction *
>(&mPassthroughFB.pfnXrDestroyPassthroughLayerFBX)),
534 "Failed to obtain the function pointer for xrDestroyPassthroughLayerFB") ||
536 !xr_result(mInstance, xrGetInstanceProcAddr(mInstance,
"xrPassthroughLayerSetStyleFB",
537 reinterpret_cast<PFN_xrVoidFunction *
>(&mPassthroughFB.pfnXrPassthroughLayerSetStyleFB)),
538 "Failed to obtain the function pointer for xrPassthroughLayerSetStyleFB"))
539 mPassthroughFB.supported =
false;
542 if (mPassthroughHTC.supported)
544 if (!xr_result(mInstance, xrGetInstanceProcAddr(mInstance,
"xrCreatePassthroughHTC",
545 reinterpret_cast<PFN_xrVoidFunction *
>(&mPassthroughHTC.pfnXrCreatePassthroughHTC)),
546 "Failed to obtain the function pointer for xrCreatePassthroughHTC") ||
548 !xr_result(mInstance, xrGetInstanceProcAddr(mInstance,
"xrDestroyPassthroughHTC",
549 reinterpret_cast<PFN_xrVoidFunction *
>(&mPassthroughHTC.pfnXrDestroyPassthroughHTC)),
550 "Failed to obtain the function pointer for xrDestroyPassthroughHTC"))
551 mPassthroughHTC.supported =
false;
554 printReferenceSpaces();
556 XrReferenceSpaceCreateInfo play_space_create_info = { XR_TYPE_REFERENCE_SPACE_CREATE_INFO, XR_NULL_HANDLE, XR_REFERENCE_SPACE_TYPE_STAGE, identity_pose };
558 result = xrCreateReferenceSpace(mSession, &play_space_create_info, &mPlaySpace);
559 if (!xr_result(mInstance, result,
"Failed to create play space!"))
561 xrDestroySession(mSession);
562 xrDestroyInstance(mInstance);
566 XrReferenceSpaceCreateInfo view_space_info = { XR_TYPE_REFERENCE_SPACE_CREATE_INFO, XR_NULL_HANDLE, XR_REFERENCE_SPACE_TYPE_VIEW, identity_pose };
567 result = xrCreateReferenceSpace(mSession, &view_space_info, &mViewSpace);
568 if (!xr_result(mInstance, result,
"Failed to create view space!"))
570 xrDestroySession(mSession);
571 xrDestroyInstance(mInstance);
576 int64_t swapchainFormat = 0;
577 if (!mRenderer->GetSwapchainFormat(mInstance, mSession, swapchainFormat))
579 xrDestroySession(mSession);
580 xrDestroyInstance(mInstance);
590 mSwapchains.resize(view_count);
597 mProjectionViews.resize(view_count);
599 for (uint32_t i = 0; i < view_count; i++)
601 XrSwapchainCreateInfo swapchain_create_info;
602 swapchain_create_info.type = XR_TYPE_SWAPCHAIN_CREATE_INFO;
603 swapchain_create_info.usageFlags = XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT;
604 swapchain_create_info.createFlags = 0;
605 swapchain_create_info.format = swapchainFormat;
606 swapchain_create_info.sampleCount = mViewconfigViews[i].recommendedSwapchainSampleCount;
607 swapchain_create_info.width =
static_cast<uint32_t
>((float)mViewconfigViews[i].recommendedImageRectWidth * mScaleRatio);
608 swapchain_create_info.height =
static_cast<uint32_t
>((float)mViewconfigViews[i].recommendedImageRectHeight * mScaleRatio);
609 swapchain_create_info.faceCount = 1;
610 swapchain_create_info.arraySize = 1;
611 swapchain_create_info.mipCount = 1;
612 swapchain_create_info.next = XR_NULL_HANDLE;
614 result = xrCreateSwapchain(mSession, &swapchain_create_info, &mSwapchains[i]);
615 if (!xr_result(mInstance, result,
"Failed to create swapchain %d!", i))
617 xrDestroySession(mSession);
618 xrDestroyInstance(mInstance);
622 if (!mRenderer->CreateSwapchainImage(mInstance, view_count, mSwapchains[i], i))
624 xrDestroySession(mSession);
625 xrDestroyInstance(mInstance);
629 mProjectionViews[i].type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW;
630 mProjectionViews[i].next = XR_NULL_HANDLE;
632 mProjectionViews[i].subImage.swapchain = mSwapchains[i];
633 mProjectionViews[i].subImage.imageArrayIndex = 0;
634 mProjectionViews[i].subImage.imageRect.offset = { 0, 0 };
635 mProjectionViews[i].subImage.imageRect.extent = {
static_cast<int32_t
>(swapchain_create_info.width),
static_cast<int32_t
>(swapchain_create_info.height) };
641 result = xrEnumerateEnvironmentBlendModes(mInstance, mSystemId, mViewType, 0, &blendCount,
nullptr);
645 std::set<XrEnvironmentBlendMode> lookForBlendModes{ XR_ENVIRONMENT_BLEND_MODE_OPAQUE, XR_ENVIRONMENT_BLEND_MODE_ADDITIVE, XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND };
646 std::vector<XrEnvironmentBlendMode> blendModes(blendCount);
647 result = xrEnumerateEnvironmentBlendModes(mInstance, mSystemId, mViewType, blendCount, &blendCount, blendModes.data());
649 for (
const auto& blendMode : blendModes)
651 if (mBlendMode == blendMode)
653 else if (lookForBlendModes.count(blendMode))
654 mBlendMode = blendMode;
658 if (!initControllers())
660 xrDestroySession(mSession);
661 xrDestroyInstance(mInstance);
671void sOpenXr::cleanup()
675 if (mInstance != XR_NULL_HANDLE)
677 if (mSession != XR_NULL_HANDLE)
678 xrEndSession(mSession);
680 if (mHandTracking.system_supported)
682 PFN_xrDestroyHandTrackerEXT pfnDestroyHandTrackerEXT = XR_NULL_HANDLE;
683 result = xrGetInstanceProcAddr(mInstance,
"xrDestroyHandTrackerEXT", (PFN_xrVoidFunction*)&pfnDestroyHandTrackerEXT);
684 if (xr_result(mInstance, result,
"Failed to get xrDestroyHandTrackerEXT function!"))
686 if (mHandTracking.trackers[VrController::Left])
688 result = pfnDestroyHandTrackerEXT(mHandTracking.trackers[VrController::Left]);
689 if (xr_result(mInstance, result,
"Failed to destroy left hand tracker"))
690 MMechostr(MSKRUNTIME,
"[OPENXR]: Destroyed hand tracker for left hand\n");
693 if (mHandTracking.trackers[VrController::Right])
695 result = pfnDestroyHandTrackerEXT(mHandTracking.trackers[VrController::Right]);
696 if (xr_result(mInstance, result,
"Failed to destroy left hand tracker"))
697 MMechostr(MSKRUNTIME,
"[OPENXR]: Destroyed hand tracker for left hand\n");
704 if (mInput.actionSet != XR_NULL_HANDLE)
706 for (
auto hand : { VrController::Left, VrController::Right })
707 xrDestroySpace(mInput.handSpace[hand]);
709 xrDestroyActionSet(mInput.actionSet);
712 xrDestroySpace(mPlaySpace);
713 xrDestroySpace(mViewSpace);
715 if (mSession != XR_NULL_HANDLE)
717 xrDestroySession(mSession);
718 mSession = XR_NULL_HANDLE;
722 if (mInstance != XR_NULL_HANDLE)
724 xrDestroyInstance(mInstance);
725 mInstance = XR_NULL_HANDLE;
730void sOpenXr::printSupportedViewConfigs()
734 uint32_t view_config_count;
735 result = xrEnumerateViewConfigurations(mInstance, mSystemId, 0, &view_config_count, XR_NULL_HANDLE);
736 if (!xr_result(mInstance, result,
"Failed to get view configuration count"))
739 MMechostr(MSKRUNTIME,
"[OPENXR]: Runtime supports %d view configurations", view_config_count);
741 std::vector<XrViewConfigurationType> view_configs(view_config_count);
742 result = xrEnumerateViewConfigurations(mInstance, mSystemId, view_config_count, &view_config_count, view_configs.data());
743 if (!xr_result(mInstance, result,
"Failed to enumerate view configurations!"))
746 MMechostr(MSKRUNTIME,
"[OPENXR]: Runtime supports view configurations:\n");
747 for (uint32_t i = 0; i < view_config_count; ++i)
749 XrViewConfigurationProperties props = { XR_TYPE_VIEW_CONFIGURATION_PROPERTIES, XR_NULL_HANDLE };
751 result = xrGetViewConfigurationProperties(mInstance, mSystemId, view_configs[i], &props);
752 if (!xr_result(mInstance, result,
"Failed to get view configuration info %d!", i))
760void sOpenXr::printViewconfigViewInfo()
762 for (uint32_t i = 0; i < mViewconfigViews.size(); i++)
764 MMechostr(MSKRUNTIME,
"[OPENXR]: View Configuration View %d:\n", i);
765 MMechostr(MSKRUNTIME,
"\tResolution : Recommended %dx%d, Max: %dx%d\n",
766 mViewconfigViews[0].recommendedImageRectWidth,
767 mViewconfigViews[0].recommendedImageRectHeight,
768 mViewconfigViews[0].maxImageRectWidth,
769 mViewconfigViews[0].maxImageRectHeight);
770 MMechostr(MSKRUNTIME,
"\tSwapchain Samples: Recommended: %d, Max: %d)\n",
771 mViewconfigViews[0].recommendedSwapchainSampleCount,
772 mViewconfigViews[0].maxSwapchainSampleCount);
776void sOpenXr::printReferenceSpaces()
780 uint32_t ref_space_count;
781 result = xrEnumerateReferenceSpaces(mSession, 0, &ref_space_count, XR_NULL_HANDLE);
782 if (!xr_result(mInstance, result,
"Getting number of reference spaces failed!"))
785 std::vector<XrReferenceSpaceType> ref_spaces(ref_space_count);
786 result = xrEnumerateReferenceSpaces(mSession, ref_space_count, &ref_space_count, ref_spaces.data());
787 if (!xr_result(mInstance, result,
"Enumerating reference spaces failed!"))
790 MMechostr(MSKRUNTIME,
"[OPENXR]: Runtime supports %d reference spaces:\n", ref_space_count);
791 for (uint32_t i = 0; i < ref_space_count; i++) {
792 if (ref_spaces[i] == XR_REFERENCE_SPACE_TYPE_LOCAL) {
793 MMechostr(MSKRUNTIME,
"\tXR_REFERENCE_SPACE_TYPE_LOCAL\n");
795 else if (ref_spaces[i] == XR_REFERENCE_SPACE_TYPE_STAGE) {
796 MMechostr(MSKRUNTIME,
"\tXR_REFERENCE_SPACE_TYPE_STAGE\n");
798 else if (ref_spaces[i] == XR_REFERENCE_SPACE_TYPE_VIEW) {
799 MMechostr(MSKRUNTIME,
"\tXR_REFERENCE_SPACE_TYPE_VIEW\n");
802 MMechostr(MSKRUNTIME,
"\tOther (extension?) refspace %u\\n", ref_spaces[i]);
808sOpenXr* sOpenXr::CreateInstance(RenderSystem rsys,
float scale)
810 if (NULL == _singleton)
812 _singleton =
new sOpenXr(rsys, scale);
816 _singleton->SetRenderer(rsys);
817 _singleton->SetScaleRatio(scale);
825 if (NULL == _singleton)
833 SAFE_DELETE(_singleton);
836RenderSystem sOpenXr::GetRenderer()
838 return mRendererType;
841void sOpenXr::SetScaleRatio(
float ratio)
843 if (mScaleRatio != ratio)
854XrInstance sOpenXr::GetXrInstance()
859XrSession sOpenXr::GetXrSession()
864bool sOpenXr::IsConnected()
869bool sOpenXr::Connect()
874 mConnected = initialize();
882std::string sOpenXr::GetHmdName()
890void sOpenXr::Disconnect()
900void sOpenXr::SetState(
bool state)
905 if (mPassthroughEnable)
907 mPassthroughEnable =
false;
909 mPassthroughEnable =
true;
914bool sOpenXr::IsVisible()
916 return (!mPaused && (mState == XR_SESSION_STATE_VISIBLE || mState == XR_SESSION_STATE_FOCUSED)) ? true :
false;
919bool sOpenXr::GetHmdOrientation(
Quaternion &quat)
921 if (!mConnected || !mPoseValid)
924 quat = mPreviousHmdQuat;
928bool sOpenXr::GetHmdPosition(
Vector3 &vec)
930 if (!mConnected || !mPoseValid)
933 vec = mPreviousHmdPos;
937bool sOpenXr::GetProjectionMatrix(VrEye eye,
float nearclip,
float farclip,
Matrix4 &mat)
939 if (!mConnected || !mPoseValid)
943 XrMatrix4x4f_CreateProjectionFov(&proj, GRAPHICS_OPENGL, mViews[eye].fov, nearclip, farclip);
948bool sOpenXr::GetStereoTextureSize(
unsigned int &w,
unsigned int &h)
954 w = (
unsigned int)(mViewconfigViews[1].recommendedImageRectWidth * mScaleRatio);
955 h = (
unsigned int)(mViewconfigViews[1].recommendedImageRectHeight * mScaleRatio);
960float sOpenXr::GetStereoConfigFovY()
962 if (!mConnected || !mPoseValid)
963 return vrRadiansFromDegrees(90.0f);
968 XrFovInRadians(fovX, fovY, GRAPHICS_OPENGL, mViews[0].fov);
973float sOpenXr::GetStereoConfigIPD()
978XrTime sOpenXr::GetPredictedDisplayTime()
980 return mPredictedDisplayTime;
983bool sOpenXr::processEvents()
985 XrEventDataBuffer runtime_event = { XR_TYPE_EVENT_DATA_BUFFER, XR_NULL_HANDLE };
986 XrResult poll_result = xrPollEvent(mInstance, &runtime_event);
989 while (poll_result == XR_SUCCESS)
991 switch (runtime_event.type)
993 case XR_TYPE_EVENT_DATA_EVENTS_LOST:
995 XrEventDataEventsLost*
event = (XrEventDataEventsLost*)&runtime_event;
996 MMechostr(MSKDEBUG,
"[OPENXR]: EVENT: %d events data lost!\n", event->lostEventCount);
1000 case XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING:
1002 XrEventDataInstanceLossPending*
event = (XrEventDataInstanceLossPending*)&runtime_event;
1003 mRequestRestart =
true;
1004 mSessionRunning =
false;
1005 MMechostr(MSKDEBUG,
"[OPENXR]: EVENT: instance loss pending at %lu! Destroying instance.\n", event->lossTime);
1008 case XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED:
1010 XrEventDataSessionStateChanged*
event = (XrEventDataSessionStateChanged*)&runtime_event;
1011 MMechostr(MSKDEBUG,
"[OPENXR]: EVENT: session state changed from %d to %d\n", mState, event->state);
1013 const XrSessionState oldState = mState;
1014 mState =
event->state;
1016 if ((event->session != XR_NULL_HANDLE) && (event->session != mSession))
1021 case XR_SESSION_STATE_READY:
1023 if (mSession != XR_NULL_HANDLE)
1025 XrSessionBeginInfo session_begin_info = { XR_TYPE_SESSION_BEGIN_INFO, XR_NULL_HANDLE, mViewType };
1026 result = xrBeginSession(mSession, &session_begin_info);
1027 if (!xr_result(mInstance, result,
"Failed to begin session!"))
1030 mSessionRunning =
true;
1031 MMechostr(MSKRUNTIME,
"[OPENXR]: Session started!\n");
1035 case XR_SESSION_STATE_STOPPING:
1037 if (mSession != XR_NULL_HANDLE)
1039 mSessionRunning =
false;
1040 xrEndSession(mSession);
1044 case XR_SESSION_STATE_EXITING:
1046 mRequestRestart =
false;
1049 case XR_SESSION_STATE_LOSS_PENDING:
1052 mRequestRestart =
true;
1060 case XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING:
1062 MMechostr(MSKDEBUG,
"[OPENXR]: EVENT: reference space change pending!\n");
1063 XrEventDataReferenceSpaceChangePending*
event = (XrEventDataReferenceSpaceChangePending*)&runtime_event;
1068 case XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED:
1070 MMechostr(MSKDEBUG,
"[OPENXR]: EVENT: interaction profile changed!\n");
1071 XrEventDataInteractionProfileChanged*
event = (XrEventDataInteractionProfileChanged*)&runtime_event;
1074 XrInteractionProfileState state = { XR_TYPE_INTERACTION_PROFILE_STATE };
1076 for (
int i = 0; i < MAX_VR_CONTROLLERS; i++)
1078 XrResult res = xrGetCurrentInteractionProfile(mSession, mInput.handSubactionPath[i], &state);
1079 if (!xr_result(mInstance, res,
"Failed to get interaction profile for %d", i))
1082 if (state.interactionProfile != XR_NULL_PATH)
1085 char profile_str[XR_MAX_PATH_LENGTH];
1086 res = xrPathToString(mInstance, state.interactionProfile, XR_MAX_PATH_LENGTH, &strl, profile_str);
1087 if (!xr_result(mInstance, res,
"Failed to get interaction profile path str"))
1090 if (std::string(profile_str) ==
"/interaction_profiles/khr/simple_controller")
1091 mLastControllerType = ControllerType::CLASSIC_CONTROLLER;
1092 else if (std::string(profile_str) ==
"/interaction_profiles/htc/vive_controller")
1093 mLastControllerType = ControllerType::HTCVIVE_CONTROLLER;
1094 else if (std::string(profile_str) ==
"/interaction_profiles/valve/index_controller")
1095 mLastControllerType = ControllerType::VALVE_INDEX_CONTROLLER;
1096 else if (std::string(profile_str) ==
"/interaction_profiles/bytedance/pico4_controller")
1097 mLastControllerType = ControllerType::PICO_PICO4_CONTROLLER;
1098 else if ((std::string(profile_str) ==
"/interaction_profiles/pico/neo3_controller") || (std::string(profile_str) ==
"/interaction_profiles/bytedance/pico_neo3_controller") || mIsPico)
1099 mLastControllerType = ControllerType::PICO_NEO3_CONTROLLER;
1100 else if (std::string(profile_str) ==
"/interaction_profiles/oculus/touch_controller")
1101 mLastControllerType = ControllerType::OCULUS_TOUCH_CONTROLLER;
1102 else if (std::string(profile_str) ==
"/interaction_profiles/microsoft/motion_controller")
1103 mLastControllerType = ControllerType::MS_MOTION_CONTROLLER;
1105 mLastControllerType = ControllerType::CLASSIC_CONTROLLER;
1107 MMechostr(MSKDEBUG,
"[OPENXR]: Event: Interaction profile changed to %s\n", profile_str);
1113 case XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR:
1115 MMechostr(MSKDEBUG,
"[OPENXR]: EVENT: visibility mask changed!!\n");
1116 XrEventDataVisibilityMaskChangedKHR*
event = (XrEventDataVisibilityMaskChangedKHR*)&runtime_event;
1121 case XR_TYPE_EVENT_DATA_PERF_SETTINGS_EXT:
1123 MMechostr(MSKDEBUG,
"[OPENXR]: EVENT: perf settings!\n");
1124 XrEventDataPerfSettingsEXT*
event = (XrEventDataPerfSettingsEXT*)&runtime_event;
1129 case XR_TYPE_EVENT_DATA_PASSTHROUGH_STATE_CHANGED_FB:
1131 MMechostr(MSKDEBUG,
"[OPENXR]: EVENT: passthroughFB state!\n");
1132 XrEventDataPassthroughStateChangedFB*
event = (XrEventDataPassthroughStateChangedFB *)&runtime_event;
1133 if (event->flags & XR_PASSTHROUGH_STATE_CHANGED_REINIT_REQUIRED_BIT_FB )
1136 createPassthrough();
1137 mPassthroughFB.available =
true;
1138 updatePassthrough();
1140 else if (event->flags & XR_PASSTHROUGH_STATE_CHANGED_RESTORED_ERROR_BIT_FB)
1142 mPassthroughFB.available =
true;
1143 updatePassthrough();
1145 else if (event->flags & XR_PASSTHROUGH_STATE_CHANGED_NON_RECOVERABLE_ERROR_BIT_FB || event->flags & XR_PASSTHROUGH_STATE_CHANGED_RECOVERABLE_ERROR_BIT_FB)
1147 mPassthroughFB.available =
false;
1152 default: MMechostr(MSKDEBUG,
"[OPENXR]: Unhandled event type %d\n", runtime_event.type);
1155 runtime_event.type = XR_TYPE_EVENT_DATA_BUFFER;
1156 poll_result = xrPollEvent(mInstance, &runtime_event);
1159 if (poll_result == XR_EVENT_UNAVAILABLE)
1166 MMechostr(MSKRUNTIME,
"[OPENXR]: Failed to poll events!\n");
1171void sOpenXr::processActions()
1173 if (mState != XR_SESSION_STATE_FOCUSED)
1179 const XrActiveActionSet activeActionSet{ mInput.actionSet, XR_NULL_PATH };
1180 XrActionsSyncInfo syncInfo{ XR_TYPE_ACTIONS_SYNC_INFO, XR_NULL_HANDLE, 1, &activeActionSet };
1181 result = xrSyncActions(mSession, &syncInfo);
1182 xr_result(mInstance, result,
"failed to sync actions!");
1185 for (
auto hand : { VrController::Left, VrController::Right })
1187 XrActionStateGetInfo getInfo{ XR_TYPE_ACTION_STATE_GET_INFO };
1188 getInfo.subactionPath = mInput.handSubactionPath[hand];
1190 unsigned int iact = 0;
1191 for (
auto act : mInput.buttonAction)
1195 getInfo.action = act;
1196 XrActionStateBoolean btnState{ XR_TYPE_ACTION_STATE_BOOLEAN };
1197 btnState.currentState = XR_FALSE;
1198 result = xrGetActionStateBoolean(mSession, &getInfo, &btnState);
1199 mInput.buttonStates[hand][iact] = btnState.currentState == XR_TRUE ? true :
false;
1205 for (
auto act : mInput.analogAction)
1209 getInfo.action = act;
1210 XrActionStateFloat analogState{ XR_TYPE_ACTION_STATE_FLOAT };
1211 analogState.currentState = 0.0;
1212 result = xrGetActionStateFloat(mSession, &getInfo, &analogState);
1215 if ((mLastControllerType == HTCVIVE_CONTROLLER) && ((iact == analogPadX) || (iact == analogPadY)) && !mInput.buttonStates[hand][(hand == VrController::Left) ? btnLThumb : btnRThumb])
1216 mInput.analogStates[hand][iact] = 0.0;
1218 mInput.analogStates[hand][iact] = analogState.currentState;
1224 for (
auto act : mInput.touchAction)
1228 getInfo.action = act;
1229 XrActionStateBoolean touchState{ XR_TYPE_ACTION_STATE_BOOLEAN };
1230 touchState.currentState = XR_FALSE;
1231 result = xrGetActionStateBoolean(mSession, &getInfo, &touchState);
1233 mInput.touchStates[hand][iact] = touchState.currentState == XR_TRUE ? true :
false;
1240 if (hand == VrController::Left)
1241 mInput.touchStates[hand][ControllerTouch::touchThumbUp] = (!mInput.touchStates[hand][ControllerTouch::touchThumbUp] &&
1242 !mInput.touchStates[hand][ControllerTouch::touchLThumb] &&
1243 !mInput.touchStates[hand][ControllerTouch::touchX] &&
1244 !mInput.touchStates[hand][ControllerTouch::touchY]
1247 mInput.touchStates[hand][ControllerTouch::touchThumbUp] = (!mInput.touchStates[hand][ControllerTouch::touchThumbUp] &&
1248 !mInput.touchStates[hand][ControllerTouch::touchRThumb] &&
1249 !mInput.touchStates[hand][ControllerTouch::touchA] &&
1250 !mInput.touchStates[hand][ControllerTouch::touchB]
1254 if (mLastControllerType == HTCVIVE_CONTROLLER)
1255 mInput.touchStates[hand][ControllerTouch::touchIndexPointing] = (mInput.analogStates[hand][ControllerAnalog::analogTrigger] == 0.0f && mInput.analogStates[hand][ControllerAnalog::analogGrip] > 0.0f) ?
true : false;
1257 mInput.touchStates[hand][ControllerTouch::touchIndexPointing] = (!mInput.touchStates[hand][ControllerTouch::touchTrigger] && mInput.analogStates[hand][ControllerAnalog::analogGrip] > 0.0f) ?
true : false;
1259 getInfo.action = mInput.poseAction;
1260 XrActionStatePose poseState{ XR_TYPE_ACTION_STATE_POSE };
1261 result = xrGetActionStatePose(mSession, &getInfo, &poseState);
1262 mInput.handActive[hand] = poseState.isActive;
1267bool sOpenXr::initControllers()
1272 XrActionSetCreateInfo actionSetInfo{ XR_TYPE_ACTION_SET_CREATE_INFO };
1273 strcpy_s(actionSetInfo.actionSetName,
"gameplay");
1274 strcpy_s(actionSetInfo.localizedActionSetName,
"Gameplay");
1275 actionSetInfo.priority = 0;
1276 result = xrCreateActionSet(mInstance, &actionSetInfo, &mInput.actionSet);
1277 if (!xr_result(mInstance, result,
"failed to creates actionset!"))
1282 xrStringToPath(mInstance,
"/user/hand/left", &mInput.handSubactionPath[VrController::Left]);
1283 xrStringToPath(mInstance,
"/user/hand/right", &mInput.handSubactionPath[VrController::Right]);
1285 mInput.handVisible[VrController::Left] =
false;
1286 mInput.handVisible[VrController::Right] =
false;
1288 mInput.buttonAction.resize(ControllerButtons::btnSize, XrAction{ XR_NULL_HANDLE });
1289 mInput.touchAction.resize(ControllerTouch::touchSize, XrAction{ XR_NULL_HANDLE });
1290 mInput.analogAction.resize(ControllerAnalog::analogSize, XrAction{ XR_NULL_HANDLE });
1292 mInput.buttonStates.resize(MAX_VR_CONTROLLERS);
1293 mInput.touchStates.resize(MAX_VR_CONTROLLERS);
1294 mInput.analogStates.resize(MAX_VR_CONTROLLERS);
1295 for (
auto hand : { VrController::Left, VrController::Right })
1297 mInput.buttonStates[hand].resize(mInput.buttonAction.size(),
false);
1298 mInput.touchStates[hand].resize(mInput.touchAction.size(),
false);
1299 mInput.analogStates[hand].resize(mInput.analogAction.size(), 0.0f);
1304 XrActionCreateInfo actionInfo{ XR_TYPE_ACTION_CREATE_INFO };
1305 actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
1306 strcpy_s(actionInfo.actionName,
"a_button");
1307 strcpy_s(actionInfo.localizedActionName,
"A Button");
1308 actionInfo.countSubactionPaths = 1;
1309 actionInfo.subactionPaths = &mInput.handSubactionPath[VrController::Right];
1310 result = xrCreateAction(mInput.actionSet, &actionInfo, &mInput.buttonAction[ControllerButtons::btnA]);
1311 if (!xr_result(mInstance, result,
"failed to creates A Button action!"))
1314 actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
1315 strcpy_s(actionInfo.actionName,
"a_touch");
1316 strcpy_s(actionInfo.localizedActionName,
"A Touch");
1317 actionInfo.countSubactionPaths = 1;
1318 actionInfo.subactionPaths = &mInput.handSubactionPath[VrController::Right];
1319 result = xrCreateAction(mInput.actionSet, &actionInfo, &mInput.touchAction[ControllerTouch::touchA]);
1320 if (!xr_result(mInstance, result,
"failed to creates A Touch action!"))
1323 actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
1324 strcpy_s(actionInfo.actionName,
"b_button");
1325 strcpy_s(actionInfo.localizedActionName,
"B Button");
1326 actionInfo.countSubactionPaths = 1;
1327 actionInfo.subactionPaths = &mInput.handSubactionPath[VrController::Right];
1328 result = xrCreateAction(mInput.actionSet, &actionInfo, &mInput.buttonAction[ControllerButtons::btnB]);
1329 if (!xr_result(mInstance, result,
"failed to creates B Button action!"))
1332 actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
1333 strcpy_s(actionInfo.actionName,
"b_touch");
1334 strcpy_s(actionInfo.localizedActionName,
"B Touch");
1335 actionInfo.countSubactionPaths = 1;
1336 actionInfo.subactionPaths = &mInput.handSubactionPath[VrController::Right];
1337 result = xrCreateAction(mInput.actionSet, &actionInfo, &mInput.touchAction[ControllerTouch::touchB]);
1338 if (!xr_result(mInstance, result,
"failed to creates B Touch action!"))
1341 actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
1342 strcpy_s(actionInfo.actionName,
"x_button");
1343 strcpy_s(actionInfo.localizedActionName,
"X Button");
1344 actionInfo.countSubactionPaths = 1;
1345 actionInfo.subactionPaths = &mInput.handSubactionPath[VrController::Left];
1346 result = xrCreateAction(mInput.actionSet, &actionInfo, &mInput.buttonAction[ControllerButtons::btnX]);
1347 if (!xr_result(mInstance, result,
"failed to creates X Button action!"))
1350 actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
1351 strcpy_s(actionInfo.actionName,
"x_touch");
1352 strcpy_s(actionInfo.localizedActionName,
"X Touch");
1353 actionInfo.countSubactionPaths = 1;
1354 actionInfo.subactionPaths = &mInput.handSubactionPath[VrController::Left];
1355 result = xrCreateAction(mInput.actionSet, &actionInfo, &mInput.touchAction[ControllerTouch::touchX]);
1356 if (!xr_result(mInstance, result,
"failed to creates X Touch action!"))
1359 actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
1360 strcpy_s(actionInfo.actionName,
"y_button");
1361 strcpy_s(actionInfo.localizedActionName,
"Y Button");
1362 actionInfo.countSubactionPaths = 1;
1363 actionInfo.subactionPaths = &mInput.handSubactionPath[VrController::Left];
1364 result = xrCreateAction(mInput.actionSet, &actionInfo, &mInput.buttonAction[ControllerButtons::btnY]);
1365 if (!xr_result(mInstance, result,
"failed to creates Y Button action!"))
1368 actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
1369 strcpy_s(actionInfo.actionName,
"y_touch");
1370 strcpy_s(actionInfo.localizedActionName,
"Y Touch");
1371 actionInfo.countSubactionPaths = 1;
1372 actionInfo.subactionPaths = &mInput.handSubactionPath[VrController::Left];
1373 result = xrCreateAction(mInput.actionSet, &actionInfo, &mInput.touchAction[ControllerTouch::touchY]);
1374 if (!xr_result(mInstance, result,
"failed to creates Y Touch action!"))
1377 actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
1378 strcpy_s(actionInfo.actionName,
"rthumb_button");
1379 strcpy_s(actionInfo.localizedActionName,
"Right Thumb Button");
1380 actionInfo.countSubactionPaths = 1;
1381 actionInfo.subactionPaths = &mInput.handSubactionPath[VrController::Right];
1382 result = xrCreateAction(mInput.actionSet, &actionInfo, &mInput.buttonAction[ControllerButtons::btnRThumb]);
1383 if (!xr_result(mInstance, result,
"failed to creates Right Thumb Button action!"))
1386 actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
1387 strcpy_s(actionInfo.actionName,
"rthumb_touch");
1388 strcpy_s(actionInfo.localizedActionName,
"Right Thumb Touch");
1389 actionInfo.countSubactionPaths = 1;
1390 actionInfo.subactionPaths = &mInput.handSubactionPath[VrController::Right];
1391 result = xrCreateAction(mInput.actionSet, &actionInfo, &mInput.touchAction[ControllerTouch::touchRThumb]);
1392 if (!xr_result(mInstance, result,
"failed to creates Right Thumb Button action!"))
1395 actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
1396 strcpy_s(actionInfo.actionName,
"lthumb_button");
1397 strcpy_s(actionInfo.localizedActionName,
"Left Thumb Button");
1398 actionInfo.countSubactionPaths = 1;
1399 actionInfo.subactionPaths = &mInput.handSubactionPath[VrController::Left];
1400 result = xrCreateAction(mInput.actionSet, &actionInfo, &mInput.buttonAction[ControllerButtons::btnLThumb]);
1401 if (!xr_result(mInstance, result,
"failed to creates Left Thumb action!"))
1404 actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
1405 strcpy_s(actionInfo.actionName,
"lthumb_touch");
1406 strcpy_s(actionInfo.localizedActionName,
"Left Thumb Touch");
1407 actionInfo.countSubactionPaths = 1;
1408 actionInfo.subactionPaths = &mInput.handSubactionPath[VrController::Left];
1409 result = xrCreateAction(mInput.actionSet, &actionInfo, &mInput.touchAction[ControllerTouch::touchLThumb]);
1410 if (!xr_result(mInstance, result,
"failed to creates Left Thumb action!"))
1413 actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
1414 strcpy_s(actionInfo.actionName,
"thumbup_touch");
1415 strcpy_s(actionInfo.localizedActionName,
"Thumbup Touch");
1416 actionInfo.countSubactionPaths = uint32_t(mInput.handSubactionPath.size());
1417 actionInfo.subactionPaths = mInput.handSubactionPath.data();
1418 result = xrCreateAction(mInput.actionSet, &actionInfo, &mInput.touchAction[ControllerTouch::touchThumbUp]);
1419 if (!xr_result(mInstance, result,
"failed to creates Thumbup Touch action!"))
1422 actionInfo.actionType = XR_ACTION_TYPE_FLOAT_INPUT;
1423 strcpy_s(actionInfo.actionName,
"thumbstick_x");
1424 strcpy_s(actionInfo.localizedActionName,
"Thumbstick X value");
1425 actionInfo.countSubactionPaths = uint32_t(mInput.handSubactionPath.size());
1426 actionInfo.subactionPaths = mInput.handSubactionPath.data();
1427 result = xrCreateAction(mInput.actionSet, &actionInfo, &mInput.analogAction[ControllerAnalog::analogPadX]);
1428 if (!xr_result(mInstance, result,
"failed to creates Thumbstick X action!"))
1431 actionInfo.actionType = XR_ACTION_TYPE_FLOAT_INPUT;
1432 strcpy_s(actionInfo.actionName,
"thumbstick_y");
1433 strcpy_s(actionInfo.localizedActionName,
"Thumbstick Y value");
1434 actionInfo.countSubactionPaths = uint32_t(mInput.handSubactionPath.size());
1435 actionInfo.subactionPaths = mInput.handSubactionPath.data();
1436 result = xrCreateAction(mInput.actionSet, &actionInfo, &mInput.analogAction[ControllerAnalog::analogPadY]);
1437 if (!xr_result(mInstance, result,
"failed to creates Thumbstick Y action!"))
1440 actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
1441 strcpy_s(actionInfo.actionName,
"grip_button");
1442 strcpy_s(actionInfo.localizedActionName,
"Grip Button");
1443 actionInfo.countSubactionPaths = uint32_t(mInput.handSubactionPath.size());
1444 actionInfo.subactionPaths = mInput.handSubactionPath.data();
1445 result = xrCreateAction(mInput.actionSet, &actionInfo, &mInput.buttonAction[ControllerButtons::btnGrip]);
1446 if (!xr_result(mInstance, result,
"failed to creates Grip Button action!"))
1449 actionInfo.actionType = XR_ACTION_TYPE_FLOAT_INPUT;
1450 strcpy_s(actionInfo.actionName,
"grip_value");
1451 strcpy_s(actionInfo.localizedActionName,
"Grip Value");
1452 actionInfo.countSubactionPaths = uint32_t(mInput.handSubactionPath.size());
1453 actionInfo.subactionPaths = mInput.handSubactionPath.data();
1454 result = xrCreateAction(mInput.actionSet, &actionInfo, &mInput.analogAction[ControllerAnalog::analogGrip]);
1455 if (!xr_result(mInstance, result,
"failed to creates Grip Value action!"))
1458 actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
1459 strcpy_s(actionInfo.actionName,
"trigger_button");
1460 strcpy_s(actionInfo.localizedActionName,
"Trigger Button");
1461 actionInfo.countSubactionPaths = uint32_t(mInput.handSubactionPath.size());
1462 actionInfo.subactionPaths = mInput.handSubactionPath.data();
1463 result = xrCreateAction(mInput.actionSet, &actionInfo, &mInput.buttonAction[ControllerButtons::btnTrigger]);
1464 if (!xr_result(mInstance, result,
"failed to creates Trigger Button action!"))
1467 actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
1468 strcpy_s(actionInfo.actionName,
"trigger_touch");
1469 strcpy_s(actionInfo.localizedActionName,
"Trigger Touch");
1470 actionInfo.countSubactionPaths = uint32_t(mInput.handSubactionPath.size());
1471 actionInfo.subactionPaths = mInput.handSubactionPath.data();
1472 result = xrCreateAction(mInput.actionSet, &actionInfo, &mInput.touchAction[ControllerTouch::touchTrigger]);
1473 if (!xr_result(mInstance, result,
"failed to creates Trigger Touch action!"))
1476 actionInfo.actionType = XR_ACTION_TYPE_FLOAT_INPUT;
1477 strcpy_s(actionInfo.actionName,
"trigger_value");
1478 strcpy_s(actionInfo.localizedActionName,
"Trigger Value");
1479 actionInfo.countSubactionPaths = uint32_t(mInput.handSubactionPath.size());
1480 actionInfo.subactionPaths = mInput.handSubactionPath.data();
1481 result = xrCreateAction(mInput.actionSet, &actionInfo, &mInput.analogAction[ControllerAnalog::analogTrigger]);
1482 if (!xr_result(mInstance, result,
"failed to creates Trigger Value action!"))
1485 actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
1486 strcpy_s(actionInfo.actionName,
"menu_button");
1487 strcpy_s(actionInfo.localizedActionName,
"Menu Button");
1488 actionInfo.countSubactionPaths = uint32_t(mInput.handSubactionPath.size());
1489 actionInfo.subactionPaths = mInput.handSubactionPath.data();
1490 result = xrCreateAction(mInput.actionSet, &actionInfo, &mInput.buttonAction[ControllerButtons::btnMenu]);
1491 if (!xr_result(mInstance, result,
"failed to creates Menu Button action!"))
1495 actionInfo.actionType = XR_ACTION_TYPE_POSE_INPUT;
1496 strcpy_s(actionInfo.actionName,
"hand_pose");
1497 strcpy_s(actionInfo.localizedActionName,
"Hand Pose");
1498 actionInfo.countSubactionPaths = uint32_t(mInput.handSubactionPath.size());
1499 actionInfo.subactionPaths = mInput.handSubactionPath.data();
1500 result = xrCreateAction(mInput.actionSet, &actionInfo, &mInput.poseAction);
1501 if (!xr_result(mInstance, result,
"failed to creates pose action!"))
1505 actionInfo.actionType = XR_ACTION_TYPE_VIBRATION_OUTPUT;
1506 strcpy_s(actionInfo.actionName,
"vibrate_hand");
1507 strcpy_s(actionInfo.localizedActionName,
"Vibrate Hand");
1508 actionInfo.countSubactionPaths = uint32_t(mInput.handSubactionPath.size());
1509 actionInfo.subactionPaths = mInput.handSubactionPath.data();
1510 result = xrCreateAction(mInput.actionSet, &actionInfo, &mInput.vibrateAction);
1511 if (!xr_result(mInstance, result,
"failed to creates vibrate action!"))
1524 std::array<XrPath, MAX_VR_CONTROLLERS> thumbClickPath;
1525 std::array<XrPath, MAX_VR_CONTROLLERS> thumbTouchPath;
1526 std::array<XrPath, MAX_VR_CONTROLLERS> thumbRestPath;
1528 std::array<XrPath, MAX_VR_CONTROLLERS> squeezeValuePath;
1529 std::array<XrPath, MAX_VR_CONTROLLERS> squeezeClickPath;
1530 std::array<XrPath, MAX_VR_CONTROLLERS> triggerValuePath;
1531 std::array<XrPath, MAX_VR_CONTROLLERS> triggerTouchPath;
1532 std::array<XrPath, MAX_VR_CONTROLLERS> triggerClickPath;
1534 std::array<XrPath, MAX_VR_CONTROLLERS> trackpadXPath;
1535 std::array<XrPath, MAX_VR_CONTROLLERS> trackpadYPath;
1536 std::array<XrPath, MAX_VR_CONTROLLERS> trackpadTouchPath;
1537 std::array<XrPath, MAX_VR_CONTROLLERS> trackpadClickPath;
1539 std::array<XrPath, MAX_VR_CONTROLLERS> thumbStickXPath;
1540 std::array<XrPath, MAX_VR_CONTROLLERS> thumbStickYPath;
1542 std::array<XrPath, MAX_VR_CONTROLLERS> selectClickPath;
1543 std::array<XrPath, MAX_VR_CONTROLLERS> menuClickPath;
1544 std::array<XrPath, MAX_VR_CONTROLLERS> sysClickPath;
1545 std::array<XrPath, MAX_VR_CONTROLLERS> posePath;
1546 std::array<XrPath, MAX_VR_CONTROLLERS> hapticPath;
1548 xrStringToPath(mInstance,
"/user/hand/right/input/a/click", &aClickPath);
1549 xrStringToPath(mInstance,
"/user/hand/right/input/a/touch", &aTouchPath);
1550 xrStringToPath(mInstance,
"/user/hand/right/input/b/click", &bClickPath);
1551 xrStringToPath(mInstance,
"/user/hand/right/input/b/touch", &bTouchPath);
1553 xrStringToPath(mInstance,
"/user/hand/left/input/x/click", &xClickPath);
1554 xrStringToPath(mInstance,
"/user/hand/left/input/x/touch", &xTouchPath);
1555 xrStringToPath(mInstance,
"/user/hand/left/input/y/click", &yClickPath);
1556 xrStringToPath(mInstance,
"/user/hand/left/input/y/touch", &yTouchPath);
1558 xrStringToPath(mInstance,
"/user/hand/left/input/thumbstick/click", &thumbClickPath[VrController::Left]);
1559 xrStringToPath(mInstance,
"/user/hand/right/input/thumbstick/click", &thumbClickPath[VrController::Right]);
1560 xrStringToPath(mInstance,
"/user/hand/left/input/thumbstick/touch", &thumbTouchPath[VrController::Left]);
1561 xrStringToPath(mInstance,
"/user/hand/right/input/thumbstick/touch", &thumbTouchPath[VrController::Right]);
1563 xrStringToPath(mInstance,
"/user/hand/left/input/thumbstick/x", &thumbStickXPath[VrController::Left]);
1564 xrStringToPath(mInstance,
"/user/hand/right/input/thumbstick/x", &thumbStickXPath[VrController::Right]);
1565 xrStringToPath(mInstance,
"/user/hand/left/input/thumbstick/y", &thumbStickYPath[VrController::Left]);
1566 xrStringToPath(mInstance,
"/user/hand/right/input/thumbstick/y", &thumbStickYPath[VrController::Right]);
1568 xrStringToPath(mInstance,
"/user/hand/left/input/thumbrest/touch", &thumbRestPath[VrController::Left]);
1569 xrStringToPath(mInstance,
"/user/hand/right/input/thumbrest/touch", &thumbRestPath[VrController::Right]);
1571 xrStringToPath(mInstance,
"/user/hand/left/input/squeeze/value", &squeezeValuePath[VrController::Left]);
1572 xrStringToPath(mInstance,
"/user/hand/right/input/squeeze/value", &squeezeValuePath[VrController::Right]);
1573 xrStringToPath(mInstance,
"/user/hand/left/input/squeeze/click", &squeezeClickPath[VrController::Left]);
1574 xrStringToPath(mInstance,
"/user/hand/right/input/squeeze/click", &squeezeClickPath[VrController::Right]);
1576 xrStringToPath(mInstance,
"/user/hand/left/input/trigger/value", &triggerValuePath[VrController::Left]);
1577 xrStringToPath(mInstance,
"/user/hand/right/input/trigger/value", &triggerValuePath[VrController::Right]);
1578 xrStringToPath(mInstance,
"/user/hand/left/input/trigger/touch", &triggerTouchPath[VrController::Left]);
1579 xrStringToPath(mInstance,
"/user/hand/right/input/trigger/touch", &triggerTouchPath[VrController::Right]);
1580 xrStringToPath(mInstance,
"/user/hand/left/input/trigger/click", &triggerClickPath[VrController::Left]);
1581 xrStringToPath(mInstance,
"/user/hand/right/input/trigger/click", &triggerClickPath[VrController::Right]);
1583 xrStringToPath(mInstance,
"/user/hand/left/input/trackpad/x", &trackpadXPath[VrController::Left]);
1584 xrStringToPath(mInstance,
"/user/hand/right/input/trackpad/x", &trackpadXPath[VrController::Right]);
1585 xrStringToPath(mInstance,
"/user/hand/left/input/trackpad/y", &trackpadYPath[VrController::Left]);
1586 xrStringToPath(mInstance,
"/user/hand/right/input/trackpad/y", &trackpadYPath[VrController::Right]);
1587 xrStringToPath(mInstance,
"/user/hand/left/input/trackpad/touch", &trackpadTouchPath[VrController::Left]);
1588 xrStringToPath(mInstance,
"/user/hand/right/input/trackpad/touch", &trackpadTouchPath[VrController::Right]);
1589 xrStringToPath(mInstance,
"/user/hand/left/input/trackpad/click", &trackpadClickPath[VrController::Left]);
1590 xrStringToPath(mInstance,
"/user/hand/right/input/trackpad/click", &trackpadClickPath[VrController::Right]);
1592 xrStringToPath(mInstance,
"/user/hand/left/input/select/click", &selectClickPath[VrController::Left]);
1593 xrStringToPath(mInstance,
"/user/hand/right/input/select/click", &selectClickPath[VrController::Right]);
1595 xrStringToPath(mInstance,
"/user/hand/left/input/menu/click", &menuClickPath[VrController::Left]);
1596 xrStringToPath(mInstance,
"/user/hand/right/input/menu/click", &menuClickPath[VrController::Right]);
1598 xrStringToPath(mInstance,
"/user/hand/left/input/system/click", &sysClickPath[VrController::Left]);
1599 xrStringToPath(mInstance,
"/user/hand/right/input/system/click", &sysClickPath[VrController::Right]);
1601 xrStringToPath(mInstance,
"/user/hand/left/input/grip/pose", &posePath[VrController::Left]);
1602 xrStringToPath(mInstance,
"/user/hand/right/input/grip/pose", &posePath[VrController::Right]);
1603 xrStringToPath(mInstance,
"/user/hand/left/output/haptic", &hapticPath[VrController::Left]);
1604 xrStringToPath(mInstance,
"/user/hand/right/output/haptic", &hapticPath[VrController::Right]);
1608 XrPath khrSimpleInteractionProfilePath;
1609 xrStringToPath(mInstance,
"/interaction_profiles/khr/simple_controller", &khrSimpleInteractionProfilePath);
1610 std::vector<XrActionSuggestedBinding> bindings{ {
1611 {mInput.buttonAction[ControllerButtons::btnTrigger], selectClickPath[VrController::Left]},
1612 {mInput.buttonAction[ControllerButtons::btnTrigger], selectClickPath[VrController::Right]},
1613 {mInput.buttonAction[ControllerButtons::btnMenu], menuClickPath[VrController::Left]},
1614 {mInput.buttonAction[ControllerButtons::btnMenu], menuClickPath[VrController::Right]},
1615 {mInput.poseAction, posePath[VrController::Left]},
1616 {mInput.poseAction, posePath[VrController::Right]},
1617 {mInput.vibrateAction, hapticPath[VrController::Left]},
1618 {mInput.vibrateAction, hapticPath[VrController::Right]}} };
1619 XrInteractionProfileSuggestedBinding suggestedBindings{ XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING };
1620 suggestedBindings.interactionProfile = khrSimpleInteractionProfilePath;
1621 suggestedBindings.suggestedBindings = bindings.data();
1622 suggestedBindings.countSuggestedBindings = (uint32_t)bindings.size();
1623 result = xrSuggestInteractionProfileBindings(mInstance, &suggestedBindings);
1624 if (!xr_result(mInstance, result,
"failed to suggest bindings"))
1629 if (mPicoController.supported)
1632 XrPath picoInteractionProfilePath;
1633 xrStringToPath(mInstance,
"/interaction_profiles/bytedance/pico_neo3_controller", &picoInteractionProfilePath);
1634 std::vector<XrActionSuggestedBinding> bindings{ {
1635 {mInput.buttonAction[ControllerButtons::btnA], aClickPath},
1636 {mInput.touchAction[ControllerTouch::touchA], aTouchPath},
1637 {mInput.buttonAction[ControllerButtons::btnB], bClickPath},
1638 {mInput.touchAction[ControllerTouch::touchB], bTouchPath},
1639 {mInput.buttonAction[ControllerButtons::btnX], xClickPath},
1640 {mInput.touchAction[ControllerTouch::touchX], xTouchPath},
1641 {mInput.buttonAction[ControllerButtons::btnY], yClickPath},
1642 {mInput.touchAction[ControllerTouch::touchY], yTouchPath},
1644 {mInput.buttonAction[ControllerButtons::btnRThumb], thumbClickPath[VrController::Right]},
1645 {mInput.buttonAction[ControllerButtons::btnLThumb], thumbClickPath[VrController::Left]},
1646 {mInput.touchAction[ControllerTouch::touchRThumb], thumbTouchPath[VrController::Right]},
1647 {mInput.touchAction[ControllerTouch::touchLThumb], thumbTouchPath[VrController::Left]},
1648 {mInput.analogAction[ControllerAnalog::analogPadX], thumbStickXPath[VrController::Left]},
1649 {mInput.analogAction[ControllerAnalog::analogPadX], thumbStickXPath[VrController::Right]},
1650 {mInput.analogAction[ControllerAnalog::analogPadY], thumbStickYPath[VrController::Left]},
1651 {mInput.analogAction[ControllerAnalog::analogPadY], thumbStickYPath[VrController::Right]},
1653 {mInput.analogAction[ControllerAnalog::analogGrip], squeezeValuePath[VrController::Left]},
1654 {mInput.analogAction[ControllerAnalog::analogGrip], squeezeValuePath[VrController::Right]},
1655 {mInput.buttonAction[ControllerButtons::btnGrip], squeezeValuePath[VrController::Left]},
1656 {mInput.buttonAction[ControllerButtons::btnGrip], squeezeValuePath[VrController::Right]},
1658 {mInput.analogAction[ControllerAnalog::analogTrigger], triggerValuePath[VrController::Left]},
1659 {mInput.analogAction[ControllerAnalog::analogTrigger], triggerValuePath[VrController::Right]},
1660 {mInput.buttonAction[ControllerButtons::btnTrigger], triggerClickPath[VrController::Left]},
1661 {mInput.buttonAction[ControllerButtons::btnTrigger], triggerClickPath[VrController::Right]},
1662 {mInput.touchAction[ControllerTouch::touchTrigger], triggerTouchPath[VrController::Left]},
1663 {mInput.touchAction[ControllerTouch::touchTrigger], triggerTouchPath[VrController::Right]},
1665 {mInput.touchAction[ControllerTouch::touchThumbUp], thumbRestPath[VrController::Left]},
1666 {mInput.touchAction[ControllerTouch::touchThumbUp], thumbRestPath[VrController::Right]},
1668 {mInput.buttonAction[ControllerButtons::btnMenu], menuClickPath[VrController::Left]},
1669 {mInput.buttonAction[ControllerButtons::btnMenu], menuClickPath[VrController::Right]},
1670 {mInput.poseAction, posePath[VrController::Left]},
1671 {mInput.poseAction, posePath[VrController::Right]},
1672 {mInput.vibrateAction, hapticPath[VrController::Left]},
1673 {mInput.vibrateAction, hapticPath[VrController::Right]}} };
1675 XrInteractionProfileSuggestedBinding suggestedBindings{ XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING };
1676 suggestedBindings.interactionProfile = picoInteractionProfilePath;
1677 suggestedBindings.suggestedBindings = bindings.data();
1678 suggestedBindings.countSuggestedBindings = (uint32_t)bindings.size();
1679 result = xrSuggestInteractionProfileBindings(mInstance, &suggestedBindings);
1680 if (result == XR_ERROR_PATH_UNSUPPORTED)
1681 MMechostr(MSKRUNTIME,
"[OPENXR]: Runtime does not supports %s\n",
"/interaction_profiles/pico/neo3_controller");
1683 xr_result(mInstance, result,
"failed to suggest bindings");
1687 XrPath picoInteractionProfilePath;
1688 xrStringToPath(mInstance,
"/interaction_profiles/bytedance/pico4_controller", &picoInteractionProfilePath);
1689 std::vector<XrActionSuggestedBinding> bindings{ {
1690 {mInput.buttonAction[ControllerButtons::btnA], aClickPath},
1691 {mInput.touchAction[ControllerTouch::touchA], aTouchPath},
1692 {mInput.buttonAction[ControllerButtons::btnB], bClickPath},
1693 {mInput.touchAction[ControllerTouch::touchB], bTouchPath},
1694 {mInput.buttonAction[ControllerButtons::btnX], xClickPath},
1695 {mInput.touchAction[ControllerTouch::touchX], xTouchPath},
1696 {mInput.buttonAction[ControllerButtons::btnY], yClickPath},
1697 {mInput.touchAction[ControllerTouch::touchY], yTouchPath},
1699 {mInput.buttonAction[ControllerButtons::btnRThumb], thumbClickPath[VrController::Right]},
1700 {mInput.buttonAction[ControllerButtons::btnLThumb], thumbClickPath[VrController::Left]},
1701 {mInput.touchAction[ControllerTouch::touchRThumb], thumbTouchPath[VrController::Right]},
1702 {mInput.touchAction[ControllerTouch::touchLThumb], thumbTouchPath[VrController::Left]},
1703 {mInput.analogAction[ControllerAnalog::analogPadX], thumbStickXPath[VrController::Left]},
1704 {mInput.analogAction[ControllerAnalog::analogPadX], thumbStickXPath[VrController::Right]},
1705 {mInput.analogAction[ControllerAnalog::analogPadY], thumbStickYPath[VrController::Left]},
1706 {mInput.analogAction[ControllerAnalog::analogPadY], thumbStickYPath[VrController::Right]},
1708 {mInput.analogAction[ControllerAnalog::analogGrip], squeezeValuePath[VrController::Left]},
1709 {mInput.analogAction[ControllerAnalog::analogGrip], squeezeValuePath[VrController::Right]},
1710 {mInput.buttonAction[ControllerButtons::btnGrip], squeezeValuePath[VrController::Left]},
1711 {mInput.buttonAction[ControllerButtons::btnGrip], squeezeValuePath[VrController::Right]},
1713 {mInput.analogAction[ControllerAnalog::analogTrigger], triggerValuePath[VrController::Left]},
1714 {mInput.analogAction[ControllerAnalog::analogTrigger], triggerValuePath[VrController::Right]},
1715 {mInput.buttonAction[ControllerButtons::btnTrigger], triggerClickPath[VrController::Left]},
1716 {mInput.buttonAction[ControllerButtons::btnTrigger], triggerClickPath[VrController::Right]},
1717 {mInput.touchAction[ControllerTouch::touchTrigger], triggerTouchPath[VrController::Left]},
1718 {mInput.touchAction[ControllerTouch::touchTrigger], triggerTouchPath[VrController::Right]},
1720 {mInput.touchAction[ControllerTouch::touchThumbUp], thumbRestPath[VrController::Left]},
1721 {mInput.touchAction[ControllerTouch::touchThumbUp], thumbRestPath[VrController::Right]},
1723 {mInput.buttonAction[ControllerButtons::btnMenu], menuClickPath[VrController::Left]},
1724 {mInput.poseAction, posePath[VrController::Left]},
1725 {mInput.poseAction, posePath[VrController::Right]},
1726 {mInput.vibrateAction, hapticPath[VrController::Left]},
1727 {mInput.vibrateAction, hapticPath[VrController::Right]}} };
1729 XrInteractionProfileSuggestedBinding suggestedBindings{ XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING };
1730 suggestedBindings.interactionProfile = picoInteractionProfilePath;
1731 suggestedBindings.suggestedBindings = bindings.data();
1732 suggestedBindings.countSuggestedBindings = (uint32_t)bindings.size();
1733 result = xrSuggestInteractionProfileBindings(mInstance, &suggestedBindings);
1734 if (result == XR_ERROR_PATH_UNSUPPORTED)
1735 MMechostr(MSKRUNTIME,
"[OPENXR]: Runtime does not supports %s\n",
"/interaction_profiles/bytedance/pico4_controller");
1737 xr_result(mInstance, result,
"failed to suggest bindings");
1743 XrPath oculusTouchInteractionProfilePath;
1744 xrStringToPath(mInstance,
"/interaction_profiles/oculus/touch_controller", &oculusTouchInteractionProfilePath);
1745 std::vector<XrActionSuggestedBinding> bindings{ {
1746 {mInput.buttonAction[ControllerButtons::btnA], aClickPath},
1747 {mInput.touchAction[ControllerTouch::touchA], aTouchPath},
1748 {mInput.buttonAction[ControllerButtons::btnB], bClickPath},
1749 {mInput.touchAction[ControllerTouch::touchB], bTouchPath},
1750 {mInput.buttonAction[ControllerButtons::btnX], xClickPath},
1751 {mInput.touchAction[ControllerTouch::touchX], xTouchPath},
1752 {mInput.buttonAction[ControllerButtons::btnY], yClickPath},
1753 {mInput.touchAction[ControllerTouch::touchY], yTouchPath},
1755 {mInput.buttonAction[ControllerButtons::btnRThumb], thumbClickPath[VrController::Right]},
1756 {mInput.buttonAction[ControllerButtons::btnLThumb], thumbClickPath[VrController::Left]},
1757 {mInput.touchAction[ControllerTouch::touchRThumb], thumbTouchPath[VrController::Right]},
1758 {mInput.touchAction[ControllerTouch::touchLThumb], thumbTouchPath[VrController::Left]},
1759 {mInput.analogAction[ControllerAnalog::analogPadX], thumbStickXPath[VrController::Left]},
1760 {mInput.analogAction[ControllerAnalog::analogPadX], thumbStickXPath[VrController::Right]},
1761 {mInput.analogAction[ControllerAnalog::analogPadY], thumbStickYPath[VrController::Left]},
1762 {mInput.analogAction[ControllerAnalog::analogPadY], thumbStickYPath[VrController::Right]},
1764 {mInput.analogAction[ControllerAnalog::analogGrip], squeezeValuePath[VrController::Left]},
1765 {mInput.analogAction[ControllerAnalog::analogGrip], squeezeValuePath[VrController::Right]},
1766 {mInput.buttonAction[ControllerButtons::btnGrip], squeezeValuePath[VrController::Left]},
1767 {mInput.buttonAction[ControllerButtons::btnGrip], squeezeValuePath[VrController::Right]},
1769 {mInput.analogAction[ControllerAnalog::analogTrigger], triggerValuePath[VrController::Left]},
1770 {mInput.analogAction[ControllerAnalog::analogTrigger], triggerValuePath[VrController::Right]},
1771 {mInput.buttonAction[ControllerButtons::btnTrigger], triggerValuePath[VrController::Left]},
1772 {mInput.buttonAction[ControllerButtons::btnTrigger], triggerValuePath[VrController::Right]},
1773 {mInput.touchAction[ControllerTouch::touchTrigger], triggerTouchPath[VrController::Left]},
1774 {mInput.touchAction[ControllerTouch::touchTrigger], triggerTouchPath[VrController::Right]},
1776 {mInput.touchAction[ControllerTouch::touchThumbUp], thumbRestPath[VrController::Left]},
1777 {mInput.touchAction[ControllerTouch::touchThumbUp], thumbRestPath[VrController::Right]},
1779 {mInput.buttonAction[ControllerButtons::btnMenu], menuClickPath[VrController::Left]},
1780 {mInput.poseAction, posePath[VrController::Left]},
1781 {mInput.poseAction, posePath[VrController::Right]},
1782 {mInput.vibrateAction, hapticPath[VrController::Left]},
1783 {mInput.vibrateAction, hapticPath[VrController::Right]}} };
1785 XrInteractionProfileSuggestedBinding suggestedBindings{ XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING };
1786 suggestedBindings.interactionProfile = oculusTouchInteractionProfilePath;
1787 suggestedBindings.suggestedBindings = bindings.data();
1788 suggestedBindings.countSuggestedBindings = (uint32_t)bindings.size();
1789 result = xrSuggestInteractionProfileBindings(mInstance, &suggestedBindings);
1790 if (result == XR_ERROR_PATH_UNSUPPORTED)
1791 MMechostr(MSKRUNTIME,
"[OPENXR]: Runtime does not supports %s\n",
"/interaction_profiles/oculus/touch_controller");
1793 xr_result(mInstance, result,
"failed to suggest bindings");
1798 XrPath viveControllerInteractionProfilePath;
1799 xrStringToPath(mInstance,
"/interaction_profiles/htc/vive_controller", &viveControllerInteractionProfilePath);
1800 std::vector<XrActionSuggestedBinding> bindings{ {
1801 {mInput.buttonAction[ControllerButtons::btnRThumb], trackpadClickPath[VrController::Right]},
1802 {mInput.buttonAction[ControllerButtons::btnLThumb], trackpadClickPath[VrController::Left]},
1803 {mInput.touchAction[ControllerTouch::touchRThumb], trackpadTouchPath[VrController::Right]},
1804 {mInput.touchAction[ControllerTouch::touchLThumb], trackpadTouchPath[VrController::Left]},
1805 {mInput.analogAction[ControllerAnalog::analogPadX], trackpadXPath[VrController::Left]},
1806 {mInput.analogAction[ControllerAnalog::analogPadX], trackpadXPath[VrController::Right]},
1807 {mInput.analogAction[ControllerAnalog::analogPadY], trackpadYPath[VrController::Left]},
1808 {mInput.analogAction[ControllerAnalog::analogPadY], trackpadYPath[VrController::Right]},
1810 {mInput.buttonAction[ControllerButtons::btnGrip], squeezeClickPath[VrController::Left]},
1811 {mInput.buttonAction[ControllerButtons::btnGrip], squeezeClickPath[VrController::Right]},
1812 {mInput.analogAction[ControllerAnalog::analogGrip], squeezeClickPath[VrController::Left]},
1813 {mInput.analogAction[ControllerAnalog::analogGrip], squeezeClickPath[VrController::Right]},
1815 {mInput.analogAction[ControllerAnalog::analogTrigger], triggerValuePath[VrController::Left]},
1816 {mInput.analogAction[ControllerAnalog::analogTrigger], triggerValuePath[VrController::Right]},
1817 {mInput.buttonAction[ControllerButtons::btnTrigger], triggerClickPath[VrController::Left]},
1818 {mInput.buttonAction[ControllerButtons::btnTrigger], triggerClickPath[VrController::Right]},
1820 {mInput.buttonAction[ControllerButtons::btnMenu], menuClickPath[VrController::Left]},
1821 {mInput.buttonAction[ControllerButtons::btnMenu], menuClickPath[VrController::Right]},
1822 {mInput.poseAction, posePath[VrController::Left]},
1823 {mInput.poseAction, posePath[VrController::Right]},
1824 {mInput.vibrateAction, hapticPath[VrController::Left]},
1825 {mInput.vibrateAction, hapticPath[VrController::Right]}} };
1826 XrInteractionProfileSuggestedBinding suggestedBindings{ XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING };
1827 suggestedBindings.interactionProfile = viveControllerInteractionProfilePath;
1828 suggestedBindings.suggestedBindings = bindings.data();
1829 suggestedBindings.countSuggestedBindings = (uint32_t)bindings.size();
1830 result = xrSuggestInteractionProfileBindings(mInstance, &suggestedBindings);
1831 if (result == XR_ERROR_PATH_UNSUPPORTED)
1832 MMechostr(MSKRUNTIME,
"[OPENXR]: Runtime does not supports %s\n",
"/interaction_profiles/htc/vive_controller");
1834 xr_result(mInstance, result,
"failed to suggest bindings");
1839 XrPath indexControllerInteractionProfilePath;
1840 xrStringToPath(mInstance,
"/interaction_profiles/valve/index_controller", &indexControllerInteractionProfilePath);
1841 std::vector<XrActionSuggestedBinding> bindings{ {
1842 {mInput.buttonAction[ControllerButtons::btnRThumb], thumbClickPath[VrController::Right]},
1843 {mInput.buttonAction[ControllerButtons::btnLThumb], thumbClickPath[VrController::Left]},
1844 {mInput.touchAction[ControllerTouch::touchRThumb], thumbTouchPath[VrController::Right]},
1845 {mInput.touchAction[ControllerTouch::touchLThumb], thumbTouchPath[VrController::Left]},
1846 {mInput.analogAction[ControllerAnalog::analogPadX], thumbStickXPath[VrController::Left]},
1847 {mInput.analogAction[ControllerAnalog::analogPadX], thumbStickXPath[VrController::Right]},
1848 {mInput.analogAction[ControllerAnalog::analogPadY], thumbStickYPath[VrController::Left]},
1849 {mInput.analogAction[ControllerAnalog::analogPadY], thumbStickYPath[VrController::Right]},
1851 {mInput.analogAction[ControllerAnalog::analogGrip], squeezeValuePath[VrController::Left]},
1852 {mInput.analogAction[ControllerAnalog::analogGrip], squeezeValuePath[VrController::Right]},
1854 {mInput.analogAction[ControllerAnalog::analogTrigger], triggerValuePath[VrController::Left]},
1855 {mInput.analogAction[ControllerAnalog::analogTrigger], triggerValuePath[VrController::Right]},
1856 {mInput.touchAction[ControllerTouch::touchTrigger], triggerTouchPath[VrController::Left]},
1857 {mInput.touchAction[ControllerTouch::touchTrigger], triggerTouchPath[VrController::Right]},
1858 {mInput.buttonAction[ControllerButtons::btnTrigger], triggerClickPath[VrController::Left]},
1859 {mInput.buttonAction[ControllerButtons::btnTrigger], triggerClickPath[VrController::Right]},
1861 {mInput.buttonAction[ControllerButtons::btnMenu], sysClickPath[VrController::Left]},
1862 {mInput.buttonAction[ControllerButtons::btnMenu], sysClickPath[VrController::Right]},
1863 {mInput.poseAction, posePath[VrController::Left]},
1864 {mInput.poseAction, posePath[VrController::Right]},
1866 {mInput.vibrateAction, hapticPath[VrController::Left]},
1867 {mInput.vibrateAction, hapticPath[VrController::Right]}} };
1868 XrInteractionProfileSuggestedBinding suggestedBindings{ XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING };
1869 suggestedBindings.interactionProfile = indexControllerInteractionProfilePath;
1870 suggestedBindings.suggestedBindings = bindings.data();
1871 suggestedBindings.countSuggestedBindings = (uint32_t)bindings.size();
1872 result = xrSuggestInteractionProfileBindings(mInstance, &suggestedBindings);
1873 if (result == XR_ERROR_PATH_UNSUPPORTED)
1874 MMechostr(MSKRUNTIME,
"[OPENXR]: Runtime does not supports %s\n",
"/interaction_profiles/valve/index_controller");
1876 xr_result(mInstance, result,
"failed to suggest bindings");
1881 XrPath microsoftMixedRealityInteractionProfilePath;
1882 xrStringToPath(mInstance,
"/interaction_profiles/microsoft/motion_controller", µsoftMixedRealityInteractionProfilePath);
1883 std::vector<XrActionSuggestedBinding> bindings{ {
1884 {mInput.buttonAction[ControllerButtons::btnRThumb], thumbClickPath[VrController::Right]},
1885 {mInput.buttonAction[ControllerButtons::btnLThumb], thumbClickPath[VrController::Left]},
1886 {mInput.touchAction[ControllerTouch::touchRThumb], trackpadTouchPath[VrController::Right]},
1887 {mInput.touchAction[ControllerTouch::touchLThumb], trackpadTouchPath[VrController::Left]},
1888 {mInput.analogAction[ControllerAnalog::analogPadX], thumbStickXPath[VrController::Left]},
1889 {mInput.analogAction[ControllerAnalog::analogPadX], thumbStickXPath[VrController::Right]},
1890 {mInput.analogAction[ControllerAnalog::analogPadY], thumbStickYPath[VrController::Left]},
1891 {mInput.analogAction[ControllerAnalog::analogPadY], thumbStickYPath[VrController::Right]},
1893 {mInput.buttonAction[ControllerButtons::btnGrip], squeezeClickPath[VrController::Left]},
1894 {mInput.buttonAction[ControllerButtons::btnGrip], squeezeClickPath[VrController::Right]},
1896 {mInput.analogAction[ControllerAnalog::analogTrigger], triggerValuePath[VrController::Left]},
1897 {mInput.analogAction[ControllerAnalog::analogTrigger], triggerValuePath[VrController::Right]},
1898 {mInput.buttonAction[ControllerButtons::btnTrigger], triggerValuePath[VrController::Left]},
1899 {mInput.buttonAction[ControllerButtons::btnTrigger], triggerValuePath[VrController::Right]},
1901 {mInput.buttonAction[ControllerButtons::btnMenu], menuClickPath[VrController::Left]},
1902 {mInput.buttonAction[ControllerButtons::btnMenu], menuClickPath[VrController::Right]},
1903 {mInput.poseAction, posePath[VrController::Left]},
1904 {mInput.poseAction, posePath[VrController::Right]},
1905 {mInput.vibrateAction, hapticPath[VrController::Left]},
1906 {mInput.vibrateAction, hapticPath[VrController::Right]}} };
1907 XrInteractionProfileSuggestedBinding suggestedBindings{ XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING };
1908 suggestedBindings.interactionProfile = microsoftMixedRealityInteractionProfilePath;
1909 suggestedBindings.suggestedBindings = bindings.data();
1910 suggestedBindings.countSuggestedBindings = (uint32_t)bindings.size();
1911 result = xrSuggestInteractionProfileBindings(mInstance, &suggestedBindings);
1912 if (result == XR_ERROR_PATH_UNSUPPORTED)
1913 MMechostr(MSKRUNTIME,
"[OPENXR]: Runtime does not supports %s\n",
"/interaction_profiles/microsoft/motion_controller");
1915 xr_result(mInstance, result,
"failed to suggest bindings");
1918 XrActionSpaceCreateInfo actionSpaceInfo{ XR_TYPE_ACTION_SPACE_CREATE_INFO };
1919 actionSpaceInfo.action = mInput.poseAction;
1920 actionSpaceInfo.poseInActionSpace.orientation.w = 1.f;
1921 actionSpaceInfo.subactionPath = mInput.handSubactionPath[VrController::Left];
1922 result = xrCreateActionSpace(mSession, &actionSpaceInfo, &mInput.handSpace[VrController::Left]);
1923 if (!xr_result(mInstance, result,
"failed to create left hand pose space"))
1926 actionSpaceInfo.subactionPath = mInput.handSubactionPath[VrController::Right];
1927 result = xrCreateActionSpace(mSession, &actionSpaceInfo, &mInput.handSpace[VrController::Right]);
1928 if (!xr_result(mInstance, result,
"failed to create right hand pose space"))
1931 XrSessionActionSetsAttachInfo attachInfo{ XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO, XR_NULL_HANDLE, 1, &mInput.actionSet };
1932 result = xrAttachSessionActionSets(mSession, &attachInfo);
1933 if (!xr_result(mInstance, result,
"failed to attach action set"))
1939void sOpenXr::getControllerOffset(ControllerType type, VrController side,
bool skeletal,
Vector3 &vec,
Quaternion &quat)
1944 case HANDS_CONTROLLER:
1945 case CLASSIC_CONTROLLER:
1947 quat = quat *
Quaternion(sqrt(0.5f), 0.0f, 0.0f, (side == VrController::Right) ? sqrt(0.5f) : -sqrt(0.5f));
1949 case HTCVIVE_CONTROLLER:
1952 quat = quat *
Quaternion(sqrt(0.5f), 0.0f, 0.0f, (side == VrController::Right) ? sqrt(0.5f) : -sqrt(0.5f));
1953 quat = quat *
Quaternion(0.9990482f, 0.0436194f, 0.0f, 0.0f);
1954 quat = quat *
Quaternion(0.9961947f, 0.0f, (side == VrController::Right) ? -0.0871557f : 0.0871557f, 0.0f);
1958 quat = quat *
Quaternion(0.9063078f, -0.4226183f, 0.0f, 0.0f);
1959 vec += quat *
Vector3((side == VrController::Right) ? 0.04f : -0.04f, -0.005f, 0.08f);
1962 case VALVE_INDEX_CONTROLLER:
1963 case PICO_PICO4_CONTROLLER:
1964 case PICO_NEO3_CONTROLLER:
1967 quat = quat *
Quaternion(sqrt(0.5f), 0.0f, 0.0f, (side == VrController::Right) ? sqrt(0.5f) : -sqrt(0.5f));
1971 quat = quat *
Quaternion(0.9961947f, -0.0871557f, 0.0f, 0.0f);
1972 vec += quat *
Vector3((side == VrController::Right) ? 0.06f : -0.06f, -0.03f, 0.09f);
1975 case OCULUS_TOUCH_CONTROLLER:
1978 quat = quat *
Quaternion(sqrt(0.5f), 0.0f, 0.0f, (side == VrController::Right) ? sqrt(0.5f) : -sqrt(0.5f));
1982 quat = quat *
Quaternion(0.8660254f, -0.5f, 0.0f, 0.0f);
1983 vec += quat *
Vector3((side == VrController::Right) ? 0.04f : -0.04f, 0.0f, 0.06f);
1986 case MS_MOTION_CONTROLLER:
1988 quat = quat * ((side == VrController::Right) ?
Quaternion(0.0f, 0.0f, 0.0f, 1.0f) *
Quaternion(sqrt(0.5f), 0.0f, 0.0f, -sqrt(0.5f)) :
Quaternion(sqrt(0.5f), 0.0f, 0.0f, sqrt(0.5f)));
1995void sOpenXr::updateControllers(XrFrameState frameState)
1998 XrHandJointLocationEXT joints[MAX_VR_CONTROLLERS][XR_HAND_JOINT_COUNT_EXT];
1999 XrHandJointVelocityEXT joint_velocity[MAX_VR_CONTROLLERS][XR_HAND_JOINT_COUNT_EXT];
2000 XrHandJointLocationsEXT joint_locations[MAX_VR_CONTROLLERS];
2001 XrHandJointVelocitiesEXT joint_velocities[MAX_VR_CONTROLLERS];
2002 XrHandTrackingAimStateFB aim_states[MAX_VR_CONTROLLERS];
2004 for (
auto hand : { VrController::Left, VrController::Right })
2006 mInput.handVisible[hand] =
false;
2007 if (mHandTracking.system_supported)
2010 if (mHandTracking.gestures)
2011 aim_states[hand] = XrHandTrackingAimStateFB{ XR_TYPE_HAND_TRACKING_AIM_STATE_FB, XR_NULL_HANDLE };
2013 joint_velocities[hand] = XrHandJointVelocitiesEXT{ XR_TYPE_HAND_JOINT_VELOCITIES_EXT, (mHandTracking.gestures) ? &aim_states[hand] : XR_NULL_HANDLE, XR_HAND_JOINT_COUNT_EXT, joint_velocity[hand] };
2014 joint_locations[hand] = XrHandJointLocationsEXT{ XR_TYPE_HAND_JOINT_LOCATIONS_EXT, &joint_velocities[hand], 0, XR_HAND_JOINT_COUNT_EXT, joints[hand] };
2016 if (mHandTracking.trackers[hand] == XR_NULL_HANDLE)
2019 XrHandJointsLocateInfoEXT globalInfo = { XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT, XR_NULL_HANDLE, mPlaySpace, frameState.predictedDisplayTime };
2020 result = mHandTracking.pfnLocateHandJointsEXT(mHandTracking.trackers[hand], &globalInfo, &joint_locations[hand]);
2021 if (!xr_result(mInstance, result,
"failed to locate hand %d joints!", hand))
2024 if (joint_locations[hand].isActive)
2026 if ((joint_locations[hand].jointLocations[XR_HAND_JOINT_WRIST_EXT].locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) != 0 &&
2027 (joint_locations[hand].jointLocations[XR_HAND_JOINT_WRIST_EXT].locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) != 0)
2029 mControllerType[hand] = ControllerType::HANDS_CONTROLLER;
2030 mInput.handVisible[hand] =
true;
2032 Vector3 offVec =
Vector3(joint_locations[hand].jointLocations[XR_HAND_JOINT_WRIST_EXT].pose.position);
2033 Quaternion offQuat =
Quaternion(joint_locations[hand].jointLocations[XR_HAND_JOINT_WRIST_EXT].pose.orientation);
2034 getControllerOffset(mLastControllerType, hand,
true, offVec, offQuat);
2036 mInput.handQuat[hand] = offQuat;
2037 mInput.handPos[hand] = offVec;
2039 if ((joint_velocities[hand].jointVelocities[XR_HAND_JOINT_WRIST_EXT].velocityFlags & XR_SPACE_VELOCITY_LINEAR_VALID_BIT) != 0 &&
2040 (joint_velocities[hand].jointVelocities[XR_HAND_JOINT_WRIST_EXT].velocityFlags & XR_SPACE_VELOCITY_ANGULAR_VALID_BIT) != 0)
2042 mInput.handVelocity[hand] = joint_velocities[hand].jointVelocities[XR_HAND_JOINT_WRIST_EXT].linearVelocity;
2043 mInput.handAngularVelocity[hand] = joint_velocities[hand].jointVelocities[XR_HAND_JOINT_WRIST_EXT].angularVelocity;
2047 mInput.handVelocity[hand] =
Vector3{ 0.0f, 0.0f, 0.0f };
2048 mInput.handAngularVelocity[hand] =
Vector3{ 0.0f, 0.0f, 0.0f };
2051 int thp = ((joint_locations[hand].jointLocations[XR_HAND_JOINT_THUMB_METACARPAL_EXT].locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) != 0) ? XR_HAND_JOINT_THUMB_METACARPAL_EXT : XR_HAND_JOINT_THUMB_PROXIMAL_EXT;
2052 int inp = ((joint_locations[hand].jointLocations[XR_HAND_JOINT_INDEX_METACARPAL_EXT].locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) != 0 && !mIsPico) ? XR_HAND_JOINT_INDEX_METACARPAL_EXT : XR_HAND_JOINT_INDEX_PROXIMAL_EXT;
2053 int mdp = ((joint_locations[hand].jointLocations[XR_HAND_JOINT_MIDDLE_METACARPAL_EXT].locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) != 0 && !mIsPico) ? XR_HAND_JOINT_MIDDLE_METACARPAL_EXT : XR_HAND_JOINT_MIDDLE_PROXIMAL_EXT;
2054 int rgp = ((joint_locations[hand].jointLocations[XR_HAND_JOINT_RING_METACARPAL_EXT].locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) != 0 && !mIsPico) ? XR_HAND_JOINT_RING_METACARPAL_EXT : XR_HAND_JOINT_RING_PROXIMAL_EXT;
2055 int ltp = ((joint_locations[hand].jointLocations[XR_HAND_JOINT_LITTLE_METACARPAL_EXT].locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) != 0) ? XR_HAND_JOINT_LITTLE_METACARPAL_EXT : XR_HAND_JOINT_LITTLE_PROXIMAL_EXT;
2057 for (uint32_t j = 0; j < joint_locations[hand].jointCount; j++)
2059 if ((mIsPico && (j == XR_HAND_JOINT_INDEX_METACARPAL_EXT || j == XR_HAND_JOINT_MIDDLE_METACARPAL_EXT || j == XR_HAND_JOINT_RING_METACARPAL_EXT)) ||
2060 ((joint_locations[hand].jointLocations[j].locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) == 0))
2062 mHandTracking.bones[hand][j].valid =
false;
2066 if ((mLastControllerType == MS_MOTION_CONTROLLER) && j == XR_HAND_JOINT_WRIST_EXT && (hand == VrController::Left))
2067 mHandTracking.bones[hand][j].rotation =
Quaternion(joint_locations[hand].jointLocations[j].pose.orientation) *
Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
2069 mHandTracking.bones[hand][j].rotation =
Quaternion(joint_locations[hand].jointLocations[j].pose.orientation);
2079 qref =
Quaternion(joint_locations[hand].jointLocations[XR_HAND_JOINT_WRIST_EXT].pose.orientation);
2081 qref =
Quaternion(joint_locations[hand].jointLocations[j-1].pose.orientation);
2084 mHandTracking.bones[hand][j].rotation = mHandTracking.bones[hand][j].rotation.Inverse() * qref;
2086 mHandTracking.bones[hand][j].position = joint_locations[hand].jointLocations[j].pose.position;
2087 mHandTracking.bones[hand][j].valid =
true;
2091 bool mpinch =
false;
2092 bool ipinch =
false;
2095 Vector3 palmpos = mHandTracking.bones[hand][XR_HAND_JOINT_PALM_EXT].position;
2096 float thmubpdist =
Vector3(mHandTracking.bones[hand][XR_HAND_JOINT_INDEX_TIP_EXT].position).distance(mHandTracking.bones[hand][XR_HAND_JOINT_THUMB_TIP_EXT].position);
2097 float thmubidist =
Vector3(mHandTracking.bones[hand][XR_HAND_JOINT_INDEX_INTERMEDIATE_EXT].position).distance(mHandTracking.bones[hand][XR_HAND_JOINT_THUMB_TIP_EXT].position);
2098 float indexdist = palmpos.distance(mHandTracking.bones[hand][XR_HAND_JOINT_INDEX_TIP_EXT].position);
2099 float middist = palmpos.distance(mHandTracking.bones[hand][XR_HAND_JOINT_MIDDLE_TIP_EXT].position);
2100 float ringdist = palmpos.distance(mHandTracking.bones[hand][XR_HAND_JOINT_RING_TIP_EXT].position);
2101 float littledist = palmpos.distance(mHandTracking.bones[hand][XR_HAND_JOINT_LITTLE_TIP_EXT].position);
2103 if (mHandTracking.gestures)
2105 mInput.buttonStates[hand][ControllerButtons::btnMenu] = ((aim_states[hand].status & XR_HAND_TRACKING_AIM_MENU_PRESSED_BIT_FB) != 0) ? true :
false;
2106 mpinch = ((aim_states[hand].status & XR_HAND_TRACKING_AIM_MIDDLE_PINCHING_BIT_FB) != 0) ? true :
false;
2107 ipinch = ((aim_states[hand].status & XR_HAND_TRACKING_AIM_INDEX_PINCHING_BIT_FB) != 0) ? true :
false;
2108 mInput.analogStates[hand][ControllerAnalog::analogTrigger] = aim_states[hand].pinchStrengthIndex;
2109 mInput.analogStates[hand][ControllerAnalog::analogGrip] = aim_states[hand].pinchStrengthMiddle;
2113 mInput.analogStates[hand][ControllerAnalog::analogTrigger] = (thmubpdist <= 0.035f) ? 1.0f - std::min(1.0f, std::max(0.0f, (1.0f / 3.5f) * ((thmubpdist - 0.01f) * 100.0f))) : 0.0f;
2114 ipinch = (mInput.analogStates[hand][ControllerAnalog::analogTrigger] >= 0.95) ?
true : false;
2115 mpinch = ((middist <= 0.05f) && (ringdist <= 0.05f)) ?
true : false;
2116 mInput.analogStates[hand][ControllerAnalog::analogGrip] = mpinch ? 1.0f : 0.0f;
2119 if (!mInput.touchStates[hand][ControllerTouch::touchIndexPointing])
2120 mInput.touchStates[hand][ControllerTouch::touchIndexPointing] = ((middist <= 0.05f) && (ringdist <= 0.055f) && (littledist <= 0.065f) && (indexdist > 0.07f)) ?
true : false;
2122 if (!mInput.buttonStates[hand][ControllerButtons::btnGrip])
2123 mInput.buttonStates[hand][ControllerButtons::btnGrip] = mpinch;
2125 if (!mInput.buttonStates[hand][ControllerButtons::btnTrigger])
2126 mInput.buttonStates[hand][ControllerButtons::btnTrigger] = ((indexdist <= 0.05f) || ipinch) ? true :
false;
2130 if (!mInput.buttonStates[hand][ControllerButtons::btnX])
2131 mInput.buttonStates[hand][ControllerButtons::btnX] = (thmubidist <= 0.030f) ?
true : false;
2135 if (!mInput.buttonStates[hand][ControllerButtons::btnA])
2136 mInput.buttonStates[hand][ControllerButtons::btnA] = (thmubidist <= 0.030f) ?
true : false;
2142 if (mInput.handVisible[hand] ==
false)
2144 XrSpaceVelocity spaceVelocity{XR_TYPE_SPACE_VELOCITY};
2145 XrSpaceLocation spaceLocation{XR_TYPE_SPACE_LOCATION, &spaceVelocity};
2146 result = xrLocateSpace(mInput.handSpace[hand], mPlaySpace, frameState.predictedDisplayTime, &spaceLocation);
2147 if (xr_result(mInstance, result,
"Unable to locate %d hand action space in app space", hand))
2149 if ((spaceLocation.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) != 0 && (spaceLocation.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) != 0)
2151 mInput.handVisible[hand] =
true;
2152 mControllerType[hand] = ControllerType::CLASSIC_CONTROLLER;
2156 getControllerOffset(mLastControllerType, hand,
false, offVec, offQuat);
2158 mInput.handQuat[hand] = offQuat;
2159 mInput.handPos[hand] = offVec;
2162 if ((spaceVelocity.velocityFlags & XR_SPACE_VELOCITY_LINEAR_VALID_BIT) != 0 && (spaceVelocity.velocityFlags & XR_SPACE_VELOCITY_ANGULAR_VALID_BIT) != 0)
2164 mInput.handVelocity[hand] = spaceVelocity.linearVelocity;
2165 mInput.handAngularVelocity[hand] = spaceVelocity.angularVelocity;
2169 mInput.handVelocity[hand] =
Vector3{0.0f, 0.0f, 0.0f};
2170 mInput.handAngularVelocity[hand] =
Vector3{0.0f, 0.0f, 0.0f};
2177bool sOpenXr::Update()
2179 if (!mConnected || mPaused)
2185 if (mRequestRestart)
2191 for (
unsigned int i = 0; i < MAX_VR_CONTROLLERS; i++)
2192 mInput.handVisible[i] =
false;
2194 if (mConnected && mSessionRunning)
2201 XrFrameState frameState = { XR_TYPE_FRAME_STATE };
2202 XrFrameWaitInfo frameWaitInfo = { XR_TYPE_FRAME_WAIT_INFO };
2203 result = xrWaitFrame(mSession, &frameWaitInfo, &frameState);
2204 if (!xr_result(mInstance, result,
"xrWaitFrame() was not successful, exiting..."))
2207 updateControllers(frameState);
2209 uint32_t view_count = 0;
2210 XrViewLocateInfo view_locate_info = { XR_TYPE_VIEW_LOCATE_INFO, XR_NULL_HANDLE, mViewType, frameState.predictedDisplayTime, mPlaySpace };
2211 XrSpaceLocation view_in_stage = { XR_TYPE_SPACE_LOCATION, XR_NULL_HANDLE, 0, identity_pose };
2212 xrLocateSpace(mViewSpace, mPlaySpace, frameState.predictedDisplayTime, &view_in_stage);
2214 XrViewState view_state = { XR_TYPE_VIEW_STATE, XR_NULL_HANDLE };
2215 result = xrLocateViews(mSession, &view_locate_info, &view_state, (uint32_t)mViews.size(), &view_count, mViews.data());
2216 if (!xr_result(mInstance, result,
"Could not locate views"))
2219 for (uint32_t i = 0; i < view_count; i++)
2221 mProjectionViews[i].pose = mViews[i].pose;
2222 mProjectionViews[i].fov = mViews[i].fov;
2225 if (view_state.viewStateFlags & XR_VIEW_STATE_ORIENTATION_VALID_BIT)
2228 if ((view_count > 1) && (view_state.viewStateFlags & XR_VIEW_STATE_POSITION_VALID_BIT))
2229 mLastIPD =
Vector3(mViews[0].pose.position).distance(
Vector3(mViews[1].pose.position));
2231 if (view_state.viewStateFlags & XR_VIEW_STATE_ORIENTATION_VALID_BIT)
2233 mPreviousHmdQuat.w = view_in_stage.pose.orientation.w;
2234 mPreviousHmdQuat.x = view_in_stage.pose.orientation.x;
2235 mPreviousHmdQuat.y = view_in_stage.pose.orientation.y;
2236 mPreviousHmdQuat.z = view_in_stage.pose.orientation.z;
2239 if (view_state.viewStateFlags & XR_VIEW_STATE_POSITION_VALID_BIT)
2241 mPreviousHmdPos.x = view_in_stage.pose.position.x;
2242 mPreviousHmdPos.y = view_in_stage.pose.position.y;
2243 mPreviousHmdPos.z = view_in_stage.pose.position.z;
2246 XrFrameBeginInfo frame_begin_info = { XR_TYPE_FRAME_BEGIN_INFO };
2248 result = xrBeginFrame(mSession, &frame_begin_info);
2249 if (!xr_result(mInstance, result,
"failed to begin frame!"))
2251 mSkipNextFrame =
true;
2254 mSkipNextFrame =
false;
2256 mPredictedDisplayTime = frameState.predictedDisplayTime;
2262void sOpenXr::UpdateTextures(SCOL_PTR_TYPE leftTexture, SCOL_PTR_TYPE rightTexture)
2264 if (mConnected && mSessionRunning && !mPaused && !mSkipNextFrame)
2267 uint32_t view_count = (uint32_t)mViews.size();
2268 bool renderState =
true;
2269 bool sessionActive = mState == XR_SESSION_STATE_READY || mState == XR_SESSION_STATE_VISIBLE || mState == XR_SESSION_STATE_FOCUSED;
2270 for (uint32_t i = 0; i < view_count; i++)
2272 SCOL_PTR_TYPE eyetex = ((i == 0) ? leftTexture : rightTexture);
2273 if (!eyetex || !sessionActive)
2275 renderState =
false;
2279 XrSwapchainImageAcquireInfo acquire_info = { XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO };
2280 uint32_t acquired_index = 0;
2281 result = xrAcquireSwapchainImage(mSwapchains[i], &acquire_info, &acquired_index);
2282 if (!xr_result(mInstance, result,
"failed to acquire swapchain image!"))
2284 renderState =
false;
2288 XrSwapchainImageWaitInfo wait_info = { XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO, XR_NULL_HANDLE, XR_INFINITE_DURATION };
2289 result = xrWaitSwapchainImage(mSwapchains[i], &wait_info);
2290 if (!xr_result(mInstance, result,
"failed to wait for swapchain image!"))
2292 renderState =
false;
2293 XrSwapchainImageReleaseInfo release_info = { XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO };
2294 result = xrReleaseSwapchainImage(mSwapchains[i], &release_info);
2295 xr_result(mInstance, result,
"failed to release swapchain image!");
2299 int32_t width = mProjectionViews[i].subImage.imageRect.extent.width;
2300 int32_t height = mProjectionViews[i].subImage.imageRect.extent.height;
2302 mRenderer->UpdateTextures(leftTexture, rightTexture, acquired_index, width, height, i);
2304 XrSwapchainImageReleaseInfo release_info = { XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO };
2305 result = xrReleaseSwapchainImage(mSwapchains[i], &release_info);
2306 if (!xr_result(mInstance, result,
"failed to release swapchain image!"))
2308 renderState =
false;
2314 std::vector<XrCompositionLayerBaseHeader*> layers;
2315 XrCompositionLayerFlags flags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT|XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT;
2316 if (((mPassthroughFB.supported && mPassthroughFB.available) || mPassthroughHTC.supported) && mPassthroughEnable)
2317 flags |= XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT;
2319 XrCompositionLayerProjection layer_proj = { XR_TYPE_COMPOSITION_LAYER_PROJECTION, XR_NULL_HANDLE, flags,
2320 mPlaySpace, view_count, mProjectionViews.data() };
2322 if (sessionActive && renderState)
2324 if (mPassthroughFB.supported && mPassthroughEnable && (mPassthroughFB.passthroughLayer != XR_NULL_HANDLE) && mPassthroughFB.available)
2326 XrCompositionLayerPassthroughFB passthroughCompLayer = {XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB, XR_NULL_HANDLE,
2327 XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT, XR_NULL_HANDLE,
2328 mPassthroughFB.passthroughLayer};
2330 layers.push_back(
reinterpret_cast<XrCompositionLayerBaseHeader*
>(&passthroughCompLayer));
2332 else if (mPassthroughHTC.supported && mPassthroughEnable)
2334 XrPassthroughColorHTC passthroughColor = { XR_TYPE_PASSTHROUGH_COLOR_HTC, XR_NULL_HANDLE, 1.0f };
2335 XrCompositionLayerPassthroughHTC passthroughCompLayer = { XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_HTC, XR_NULL_HANDLE,
2336 XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT, mViewSpace,
2337 mPassthroughHTC.passthroughFeature, passthroughColor};
2339 layers.push_back(
reinterpret_cast<XrCompositionLayerBaseHeader*
>(&passthroughCompLayer));
2342 layers.push_back(
reinterpret_cast<XrCompositionLayerBaseHeader*
>(&layer_proj));
2345 XrFrameEndInfo frameEndInfo = {};
2346 frameEndInfo.type = XR_TYPE_FRAME_END_INFO;
2347 frameEndInfo.displayTime = mPredictedDisplayTime;
2348 frameEndInfo.layerCount = (uint32_t)layers.size();
2349 frameEndInfo.layers = layers.data();
2350 frameEndInfo.environmentBlendMode = mBlendMode;
2351 frameEndInfo.next = XR_NULL_HANDLE;
2352 result = xrEndFrame(mSession, &frameEndInfo);
2353 if (!xr_result(mInstance, result,
"failed to end frame!") && mPassthroughFB.supported && mPassthroughEnable)
2356 layers.push_back(
reinterpret_cast<XrCompositionLayerBaseHeader*
>(&layer_proj));
2357 frameEndInfo.layerCount = (uint32_t)layers.size();
2358 frameEndInfo.layers = layers.data();
2359 result = xrEndFrame(mSession, &frameEndInfo);
2360 xr_result(mInstance, result,
"failed to end frame even with simple layer!");
2365bool sOpenXr::GetControllerVisibility(
int id)
2367 return mInput.handVisible[id];
2370Vector3 sOpenXr::GetControllerPosition(
int id)
2372 return mInput.handPos[id];
2375Quaternion sOpenXr::GetControllerOrientation(
int id)
2377 return mInput.handQuat[id];
2380Vector3 sOpenXr::GetControllerVelocity(
int id)
2382 return mInput.handVelocity[id];
2385Vector3 sOpenXr::GetControllerAngularVelocity(
int id)
2387 return mInput.handAngularVelocity[id];
2390std::vector<bool> sOpenXr::GetControllerButtonsState(
int id)
2392 if (!mConnected ||
id >= mInput.buttonStates.size())
2394 std::vector<bool> ret;
2397 return mInput.buttonStates[id];
2400std::vector<bool> sOpenXr::GetControllerTouchesState(
int id)
2402 if (!mConnected ||
id >= mInput.touchStates.size())
2404 std::vector<bool> ret;
2407 return mInput.touchStates[id];
2410std::vector<float> sOpenXr::GetControllerAnalogState(
int id)
2412 if (!mConnected ||
id >= mInput.analogStates.size())
2414 std::vector<float> ret;
2417 return mInput.analogStates[id];
2420void sOpenXr::SetControllerVibration(
int id,
float value)
2422 if (mState != XR_SESSION_STATE_FOCUSED)
2425 XrHapticVibration vibration{ XR_TYPE_HAPTIC_VIBRATION };
2426 vibration.amplitude = value;
2427 vibration.duration = XR_MIN_HAPTIC_DURATION;
2428 vibration.frequency = XR_FREQUENCY_UNSPECIFIED;
2430 XrHapticActionInfo hapticActionInfo{ XR_TYPE_HAPTIC_ACTION_INFO };
2431 hapticActionInfo.action = mInput.vibrateAction;
2432 hapticActionInfo.subactionPath = mInput.handSubactionPath[id];
2433 xrApplyHapticFeedback(mSession, &hapticActionInfo, (XrHapticBaseHeader*)&vibration);
2436std::array<Position, MAX_HAND_JOINTS> sOpenXr::GetControllerBones(
int id,
bool &ret)
2438 if (!mConnected || !mHandTracking.supported || (
id > 1))
2442 return mHandTracking.bones[id];
2445int sOpenXr::GetControllerType(
int id)
2450 return mControllerType[id];
2453bool sOpenXr::IsPassthroughSupported()
2455 return mPassthroughFB.supported || mPassthroughHTC.supported;
2458bool sOpenXr::updatePassthrough()
2460 if (!IsPassthroughSupported())
2464 if (mPassthroughEnable)
2466 if (mPassthroughFB.supported)
2468 result = mPassthroughFB.pfnXrPassthroughStartFBX(mPassthroughFB.passthroughFeature);
2469 if (!xr_result(mInstance, result,
"Could not start passthrough!"))
2472 result = mPassthroughFB.pfnXrPassthroughLayerResumeFBX(mPassthroughFB.passthroughLayer);
2473 if (!xr_result(mInstance, result,
"Could not resume passthrough layer!"))
2476 if (mPassthroughFB.pfnXrPassthroughLayerSetStyleFB)
2478 XrPassthroughStyleFB style{ XR_TYPE_PASSTHROUGH_STYLE_FB };
2479 style.textureOpacityFactor = 1.0f;
2480 style.edgeColor = { 0.0f, 0.0f, 0.0f, 0.0f };
2481 mPassthroughFB.pfnXrPassthroughLayerSetStyleFB(mPassthroughFB.passthroughLayer, &style);
2484 mPassthroughFB.available =
true;
2486 else if (mPassthroughHTC.supported)
2488 XrPassthroughCreateInfoHTC passthroughInfo = { XR_TYPE_PASSTHROUGH_CREATE_INFO_HTC, XR_NULL_HANDLE, XR_PASSTHROUGH_FORM_PLANAR_HTC };
2489 result = mPassthroughHTC.pfnXrCreatePassthroughHTC(mSession, &passthroughInfo, &mPassthroughHTC.passthroughFeature);
2490 if (!xr_result(mInstance, result,
"Could not start passthrough!"))
2493 SetSceneBlendMode(XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND);
2497 if (mPassthroughFB.supported)
2499 result = mPassthroughFB.pfnXrPassthroughLayerPauseFBX(mPassthroughFB.passthroughLayer);
2500 if (!xr_result(mInstance, result,
"Could not pause passthrough layer!"))
2503 result = mPassthroughFB.pfnXrPassthroughPauseFBX(mPassthroughFB.passthroughFeature);
2504 if (!xr_result(mInstance, result,
"Could not pause passthrough!"))
2507 else if (mPassthroughHTC.supported)
2509 result = mPassthroughHTC.pfnXrDestroyPassthroughHTC(mPassthroughHTC.passthroughFeature);
2510 mPassthroughHTC.passthroughFeature = XR_NULL_HANDLE;
2511 if (!xr_result(mInstance, result,
"Could not stop passthrough!"))
2515 SetSceneBlendMode(XR_ENVIRONMENT_BLEND_MODE_OPAQUE);
2520bool sOpenXr::SetPassthroughState(
bool state)
2522 if (!IsPassthroughSupported() || (mPassthroughEnable == state))
2525 mPassthroughEnable = state;
2527 updatePassthrough();
2531bool sOpenXr::createPassthrough()
2533 if (!mPassthroughFB.supported)
2547 XrPassthroughCreateInfoFB passthroughCreateInfo = {XR_TYPE_PASSTHROUGH_CREATE_INFO_FB, XR_NULL_HANDLE, 0};
2548 result = mPassthroughFB.pfnXrCreatePassthroughFBX(mSession, &passthroughCreateInfo, &mPassthroughFB.passthroughFeature);
2549 if (!xr_result(mInstance, result,
"Failed to create a passthrough feature."))
2550 return mPassthroughFB.supported =
false;
2553 XrPassthroughLayerCreateInfoFB layerCreateInfo = {XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB, XR_NULL_HANDLE,
2554 mPassthroughFB.passthroughFeature, 0,
2555 XR_PASSTHROUGH_LAYER_PURPOSE_RECONSTRUCTION_FB};
2556 result = mPassthroughFB.pfnXrCreatePassthroughLayerFBX(mSession, &layerCreateInfo, &mPassthroughFB.passthroughLayer);
2557 if (!xr_result(mInstance, result,
"Failed to create and start a passthrough layer"))
2558 return mPassthroughFB.supported =
false;
2563void sOpenXr::cleanPassthrough()
2566 if (mPassthroughFB.supported)
2568 if (mPassthroughEnable)
2570 result = mPassthroughFB.pfnXrPassthroughLayerPauseFBX(mPassthroughFB.passthroughLayer);
2571 xr_result(mInstance, result,
"Could not pause passthrough layer!");
2573 result = mPassthroughFB.pfnXrPassthroughPauseFBX(mPassthroughFB.passthroughFeature);
2574 xr_result(mInstance, result,
"Could not pause passthrough!");
2578 if (mPassthroughFB.passthroughLayer != XR_NULL_HANDLE)
2580 result = mPassthroughFB.pfnXrDestroyPassthroughLayerFBX(mPassthroughFB.passthroughLayer);
2581 xr_result(mInstance, result,
"Failed to destroy a passthrough layer");
2582 mPassthroughFB.passthroughLayer = XR_NULL_HANDLE;
2586 if (mPassthroughFB.passthroughFeature != XR_NULL_HANDLE)
2588 result = mPassthroughFB.pfnXrDestroyPassthroughFBX(mPassthroughFB.passthroughFeature);
2589 xr_result(mInstance, result,
"Failed to destroy a passthrough feature.");
2590 mPassthroughFB.passthroughFeature = XR_NULL_HANDLE;
2594 if (mPassthroughHTC.supported && mPassthroughHTC.passthroughFeature != XR_NULL_HANDLE)
2596 result = mPassthroughHTC.pfnXrDestroyPassthroughHTC(mPassthroughHTC.passthroughFeature);
2597 mPassthroughHTC.passthroughFeature = XR_NULL_HANDLE;
2598 xr_result(mInstance, result,
"Failed to destroy a passthrough feature.");
sOpenXr(RenderSystem rsys=XR_OPENGL_RENDERER, float scaleRatio=1.0f)